6#include <glm/gtc/type_ptr.hpp>
7#include <glm/gtc/matrix_transform.hpp>
10#include "imgui_stdlib.h"
18#include "stb_image_write.h"
29void captureScreenshot(
const std::string& path,
ViewportFBO& fbo, std::string& status)
33 status =
"No viewport to capture.";
37 const int w = fbo.
width;
39 std::vector<unsigned char> pixels(
static_cast<size_t>(w) * h * 4);
41 glBindFramebuffer(GL_FRAMEBUFFER, fbo.
fbo);
42 glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
43 glBindFramebuffer(GL_FRAMEBUFFER, 0);
46 const size_t rowBytes =
static_cast<size_t>(w) * 4;
47 std::vector<unsigned char> row(rowBytes);
48 for (
int y = 0; y < h / 2; ++y)
50 unsigned char* top = pixels.data() + y * rowBytes;
51 unsigned char* bot = pixels.data() + (h - 1 - y) * rowBytes;
52 std::memcpy(row.data(), top, rowBytes);
53 std::memcpy(top, bot, rowBytes);
54 std::memcpy(bot, row.data(), rowBytes);
57 if (stbi_write_png(path.c_str(), w, h, 4, pixels.data(),
static_cast<int>(rowBytes)))
59 status =
"Saved: " + path;
60 LOG_INFO <<
"Screenshot saved to " << path;
64 status =
"Failed to write: " + path;
65 LOG_ERROR <<
"Screenshot failed: " << path;
70void captureAtResolution(
const std::string& path,
int cw,
int ch,
73 const glm::vec3& bgColor,
bool drawGrid,
77 renderer.
renderScene(tmpFbo, cw, ch, camera, fov, bgColor, drawGrid,
80 glEnable(GL_LIGHTING);
81 glEnable(GL_TEXTURE_2D);
82 glEnable(GL_DEPTH_TEST);
83 glDepthFunc(GL_LEQUAL);
85 glEnable(GL_TEXTURE_2D);
86 glDisable(GL_LIGHTING);
87 glDepthMask(GL_FALSE);
95 std::vector<unsigned char> pixels(
static_cast<size_t>(cw) * ch * 4);
96 glBindFramebuffer(GL_FRAMEBUFFER, tmpFbo.
fbo);
97 glReadPixels(0, 0, cw, ch, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
98 glBindFramebuffer(GL_FRAMEBUFFER, 0);
99 const size_t rowBytes =
static_cast<size_t>(cw) * 4;
100 std::vector<unsigned char> row(rowBytes);
101 for (
int y = 0; y < ch / 2; ++y)
103 unsigned char* top = pixels.data() + y * rowBytes;
104 unsigned char* bot = pixels.data() + (ch - 1 - y) * rowBytes;
105 std::memcpy(row.data(), top, rowBytes);
106 std::memcpy(top, bot, rowBytes);
107 std::memcpy(bot, row.data(), rowBytes);
110 if (stbi_write_png(path.c_str(), cw, ch, 4, pixels.data(),
static_cast<int>(rowBytes)))
112 status = std::format(
"Saved ({}x{}): {}", cw, ch, path);
113 LOG_INFO <<
"Screenshot saved to " << path <<
" (" << cw <<
"x" << ch <<
")";
117 status =
"Failed to write: " + path;
127 assert(ctx.
screenshotPath &&
"DrawContext::screenshotPath must not be null");
128 assert(ctx.
screenshotStatus &&
"DrawContext::screenshotStatus must not be null");
129 assert(ctx.
useCanvasOverride &&
"DrawContext::useCanvasOverride must not be null");
130 assert(ctx.
fbo &&
"DrawContext::fbo must not be null");
131 assert(ctx.
camera &&
"DrawContext::camera must not be null");
133 ImGui::SeparatorText(
"Capture Viewport");
134 ImGui::Text(
"Output File:");
135 ImGui::SetNextItemWidth(-1);
138 if (ImGui::Button(
"Save Screenshot", ImVec2(-1, 0)))
159 ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f),
"%s", ctx.
screenshotStatus->c_str());
161 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
"%s", ctx.
screenshotStatus->c_str());
164 ImGui::SeparatorText(
"Canvas Size Override");
168 ImGui::SetNextItemWidth(100);
169 ImGui::InputInt(
"Width##canvas", ctx.
canvasWidth, 0, 0);
171 ImGui::SetNextItemWidth(100);
172 ImGui::InputInt(
"Height##canvas", ctx.
canvasHeight, 0, 0);
176 ImGui::Text(
"Quick:");
188 ImGui::TextDisabled(
"Captures at current viewport resolution (%dx%d).",
Scene-graph node that attaches a Displayable to a parent bone slot.
Orbit camera that revolves around a target point.
void renderScene(ViewportFBO &fbo, int w, int h, const OrbitCamera &camera, float fov, const glm::vec3 &clearColor, bool drawGrid, const std::function< void()> &drawObjects)
void draw(DrawContext &ctx)
Per-frame context for the screenshot panel.
std::string * screenshotPath
std::string * screenshotStatus
Simple OpenGL framebuffer object wrapper for off-screen rendering.
void destroy()
Release all GPU resources.
int width
Current width in pixels.
GLuint fbo
Framebuffer object handle.
int height
Current height in pixels.