1
0
mirror of https://github.com/luanti-org/luanti.git synced 2025-11-19 16:15:19 +01:00

IrrlichtMt: Initial SDL3 support (#16583)

This commit implements support for SDL3, more specifically, >= 3.2.0 (the first released version).
Almost all changes were made according to https://github.com/libsdl-org/SDL/blob/release-3.2.10/docs/README-migration.md?plain=1 and the suggestions provided by `SDL3/SDL_oldnames.h`.
This commit is contained in:
SmallJoker
2025-11-17 20:55:52 +01:00
committed by GitHub
parent fcd96e9244
commit 36c261c1f0
12 changed files with 465 additions and 187 deletions

View File

@@ -23,6 +23,8 @@ General options and their default values:
PRECOMPILE_HEADERS=FALSE - Precompile some headers (experimental; requires CMake 3.16 or later)
PRECOMPILED_HEADERS_PATH= - Path to a file listing all headers to precompile (default points to src/precompiled_headers.txt)
USE_SDL2_STATIC=TRUE - Links with SDL2::SDL2-static instead of SDL2::SDL2
USE_SDL3=FALSE - Build with SDL3; Enables IrrlichtMt device SDL3 (experimental)
USE_SDL3_STATIC=TRUE - Links with SDL3::SDL3-static instead of SDL3::SDL3-shared
ENABLE_CURL=ON - Build with cURL; Enables use of online mod repo, public serverlist and remote media fetching via http
ENABLE_CURSES=ON - Build with (n)curses; Enables a server side terminal (command line option: --terminal)
ENABLE_GETTEXT=ON - Build with Gettext; Allows using translations

View File

@@ -11,15 +11,16 @@ Build
The build system is CMake.
The following libraries are required to be installed:
* zlib, libPNG, libJPEG
* OpenGL
* zlib, libPNG, libJPEG
* OpenGL
* or on mobile: OpenGL ES (can be optionally enabled on desktop too)
* SDL2
* SDL2 or SDL3 (see below)
Aside from standard search options (`ZLIB_INCLUDE_DIR`, `ZLIB_LIBRARY`, ...) the following options are available:
* `ENABLE_OPENGL` - Enable OpenGL driver
* `ENABLE_OPENGL3` - Enable OpenGL 3+ driver
* `ENABLE_GLES2` - Enable OpenGL ES 2+ driver
* `ENABLE_OPENGL` - Enable OpenGL driver
* `ENABLE_OPENGL3` - Enable OpenGL 3+ driver
* `ENABLE_GLES2` - Enable OpenGL ES 2+ driver
* `USE_SDL3` (default: `OFF`) - Use the SDL3 device instead of SDL2 (**experimental**)
**However, IrrlichtMt cannot be built or installed separately.**
@@ -34,6 +35,25 @@ We aim to support these platforms:
This doesn't mean other platforms don't work or won't be supported, if you find something that doesn't work contributions are welcome.
Compatibility matrix
--------------------
Driver (rows) vs Device (columns)
| | SDL2 [1] | SDL3 [2] |
|---------------------------|----------|----------|
| OpenGL 1.2 (to 2.1) | Works | Testing |
| OpenGL 3.2+ | Works | Works |
| OpenGL ES 2.x | Works | Testing |
| WebGL 1 | ? | ? |
| Null (no graphics output) | Works | Works |
Notes:
* [1] `CIrrDeviceSDL` with `USE_SDL3=0`: supports [many platforms](https://wiki.libsdl.org/SDL3/README-platforms)
* [2] `CIrrDeviceSDL` with `USE_SDL3=1`
License
-------

View File

@@ -14,7 +14,8 @@ enum E_DEVICE_TYPE
EIDT_OSX,
//! A device which uses Simple DirectMedia Layer
/** The SDL device works under all platforms supported by SDL. */
/** The SDL device works under all platforms supported by SDL2 or SDL3.
See also: CMake option 'USE_SDL3' */
EIDT_SDL,
//! This selection allows Irrlicht to choose the best device from the ones available.

View File

@@ -361,6 +361,7 @@ public:
\return The corresponding keycode.
*/
virtual Keycode getKeyFromScancode(const u32 scancode) const {
return Keycode(KEY_UNKNOWN, (wchar_t)scancode);
(void)scancode;
return Keycode(KEY_UNKNOWN, (wchar_t)0xFFFF);
}
};

View File

@@ -17,7 +17,12 @@
#include "Keycodes.h"
#include "COSOperator.h"
#include "SIrrCreationParameters.h"
#ifdef _IRR_USE_SDL3_
#include <SDL3/SDL_version.h>
#else
#include <SDL_video.h>
#endif
#include <cstdio>
#include <cstdlib>
@@ -29,6 +34,72 @@
#include "CSDLManager.h"
#ifndef _IRR_USE_SDL3_
// SDL2 backwards compatibility for things that were renamed in SDL3.
#define SDL_KMOD_SHIFT KMOD_SHIFT
#define SDL_KMOD_CTRL KMOD_CTRL
#define SDL_KMOD_NUM KMOD_NUM
#define SDL_TextInputActive(unused) SDL_IsTextInputActive()
#define SDL_CloseJoystick SDL_JoystickClose
#define SDL_GL_DestroyContext SDL_GL_DeleteContext
#define SDL_WINDOW_HIGH_PIXEL_DENSITY SDL_WINDOW_ALLOW_HIGHDPI
#define SDL_StartTextInput(unused) SDL_StartTextInput()
#define SDL_StopTextInput(unused) SDL_StopTextInput()
#define SDL_EVENT_MOUSE_MOTION SDL_MOUSEMOTION
#define SDL_EVENT_MOUSE_WHEEL SDL_MOUSEWHEEL
#define SDL_EVENT_MOUSE_BUTTON_DOWN SDL_MOUSEBUTTONDOWN
#define SDL_EVENT_MOUSE_BUTTON_UP SDL_MOUSEBUTTONUP
#define SDL_EVENT_TEXT_INPUT SDL_TEXTINPUT
#define SDL_EVENT_KEY_DOWN SDL_KEYDOWN
#define SDL_EVENT_KEY_UP SDL_KEYUP
#define SDL_EVENT_QUIT SDL_QUIT
#define SDL_EVENT_USER SDL_USEREVENT
#define SDL_EVENT_FINGER_DOWN SDL_FINGERDOWN
#define SDL_EVENT_FINGER_MOTION SDL_FINGERMOTION
#define SDL_EVENT_FINGER_UP SDL_FINGERUP
#define SDL_EVENT_WILL_ENTER_BACKGROUND SDL_APP_WILLENTERBACKGROUND
#define SDL_EVENT_WILL_ENTER_FOREGROUND SDL_APP_WILLENTERFOREGROUND
#define SDL_EVENT_RENDER_TARGETS_RESET SDL_RENDER_TARGETS_RESET
#define SDL_EVENT_RENDER_DEVICE_LOST SDL_RENDER_DEVICE_RESET
#define SDL_UpdateJoysticks SDL_JoystickUpdate
#define SDL_GetNumJoystickButtons SDL_JoystickNumButtons
#define SDL_GetNumJoystickAxes SDL_JoystickNumAxes
#define SDL_GetJoystickButton SDL_JoystickGetButton
#define SDL_GetJoystickAxis SDL_JoystickGetAxis
#define SDL_GetNumJoystickHats SDL_JoystickNumHats
#define SDL_GetJoystickHat SDL_JoystickGetHat
#define SDL_OpenJoystick SDL_JoystickOpen
#define SDL_GetJoystickName SDL_JoystickName
#define SDL_GetWindowSizeInPixels SDL_GL_GetDrawableSize
#define SDL_DestroySurface SDL_FreeSurface
#define SDL_SYSTEM_CURSOR_DEFAULT SDL_SYSTEM_CURSOR_ARROW
#define SDL_SYSTEM_CURSOR_POINTER SDL_SYSTEM_CURSOR_HAND
#define SDL_SYSTEM_CURSOR_TEXT SDL_SYSTEM_CURSOR_IBEAM
#define SDL_SYSTEM_CURSOR_NOT_ALLOWED SDL_SYSTEM_CURSOR_NO
#define SDL_SYSTEM_CURSOR_MOVE SDL_SYSTEM_CURSOR_SIZEALL
#define SDL_SYSTEM_CURSOR_NESW_RESIZE SDL_SYSTEM_CURSOR_SIZENESW
#define SDL_SYSTEM_CURSOR_NWSE_RESIZE SDL_SYSTEM_CURSOR_SIZENWSE
#define SDL_SYSTEM_CURSOR_NS_RESIZE SDL_SYSTEM_CURSOR_SIZENS
#define SDL_SYSTEM_CURSOR_EW_RESIZE SDL_SYSTEM_CURSOR_SIZEWE
#endif
#ifdef _IRR_USE_SDL3_
#define SDL_FINGER_ID(ev) ((ev).tfinger.fingerID)
#else
#define SDL_FINGER_ID(ev) ((ev).tfinger.fingerId)
#endif
// Since SDL doesn't have mouse keys as keycodes we need to fall back to EKEY_CODE in some cases.
static inline bool is_fake_key(EKEY_CODE key) {
switch (key) {
@@ -158,7 +229,7 @@ bool CIrrDeviceSDL::keyIsKnownSpecial(EKEY_CODE irrlichtKey)
}
}
int CIrrDeviceSDL::findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtKey, bool numlock)
wchar_t CIrrDeviceSDL::findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtKey, u16 keymod)
{
switch (irrlichtKey) {
// special cases that always return a char regardless of how the SDL keycode
@@ -184,7 +255,7 @@ int CIrrDeviceSDL::findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtK
break;
}
if (numlock) {
if (keymod & SDL_KMOD_NUM) {
// Number keys on the numpad are also affected, but we only want them
// to produce number chars when numlock is enabled.
switch (irrlichtKey) {
@@ -252,15 +323,32 @@ std::variant<u32, EKEY_CODE> CIrrDeviceSDL::getScancodeFromKey(const Keycode &ke
} else {
keynum = std::get<wchar_t>(key);
}
// SDL3 returns a valid scancode for keycode 0. This is undesired.
if (keynum == 0)
return (u32) 0;
#ifdef _IRR_USE_SDL3_
SDL_Keymod kmod = SDL_KMOD_NONE; // TODO: respect modifiers
return (u32)SDL_GetScancodeFromKey(keynum, &kmod);
#else
// Modifiers not supported
return (u32)SDL_GetScancodeFromKey(keynum);
#endif
}
Keycode CIrrDeviceSDL::getKeyFromScancode(const u32 scancode) const
{
#ifdef _IRR_USE_SDL3_
// TODO: SDL_HINT_KEYCODE_OPTIONS ?
auto keycode = SDL_GetKeyFromScancode((SDL_Scancode)scancode, SDL_KMOD_NONE, true);
#else
// Modifiers not supported
auto keycode = SDL_GetKeyFromScancode((SDL_Scancode)scancode);
#endif
const auto &keyentry = KeyMap.find(keycode);
auto irrcode = keyentry != KeyMap.end() ? keyentry->second : KEY_UNKNOWN;
auto keychar = findCharToPassToIrrlicht(keycode, irrcode, false);
wchar_t keychar = findCharToPassToIrrlicht(keycode, irrcode, false);
return Keycode(irrcode, keychar);
}
@@ -273,18 +361,22 @@ void CIrrDeviceSDL::resetReceiveTextInputEvents()
// sent as text input events instead of the result) when
// SDL_StartTextInput() is called on the same input box.
core::rect<s32> pos = elem->getAbsolutePosition();
if (!SDL_IsTextInputActive() || lastElemPos != pos) {
if (!SDL_TextInputActive(Window) || lastElemPos != pos) {
lastElemPos = pos;
SDL_Rect rect;
rect.x = pos.UpperLeftCorner.X;
rect.y = pos.UpperLeftCorner.Y;
rect.w = pos.getWidth();
rect.h = pos.getHeight();
#ifdef _IRR_USE_SDL3_
SDL_SetTextInputArea(Window, &rect, 10);
#else
SDL_SetTextInputRect(&rect);
SDL_StartTextInput();
#endif
SDL_StartTextInput(Window);
}
} else {
SDL_StopTextInput();
SDL_StopTextInput(Window);
}
}
@@ -302,7 +394,9 @@ CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters &param) :
// Blocking on pause causes problems with multiplayer.
// see <https://github.com/luanti-org/luanti/issues/10842>
SDL_SetHint(SDL_HINT_ANDROID_BLOCK_ON_PAUSE, "0");
#ifndef _IRR_USE_SDL3_
SDL_SetHint(SDL_HINT_ANDROID_BLOCK_ON_PAUSE_PAUSEAUDIO, "0");
#endif // SDL3: Handled automatically
SDL_SetHint(SDL_HINT_ANDROID_TRAP_BACK_BUTTON, "1");
@@ -319,14 +413,16 @@ CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters &param) :
#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
// These are not interesting for our use
#ifndef _IRR_USE_SDL3_
SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
#endif // SDL3: Removed hint
SDL_SetHint(SDL_HINT_TV_REMOTE_AS_JOYSTICK, "0");
#endif
#if SDL_VERSION_ATLEAST(2, 24, 0)
#if SDL_VERSION_ATLEAST(2, 24, 0) && !SDL_VERSION_ATLEAST(3, 0, 0)
// highdpi support on Windows
SDL_SetHint(SDL_HINT_WINDOWS_DPI_SCALING, "1");
#endif
#endif // SDL3: Removed hint
// Minetest has its own code to synthesize mouse events from touch events,
// so we prevent SDL from doing it.
@@ -338,18 +434,33 @@ CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters &param) :
#endif
// Set IME hints
#ifdef _IRR_USE_SDL3_
SDL_SetHint(SDL_HINT_IME_IMPLEMENTED_UI, "0");
#else
SDL_SetHint(SDL_HINT_IME_INTERNAL_EDITING, "1");
#endif
#if defined(SDL_HINT_IME_SHOW_UI)
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
#endif
u32 flags = SDL_INIT_TIMER | SDL_INIT_EVENTS;
// Initialize SDL
u32 flags = SDL_INIT_EVENTS;
#ifndef _IRR_USE_SDL3_
flags |= SDL_INIT_TIMER;
#endif
if (CreationParams.DriverType != video::EDT_NULL)
flags |= SDL_INIT_VIDEO;
#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
flags |= SDL_INIT_JOYSTICK;
#endif
if (SDL_Init(flags) < 0) {
#ifdef _IRR_USE_SDL3_
if (!SDL_Init(flags))
#else
if (SDL_Init(flags) < 0)
#endif
{
os::Printer::log("Unable to initialize SDL", SDL_GetError(), ELL_ERROR);
Close = true;
}
@@ -368,18 +479,7 @@ CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters &param) :
core::stringc sdlver = "SDL ";
{
SDL_version v{};
SDL_GetVersion(&v);
sdlver += v.major;
sdlver += ".";
sdlver += v.minor;
sdlver += ".";
sdlver += v.patch;
// the SDL team seems to intentionally number sdl2-compat this way:
// <https://github.com/libsdl-org/sdl2-compat/tags>
if (v.patch >= 50)
sdlver += " (compat)";
sdlver += getVersionString();
sdlver += " on ";
sdlver += SDL_GetPlatform();
}
@@ -407,11 +507,11 @@ CIrrDeviceSDL::~CIrrDeviceSDL()
#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
const u32 numJoysticks = Joysticks.size();
for (u32 i = 0; i < numJoysticks; ++i)
SDL_JoystickClose(Joysticks[i]);
SDL_CloseJoystick(Joysticks[i]);
#endif
if (Window && Context) {
SDL_GL_MakeCurrent(Window, NULL);
SDL_GL_DeleteContext(Context);
SDL_GL_DestroyContext(Context);
}
if (Window) {
SDL_DestroyWindow(Window);
@@ -532,9 +632,11 @@ bool CIrrDeviceSDL::createWindow()
bool CIrrDeviceSDL::createWindowWithContext()
{
u32 SDL_Flags = 0;
SDL_Flags |= SDL_WINDOW_ALLOW_HIGHDPI;
SDL_Flags |= SDL_WINDOW_HIGH_PIXEL_DENSITY;
#ifndef _IRR_USE_SDL3_
SDL_Flags |= getFullscreenFlag(CreationParams.Fullscreen);
#endif
if (Resizable)
SDL_Flags |= SDL_WINDOW_RESIZABLE;
if (CreationParams.WindowMaximized)
@@ -629,7 +731,11 @@ bool CIrrDeviceSDL::createWindowWithContext()
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
}
#ifdef _IRR_USE_SDL3_
Window = SDL_CreateWindow("", Width, Height, SDL_Flags);
#else
Window = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Width, Height, SDL_Flags);
#endif
if (!Window) {
os::Printer::log("Could not create window", SDL_GetError(), ELL_WARNING);
return false;
@@ -643,6 +749,11 @@ bool CIrrDeviceSDL::createWindowWithContext()
return false;
}
#ifdef _IRR_USE_SDL3_
if (CreationParams.Fullscreen)
SDL_SetWindowFullscreen(Window, true);
#endif
updateSizeAndScale();
if (ScaleX != 1.0f || ScaleY != 1.0f) {
// The given window size is in pixels, not in screen coordinates.
@@ -708,12 +819,33 @@ bool CIrrDeviceSDL::run()
SEvent irrevent;
SDL_Event SDL_event;
auto get_touch_id_x_y = [this, &irrevent, &SDL_event]() {
irrevent.TouchInput.ID = SDL_FINGER_ID(SDL_event);
irrevent.TouchInput.X = static_cast<s32>(SDL_event.tfinger.x * Width);
irrevent.TouchInput.Y = static_cast<s32>(SDL_event.tfinger.y * Height);
};
auto handle_window_resize_event = [this, &irrevent]() {
u32 old_w = Width, old_h = Height;
f32 old_scale_x = ScaleX, old_scale_y = ScaleY;
updateSizeAndScale();
if (old_w != Width || old_h != Height) {
if (VideoDriver)
VideoDriver->OnResize(core::dimension2d<u32>(Width, Height));
}
if (old_scale_x != ScaleX || old_scale_y != ScaleY) {
irrevent.EventType = EET_APPLICATION_EVENT;
irrevent.ApplicationEvent.EventType = EAET_DPI_CHANGED;
postEventFromUser(irrevent);
}
};
while (!Close && wrap_PollEvent(&SDL_event)) {
// os::Printer::log("event: ", core::stringc((int)SDL_event.type).c_str(), ELL_INFORMATION); // just for debugging
irrevent = {};
switch (SDL_event.type) {
case SDL_MOUSEMOTION: {
case SDL_EVENT_MOUSE_MOTION: {
SDL_Keymod keymod = SDL_GetModState();
irrevent.EventType = EET_MOUSE_INPUT_EVENT;
@@ -721,7 +853,12 @@ bool CIrrDeviceSDL::run()
MouseXRel = static_cast<s32>(SDL_event.motion.xrel * ScaleX);
MouseYRel = static_cast<s32>(SDL_event.motion.yrel * ScaleY);
if (!SDL_GetRelativeMouseMode()) {
#ifdef _IRR_USE_SDL3_
if (!SDL_GetWindowRelativeMouseMode(Window))
#else
if (!SDL_GetRelativeMouseMode())
#endif
{
MouseX = static_cast<s32>(SDL_event.motion.x * ScaleX);
MouseY = static_cast<s32>(SDL_event.motion.y * ScaleY);
} else {
@@ -732,25 +869,27 @@ bool CIrrDeviceSDL::run()
irrevent.MouseInput.Y = MouseY;
irrevent.MouseInput.ButtonStates = MouseButtonStates;
irrevent.MouseInput.Shift = (keymod & KMOD_SHIFT) != 0;
irrevent.MouseInput.Control = (keymod & KMOD_CTRL) != 0;
irrevent.MouseInput.Shift = (keymod & SDL_KMOD_SHIFT) != 0;
irrevent.MouseInput.Control = (keymod & SDL_KMOD_CTRL) != 0;
postEventFromUser(irrevent);
break;
}
case SDL_MOUSEWHEEL: {
case SDL_EVENT_MOUSE_WHEEL: {
SDL_Keymod keymod = SDL_GetModState();
irrevent.EventType = EET_MOUSE_INPUT_EVENT;
irrevent.MouseInput.Event = EMIE_MOUSE_WHEEL;
#if SDL_VERSION_ATLEAST(2, 0, 18)
#ifdef _IRR_USE_SDL3_
irrevent.MouseInput.Wheel = SDL_event.wheel.y;
#elif SDL_VERSION_ATLEAST(2, 0, 18)
irrevent.MouseInput.Wheel = SDL_event.wheel.preciseY;
#else
irrevent.MouseInput.Wheel = SDL_event.wheel.y;
#endif
irrevent.MouseInput.ButtonStates = MouseButtonStates;
irrevent.MouseInput.Shift = (keymod & KMOD_SHIFT) != 0;
irrevent.MouseInput.Control = (keymod & KMOD_CTRL) != 0;
irrevent.MouseInput.Shift = (keymod & SDL_KMOD_SHIFT) != 0;
irrevent.MouseInput.Control = (keymod & SDL_KMOD_CTRL) != 0;
irrevent.MouseInput.X = MouseX;
irrevent.MouseInput.Y = MouseY;
@@ -761,8 +900,8 @@ bool CIrrDeviceSDL::run()
postEventFromUser(irrevent);
break;
}
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP: {
case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP: {
SDL_Keymod keymod = SDL_GetModState();
irrevent.EventType = EET_MOUSE_INPUT_EVENT;
@@ -801,7 +940,7 @@ bool CIrrDeviceSDL::run()
#endif
switch (button) {
case SDL_BUTTON_LEFT:
if (SDL_event.type == SDL_MOUSEBUTTONDOWN) {
if (SDL_event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
irrevent.MouseInput.Event = EMIE_LMOUSE_PRESSED_DOWN;
MouseButtonStates |= EMBSM_LEFT;
} else {
@@ -811,7 +950,7 @@ bool CIrrDeviceSDL::run()
break;
case SDL_BUTTON_RIGHT:
if (SDL_event.type == SDL_MOUSEBUTTONDOWN) {
if (SDL_event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
irrevent.MouseInput.Event = EMIE_RMOUSE_PRESSED_DOWN;
MouseButtonStates |= EMBSM_RIGHT;
} else {
@@ -821,7 +960,7 @@ bool CIrrDeviceSDL::run()
break;
case SDL_BUTTON_MIDDLE:
if (SDL_event.type == SDL_MOUSEBUTTONDOWN) {
if (SDL_event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
irrevent.MouseInput.Event = EMIE_MMOUSE_PRESSED_DOWN;
MouseButtonStates |= EMBSM_MIDDLE;
} else {
@@ -844,8 +983,8 @@ bool CIrrDeviceSDL::run()
break;
}
bool shift = (keymod & KMOD_SHIFT) != 0;
bool control = (keymod & KMOD_CTRL) != 0;
bool shift = (keymod & SDL_KMOD_SHIFT) != 0;
bool control = (keymod & SDL_KMOD_CTRL) != 0;
if (irrevent.EventType == EET_MOUSE_INPUT_EVENT && irrevent.MouseInput.Event != EMIE_MOUSE_MOVED) {
irrevent.MouseInput.ButtonStates = MouseButtonStates;
irrevent.MouseInput.X = static_cast<s32>(SDL_event.button.x * ScaleX);
@@ -866,7 +1005,7 @@ bool CIrrDeviceSDL::run()
}
} else if (irrevent.EventType == EET_KEY_INPUT_EVENT) {
irrevent.KeyInput.Char = 0;
irrevent.KeyInput.PressedDown = SDL_event.type == SDL_MOUSEBUTTONDOWN;
irrevent.KeyInput.PressedDown = SDL_event.type == SDL_EVENT_MOUSE_BUTTON_DOWN;
irrevent.KeyInput.Shift = shift;
irrevent.KeyInput.Control = control;
postEventFromUser(irrevent);
@@ -874,7 +1013,7 @@ bool CIrrDeviceSDL::run()
break;
}
case SDL_TEXTINPUT: {
case SDL_EVENT_TEXT_INPUT: {
irrevent.EventType = EET_STRING_INPUT_EVENT;
irrevent.StringInput.Str = new core::stringw();
core::utf8ToWString(*irrevent.StringInput.Str, SDL_event.text.text);
@@ -883,10 +1022,17 @@ bool CIrrDeviceSDL::run()
irrevent.StringInput.Str = NULL;
} break;
case SDL_KEYDOWN:
case SDL_KEYUP: {
case SDL_EVENT_KEY_DOWN:
case SDL_EVENT_KEY_UP: {
#ifdef _IRR_USE_SDL3_
SDL_Keycode keysym = SDL_event.key.key;
SDL_Scancode scancode = SDL_event.key.scancode;
SDL_Keymod keymod = SDL_event.key.mod;
#else
auto keysym = SDL_event.key.keysym.sym;
auto scancode = SDL_event.key.keysym.scancode;
auto keymod = SDL_event.key.keysym.mod;
#endif
// Treat AC_BACK as the Escape key
if (scancode == SDL_SCANCODE_AC_BACK) {
@@ -900,26 +1046,41 @@ bool CIrrDeviceSDL::run()
if (!Keycode::isValid(key))
os::Printer::log("keycode not mapped", core::stringc(keysym), ELL_DEBUG);
// Make sure to only input special characters if something is in focus, as SDL_TEXTINPUT handles normal unicode already
if (SDL_IsTextInputActive() && !keyIsKnownSpecial(key) && (SDL_event.key.keysym.mod & KMOD_CTRL) == 0)
// Make sure to only input special characters if something is in focus,
// as SDL_EVENT_TEXT_INPUT handles normal unicode already
if (SDL_TextInputActive(Window) && !keyIsKnownSpecial(key) && (keymod & SDL_KMOD_CTRL) == 0)
break;
irrevent.EventType = EET_KEY_INPUT_EVENT;
irrevent.KeyInput.Key = key;
irrevent.KeyInput.PressedDown = (SDL_event.type == SDL_KEYDOWN);
irrevent.KeyInput.Shift = (SDL_event.key.keysym.mod & KMOD_SHIFT) != 0;
irrevent.KeyInput.Control = (SDL_event.key.keysym.mod & KMOD_CTRL) != 0;
irrevent.KeyInput.Char = findCharToPassToIrrlicht(keysym, key,
(SDL_event.key.keysym.mod & KMOD_NUM) != 0);
irrevent.KeyInput.PressedDown = (SDL_event.type == SDL_EVENT_KEY_DOWN);
irrevent.KeyInput.Shift = (keymod & SDL_KMOD_SHIFT) != 0;
irrevent.KeyInput.Control = (keymod & SDL_KMOD_CTRL) != 0;
#ifdef _IRR_USE_SDL3_
{
// Look up the printable character (like in an input box)
SDL_Keycode keycode_Aa = SDL_GetKeyFromScancode(scancode, keymod, false);
// Discard non-printable, such as CTRL, HOME, F3, ...
irrevent.KeyInput.Char = keycode_Aa < SDLK_EXTENDED_MASK ? keycode_Aa : 0;
}
#else
irrevent.KeyInput.Char = findCharToPassToIrrlicht(keysym, key, keymod);
#endif
irrevent.KeyInput.SystemKeyCode = scancode;
postEventFromUser(irrevent);
} break;
case SDL_QUIT:
case SDL_EVENT_QUIT:
Close = true;
break;
#ifdef _IRR_USE_SDL3_
case SDL_EVENT_WINDOW_RESIZED:
case SDL_EVENT_WINDOW_DISPLAY_CHANGED:
handle_window_resize_event();
break;
#else
case SDL_WINDOWEVENT:
switch (SDL_event.window.event) {
case SDL_WINDOWEVENT_RESIZED:
@@ -927,23 +1088,13 @@ bool CIrrDeviceSDL::run()
#if SDL_VERSION_ATLEAST(2, 0, 18)
case SDL_WINDOWEVENT_DISPLAY_CHANGED:
#endif
u32 old_w = Width, old_h = Height;
f32 old_scale_x = ScaleX, old_scale_y = ScaleY;
updateSizeAndScale();
if (old_w != Width || old_h != Height) {
if (VideoDriver)
VideoDriver->OnResize(core::dimension2d<u32>(Width, Height));
}
if (old_scale_x != ScaleX || old_scale_y != ScaleY) {
irrevent.EventType = EET_APPLICATION_EVENT;
irrevent.ApplicationEvent.EventType = EAET_DPI_CHANGED;
postEventFromUser(irrevent);
}
handle_window_resize_event();
break;
}
break;
#endif
case SDL_USEREVENT:
case SDL_EVENT_USER:
irrevent.EventType = EET_USER_EVENT;
irrevent.UserEvent.UserData1 = reinterpret_cast<uintptr_t>(SDL_event.user.data1);
irrevent.UserEvent.UserData2 = reinterpret_cast<uintptr_t>(SDL_event.user.data2);
@@ -951,35 +1102,29 @@ bool CIrrDeviceSDL::run()
postEventFromUser(irrevent);
break;
case SDL_FINGERDOWN:
case SDL_EVENT_FINGER_DOWN:
irrevent.EventType = EET_TOUCH_INPUT_EVENT;
irrevent.TouchInput.Event = ETIE_PRESSED_DOWN;
irrevent.TouchInput.ID = SDL_event.tfinger.fingerId;
irrevent.TouchInput.X = static_cast<s32>(SDL_event.tfinger.x * Width);
irrevent.TouchInput.Y = static_cast<s32>(SDL_event.tfinger.y * Height);
get_touch_id_x_y();
CurrentTouchCount++;
irrevent.TouchInput.touchedCount = CurrentTouchCount;
postEventFromUser(irrevent);
break;
case SDL_FINGERMOTION:
case SDL_EVENT_FINGER_MOTION:
irrevent.EventType = EET_TOUCH_INPUT_EVENT;
irrevent.TouchInput.Event = ETIE_MOVED;
irrevent.TouchInput.ID = SDL_event.tfinger.fingerId;
irrevent.TouchInput.X = static_cast<s32>(SDL_event.tfinger.x * Width);
irrevent.TouchInput.Y = static_cast<s32>(SDL_event.tfinger.y * Height);
get_touch_id_x_y();
irrevent.TouchInput.touchedCount = CurrentTouchCount;
postEventFromUser(irrevent);
break;
case SDL_FINGERUP:
case SDL_EVENT_FINGER_UP:
irrevent.EventType = EET_TOUCH_INPUT_EVENT;
irrevent.TouchInput.Event = ETIE_LEFT_UP;
irrevent.TouchInput.ID = SDL_event.tfinger.fingerId;
irrevent.TouchInput.X = static_cast<s32>(SDL_event.tfinger.x * Width);
irrevent.TouchInput.Y = static_cast<s32>(SDL_event.tfinger.y * Height);
get_touch_id_x_y();
// To match Android behavior, still count the pointer that was
// just released.
irrevent.TouchInput.touchedCount = CurrentTouchCount;
@@ -990,25 +1135,25 @@ bool CIrrDeviceSDL::run()
postEventFromUser(irrevent);
break;
// Contrary to what the SDL documentation says, SDL_APP_WILLENTERBACKGROUND
// SDL2: Contrary to what the SDL documentation says, SDL_APP_WILLENTERBACKGROUND
// and SDL_APP_WILLENTERFOREGROUND are actually sent in onStop/onStart,
// not onPause/onResume, on recent Android versions. This can be verified
// by testing or by looking at the org.libsdl.app.SDLActivity Java code.
// -> This means we can use them to implement isWindowVisible().
case SDL_APP_WILLENTERBACKGROUND:
case SDL_EVENT_WILL_ENTER_BACKGROUND:
IsInBackground = true;
break;
case SDL_APP_WILLENTERFOREGROUND:
case SDL_EVENT_WILL_ENTER_FOREGROUND:
IsInBackground = false;
break;
case SDL_RENDER_TARGETS_RESET:
case SDL_EVENT_RENDER_TARGETS_RESET:
os::Printer::log("Received SDL_RENDER_TARGETS_RESET. Rendering is probably broken.", ELL_ERROR);
break;
case SDL_RENDER_DEVICE_RESET:
case SDL_EVENT_RENDER_DEVICE_LOST:
os::Printer::log("Received SDL_RENDER_DEVICE_RESET. Rendering is probably broken.", ELL_ERROR);
break;
@@ -1023,7 +1168,7 @@ bool CIrrDeviceSDL::run()
// open/close in the constructor/destructor instead
// update joystick states manually
SDL_JoystickUpdate();
SDL_UpdateJoysticks();
// we'll always send joystick input events...
SEvent joyevent;
joyevent.EventType = EET_JOYSTICK_INPUT_EVENT;
@@ -1032,13 +1177,14 @@ bool CIrrDeviceSDL::run()
if (joystick) {
int j;
// query all buttons
const int numButtons = core::min_(SDL_JoystickNumButtons(joystick), 32);
const int numButtons = core::min_(SDL_GetNumJoystickButtons(joystick), 32);
joyevent.JoystickEvent.ButtonStates = 0;
for (j = 0; j < numButtons; ++j)
joyevent.JoystickEvent.ButtonStates |= (SDL_JoystickGetButton(joystick, j) << j);
joyevent.JoystickEvent.ButtonStates |= (SDL_GetJoystickButton(joystick, j) << j);
// query all axes, already in correct range
const int numAxes = core::min_(SDL_JoystickNumAxes(joystick), (int)SEvent::SJoystickEvent::NUMBER_OF_AXES);
const int numAxes = core::min_(SDL_GetNumJoystickAxes(joystick),
(int)SEvent::SJoystickEvent::NUMBER_OF_AXES);
joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_X] = 0;
joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Y] = 0;
joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Z] = 0;
@@ -1046,11 +1192,11 @@ bool CIrrDeviceSDL::run()
joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_U] = 0;
joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_V] = 0;
for (j = 0; j < numAxes; ++j)
joyevent.JoystickEvent.Axis[j] = SDL_JoystickGetAxis(joystick, j);
joyevent.JoystickEvent.Axis[j] = SDL_GetJoystickAxis(joystick, j);
// we can only query one hat, SDL only supports 8 directions
if (SDL_JoystickNumHats(joystick) > 0) {
switch (SDL_JoystickGetHat(joystick, 0)) {
if (SDL_GetNumJoystickHats(joystick) > 0) {
switch (SDL_GetJoystickHat(joystick, 0)) {
case SDL_HAT_UP:
joyevent.JoystickEvent.POV = 0;
break;
@@ -1101,21 +1247,28 @@ bool CIrrDeviceSDL::activateJoysticks(core::array<SJoystickInfo> &joystickInfo)
#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
joystickInfo.clear();
int numJoysticks = 0;
#ifdef _IRR_USE_SDL3_
(void)SDL_GetJoysticks(&numJoysticks);
#else
numJoysticks = SDL_NumJoysticks();
#endif
// we can name up to 256 different joysticks
const int numJoysticks = core::min_(SDL_NumJoysticks(), 256);
numJoysticks = core::min_(numJoysticks, 256);
Joysticks.reallocate(numJoysticks);
joystickInfo.reallocate(numJoysticks);
int joystick = 0;
for (; joystick < numJoysticks; ++joystick) {
Joysticks.push_back(SDL_JoystickOpen(joystick));
Joysticks.push_back(SDL_OpenJoystick(joystick));
SJoystickInfo info;
info.Joystick = joystick;
info.Axes = SDL_JoystickNumAxes(Joysticks[joystick]);
info.Buttons = SDL_JoystickNumButtons(Joysticks[joystick]);
info.Name = SDL_JoystickName(Joysticks[joystick]);
info.PovHat = (SDL_JoystickNumHats(Joysticks[joystick]) > 0)
info.Axes = SDL_GetNumJoystickAxes(Joysticks[joystick]);
info.Buttons = SDL_GetNumJoystickButtons(Joysticks[joystick]);
info.Name = SDL_GetJoystickName(Joysticks[joystick]);
info.PovHat = (SDL_GetNumJoystickHats(Joysticks[joystick]) > 0)
? SJoystickInfo::POV_HAT_PRESENT
: SJoystickInfo::POV_HAT_ABSENT;
@@ -1143,7 +1296,7 @@ void CIrrDeviceSDL::updateSizeAndScale()
SDL_GetWindowSize(Window, &window_w, &window_h);
int drawable_w, drawable_h;
SDL_GL_GetDrawableSize(Window, &drawable_w, &drawable_h);
SDL_GetWindowSizeInPixels(Window, &drawable_w, &drawable_h);
ScaleX = (float)drawable_w / (float)window_w;
ScaleY = (float)drawable_h / (float)window_h;
@@ -1152,6 +1305,35 @@ void CIrrDeviceSDL::updateSizeAndScale()
Height = drawable_h;
}
std::string CIrrDeviceSDL::getVersionString() const
{
char buf[32];
#ifdef _IRR_USE_SDL3_
int ver = SDL_GetVersion();
snprintf_irr(buf, sizeof(buf), "%d.%d.%d (%d.%d.%d)",
// Version of the dynamic library
SDL_VERSIONNUM_MAJOR(ver),
SDL_VERSIONNUM_MINOR(ver),
SDL_VERSIONNUM_MICRO(ver),
// Version of the headers
SDL_MAJOR_VERSION,
SDL_MINOR_VERSION,
SDL_MICRO_VERSION
);
return std::string(buf);
#else
SDL_version ver{};
SDL_GetVersion(&ver);
snprintf_irr(buf, sizeof(buf), "%d.%d.%d%s",
ver.major, ver.minor, ver.patch,
// the SDL team seems to intentionally number sdl2-compat this way:
// <https://github.com/libsdl-org/sdl2-compat/tags>
ver.patch >= 50 ? " (compat)" : ""
);
return std::string(buf);
#endif
}
//! Get the display density in dots per inch.
float CIrrDeviceSDL::getDisplayDensity() const
{
@@ -1200,8 +1382,14 @@ bool CIrrDeviceSDL::setWindowIcon(const video::IImage *img)
u32 height = img->getDimension().Height;
u32 width = img->getDimension().Width;
SDL_Surface *surface = SDL_CreateRGBSurface(0, width, height, 32,
0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
SDL_Surface *surface =
#ifdef _IRR_USE_SDL3_
SDL_CreateSurface(width, height, SDL_GetPixelFormatForMasks(
32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000));
#else
SDL_CreateRGBSurface(0, width, height,
32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
#endif
if (!surface) {
os::Printer::log("Failed to create SDL suface", ELL_ERROR);
@@ -1214,13 +1402,13 @@ bool CIrrDeviceSDL::setWindowIcon(const video::IImage *img)
if (!succ) {
os::Printer::log("Could not copy icon image. Is the format not ECF_A8R8G8B8?", ELL_ERROR);
SDL_FreeSurface(surface);
SDL_DestroySurface(surface);
return false;
}
SDL_SetWindowIcon(Window, surface);
SDL_FreeSurface(surface);
SDL_DestroySurface(surface);
return true;
}
@@ -1240,7 +1428,11 @@ void CIrrDeviceSDL::setResizable(bool resize)
#else // !_IRR_EMSCRIPTEN_PLATFORM_
if (resize != Resizable) {
if (Window) {
#ifdef _IRR_USE_SDL3_
SDL_SetWindowResizable(Window, resize);
#else
SDL_SetWindowResizable(Window, (SDL_bool)resize);
#endif
}
Resizable = resize;
}
@@ -1283,11 +1475,17 @@ bool CIrrDeviceSDL::isFullscreen() const
{
if (!Window)
return false;
u32 flags = SDL_GetWindowFlags(Window);
return (flags & SDL_WINDOW_FULLSCREEN) != 0 ||
#ifdef _IRR_USE_SDL3_
!SDL_GetWindowFullscreenMode(Window); // borderless fullscreen
#else
(flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
#endif
}
#ifndef _IRR_USE_SDL3_
u32 CIrrDeviceSDL::getFullscreenFlag(bool fullscreen)
{
if (!fullscreen)
@@ -1298,15 +1496,20 @@ u32 CIrrDeviceSDL::getFullscreenFlag(bool fullscreen)
return SDL_WINDOW_FULLSCREEN_DESKTOP;
#endif
}
#endif
bool CIrrDeviceSDL::setFullscreen(bool fullscreen)
{
if (!Window)
return false;
#ifdef _IRR_USE_SDL3_
bool success = SDL_SetWindowFullscreen(Window, fullscreen);
#else
// The SDL wiki says that this may trigger SDL_RENDER_TARGETS_RESET, but
// looking at the SDL source, this only happens with D3D, so it's not
// relevant to us.
bool success = SDL_SetWindowFullscreen(Window, getFullscreenFlag(fullscreen)) == 0;
#endif
if (!success)
os::Printer::log("SDL_SetWindowFullscreen failed", SDL_GetError(), ELL_ERROR);
return success;
@@ -1335,8 +1538,12 @@ bool CIrrDeviceSDL::isWindowActive() const
return false;
}
#endif
const u32 windowFlags = SDL_GetWindowFlags(Window);
return windowFlags & SDL_WINDOW_SHOWN && windowFlags & SDL_WINDOW_INPUT_FOCUS;
const u64 windowFlags = SDL_GetWindowFlags(Window);
#ifdef _IRR_USE_SDL3_
return !(windowFlags & SDL_WINDOW_HIDDEN) && (windowFlags & SDL_WINDOW_INPUT_FOCUS);
#else
return (windowFlags & SDL_WINDOW_SHOWN) && (windowFlags & SDL_WINDOW_INPUT_FOCUS);
#endif
}
//! returns if window has focus.
@@ -1351,6 +1558,7 @@ bool CIrrDeviceSDL::isWindowMinimized() const
return Window && (SDL_GetWindowFlags(Window) & SDL_WINDOW_MINIMIZED) != 0;
}
void CIrrDeviceSDL::createKeyMap()
{
// I don't know if this is the best method to create
@@ -1405,32 +1613,13 @@ void CIrrDeviceSDL::createKeyMap()
KeyMap.emplace(SDLK_8, KEY_KEY_8);
KeyMap.emplace(SDLK_9, KEY_KEY_9);
KeyMap.emplace(SDLK_a, KEY_KEY_A);
KeyMap.emplace(SDLK_b, KEY_KEY_B);
KeyMap.emplace(SDLK_c, KEY_KEY_C);
KeyMap.emplace(SDLK_d, KEY_KEY_D);
KeyMap.emplace(SDLK_e, KEY_KEY_E);
KeyMap.emplace(SDLK_f, KEY_KEY_F);
KeyMap.emplace(SDLK_g, KEY_KEY_G);
KeyMap.emplace(SDLK_h, KEY_KEY_H);
KeyMap.emplace(SDLK_i, KEY_KEY_I);
KeyMap.emplace(SDLK_j, KEY_KEY_J);
KeyMap.emplace(SDLK_k, KEY_KEY_K);
KeyMap.emplace(SDLK_l, KEY_KEY_L);
KeyMap.emplace(SDLK_m, KEY_KEY_M);
KeyMap.emplace(SDLK_n, KEY_KEY_N);
KeyMap.emplace(SDLK_o, KEY_KEY_O);
KeyMap.emplace(SDLK_p, KEY_KEY_P);
KeyMap.emplace(SDLK_q, KEY_KEY_Q);
KeyMap.emplace(SDLK_r, KEY_KEY_R);
KeyMap.emplace(SDLK_s, KEY_KEY_S);
KeyMap.emplace(SDLK_t, KEY_KEY_T);
KeyMap.emplace(SDLK_u, KEY_KEY_U);
KeyMap.emplace(SDLK_v, KEY_KEY_V);
KeyMap.emplace(SDLK_w, KEY_KEY_W);
KeyMap.emplace(SDLK_x, KEY_KEY_X);
KeyMap.emplace(SDLK_y, KEY_KEY_Y);
KeyMap.emplace(SDLK_z, KEY_KEY_Z);
#ifdef _IRR_USE_SDL3_
const u32 sdl_key_A = SDLK_A;
#else
const u32 sdl_key_A = SDLK_a;
#endif
for (u32 i = 0; i <= ('Z' - 'A'); ++i)
KeyMap.emplace(sdl_key_A + i, (EKEY_CODE)(KEY_KEY_A + i));
KeyMap.emplace(SDLK_LGUI, KEY_LWIN);
KeyMap.emplace(SDLK_RGUI, KEY_RWIN);
@@ -1492,18 +1681,18 @@ void CIrrDeviceSDL::CCursorControl::initCursors()
{
Cursors.reserve(gui::ECI_COUNT);
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW)); // ECI_NORMAL
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT)); // ECI_NORMAL
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR)); // ECI_CROSS
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND)); // ECI_HAND
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_POINTER)); // ECI_HAND
Cursors.emplace_back(nullptr); // ECI_HELP
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM)); // ECI_IBEAM
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO)); // ECI_NO
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_TEXT)); // ECI_IBEAM
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NOT_ALLOWED)); // ECI_NO
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT)); // ECI_WAIT
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL)); // ECI_SIZEALL
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW)); // ECI_SIZENESW
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE)); // ECI_SIZENWSE
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS)); // ECI_SIZENS
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE)); // ECI_SIZEWE
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_MOVE)); // ECI_SIZEALL
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NESW_RESIZE)); // ECI_SIZENESW
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NWSE_RESIZE)); // ECI_SIZENWSE
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NS_RESIZE)); // ECI_SIZENS
Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_EW_RESIZE)); // ECI_SIZEWE
Cursors.emplace_back(nullptr); // ECI_UP
}

View File

@@ -16,7 +16,13 @@
#include <emscripten/html5.h>
#endif
#ifdef _IRR_USE_SDL3_
#define SDL_DISABLE_OLD_NAMES
#include <SDL3/SDL.h>
#include <SDL3/SDL_mouse.h>
#else
#include <SDL.h>
#endif
#include <memory>
#include <unordered_map>
@@ -99,12 +105,7 @@ public:
}
//! Get the SDL version
std::string getVersionString() const override
{
SDL_version ver;
SDL_GetVersion(&ver);
return std::to_string(ver.major) + "." + std::to_string(ver.minor) + "." + std::to_string(ver.patch);
}
std::string getVersionString() const override;
//! Get the display density in dots per inch.
float getDisplayDensity() const override;
@@ -125,11 +126,14 @@ public:
void setVisible(bool visible) override
{
IsVisible = visible;
#ifdef _IRR_USE_SDL3_
if (visible)
SDL_ShowCursor(SDL_ENABLE);
else {
SDL_ShowCursor(SDL_DISABLE);
}
SDL_ShowCursor();
else
SDL_HideCursor();
#else
SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE);
#endif
}
//! Returns if the cursor is currently visible.
@@ -166,8 +170,11 @@ public:
static_cast<int>(x / Device->ScaleX),
static_cast<int>(y / Device->ScaleY));
#endif
#ifdef _IRR_USE_SDL3_
if (SDL_GetWindowRelativeMouseMode(Device->Window)) {
#else
if (SDL_GetRelativeMouseMode()) {
#endif
// There won't be an event for this warp (details on libsdl-org/SDL/issues/6034)
Device->MouseX = x;
Device->MouseY = y;
@@ -197,13 +204,16 @@ public:
virtual void setRelativeMode(bool relative) override
{
#ifdef _IRR_USE_SDL3_
if (relative != (bool)SDL_GetWindowRelativeMouseMode(Device->Window)) {
SDL_SetWindowRelativeMouseMode(Device->Window, relative);
}
#else
// Only change it when necessary, as it flushes mouse motion when enabled
if (relative != static_cast<bool>(SDL_GetRelativeMouseMode())) {
if (relative)
SDL_SetRelativeMouseMode(SDL_TRUE);
else
SDL_SetRelativeMouseMode(SDL_FALSE);
SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE);
}
#endif
}
void setActiveIcon(gui::ECURSOR_ICON iconId) override
@@ -263,8 +273,13 @@ public:
{
void operator()(SDL_Cursor *ptr)
{
#ifdef _IRR_USE_SDL3_
if (ptr)
SDL_DestroyCursor(ptr);
#else
if (ptr)
SDL_FreeCursor(ptr);
#endif
}
};
std::vector<std::unique_ptr<SDL_Cursor, CursorDeleter>> Cursors;
@@ -282,7 +297,7 @@ private:
static bool keyIsKnownSpecial(EKEY_CODE irrlichtKey);
// Return the Char that should be sent to Irrlicht for the given key (either the one passed in or 0).
static int findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtKey, bool numlock);
static wchar_t findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtKey, u16 keymod);
std::variant<u32, EKEY_CODE> getScancodeFromKey(const Keycode &key) const override;
Keycode getKeyFromScancode(const u32 scancode) const override;
@@ -316,7 +331,9 @@ private:
bool Resizable;
#ifndef _IRR_USE_SDL3_
static u32 getFullscreenFlag(bool fullscreen);
#endif // SDL3: Replaced by boolean
core::rect<s32> lastElemPos;

View File

@@ -1,5 +1,11 @@
set(DEFAULT_SDL3 OFF)
option(USE_SDL2_STATIC "Link with SDL2 static libraries" FALSE)
option(USE_SDL3 "Use the SDL3 backend instead of SDL3" ${DEFAULT_SDL3})
option(USE_SDL3_STATIC "Link with SDL3 static libraries" FALSE)
# Compiler flags
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
@@ -165,8 +171,25 @@ endif()
if(ENABLE_OPENGL)
find_package(OpenGL REQUIRED)
endif()
set(USE_SDL2_SHARED FALSE)
if(TRUE)
if(USE_SDL3)
set(USE_SDL2_STATIC FALSE) # do not attempt to link against SDL2
# https://wiki.libsdl.org/SDL3/README-cmake#a-system-sdl-library
if(USE_SDL3_STATIC)
set(SDL3_SUFFIX "static")
else()
set(SDL3_SUFFIX "shared")
endif()
find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3-${SDL3_SUFFIX})
message(STATUS "Found SDL3: ${SDL3_VERSION} (${SDL3_SUFFIX} library)")
# https://github.com/libsdl-org/SDL/blob/release-3.2.x/include/SDL3/SDL_opengl_glext.h#L2859
set(USE_SDL_OPENGL_4_5_HEADER TRUE)
else()
# Fall back to SDL2
if(NOT USE_SDL2_STATIC)
set(USE_SDL2_SHARED TRUE)
endif()
@@ -199,20 +222,22 @@ endif()
# More special config
if(ENABLE_OPENGL)
# The legacy GL driver requires some symbols from GL 4.5 to compile,
# which SDL only provides since 2.26.0 (Nov 2022).
# We have a fallback in case this isn't satisfied so test for it.
if(USE_SDL2 AND ENABLE_OPENGL)
set(CMAKE_REQUIRED_INCLUDES ${SDL2_INCLUDE_DIRS})
unset(CHECK_GL_VERSION_4_5 CACHE)
unset(USE_SDL_OPENGL_4_5_HEADER CACHE) # Why?
check_cxx_source_compiles("#include <SDL_opengl.h>\n\
#ifndef GL_VERSION_4_5\n\
#error\n\
#endif\n\
int main() {}" CHECK_GL_VERSION_4_5)
if(CHECK_GL_VERSION_4_5)
int main() {}" USE_SDL_OPENGL_4_5_HEADER)
endif()
if(USE_SDL_OPENGL_4_5_HEADER)
# The legacy GL driver requires some symbols from GL 4.5 to compile,
# which SDL only provides since 2.26.0 (Nov 2022).
# We have a fallback in case this isn't satisfied so test for it.
add_compile_definitions(IRR_PREFER_SDL_GL_HEADER)
endif()
message(STATUS "Using SDL OpenGL header")
endif()
# Platform-specific libs
@@ -228,7 +253,7 @@ set(link_includes
"${ZLIB_INCLUDE_DIR}"
"${JPEG_INCLUDE_DIR}"
"${PNG_INCLUDE_DIR}"
"${SDL2_INCLUDE_DIRS}"
"$<$<NOT:$<BOOL:${USE_SDL3}>>:${SDL2_INCLUDE_DIRS}>"
${OPENGL_INCLUDE_DIR}
${OPENGLES2_INCLUDE_DIR}
@@ -387,6 +412,12 @@ if(APPLE)
set_target_properties(IRROTHEROBJ PROPERTIES COMPILE_OPTIONS "-xobjective-c++")
endif()
if(USE_SDL3)
include_directories(IRROTHEROBJ $<TARGET_PROPERTY:SDL3::Headers,INTERFACE_INCLUDE_DIRECTORIES>)
target_compile_definitions(IRROTHEROBJ PRIVATE _IRR_USE_SDL3_)
target_compile_definitions(IRRVIDEOOBJ PRIVATE _IRR_USE_SDL3_) # OpenGL/Common.h
endif()
add_library(IRRGUIOBJ OBJECT
CGUIButton.h
CGUICheckBox.h
@@ -485,6 +516,8 @@ target_link_libraries(IrrlichtMt PRIVATE
"$<$<BOOL:${USE_SDL2_SHARED}>:SDL2::SDL2>"
"$<$<BOOL:${USE_SDL2_STATIC}>:SDL2::SDL2-static>"
"$<$<BOOL:${USE_SDL3}>:SDL3::SDL3-${SDL3_SUFFIX}>"
"$<$<BOOL:${OPENGL_DIRECT_LINK}>:${OPENGL_LIBRARIES}>"
${EGL_LIBRARY}

View File

@@ -17,9 +17,13 @@
#endif
#endif
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
#include <SDL_clipboard.h>
#include <SDL_version.h>
// "SDL_version.h" for SDL_VERSION_ATLEAST
#ifdef _IRR_USE_SDL3_
#include <SDL3/SDL_clipboard.h>
#include <SDL3/SDL_version.h>
#else
#include <SDL_clipboard.h>
#include <SDL_version.h>
#endif
#include "fast_atof.h"
@@ -89,4 +93,3 @@ const c8 *COSOperator::getTextFromPrimarySelection() const
return 0;
#endif
}

View File

@@ -7,8 +7,12 @@
#ifdef _IRR_COMPILE_WITH_OPENGL_
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_) && defined(IRR_PREFER_SDL_GL_HEADER)
#include <SDL_video.h>
#include <SDL_opengl.h>
#ifdef _IRR_USE_SDL3_
#include <SDL3/SDL_opengl.h>
#else
#include <SDL_video.h>
#include <SDL_opengl.h>
#endif
#else
#include "vendor/gl.h"
#endif

View File

@@ -33,7 +33,7 @@ bool CSDLManager::activateContext(const SExposedVideoData &videoData, bool resto
void *CSDLManager::getProcAddress(const std::string &procName)
{
return SDL_GL_GetProcAddress(procName.c_str());
return (void *)SDL_GL_GetProcAddress(procName.c_str());
}
bool CSDLManager::swapBuffers()

View File

@@ -8,8 +8,12 @@
#include "irrTypes.h"
// even though we have mt_opengl.h our driver code still uses GL_* constants
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
#include <SDL_video.h>
#include <SDL_opengl.h>
#ifdef _IRR_USE_SDL3_
#include <SDL3/SDL_opengl.h>
#else
#include <SDL_video.h>
#include <SDL_opengl.h>
#endif
#else
#include "vendor/gl.h"
#endif

View File

@@ -7,7 +7,11 @@
#include "irrMath.h"
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
#include <SDL_endian.h>
#ifdef _IRR_USE_SDL3_
#include <SDL3/SDL_endian.h>
#else
#include <SDL_endian.h>
#endif
#define bswap_16(X) SDL_Swap16(X)
#define bswap_32(X) SDL_Swap32(X)
#define bswap_64(X) SDL_Swap64(X)