#ifndef SDL_ENABLE_OLD_NAMES
#define SDL_ENABLE_OLD_NAMES
#endif
#include "SDL.h"
#if defined(GRAPHICS_API_OPENGL_ES2)
#else
#include "SDL_opengl.h"
#endif
#ifndef MAX_CLIPBOARD_BUFFER_LENGTH
#define MAX_CLIPBOARD_BUFFER_LENGTH 1024
#endif
#if ((defined(SDL_MAJOR_VERSION) && SDL_MAJOR_VERSION == 3) && (defined(SDL_MINOR_VERSION) && SDL_MINOR_VERSION >= 1))
#ifndef PLATFORM_DESKTOP_SDL3
#define PLATFORM_DESKTOP_SDL3
#endif
#endif
typedef struct {
SDL_Window *window;
SDL_GLContext glContext;
SDL_GameController *gamepad[MAX_GAMEPADS];
SDL_Cursor *cursor;
bool cursorRelative;
} PlatformData;
extern CoreData CORE;
static PlatformData platform = { 0 };
#define SCANCODE_MAPPED_NUM 232
static const KeyboardKey mapScancodeToKey[SCANCODE_MAPPED_NUM] = {
KEY_NULL, 0,
0,
0,
KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_ONE, KEY_TWO, KEY_THREE, KEY_FOUR, KEY_FIVE, KEY_SIX, KEY_SEVEN, KEY_EIGHT, KEY_NINE, KEY_ZERO, KEY_ENTER, KEY_ESCAPE, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, KEY_MINUS, KEY_EQUAL, KEY_LEFT_BRACKET, KEY_RIGHT_BRACKET, KEY_BACKSLASH, 0, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, KEY_PERIOD, KEY_SLASH, KEY_CAPS_LOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_PRINT_SCREEN, KEY_SCROLL_LOCK, KEY_PAUSE, KEY_INSERT, KEY_HOME, KEY_PAGE_UP, KEY_DELETE, KEY_END, KEY_PAGE_DOWN, KEY_RIGHT, KEY_LEFT, KEY_DOWN, KEY_UP, KEY_NUM_LOCK, KEY_KP_DIVIDE, KEY_KP_MULTIPLY, KEY_KP_SUBTRACT, KEY_KP_ADD, KEY_KP_ENTER, KEY_KP_1, KEY_KP_2, KEY_KP_3, KEY_KP_4, KEY_KP_5, KEY_KP_6, KEY_KP_7, KEY_KP_8, KEY_KP_9, KEY_KP_0, KEY_KP_DECIMAL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
KEY_LEFT_CONTROL, KEY_LEFT_SHIFT, KEY_LEFT_ALT, KEY_LEFT_SUPER, KEY_RIGHT_CONTROL, KEY_RIGHT_SHIFT, KEY_RIGHT_ALT, KEY_RIGHT_SUPER };
static const int CursorsLUT[] = {
SDL_SYSTEM_CURSOR_ARROW, SDL_SYSTEM_CURSOR_ARROW, SDL_SYSTEM_CURSOR_IBEAM, SDL_SYSTEM_CURSOR_CROSSHAIR, SDL_SYSTEM_CURSOR_HAND, SDL_SYSTEM_CURSOR_SIZEWE, SDL_SYSTEM_CURSOR_SIZENS, SDL_SYSTEM_CURSOR_SIZENWSE, SDL_SYSTEM_CURSOR_SIZENESW, SDL_SYSTEM_CURSOR_SIZEALL, SDL_SYSTEM_CURSOR_NO };
#if defined(PLATFORM_DESKTOP_SDL3)
#define SDL_WINDOW_FULLSCREEN_DESKTOP SDL_WINDOW_FULLSCREEN
#define SDL_IGNORE false
#define SDL_DISABLE false
#define SDL_ENABLE true
#define SDL_INIT_TIMER 0x0
#define SDL_WINDOW_SHOWN 0x0
#define SDL_DROPFILE SDL_EVENT_DROP_FILE
const char *SDL_GameControllerNameForIndex(int joystickIndex)
{
const char *name = NULL;
int numJoysticks = 0;
SDL_JoystickID *joysticks = SDL_GetJoysticks(&numJoysticks);
if (joysticks)
{
if (joystickIndex < numJoysticks)
{
SDL_JoystickID instance_id = joysticks[joystickIndex];
name = SDL_GetGamepadNameForID(instance_id);
}
SDL_free(joysticks);
}
return name;
}
int SDL_GetNumVideoDisplays(void)
{
int monitorCount = 0;
SDL_DisplayID *displays = SDL_GetDisplays(&monitorCount);
SDL_free(displays);
return monitorCount;
}
Uint8 SDL_EventState(Uint32 type, int state)
{
Uint8 stateBefore = SDL_EventEnabled(type);
switch (state)
{
case SDL_DISABLE: SDL_SetEventEnabled(type, false); break;
case SDL_ENABLE: SDL_SetEventEnabled(type, true); break;
default: TRACELOG(LOG_WARNING, "Event sate: unknow type");
}
return stateBefore;
}
void SDL_GetCurrentDisplayMode_Adapter(SDL_DisplayID displayID, SDL_DisplayMode* mode)
{
const SDL_DisplayMode* currMode = SDL_GetCurrentDisplayMode(displayID);
if (currMode == NULL) TRACELOG(LOG_WARNING, "No current display mode");
else *mode = *currMode;
}
#define SDL_GetCurrentDisplayMode SDL_GetCurrentDisplayMode_Adapter
SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
{
return SDL_CreateSurface(width, height, SDL_GetPixelFormatForMasks(depth, Rmask, Gmask, Bmask, Amask));
}
int SDL_GetDisplayDPI(int displayIndex, float *ddpi, float *hdpi, float *vdpi)
{
float dpi = SDL_GetWindowDisplayScale(platform.window)*96.0;
if (ddpi != NULL) *ddpi = dpi;
if (hdpi != NULL) *hdpi = dpi;
if (vdpi != NULL) *vdpi = dpi;
return 0;
}
SDL_Surface *SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth, Uint32 format)
{
return SDL_CreateSurface(width, height, format);
}
SDL_Surface *SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
{
return SDL_CreateSurfaceFrom(width, height, SDL_GetPixelFormatForMasks(depth, Rmask, Gmask, Bmask, Amask), pixels, pitch);
}
SDL_Surface *SDL_CreateRGBSurfaceWithFormatFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 format)
{
return SDL_CreateSurfaceFrom(width, height, format, pixels, pitch);
}
int SDL_NumJoysticks(void)
{
int numJoysticks;
SDL_JoystickID *joysticks = SDL_GetJoysticks(&numJoysticks);
SDL_free(joysticks);
return numJoysticks;
}
int SDL_SetRelativeMouseMode_Adapter(SDL_bool enabled)
{
if (SDL_SetWindowRelativeMouseMode(platform.window, enabled))
{
return 0; }
else
{
return -1; }
}
#define SDL_SetRelativeMouseMode SDL_SetRelativeMouseMode_Adapter
bool SDL_GetRelativeMouseMode_Adapter(void)
{
return SDL_GetWindowRelativeMouseMode(platform.window);
}
#define SDL_GetRelativeMouseMode SDL_GetRelativeMouseMode_Adapter
int SDL_GetNumTouchFingers(SDL_TouchID touchID)
{
int count = 0;
SDL_Finger **fingers = SDL_GetTouchFingers(touchID, &count);
SDL_free(fingers);
return count;
}
#else
void* SDL_GetClipboardData(const char *mime_type, size_t *size)
{
TRACELOG(LOG_WARNING, "Getting clipboard data that is not text is only available in SDL3");
return NULL;
}
#endif
int InitPlatform(void); void ClosePlatform(void);
static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode);
bool WindowShouldClose(void)
{
if (CORE.Window.ready) return CORE.Window.shouldClose;
else return true;
}
void ToggleFullscreen(void)
{
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(PLATFORM_DESKTOP_SDL3)
if ((monitor > 0) && (monitor <= monitorCount))
#else
if ((monitor >= 0) && (monitor < monitorCount))
#endif
{
if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)
{
SDL_SetWindowFullscreen(platform.window, 0);
CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
CORE.Window.fullscreen = false;
}
else
{
SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN);
CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
CORE.Window.fullscreen = true;
}
}
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
}
void ToggleBorderlessWindowed(void)
{
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(PLATFORM_DESKTOP_SDL3)
if ((monitor > 0) && (monitor <= monitorCount))
#else
if ((monitor >= 0) && (monitor < monitorCount))
#endif
{
if ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0)
{
SDL_SetWindowFullscreen(platform.window, 0);
CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
}
else
{
SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN_DESKTOP);
CORE.Window.flags |= FLAG_BORDERLESS_WINDOWED_MODE;
}
}
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
}
void MaximizeWindow(void)
{
SDL_MaximizeWindow(platform.window);
CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
}
void MinimizeWindow(void)
{
SDL_MinimizeWindow(platform.window);
CORE.Window.flags |= FLAG_WINDOW_MINIMIZED;
}
void RestoreWindow(void)
{
SDL_ShowWindow(platform.window);
}
void SetWindowState(unsigned int flags)
{
CORE.Window.flags |= flags;
if (flags & FLAG_VSYNC_HINT)
{
SDL_GL_SetSwapInterval(1);
}
if (flags & FLAG_FULLSCREEN_MODE)
{
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(PLATFORM_DESKTOP_SDL3)
if ((monitor > 0) && (monitor <= monitorCount))
#else
if ((monitor >= 0) && (monitor < monitorCount))
#endif
{
SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN);
CORE.Window.fullscreen = true;
}
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
}
if (flags & FLAG_WINDOW_RESIZABLE)
{
SDL_SetWindowResizable(platform.window, SDL_TRUE);
}
if (flags & FLAG_WINDOW_UNDECORATED)
{
SDL_SetWindowBordered(platform.window, SDL_FALSE);
}
if (flags & FLAG_WINDOW_HIDDEN)
{
SDL_HideWindow(platform.window);
}
if (flags & FLAG_WINDOW_MINIMIZED)
{
SDL_MinimizeWindow(platform.window);
}
if (flags & FLAG_WINDOW_MAXIMIZED)
{
SDL_MaximizeWindow(platform.window);
}
if (flags & FLAG_WINDOW_UNFOCUSED)
{
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_UNFOCUSED is not supported on PLATFORM_DESKTOP_SDL");
}
if (flags & FLAG_WINDOW_TOPMOST)
{
SDL_SetWindowAlwaysOnTop(platform.window, SDL_FALSE);
}
if (flags & FLAG_WINDOW_ALWAYS_RUN)
{
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_ALWAYS_RUN is not supported on PLATFORM_DESKTOP_SDL");
}
if (flags & FLAG_WINDOW_TRANSPARENT)
{
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_TRANSPARENT is not supported on PLATFORM_DESKTOP_SDL");
}
if (flags & FLAG_WINDOW_HIGHDPI)
{
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_HIGHDPI is not supported on PLATFORM_DESKTOP_SDL");
}
if (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH)
{
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_MOUSE_PASSTHROUGH is not supported on PLATFORM_DESKTOP_SDL");
}
if (flags & FLAG_BORDERLESS_WINDOWED_MODE)
{
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(PLATFORM_DESKTOP_SDL3)
if ((monitor > 0) && (monitor <= monitorCount))
#else
if ((monitor >= 0) && (monitor < monitorCount))
#endif
{
SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN_DESKTOP);
}
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
}
if (flags & FLAG_MSAA_4X_HINT)
{
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); }
if (flags & FLAG_INTERLACED_HINT)
{
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_INTERLACED_HINT is not supported on PLATFORM_DESKTOP_SDL");
}
}
void ClearWindowState(unsigned int flags)
{
CORE.Window.flags &= ~flags;
if (flags & FLAG_VSYNC_HINT)
{
SDL_GL_SetSwapInterval(0);
}
if (flags & FLAG_FULLSCREEN_MODE)
{
SDL_SetWindowFullscreen(platform.window, 0);
CORE.Window.fullscreen = false;
}
if (flags & FLAG_WINDOW_RESIZABLE)
{
SDL_SetWindowResizable(platform.window, SDL_FALSE);
}
if (flags & FLAG_WINDOW_UNDECORATED)
{
SDL_SetWindowBordered(platform.window, SDL_TRUE);
}
if (flags & FLAG_WINDOW_HIDDEN)
{
SDL_ShowWindow(platform.window);
}
if (flags & FLAG_WINDOW_MINIMIZED)
{
SDL_RestoreWindow(platform.window);
}
if (flags & FLAG_WINDOW_MAXIMIZED)
{
SDL_RestoreWindow(platform.window);
}
if (flags & FLAG_WINDOW_UNFOCUSED)
{
TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_UNFOCUSED is not supported on PLATFORM_DESKTOP_SDL");
}
if (flags & FLAG_WINDOW_TOPMOST)
{
SDL_SetWindowAlwaysOnTop(platform.window, SDL_FALSE);
}
if (flags & FLAG_WINDOW_ALWAYS_RUN)
{
TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_ALWAYS_RUN is not supported on PLATFORM_DESKTOP_SDL");
}
if (flags & FLAG_WINDOW_TRANSPARENT)
{
TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_TRANSPARENT is not supported on PLATFORM_DESKTOP_SDL");
}
if (flags & FLAG_WINDOW_HIGHDPI)
{
TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_HIGHDPI is not supported on PLATFORM_DESKTOP_SDL");
}
if (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH)
{
TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_MOUSE_PASSTHROUGH is not supported on PLATFORM_DESKTOP_SDL");
}
if (flags & FLAG_BORDERLESS_WINDOWED_MODE)
{
SDL_SetWindowFullscreen(platform.window, 0);
}
if (flags & FLAG_MSAA_4X_HINT)
{
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); }
if (flags & FLAG_INTERLACED_HINT)
{
TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_INTERLACED_HINT is not supported on PLATFORM_DESKTOP_SDL");
}
}
void SetWindowIcon(Image image)
{
SDL_Surface *iconSurface = NULL;
unsigned int rmask = 0, gmask = 0, bmask = 0, amask = 0;
int depth = 0; int pitch = 0;
switch (image.format)
{
case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
rmask = 0xFF, gmask = 0;
bmask = 0, amask = 0;
depth = 8, pitch = image.width;
break;
case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
rmask = 0xFF, gmask = 0xFF00;
bmask = 0, amask = 0;
depth = 16, pitch = image.width*2;
break;
case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
rmask = 0xF800, gmask = 0x07E0;
bmask = 0x001F, amask = 0;
depth = 16, pitch = image.width*2;
break;
case PIXELFORMAT_UNCOMPRESSED_R8G8B8: rmask = 0x0000FF, gmask = 0x00FF00;
bmask = 0xFF0000, amask = 0;
depth = 24, pitch = image.width*3;
break;
case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
rmask = 0xF800, gmask = 0x07C0;
bmask = 0x003E, amask = 0x0001;
depth = 16, pitch = image.width*2;
break;
case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
rmask = 0xF000, gmask = 0x0F00;
bmask = 0x00F0, amask = 0x000F;
depth = 16, pitch = image.width*2;
break;
case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
rmask = 0xFF000000, gmask = 0x00FF0000;
bmask = 0x0000FF00, amask = 0x000000FF;
depth = 32, pitch = image.width*4;
break;
case PIXELFORMAT_UNCOMPRESSED_R32:
rmask = 0xFFFFFFFF, gmask = 0;
bmask = 0, amask = 0;
depth = 32, pitch = image.width*4;
break;
case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
rmask = 0xFFFFFFFF, gmask = 0xFFFFFFFF;
bmask = 0xFFFFFFFF, amask = 0;
depth = 96, pitch = image.width*12;
break;
case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
rmask = 0xFFFFFFFF, gmask = 0xFFFFFFFF;
bmask = 0xFFFFFFFF, amask = 0xFFFFFFFF;
depth = 128, pitch = image.width*16;
break;
case PIXELFORMAT_UNCOMPRESSED_R16:
rmask = 0xFFFF, gmask = 0;
bmask = 0, amask = 0;
depth = 16, pitch = image.width*2;
break;
case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
rmask = 0xFFFF, gmask = 0xFFFF;
bmask = 0xFFFF, amask = 0;
depth = 48, pitch = image.width*6;
break;
case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
rmask = 0xFFFF, gmask = 0xFFFF;
bmask = 0xFFFF, amask = 0xFFFF;
depth = 64, pitch = image.width*8;
break;
default: return; }
iconSurface = SDL_CreateRGBSurfaceFrom( image.data, image.width, image.height, depth, pitch, rmask, gmask, bmask, amask );
if (iconSurface)
{
SDL_SetWindowIcon(platform.window, iconSurface);
SDL_FreeSurface(iconSurface);
}
}
void SetWindowIcons(Image *images, int count)
{
TRACELOG(LOG_WARNING, "SetWindowIcons() not available on target platform");
}
void SetWindowTitle(const char *title)
{
SDL_SetWindowTitle(platform.window, title);
CORE.Window.title = title;
}
void SetWindowPosition(int x, int y)
{
SDL_SetWindowPosition(platform.window, x, y);
CORE.Window.position.x = x;
CORE.Window.position.y = y;
}
void SetWindowMonitor(int monitor)
{
const int monitorCount = SDL_GetNumVideoDisplays();
if ((monitor >= 0) && (monitor < monitorCount))
{
const bool wasFullscreen = ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)? true : false;
const int screenWidth = CORE.Window.screen.width;
const int screenHeight = CORE.Window.screen.height;
SDL_Rect usableBounds;
#if defined(PLATFORM_DESKTOP_SDL3)
if (SDL_GetDisplayUsableBounds(monitor, &usableBounds))
#else
if (SDL_GetDisplayUsableBounds(monitor, &usableBounds) == 0)
#endif
{
if (wasFullscreen == 1) ToggleFullscreen();
if ((screenWidth >= usableBounds.w) || (screenHeight >= usableBounds.h))
{
SDL_SetWindowPosition(platform.window, usableBounds.x, usableBounds.y);
CORE.Window.position.x = usableBounds.x;
CORE.Window.position.y = usableBounds.y;
}
else
{
const int x = usableBounds.x + (usableBounds.w/2) - (screenWidth/2);
const int y = usableBounds.y + (usableBounds.h/2) - (screenHeight/2);
SDL_SetWindowPosition(platform.window, x, y);
CORE.Window.position.x = x;
CORE.Window.position.y = y;
}
if (wasFullscreen == 1) ToggleFullscreen(); }
else TRACELOG(LOG_WARNING, "SDL: Failed to get selected display usable bounds");
}
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
}
void SetWindowMinSize(int width, int height)
{
SDL_SetWindowMinimumSize(platform.window, width, height);
CORE.Window.screenMin.width = width;
CORE.Window.screenMin.height = height;
}
void SetWindowMaxSize(int width, int height)
{
SDL_SetWindowMaximumSize(platform.window, width, height);
CORE.Window.screenMax.width = width;
CORE.Window.screenMax.height = height;
}
void SetWindowSize(int width, int height)
{
SDL_SetWindowSize(platform.window, width, height);
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
}
void SetWindowOpacity(float opacity)
{
if (opacity >= 1.0f) opacity = 1.0f;
else if (opacity <= 0.0f) opacity = 0.0f;
SDL_SetWindowOpacity(platform.window, opacity);
}
void SetWindowFocused(void)
{
SDL_RaiseWindow(platform.window);
}
void *GetWindowHandle(void)
{
return (void *)platform.window;
}
int GetMonitorCount(void)
{
int monitorCount = 0;
monitorCount = SDL_GetNumVideoDisplays();
return monitorCount;
}
int GetCurrentMonitor(void)
{
int currentMonitor = 0;
currentMonitor = SDL_GetWindowDisplayIndex(platform.window);
return currentMonitor;
}
Vector2 GetMonitorPosition(int monitor)
{
const int monitorCount = SDL_GetNumVideoDisplays();
if ((monitor >= 0) && (monitor < monitorCount))
{
SDL_Rect displayBounds;
#if defined(PLATFORM_DESKTOP_SDL3)
if (SDL_GetDisplayUsableBounds(monitor, &displayBounds))
#else
if (SDL_GetDisplayUsableBounds(monitor, &displayBounds) == 0)
#endif
{
return (Vector2){ (float)displayBounds.x, (float)displayBounds.y };
}
else TRACELOG(LOG_WARNING, "SDL: Failed to get selected display usable bounds");
}
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
return (Vector2){ 0.0f, 0.0f };
}
int GetMonitorWidth(int monitor)
{
int width = 0;
const int monitorCount = SDL_GetNumVideoDisplays();
if ((monitor >= 0) && (monitor < monitorCount))
{
SDL_DisplayMode mode;
SDL_GetCurrentDisplayMode(monitor, &mode);
width = mode.w;
}
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
return width;
}
int GetMonitorHeight(int monitor)
{
int height = 0;
const int monitorCount = SDL_GetNumVideoDisplays();
if ((monitor >= 0) && (monitor < monitorCount))
{
SDL_DisplayMode mode;
SDL_GetCurrentDisplayMode(monitor, &mode);
height = mode.h;
}
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
return height;
}
int GetMonitorPhysicalWidth(int monitor)
{
int width = 0;
const int monitorCount = SDL_GetNumVideoDisplays();
if ((monitor >= 0) && (monitor < monitorCount))
{
float ddpi = 0.0f;
SDL_GetDisplayDPI(monitor, &ddpi, NULL, NULL);
SDL_DisplayMode mode;
SDL_GetCurrentDisplayMode(monitor, &mode);
if (ddpi > 0.0f) width = (mode.w/ddpi)*25.4f;
}
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
return width;
}
int GetMonitorPhysicalHeight(int monitor)
{
int height = 0;
const int monitorCount = SDL_GetNumVideoDisplays();
if ((monitor >= 0) && (monitor < monitorCount))
{
float ddpi = 0.0f;
SDL_GetDisplayDPI(monitor, &ddpi, NULL, NULL);
SDL_DisplayMode mode;
SDL_GetCurrentDisplayMode(monitor, &mode);
if (ddpi > 0.0f) height = (mode.h/ddpi)*25.4f;
}
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
return height;
}
int GetMonitorRefreshRate(int monitor)
{
int refresh = 0;
const int monitorCount = SDL_GetNumVideoDisplays();
if ((monitor >= 0) && (monitor < monitorCount))
{
SDL_DisplayMode mode;
SDL_GetCurrentDisplayMode(monitor, &mode);
refresh = mode.refresh_rate;
}
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
return refresh;
}
const char *GetMonitorName(int monitor)
{
const int monitorCount = SDL_GetNumVideoDisplays();
if ((monitor >= 0) && (monitor < monitorCount)) return SDL_GetDisplayName(monitor);
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
return "";
}
Vector2 GetWindowPosition(void)
{
int x = 0;
int y = 0;
SDL_GetWindowPosition(platform.window, &x, &y);
return (Vector2){ (float)x, (float)y };
}
Vector2 GetWindowScaleDPI(void)
{
Vector2 scale = { 1.0f, 1.0f };
#ifndef PLATFORM_DESKTOP_SDL3
TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform");
#else
scale.x = SDL_GetWindowDisplayScale(platform.window);
scale.y = scale.x;
TRACELOG(LOG_INFO, "WindowScaleDPI is %f", scale.x);
#endif
return scale;
}
void SetClipboardText(const char *text)
{
SDL_SetClipboardText(text);
}
const char *GetClipboardText(void)
{
static char buffer[MAX_CLIPBOARD_BUFFER_LENGTH] = { 0 };
char *clipboard = SDL_GetClipboardText();
int clipboardSize = snprintf(buffer, sizeof(buffer), "%s", clipboard);
if (clipboardSize >= MAX_CLIPBOARD_BUFFER_LENGTH)
{
char *truncate = buffer + MAX_CLIPBOARD_BUFFER_LENGTH - 4;
sprintf(truncate, "...");
}
SDL_free(clipboard);
return buffer;
}
Image GetClipboardImage(void)
{
Image image = { 0 };
#if defined(SUPPORT_CLIPBOARD_IMAGE)
const char *imageFormats[] = {
"image/bmp",
"image/png",
"image/jpg",
"image/tiff",
};
const char *imageExtensions[] = {
".bmp",
".png",
".jpg",
".tiff",
};
size_t dataSize = 0;
void *fileData = NULL;
for (int i = 0; i < SDL_arraysize(imageFormats); ++i)
{
fileData = SDL_GetClipboardData(imageFormats[i], &dataSize);
if (fileData)
{
image = LoadImageFromMemory(imageExtensions[i], fileData, dataSize);
if (IsImageValid(image))
{
TRACELOG(LOG_INFO, "Clipboard image: Got image from clipboard as a `%s` successfully", imageExtensions[i]);
return image;
}
}
}
if (!IsImageValid(image)) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data. Error: %s", SDL_GetError());
#endif
return image;
}
void ShowCursor(void)
{
#if defined(PLATFORM_DESKTOP_SDL3)
SDL_ShowCursor();
#else
SDL_ShowCursor(SDL_ENABLE);
#endif
CORE.Input.Mouse.cursorHidden = false;
}
void HideCursor(void)
{
#if defined(PLATFORM_DESKTOP_SDL3)
SDL_HideCursor();
#else
SDL_ShowCursor(SDL_DISABLE);
#endif
CORE.Input.Mouse.cursorHidden = true;
}
void EnableCursor(void)
{
SDL_SetRelativeMouseMode(SDL_FALSE);
#if defined(PLATFORM_DESKTOP_SDL3)
SDL_ShowCursor();
#else
SDL_ShowCursor(SDL_ENABLE);
#endif
platform.cursorRelative = false;
CORE.Input.Mouse.cursorHidden = false;
}
void DisableCursor(void)
{
SDL_SetRelativeMouseMode(SDL_TRUE);
platform.cursorRelative = true;
CORE.Input.Mouse.cursorHidden = true;
}
void SwapScreenBuffer(void)
{
SDL_GL_SwapWindow(platform.window);
}
double GetTime(void)
{
unsigned int ms = SDL_GetTicks(); double time = (double)ms/1000;
return time;
}
void OpenURL(const char *url)
{
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
else SDL_OpenURL(url);
}
int SetGamepadMappings(const char *mappings)
{
return SDL_GameControllerAddMapping(mappings);
}
void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration)
{
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (duration > 0.0f))
{
if (leftMotor < 0.0f) leftMotor = 0.0f;
if (leftMotor > 1.0f) leftMotor = 1.0f;
if (rightMotor < 0.0f) rightMotor = 0.0f;
if (rightMotor > 1.0f) rightMotor = 1.0f;
if (duration > MAX_GAMEPAD_VIBRATION_TIME) duration = MAX_GAMEPAD_VIBRATION_TIME;
SDL_GameControllerRumble(platform.gamepad[gamepad], (Uint16)(leftMotor*65535.0f), (Uint16)(rightMotor*65535.0f), (Uint32)(duration*1000.0f));
}
}
void SetMousePosition(int x, int y)
{
SDL_WarpMouseInWindow(platform.window, x, y);
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
}
void SetMouseCursor(int cursor)
{
platform.cursor = SDL_CreateSystemCursor(CursorsLUT[cursor]);
SDL_SetCursor(platform.cursor);
CORE.Input.Mouse.cursor = cursor;
}
const char *GetKeyName(int key)
{
return SDL_GetKeyName(key);
}
static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event)
{
#if defined(PLATFORM_DESKTOP_SDL3)
int count = 0;
SDL_Finger **fingers = SDL_GetTouchFingers(event.touchID, &count);
CORE.Input.Touch.pointCount = count;
for (int i = 0; i < CORE.Input.Touch.pointCount; i++)
{
SDL_Finger *finger = fingers[i];
CORE.Input.Touch.pointId[i] = finger->id;
CORE.Input.Touch.position[i].x = finger->x*CORE.Window.screen.width;
CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height;
CORE.Input.Touch.currentTouchState[i] = 1;
}
SDL_free(fingers);
#else
CORE.Input.Touch.pointCount = SDL_GetNumTouchFingers(event.touchId);
for (int i = 0; i < CORE.Input.Touch.pointCount; i++)
{
SDL_Finger *finger = SDL_GetTouchFinger(event.touchId, i);
CORE.Input.Touch.pointId[i] = finger->id;
CORE.Input.Touch.position[i].x = finger->x*CORE.Window.screen.width;
CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height;
CORE.Input.Touch.currentTouchState[i] = 1;
}
#endif
for (int i = CORE.Input.Touch.pointCount; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.currentTouchState[i] = 0;
}
void PollInputEvents(void)
{
#if defined(SUPPORT_GESTURES_SYSTEM)
UpdateGestures();
#endif
CORE.Input.Keyboard.keyPressedQueueCount = 0;
CORE.Input.Keyboard.charPressedQueueCount = 0;
CORE.Input.Mouse.currentWheelMove.x = 0;
CORE.Input.Mouse.currentWheelMove.y = 0;
if (platform.cursorRelative) CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f };
else CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
for (int i = 0; (i < SDL_NumJoysticks()) && (i < MAX_GAMEPADS); i++)
{
if (CORE.Input.Gamepad.ready[i])
{
for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++)
{
CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k];
}
}
}
for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i];
CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
int touchAction = -1; bool realTouch = false;
for (int i = 0; i < MAX_KEYBOARD_KEYS; i++)
{
CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i];
CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;
}
for (int i = 0; i < MAX_MOUSE_BUTTONS; i++) CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i];
CORE.Window.resizedLastFrame = false;
SDL_Event event = { 0 };
while (SDL_PollEvent(&event) != 0)
{
switch (event.type)
{
case SDL_QUIT: CORE.Window.shouldClose = true; break;
case SDL_DROPFILE: {
if (CORE.Window.dropFileCount == 0)
{
CORE.Window.dropFilepaths = (char **)RL_CALLOC(1024, sizeof(char *));
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
#if defined(PLATFORM_DESKTOP_SDL3)
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data);
#else
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file);
SDL_free(event.drop.file);
#endif
CORE.Window.dropFileCount++;
}
else if (CORE.Window.dropFileCount < 1024)
{
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
#if defined(PLATFORM_DESKTOP_SDL3)
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data);
#else
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file);
SDL_free(event.drop.file);
#endif
CORE.Window.dropFileCount++;
}
else TRACELOG(LOG_WARNING, "FILE: Maximum drag and drop files at once is limited to 1024 files!");
} break;
#ifndef PLATFORM_DESKTOP_SDL3
case SDL_WINDOWEVENT:
{
switch (event.window.event)
{
#endif
case SDL_WINDOWEVENT_RESIZED:
case SDL_WINDOWEVENT_SIZE_CHANGED:
{
const int width = event.window.data1;
const int height = event.window.data2;
SetupViewport(width, height);
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
CORE.Window.currentFbo.width = width;
CORE.Window.currentFbo.height = height;
CORE.Window.resizedLastFrame = true;
} break;
case SDL_WINDOWEVENT_ENTER:
{
CORE.Input.Mouse.cursorOnScreen = true;
} break;
case SDL_WINDOWEVENT_LEAVE:
{
CORE.Input.Mouse.cursorOnScreen = false;
} break;
case SDL_WINDOWEVENT_HIDDEN:
case SDL_WINDOWEVENT_MINIMIZED:
case SDL_WINDOWEVENT_FOCUS_LOST:
case SDL_WINDOWEVENT_SHOWN:
case SDL_WINDOWEVENT_FOCUS_GAINED:
case SDL_WINDOWEVENT_MAXIMIZED:
case SDL_WINDOWEVENT_RESTORED:
#if defined(PLATFORM_DESKTOP_SDL3)
break;
#else
default: break;
}
} break;
#endif
case SDL_KEYDOWN:
{
#if defined(PLATFORM_DESKTOP_SDL3)
KeyboardKey key = ConvertScancodeToKey(event.key.scancode);
#else
KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode);
#endif
if (key != KEY_NULL)
{
if ((CORE.Input.Keyboard.currentKeyState[key] == 0) && (CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE))
{
CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key;
CORE.Input.Keyboard.keyPressedQueueCount++;
}
CORE.Input.Keyboard.currentKeyState[key] = 1;
}
if (event.key.repeat) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1;
if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey])
{
CORE.Window.shouldClose = true;
}
} break;
case SDL_KEYUP:
{
#if defined(PLATFORM_DESKTOP_SDL3)
KeyboardKey key = ConvertScancodeToKey(event.key.scancode);
#else
KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode);
#endif
if (key != KEY_NULL) CORE.Input.Keyboard.currentKeyState[key] = 0;
} break;
case SDL_TEXTINPUT:
{
int codepointSize = 0;
if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
{
CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = GetCodepointNext(event.text.text, &codepointSize);
CORE.Input.Keyboard.charPressedQueueCount++;
}
} break;
case SDL_MOUSEBUTTONDOWN:
{
int btn = event.button.button - 1;
if (btn == 2) btn = 1;
else if (btn == 1) btn = 2;
CORE.Input.Mouse.currentButtonState[btn] = 1;
CORE.Input.Touch.currentTouchState[btn] = 1;
touchAction = 1;
} break;
case SDL_MOUSEBUTTONUP:
{
int btn = event.button.button - 1;
if (btn == 2) btn = 1;
else if (btn == 1) btn = 2;
CORE.Input.Mouse.currentButtonState[btn] = 0;
CORE.Input.Touch.currentTouchState[btn] = 0;
touchAction = 0;
} break;
case SDL_MOUSEWHEEL:
{
CORE.Input.Mouse.currentWheelMove.x = (float)event.wheel.x;
CORE.Input.Mouse.currentWheelMove.y = (float)event.wheel.y;
} break;
case SDL_MOUSEMOTION:
{
if (platform.cursorRelative)
{
CORE.Input.Mouse.currentPosition.x = (float)event.motion.xrel;
CORE.Input.Mouse.currentPosition.y = (float)event.motion.yrel;
CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f };
}
else
{
CORE.Input.Mouse.currentPosition.x = (float)event.motion.x;
CORE.Input.Mouse.currentPosition.y = (float)event.motion.y;
}
CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
touchAction = 2;
} break;
case SDL_FINGERDOWN:
{
UpdateTouchPointsSDL(event.tfinger);
touchAction = 1;
realTouch = true;
} break;
case SDL_FINGERUP:
{
UpdateTouchPointsSDL(event.tfinger);
touchAction = 0;
realTouch = true;
} break;
case SDL_FINGERMOTION:
{
UpdateTouchPointsSDL(event.tfinger);
touchAction = 2;
realTouch = true;
} break;
case SDL_JOYDEVICEADDED:
{
int jid = event.jdevice.which;
if (!CORE.Input.Gamepad.ready[jid] && (jid < MAX_GAMEPADS))
{
platform.gamepad[jid] = SDL_GameControllerOpen(jid);
if (platform.gamepad[jid])
{
CORE.Input.Gamepad.ready[jid] = true;
CORE.Input.Gamepad.axisCount[jid] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[jid]));
CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
strncpy(CORE.Input.Gamepad.name[jid], SDL_GameControllerNameForIndex(jid), 63);
CORE.Input.Gamepad.name[jid][63] = '\0';
}
else
{
TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
}
}
} break;
case SDL_JOYDEVICEREMOVED:
{
int jid = event.jdevice.which;
if (jid == SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[jid])))
{
SDL_GameControllerClose(platform.gamepad[jid]);
platform.gamepad[jid] = SDL_GameControllerOpen(0);
CORE.Input.Gamepad.ready[jid] = false;
memset(CORE.Input.Gamepad.name[jid], 0, 64);
}
} break;
case SDL_CONTROLLERBUTTONDOWN:
{
int button = -1;
switch (event.jbutton.button)
{
case SDL_CONTROLLER_BUTTON_Y: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break;
case SDL_CONTROLLER_BUTTON_B: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break;
case SDL_CONTROLLER_BUTTON_A: button = GAMEPAD_BUTTON_RIGHT_FACE_DOWN; break;
case SDL_CONTROLLER_BUTTON_X: button = GAMEPAD_BUTTON_RIGHT_FACE_LEFT; break;
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: button = GAMEPAD_BUTTON_LEFT_TRIGGER_1; break;
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: button = GAMEPAD_BUTTON_RIGHT_TRIGGER_1; break;
case SDL_CONTROLLER_BUTTON_BACK: button = GAMEPAD_BUTTON_MIDDLE_LEFT; break;
case SDL_CONTROLLER_BUTTON_GUIDE: button = GAMEPAD_BUTTON_MIDDLE; break;
case SDL_CONTROLLER_BUTTON_START: button = GAMEPAD_BUTTON_MIDDLE_RIGHT; break;
case SDL_CONTROLLER_BUTTON_DPAD_UP: button = GAMEPAD_BUTTON_LEFT_FACE_UP; break;
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: button = GAMEPAD_BUTTON_LEFT_FACE_RIGHT; break;
case SDL_CONTROLLER_BUTTON_DPAD_DOWN: button = GAMEPAD_BUTTON_LEFT_FACE_DOWN; break;
case SDL_CONTROLLER_BUTTON_DPAD_LEFT: button = GAMEPAD_BUTTON_LEFT_FACE_LEFT; break;
case SDL_CONTROLLER_BUTTON_LEFTSTICK: button = GAMEPAD_BUTTON_LEFT_THUMB; break;
case SDL_CONTROLLER_BUTTON_RIGHTSTICK: button = GAMEPAD_BUTTON_RIGHT_THUMB; break;
default: break;
}
if (button >= 0)
{
CORE.Input.Gamepad.currentButtonState[event.jbutton.which][button] = 1;
CORE.Input.Gamepad.lastButtonPressed = button;
}
} break;
case SDL_CONTROLLERBUTTONUP:
{
int button = -1;
switch (event.jbutton.button)
{
case SDL_CONTROLLER_BUTTON_Y: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break;
case SDL_CONTROLLER_BUTTON_B: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break;
case SDL_CONTROLLER_BUTTON_A: button = GAMEPAD_BUTTON_RIGHT_FACE_DOWN; break;
case SDL_CONTROLLER_BUTTON_X: button = GAMEPAD_BUTTON_RIGHT_FACE_LEFT; break;
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: button = GAMEPAD_BUTTON_LEFT_TRIGGER_1; break;
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: button = GAMEPAD_BUTTON_RIGHT_TRIGGER_1; break;
case SDL_CONTROLLER_BUTTON_BACK: button = GAMEPAD_BUTTON_MIDDLE_LEFT; break;
case SDL_CONTROLLER_BUTTON_GUIDE: button = GAMEPAD_BUTTON_MIDDLE; break;
case SDL_CONTROLLER_BUTTON_START: button = GAMEPAD_BUTTON_MIDDLE_RIGHT; break;
case SDL_CONTROLLER_BUTTON_DPAD_UP: button = GAMEPAD_BUTTON_LEFT_FACE_UP; break;
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: button = GAMEPAD_BUTTON_LEFT_FACE_RIGHT; break;
case SDL_CONTROLLER_BUTTON_DPAD_DOWN: button = GAMEPAD_BUTTON_LEFT_FACE_DOWN; break;
case SDL_CONTROLLER_BUTTON_DPAD_LEFT: button = GAMEPAD_BUTTON_LEFT_FACE_LEFT; break;
case SDL_CONTROLLER_BUTTON_LEFTSTICK: button = GAMEPAD_BUTTON_LEFT_THUMB; break;
case SDL_CONTROLLER_BUTTON_RIGHTSTICK: button = GAMEPAD_BUTTON_RIGHT_THUMB; break;
default: break;
}
if (button >= 0)
{
CORE.Input.Gamepad.currentButtonState[event.jbutton.which][button] = 0;
if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
}
} break;
case SDL_CONTROLLERAXISMOTION:
{
int axis = -1;
switch (event.jaxis.axis)
{
case SDL_CONTROLLER_AXIS_LEFTX: axis = GAMEPAD_AXIS_LEFT_X; break;
case SDL_CONTROLLER_AXIS_LEFTY: axis = GAMEPAD_AXIS_LEFT_Y; break;
case SDL_CONTROLLER_AXIS_RIGHTX: axis = GAMEPAD_AXIS_RIGHT_X; break;
case SDL_CONTROLLER_AXIS_RIGHTY: axis = GAMEPAD_AXIS_RIGHT_Y; break;
case SDL_CONTROLLER_AXIS_TRIGGERLEFT: axis = GAMEPAD_AXIS_LEFT_TRIGGER; break;
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: axis = GAMEPAD_AXIS_RIGHT_TRIGGER; break;
default: break;
}
if (axis >= 0)
{
float value = event.jaxis.value/(float)32767;
CORE.Input.Gamepad.axisState[event.jaxis.which][axis] = value;
if ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))
{
int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER)? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2;
int pressed = (value > 0.1f);
CORE.Input.Gamepad.currentButtonState[event.jaxis.which][button] = pressed;
if (pressed) CORE.Input.Gamepad.lastButtonPressed = button;
else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
}
}
} break;
default: break;
}
#if defined(SUPPORT_GESTURES_SYSTEM)
if (touchAction > -1)
{
GestureEvent gestureEvent = { 0 };
gestureEvent.touchAction = touchAction;
gestureEvent.pointId[0] = 0;
gestureEvent.pointCount = 1;
if (touchAction == 2 || realTouch) gestureEvent.position[0] = CORE.Input.Touch.position[0];
else gestureEvent.position[0] = GetMousePosition();
gestureEvent.position[0].x /= (float)GetScreenWidth();
gestureEvent.position[0].y /= (float)GetScreenHeight();
ProcessGestureEvent(gestureEvent);
touchAction = -1;
}
#endif
}
}
int InitPlatform(void)
{
int result = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER);
if (result < 0) { TRACELOG(LOG_WARNING, "SDL: Failed to initialize SDL"); return -1; }
unsigned int flags = 0;
flags |= SDL_WINDOW_SHOWN;
flags |= SDL_WINDOW_OPENGL;
flags |= SDL_WINDOW_INPUT_FOCUS;
flags |= SDL_WINDOW_MOUSE_FOCUS;
flags |= SDL_WINDOW_MOUSE_CAPTURE;
if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)
{
CORE.Window.fullscreen = true;
flags |= SDL_WINDOW_FULLSCREEN;
}
if ((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) flags |= SDL_WINDOW_BORDERLESS;
if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) flags |= SDL_WINDOW_RESIZABLE;
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) flags |= SDL_WINDOW_MINIMIZED;
if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) flags |= SDL_WINDOW_MAXIMIZED;
if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0)
{
flags &= ~SDL_WINDOW_INPUT_FOCUS;
flags &= ~SDL_WINDOW_MOUSE_FOCUS;
}
if ((CORE.Window.flags & FLAG_WINDOW_TOPMOST) > 0) flags |= SDL_WINDOW_ALWAYS_ON_TOP;
if ((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0) flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) flags |= SDL_WINDOW_ALLOW_HIGHDPI;
if (rlGetVersion() == RL_OPENGL_21)
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
}
else if (rlGetVersion() == RL_OPENGL_33)
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
}
else if (rlGetVersion() == RL_OPENGL_43)
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); #endif
}
else if (rlGetVersion() == RL_OPENGL_ES_20) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
}
else if (rlGetVersion() == RL_OPENGL_ES_30) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
}
if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
{
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
}
#if defined(PLATFORM_DESKTOP_SDL3)
platform.window = SDL_CreateWindow(CORE.Window.title, CORE.Window.screen.width, CORE.Window.screen.height, flags);
#else
platform.window = SDL_CreateWindow(CORE.Window.title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, CORE.Window.screen.width, CORE.Window.screen.height, flags);
#endif
platform.glContext = SDL_GL_CreateContext(platform.window);
if ((platform.window != NULL) && (platform.glContext != NULL))
{
CORE.Window.ready = true;
SDL_DisplayMode displayMode = { 0 };
SDL_GetCurrentDisplayMode(GetCurrentMonitor(), &displayMode);
CORE.Window.display.width = displayMode.w;
CORE.Window.display.height = displayMode.h;
CORE.Window.render.width = CORE.Window.screen.width;
CORE.Window.render.height = CORE.Window.screen.height;
CORE.Window.currentFbo.width = CORE.Window.render.width;
CORE.Window.currentFbo.height = CORE.Window.render.height;
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
if (CORE.Window.flags & FLAG_VSYNC_HINT) SDL_GL_SetSwapInterval(1);
else SDL_GL_SetSwapInterval(0);
}
else
{
TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphics device");
return -1;
}
rlLoadExtensions(SDL_GL_GetProcAddress);
for (int i = 0; (i < SDL_NumJoysticks()) && (i < MAX_GAMEPADS); i++)
{
platform.gamepad[i] = SDL_GameControllerOpen(i);
if (platform.gamepad[i])
{
CORE.Input.Gamepad.ready[i] = true;
CORE.Input.Gamepad.axisCount[i] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[i]));
CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
strncpy(CORE.Input.Gamepad.name[i], SDL_GameControllerNameForIndex(i), 63);
CORE.Input.Gamepad.name[i][63] = '\0';
}
else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
}
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
CORE.Time.previous = GetTime();
#if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP)
SDL_SetHint(SDL_HINT_TIMER_RESOLUTION, "1"); #endif
CORE.Storage.basePath = SDL_GetBasePath();
#if defined(PLATFORM_DESKTOP_SDL3)
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL3): Initialized successfully");
#else
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL2): Initialized successfully");
#endif
return 0;
}
void ClosePlatform(void)
{
SDL_FreeCursor(platform.cursor); SDL_GL_DeleteContext(platform.glContext); SDL_DestroyWindow(platform.window);
SDL_Quit(); }
static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode)
{
if (sdlScancode >= 0 && sdlScancode < SCANCODE_MAPPED_NUM)
{
return mapScancodeToKey[sdlScancode];
}
return KEY_NULL; }