| 50 | namespace oid::host { |
| 51 | |
| 52 | bool GlfwCanvas::render_buffer_icon(oid::Stage& stage, |
| 53 | const int icon_width, |
| 54 | const int icon_height) { |
| 55 | if (!ready_) { |
| 56 | return false; |
| 57 | } |
| 58 | // Lazily allocate the icon FBO/texture on first use (same shape as |
| 59 | // get_text_renderer()'s lazy bake), rather than eagerly at construction: |
| 60 | // most frames never render a thumbnail (e.g. an empty buffer list), so |
| 61 | // this avoids allocating GL resources that may never be needed. |
| 62 | if (!icon_framebuffer_ready_ && |
| 63 | !init_icon_framebuffer(icon_width, icon_height)) { |
| 64 | return false; |
| 65 | } |
| 66 | |
| 67 | const auto& dialect = oid::the_dialect(); |
| 68 | const auto icon_read_format = dialect.icon_gl_format; |
| 69 | const auto icon_bytes_per_pixel = dialect.icon_bytes_per_pixel; |
| 70 | |
| 71 | glBindFramebuffer(GL_FRAMEBUFFER, icon_fbo_); |
| 72 | |
| 73 | glViewport(0, 0, icon_width, icon_height); |
| 74 | glDisable(GL_SCISSOR_TEST); |
| 75 | glClearColor(0.1f, 0.1f, 0.1f, 1.0f); |
| 76 | glClear(GL_COLOR_BUFFER_BIT); |
| 77 | |
| 78 | const auto camera = stage.get_game_object("camera"); |
| 79 | if (!camera.has_value()) [[unlikely]] { |
| 80 | glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| 81 | glViewport(0, 0, render_width(), render_height()); |
| 82 | return false; |
| 83 | } |
| 84 | const auto cam_opt = |
| 85 | camera->get().get_component<oid::Camera>("camera_component"); |
| 86 | if (!cam_opt.has_value()) [[unlikely]] { |
| 87 | glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| 88 | glViewport(0, 0, render_width(), render_height()); |
| 89 | return false; |
| 90 | } |
| 91 | auto& cam = cam_opt->get(); |
| 92 | |
| 93 | // Save original camera pose |
| 94 | const auto original_pose = oid::Camera{cam}; |
| 95 | |
| 96 | // Adapt camera to the thumbnail dimensions |
| 97 | cam.window_resized(icon_width, icon_height); |
| 98 | // Flips the projected image along the horizontal axis |
| 99 | cam.projection().set_ortho_projection(static_cast<float>(icon_width) / 2.0f, |
| 100 | static_cast<float>(-icon_height) / |
| 101 | 2.0f, |
| 102 | -1.0f, |
| 103 | 1.0f); |
| 104 | // Reposition buffer in the center of the canvas |
| 105 | cam.recenter_camera(); |
| 106 | |
| 107 | // Enable icon drawing mode (forbids pixel borders drawing) |
| 108 | stage.set_icon_drawing_mode(true); |
| 109 |
no test coverage detected