9#include "absl/status/status.h"
10#include "absl/strings/str_format.h"
14#include "imgui/backends/imgui_impl_sdl2.h"
15#include "imgui/backends/imgui_impl_sdlrenderer2.h"
16#include "imgui/imgui.h"
30#define g_window_is_resizing yaze::core::g_window_is_resizing
40 LOG_WARN(
"SDL2WindowBackend",
"Already initialized, shutting down first");
45 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER |
46 SDL_INIT_GAMECONTROLLER) != 0) {
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) {
57 SDL_DisplayMode display_mode;
58 if (SDL_GetCurrentDisplayMode(0, &display_mode) == 0) {
59 screen_width =
static_cast<int>(display_mode.w * config.
display_scale);
60 screen_height =
static_cast<int>(display_mode.h * config.
display_scale);
66 "Failed to get display mode, using defaults: %dx%d",
67 screen_width, screen_height);
74 flags |= SDL_WINDOW_RESIZABLE;
77 flags |= SDL_WINDOW_MAXIMIZED;
80 flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
83 flags |= SDL_WINDOW_ALLOW_HIGHDPI;
86 flags |= SDL_WINDOW_HIDDEN;
90 window_ = std::unique_ptr<SDL_Window, util::SDL_Deleter>(
91 SDL_CreateWindow(config.
title.c_str(), SDL_WINDOWPOS_UNDEFINED,
92 SDL_WINDOWPOS_UNDEFINED, screen_width, screen_height,
98 return absl::InternalError(
99 absl::StrFormat(
"SDL_CreateWindow failed: %s", SDL_GetError()));
103 const int audio_frequency = 48000;
104 const size_t buffer_size = (audio_frequency / 50) * 2;
105 audio_buffer_ = std::shared_ptr<int16_t>(
new int16_t[buffer_size],
106 std::default_delete<int16_t[]>());
108 LOG_INFO(
"SDL2WindowBackend",
"Initialized: %dx%d, audio buffer: %zu samples",
109 screen_width, screen_height, buffer_size);
113 return absl::OkStatus();
118 return absl::OkStatus();
134 LOG_INFO(
"SDL2WindowBackend",
"Shutting down graphics arena...");
139 LOG_INFO(
"SDL2WindowBackend",
"Destroying window...");
144 LOG_INFO(
"SDL2WindowBackend",
"Shutting down SDL...");
148 LOG_INFO(
"SDL2WindowBackend",
"Shutdown complete");
149 return absl::OkStatus();
154 if (SDL_PollEvent(&sdl_event)) {
157 ImGui_ImplSDL2_ProcessEvent(&sdl_event);
171 return SDL_WaitEventTimeout(
nullptr, timeout_ms) == 1;
176 ImGui_ImplSDL2_ProcessEvent(
static_cast<SDL_Event*
>(native_event));
184 switch (sdl_event.type) {
191 event.key_code = sdl_event.key.keysym.sym;
192 event.scan_code = sdl_event.key.keysym.scancode;
202 event.key_code = sdl_event.key.keysym.sym;
203 event.scan_code = sdl_event.key.keysym.scancode;
211 case SDL_MOUSEMOTION:
213 event.mouse_x =
static_cast<float>(sdl_event.motion.x);
214 event.mouse_y =
static_cast<float>(sdl_event.motion.y);
217 case SDL_MOUSEBUTTONDOWN:
219 event.mouse_x =
static_cast<float>(sdl_event.button.x);
220 event.mouse_y =
static_cast<float>(sdl_event.button.y);
221 event.mouse_button = sdl_event.button.button;
224 case SDL_MOUSEBUTTONUP:
226 event.mouse_x =
static_cast<float>(sdl_event.button.x);
227 event.mouse_y =
static_cast<float>(sdl_event.button.y);
228 event.mouse_button = sdl_event.button.button;
233 event.wheel_x =
static_cast<float>(sdl_event.wheel.x);
234 event.wheel_y =
static_cast<float>(sdl_event.wheel.y);
239 if (sdl_event.drop.file) {
240 event.dropped_file = sdl_event.drop.file;
241 SDL_free(sdl_event.drop.file);
245 case SDL_WINDOWEVENT:
246 switch (sdl_event.window.event) {
247 case SDL_WINDOWEVENT_CLOSE:
251 case SDL_WINDOWEVENT_SIZE_CHANGED:
252 case SDL_WINDOWEVENT_RESIZED:
254 event.window_width = sdl_event.window.data1;
255 event.window_height = sdl_event.window.data2;
260 case SDL_WINDOWEVENT_MINIMIZED:
266 case SDL_WINDOWEVENT_MAXIMIZED:
270 case SDL_WINDOWEVENT_RESTORED:
276 case SDL_WINDOWEVENT_SHOWN:
282 case SDL_WINDOWEVENT_HIDDEN:
288 case SDL_WINDOWEVENT_EXPOSED:
294 case SDL_WINDOWEVENT_FOCUS_GAINED:
298 case SDL_WINDOWEVENT_FOCUS_LOST:
309 SDL_Keymod mod = SDL_GetModState();
322 Uint32 flags = SDL_GetWindowFlags(
window_.get());
323 status.
is_minimized = (flags & SDL_WINDOW_MINIMIZED) != 0;
324 status.
is_maximized = (flags & SDL_WINDOW_MAXIMIZED) != 0;
326 (flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)) != 0;
327 status.
is_focused = (flags & SDL_WINDOW_INPUT_FOCUS) != 0;
337 SDL_GetWindowSize(
window_.get(), width, height);
348 SDL_SetWindowSize(
window_.get(), width, height);
354 const char* title = SDL_GetWindowTitle(
window_.get());
355 return title ? title :
"";
362 SDL_SetWindowTitle(
window_.get(), title.c_str());
393 return absl::OkStatus();
397 return absl::InvalidArgumentError(
"Renderer is null");
400 IMGUI_CHECKVERSION();
401 ImGui::CreateContext();
403 ImGuiIO& io = ImGui::GetIO();
404 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
405 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
412 io.ConfigMacOSXBehaviors =
true;
413 LOG_INFO(
"SDL2WindowBackend",
"Enabled ConfigMacOSXBehaviors for macOS");
417 static std::string ini_path_str;
418 if (ini_path_str.empty()) {
419 ini_path_str = ini_path->string();
421 io.IniFilename = ini_path_str.c_str();
423 io.IniFilename =
nullptr;
424 LOG_WARN(
"SDL2WindowBackend",
"Failed to resolve ImGui ini path: %s",
425 ini_path.status().ToString().c_str());
429 SDL_Renderer* sdl_renderer =
433 return absl::InternalError(
"Failed to get SDL renderer from IRenderer");
436 if (!ImGui_ImplSDL2_InitForSDLRenderer(
window_.get(), sdl_renderer)) {
437 return absl::InternalError(
"ImGui_ImplSDL2_InitForSDLRenderer failed");
441 ImGui_ImplSDL2_Shutdown();
442 return absl::InternalError(
"ImGui_ImplSDLRenderer2_Init failed");
452 LOG_INFO(
"SDL2WindowBackend",
"ImGui initialized successfully");
453 return absl::OkStatus();
461 LOG_INFO(
"SDL2WindowBackend",
"Shutting down ImGui implementations...");
463 ImGui_ImplSDL2_Shutdown();
465 LOG_INFO(
"SDL2WindowBackend",
"Destroying ImGui context...");
466 ImGui::DestroyContext();
477 ImGui_ImplSDL2_NewFrame();
492 SDL_Renderer* sdl_renderer =
500 ImGuiIO& io = ImGui::GetIO();
501 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
502 ImGui::UpdatePlatformWindows();
503 ImGui::RenderPlatformWindowsDefault();
Defines an abstract interface for all rendering operations.
virtual bool Initialize(SDL_Window *window)=0
Initializes the renderer with a given window.
virtual void * GetBackendRenderer()=0
Provides an escape hatch to get the underlying, concrete renderer object.
void ImGui_ImplSDLRenderer2_NewFrame()
void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData *draw_data, SDL_Renderer *renderer)
bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer *renderer)
void ImGui_ImplSDLRenderer2_Shutdown()
#define LOG_WARN(category, format,...)
#define LOG_INFO(category, format,...)
bool g_window_is_resizing
absl::Status LoadPackageFonts()
#define g_window_is_resizing
SDL2/SDL3 compatibility layer.
#define RETURN_IF_ERROR(expr)
Deleter for SDL_Window and SDL_Renderer.