22#include " EditorHost.h"
33#include " AppSettings.h"
44
5- #include < SDL.h>
6- #include < SDL_opengl.h>
5+ #include < SDL3/SDL.h>
76
8- #include " imgui_impl_sdl2 .h"
7+ #include " imgui_impl_sdl3 .h"
98#include " imgui_impl_opengl3.h"
109
1110#include < cstdlib>
1211
1312#include " nfd.hpp"
14- #include " nfd_sdl2 .h"
13+ #include " nfd_sdl3 .h"
1514
1615using namespace doriax ;
1716
@@ -39,23 +38,23 @@ std::string editor::Backend::title;
3938static void hideEditorCursor () {
4039 ImGuiIO& io = ImGui::GetIO ();
4140 io.MouseDrawCursor = false ;
42- SDL_SetRelativeMouseMode ( SDL_FALSE );
43- SDL_SetWindowGrab (window, SDL_FALSE );
41+ SDL_SetWindowRelativeMouseMode (window, false );
42+ SDL_SetWindowMouseGrab (window, false );
4443 io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange;
4544 if (invisibleCursor) {
4645 SDL_SetCursor (invisibleCursor);
4746 }
48- SDL_ShowCursor ( SDL_DISABLE );
47+ SDL_HideCursor ( );
4948 gameCursorHidden = true ;
5049}
5150
5251static void showEditorCursor () {
5352 ImGuiIO& io = ImGui::GetIO ();
5453 io.MouseDrawCursor = false ;
5554
56- SDL_SetRelativeMouseMode ( SDL_FALSE );
57- SDL_SetWindowGrab (window, SDL_FALSE );
58- SDL_ShowCursor (SDL_ENABLE );
55+ SDL_SetWindowRelativeMouseMode (window, false );
56+ SDL_SetWindowMouseGrab (window, true );
57+ SDL_ShowCursor ();
5958 SDL_SetCursor (SDL_GetDefaultCursor ());
6059 io.ConfigFlags &= ~ImGuiConfigFlags_NoMouseCursorChange;
6160 gameCursorHidden = false ;
@@ -66,10 +65,10 @@ static void confineEditorCursor() {
6665 ImGuiIO& io = ImGui::GetIO ();
6766 io.MouseDrawCursor = false ;
6867 io.ConfigFlags &= ~ImGuiConfigFlags_NoMouseCursorChange;
69- SDL_SetRelativeMouseMode ( SDL_FALSE );
70- SDL_ShowCursor (SDL_ENABLE );
68+ SDL_SetWindowRelativeMouseMode (window, false );
69+ SDL_ShowCursor ();
7170 SDL_SetCursor (SDL_GetDefaultCursor ());
72- SDL_SetWindowGrab (window, SDL_TRUE );
71+ SDL_SetWindowMouseGrab (window, true );
7372 gameCursorHidden = false ;
7473}
7574
@@ -107,17 +106,22 @@ int editor::Backend::init(int argc, char* argv[]) {
107106 // (DISPLAY set), select the x11 driver. Respect an explicit user-provided
108107 // SDL_VIDEODRIVER. Must be set before SDL_Init().
109108 if (AppSettings::getMultiViewportEnabled () &&
110- getenv (" WAYLAND_DISPLAY" ) && getenv (" DISPLAY" ) && !getenv (" SDL_VIDEODRIVER" ))
111- setenv (" SDL_VIDEODRIVER" , " x11" , 1 );
109+ getenv (" WAYLAND_DISPLAY" ) &&
110+ getenv (" DISPLAY" ) &&
111+ !getenv (" SDL_VIDEODRIVER" )
112+ ) {
113+ SDL_SetHint (SDL_HINT_VIDEO_DRIVER , " x11" );
114+ }
112115#endif
113116
114117 // Initialize SDL
115- if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_TIMER ) != 0 ) {
118+ if (!SDL_Init (SDL_INIT_VIDEO )) {
119+ fprintf (stderr, " Error: SDL_Init failed: %s\n " , SDL_GetError ());
116120 return -1 ;
117121 }
118122
119123 if (NFD_Init () != NFD_OKAY ) {
120- printf ( " Error: NFD_Init failed: %s\n " , NFD_GetError ());
124+ fprintf (stderr, " Error: NFD_Init failed: %s\n " , NFD_GetError ());
121125 return -1 ;
122126 }
123127
@@ -142,37 +146,50 @@ int editor::Backend::init(int argc, char* argv[]) {
142146 // Get saved window dimensions from app
143147 int windowWidth = app.getInitialWindowWidth ();
144148 int windowHeight = app.getInitialWindowHeight ();
149+ int initWindowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY ;
145150
146151 // Create window with OpenGL context
147152 window = SDL_CreateWindow (
148- " Doriax Engine" ,
149- SDL_WINDOWPOS_CENTERED , SDL_WINDOWPOS_CENTERED ,
150- windowWidth, windowHeight,
151- SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI
153+ " Doriax Engine" , windowWidth, windowHeight, initWindowFlags
152154 );
153-
154155 if (!window) {
156+ fprintf (stderr, " Error: SDL_CreateWindow failed: %s\n " , SDL_GetError ());
155157 NFD_Quit ();
156158 SDL_Quit ();
157159 return -1 ;
158160 }
159161
162+ // Tell NFD to set the Wayland display (does nothing in other platforms)
163+ NFD_SetDisplayPropertiesFromSDLWindow (window);
164+
165+ // Get the scale of the window and not the display
166+ float window_scale = SDL_GetWindowDisplayScale (window);
167+
168+ if (window_scale == 0 .0f ) {
169+ window_scale = 1 .0f ;
170+ }
171+
160172 // Apply saved window state
161173 if (app.getInitialWindowMaximized ()) {
162174 SDL_MaximizeWindow (window);
163175 }
164176
165- SDL_Surface* cursorSurface = SDL_CreateRGBSurfaceWithFormat ( 0 , 16 , 16 , 32 , SDL_PIXELFORMAT_RGBA32 );
177+ SDL_Surface* cursorSurface = SDL_CreateSurface ( 16 , 16 , SDL_PIXELFORMAT_RGBA32 );
166178 if (cursorSurface) {
167179 SDL_memset (cursorSurface->pixels , 0 , cursorSurface->pitch * cursorSurface->h );
168180 invisibleCursor = SDL_CreateColorCursor (cursorSurface, 0 , 0 );
169- SDL_FreeSurface (cursorSurface);
181+ SDL_DestroySurface (cursorSurface);
170182 }
171183
172- NFD_GetNativeWindowFromSDLWindow (window, &nativeWindow);
184+ // We log information (not error) in case this fails
185+ if (NFD_GetNativeWindowFromSDLWindow (window, &nativeWindow) != NFD_OKAY ) {
186+ printf (" Warning: Could not get native window handle for file dialogs.\n " );
187+ nativeWindow.type = NFD_WINDOW_HANDLE_TYPE_UNSET ;
188+ }
173189
174190 SDL_GLContext glContext = SDL_GL_CreateContext (window);
175191 if (!glContext) {
192+ fprintf (stderr, " Error: SDL_GL_CreateContext failed: %s\n " , SDL_GetError ());
176193 SDL_DestroyWindow (window);
177194 NFD_Quit ();
178195 SDL_Quit ();
@@ -181,20 +198,29 @@ int editor::Backend::init(int argc, char* argv[]) {
181198
182199 SDL_GL_MakeCurrent (window, glContext);
183200 SDL_GL_SetSwapInterval (1 ); // Initial default; project/Wayland policy is applied below.
201+ SDL_SetWindowPosition (
202+ window, SDL_WINDOWPOS_CENTERED , SDL_WINDOWPOS_CENTERED
203+ );
204+ SDL_ShowWindow (window);
184205
185206 // Setup Dear ImGui context - MUST BE DONE BEFORE app.setup()
186207 IMGUI_CHECKVERSION ();
187208 ImGui::CreateContext ();
188209
210+ // Setup scaling
211+ ImGuiStyle& style = ImGui::GetStyle ();
212+ style.ScaleAllSizes (window_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
213+ style.FontScaleDpi = window_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
214+
189215 // Setup Platform/Renderer bindings - MUST BE DONE AFTER ImGui::CreateContext()
190- ImGui_ImplSDL2_InitForOpenGL (window, glContext);
216+ ImGui_ImplSDL3_InitForOpenGL (window, glContext);
191217 ImGui_ImplOpenGL3_Init (" #version 410" );
192218
193219 // Now we can safely call app.setup() which uses ImGui
194220 app.setup ();
195221 app.engineInit (argc, argv);
196222
197- SDL_ShowCursor ( SDL_DISABLE );
223+ SDL_HideCursor ( );
198224
199225 app.engineViewLoaded ();
200226
@@ -211,9 +237,10 @@ int editor::Backend::init(int argc, char* argv[]) {
211237 SDL_GL_SetSwapInterval (0 );
212238 }
213239 double framePeriod = 1.0 / 60.0 ;
214- SDL_DisplayMode displayMode;
215- if (SDL_GetCurrentDisplayMode (0 , &displayMode) == 0 && displayMode.refresh_rate > 0 ) {
216- framePeriod = 1.0 / displayMode.refresh_rate ;
240+ SDL_DisplayID displayID = SDL_GetDisplayForWindow (window);
241+ const SDL_DisplayMode* displayMode = SDL_GetCurrentDisplayMode (displayID);
242+ if (displayMode && displayMode->refresh_rate > 0 ) {
243+ framePeriod = 1.0 / displayMode->refresh_rate ;
217244 }
218245 const double perfFrequency = static_cast <double >(SDL_GetPerformanceFrequency ());
219246
@@ -231,23 +258,25 @@ int editor::Backend::init(int argc, char* argv[]) {
231258
232259 SDL_Event event;
233260 while (SDL_PollEvent (&event)) {
234- ImGui_ImplSDL2_ProcessEvent (&event);
235- if (event.type == SDL_QUIT ) {
261+ ImGui_ImplSDL3_ProcessEvent (&event);
262+ if (event.type == SDL_EVENT_QUIT ) {
236263 // Handle quit event, but don't close immediately
237264 app.exit ();
238265 }
239- if (event.type == SDL_WINDOWEVENT && event.window .event == SDL_WINDOWEVENT_CLOSE && event.window .windowID == SDL_GetWindowID (window)) {
266+ if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED &&
267+ event.window .windowID == SDL_GetWindowID (window))
268+ {
240269 // Handle window close event, but don't close immediately
241270 app.exit ();
242271 }
243- if (event.type == SDL_DROPBEGIN ) {
272+ if (event.type == SDL_EVENT_DROP_BEGIN ) {
244273 droppedPaths.clear ();
245274 }
246- if (event.type == SDL_DROPFILE ) {
247- droppedPaths.push_back (event.drop .file );
248- SDL_free (event.drop .file );
275+ if (event.type == SDL_EVENT_DROP_FILE ) {
276+ droppedPaths.push_back (event.drop .data );
277+ SDL_free (( void *) event.drop .data );
249278 }
250- if (event.type == SDL_DROPCOMPLETE ) {
279+ if (event.type == SDL_EVENT_DROP_COMPLETE ) {
251280 app.handleExternalDrop (droppedPaths);
252281 }
253282 }
@@ -261,6 +290,8 @@ int editor::Backend::init(int argc, char* argv[]) {
261290 // Skip presenting while minimized: SwapWindow of a hidden window can
262291 // block and stall clipboard + AI. Keep polling/updating so both keep
263292 // working.
293+ // On Wayland, "SDL_WINDOW_MINIMIZED" is not sent, when windows
294+ // are minimized, unless we call "SDL_MinimizeWindow()" manually.
264295 const Uint32 windowFlags = SDL_GetWindowFlags (window);
265296 const bool minimized = (windowFlags & SDL_WINDOW_MINIMIZED ) != 0 ;
266297
@@ -272,7 +303,8 @@ int editor::Backend::init(int argc, char* argv[]) {
272303 // unfocused so SwapWindow never blocks; the delay below then paces the idle
273304 // loop. On Wayland, project VSync is implemented by manual pacing.
274305 const bool focused = (windowFlags & SDL_WINDOW_INPUT_FOCUS ) != 0 ;
275- const bool frameSyncEnabled = !activeProject->isPlaySessionActive () || activeProject->isVSyncEnabled ();
306+ const bool frameSyncEnabled = !activeProject->isPlaySessionActive ()
307+ || activeProject->isVSyncEnabled ();
276308
277309 // Hand the cursor back to the editor while a play session isn't actively
278310 // running (paused or loading) so a game-held cursor lock can't trap the
@@ -281,10 +313,9 @@ int editor::Backend::init(int argc, char* argv[]) {
281313 // focus loss natively (as an exported game does), and folding focus in here
282314 // broke capture under multi-viewport, where the main window reports
283315 // unfocused whenever input is on a viewport panel. No-op outside a session.
284- setMouseControlSuspended (activeProject->isPlaySessionActive () &&
285- !activeProject->isMainScenePlaying ());
316+ setMouseControlSuspended (activeProject->isPlaySessionActive () && !activeProject->isMainScenePlaying ());
286317 if (!isWayland) {
287- const int desiredInterval = ( focused && frameSyncEnabled) ? 1 : 0 ;
318+ const int desiredInterval = focused && frameSyncEnabled;
288319 if (desiredInterval != currentSwapInterval) {
289320 SDL_GL_SetSwapInterval (desiredInterval);
290321 currentSwapInterval = desiredInterval;
@@ -293,14 +324,14 @@ int editor::Backend::init(int argc, char* argv[]) {
293324
294325 // Start the Dear ImGui frame
295326 ImGui_ImplOpenGL3_NewFrame ();
296- ImGui_ImplSDL2_NewFrame ();
327+ ImGui_ImplSDL3_NewFrame ();
297328 ImGui::NewFrame ();
298329
299330 if (!minimized) {
300331 app.engineRender ();
301332
302333 int display_w, display_h;
303- SDL_GL_GetDrawableSize (window, &display_w, &display_h);
334+ SDL_GetWindowSizeInPixels (window, &display_w, &display_h);
304335
305336 render.setClearColor (Vector4 (0 .45f , 0 .55f , 0 .60f , 1 .00f ));
306337 render.startRenderPass (display_w, display_h);
@@ -364,17 +395,17 @@ int editor::Backend::init(int argc, char* argv[]) {
364395
365396 // Cleanup
366397 ImGui_ImplOpenGL3_Shutdown ();
367- ImGui_ImplSDL2_Shutdown ();
398+ ImGui_ImplSDL3_Shutdown ();
368399 ImGui::DestroyContext ();
369400
370401 app.engineViewDestroyed ();
371402
372403 if (invisibleCursor) {
373- SDL_FreeCursor (invisibleCursor);
404+ SDL_DestroyCursor (invisibleCursor);
374405 invisibleCursor = nullptr ;
375406 }
376407
377- SDL_GL_DeleteContext (glContext);
408+ SDL_GL_DestroyContext (glContext);
378409 SDL_DestroyWindow (window);
379410 NFD_Quit ();
380411 SDL_Quit ();
@@ -397,9 +428,9 @@ void editor::Backend::disableMouseCursor() {
397428 SDL_SetCursor (invisibleCursor);
398429 }
399430
400- SDL_SetWindowGrab (window, SDL_FALSE );
401- SDL_ShowCursor (SDL_DISABLE );
402- SDL_SetRelativeMouseMode ( SDL_TRUE );
431+ SDL_SetWindowMouseGrab (window, true );
432+ SDL_ShowCursor ();
433+ SDL_SetWindowRelativeMouseMode (window, true );
403434}
404435
405436void editor::Backend::enableMouseCursor () {
0 commit comments