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"
29#define g_window_is_resizing yaze::core::g_window_is_resizing
39 LOG_WARN(
"SDL2WindowBackend",
"Already initialized, shutting down first");
44 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) != 0) {
45 return absl::InternalError(
46 absl::StrFormat(
"SDL_Init failed: %s", SDL_GetError()));
50 int screen_width = config.
width;
51 int screen_height = config.
height;
53 if (screen_width == 0 || screen_height == 0) {
55 SDL_DisplayMode display_mode;
56 if (SDL_GetCurrentDisplayMode(0, &display_mode) == 0) {
57 screen_width =
static_cast<int>(display_mode.w * config.
display_scale);
58 screen_height =
static_cast<int>(display_mode.h * config.
display_scale);
64 "Failed to get display mode, using defaults: %dx%d",
65 screen_width, screen_height);
72 flags |= SDL_WINDOW_RESIZABLE;
75 flags |= SDL_WINDOW_MAXIMIZED;
78 flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
81 flags |= SDL_WINDOW_ALLOW_HIGHDPI;
85 window_ = std::unique_ptr<SDL_Window, util::SDL_Deleter>(
86 SDL_CreateWindow(config.
title.c_str(), SDL_WINDOWPOS_UNDEFINED,
87 SDL_WINDOWPOS_UNDEFINED, screen_width, screen_height,
93 return absl::InternalError(
94 absl::StrFormat(
"SDL_CreateWindow failed: %s", SDL_GetError()));
98 const int audio_frequency = 48000;
99 const size_t buffer_size = (audio_frequency / 50) * 2;
100 audio_buffer_ = std::shared_ptr<int16_t>(
new int16_t[buffer_size],
101 std::default_delete<int16_t[]>());
104 "Initialized: %dx%d, audio buffer: %zu samples", screen_width,
105 screen_height, buffer_size);
109 return absl::OkStatus();
114 return absl::OkStatus();
130 LOG_INFO(
"SDL2WindowBackend",
"Shutting down graphics arena...");
135 LOG_INFO(
"SDL2WindowBackend",
"Destroying window...");
140 LOG_INFO(
"SDL2WindowBackend",
"Shutting down SDL...");
144 LOG_INFO(
"SDL2WindowBackend",
"Shutdown complete");
145 return absl::OkStatus();
150 if (SDL_PollEvent(&sdl_event)) {
153 ImGui_ImplSDL2_ProcessEvent(&sdl_event);
167 ImGui_ImplSDL2_ProcessEvent(
static_cast<SDL_Event*
>(native_event));
175 switch (sdl_event.type) {
183 event.key_code = sdl_event.key.keysym.sym;
184 event.scan_code = sdl_event.key.keysym.scancode;
194 event.key_code = sdl_event.key.keysym.sym;
195 event.scan_code = sdl_event.key.keysym.scancode;
203 case SDL_MOUSEMOTION:
205 event.mouse_x =
static_cast<float>(sdl_event.motion.x);
206 event.mouse_y =
static_cast<float>(sdl_event.motion.y);
209 case SDL_MOUSEBUTTONDOWN:
211 event.mouse_x =
static_cast<float>(sdl_event.button.x);
212 event.mouse_y =
static_cast<float>(sdl_event.button.y);
213 event.mouse_button = sdl_event.button.button;
216 case SDL_MOUSEBUTTONUP:
218 event.mouse_x =
static_cast<float>(sdl_event.button.x);
219 event.mouse_y =
static_cast<float>(sdl_event.button.y);
220 event.mouse_button = sdl_event.button.button;
225 event.wheel_x =
static_cast<float>(sdl_event.wheel.x);
226 event.wheel_y =
static_cast<float>(sdl_event.wheel.y);
231 if (sdl_event.drop.file) {
232 event.dropped_file = sdl_event.drop.file;
233 SDL_free(sdl_event.drop.file);
237 case SDL_WINDOWEVENT:
238 switch (sdl_event.window.event) {
239 case SDL_WINDOWEVENT_CLOSE:
244 case SDL_WINDOWEVENT_SIZE_CHANGED:
245 case SDL_WINDOWEVENT_RESIZED:
247 event.window_width = sdl_event.window.data1;
248 event.window_height = sdl_event.window.data2;
253 case SDL_WINDOWEVENT_MINIMIZED:
259 case SDL_WINDOWEVENT_MAXIMIZED:
263 case SDL_WINDOWEVENT_RESTORED:
269 case SDL_WINDOWEVENT_SHOWN:
275 case SDL_WINDOWEVENT_HIDDEN:
281 case SDL_WINDOWEVENT_EXPOSED:
287 case SDL_WINDOWEVENT_FOCUS_GAINED:
291 case SDL_WINDOWEVENT_FOCUS_LOST:
302 SDL_Keymod mod = SDL_GetModState();
315 Uint32 flags = SDL_GetWindowFlags(
window_.get());
316 status.
is_minimized = (flags & SDL_WINDOW_MINIMIZED) != 0;
317 status.
is_maximized = (flags & SDL_WINDOW_MAXIMIZED) != 0;
319 (flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)) != 0;
320 status.
is_focused = (flags & SDL_WINDOW_INPUT_FOCUS) != 0;
330 SDL_GetWindowSize(
window_.get(), width, height);
332 if (width) *width = 0;
333 if (height) *height = 0;
339 SDL_SetWindowSize(
window_.get(), width, height);
345 const char* title = SDL_GetWindowTitle(
window_.get());
346 return title ? title :
"";
353 SDL_SetWindowTitle(
window_.get(), title.c_str());
372 return absl::OkStatus();
376 return absl::InvalidArgumentError(
"Renderer is null");
379 IMGUI_CHECKVERSION();
380 ImGui::CreateContext();
382 ImGuiIO& io = ImGui::GetIO();
383 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
384 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
391 io.ConfigMacOSXBehaviors =
true;
392 LOG_INFO(
"SDL2WindowBackend",
"Enabled ConfigMacOSXBehaviors for macOS");
396 SDL_Renderer* sdl_renderer =
400 return absl::InternalError(
"Failed to get SDL renderer from IRenderer");
403 if (!ImGui_ImplSDL2_InitForSDLRenderer(
window_.get(), sdl_renderer)) {
404 return absl::InternalError(
"ImGui_ImplSDL2_InitForSDLRenderer failed");
407 if (!ImGui_ImplSDLRenderer2_Init(sdl_renderer)) {
408 ImGui_ImplSDL2_Shutdown();
409 return absl::InternalError(
"ImGui_ImplSDLRenderer2_Init failed");
419 LOG_INFO(
"SDL2WindowBackend",
"ImGui initialized successfully");
420 return absl::OkStatus();
428 LOG_INFO(
"SDL2WindowBackend",
"Shutting down ImGui implementations...");
429 ImGui_ImplSDLRenderer2_Shutdown();
430 ImGui_ImplSDL2_Shutdown();
432 LOG_INFO(
"SDL2WindowBackend",
"Destroying ImGui context...");
433 ImGui::DestroyContext();
443 ImGui_ImplSDLRenderer2_NewFrame();
444 ImGui_ImplSDL2_NewFrame();
459 SDL_Renderer* sdl_renderer =
462 ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), sdl_renderer);
467 ImGuiIO& io = ImGui::GetIO();
468 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
469 ImGui::UpdatePlatformWindows();
470 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.
#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.