10#include "absl/status/status.h"
11#include "absl/strings/str_format.h"
15#include "imgui/backends/imgui_impl_sdl3.h"
16#include "imgui/backends/imgui_impl_sdlrenderer3.h"
17#include "imgui/imgui.h"
30#define g_window_is_resizing yaze::core::g_window_is_resizing
32SDL3WindowBackend::~SDL3WindowBackend() {
38absl::Status SDL3WindowBackend::Initialize(
const WindowConfig& config) {
40 LOG_WARN(
"SDL3WindowBackend",
"Already initialized, shutting down first");
46 if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_EVENTS)) {
47 return absl::InternalError(
48 absl::StrFormat(
"SDL_Init failed: %s", SDL_GetError()));
52 int screen_width = config.width;
53 int screen_height = config.height;
55 if (screen_width == 0 || screen_height == 0) {
58 SDL_DisplayID display_id = SDL_GetPrimaryDisplay();
59 const SDL_DisplayMode* mode = SDL_GetCurrentDisplayMode(display_id);
62 screen_width =
static_cast<int>(mode->w * config.display_scale);
63 screen_height =
static_cast<int>(mode->h * config.display_scale);
69 "Failed to get display mode, using defaults: %dx%d",
70 screen_width, screen_height);
76 SDL_WindowFlags flags = 0;
77 if (config.resizable) {
78 flags |= SDL_WINDOW_RESIZABLE;
80 if (config.maximized) {
81 flags |= SDL_WINDOW_MAXIMIZED;
83 if (config.fullscreen) {
84 flags |= SDL_WINDOW_FULLSCREEN;
86 if (config.high_dpi) {
87 flags |= SDL_WINDOW_HIGH_PIXEL_DENSITY;
92 SDL_Window* raw_window = SDL_CreateWindow(config.title.c_str(), screen_width,
93 screen_height, flags);
97 return absl::InternalError(
98 absl::StrFormat(
"SDL_CreateWindow failed: %s", SDL_GetError()));
101 window_ = std::unique_ptr<SDL_Window, SDL3WindowDeleter>(raw_window);
104 const int audio_frequency = 48000;
105 const size_t buffer_size = (audio_frequency / 50) * 2;
106 audio_buffer_ = std::shared_ptr<int16_t>(
new int16_t[buffer_size],
107 std::default_delete<int16_t[]>());
109 LOG_INFO(
"SDL3WindowBackend",
"Initialized: %dx%d, audio buffer: %zu samples",
110 screen_width, screen_height, buffer_size);
114 return absl::OkStatus();
117absl::Status SDL3WindowBackend::Shutdown() {
119 return absl::OkStatus();
123 if (imgui_initialized_) {
128 LOG_INFO(
"SDL3WindowBackend",
"Shutting down graphics arena...");
133 LOG_INFO(
"SDL3WindowBackend",
"Destroying window...");
138 LOG_INFO(
"SDL3WindowBackend",
"Shutting down SDL...");
141 initialized_ =
false;
142 LOG_INFO(
"SDL3WindowBackend",
"Shutdown complete");
143 return absl::OkStatus();
146bool SDL3WindowBackend::PollEvent(WindowEvent& out_event) {
148 if (SDL_PollEvent(&sdl_event)) {
150 if (imgui_initialized_) {
151 ImGui_ImplSDL3_ProcessEvent(&sdl_event);
155 out_event = ConvertSDL3Event(sdl_event);
156 out_event.has_native_event =
true;
157 out_event.native_event = sdl_event;
163void SDL3WindowBackend::ProcessNativeEvent(
void* native_event) {
164 if (native_event && imgui_initialized_) {
165 ImGui_ImplSDL3_ProcessEvent(
static_cast<SDL_Event*
>(native_event));
169WindowEvent SDL3WindowBackend::ConvertSDL3Event(
const SDL_Event& sdl_event) {
173 switch (sdl_event.type) {
186 case SDL_EVENT_KEY_DOWN:
188 event.key_code = sdl_event.key.key;
189 event.scan_code = sdl_event.key.scancode;
190 UpdateModifierState();
191 event.key_shift = key_shift_;
192 event.key_ctrl = key_ctrl_;
193 event.key_alt = key_alt_;
194 event.key_super = key_super_;
197 case SDL_EVENT_KEY_UP:
199 event.key_code = sdl_event.key.key;
200 event.scan_code = sdl_event.key.scancode;
201 UpdateModifierState();
202 event.key_shift = key_shift_;
203 event.key_ctrl = key_ctrl_;
204 event.key_alt = key_alt_;
205 event.key_super = key_super_;
212 case SDL_EVENT_MOUSE_MOTION:
214 event.mouse_x = sdl_event.motion.x;
215 event.mouse_y = sdl_event.motion.y;
218 case SDL_EVENT_MOUSE_BUTTON_DOWN:
220 event.mouse_x = sdl_event.button.x;
221 event.mouse_y = sdl_event.button.y;
222 event.mouse_button = sdl_event.button.button;
225 case SDL_EVENT_MOUSE_BUTTON_UP:
227 event.mouse_x = sdl_event.button.x;
228 event.mouse_y = sdl_event.button.y;
229 event.mouse_button = sdl_event.button.button;
232 case SDL_EVENT_MOUSE_WHEEL:
234 event.wheel_x = sdl_event.wheel.x;
235 event.wheel_y = sdl_event.wheel.y;
241 case SDL_EVENT_DROP_FILE:
243 if (sdl_event.drop.data) {
244 event.dropped_file = sdl_event.drop.data;
254 case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
259 case SDL_EVENT_WINDOW_RESIZED:
261 event.window_width = sdl_event.window.data1;
262 event.window_height = sdl_event.window.data2;
267 case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
270 event.window_width = sdl_event.window.data1;
271 event.window_height = sdl_event.window.data2;
276 case SDL_EVENT_WINDOW_MINIMIZED:
278 is_resizing_ =
false;
282 case SDL_EVENT_WINDOW_MAXIMIZED:
286 case SDL_EVENT_WINDOW_RESTORED:
288 is_resizing_ =
false;
292 case SDL_EVENT_WINDOW_SHOWN:
294 is_resizing_ =
false;
298 case SDL_EVENT_WINDOW_HIDDEN:
300 is_resizing_ =
false;
304 case SDL_EVENT_WINDOW_EXPOSED:
306 is_resizing_ =
false;
310 case SDL_EVENT_WINDOW_FOCUS_GAINED:
314 case SDL_EVENT_WINDOW_FOCUS_LOST:
322void SDL3WindowBackend::UpdateModifierState() {
324 SDL_Keymod mod = SDL_GetModState();
325 key_shift_ = (mod & SDL_KMOD_SHIFT) != 0;
326 key_ctrl_ = (mod & SDL_KMOD_CTRL) != 0;
327 key_alt_ = (mod & SDL_KMOD_ALT) != 0;
328 key_super_ = (mod & SDL_KMOD_GUI) != 0;
331WindowStatus SDL3WindowBackend::GetStatus()
const {
333 status.is_active = active_;
334 status.is_resizing = is_resizing_;
337 SDL_WindowFlags flags = SDL_GetWindowFlags(window_.get());
338 status.is_minimized = (flags & SDL_WINDOW_MINIMIZED) != 0;
339 status.is_maximized = (flags & SDL_WINDOW_MAXIMIZED) != 0;
340 status.is_fullscreen = (flags & SDL_WINDOW_FULLSCREEN) != 0;
341 status.is_focused = (flags & SDL_WINDOW_INPUT_FOCUS) != 0;
343 SDL_GetWindowSize(window_.get(), &status.width, &status.height);
349void SDL3WindowBackend::GetSize(
int* width,
int* height)
const {
351 SDL_GetWindowSize(window_.get(), width, height);
360void SDL3WindowBackend::SetSize(
int width,
int height) {
362 SDL_SetWindowSize(window_.get(), width, height);
366std::string SDL3WindowBackend::GetTitle()
const {
368 const char* title = SDL_GetWindowTitle(window_.get());
369 return title ? title :
"";
374void SDL3WindowBackend::SetTitle(
const std::string& title) {
376 SDL_SetWindowTitle(window_.get(), title.c_str());
380bool SDL3WindowBackend::InitializeRenderer(gfx::IRenderer* renderer) {
381 if (!window_ || !renderer) {
385 if (renderer->GetBackendRenderer()) {
390 return renderer->Initialize(window_.get());
393absl::Status SDL3WindowBackend::InitializeImGui(gfx::IRenderer* renderer) {
394 if (imgui_initialized_) {
395 return absl::OkStatus();
399 return absl::InvalidArgumentError(
"Renderer is null");
402 IMGUI_CHECKVERSION();
403 ImGui::CreateContext();
405 ImGuiIO& io = ImGui::GetIO();
406 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
407 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
408 io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
412 io.ConfigMacOSXBehaviors =
true;
416 SDL_Renderer* sdl_renderer =
417 static_cast<SDL_Renderer*
>(renderer->GetBackendRenderer());
420 return absl::InternalError(
"Failed to get SDL renderer from IRenderer");
424 if (!ImGui_ImplSDL3_InitForSDLRenderer(window_.get(), sdl_renderer)) {
425 return absl::InternalError(
"ImGui_ImplSDL3_InitForSDLRenderer failed");
428 if (!ImGui_ImplSDLRenderer3_Init(sdl_renderer)) {
429 ImGui_ImplSDL3_Shutdown();
430 return absl::InternalError(
"ImGui_ImplSDLRenderer3_Init failed");
439 imgui_initialized_ =
true;
440 LOG_INFO(
"SDL3WindowBackend",
"ImGui initialized successfully");
441 return absl::OkStatus();
444void SDL3WindowBackend::ShutdownImGui() {
445 if (!imgui_initialized_) {
449 LOG_INFO(
"SDL3WindowBackend",
"Shutting down ImGui implementations...");
450 ImGui_ImplSDLRenderer3_Shutdown();
451 ImGui_ImplSDL3_Shutdown();
453 LOG_INFO(
"SDL3WindowBackend",
"Destroying ImGui context...");
454 ImGui::DestroyContext();
456 imgui_initialized_ =
false;
459void SDL3WindowBackend::NewImGuiFrame() {
460 if (!imgui_initialized_) {
464 ImGui_ImplSDLRenderer3_NewFrame();
465 ImGui_ImplSDL3_NewFrame();
468void SDL3WindowBackend::RenderImGui(gfx::IRenderer* renderer) {
469 if (!imgui_initialized_) {
477 SDL_Renderer* sdl_renderer =
478 static_cast<SDL_Renderer*
>(renderer->GetBackendRenderer());
480 ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), sdl_renderer);
485 ImGuiIO& io = ImGui::GetIO();
486 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
487 ImGui::UpdatePlatformWindows();
488 ImGui::RenderPlatformWindowsDefault();
#define LOG_WARN(category, format,...)
#define LOG_INFO(category, format,...)
bool g_window_is_resizing
absl::Status LoadPackageFonts()
#define g_window_is_resizing
#define RETURN_IF_ERROR(expr)