From 6a1ec78cfbc872f866e0b8fbf41554ba1809ee43 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Thu, 4 Sep 2025 17:38:12 +0200 Subject: [PATCH] Add SDL3 backend --- .github/workflows/build.yml | 14 +- CMakeLists.txt | 7 +- cmake/librw-config.cmake.in | 11 +- premake5.lua | 24 ++- skeleton/CMakeLists.txt | 3 +- skeleton/glfw.cpp | 2 +- skeleton/sdl3.cpp | 323 ++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 8 + src/gl/gl3device.cpp | 286 +++++++++++++++++++++++++++- src/gl/rwgl3.h | 13 +- src/gl/rwgl3impl.h | 17 +- tools/dumprwtree/CMakeLists.txt | 2 +- tools/ska2anm/CMakeLists.txt | 2 +- 13 files changed, 685 insertions(+), 27 deletions(-) create mode 100644 skeleton/sdl3.cpp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 18dbfcd..1187683 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,13 +16,15 @@ jobs: case: - { name: 'Windows (DirectX 9)', os: 'windows-latest', platform: 'D3D9' } - { name: 'Windows (GL3, glfw)', os: 'windows-latest', platform: 'GL3', gl3_gfxlib: 'GLFW' } - - { name: 'Windows (GL3, SDL2)', os: 'windows-latest', platform: 'GL3', gl3_gfxlib: 'SDL2' } + - { name: 'Windows (GL3, SDL2)', os: 'windows-latest', platform: 'GL3', gl3_gfxlib: 'SDL2', sdl-version: '2-latest' } + - { name: 'Windows (GL3, SDL3)', os: 'windows-latest', platform: 'GL3', gl3_gfxlib: 'SDL3', sdl-version: '3-latest' } - { name: 'Windows (null)', os: 'windows-latest', platform: 'NULL' } - { name: 'macOS (GL3, glfw)', os: 'macos-latest', platform: 'GL3', gl3_gfxlib: 'GLFW' } - - { name: 'macOS (GL3, SDL2)', os: 'macos-latest', platform: 'GL3', gl3_gfxlib: 'SDL2' } + - { name: 'macOS (GL3, SDL2)', os: 'macos-latest', platform: 'GL3', gl3_gfxlib: 'SDL2', sdl-version: '2-latest' } + - { name: 'macOS (GL3, SDL3)', os: 'macos-latest', platform: 'GL3', gl3_gfxlib: 'SDL3', sdl-version: '3-latest' } - { name: 'macOS (null)', os: 'macos-latest', platform: 'NULL' } - { name: 'Ubuntu (GL3, glfw)', os: 'ubuntu-latest', platform: 'GL3', gl3_gfxlib: 'GLFW' } - - { name: 'Ubuntu (GL3, SDL2)', os: 'ubuntu-latest', platform: 'GL3', gl3_gfxlib: 'SDL2' } + - { name: 'Ubuntu (GL3, SDL2)', os: 'ubuntu-latest', platform: 'GL3', gl3_gfxlib: 'SDL2', sdl-version: '2-latest' } - { name: 'Ubuntu (null)', os: 'ubuntu-latest', platform: 'NULL' } - { name: 'PlayStation 2', os: 'ubuntu-latest', platform: 'PS2', ps2: true, container: 'ps2dev/ps2dev:latest', cmake-toolchain-file: 'cmake/ps2/cmaketoolchain/toolchain_ps2_ee.cmake' } - { name: 'Nintendo Switch', os: 'ubuntu-latest', platform: 'GL3', gl3_gfxlib: 'GLFW', glfw-nobuild: true, container: 'devkitpro/devkita64:latest', cmake-toolchain-file: '/opt/devkitpro/cmake/Switch.cmake' } @@ -36,11 +38,11 @@ jobs: if: ${{ matrix.case.ps2 }} run: | apk add cmake gmp mpc1 mpfr4 make pkgconf git - - name: 'Setup SDL2' - if: ${{ matrix.case.gl3_gfxlib == 'SDL2' }} + - name: 'Setup SDL' + if: ${{ !!matrix.case.sdl-version }} uses: libsdl-org/setup-sdl@main with: - version: 2-latest + version: ${{ matrix.case.sdl-version }} install-linux-dependencies: true cmake-toolchain-file: ${{ matrix.case.cmake-toolchain-file }} - name: 'Setup GLFW' diff --git a/CMakeLists.txt b/CMakeLists.txt index a49cdf5..92e5796 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ if(NOT LIBRW_PLATFORM IN_LIST LIBRW_PLATFORMS) endif() if(LIBRW_PLATFORM_GL3) - set(LIBRW_GL3_GFXLIBS "GLFW" "SDL2") + set(LIBRW_GL3_GFXLIBS "GLFW" "SDL2" "SDL3") set(LIBRW_GL3_GFXLIB "GLFW" CACHE STRING "gfxlib for gl3 (choices=${LIBRW_GL3_GFXLIBS})") set_property(CACHE LIBRW_GL3_GFXLIB PROPERTY STRINGS ${LIBRW_GL3_GFXLIBS}) if(LIBRW_PLATFORM_GL3) @@ -91,6 +91,7 @@ if(LIBRW_INSTALL) EXPORT librw-targets NAMESPACE librw:: DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" ) + export(TARGETS librw NAMESPACE librw:: FILE librw-targets.cmake) if(LIBRW_GL3_GFXLIB STREQUAL "SDL2") install( @@ -126,8 +127,10 @@ if(LIBRW_INSTALL) elseif(LIBRW_PLATFORM_GL3) if(LIBRW_GL3_GFXLIB STREQUAL "GLFW") set(platform "-gl3-glfw") - else() + elseif(LIBRW_GL3_GFXLIB STREQUAL "SDL2") set(platform "-gl3-sdl2") + elseif(LIBRW_GL3_GFXLIB STREQUAL "SDL3") + set(platform "-gl3-sdl3") endif() elseif(LIBRW_PLATFORM_D3D9) set(platform "-d3d9") diff --git a/cmake/librw-config.cmake.in b/cmake/librw-config.cmake.in index 6cb7a8b..02163c8 100644 --- a/cmake/librw-config.cmake.in +++ b/cmake/librw-config.cmake.in @@ -14,16 +14,21 @@ if(LIBRW_PLATFORM_GL3) message(FATAL_ERROR "find_package(OpenGL) failed: no target was created") endif() + include(CMakeFindDependencyMacro) if(LIBRW_GL3_GFXLIB STREQUAL "GLFW") if (NOT TARGET glfw) - find_package(glfw3 REQUIRED) + find_dependency(glfw3 REQUIRED) endif() elseif(LIBRW_GL3_GFXLIB STREQUAL "SDL2") if (NOT TARGET SDL2::SDL2) - find_package(SDL2 CONFIG) + find_dependency(SDL2 CONFIG) if (NOT TARGET SDL2::SDL2) - find_package(SDL2 MODULE REQUIRED) + find_dependency(SDL2 MODULE REQUIRED) endif() endif() + elseif(LIBRW_GL3_GFXLIB STREQUAL "SDL3") + if (NOT TARGET SDL3::SDL3) + find_dependency(SDL3 CONFIG REQUIRED) + endif() endif() endif() diff --git a/premake5.lua b/premake5.lua index e9e7839..0cb4afa 100755 --- a/premake5.lua +++ b/premake5.lua @@ -6,6 +6,7 @@ newoption { allowed = { { "glfw", "GLFW" }, { "sdl2", "SDL2" }, + { "sdl3", "SDL3" }, }, } @@ -27,7 +28,14 @@ newoption { trigger = "sdl2dir", value = "PATH", description = "Directory of sdl2", - default = "../SDL2-2.0.14", + default = "../SDL2-2.32.10", +} + +newoption { + trigger = "sdl3dir", + value = "PATH", + description = "Directory of sdl3", + default = "../SDL3-3.2.22", } workspace "librw" @@ -64,6 +72,10 @@ workspace "librw" defines { "RW_GL3" } if _OPTIONS["gfxlib"] == "sdl2" then defines { "LIBRW_SDL2" } + elseif _OPTIONS["gfxlib"] == "sdl3" then + defines { "LIBRW_SDL3" } + elseif _OPTIONS["gfxlib"] == "glfw" then + defines { "LIBRW_GLFW" } end filter { "platforms:*d3d9" } defines { "RW_D3D9" } @@ -131,21 +143,27 @@ function findlibs() links { "GL" } if _OPTIONS["gfxlib"] == "glfw" then links { "glfw" } - else + elseif _OPTIONS["gfxlib"] == "sdl2" then links { "SDL2" } + elseif _OPTIONS["gfxlib"] == "sdl3" then + links { "SDL3" } end filter { "platforms:win-amd64-gl3" } libdirs { path.join(_OPTIONS["glfwdir64"], "lib-vc2015") } libdirs { path.join(_OPTIONS["sdl2dir"], "lib/x64") } + libdirs { path.join(_OPTIONS["sdl3dir"], "lib/x64") } filter { "platforms:win-x86-gl3" } libdirs { path.join(_OPTIONS["glfwdir32"], "lib-vc2015") } libdirs { path.join(_OPTIONS["sdl2dir"], "lib/x86") } + libdirs { path.join(_OPTIONS["sdl3dir"], "lib/x86") } filter { "platforms:win*gl3" } links { "opengl32" } if _OPTIONS["gfxlib"] == "glfw" then links { "glfw3" } - else + elseif _OPTIONS["gfxlib"] == "sdl2" then links { "SDL2" } + elseif _OPTIONS["gfxlib"] == "sdl3" then + links { "SDL3" } end filter { "platforms:*d3d9" } links { "gdi32", "d3d9" } diff --git a/skeleton/CMakeLists.txt b/skeleton/CMakeLists.txt index 0124fc4..d6956be 100644 --- a/skeleton/CMakeLists.txt +++ b/skeleton/CMakeLists.txt @@ -1,6 +1,7 @@ add_library(librw_skeleton glfw.cpp sdl2.cpp + sdl3.cpp skeleton.cpp skeleton.h win.cpp @@ -38,7 +39,7 @@ target_link_libraries(librw_skeleton librw ) -if (LIBRW_GL3_GFXLIB STREQUAL "SDL2") +if (LIBRW_GL3_GFXLIB MATCHES "SDL[23]") target_compile_definitions(librw_skeleton PRIVATE SDL_MAIN_HANDLED) endif() diff --git a/skeleton/glfw.cpp b/skeleton/glfw.cpp index 23832c0..cae9b9a 100644 --- a/skeleton/glfw.cpp +++ b/skeleton/glfw.cpp @@ -1,4 +1,4 @@ -#ifndef LIBRW_SDL2 +#ifdef LIBRW_GLFW #include #include "skeleton.h" diff --git a/skeleton/sdl3.cpp b/skeleton/sdl3.cpp new file mode 100644 index 0000000..fdceb0c --- /dev/null +++ b/skeleton/sdl3.cpp @@ -0,0 +1,323 @@ +#ifdef LIBRW_SDL3 + +#include +#include "skeleton.h" + +using namespace sk; +using namespace rw; + +#ifdef RW_OPENGL + +SDL_Window *window; + +static int keyCodeToSkKey(SDL_Keycode keycode) { + switch (keycode) { + case SDLK_SPACE: return ' '; + case SDLK_APOSTROPHE: return '\''; + case SDLK_COMMA: return ','; + case SDLK_MINUS: return '-'; + case SDLK_PERIOD: return '.'; + case SDLK_SLASH: return '/'; + + case SDLK_0: return '0'; + case SDLK_1: return '1'; + case SDLK_2: return '2'; + case SDLK_3: return '3'; + case SDLK_4: return '4'; + case SDLK_5: return '5'; + case SDLK_6: return '6'; + case SDLK_7: return '7'; + case SDLK_8: return '8'; + case SDLK_9: return '9'; + + case SDLK_SEMICOLON: return ';'; + case SDLK_EQUALS: return '='; + + case SDLK_A: return 'A'; + case SDLK_B: return 'B'; + case SDLK_C: return 'C'; + case SDLK_D: return 'D'; + case SDLK_E: return 'E'; + case SDLK_F: return 'F'; + case SDLK_G: return 'G'; + case SDLK_H: return 'H'; + case SDLK_I: return 'I'; + case SDLK_J: return 'J'; + case SDLK_K: return 'K'; + case SDLK_L: return 'L'; + case SDLK_M: return 'M'; + case SDLK_N: return 'N'; + case SDLK_O: return 'O'; + case SDLK_P: return 'P'; + case SDLK_Q: return 'Q'; + case SDLK_R: return 'R'; + case SDLK_S: return 'S'; + case SDLK_T: return 'T'; + case SDLK_U: return 'U'; + case SDLK_V: return 'V'; + case SDLK_W: return 'W'; + case SDLK_X: return 'X'; + case SDLK_Y: return 'Y'; + case SDLK_Z: return 'Z'; + + case SDLK_LEFTBRACKET: return '['; + case SDLK_BACKSLASH: return '\\'; + case SDLK_RIGHTBRACKET: return ']'; + case SDLK_GRAVE: return '`'; + case SDLK_ESCAPE: return KEY_ESC; + case SDLK_RETURN: return KEY_ENTER; + case SDLK_TAB: return KEY_TAB; + case SDLK_BACKSPACE: return KEY_BACKSP; + case SDLK_INSERT: return KEY_INS; + case SDLK_DELETE: return KEY_DEL; + case SDLK_RIGHT: return KEY_RIGHT; + case SDLK_LEFT: return KEY_LEFT; + case SDLK_DOWN: return KEY_DOWN; + case SDLK_UP: return KEY_UP; + case SDLK_PAGEUP: return KEY_PGUP; + case SDLK_PAGEDOWN: return KEY_PGDN; + case SDLK_HOME: return KEY_HOME; + case SDLK_END: return KEY_END; + case SDLK_CAPSLOCK: return KEY_CAPSLK; + case SDLK_SCROLLLOCK: return KEY_NULL; + case SDLK_NUMLOCKCLEAR: return KEY_NULL; + case SDLK_PRINTSCREEN: return KEY_NULL; + case SDLK_PAUSE: return KEY_NULL; + + case SDLK_F1: return KEY_F1; + case SDLK_F2: return KEY_F2; + case SDLK_F3: return KEY_F3; + case SDLK_F4: return KEY_F4; + case SDLK_F5: return KEY_F5; + case SDLK_F6: return KEY_F6; + case SDLK_F7: return KEY_F7; + case SDLK_F8: return KEY_F8; + case SDLK_F9: return KEY_F9; + case SDLK_F10: return KEY_F10; + case SDLK_F11: return KEY_F11; + case SDLK_F12: return KEY_F12; + case SDLK_F13: return KEY_NULL; + case SDLK_F14: return KEY_NULL; + case SDLK_F15: return KEY_NULL; + case SDLK_F16: return KEY_NULL; + case SDLK_F17: return KEY_NULL; + case SDLK_F18: return KEY_NULL; + case SDLK_F19: return KEY_NULL; + case SDLK_F20: return KEY_NULL; + case SDLK_F21: return KEY_NULL; + case SDLK_F22: return KEY_NULL; + case SDLK_F23: return KEY_NULL; + case SDLK_F24: return KEY_NULL; + + case SDLK_KP_0: return KEY_NULL; + case SDLK_KP_1: return KEY_NULL; + case SDLK_KP_2: return KEY_NULL; + case SDLK_KP_3: return KEY_NULL; + case SDLK_KP_4: return KEY_NULL; + case SDLK_KP_5: return KEY_NULL; + case SDLK_KP_6: return KEY_NULL; + case SDLK_KP_7: return KEY_NULL; + case SDLK_KP_8: return KEY_NULL; + case SDLK_KP_9: return KEY_NULL; + case SDLK_KP_DECIMAL: return KEY_NULL; + case SDLK_KP_DIVIDE: return KEY_NULL; + case SDLK_KP_MULTIPLY: return KEY_NULL; + case SDLK_KP_MINUS: return KEY_NULL; + case SDLK_KP_PLUS: return KEY_NULL; + case SDLK_KP_ENTER: return KEY_NULL; + case SDLK_KP_EQUALS: return KEY_NULL; + + case SDLK_LSHIFT: return KEY_LSHIFT; + case SDLK_LCTRL: return KEY_LCTRL; + case SDLK_LALT: return KEY_LALT; + case SDLK_LGUI: return KEY_NULL; + case SDLK_RSHIFT: return KEY_RSHIFT; + case SDLK_RCTRL: return KEY_RCTRL; + case SDLK_RALT: return KEY_RALT; + case SDLK_RGUI: return KEY_NULL; + case SDLK_MENU: return KEY_NULL; + } + return KEY_NULL; +} + +#if 0 +static void +keypress(SDL_Window *window, int key, int scancode, int action, int mods) +{ + if(key >= 0 && key <= GLFW_KEY_LAST){ + if(action == GLFW_RELEASE) KeyUp(keymap[key]); + else if(action == GLFW_PRESS) KeyDown(keymap[key]); + else if(action == GLFW_REPEAT) KeyDown(keymap[key]); + } +} + +static void +charinput(GLFWwindow *window, unsigned int c) +{ + EventHandler(CHARINPUT, (void*)(uintptr)c); +} + +static void +resize(GLFWwindow *window, int w, int h) +{ + rw::Rect r; + r.x = 0; + r.y = 0; + r.w = w; + r.h = h; + EventHandler(RESIZE, &r); +} + +static void +mousebtn(GLFWwindow *window, int button, int action, int mods) +{ + static int buttons = 0; + sk::MouseState ms; + + switch(button){ + case GLFW_MOUSE_BUTTON_LEFT: + if(action == GLFW_PRESS) + buttons |= 1; + else + buttons &= ~1; + break; + case GLFW_MOUSE_BUTTON_MIDDLE: + if(action == GLFW_PRESS) + buttons |= 2; + else + buttons &= ~2; + break; + case GLFW_MOUSE_BUTTON_RIGHT: + if(action == GLFW_PRESS) + buttons |= 4; + else + buttons &= ~4; + break; + } + + sk::MouseState ms; + ms.buttons = buttons; + EventHandler(MOUSEBTN, &ms); +} +#endif + +enum mousebutton { +BUTTON_LEFT = 0x1, +BUTTON_MIDDLE = 0x2, +BUTTON_RIGHT = 0x4, +}; + +int +main(int argc, char *argv[]) +{ + args.argc = argc; + args.argv = argv; + + if(EventHandler(INITIALIZE, nil) == EVENTERROR) + return 0; + + engineOpenParams.width = sk::globals.width; + engineOpenParams.height = sk::globals.height; + engineOpenParams.windowtitle = sk::globals.windowtitle; + engineOpenParams.window = &window; + + if(EventHandler(RWINITIALIZE, nil) == EVENTERROR) + return 0; + + Uint64 lastTicks = SDL_GetPerformanceCounter(); + const float tickPeriod = 1.f / SDL_GetPerformanceFrequency(); + SDL_Event event; + int mouseButtons = 0; + + SDL_StartTextInput(window); + + while(!sk::globals.quit){ + while(SDL_PollEvent(&event)){ + switch(event.type){ + case SDL_EVENT_QUIT: + sk::globals.quit = true; + break; + case SDL_EVENT_WINDOW_RESIZED: { + rw::Rect r; + SDL_GetWindowPosition(window, &r.x, &r.y); + r.w = event.window.data1; + r.h = event.window.data2; + EventHandler(RESIZE, &r); + break; + } + case SDL_EVENT_KEY_UP: { + int c = keyCodeToSkKey(event.key.key); + EventHandler(KEYUP, &c); + break; + } + case SDL_EVENT_KEY_DOWN: { + int c = keyCodeToSkKey(event.key.key); + EventHandler(KEYDOWN, &c); + break; + } + case SDL_EVENT_TEXT_INPUT: { + const char *c = event.text.text; + while (int ci = *c) { + EventHandler(CHARINPUT, (void*)(uintptr)ci); + ++c; + } + break; + } + case SDL_EVENT_MOUSE_MOTION: { + sk::MouseState ms; + ms.posx = event.motion.x; + ms.posy = event.motion.y; + EventHandler(MOUSEMOVE, &ms); + break; + } + case SDL_EVENT_MOUSE_BUTTON_DOWN: { + switch (event.button.button) { + case SDL_BUTTON_LEFT: mouseButtons |= BUTTON_LEFT; break; + case SDL_BUTTON_MIDDLE: mouseButtons |= BUTTON_MIDDLE; break; + case SDL_BUTTON_RIGHT: mouseButtons |= BUTTON_RIGHT; break; + } + sk::MouseState ms; + ms.buttons = mouseButtons; + EventHandler(MOUSEBTN, &ms); + break; + } + case SDL_EVENT_MOUSE_BUTTON_UP: { + switch (event.button.button) { + case SDL_BUTTON_LEFT: mouseButtons &= ~BUTTON_LEFT; break; + case SDL_BUTTON_MIDDLE: mouseButtons &= ~BUTTON_MIDDLE; break; + case SDL_BUTTON_RIGHT: mouseButtons &= ~BUTTON_RIGHT; break; + } + sk::MouseState ms; + ms.buttons = mouseButtons; + EventHandler(MOUSEBTN, &ms); + break; + } + } + } + Uint64 currTicks = SDL_GetPerformanceCounter(); + float timeDelta = (currTicks - lastTicks) * tickPeriod; + + EventHandler(IDLE, &timeDelta); + + lastTicks = currTicks; + } + + SDL_StopTextInput(window); + + EventHandler(RWTERMINATE, nil); + + return 0; +} + +namespace sk { + +void +SetMousePosition(int x, int y) +{ + SDL_WarpMouseInWindow(*engineOpenParams.window, x, y); +} + +} + +#endif +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 21c00ac..e9143b7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -153,6 +153,7 @@ if(LIBRW_PLATFORM_GL3) if (NOT TARGET glfw) find_package(glfw3 REQUIRED) endif() + target_compile_definitions(librw PUBLIC LIBRW_GLFW) target_link_libraries(librw PUBLIC glfw @@ -169,6 +170,13 @@ if(LIBRW_PLATFORM_GL3) PUBLIC SDL2::SDL2 ) + elseif (LIBRW_GL3_GFXLIB STREQUAL "SDL3") + find_package(SDL3 CONFIG REQUIRED) + target_compile_definitions(librw PUBLIC LIBRW_SDL3) + target_link_libraries(librw + PUBLIC + SDL3::SDL3 + ) endif() set(OpenGL_GL_PREFERENCE GLVND) diff --git a/src/gl/gl3device.cpp b/src/gl/gl3device.cpp index 6a4c8dd..3c5adf9 100644 --- a/src/gl/gl3device.cpp +++ b/src/gl/gl3device.cpp @@ -1246,8 +1246,12 @@ getFramebufferRect(Raster *frameBuffer) if(fb->type == Raster::CAMERA){ #ifdef LIBRW_SDL2 SDL_GetWindowSize(glGlobals.window, &r.w, &r.h); -#else +#elif defined(LIBRW_SDL3) + SDL_GetWindowSize(glGlobals.window, &r.w, &r.h); +#elif defined(LIBRW_GLFW) glfwGetFramebufferSize(glGlobals.window, &r.w, &r.h); +#else + missing implementation #endif }else{ r.w = fb->width; @@ -1412,12 +1416,20 @@ showRaster(Raster *raster, uint32 flags) else SDL_GL_SetSwapInterval(0); SDL_GL_SwapWindow(glGlobals.window); -#else +#elif defined(LIBRW_SDL3) + if(flags & Raster::FLIPWAITVSYNCH) + SDL_GL_SetSwapInterval(1); + else + SDL_GL_SetSwapInterval(0); + SDL_GL_SwapWindow(glGlobals.window); +#elif defined(LIBRW_GLFW) if(flags & Raster::FLIPWAITVSYNCH) glfwSwapInterval(1); else glfwSwapInterval(0); glfwSwapBuffers(glGlobals.window); +#else + not implemented #endif } @@ -1603,7 +1615,174 @@ stopSDL2(void) SDL_DestroyWindow(glGlobals.window); return 1; } -#else + +#elif defined(LIBRW_SDL3) + +static void +addVideoMode(const SDL_DisplayMode *mode) +{ + int i; + + for(i = 1; i < glGlobals.numModes; i++){ + if(glGlobals.modes[i].mode.w == mode->w && + glGlobals.modes[i].mode.h == mode->h && + glGlobals.modes[i].mode.format == mode->format){ + // had this mode already, remember highest refresh rate + if(mode->refresh_rate > glGlobals.modes[i].mode.refresh_rate) + glGlobals.modes[i].mode.refresh_rate = mode->refresh_rate; + return; + } + } + + // none found, add + glGlobals.modes[glGlobals.numModes].mode = *mode; + glGlobals.modes[glGlobals.numModes].flags = VIDEOMODEEXCLUSIVE; + glGlobals.numModes++; +} + +static void +makeVideoModeList(SDL_DisplayID displayIndex, SDL_DisplayID *displays) +{ + int i, num, depth; + const SDL_DisplayMode *currentMode; + SDL_DisplayMode **modes; + + currentMode = SDL_GetCurrentDisplayMode(displays[displayIndex]); + modes = SDL_GetFullscreenDisplayModes(displayIndex, &num); + + rwFree(glGlobals.modes); + glGlobals.modes = rwNewT(DisplayMode, num+(currentMode != NULL ? 1 : 0), ID_DRIVER | MEMDUR_EVENT); + + if (currentMode) { + glGlobals.modes[0].mode = *currentMode; + glGlobals.modes[0].flags = 0; + glGlobals.numModes = 1; + } + + for(i = 0; i < num; i++) + addVideoMode(modes[i]); + + for(i = 0; i < glGlobals.numModes; i++){ + depth = SDL_BITSPERPIXEL(glGlobals.modes[i].mode.format); + // set depth to power of two + for(glGlobals.modes[i].depth = 1; glGlobals.modes[i].depth < depth; glGlobals.modes[i].depth <<= 1); + } + SDL_free(modes); +} + +static int +openSDL3(EngineOpenParams *openparams) +{ + glGlobals.winWidth = openparams->width; + glGlobals.winHeight = openparams->height; + glGlobals.winTitle = openparams->windowtitle; + glGlobals.pWindow = openparams->window; + + memset(&gl3Caps, 0, sizeof(gl3Caps)); + + /* Init SDL */ + if (!SDL_InitSubSystem(SDL_INIT_VIDEO)){ + RWERROR((ERR_GENERAL, SDL_GetError())); + return 0; + } + + glGlobals.currentDisplay = 0; + SDL_DisplayID *displays = SDL_GetDisplays(&glGlobals.numDisplays); + + if (glGlobals.currentDisplay >= glGlobals.numDisplays) { + RWERROR((ERR_GENERAL, SDL_GetError())); + return 0; + } + + makeVideoModeList(glGlobals.currentDisplay, displays); + SDL_free(displays); + + return 1; +} + +static int +closeSDL3(void) +{ + SDL_QuitSubSystem(SDL_INIT_VIDEO); + return 1; +} + +static struct { + int gl; + int major, minor; +} profiles[] = { + { SDL_GL_CONTEXT_PROFILE_CORE, 3, 3 }, + { SDL_GL_CONTEXT_PROFILE_CORE, 2, 1 }, + { SDL_GL_CONTEXT_PROFILE_ES, 3, 1 }, + { SDL_GL_CONTEXT_PROFILE_ES, 2, 0 }, + { 0, 0, 0 }, +}; + +static int +startSDL3(void) +{ + SDL_Window *win; + SDL_GLContext ctx; + DisplayMode *mode; + + mode = &glGlobals.modes[glGlobals.currentMode]; + + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, glGlobals.numSamples); + + int i; + for(i = 0; profiles[i].gl; i++){ + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profiles[i].gl); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, profiles[i].major); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, profiles[i].minor); + + if(mode->flags & VIDEOMODEEXCLUSIVE) { + win = SDL_CreateWindow(glGlobals.winTitle, mode->mode.w, mode->mode.h, SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN); + if (win) + SDL_SetWindowFullscreenMode(win, &mode->mode); + } else { + win = SDL_CreateWindow(glGlobals.winTitle, glGlobals.winWidth, glGlobals.winHeight, SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL); + if (win) + SDL_SetWindowFullscreenMode(win, NULL); + } + if(win){ + gl3Caps.gles = profiles[i].gl == SDL_GL_CONTEXT_PROFILE_ES; + gl3Caps.glversion = profiles[i].major*10 + profiles[i].minor; + break; + } + } + if(win == nil){ + RWERROR((ERR_GENERAL, SDL_GetError())); + return 0; + } + ctx = SDL_GL_CreateContext(win); + + if (!((gl3Caps.gles ? gladLoadGLES2Loader : gladLoadGLLoader) ((GLADloadproc) SDL_GL_GetProcAddress, gl3Caps.glversion)) ) { + RWERROR((ERR_GENERAL, "gladLoadGLLoader failed")); + SDL_GL_DestroyContext(ctx); + SDL_DestroyWindow(win); + return 0; + } + + printf("OpenGL version: %s\n", glGetString(GL_VERSION)); + + glGlobals.window = win; + glGlobals.glcontext = ctx; + *glGlobals.pWindow = win; + glGlobals.presentWidth = 0; + glGlobals.presentHeight = 0; + glGlobals.presentOffX = 0; + glGlobals.presentOffY = 0; + return 1; +} + +static int +stopSDL3(void) +{ + SDL_GL_DestroyContext(glGlobals.glcontext); + SDL_DestroyWindow(glGlobals.window); + return 1; +} +#elif defined(LIBRW_GLFW) static void addVideoMode(const GLFWvidmode *mode) @@ -1767,6 +1946,8 @@ stopGLFW(void) glfwDestroyWindow(glGlobals.window); return 1; } +#else +not implemented #endif static int @@ -2007,7 +2188,94 @@ deviceSystemSDL2(DeviceReq req, void *arg, int32 n) return 1; } -#else +#elif defined(LIBRW_SDL3) + +static int +deviceSystemSDL3(DeviceReq req, void *arg, int32 n) +{ + VideoMode *rwmode; + + switch(req){ + case DEVICEOPEN: + return openSDL3((EngineOpenParams*)arg); + case DEVICECLOSE: + return closeSDL3(); + + case DEVICEINIT: + return startSDL3() && initOpenGL(); + case DEVICETERM: + return termOpenGL() && stopSDL3(); + + case DEVICEFINALIZE: + return finalizeOpenGL(); + + + case DEVICEGETNUMSUBSYSTEMS: + return glGlobals.numDisplays; + + case DEVICEGETCURRENTSUBSYSTEM: + return glGlobals.currentDisplay; + + case DEVICESETSUBSYSTEM: + if (n >= glGlobals.numDisplays) + return 0; + glGlobals.currentDisplay = n; + return 1; + + case DEVICEGETSUBSSYSTEMINFO: { + const char *display_name = SDL_GetDisplayName(n); + if (display_name == nil) + return 0; + strncpy(((SubSystemInfo*)arg)->name, display_name, sizeof(SubSystemInfo::name)); + return 1; + } + + + case DEVICEGETNUMVIDEOMODES: + return glGlobals.numModes; + + case DEVICEGETCURRENTVIDEOMODE: + return glGlobals.currentMode; + + case DEVICESETVIDEOMODE: + if(n >= glGlobals.numModes) + return 0; + glGlobals.currentMode = n; + return 1; + + case DEVICEGETVIDEOMODEINFO: + if (n <= 0) + return 0; + rwmode = (VideoMode*)arg; + rwmode->width = glGlobals.modes[n].mode.w; + rwmode->height = glGlobals.modes[n].mode.h; + rwmode->depth = glGlobals.modes[n].depth; + rwmode->flags = glGlobals.modes[n].flags; + return 1; + + case DEVICEGETMAXMULTISAMPLINGLEVELS: + { + GLint maxSamples; + glGetIntegerv(GL_MAX_SAMPLES, &maxSamples); + if(maxSamples == 0) + return 1; + return maxSamples; + } + case DEVICEGETMULTISAMPLINGLEVELS: + if(glGlobals.numSamples == 0) + return 1; + return glGlobals.numSamples; + case DEVICESETMULTISAMPLINGLEVELS: + glGlobals.numSamples = (uint32)n; + return 1; + default: + assert(0 && "not implemented"); + return 0; + } + return 1; +} + +#elif defined(LIBRW_GLFW) static int deviceSystemGLFW(DeviceReq req, void *arg, int32 n) @@ -2094,6 +2362,10 @@ deviceSystemGLFW(DeviceReq req, void *arg, int32 n) return 1; } +#else + +not implemented + #endif Device renderdevice = { @@ -2115,8 +2387,12 @@ Device renderdevice = { gl3::im3DEnd, #ifdef LIBRW_SDL2 gl3::deviceSystemSDL2 -#else +#elif defined(LIBRW_SDL3) + gl3::deviceSystemSDL3 +#elif defined(LIBRW_GLFW) gl3::deviceSystemGLFW +#else + not implemented #endif }; diff --git a/src/gl/rwgl3.h b/src/gl/rwgl3.h index 3275679..f7d963d 100644 --- a/src/gl/rwgl3.h +++ b/src/gl/rwgl3.h @@ -2,8 +2,12 @@ #include "glad/glad.h" #ifdef LIBRW_SDL2 #include -#else +#elif defined(LIBRW_SDL3) +#include +#elif defined(LIBRW_GLFW) #include +#else +not implemented #endif #endif @@ -15,8 +19,13 @@ struct EngineOpenParams #ifdef LIBRW_SDL2 SDL_Window **window; bool32 fullscreen; -#else +#elif defined(LIBRW_SDL3) + SDL_Window **window; + bool32 fullscreen; +#elif defined(LIBRW_GLFW) GLFWwindow **window; +#else + not implemented #endif int width, height; const char *windowtitle; diff --git a/src/gl/rwgl3impl.h b/src/gl/rwgl3impl.h index 6718a60..9d3be44 100644 --- a/src/gl/rwgl3impl.h +++ b/src/gl/rwgl3impl.h @@ -26,8 +26,12 @@ struct DisplayMode { #ifdef LIBRW_SDL2 SDL_DisplayMode mode; -#else +#elif defined(LIBRW_SDL3) + SDL_DisplayMode mode; +#elif defined(LIBRW_GLFW) GLFWvidmode mode; +#else + not implemented #endif int32 depth; uint32 flags; @@ -42,13 +46,22 @@ struct GlGlobals int numDisplays; int currentDisplay; -#else +#elif defined(LIBRW_SDL3) + SDL_Window **pWindow; + SDL_Window *window; + SDL_GLContext glcontext; + + int numDisplays; + int currentDisplay; +#elif defined(LIBRW_GLFW) GLFWwindow **pWindow; GLFWwindow *window; GLFWmonitor *monitor; int numMonitors; int currentMonitor; +#else + not implemented #endif DisplayMode *modes; diff --git a/tools/dumprwtree/CMakeLists.txt b/tools/dumprwtree/CMakeLists.txt index 16e50e1..092b3dd 100644 --- a/tools/dumprwtree/CMakeLists.txt +++ b/tools/dumprwtree/CMakeLists.txt @@ -7,7 +7,7 @@ target_link_libraries(dumprwtree librw::librw ) -if(LIBRW_GL3_GFXLIB STREQUAL "SDL2") +if(LIBRW_GL3_GFXLIB MATCHES "SDL[23]") target_compile_definitions(dumprwtree PRIVATE SDL_MAIN_HANDLED) endif() diff --git a/tools/ska2anm/CMakeLists.txt b/tools/ska2anm/CMakeLists.txt index 87e463e..9a315c2 100644 --- a/tools/ska2anm/CMakeLists.txt +++ b/tools/ska2anm/CMakeLists.txt @@ -7,7 +7,7 @@ target_link_libraries(ska2anm librw::librw ) -if(LIBRW_GL3_GFXLIB STREQUAL "SDL2") +if(LIBRW_GL3_GFXLIB MATCHES "SDL[23]") target_compile_definitions(ska2anm PRIVATE SDL_MAIN_HANDLED) endif()