Skip to content

Commit 3f70a05

Browse files
rempasRempas
andauthored
Updated NFD lib and ported SDL2 to SDL3 in the editor (#39)
* Initial work * Completed the editor and ready for testing! * Fixed the first erros and first build * Final version before PR! * One more change * Last fixes before the PR * (hopefully) removed editor_layout.ini from tracking --------- Co-authored-by: Rempas <rempas@tutanota.com>
1 parent 1ae80cc commit 3f70a05

16 files changed

Lines changed: 1473 additions & 418 deletions

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
.vscode
22
build
33
build-rel
4+
build-release
45
settings.yaml
6+
./editor_layout.ini
57

68
### Linux ###
79
*~
@@ -70,4 +72,4 @@ $RECYCLE.BIN/
7072
*.msp
7173

7274
# Windows shortcuts
73-
*.lnk
75+
*.lnk

CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,15 +146,15 @@ if(API_BACKEND STREQUAL "glfw")
146146
endif()
147147

148148
if(API_BACKEND STREQUAL "sdl")
149-
find_package(SDL2 REQUIRED)
149+
find_package(SDL3 REQUIRED)
150150

151151
list(APPEND BACKEND_SOURCES
152-
${IMGUI_DIR}/backends/imgui_impl_sdl2.cpp
152+
${IMGUI_DIR}/backends/imgui_impl_sdl3.cpp
153153
${EDITOR_DIR}/backend/BackendSDL.cpp
154154
)
155155

156156
list(APPEND BACKEND_LIBS
157-
${SDL2_LIBRARIES}
157+
${SDL3_LIBRARIES}
158158
)
159159
endif()
160160

editor/backend/BackendSDL.cpp

Lines changed: 81 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,15 @@
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

1615
using namespace doriax;
1716

@@ -39,23 +38,23 @@ std::string editor::Backend::title;
3938
static 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

5251
static 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

405436
void editor::Backend::enableMouseCursor() {

libs/nfd/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ endif ()
99
option(BUILD_SHARED_LIBS "Build a shared library instead of static" OFF)
1010
option(NFD_BUILD_TESTS "Build tests for nfd" ${nfd_ROOT_PROJECT})
1111
option(NFD_BUILD_SDL2_TESTS "Build SDL2 tests for nfd" OFF)
12+
option(NFD_BUILD_SDL3_TESTS "Build SDL3 tests for nfd" OFF)
1213
option(NFD_INSTALL "Generate install target for nfd" ${nfd_ROOT_PROJECT})
1314

1415
set(nfd_PLATFORM Undefined)
@@ -47,6 +48,6 @@ endif()
4748

4849
add_subdirectory(src)
4950

50-
if(${NFD_BUILD_TESTS} OR ${NFD_BUILD_SDL2_TESTS})
51+
if(${NFD_BUILD_TESTS} OR ${NFD_BUILD_SDL2_TESTS} OR ${NFD_BUILD_SDL3_TESTS})
5152
add_subdirectory(test)
5253
endif()

0 commit comments

Comments
 (0)