void DEBUG_startup(void) { g_debug = persistent_mem_alloc(&g_memory->debug, 1, sizeof(*g_debug)); } char* DEBUG_load_shader(const char* path, size_t* size) { SDL_RWops* ops = SDL_RWFromFile(path, "r"); if (ops == NULL) { LOG_ERROR("Error opening file %s: %s", path, SDL_GetError()); exit(EXIT_FAILURE); } Sint64 file_size = SDL_RWsize(ops); if (size < 0) { LOG_ERROR("Error getting size of file %s: %s", path, SDL_GetError()); } char* buf = scratch_mem_alloc(1, file_size); size_t items_read = SDL_RWread(ops, buf, file_size, 1); if (items_read != 1) { LOG_ERROR("Error reading file %s: %s", path, SDL_GetError()); } int ret = SDL_RWclose(ops); if (ret != 0) { LOG_ERROR("Error closing file %s: %s", path, SDL_GetError()); } *size = (size_t)file_size; return buf; } void DEBUG_reload_shaders(render_mgr_t* in) { glUseProgram(0); { struct stat attrib; stat("shaders/geo.glsl", &attrib); time_t mod_time = attrib.st_mtime; if (mod_time != g_debug->render_mgr.geo) { LOG_DEBUG("Reloading geo.glsl"); glDeleteProgram(in->geo.shader); size_t size; char* buf = DEBUG_load_shader("shaders/geo.glsl", &size); in->geo.shader = create_shader(buf, size); g_debug->render_mgr.geo = mod_time; } } { struct stat attrib; stat("shaders/screen.glsl", &attrib); time_t mod_time = attrib.st_mtime; if (mod_time != g_debug->render_mgr.screen) { LOG_DEBUG("Reloading screen.glsl"); glDeleteProgram(in->screen.shader); size_t size; char* buf = DEBUG_load_shader("shaders/screen.glsl", &size); in->screen.shader = create_shader(buf, size); g_debug->render_mgr.screen = mod_time; } } { struct stat attrib; stat("shaders/text.glsl", &attrib); time_t mod_time = attrib.st_mtime; if (mod_time != g_debug->render_mgr.text) { LOG_DEBUG("Reloading text.glsl"); glDeleteProgram(in->text.shader); size_t size; char* buf = DEBUG_load_shader("shaders/text.glsl", &size); in->text.shader = create_shader(buf, size); g_debug->render_mgr.text = mod_time; } } } void DEBUG_reload_data1(void) { const char* path = "../../assets/processed/data1.bin"; struct stat attrib; stat(path, &attrib); time_t mod_time = attrib.st_mtime; if (mod_time != g_debug->data_loader.data1) { LOG_DEBUG("Reloading data1.bin"); g_debug->data_loader.data1 = mod_time; // Delay briefly to ensure file has been fully written SDL_Delay(100); // Free old GPU data for (size_t i = 0; i < g_engine->asset_mgr.meshes.count; i++) { mesh_t* mesh = &g_engine->asset_mgr.meshes.data[i]; glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glDeleteBuffers(1, &mesh->vbo); glDeleteBuffers(1, &mesh->ebo); glDeleteVertexArrays(1, &mesh->vao); } for (size_t i = 0; i < g_engine->asset_mgr.materials.count; i++) { material_t* material = &g_engine->asset_mgr.materials.data[i]; glBindTexture(GL_TEXTURE_2D, 0); glDeleteTextures(1, &material->texture); } // Reset // TODO: Do this automatically so that adding new fields to the asset_mgr doesn't require changing this hash_reset(&g_engine->asset_mgr.meshes.hash); hash_reset(&g_engine->asset_mgr.materials.hash); hash_reset(&g_engine->asset_mgr.cameras.hash); g_engine->asset_mgr.meshes.count = 0; g_engine->asset_mgr.materials.count = 0; g_engine->asset_mgr.transforms.count = 0; g_engine->asset_mgr.cameras.count = 0; g_engine->asset_mgr.renderables.count = 0; g_engine->asset_mgr.colliders.count = 0; g_engine->asset_mgr.lights.count = 0; persistent_mem_reset(&g_memory->data1); load_data1(path); } } void DEBUG_camera_toggle(void) { if (g_debug->camera.enabled) { g_debug->camera.enabled = false; } else { g_debug->camera.enabled = true; camera_t* camera = get_active_camera(); transform_t* transform = get_transform(camera->transform); // Copy existing camera's info so that debug camera starts from that position g_debug->camera.fly = *camera; g_debug->camera.transform = *transform; } } void DEBUG_camera_update(float dt, input_t input) { // Keep all this logic local to this one debug function so we don't pollute // the non-debug functions which use real transform handles vec3 velocity = {0}; if (input.forward) { velocity.y = 1.0f; } else if (input.backward) { velocity.y = -1.0f; } if (input.strafe_left) { velocity.x = -1.0f; } else if (input.strafe_right) { velocity.x = 1.0f; } if (input.debug.up) { velocity.z = 1.0f; } else if (input.debug.down) { velocity.z = -1.0f; } float speed_multiplier = 1.0f; if (input.debug.speed) { speed_multiplier = 2.5f; } float speed = dt * PLAYER_SPEED * speed_multiplier; velocity = vec3_mult(vec3_normalize(velocity), speed); float mouse_offset_x = -1.0f * input.mouse_x_delta * CAMERA_SENSITIVITY; float mouse_offset_y = -1.0f * input.mouse_y_delta * CAMERA_SENSITIVITY; camera_t* camera = &g_debug->camera.fly; transform_t* transform = &g_debug->camera.transform; // Move transform->position = vec3_add(transform->position, vec3_mult(camera->front, velocity.y)); camera->right = vec3_cross(camera->front, WORLD_UP); transform->position = vec3_add(transform->position, vec3_mult(vec3_normalize(camera->right), velocity.x)); transform->position = vec3_add(transform->position, vec3_mult(WORLD_UP, velocity.z)); // Rotate camera_rotate(camera, mouse_offset_x, mouse_offset_y); // Update view vec3 target = vec3_add(transform->position, camera->front); vec3 front = vec3_normalize(vec3_sub(target, transform->position)); vec3 side = vec3_normalize(vec3_cross(front, WORLD_UP)); vec3 up = vec3_cross(side, front); mat4 view_mat = { side.x, side.y, side.z, -vec3_dot(transform->position, side), up.x, up.y, up.z, -vec3_dot(transform->position, up), front.x, front.y, front.z, -vec3_dot(transform->position, front), 0.0f, 0.0f, 0.0f, 1.0f }; camera->view_mat = view_mat; }