27#include "absl/status/status.h"
28#include "absl/status/statusor.h"
29#include "absl/strings/str_format.h"
30#include "absl/time/clock.h"
32#include "imgui_internal.h"
39struct ImGui_ImplSDLRenderer2_Data {
40 SDL_Renderer* Renderer;
43std::filesystem::path DefaultScreenshotPath() {
44 std::filesystem::path base_dir =
45 std::filesystem::temp_directory_path() /
"yaze" /
"test-results";
47 std::filesystem::create_directories(base_dir, ec);
49 const int64_t timestamp_ms = absl::ToUnixMillis(absl::Now());
51 std::filesystem::path(
52 absl::StrFormat(
"harness_%lld.bmp",
static_cast<long long>(timestamp_ms)));
57absl::StatusOr<ScreenshotArtifact> CaptureHarnessScreenshot(
58 const std::string& preferred_path) {
59 ImGuiIO& io = ImGui::GetIO();
61 static_cast<ImGui_ImplSDLRenderer2_Data*
>(io.BackendRendererUserData);
63 if (!backend_data || !backend_data->Renderer) {
64 return absl::FailedPreconditionError(
"SDL renderer not available");
67 SDL_Renderer* renderer = backend_data->Renderer;
70 if (SDL_GetRendererOutputSize(renderer, &width, &height) != 0) {
71 return absl::InternalError(
72 absl::StrFormat(
"Failed to get renderer size: %s", SDL_GetError()));
75 std::filesystem::path output_path = preferred_path.empty()
76 ? DefaultScreenshotPath()
77 : std::filesystem::path(preferred_path);
78 if (output_path.has_parent_path()) {
80 std::filesystem::create_directories(output_path.parent_path(), ec);
83 SDL_Surface* surface = SDL_CreateRGBSurface(0, width, height, 32, 0x00FF0000,
84 0x0000FF00, 0x000000FF,
87 return absl::InternalError(
88 absl::StrFormat(
"Failed to create SDL surface: %s", SDL_GetError()));
91 if (SDL_RenderReadPixels(renderer,
nullptr, SDL_PIXELFORMAT_ARGB8888,
92 surface->pixels, surface->pitch) != 0) {
93 SDL_FreeSurface(surface);
94 return absl::InternalError(
95 absl::StrFormat(
"Failed to read renderer pixels: %s", SDL_GetError()));
98 if (SDL_SaveBMP(surface, output_path.string().c_str()) != 0) {
99 SDL_FreeSurface(surface);
100 return absl::InternalError(
101 absl::StrFormat(
"Failed to save BMP: %s", SDL_GetError()));
104 SDL_FreeSurface(surface);
107 const int64_t file_size =
108 std::filesystem::file_size(output_path, ec);
110 return absl::InternalError(
111 absl::StrFormat(
"Failed to stat screenshot %s: %s",
112 output_path.string(), ec.message()));
115 ScreenshotArtifact artifact;
116 artifact.file_path = output_path.string();
117 artifact.width = width;
118 artifact.height = height;
119 artifact.file_size_bytes = file_size;
123absl::StatusOr<ScreenshotArtifact> CaptureHarnessScreenshotRegion(
124 const std::optional<CaptureRegion>& region,
125 const std::string& preferred_path) {
126 ImGuiIO& io = ImGui::GetIO();
128 static_cast<ImGui_ImplSDLRenderer2_Data*
>(io.BackendRendererUserData);
130 if (!backend_data || !backend_data->Renderer) {
131 return absl::FailedPreconditionError(
"SDL renderer not available");
134 SDL_Renderer* renderer = backend_data->Renderer;
139 if (SDL_GetRendererOutputSize(renderer, &full_width, &full_height) != 0) {
140 return absl::InternalError(
141 absl::StrFormat(
"Failed to get renderer size: %s", SDL_GetError()));
147 int capture_width = full_width;
148 int capture_height = full_height;
150 if (region.has_value()) {
151 capture_x = region->x;
152 capture_y = region->y;
153 capture_width = region->width;
154 capture_height = region->height;
157 if (capture_x < 0) capture_x = 0;
158 if (capture_y < 0) capture_y = 0;
159 if (capture_x + capture_width > full_width) {
160 capture_width = full_width - capture_x;
162 if (capture_y + capture_height > full_height) {
163 capture_height = full_height - capture_y;
166 if (capture_width <= 0 || capture_height <= 0) {
167 return absl::InvalidArgumentError(
"Invalid capture region");
171 std::filesystem::path output_path = preferred_path.empty()
172 ? DefaultScreenshotPath()
173 : std::filesystem::path(preferred_path);
174 if (output_path.has_parent_path()) {
176 std::filesystem::create_directories(output_path.parent_path(), ec);
180 SDL_Surface* surface = SDL_CreateRGBSurface(0, capture_width, capture_height,
181 32, 0x00FF0000, 0x0000FF00,
182 0x000000FF, 0xFF000000);
184 return absl::InternalError(
185 absl::StrFormat(
"Failed to create SDL surface: %s", SDL_GetError()));
189 SDL_Rect region_rect = {capture_x, capture_y, capture_width, capture_height};
190 if (SDL_RenderReadPixels(renderer, ®ion_rect, SDL_PIXELFORMAT_ARGB8888,
191 surface->pixels, surface->pitch) != 0) {
192 SDL_FreeSurface(surface);
193 return absl::InternalError(
194 absl::StrFormat(
"Failed to read renderer pixels: %s", SDL_GetError()));
197 if (SDL_SaveBMP(surface, output_path.string().c_str()) != 0) {
198 SDL_FreeSurface(surface);
199 return absl::InternalError(
200 absl::StrFormat(
"Failed to save BMP: %s", SDL_GetError()));
203 SDL_FreeSurface(surface);
206 const int64_t file_size = std::filesystem::file_size(output_path, ec);
208 return absl::InternalError(
209 absl::StrFormat(
"Failed to stat screenshot %s: %s",
210 output_path.string(), ec.message()));
213 ScreenshotArtifact artifact;
214 artifact.file_path = output_path.string();
215 artifact.width = capture_width;
216 artifact.height = capture_height;
217 artifact.file_size_bytes = file_size;
221absl::StatusOr<ScreenshotArtifact> CaptureActiveWindow(
222 const std::string& preferred_path) {
223 ImGuiContext* ctx = ImGui::GetCurrentContext();
224 if (!ctx || !ctx->NavWindow) {
225 return absl::FailedPreconditionError(
"No active ImGui window");
228 ImGuiWindow* window = ctx->NavWindow;
229 CaptureRegion region;
230 region.x =
static_cast<int>(window->Pos.x);
231 region.y =
static_cast<int>(window->Pos.y);
232 region.width =
static_cast<int>(window->Size.x);
233 region.height =
static_cast<int>(window->Size.y);
235 return CaptureHarnessScreenshotRegion(region, preferred_path);
238absl::StatusOr<ScreenshotArtifact> CaptureWindowByName(
239 const std::string& window_name,
240 const std::string& preferred_path) {
241 ImGuiContext* ctx = ImGui::GetCurrentContext();
243 return absl::FailedPreconditionError(
"No ImGui context");
246 ImGuiWindow* window = ImGui::FindWindowByName(window_name.c_str());
248 return absl::NotFoundError(
249 absl::StrFormat(
"Window '%s' not found", window_name));
252 CaptureRegion region;
253 region.x =
static_cast<int>(window->Pos.x);
254 region.y =
static_cast<int>(window->Pos.y);
255 region.width =
static_cast<int>(window->Size.x);
256 region.height =
static_cast<int>(window->Size.y);
258 return CaptureHarnessScreenshotRegion(region, preferred_path);
Main namespace for the application.