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(absl::StrFormat(
52 "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;
71 return absl::InternalError(
72 absl::StrFormat(
"Failed to get renderer size: %s", SDL_GetError()));
75 std::filesystem::path output_path =
76 preferred_path.empty() ? DefaultScreenshotPath()
77 : std::filesystem::path(preferred_path);
78 if (output_path.has_parent_path()) {
80 std::filesystem::create_directories(output_path.parent_path(), ec);
85 return absl::InternalError(
86 absl::StrFormat(
"Failed to read pixels to surface: %s", SDL_GetError()));
89 if (SDL_SaveBMP(surface, output_path.string().c_str()) != 0) {
91 return absl::InternalError(
92 absl::StrFormat(
"Failed to save BMP: %s", SDL_GetError()));
98 const int64_t file_size = std::filesystem::file_size(output_path, ec);
100 return absl::InternalError(
101 absl::StrFormat(
"Failed to stat screenshot %s: %s",
102 output_path.string(), ec.message()));
105 ScreenshotArtifact artifact;
106 artifact.file_path = output_path.string();
107 artifact.width = width;
108 artifact.height = height;
109 artifact.file_size_bytes = file_size;
113absl::StatusOr<ScreenshotArtifact> CaptureHarnessScreenshotRegion(
114 const std::optional<CaptureRegion>& region,
115 const std::string& preferred_path) {
116 ImGuiIO& io = ImGui::GetIO();
118 static_cast<ImGui_ImplSDLRenderer2_Data*
>(io.BackendRendererUserData);
120 if (!backend_data || !backend_data->Renderer) {
121 return absl::FailedPreconditionError(
"SDL renderer not available");
124 SDL_Renderer* renderer = backend_data->Renderer;
130 return absl::InternalError(
131 absl::StrFormat(
"Failed to get renderer size: %s", SDL_GetError()));
137 int capture_width = full_width;
138 int capture_height = full_height;
140 if (region.has_value()) {
141 capture_x = region->x;
142 capture_y = region->y;
143 capture_width = region->width;
144 capture_height = region->height;
151 if (capture_x + capture_width > full_width) {
152 capture_width = full_width - capture_x;
154 if (capture_y + capture_height > full_height) {
155 capture_height = full_height - capture_y;
158 if (capture_width <= 0 || capture_height <= 0) {
159 return absl::InvalidArgumentError(
"Invalid capture region");
163 std::filesystem::path output_path =
164 preferred_path.empty() ? DefaultScreenshotPath()
165 : std::filesystem::path(preferred_path);
166 if (output_path.has_parent_path()) {
168 std::filesystem::create_directories(output_path.parent_path(), ec);
172 SDL_Rect region_rect = {capture_x, capture_y, capture_width, capture_height};
176 return absl::InternalError(
177 absl::StrFormat(
"Failed to read pixels to surface: %s", SDL_GetError()));
180 if (SDL_SaveBMP(surface, output_path.string().c_str()) != 0) {
182 return absl::InternalError(
183 absl::StrFormat(
"Failed to save BMP: %s", SDL_GetError()));
189 const int64_t file_size = std::filesystem::file_size(output_path, ec);
191 return absl::InternalError(
192 absl::StrFormat(
"Failed to stat screenshot %s: %s",
193 output_path.string(), ec.message()));
196 ScreenshotArtifact artifact;
197 artifact.file_path = output_path.string();
198 artifact.width = capture_width;
199 artifact.height = capture_height;
200 artifact.file_size_bytes = file_size;
204absl::StatusOr<ScreenshotArtifact> CaptureActiveWindow(
205 const std::string& preferred_path) {
206 ImGuiContext* ctx = ImGui::GetCurrentContext();
207 if (!ctx || !ctx->NavWindow) {
208 return absl::FailedPreconditionError(
"No active ImGui window");
211 ImGuiWindow* window = ctx->NavWindow;
212 CaptureRegion region;
213 region.x =
static_cast<int>(window->Pos.x);
214 region.y =
static_cast<int>(window->Pos.y);
215 region.width =
static_cast<int>(window->Size.x);
216 region.height =
static_cast<int>(window->Size.y);
218 return CaptureHarnessScreenshotRegion(region, preferred_path);
221absl::StatusOr<ScreenshotArtifact> CaptureWindowByName(
222 const std::string& window_name,
const std::string& preferred_path) {
223 ImGuiContext* ctx = ImGui::GetCurrentContext();
225 return absl::FailedPreconditionError(
"No ImGui context");
228 ImGuiWindow* window = ImGui::FindWindowByName(window_name.c_str());
230 return absl::NotFoundError(
231 absl::StrFormat(
"Window '%s' not found", window_name));
234 CaptureRegion region;
235 region.x =
static_cast<int>(window->Pos.x);
236 region.y =
static_cast<int>(window->Pos.y);
237 region.width =
static_cast<int>(window->Size.x);
238 region.height =
static_cast<int>(window->Size.y);
240 return CaptureHarnessScreenshotRegion(region, preferred_path);
SDL2/SDL3 compatibility layer.