minesweeper

A minewseeper implementation to play around with Hare and Raylib
git clone https://git.tronto.net/minesweeper
Download | Log | Files | Refs | README | LICENSE

rcore_desktop_sdl.c (75450B)


      1 /**********************************************************************************************
      2 *
      3 *   rcore_desktop_sdl - Functions to manage window, graphics device and inputs
      4 *
      5 *   PLATFORM: DESKTOP: SDL
      6 *       - Windows (Win32, Win64)
      7 *       - Linux (X11/Wayland desktop mode)
      8 *       - Others (not tested)
      9 *
     10 *   LIMITATIONS:
     11 *       - Limitation 01
     12 *       - Limitation 02
     13 *
     14 *   POSSIBLE IMPROVEMENTS:
     15 *       - Improvement 01
     16 *       - Improvement 02
     17 *
     18 *   ADDITIONAL NOTES:
     19 *       - TRACELOG() function is located in raylib [utils] module
     20 *
     21 *   CONFIGURATION:
     22 *       #define RCORE_PLATFORM_CUSTOM_FLAG
     23 *           Custom flag for rcore on target platform -not used-
     24 *
     25 *   DEPENDENCIES:
     26 *       - SDL 2 or SLD 3 (main library): Windowing and inputs management
     27 *       - gestures: Gestures system for touch-ready devices (or simulated from mouse inputs)
     28 *
     29 *
     30 *   LICENSE: zlib/libpng
     31 *
     32 *   Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) and contributors
     33 *
     34 *   This software is provided "as-is", without any express or implied warranty. In no event
     35 *   will the authors be held liable for any damages arising from the use of this software.
     36 *
     37 *   Permission is granted to anyone to use this software for any purpose, including commercial
     38 *   applications, and to alter it and redistribute it freely, subject to the following restrictions:
     39 *
     40 *     1. The origin of this software must not be misrepresented; you must not claim that you
     41 *     wrote the original software. If you use this software in a product, an acknowledgment
     42 *     in the product documentation would be appreciated but is not required.
     43 *
     44 *     2. Altered source versions must be plainly marked as such, and must not be misrepresented
     45 *     as being the original software.
     46 *
     47 *     3. This notice may not be removed or altered from any source distribution.
     48 *
     49 **********************************************************************************************/
     50 
     51 
     52 #ifndef SDL_ENABLE_OLD_NAMES
     53     #define SDL_ENABLE_OLD_NAMES    // Just in case we're on SDL3, we need some in-between compatibily
     54 #endif
     55 #include "SDL.h"                // SDL base library (window/rendered, input, timing... functionality)
     56 
     57 #if defined(GRAPHICS_API_OPENGL_ES2)
     58     // It seems it does not need to be included to work
     59     //#include "SDL_opengles2.h"
     60 #else
     61     #include "SDL_opengl.h"     // SDL OpenGL functionality (if required, instead of internal renderer)
     62 #endif
     63 
     64 //----------------------------------------------------------------------------------
     65 // Defines and Macros
     66 //----------------------------------------------------------------------------------
     67 #ifndef MAX_CLIPBOARD_BUFFER_LENGTH
     68     #define MAX_CLIPBOARD_BUFFER_LENGTH 1024 // Size of the clipboard buffer used on GetClipboardText()
     69 #endif
     70 
     71 #if ((defined(SDL_MAJOR_VERSION) && SDL_MAJOR_VERSION == 3) && (defined(SDL_MINOR_VERSION) && SDL_MINOR_VERSION >= 1))
     72     #ifndef PLATFORM_DESKTOP_SDL3
     73         #define PLATFORM_DESKTOP_SDL3
     74     #endif
     75 #endif
     76 
     77 
     78 //----------------------------------------------------------------------------------
     79 // Types and Structures Definition
     80 //----------------------------------------------------------------------------------
     81 typedef struct {
     82     SDL_Window *window;
     83     SDL_GLContext glContext;
     84 
     85     SDL_GameController *gamepad[MAX_GAMEPADS];
     86     SDL_Cursor *cursor;
     87     bool cursorRelative;
     88 } PlatformData;
     89 
     90 //----------------------------------------------------------------------------------
     91 // Global Variables Definition
     92 //----------------------------------------------------------------------------------
     93 extern CoreData CORE;                   // Global CORE state context
     94 
     95 static PlatformData platform = { 0 };   // Platform specific data
     96 
     97 //----------------------------------------------------------------------------------
     98 // Local Variables Definition
     99 //----------------------------------------------------------------------------------
    100 #define SCANCODE_MAPPED_NUM 232
    101 static const KeyboardKey mapScancodeToKey[SCANCODE_MAPPED_NUM] = {
    102     KEY_NULL,           // SDL_SCANCODE_UNKNOWN
    103     0,
    104     0,
    105     0,
    106     KEY_A,              // SDL_SCANCODE_A
    107     KEY_B,              // SDL_SCANCODE_B
    108     KEY_C,              // SDL_SCANCODE_C
    109     KEY_D,              // SDL_SCANCODE_D
    110     KEY_E,              // SDL_SCANCODE_E
    111     KEY_F,              // SDL_SCANCODE_F
    112     KEY_G,              // SDL_SCANCODE_G
    113     KEY_H,              // SDL_SCANCODE_H
    114     KEY_I,              // SDL_SCANCODE_I
    115     KEY_J,              // SDL_SCANCODE_J
    116     KEY_K,              // SDL_SCANCODE_K
    117     KEY_L,              // SDL_SCANCODE_L
    118     KEY_M,              // SDL_SCANCODE_M
    119     KEY_N,              // SDL_SCANCODE_N
    120     KEY_O,              // SDL_SCANCODE_O
    121     KEY_P,              // SDL_SCANCODE_P
    122     KEY_Q,              // SDL_SCANCODE_Q
    123     KEY_R,              // SDL_SCANCODE_R
    124     KEY_S,              // SDL_SCANCODE_S
    125     KEY_T,              // SDL_SCANCODE_T
    126     KEY_U,              // SDL_SCANCODE_U
    127     KEY_V,              // SDL_SCANCODE_V
    128     KEY_W,              // SDL_SCANCODE_W
    129     KEY_X,              // SDL_SCANCODE_X
    130     KEY_Y,              // SDL_SCANCODE_Y
    131     KEY_Z,              // SDL_SCANCODE_Z
    132     KEY_ONE,            // SDL_SCANCODE_1
    133     KEY_TWO,            // SDL_SCANCODE_2
    134     KEY_THREE,          // SDL_SCANCODE_3
    135     KEY_FOUR,           // SDL_SCANCODE_4
    136     KEY_FIVE,           // SDL_SCANCODE_5
    137     KEY_SIX,            // SDL_SCANCODE_6
    138     KEY_SEVEN,          // SDL_SCANCODE_7
    139     KEY_EIGHT,          // SDL_SCANCODE_8
    140     KEY_NINE,           // SDL_SCANCODE_9
    141     KEY_ZERO,           // SDL_SCANCODE_0
    142     KEY_ENTER,          // SDL_SCANCODE_RETURN
    143     KEY_ESCAPE,         // SDL_SCANCODE_ESCAPE
    144     KEY_BACKSPACE,      // SDL_SCANCODE_BACKSPACE
    145     KEY_TAB,            // SDL_SCANCODE_TAB
    146     KEY_SPACE,          // SDL_SCANCODE_SPACE
    147     KEY_MINUS,          // SDL_SCANCODE_MINUS
    148     KEY_EQUAL,          // SDL_SCANCODE_EQUALS
    149     KEY_LEFT_BRACKET,   // SDL_SCANCODE_LEFTBRACKET
    150     KEY_RIGHT_BRACKET,  // SDL_SCANCODE_RIGHTBRACKET
    151     KEY_BACKSLASH,      // SDL_SCANCODE_BACKSLASH
    152     0,                  // SDL_SCANCODE_NONUSHASH
    153     KEY_SEMICOLON,      // SDL_SCANCODE_SEMICOLON
    154     KEY_APOSTROPHE,     // SDL_SCANCODE_APOSTROPHE
    155     KEY_GRAVE,          // SDL_SCANCODE_GRAVE
    156     KEY_COMMA,          // SDL_SCANCODE_COMMA
    157     KEY_PERIOD,         // SDL_SCANCODE_PERIOD
    158     KEY_SLASH,          // SDL_SCANCODE_SLASH
    159     KEY_CAPS_LOCK,      // SDL_SCANCODE_CAPSLOCK
    160     KEY_F1,             // SDL_SCANCODE_F1
    161     KEY_F2,             // SDL_SCANCODE_F2
    162     KEY_F3,             // SDL_SCANCODE_F3
    163     KEY_F4,             // SDL_SCANCODE_F4
    164     KEY_F5,             // SDL_SCANCODE_F5
    165     KEY_F6,             // SDL_SCANCODE_F6
    166     KEY_F7,             // SDL_SCANCODE_F7
    167     KEY_F8,             // SDL_SCANCODE_F8
    168     KEY_F9,             // SDL_SCANCODE_F9
    169     KEY_F10,            // SDL_SCANCODE_F10
    170     KEY_F11,            // SDL_SCANCODE_F11
    171     KEY_F12,            // SDL_SCANCODE_F12
    172     KEY_PRINT_SCREEN,   // SDL_SCANCODE_PRINTSCREEN
    173     KEY_SCROLL_LOCK,    // SDL_SCANCODE_SCROLLLOCK
    174     KEY_PAUSE,          // SDL_SCANCODE_PAUSE
    175     KEY_INSERT,         // SDL_SCANCODE_INSERT
    176     KEY_HOME,           // SDL_SCANCODE_HOME
    177     KEY_PAGE_UP,        // SDL_SCANCODE_PAGEUP
    178     KEY_DELETE,         // SDL_SCANCODE_DELETE
    179     KEY_END,            // SDL_SCANCODE_END
    180     KEY_PAGE_DOWN,      // SDL_SCANCODE_PAGEDOWN
    181     KEY_RIGHT,          // SDL_SCANCODE_RIGHT
    182     KEY_LEFT,           // SDL_SCANCODE_LEFT
    183     KEY_DOWN,           // SDL_SCANCODE_DOWN
    184     KEY_UP,             // SDL_SCANCODE_UP
    185     KEY_NUM_LOCK,       // SDL_SCANCODE_NUMLOCKCLEAR
    186     KEY_KP_DIVIDE,      // SDL_SCANCODE_KP_DIVIDE
    187     KEY_KP_MULTIPLY,    // SDL_SCANCODE_KP_MULTIPLY
    188     KEY_KP_SUBTRACT,    // SDL_SCANCODE_KP_MINUS
    189     KEY_KP_ADD,         // SDL_SCANCODE_KP_PLUS
    190     KEY_KP_ENTER,       // SDL_SCANCODE_KP_ENTER
    191     KEY_KP_1,           // SDL_SCANCODE_KP_1
    192     KEY_KP_2,           // SDL_SCANCODE_KP_2
    193     KEY_KP_3,           // SDL_SCANCODE_KP_3
    194     KEY_KP_4,           // SDL_SCANCODE_KP_4
    195     KEY_KP_5,           // SDL_SCANCODE_KP_5
    196     KEY_KP_6,           // SDL_SCANCODE_KP_6
    197     KEY_KP_7,           // SDL_SCANCODE_KP_7
    198     KEY_KP_8,           // SDL_SCANCODE_KP_8
    199     KEY_KP_9,           // SDL_SCANCODE_KP_9
    200     KEY_KP_0,           // SDL_SCANCODE_KP_0
    201     KEY_KP_DECIMAL,     // SDL_SCANCODE_KP_PERIOD
    202     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    203     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    204     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    205     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    206     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    207     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    208     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    209     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    210     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    211     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    212     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    213     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    214     0, 0, 0, 0,
    215     KEY_LEFT_CONTROL,   //SDL_SCANCODE_LCTRL
    216     KEY_LEFT_SHIFT,     //SDL_SCANCODE_LSHIFT
    217     KEY_LEFT_ALT,       //SDL_SCANCODE_LALT
    218     KEY_LEFT_SUPER,     //SDL_SCANCODE_LGUI
    219     KEY_RIGHT_CONTROL,  //SDL_SCANCODE_RCTRL
    220     KEY_RIGHT_SHIFT,    //SDL_SCANCODE_RSHIFT
    221     KEY_RIGHT_ALT,      //SDL_SCANCODE_RALT
    222     KEY_RIGHT_SUPER     //SDL_SCANCODE_RGUI
    223 };
    224 
    225 static const int CursorsLUT[] = {
    226     SDL_SYSTEM_CURSOR_ARROW,       // 0  MOUSE_CURSOR_DEFAULT
    227     SDL_SYSTEM_CURSOR_ARROW,       // 1  MOUSE_CURSOR_ARROW
    228     SDL_SYSTEM_CURSOR_IBEAM,       // 2  MOUSE_CURSOR_IBEAM
    229     SDL_SYSTEM_CURSOR_CROSSHAIR,   // 3  MOUSE_CURSOR_CROSSHAIR
    230     SDL_SYSTEM_CURSOR_HAND,        // 4  MOUSE_CURSOR_POINTING_HAND
    231     SDL_SYSTEM_CURSOR_SIZEWE,      // 5  MOUSE_CURSOR_RESIZE_EW
    232     SDL_SYSTEM_CURSOR_SIZENS,      // 6  MOUSE_CURSOR_RESIZE_NS
    233     SDL_SYSTEM_CURSOR_SIZENWSE,    // 7  MOUSE_CURSOR_RESIZE_NWSE
    234     SDL_SYSTEM_CURSOR_SIZENESW,    // 8  MOUSE_CURSOR_RESIZE_NESW
    235     SDL_SYSTEM_CURSOR_SIZEALL,     // 9  MOUSE_CURSOR_RESIZE_ALL
    236     SDL_SYSTEM_CURSOR_NO           // 10 MOUSE_CURSOR_NOT_ALLOWED
    237     //SDL_SYSTEM_CURSOR_WAIT,      // No equivalent implemented on MouseCursor enum on raylib.h
    238     //SDL_SYSTEM_CURSOR_WAITARROW, // No equivalent implemented on MouseCursor enum on raylib.h
    239 };
    240 
    241 
    242 // SDL3 Migration Layer made to avoid `ifdefs` inside functions when we can.
    243 #ifdef PLATFORM_DESKTOP_SDL3
    244 
    245 // SDL3 Migration:
    246 //     SDL_WINDOW_FULLSCREEN_DESKTOP has been removed,
    247 //     and you can call SDL_GetWindowFullscreenMode()
    248 //     to see whether an exclusive fullscreen mode will be used 
    249 //     or the borderless fullscreen desktop mode will be used
    250 #define SDL_WINDOW_FULLSCREEN_DESKTOP SDL_WINDOW_FULLSCREEN
    251 
    252 
    253 #define SDL_IGNORE  false
    254 #define SDL_DISABLE false
    255 #define SDL_ENABLE  true
    256 
    257 // SDL3 Migration: SDL_INIT_TIMER - no longer needed before calling SDL_AddTimer()
    258 #define SDL_INIT_TIMER 0x0 // It's a flag, so no problem in setting it to zero if we use in a bitor (|)
    259 
    260 // SDL3 Migration: The SDL_WINDOW_SHOWN flag has been removed. Windows are shown by default and can be created hidden by using the SDL_WINDOW_HIDDEN flag.
    261 #define SDL_WINDOW_SHOWN 0x0 // It's a flag, so no problem in setting it to zero if we use in a bitor (|)
    262 
    263 //
    264 // SDL3 Migration: Renamed
    265 // IMPORTANT:
    266 // Might need to call SDL_CleanupEvent somewhere see :https://github.com/libsdl-org/SDL/issues/3540#issuecomment-1793449852
    267 //
    268 #define SDL_DROPFILE  SDL_EVENT_DROP_FILE
    269 
    270 
    271 const char* SDL_GameControllerNameForIndex(int joystickIndex)
    272 {
    273     // NOTE: SDL3 uses the IDs itself (SDL_JoystickID) instead of SDL2 joystick_index
    274     const char* name = NULL;
    275     int numJoysticks = 0;
    276     SDL_JoystickID *joysticks = SDL_GetJoysticks(&numJoysticks);
    277     if (joysticks) {
    278         if (joystickIndex < numJoysticks) {
    279             SDL_JoystickID instance_id = joysticks[joystickIndex];
    280             name = SDL_GetGamepadNameForID(instance_id);
    281         }
    282         SDL_free(joysticks);
    283     }
    284     return name;
    285 }
    286 
    287 int SDL_GetNumVideoDisplays(void)
    288 {
    289     int monitorCount = 0;
    290     SDL_DisplayID *displays = SDL_GetDisplays(&monitorCount);
    291     // Safe because If `mem` is NULL, SDL_free does nothing.
    292     SDL_free(displays);
    293 
    294     return monitorCount;
    295 }
    296 
    297 
    298 // SLD3 Migration:
    299 //    To emulate SDL2 this function should return `SDL_DISABLE` or `SDL_ENABLE`
    300 //    representing the *processing state* of the event before this function makes any changes to it.
    301 Uint8 SDL_EventState(Uint32 type, int state) {
    302 
    303     Uint8 stateBefore = SDL_EventEnabled(type);
    304     switch (state)
    305     {
    306         case SDL_DISABLE: SDL_SetEventEnabled(type, false); break;
    307         case SDL_ENABLE: SDL_SetEventEnabled(type, true); break;
    308         default: TRACELOG(LOG_WARNING, "Event sate: unknow type");
    309     }
    310     return stateBefore;
    311 }
    312 
    313 void SDL_GetCurrentDisplayMode_Adapter(SDL_DisplayID displayID, SDL_DisplayMode* mode)
    314 {
    315     const SDL_DisplayMode* currMode = SDL_GetCurrentDisplayMode(displayID);
    316     if (currMode == NULL)
    317     {
    318         TRACELOG(LOG_WARNING, "No current display mode");
    319     }
    320     else
    321     {
    322         *mode = *currMode;
    323     }
    324 }
    325 
    326 // SDL3 Migration: Renamed
    327 #define SDL_GetCurrentDisplayMode SDL_GetCurrentDisplayMode_Adapter
    328 
    329 
    330 SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
    331 {
    332     return SDL_CreateSurface(width, height, SDL_GetPixelFormatForMasks(depth, Rmask, Gmask, Bmask, Amask));
    333 }
    334 
    335 // SDL3 Migration:
    336 //     SDL_GetDisplayDPI() -
    337 //     not reliable across platforms, approximately replaced by multiplying
    338 //     SDL_GetWindowDisplayScale() times 160 on iPhone and Android, and 96 on other platforms.
    339 // returns 0 on success or a negative error code on failure
    340 int SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi) {
    341     float dpi = SDL_GetWindowDisplayScale(platform.window) * 96.0;
    342     if (ddpi != NULL) *ddpi = dpi;
    343     if (hdpi != NULL) *hdpi = dpi;
    344     if (vdpi != NULL) *vdpi = dpi;
    345     return 0;
    346 }
    347 
    348 SDL_Surface *SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth, Uint32 format)
    349 {
    350     return SDL_CreateSurface(width, height, format);
    351 }
    352 
    353 SDL_Surface *SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
    354 {
    355     return SDL_CreateSurfaceFrom(width, height, SDL_GetPixelFormatForMasks(depth, Rmask, Gmask, Bmask, Amask), pixels, pitch);
    356 }
    357 
    358 SDL_Surface *SDL_CreateRGBSurfaceWithFormatFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 format)
    359 {
    360     return SDL_CreateSurfaceFrom(width, height, format, pixels, pitch);
    361 }
    362 
    363 int SDL_NumJoysticks(void)
    364 {
    365     int numJoysticks;
    366     SDL_JoystickID *joysticks = SDL_GetJoysticks(&numJoysticks);
    367     SDL_free(joysticks);
    368     return numJoysticks;
    369 }
    370 
    371 
    372 // SDL_SetRelativeMouseMode
    373 // returns 0 on success or a negative error code on failure
    374 // If relative mode is not supported, this returns -1.
    375 int SDL_SetRelativeMouseMode_Adapter(SDL_bool enabled)
    376 {
    377 
    378     //
    379     // SDL_SetWindowRelativeMouseMode(SDL_Window *window, bool enabled)
    380     // \returns true on success or false on failure; call SDL_GetError() for more
    381     //
    382     if (SDL_SetWindowRelativeMouseMode(platform.window, enabled))
    383     {
    384         return 0; // success
    385     }
    386     else
    387     {
    388         return -1; // failure
    389     }
    390 }
    391 
    392 #define SDL_SetRelativeMouseMode SDL_SetRelativeMouseMode_Adapter
    393 
    394 bool SDL_GetRelativeMouseMode_Adapter(void)
    395 {
    396     return SDL_GetWindowRelativeMouseMode(platform.window);
    397 }
    398 
    399 #define SDL_GetRelativeMouseMode SDL_GetRelativeMouseMode_Adapter
    400 
    401 
    402 int SDL_GetNumTouchFingers(SDL_TouchID touchID)
    403 {
    404     // SDL_Finger **SDL_GetTouchFingers(SDL_TouchID touchID, int *count)
    405     int count = 0;
    406     SDL_Finger **fingers = SDL_GetTouchFingers(touchID, &count);
    407     SDL_free(fingers);
    408     return count;
    409 }
    410 
    411 #else // We're on SDL2
    412 
    413 // Since SDL2 doesn't have this function we leave a stub
    414 // SDL_GetClipboardData function is available since SDL 3.1.3. (e.g. SDL3)
    415 void* SDL_GetClipboardData(const char *mime_type, size_t *size) {
    416     TRACELOG(LOG_WARNING, "Getting clipboard data that is not text is only available in SDL3");
    417     // We could possibly implement it ourselves in this case for some easier platforms
    418     return NULL;
    419 }
    420 
    421 #endif // PLATFORM_DESKTOP_SDL3
    422 
    423 
    424 
    425 //----------------------------------------------------------------------------------
    426 // Module Internal Functions Declaration
    427 //----------------------------------------------------------------------------------
    428 int InitPlatform(void);                                      // Initialize platform (graphics, inputs and more)
    429 void ClosePlatform(void);                                    // Close platform
    430 
    431 static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode);  // Help convert SDL scancodes to raylib key
    432 
    433 //----------------------------------------------------------------------------------
    434 // Module Functions Declaration
    435 //----------------------------------------------------------------------------------
    436 // NOTE: Functions declaration is provided by raylib.h
    437 
    438 //----------------------------------------------------------------------------------
    439 // Module Functions Definition: Window and Graphics Device
    440 //----------------------------------------------------------------------------------
    441 
    442 // Check if application should close
    443 bool WindowShouldClose(void)
    444 {
    445     if (CORE.Window.ready) return CORE.Window.shouldClose;
    446     else return true;
    447 }
    448 
    449 // Toggle fullscreen mode
    450 void ToggleFullscreen(void)
    451 {
    452     const int monitor = SDL_GetWindowDisplayIndex(platform.window);
    453     const int monitorCount = SDL_GetNumVideoDisplays();
    454 
    455 #ifdef PLATFORM_DESKTOP_SDL3 // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
    456     if ((monitor > 0) && (monitor <= monitorCount))
    457 #else
    458     if ((monitor >= 0) && (monitor < monitorCount))
    459 #endif
    460     {
    461         if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)
    462         {
    463             SDL_SetWindowFullscreen(platform.window, 0);
    464             CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
    465             CORE.Window.fullscreen = false;
    466         }
    467         else
    468         {
    469             SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN);
    470             CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
    471             CORE.Window.fullscreen = true;
    472         }
    473     }
    474     else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
    475 }
    476 
    477 // Toggle borderless windowed mode
    478 void ToggleBorderlessWindowed(void)
    479 {
    480     const int monitor = SDL_GetWindowDisplayIndex(platform.window);
    481     const int monitorCount = SDL_GetNumVideoDisplays();
    482 #ifdef PLATFORM_DESKTOP_SDL3 // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
    483     if ((monitor > 0) && (monitor <= monitorCount))
    484 #else
    485     if ((monitor >= 0) && (monitor < monitorCount))
    486 #endif
    487     {
    488         if ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0)
    489         {
    490             SDL_SetWindowFullscreen(platform.window, 0);
    491             CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
    492         }
    493         else
    494         {
    495             SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN_DESKTOP);
    496             CORE.Window.flags |= FLAG_BORDERLESS_WINDOWED_MODE;
    497         }
    498     }
    499     else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
    500 }
    501 
    502 // Set window state: maximized, if resizable
    503 void MaximizeWindow(void)
    504 {
    505     SDL_MaximizeWindow(platform.window);
    506     CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
    507 }
    508 
    509 // Set window state: minimized
    510 void MinimizeWindow(void)
    511 {
    512     SDL_MinimizeWindow(platform.window);
    513     CORE.Window.flags |= FLAG_WINDOW_MINIMIZED;
    514 }
    515 
    516 // Set window state: not minimized/maximized
    517 void RestoreWindow(void)
    518 {
    519     SDL_ShowWindow(platform.window);
    520 }
    521 
    522 // Set window configuration state using flags
    523 void SetWindowState(unsigned int flags)
    524 {
    525     CORE.Window.flags |= flags;
    526 
    527     if (flags & FLAG_VSYNC_HINT)
    528     {
    529         SDL_GL_SetSwapInterval(1);
    530     }
    531     if (flags & FLAG_FULLSCREEN_MODE)
    532     {
    533         const int monitor = SDL_GetWindowDisplayIndex(platform.window);
    534         const int monitorCount = SDL_GetNumVideoDisplays();
    535     #ifdef PLATFORM_DESKTOP_SDL3 // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
    536         if ((monitor > 0) && (monitor <= monitorCount))
    537     #else
    538         if ((monitor >= 0) && (monitor < monitorCount))
    539     #endif
    540         {
    541             SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN);
    542             CORE.Window.fullscreen = true;
    543         }
    544         else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
    545     }
    546     if (flags & FLAG_WINDOW_RESIZABLE)
    547     {
    548         SDL_SetWindowResizable(platform.window, SDL_TRUE);
    549     }
    550     if (flags & FLAG_WINDOW_UNDECORATED)
    551     {
    552         SDL_SetWindowBordered(platform.window, SDL_FALSE);
    553     }
    554     if (flags & FLAG_WINDOW_HIDDEN)
    555     {
    556         SDL_HideWindow(platform.window);
    557     }
    558     if (flags & FLAG_WINDOW_MINIMIZED)
    559     {
    560         SDL_MinimizeWindow(platform.window);
    561     }
    562     if (flags & FLAG_WINDOW_MAXIMIZED)
    563     {
    564         SDL_MaximizeWindow(platform.window);
    565     }
    566     if (flags & FLAG_WINDOW_UNFOCUSED)
    567     {
    568         // NOTE: To be able to implement this part it seems that we should
    569         // do it ourselves, via `Windows.h`, `X11/Xlib.h` or even `Cocoa.h`
    570         TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_UNFOCUSED is not supported on PLATFORM_DESKTOP_SDL");
    571     }
    572     if (flags & FLAG_WINDOW_TOPMOST)
    573     {
    574         SDL_SetWindowAlwaysOnTop(platform.window, SDL_FALSE);
    575     }
    576     if (flags & FLAG_WINDOW_ALWAYS_RUN)
    577     {
    578         TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_ALWAYS_RUN is not supported on PLATFORM_DESKTOP_SDL");
    579     }
    580     if (flags & FLAG_WINDOW_TRANSPARENT)
    581     {
    582         TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_TRANSPARENT is not supported on PLATFORM_DESKTOP_SDL");
    583     }
    584     if (flags & FLAG_WINDOW_HIGHDPI)
    585     {
    586         // NOTE: Such a function does not seem to exist
    587         TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_HIGHDPI is not supported on PLATFORM_DESKTOP_SDL");
    588     }
    589     if (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH)
    590     {
    591         //SDL_SetWindowGrab(platform.window, SDL_FALSE);
    592         TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_MOUSE_PASSTHROUGH is not supported on PLATFORM_DESKTOP_SDL");
    593     }
    594     if (flags & FLAG_BORDERLESS_WINDOWED_MODE)
    595     {
    596         const int monitor = SDL_GetWindowDisplayIndex(platform.window);
    597         const int monitorCount = SDL_GetNumVideoDisplays();
    598     #ifdef PLATFORM_DESKTOP_SDL3 // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
    599         if ((monitor > 0) && (monitor <= monitorCount))
    600     #else
    601         if ((monitor >= 0) && (monitor < monitorCount))
    602     #endif
    603         {
    604             SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN_DESKTOP);
    605         }
    606         else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
    607     }
    608     if (flags & FLAG_MSAA_4X_HINT)
    609     {
    610         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); // Enable multisampling buffers
    611         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); // Enable multisampling
    612     }
    613     if (flags & FLAG_INTERLACED_HINT)
    614     {
    615         TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_INTERLACED_HINT is not supported on PLATFORM_DESKTOP_SDL");
    616     }
    617 }
    618 
    619 // Clear window configuration state flags
    620 void ClearWindowState(unsigned int flags)
    621 {
    622     CORE.Window.flags &= ~flags;
    623 
    624     if (flags & FLAG_VSYNC_HINT)
    625     {
    626         SDL_GL_SetSwapInterval(0);
    627     }
    628     if (flags & FLAG_FULLSCREEN_MODE)
    629     {
    630         SDL_SetWindowFullscreen(platform.window, 0);
    631         CORE.Window.fullscreen = false;
    632     }
    633     if (flags & FLAG_WINDOW_RESIZABLE)
    634     {
    635         SDL_SetWindowResizable(platform.window, SDL_FALSE);
    636     }
    637     if (flags & FLAG_WINDOW_UNDECORATED)
    638     {
    639         SDL_SetWindowBordered(platform.window, SDL_TRUE);
    640     }
    641     if (flags & FLAG_WINDOW_HIDDEN)
    642     {
    643         SDL_ShowWindow(platform.window);
    644     }
    645     if (flags & FLAG_WINDOW_MINIMIZED)
    646     {
    647         SDL_RestoreWindow(platform.window);
    648     }
    649     if (flags & FLAG_WINDOW_MAXIMIZED)
    650     {
    651         SDL_RestoreWindow(platform.window);
    652     }
    653     if (flags & FLAG_WINDOW_UNFOCUSED)
    654     {
    655         //SDL_RaiseWindow(platform.window);
    656         TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_UNFOCUSED is not supported on PLATFORM_DESKTOP_SDL");
    657     }
    658     if (flags & FLAG_WINDOW_TOPMOST)
    659     {
    660         SDL_SetWindowAlwaysOnTop(platform.window, SDL_FALSE);
    661     }
    662     if (flags & FLAG_WINDOW_ALWAYS_RUN)
    663     {
    664         TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_ALWAYS_RUN is not supported on PLATFORM_DESKTOP_SDL");
    665     }
    666     if (flags & FLAG_WINDOW_TRANSPARENT)
    667     {
    668         TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_TRANSPARENT is not supported on PLATFORM_DESKTOP_SDL");
    669     }
    670     if (flags & FLAG_WINDOW_HIGHDPI)
    671     {
    672         // NOTE: There also doesn't seem to be a feature to disable high DPI once enabled
    673         TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_HIGHDPI is not supported on PLATFORM_DESKTOP_SDL");
    674     }
    675     if (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH)
    676     {
    677         //SDL_SetWindowGrab(platform.window, SDL_TRUE);
    678         TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_MOUSE_PASSTHROUGH is not supported on PLATFORM_DESKTOP_SDL");
    679     }
    680     if (flags & FLAG_BORDERLESS_WINDOWED_MODE)
    681     {
    682         SDL_SetWindowFullscreen(platform.window, 0);
    683     }
    684     if (flags & FLAG_MSAA_4X_HINT)
    685     {
    686         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); // Disable multisampling buffers
    687         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); // Disable multisampling
    688     }
    689     if (flags & FLAG_INTERLACED_HINT)
    690     {
    691         TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_INTERLACED_HINT is not supported on PLATFORM_DESKTOP_SDL");
    692     }
    693 }
    694 
    695 // Set icon for window
    696 void SetWindowIcon(Image image)
    697 {
    698     SDL_Surface *iconSurface = NULL;
    699 
    700     unsigned int rmask = 0, gmask = 0, bmask = 0, amask = 0;
    701     int depth = 0;  // Depth in bits
    702     int pitch = 0;  // Pixel spacing (pitch) in bytes
    703 
    704     switch (image.format)
    705     {
    706         case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
    707             rmask = 0xFF, gmask = 0;
    708             bmask = 0, amask = 0;
    709             depth = 8, pitch = image.width;
    710             break;
    711         case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
    712             rmask = 0xFF, gmask = 0xFF00;
    713             bmask = 0, amask = 0;
    714             depth = 16, pitch = image.width*2;
    715             break;
    716         case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
    717             rmask = 0xF800, gmask = 0x07E0;
    718             bmask = 0x001F, amask = 0;
    719             depth = 16, pitch = image.width*2;
    720             break;
    721         case PIXELFORMAT_UNCOMPRESSED_R8G8B8: // Uses BGR for 24-bit
    722             rmask = 0x0000FF, gmask = 0x00FF00;
    723             bmask = 0xFF0000, amask = 0;
    724             depth = 24, pitch = image.width*3;
    725             break;
    726         case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
    727             rmask = 0xF800, gmask = 0x07C0;
    728             bmask = 0x003E, amask = 0x0001;
    729             depth = 16, pitch = image.width*2;
    730             break;
    731         case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
    732             rmask = 0xF000, gmask = 0x0F00;
    733             bmask = 0x00F0, amask = 0x000F;
    734             depth = 16, pitch = image.width*2;
    735             break;
    736         case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
    737             rmask = 0xFF000000, gmask = 0x00FF0000;
    738             bmask = 0x0000FF00, amask = 0x000000FF;
    739             depth = 32, pitch = image.width*4;
    740             break;
    741         case PIXELFORMAT_UNCOMPRESSED_R32:
    742             rmask = 0xFFFFFFFF, gmask = 0;
    743             bmask = 0, amask = 0;
    744             depth = 32, pitch = image.width*4;
    745             break;
    746         case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
    747             rmask = 0xFFFFFFFF, gmask = 0xFFFFFFFF;
    748             bmask = 0xFFFFFFFF, amask = 0;
    749             depth = 96, pitch = image.width*12;
    750             break;
    751         case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
    752             rmask = 0xFFFFFFFF, gmask = 0xFFFFFFFF;
    753             bmask = 0xFFFFFFFF, amask = 0xFFFFFFFF;
    754             depth = 128, pitch = image.width*16;
    755             break;
    756         case PIXELFORMAT_UNCOMPRESSED_R16:
    757             rmask = 0xFFFF, gmask = 0;
    758             bmask = 0, amask = 0;
    759             depth = 16, pitch = image.width*2;
    760             break;
    761         case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
    762             rmask = 0xFFFF, gmask = 0xFFFF;
    763             bmask = 0xFFFF, amask = 0;
    764             depth = 48, pitch = image.width*6;
    765             break;
    766         case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
    767             rmask = 0xFFFF, gmask = 0xFFFF;
    768             bmask = 0xFFFF, amask = 0xFFFF;
    769             depth = 64, pitch = image.width*8;
    770             break;
    771         default: return; // Compressed formats are not supported
    772     }
    773 
    774     iconSurface = SDL_CreateRGBSurfaceFrom( image.data, image.width, image.height, depth, pitch, rmask, gmask, bmask, amask );
    775 
    776     if (iconSurface)
    777     {
    778         SDL_SetWindowIcon(platform.window, iconSurface);
    779         SDL_FreeSurface(iconSurface);
    780     }
    781 }
    782 
    783 // Set icon for window
    784 void SetWindowIcons(Image *images, int count)
    785 {
    786     TRACELOG(LOG_WARNING, "SetWindowIcons() not available on target platform");
    787 }
    788 
    789 // Set title for window
    790 void SetWindowTitle(const char *title)
    791 {
    792     SDL_SetWindowTitle(platform.window, title);
    793 
    794     CORE.Window.title = title;
    795 }
    796 
    797 // Set window position on screen (windowed mode)
    798 void SetWindowPosition(int x, int y)
    799 {
    800     SDL_SetWindowPosition(platform.window, x, y);
    801 
    802     CORE.Window.position.x = x;
    803     CORE.Window.position.y = y;
    804 }
    805 
    806 // Set monitor for the current window
    807 void SetWindowMonitor(int monitor)
    808 {
    809     const int monitorCount = SDL_GetNumVideoDisplays();
    810     if ((monitor >= 0) && (monitor < monitorCount))
    811     {
    812         // NOTE:
    813         // 1. SDL started supporting moving exclusive fullscreen windows between displays on SDL3,
    814         //    see commit https://github.com/libsdl-org/SDL/commit/3f5ef7dd422057edbcf3e736107e34be4b75d9ba
    815         // 2. A workaround for SDL2 is leaving fullscreen, moving the window, then entering full screen again.
    816         const bool wasFullscreen = ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)? true : false;
    817 
    818         const int screenWidth = CORE.Window.screen.width;
    819         const int screenHeight = CORE.Window.screen.height;
    820         SDL_Rect usableBounds;
    821     #ifdef PLATFORM_DESKTOP_SDL3 // Different style for success checking
    822         if (SDL_GetDisplayUsableBounds(monitor, &usableBounds))
    823     #else
    824         if (SDL_GetDisplayUsableBounds(monitor, &usableBounds) == 0)
    825     #endif
    826         {
    827             if (wasFullscreen == 1) ToggleFullscreen(); // Leave fullscreen.
    828 
    829             // If the screen size is larger than the monitor usable area, anchor it on the top left corner, otherwise, center it
    830             if ((screenWidth >= usableBounds.w) || (screenHeight >= usableBounds.h))
    831             {
    832                 // NOTE:
    833                 // 1. There's a known issue where if the window larger than the target display bounds,
    834                 //    when moving the windows to that display, the window could be clipped back
    835                 //    ending up positioned partly outside the target display.
    836                 // 2. The workaround for that is, previously to moving the window,
    837                 //    setting the window size to the target display size, so they match.
    838                 // 3. It wasn't done here because we can't assume changing the window size automatically
    839                 //    is acceptable behavior by the user.
    840                 SDL_SetWindowPosition(platform.window, usableBounds.x, usableBounds.y);
    841                 CORE.Window.position.x = usableBounds.x;
    842                 CORE.Window.position.y = usableBounds.y;
    843             }
    844             else
    845             {
    846                 const int x = usableBounds.x + (usableBounds.w/2) - (screenWidth/2);
    847                 const int y = usableBounds.y + (usableBounds.h/2) - (screenHeight/2);
    848                 SDL_SetWindowPosition(platform.window, x, y);
    849                 CORE.Window.position.x = x;
    850                 CORE.Window.position.y = y;
    851             }
    852 
    853             if (wasFullscreen == 1) ToggleFullscreen(); // Re-enter fullscreen
    854         }
    855         else TRACELOG(LOG_WARNING, "SDL: Failed to get selected display usable bounds");
    856     }
    857     else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
    858 }
    859 
    860 // Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
    861 void SetWindowMinSize(int width, int height)
    862 {
    863     SDL_SetWindowMinimumSize(platform.window, width, height);
    864 
    865     CORE.Window.screenMin.width = width;
    866     CORE.Window.screenMin.height = height;
    867 }
    868 
    869 // Set window maximum dimensions (FLAG_WINDOW_RESIZABLE)
    870 void SetWindowMaxSize(int width, int height)
    871 {
    872     SDL_SetWindowMaximumSize(platform.window, width, height);
    873 
    874     CORE.Window.screenMax.width = width;
    875     CORE.Window.screenMax.height = height;
    876 }
    877 
    878 // Set window dimensions
    879 void SetWindowSize(int width, int height)
    880 {
    881     SDL_SetWindowSize(platform.window, width, height);
    882 
    883     CORE.Window.screen.width = width;
    884     CORE.Window.screen.height = height;
    885 }
    886 
    887 // Set window opacity, value opacity is between 0.0 and 1.0
    888 void SetWindowOpacity(float opacity)
    889 {
    890     if (opacity >= 1.0f) opacity = 1.0f;
    891     else if (opacity <= 0.0f) opacity = 0.0f;
    892 
    893     SDL_SetWindowOpacity(platform.window, opacity);
    894 }
    895 
    896 // Set window focused
    897 void SetWindowFocused(void)
    898 {
    899     SDL_RaiseWindow(platform.window);
    900 }
    901 
    902 // Get native window handle
    903 void *GetWindowHandle(void)
    904 {
    905     return (void *)platform.window;
    906 }
    907 
    908 // Get number of monitors
    909 int GetMonitorCount(void)
    910 {
    911     int monitorCount = 0;
    912 
    913     monitorCount = SDL_GetNumVideoDisplays();
    914 
    915     return monitorCount;
    916 }
    917 
    918 // Get number of monitors
    919 int GetCurrentMonitor(void)
    920 {
    921     int currentMonitor = 0;
    922 
    923     // Be aware that this returns an ID in SDL3 and a Index in SDL2
    924     currentMonitor = SDL_GetWindowDisplayIndex(platform.window);
    925 
    926     return currentMonitor;
    927 }
    928 
    929 // Get selected monitor position
    930 Vector2 GetMonitorPosition(int monitor)
    931 {
    932     const int monitorCount = SDL_GetNumVideoDisplays();
    933     if ((monitor >= 0) && (monitor < monitorCount))
    934     {
    935         SDL_Rect displayBounds;
    936     #ifdef PLATFORM_DESKTOP_SDL3
    937         if (SDL_GetDisplayUsableBounds(monitor, &displayBounds))
    938     #else
    939         if (SDL_GetDisplayUsableBounds(monitor, &displayBounds) == 0)
    940     #endif
    941         {
    942             return (Vector2){ (float)displayBounds.x, (float)displayBounds.y };
    943         }
    944         else TRACELOG(LOG_WARNING, "SDL: Failed to get selected display usable bounds");
    945     }
    946     else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
    947     return (Vector2){ 0.0f, 0.0f };
    948 }
    949 
    950 // Get selected monitor width (currently used by monitor)
    951 int GetMonitorWidth(int monitor)
    952 {
    953     int width = 0;
    954 
    955     const int monitorCount = SDL_GetNumVideoDisplays();
    956     if ((monitor >= 0) && (monitor < monitorCount))
    957     {
    958         SDL_DisplayMode mode;
    959         SDL_GetCurrentDisplayMode(monitor, &mode);
    960         width = mode.w;
    961     }
    962     else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
    963 
    964     return width;
    965 }
    966 
    967 // Get selected monitor height (currently used by monitor)
    968 int GetMonitorHeight(int monitor)
    969 {
    970     int height = 0;
    971 
    972     const int monitorCount = SDL_GetNumVideoDisplays();
    973     if ((monitor >= 0) && (monitor < monitorCount))
    974     {
    975         SDL_DisplayMode mode;
    976         SDL_GetCurrentDisplayMode(monitor, &mode);
    977         height = mode.h;
    978     }
    979     else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
    980 
    981     return height;
    982 }
    983 
    984 // Get selected monitor physical width in millimetres
    985 int GetMonitorPhysicalWidth(int monitor)
    986 {
    987     int width = 0;
    988 
    989     const int monitorCount = SDL_GetNumVideoDisplays();
    990     if ((monitor >= 0) && (monitor < monitorCount))
    991     {
    992         float ddpi = 0.0f;
    993         SDL_GetDisplayDPI(monitor, &ddpi, NULL, NULL);
    994         SDL_DisplayMode mode;
    995         SDL_GetCurrentDisplayMode(monitor, &mode);
    996         // Calculate size on inches, then convert to millimeter
    997         if (ddpi > 0.0f) width = (mode.w/ddpi)*25.4f;
    998     }
    999     else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
   1000 
   1001     return width;
   1002 }
   1003 
   1004 // Get selected monitor physical height in millimetres
   1005 int GetMonitorPhysicalHeight(int monitor)
   1006 {
   1007     int height = 0;
   1008 
   1009     const int monitorCount = SDL_GetNumVideoDisplays();
   1010     if ((monitor >= 0) && (monitor < monitorCount))
   1011     {
   1012         float ddpi = 0.0f;
   1013         SDL_GetDisplayDPI(monitor, &ddpi, NULL, NULL);
   1014         SDL_DisplayMode mode;
   1015         SDL_GetCurrentDisplayMode(monitor, &mode);
   1016         // Calculate size on inches, then convert to millimeter
   1017         if (ddpi > 0.0f) height = (mode.h/ddpi)*25.4f;
   1018     }
   1019     else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
   1020 
   1021     return height;
   1022 }
   1023 
   1024 // Get selected monitor refresh rate
   1025 int GetMonitorRefreshRate(int monitor)
   1026 {
   1027     int refresh = 0;
   1028 
   1029     const int monitorCount = SDL_GetNumVideoDisplays();
   1030     if ((monitor >= 0) && (monitor < monitorCount))
   1031     {
   1032         SDL_DisplayMode mode;
   1033         SDL_GetCurrentDisplayMode(monitor, &mode);
   1034         refresh = mode.refresh_rate;
   1035     }
   1036     else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
   1037 
   1038     return refresh;
   1039 }
   1040 
   1041 // Get the human-readable, UTF-8 encoded name of the selected monitor
   1042 const char *GetMonitorName(int monitor)
   1043 {
   1044     const int monitorCount = SDL_GetNumVideoDisplays();
   1045 
   1046     if ((monitor >= 0) && (monitor < monitorCount)) return SDL_GetDisplayName(monitor);
   1047     else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
   1048 
   1049     return "";
   1050 }
   1051 
   1052 // Get window position XY on monitor
   1053 Vector2 GetWindowPosition(void)
   1054 {
   1055     int x = 0;
   1056     int y = 0;
   1057 
   1058     SDL_GetWindowPosition(platform.window, &x, &y);
   1059 
   1060     return (Vector2){ (float)x, (float)y };
   1061 }
   1062 
   1063 // Get window scale DPI factor for current monitor
   1064 Vector2 GetWindowScaleDPI(void)
   1065 {
   1066     Vector2 scale = { 1.0f, 1.0f };
   1067 
   1068 #ifndef PLATFORM_DESKTOP_SDL3
   1069     // NOTE: SDL_GetWindowDisplayScale was only added on SDL3
   1070     //       see https://wiki.libsdl.org/SDL3/SDL_GetWindowDisplayScale
   1071     // TODO: Implement the window scale factor calculation manually.
   1072     TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform");
   1073 #else
   1074     scale.x = SDL_GetWindowDisplayScale(platform.window);
   1075     scale.y = scale.x;
   1076     TRACELOG(LOG_INFO, "WindowScaleDPI is %f", scale.x);
   1077 #endif
   1078 
   1079     return scale;
   1080 }
   1081 
   1082 // Set clipboard text content
   1083 void SetClipboardText(const char *text)
   1084 {
   1085     SDL_SetClipboardText(text);
   1086 }
   1087 
   1088 // Get clipboard text content
   1089 const char *GetClipboardText(void)
   1090 {
   1091     static char buffer[MAX_CLIPBOARD_BUFFER_LENGTH] = { 0 };
   1092 
   1093     char *clipboard = SDL_GetClipboardText();
   1094 
   1095     int clipboardSize = snprintf(buffer, sizeof(buffer), "%s", clipboard);
   1096     if (clipboardSize >= MAX_CLIPBOARD_BUFFER_LENGTH)
   1097     {
   1098         char *truncate = buffer + MAX_CLIPBOARD_BUFFER_LENGTH - 4;
   1099         sprintf(truncate, "...");
   1100     }
   1101 
   1102     SDL_free(clipboard);
   1103 
   1104     return buffer;
   1105 }
   1106 
   1107 
   1108 #if defined(SUPPORT_CLIPBOARD_IMAGE)
   1109 // Get clipboard image
   1110 Image GetClipboardImage(void)
   1111 {
   1112     // Let's hope compiler put these arrays in static memory
   1113     const char *image_formats[] = {
   1114         "image/bmp",
   1115         "image/png",
   1116         "image/jpg",
   1117         "image/tiff",
   1118     };
   1119     const char *image_extensions[] = {
   1120         ".bmp",
   1121         ".png",
   1122         ".jpg",
   1123         ".tiff",
   1124     };
   1125 
   1126 
   1127     Image image = {0};
   1128     size_t dataSize = 0;
   1129     void  *fileData = NULL;
   1130     for (int i = 0; i < SDL_arraysize(image_formats); ++i)
   1131     {
   1132         // NOTE: This pointer should be free with SDL_free() at some point.
   1133         fileData = SDL_GetClipboardData(image_formats[i], &dataSize);
   1134         if (fileData) {
   1135             image = LoadImageFromMemory(image_extensions[i], fileData, dataSize);
   1136             if (IsImageValid(image))
   1137             {
   1138                 TRACELOG(LOG_INFO, "Clipboard image: Got image from clipboard as a `%s` successfully", image_extensions[i]);
   1139                 return image;
   1140             }
   1141         }
   1142     }
   1143 
   1144     TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data. %s", SDL_GetError());
   1145     return image;
   1146 }
   1147 #endif
   1148 
   1149 
   1150 // Show mouse cursor
   1151 void ShowCursor(void)
   1152 {
   1153 #ifdef PLATFORM_DESKTOP_SDL3
   1154     SDL_ShowCursor();
   1155 #else
   1156     SDL_ShowCursor(SDL_ENABLE);
   1157 #endif
   1158     CORE.Input.Mouse.cursorHidden = false;
   1159 }
   1160 
   1161 // Hides mouse cursor
   1162 void HideCursor(void)
   1163 {
   1164 #ifdef PLATFORM_DESKTOP_SDL3
   1165     SDL_HideCursor();
   1166 #else
   1167     SDL_ShowCursor(SDL_DISABLE);
   1168 #endif
   1169     CORE.Input.Mouse.cursorHidden = true;
   1170 }
   1171 
   1172 // Enables cursor (unlock cursor)
   1173 void EnableCursor(void)
   1174 {
   1175     SDL_SetRelativeMouseMode(SDL_FALSE);
   1176 
   1177 #ifdef PLATFORM_DESKTOP_SDL3
   1178     // SDL_ShowCursor() has been split into three functions: SDL_ShowCursor(), SDL_HideCursor(), and SDL_CursorVisible()
   1179     SDL_ShowCursor();
   1180 #else
   1181     SDL_ShowCursor(SDL_ENABLE);
   1182 #endif
   1183 
   1184     platform.cursorRelative = false;
   1185     CORE.Input.Mouse.cursorHidden = false;
   1186 }
   1187 
   1188 // Disables cursor (lock cursor)
   1189 void DisableCursor(void)
   1190 {
   1191     SDL_SetRelativeMouseMode(SDL_TRUE);
   1192 
   1193     platform.cursorRelative = true;
   1194     CORE.Input.Mouse.cursorHidden = true;
   1195 }
   1196 
   1197 // Swap back buffer with front buffer (screen drawing)
   1198 void SwapScreenBuffer(void)
   1199 {
   1200     SDL_GL_SwapWindow(platform.window);
   1201 }
   1202 
   1203 //----------------------------------------------------------------------------------
   1204 // Module Functions Definition: Misc
   1205 //----------------------------------------------------------------------------------
   1206 
   1207 // Get elapsed time measure in seconds
   1208 double GetTime(void)
   1209 {
   1210     unsigned int ms = SDL_GetTicks();    // Elapsed time in milliseconds since SDL_Init()
   1211     double time = (double)ms/1000;
   1212     return time;
   1213 }
   1214 
   1215 // Open URL with default system browser (if available)
   1216 // NOTE: This function is only safe to use if you control the URL given.
   1217 // A user could craft a malicious string performing another action.
   1218 // Only call this function yourself not with user input or make sure to check the string yourself.
   1219 // Ref: https://github.com/raysan5/raylib/issues/686
   1220 void OpenURL(const char *url)
   1221 {
   1222     // Security check to (partially) avoid malicious code
   1223     if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
   1224     else SDL_OpenURL(url);
   1225 }
   1226 
   1227 //----------------------------------------------------------------------------------
   1228 // Module Functions Definition: Inputs
   1229 //----------------------------------------------------------------------------------
   1230 
   1231 // Set internal gamepad mappings
   1232 int SetGamepadMappings(const char *mappings)
   1233 {
   1234     return SDL_GameControllerAddMapping(mappings);
   1235 }
   1236 
   1237 // Set gamepad vibration
   1238 void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration)
   1239 {
   1240     if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (duration > 0.0f))
   1241     {
   1242         if (leftMotor < 0.0f) leftMotor = 0.0f;
   1243         if (leftMotor > 1.0f) leftMotor = 1.0f;
   1244         if (rightMotor < 0.0f) rightMotor = 0.0f;
   1245         if (rightMotor > 1.0f) rightMotor = 1.0f;
   1246         if (duration > MAX_GAMEPAD_VIBRATION_TIME) duration = MAX_GAMEPAD_VIBRATION_TIME;
   1247 
   1248         SDL_GameControllerRumble(platform.gamepad[gamepad], (Uint16)(leftMotor*65535.0f), (Uint16)(rightMotor*65535.0f), (Uint32)(duration*1000.0f));
   1249     }
   1250 }
   1251 
   1252 // Set mouse position XY
   1253 void SetMousePosition(int x, int y)
   1254 {
   1255     SDL_WarpMouseInWindow(platform.window, x, y);
   1256 
   1257     CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
   1258     CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
   1259 }
   1260 
   1261 // Set mouse cursor
   1262 void SetMouseCursor(int cursor)
   1263 {
   1264     platform.cursor = SDL_CreateSystemCursor(CursorsLUT[cursor]);
   1265     SDL_SetCursor(platform.cursor);
   1266 
   1267     CORE.Input.Mouse.cursor = cursor;
   1268 }
   1269 
   1270 // Get physical key name.
   1271 const char *GetKeyName(int key)
   1272 {
   1273     return SDL_GetKeyName(key);
   1274 }
   1275 
   1276 static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event)
   1277 {
   1278 #ifdef PLATFORM_DESKTOP_SDL3 // SDL3
   1279     int count = 0;
   1280     SDL_Finger **fingers = SDL_GetTouchFingers(event.touchID, &count);
   1281     CORE.Input.Touch.pointCount = count;
   1282 
   1283     for (int i = 0; i < CORE.Input.Touch.pointCount; i++)
   1284     {
   1285         SDL_Finger *finger = fingers[i];
   1286         CORE.Input.Touch.pointId[i] = finger->id;
   1287         CORE.Input.Touch.position[i].x = finger->x*CORE.Window.screen.width;
   1288         CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height;
   1289         CORE.Input.Touch.currentTouchState[i] = 1;
   1290     }
   1291     SDL_free(fingers);
   1292 #else // SDL2
   1293 
   1294     CORE.Input.Touch.pointCount = SDL_GetNumTouchFingers(event.touchId);
   1295 
   1296     for (int i = 0; i < CORE.Input.Touch.pointCount; i++)
   1297     {
   1298         SDL_Finger *finger = SDL_GetTouchFinger(event.touchId, i);
   1299         CORE.Input.Touch.pointId[i] = finger->id;
   1300         CORE.Input.Touch.position[i].x = finger->x*CORE.Window.screen.width;
   1301         CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height;
   1302         CORE.Input.Touch.currentTouchState[i] = 1;
   1303     }
   1304 #endif
   1305 
   1306     for (int i = CORE.Input.Touch.pointCount; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.currentTouchState[i] = 0;
   1307 }
   1308 
   1309 // Register all input events
   1310 void PollInputEvents(void)
   1311 {
   1312 #if defined(SUPPORT_GESTURES_SYSTEM)
   1313     // NOTE: Gestures update must be called every frame to reset gestures correctly
   1314     // because ProcessGestureEvent() is just called on an event, not every frame
   1315     UpdateGestures();
   1316 #endif
   1317 
   1318     // Reset keys/chars pressed registered
   1319     CORE.Input.Keyboard.keyPressedQueueCount = 0;
   1320     CORE.Input.Keyboard.charPressedQueueCount = 0;
   1321 
   1322     // Reset mouse wheel
   1323     CORE.Input.Mouse.currentWheelMove.x = 0;
   1324     CORE.Input.Mouse.currentWheelMove.y = 0;
   1325 
   1326     // Register previous mouse position
   1327     if (platform.cursorRelative) CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f };
   1328     else CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
   1329 
   1330     // Reset last gamepad button/axis registered state
   1331     for (int i = 0; (i < SDL_NumJoysticks()) && (i < MAX_GAMEPADS); i++)
   1332     {
   1333         // Check if gamepad is available
   1334         if (CORE.Input.Gamepad.ready[i])
   1335         {
   1336             // Register previous gamepad button states
   1337             for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++)
   1338             {
   1339                 CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k];
   1340             }
   1341         }
   1342     }
   1343 
   1344     // Register previous touch states
   1345     for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i];
   1346 
   1347     // Map touch position to mouse position for convenience
   1348     CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
   1349 
   1350     int touchAction = -1;       // 0-TOUCH_ACTION_UP, 1-TOUCH_ACTION_DOWN, 2-TOUCH_ACTION_MOVE
   1351     bool realTouch = false;     // Flag to differentiate real touch gestures from mouse ones
   1352 
   1353     // Register previous keys states
   1354     // NOTE: Android supports up to 260 keys
   1355     for (int i = 0; i < MAX_KEYBOARD_KEYS; i++)
   1356     {
   1357         CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i];
   1358         CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;
   1359     }
   1360 
   1361     // Register previous mouse states
   1362     for (int i = 0; i < MAX_MOUSE_BUTTONS; i++) CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i];
   1363 
   1364     // Poll input events for current platform
   1365     //-----------------------------------------------------------------------------
   1366     /*
   1367     // WARNING: Indexes into this array are obtained by using SDL_Scancode values, not SDL_Keycode values
   1368     const Uint8 *keys = SDL_GetKeyboardState(NULL);
   1369     for (int i = 0; i < 256; ++i)
   1370     {
   1371         CORE.Input.Keyboard.currentKeyState[i] = keys[i];
   1372         //if (keys[i]) TRACELOG(LOG_WARNING, "Pressed key: %i", i);
   1373     }
   1374     */
   1375 
   1376     CORE.Window.resizedLastFrame = false;
   1377 
   1378     SDL_Event event = { 0 };
   1379     while (SDL_PollEvent(&event) != 0)
   1380     {
   1381         // All input events can be processed after polling
   1382         switch (event.type)
   1383         {
   1384             case SDL_QUIT: CORE.Window.shouldClose = true; break;
   1385 
   1386             case SDL_DROPFILE:      // Dropped file
   1387             {
   1388                 if (CORE.Window.dropFileCount == 0)
   1389                 {
   1390                     // When a new file is dropped, we reserve a fixed number of slots for all possible dropped files
   1391                     // at the moment we limit the number of drops at once to 1024 files but this behaviour should probably be reviewed
   1392                     // TODO: Pointers should probably be reallocated for any new file added...
   1393                     CORE.Window.dropFilepaths = (char **)RL_CALLOC(1024, sizeof(char *));
   1394 
   1395                     CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
   1396                 #ifdef PLATFORM_DESKTOP_SDL3
   1397                     // const char *data;   /**< The text for SDL_EVENT_DROP_TEXT and the file name for SDL_EVENT_DROP_FILE, NULL for other events */
   1398                     // Event memory is now managed by SDL, so you should not free the data in SDL_EVENT_DROP_FILE, and if you want to hold onto the text in SDL_EVENT_TEXT_EDITING and SDL_EVENT_TEXT_INPUT events, you should make a copy of it. SDL_TEXTINPUTEVENT_TEXT_SIZE is no longer necessary and has been removed.
   1399                     strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data);
   1400                 #else
   1401                     strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file);
   1402                     SDL_free(event.drop.file);
   1403                 #endif
   1404 
   1405                     CORE.Window.dropFileCount++;
   1406                 }
   1407                 else if (CORE.Window.dropFileCount < 1024)
   1408                 {
   1409                     CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
   1410                 #ifdef PLATFORM_DESKTOP_SDL3
   1411                     strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data);
   1412                 #else
   1413                     strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file);
   1414                     SDL_free(event.drop.file);
   1415                 #endif
   1416 
   1417                     CORE.Window.dropFileCount++;
   1418                 }
   1419                 else TRACELOG(LOG_WARNING, "FILE: Maximum drag and drop files at once is limited to 1024 files!");
   1420 
   1421             } break;
   1422 
   1423             // Window events are also polled (Minimized, maximized, close...)
   1424 
   1425         #ifndef PLATFORM_DESKTOP_SDL3
   1426             // SDL3 states:
   1427             //     The SDL_WINDOWEVENT_* events have been moved to top level events,
   1428             //     and SDL_WINDOWEVENT has been removed.
   1429             //     In general, handling this change just means checking for the individual events instead of first checking for SDL_WINDOWEVENT
   1430             //     and then checking for window events. You can compare the event >= SDL_EVENT_WINDOW_FIRST and <= SDL_EVENT_WINDOW_LAST if you need to see whether it's a window event.
   1431             case SDL_WINDOWEVENT:
   1432             {
   1433                 switch (event.window.event)
   1434                 {
   1435         #endif
   1436                     case SDL_WINDOWEVENT_RESIZED:
   1437                     case SDL_WINDOWEVENT_SIZE_CHANGED:
   1438                     {
   1439                         const int width = event.window.data1;
   1440                         const int height = event.window.data2;
   1441                         SetupViewport(width, height);
   1442                         CORE.Window.screen.width = width;
   1443                         CORE.Window.screen.height = height;
   1444                         CORE.Window.currentFbo.width = width;
   1445                         CORE.Window.currentFbo.height = height;
   1446                         CORE.Window.resizedLastFrame = true;
   1447                     } break;
   1448                     case SDL_WINDOWEVENT_ENTER:
   1449                     {
   1450                         CORE.Input.Mouse.cursorOnScreen = true;
   1451                     } break;
   1452                     case SDL_WINDOWEVENT_LEAVE:
   1453                     {
   1454                         CORE.Input.Mouse.cursorOnScreen = false;
   1455                     } break;
   1456                     case SDL_WINDOWEVENT_HIDDEN:
   1457                     case SDL_WINDOWEVENT_MINIMIZED:
   1458                     case SDL_WINDOWEVENT_FOCUS_LOST:
   1459                     case SDL_WINDOWEVENT_SHOWN:
   1460                     case SDL_WINDOWEVENT_FOCUS_GAINED:
   1461                     case SDL_WINDOWEVENT_MAXIMIZED:
   1462                     case SDL_WINDOWEVENT_RESTORED:
   1463             #ifdef PLATFORM_DESKTOP_SDL3
   1464                         break;
   1465             #else
   1466                     default: break;
   1467                 }
   1468             } break;
   1469             #endif
   1470 
   1471             // Keyboard events
   1472             case SDL_KEYDOWN:
   1473             {
   1474             #ifdef PLATFORM_DESKTOP_SDL3
   1475                 // SDL3 Migration: The following structures have been removed: * SDL_Keysym
   1476                 KeyboardKey key = ConvertScancodeToKey(event.key.scancode);
   1477             #else
   1478                 KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode);
   1479             #endif
   1480 
   1481                 if (key != KEY_NULL)
   1482                 {
   1483                     // If key was up, add it to the key pressed queue
   1484                     if ((CORE.Input.Keyboard.currentKeyState[key] == 0) && (CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE))
   1485                     {
   1486                         CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key;
   1487                         CORE.Input.Keyboard.keyPressedQueueCount++;
   1488                     }
   1489 
   1490                     CORE.Input.Keyboard.currentKeyState[key] = 1;
   1491                 }
   1492 
   1493                 if (event.key.repeat) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1;
   1494 
   1495                 // TODO: Put exitKey verification outside the switch?
   1496                 if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey])
   1497                 {
   1498                     CORE.Window.shouldClose = true;
   1499                 }
   1500             } break;
   1501 
   1502             case SDL_KEYUP:
   1503             {
   1504 
   1505             #ifdef PLATFORM_DESKTOP_SDL3
   1506                 KeyboardKey key = ConvertScancodeToKey(event.key.scancode);
   1507             #else
   1508                 KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode);
   1509             #endif
   1510                 if (key != KEY_NULL) CORE.Input.Keyboard.currentKeyState[key] = 0;
   1511             } break;
   1512 
   1513             case SDL_TEXTINPUT:
   1514             {
   1515                 // NOTE: event.text.text data comes an UTF-8 text sequence but we register codepoints (int)
   1516 
   1517                 int codepointSize = 0;
   1518 
   1519                 // Check if there is space available in the queue
   1520                 if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
   1521                 {
   1522                     // Add character (codepoint) to the queue
   1523                     CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = GetCodepointNext(event.text.text, &codepointSize);
   1524                     CORE.Input.Keyboard.charPressedQueueCount++;
   1525                 }
   1526             } break;
   1527 
   1528             // Check mouse events
   1529             case SDL_MOUSEBUTTONDOWN:
   1530             {
   1531                 // NOTE: SDL2 mouse button order is LEFT, MIDDLE, RIGHT, but raylib uses LEFT, RIGHT, MIDDLE like GLFW
   1532                 //       The following conditions align SDL with raylib.h MouseButton enum order
   1533                 int btn = event.button.button - 1;
   1534                 if (btn == 2) btn = 1;
   1535                 else if (btn == 1) btn = 2;
   1536 
   1537                 CORE.Input.Mouse.currentButtonState[btn] = 1;
   1538                 CORE.Input.Touch.currentTouchState[btn] = 1;
   1539 
   1540                 touchAction = 1;
   1541             } break;
   1542             case SDL_MOUSEBUTTONUP:
   1543             {
   1544                 // NOTE: SDL2 mouse button order is LEFT, MIDDLE, RIGHT, but raylib uses LEFT, RIGHT, MIDDLE like GLFW
   1545                 //       The following conditions align SDL with raylib.h MouseButton enum order
   1546                 int btn = event.button.button - 1;
   1547                 if (btn == 2) btn = 1;
   1548                 else if (btn == 1) btn = 2;
   1549 
   1550                 CORE.Input.Mouse.currentButtonState[btn] = 0;
   1551                 CORE.Input.Touch.currentTouchState[btn] = 0;
   1552 
   1553                 touchAction = 0;
   1554             } break;
   1555             case SDL_MOUSEWHEEL:
   1556             {
   1557                 CORE.Input.Mouse.currentWheelMove.x = (float)event.wheel.x;
   1558                 CORE.Input.Mouse.currentWheelMove.y = (float)event.wheel.y;
   1559             } break;
   1560             case SDL_MOUSEMOTION:
   1561             {
   1562                 if (platform.cursorRelative)
   1563                 {
   1564                     CORE.Input.Mouse.currentPosition.x = (float)event.motion.xrel;
   1565                     CORE.Input.Mouse.currentPosition.y = (float)event.motion.yrel;
   1566                     CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f };
   1567                 }
   1568                 else
   1569                 {
   1570                     CORE.Input.Mouse.currentPosition.x = (float)event.motion.x;
   1571                     CORE.Input.Mouse.currentPosition.y = (float)event.motion.y;
   1572                 }
   1573 
   1574                 CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
   1575                 touchAction = 2;
   1576             } break;
   1577 
   1578             case SDL_FINGERDOWN:
   1579             {
   1580                 UpdateTouchPointsSDL(event.tfinger);
   1581                 touchAction = 1;
   1582                 realTouch = true;
   1583             } break;
   1584             case SDL_FINGERUP:
   1585             {
   1586                 UpdateTouchPointsSDL(event.tfinger);
   1587                 touchAction = 0;
   1588                 realTouch = true;
   1589             } break;
   1590             case SDL_FINGERMOTION:
   1591             {
   1592                 UpdateTouchPointsSDL(event.tfinger);
   1593                 touchAction = 2;
   1594                 realTouch = true;
   1595             } break;
   1596 
   1597             // Check gamepad events
   1598             case SDL_JOYDEVICEADDED:
   1599             {
   1600                 int jid = event.jdevice.which;
   1601 
   1602                 if (!CORE.Input.Gamepad.ready[jid] && (jid < MAX_GAMEPADS))
   1603                 {
   1604                     platform.gamepad[jid] = SDL_GameControllerOpen(jid);
   1605 
   1606                     if (platform.gamepad[jid])
   1607                     {
   1608                         CORE.Input.Gamepad.ready[jid] = true;
   1609                         CORE.Input.Gamepad.axisCount[jid] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[jid]));
   1610                         CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
   1611                         CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
   1612                         strncpy(CORE.Input.Gamepad.name[jid], SDL_GameControllerNameForIndex(jid), 63);
   1613                         CORE.Input.Gamepad.name[jid][63] = '\0';
   1614                     }
   1615                     else
   1616                     {
   1617                         TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
   1618                     }
   1619                 }
   1620             } break;
   1621             case SDL_JOYDEVICEREMOVED:
   1622             {
   1623                 int jid = event.jdevice.which;
   1624 
   1625                 if (jid == SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[jid])))
   1626                 {
   1627                     SDL_GameControllerClose(platform.gamepad[jid]);
   1628                     platform.gamepad[jid] = SDL_GameControllerOpen(0);
   1629                     CORE.Input.Gamepad.ready[jid] = false;
   1630                     memset(CORE.Input.Gamepad.name[jid], 0, 64);
   1631                 }
   1632             } break;
   1633             case SDL_CONTROLLERBUTTONDOWN:
   1634             {
   1635                 int button = -1;
   1636 
   1637                 switch (event.jbutton.button)
   1638                 {
   1639                     case SDL_CONTROLLER_BUTTON_Y: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break;
   1640                     case SDL_CONTROLLER_BUTTON_B: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break;
   1641                     case SDL_CONTROLLER_BUTTON_A: button = GAMEPAD_BUTTON_RIGHT_FACE_DOWN; break;
   1642                     case SDL_CONTROLLER_BUTTON_X: button = GAMEPAD_BUTTON_RIGHT_FACE_LEFT; break;
   1643 
   1644                     case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: button = GAMEPAD_BUTTON_LEFT_TRIGGER_1; break;
   1645                     case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: button = GAMEPAD_BUTTON_RIGHT_TRIGGER_1; break;
   1646 
   1647                     case SDL_CONTROLLER_BUTTON_BACK: button = GAMEPAD_BUTTON_MIDDLE_LEFT; break;
   1648                     case SDL_CONTROLLER_BUTTON_GUIDE: button = GAMEPAD_BUTTON_MIDDLE; break;
   1649                     case SDL_CONTROLLER_BUTTON_START: button = GAMEPAD_BUTTON_MIDDLE_RIGHT; break;
   1650 
   1651                     case SDL_CONTROLLER_BUTTON_DPAD_UP: button = GAMEPAD_BUTTON_LEFT_FACE_UP; break;
   1652                     case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: button = GAMEPAD_BUTTON_LEFT_FACE_RIGHT; break;
   1653                     case SDL_CONTROLLER_BUTTON_DPAD_DOWN: button = GAMEPAD_BUTTON_LEFT_FACE_DOWN; break;
   1654                     case SDL_CONTROLLER_BUTTON_DPAD_LEFT: button = GAMEPAD_BUTTON_LEFT_FACE_LEFT; break;
   1655 
   1656                     case SDL_CONTROLLER_BUTTON_LEFTSTICK: button = GAMEPAD_BUTTON_LEFT_THUMB; break;
   1657                     case SDL_CONTROLLER_BUTTON_RIGHTSTICK: button = GAMEPAD_BUTTON_RIGHT_THUMB; break;
   1658                     default: break;
   1659                 }
   1660 
   1661                 if (button >= 0)
   1662                 {
   1663                     CORE.Input.Gamepad.currentButtonState[event.jbutton.which][button] = 1;
   1664                     CORE.Input.Gamepad.lastButtonPressed = button;
   1665                 }
   1666             } break;
   1667             case SDL_CONTROLLERBUTTONUP:
   1668             {
   1669                 int button = -1;
   1670 
   1671                 switch (event.jbutton.button)
   1672                 {
   1673                     case SDL_CONTROLLER_BUTTON_Y: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break;
   1674                     case SDL_CONTROLLER_BUTTON_B: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break;
   1675                     case SDL_CONTROLLER_BUTTON_A: button = GAMEPAD_BUTTON_RIGHT_FACE_DOWN; break;
   1676                     case SDL_CONTROLLER_BUTTON_X: button = GAMEPAD_BUTTON_RIGHT_FACE_LEFT; break;
   1677 
   1678                     case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: button = GAMEPAD_BUTTON_LEFT_TRIGGER_1; break;
   1679                     case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: button = GAMEPAD_BUTTON_RIGHT_TRIGGER_1; break;
   1680 
   1681                     case SDL_CONTROLLER_BUTTON_BACK: button = GAMEPAD_BUTTON_MIDDLE_LEFT; break;
   1682                     case SDL_CONTROLLER_BUTTON_GUIDE: button = GAMEPAD_BUTTON_MIDDLE; break;
   1683                     case SDL_CONTROLLER_BUTTON_START: button = GAMEPAD_BUTTON_MIDDLE_RIGHT; break;
   1684 
   1685                     case SDL_CONTROLLER_BUTTON_DPAD_UP: button = GAMEPAD_BUTTON_LEFT_FACE_UP; break;
   1686                     case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: button = GAMEPAD_BUTTON_LEFT_FACE_RIGHT; break;
   1687                     case SDL_CONTROLLER_BUTTON_DPAD_DOWN: button = GAMEPAD_BUTTON_LEFT_FACE_DOWN; break;
   1688                     case SDL_CONTROLLER_BUTTON_DPAD_LEFT: button = GAMEPAD_BUTTON_LEFT_FACE_LEFT; break;
   1689 
   1690                     case SDL_CONTROLLER_BUTTON_LEFTSTICK: button = GAMEPAD_BUTTON_LEFT_THUMB; break;
   1691                     case SDL_CONTROLLER_BUTTON_RIGHTSTICK: button = GAMEPAD_BUTTON_RIGHT_THUMB; break;
   1692                     default: break;
   1693                 }
   1694 
   1695                 if (button >= 0)
   1696                 {
   1697                     CORE.Input.Gamepad.currentButtonState[event.jbutton.which][button] = 0;
   1698                     if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
   1699                 }
   1700             } break;
   1701             case SDL_CONTROLLERAXISMOTION:
   1702             {
   1703                 int axis = -1;
   1704 
   1705                 switch (event.jaxis.axis)
   1706                 {
   1707                     case SDL_CONTROLLER_AXIS_LEFTX: axis = GAMEPAD_AXIS_LEFT_X; break;
   1708                     case SDL_CONTROLLER_AXIS_LEFTY: axis = GAMEPAD_AXIS_LEFT_Y; break;
   1709                     case SDL_CONTROLLER_AXIS_RIGHTX: axis = GAMEPAD_AXIS_RIGHT_X; break;
   1710                     case SDL_CONTROLLER_AXIS_RIGHTY: axis = GAMEPAD_AXIS_RIGHT_Y; break;
   1711                     case SDL_CONTROLLER_AXIS_TRIGGERLEFT: axis = GAMEPAD_AXIS_LEFT_TRIGGER; break;
   1712                     case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: axis = GAMEPAD_AXIS_RIGHT_TRIGGER; break;
   1713                     default: break;
   1714                 }
   1715 
   1716                 if (axis >= 0)
   1717                 {
   1718                     // SDL axis value range is -32768 to 32767, we normalize it to RayLib's -1.0 to 1.0f range
   1719                     float value = event.jaxis.value/(float)32767;
   1720                     CORE.Input.Gamepad.axisState[event.jaxis.which][axis] = value;
   1721 
   1722                     // Register button state for triggers in addition to their axes
   1723                     if ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))
   1724                     {
   1725                         int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER)? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2;
   1726                         int pressed = (value > 0.1f);
   1727                         CORE.Input.Gamepad.currentButtonState[event.jaxis.which][button] = pressed;
   1728                         if (pressed) CORE.Input.Gamepad.lastButtonPressed = button;
   1729                         else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
   1730                     }
   1731                 }
   1732             } break;
   1733             default: break;
   1734         }
   1735 
   1736 #if defined(SUPPORT_GESTURES_SYSTEM)
   1737         if (touchAction > -1)
   1738         {
   1739             // Process mouse events as touches to be able to use mouse-gestures
   1740             GestureEvent gestureEvent = { 0 };
   1741 
   1742             // Register touch actions
   1743             gestureEvent.touchAction = touchAction;
   1744 
   1745             // Assign a pointer ID
   1746             gestureEvent.pointId[0] = 0;
   1747 
   1748             // Register touch points count
   1749             gestureEvent.pointCount = 1;
   1750 
   1751             // Register touch points position, only one point registered
   1752             if (touchAction == 2 || realTouch) gestureEvent.position[0] = CORE.Input.Touch.position[0];
   1753             else gestureEvent.position[0] = GetMousePosition();
   1754 
   1755             // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height
   1756             gestureEvent.position[0].x /= (float)GetScreenWidth();
   1757             gestureEvent.position[0].y /= (float)GetScreenHeight();
   1758 
   1759             // Gesture data is sent to gestures-system for processing
   1760             ProcessGestureEvent(gestureEvent);
   1761 
   1762             touchAction = -1;
   1763         }
   1764 #endif
   1765     }
   1766     //-----------------------------------------------------------------------------
   1767 }
   1768 
   1769 //----------------------------------------------------------------------------------
   1770 // Module Internal Functions Definition
   1771 //----------------------------------------------------------------------------------
   1772 
   1773 // Initialize platform: graphics, inputs and more
   1774 int InitPlatform(void)
   1775 {
   1776     // Initialize SDL internal global state, only required systems
   1777     // NOTE: Not all systems need to be initialized, SDL_INIT_AUDIO is not required, managed by miniaudio
   1778     int result = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER);
   1779     if (result < 0) { TRACELOG(LOG_WARNING, "SDL: Failed to initialize SDL"); return -1; }
   1780 
   1781     // Initialize graphic device: display/window and graphic context
   1782     //----------------------------------------------------------------------------
   1783     unsigned int flags = 0;
   1784     flags |= SDL_WINDOW_SHOWN;
   1785     flags |= SDL_WINDOW_OPENGL;
   1786     flags |= SDL_WINDOW_INPUT_FOCUS;
   1787     flags |= SDL_WINDOW_MOUSE_FOCUS;
   1788     flags |= SDL_WINDOW_MOUSE_CAPTURE;  // Window has mouse captured
   1789 
   1790     // Check window creation flags
   1791     if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)
   1792     {
   1793         CORE.Window.fullscreen = true;
   1794         flags |= SDL_WINDOW_FULLSCREEN;
   1795     }
   1796 
   1797     //if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) == 0) flags |= SDL_WINDOW_HIDDEN;
   1798     if ((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) flags |= SDL_WINDOW_BORDERLESS;
   1799     if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) flags |= SDL_WINDOW_RESIZABLE;
   1800     if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) flags |= SDL_WINDOW_MINIMIZED;
   1801     if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) flags |= SDL_WINDOW_MAXIMIZED;
   1802 
   1803     if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0)
   1804     {
   1805         flags &= ~SDL_WINDOW_INPUT_FOCUS;
   1806         flags &= ~SDL_WINDOW_MOUSE_FOCUS;
   1807     }
   1808 
   1809     if ((CORE.Window.flags & FLAG_WINDOW_TOPMOST) > 0) flags |= SDL_WINDOW_ALWAYS_ON_TOP;
   1810     if ((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0) flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
   1811 
   1812     if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) flags |= SDL_WINDOW_ALLOW_HIGHDPI;
   1813 
   1814     //if ((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) flags |= SDL_WINDOW_TRANSPARENT;     // Alternative: SDL_GL_ALPHA_SIZE = 8
   1815 
   1816     //if ((CORE.Window.flags & FLAG_FULLSCREEN_DESKTOP) > 0) flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
   1817 
   1818     // NOTE: Some OpenGL context attributes must be set before window creation
   1819 
   1820     // Check selection OpenGL version
   1821     if (rlGetVersion() == RL_OPENGL_21)
   1822     {
   1823         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
   1824         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
   1825     }
   1826     else if (rlGetVersion() == RL_OPENGL_33)
   1827     {
   1828         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
   1829         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
   1830         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
   1831     }
   1832     else if (rlGetVersion() == RL_OPENGL_43)
   1833     {
   1834         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
   1835         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
   1836         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
   1837 #if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT)
   1838         SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);   // Enable OpenGL Debug Context
   1839 #endif
   1840     }
   1841     else if (rlGetVersion() == RL_OPENGL_ES_20)                 // Request OpenGL ES 2.0 context
   1842     {
   1843         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
   1844         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
   1845         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
   1846     }
   1847     else if (rlGetVersion() == RL_OPENGL_ES_30)                 // Request OpenGL ES 3.0 context
   1848     {
   1849         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
   1850         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
   1851         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
   1852     }
   1853 
   1854     if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
   1855     {
   1856         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
   1857         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
   1858     }
   1859 
   1860     // Init window
   1861 #ifdef PLATFORM_DESKTOP_SDL3
   1862     platform.window = SDL_CreateWindow(CORE.Window.title, CORE.Window.screen.width, CORE.Window.screen.height, flags);
   1863 #else
   1864     platform.window = SDL_CreateWindow(CORE.Window.title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, CORE.Window.screen.width, CORE.Window.screen.height, flags);
   1865 #endif
   1866 
   1867     // Init OpenGL context
   1868     platform.glContext = SDL_GL_CreateContext(platform.window);
   1869 
   1870     // Check window and glContext have been initialized successfully
   1871     if ((platform.window != NULL) && (platform.glContext != NULL))
   1872     {
   1873         CORE.Window.ready = true;
   1874 
   1875         SDL_DisplayMode displayMode = { 0 };
   1876         SDL_GetCurrentDisplayMode(GetCurrentMonitor(), &displayMode);
   1877 
   1878         CORE.Window.display.width = displayMode.w;
   1879         CORE.Window.display.height = displayMode.h;
   1880 
   1881         CORE.Window.render.width = CORE.Window.screen.width;
   1882         CORE.Window.render.height = CORE.Window.screen.height;
   1883         CORE.Window.currentFbo.width = CORE.Window.render.width;
   1884         CORE.Window.currentFbo.height = CORE.Window.render.height;
   1885 
   1886         TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
   1887         TRACELOG(LOG_INFO, "    > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
   1888         TRACELOG(LOG_INFO, "    > Screen size:  %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
   1889         TRACELOG(LOG_INFO, "    > Render size:  %i x %i", CORE.Window.render.width, CORE.Window.render.height);
   1890         TRACELOG(LOG_INFO, "    > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
   1891 
   1892         if (CORE.Window.flags & FLAG_VSYNC_HINT) SDL_GL_SetSwapInterval(1);
   1893         else SDL_GL_SetSwapInterval(0);
   1894     }
   1895     else
   1896     {
   1897         TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphics device");
   1898         return -1;
   1899     }
   1900 
   1901     // Load OpenGL extensions
   1902     // NOTE: GL procedures address loader is required to load extensions
   1903     rlLoadExtensions(SDL_GL_GetProcAddress);
   1904     //----------------------------------------------------------------------------
   1905 
   1906     // Initialize input events system
   1907     //----------------------------------------------------------------------------
   1908     // Initialize gamepads
   1909     for (int i = 0; (i < SDL_NumJoysticks()) && (i < MAX_GAMEPADS); i++)
   1910     {
   1911         platform.gamepad[i] = SDL_GameControllerOpen(i);
   1912 
   1913         if (platform.gamepad[i])
   1914         {
   1915             CORE.Input.Gamepad.ready[i] = true;
   1916             CORE.Input.Gamepad.axisCount[i] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[i]));
   1917             CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
   1918             CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
   1919             strncpy(CORE.Input.Gamepad.name[i], SDL_GameControllerNameForIndex(i), 63);
   1920             CORE.Input.Gamepad.name[i][63] = '\0';
   1921         }
   1922         else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
   1923     }
   1924 
   1925     // Disable mouse events being interpreted as touch events
   1926     // NOTE: This is wanted because there are SDL_FINGER* events available which provide unique data
   1927     //       Due to the way PollInputEvents() and rgestures.h are currently implemented, setting this won't break SUPPORT_MOUSE_GESTURES
   1928     SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
   1929 
   1930     SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
   1931     //----------------------------------------------------------------------------
   1932 
   1933     // Initialize timing system
   1934     //----------------------------------------------------------------------------
   1935     // NOTE: No need to call InitTimer(), let SDL manage it internally
   1936     CORE.Time.previous = GetTime();     // Get time as double
   1937 
   1938     #if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP)
   1939     SDL_SetHint(SDL_HINT_TIMER_RESOLUTION, "1"); // SDL equivalent of timeBeginPeriod() and timeEndPeriod()
   1940     #endif
   1941     //----------------------------------------------------------------------------
   1942 
   1943     // Initialize storage system
   1944     //----------------------------------------------------------------------------
   1945     // Define base path for storage
   1946     CORE.Storage.basePath = SDL_GetBasePath(); // Alternative: GetWorkingDirectory();
   1947     //----------------------------------------------------------------------------
   1948 
   1949 
   1950 #ifdef PLATFORM_DESKTOP_SDL3
   1951     TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL3): Initialized successfully");
   1952 #else
   1953     TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL): Initialized successfully");
   1954 #endif
   1955 
   1956     return 0;
   1957 }
   1958 
   1959 // Close platform
   1960 void ClosePlatform(void)
   1961 {
   1962     SDL_FreeCursor(platform.cursor); // Free cursor
   1963     SDL_GL_DeleteContext(platform.glContext); // Deinitialize OpenGL context
   1964     SDL_DestroyWindow(platform.window);
   1965     SDL_Quit(); // Deinitialize SDL internal global state
   1966 }
   1967 
   1968 // Scancode to keycode mapping
   1969 static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode)
   1970 {
   1971     if (sdlScancode >= 0 && sdlScancode < SCANCODE_MAPPED_NUM)
   1972     {
   1973         return mapScancodeToKey[sdlScancode];
   1974     }
   1975 
   1976     return KEY_NULL; // No equivalent key in Raylib
   1977 }
   1978 // EOF