aboutsummaryrefslogtreecommitdiff
path: root/raylib/src/platforms/rcore_desktop_sdl.c
diff options
context:
space:
mode:
Diffstat (limited to 'raylib/src/platforms/rcore_desktop_sdl.c')
-rw-r--r--raylib/src/platforms/rcore_desktop_sdl.c1978
1 files changed, 1978 insertions, 0 deletions
diff --git a/raylib/src/platforms/rcore_desktop_sdl.c b/raylib/src/platforms/rcore_desktop_sdl.c
new file mode 100644
index 0000000..a201f2c
--- /dev/null
+++ b/raylib/src/platforms/rcore_desktop_sdl.c
@@ -0,0 +1,1978 @@
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//----------------------------------------------------------------------------------
81typedef 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//----------------------------------------------------------------------------------
93extern CoreData CORE; // Global CORE state context
94
95static PlatformData platform = { 0 }; // Platform specific data
96
97//----------------------------------------------------------------------------------
98// Local Variables Definition
99//----------------------------------------------------------------------------------
100#define SCANCODE_MAPPED_NUM 232
101static 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
225static 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
271const 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
287int 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.
301Uint8 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
313void 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
330SDL_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
340int 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
348SDL_Surface *SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth, Uint32 format)
349{
350 return SDL_CreateSurface(width, height, format);
351}
352
353SDL_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
358SDL_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
363int 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.
375int 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
394bool SDL_GetRelativeMouseMode_Adapter(void)
395{
396 return SDL_GetWindowRelativeMouseMode(platform.window);
397}
398
399#define SDL_GetRelativeMouseMode SDL_GetRelativeMouseMode_Adapter
400
401
402int 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)
415void* 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//----------------------------------------------------------------------------------
428int InitPlatform(void); // Initialize platform (graphics, inputs and more)
429void ClosePlatform(void); // Close platform
430
431static 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
443bool WindowShouldClose(void)
444{
445 if (CORE.Window.ready) return CORE.Window.shouldClose;
446 else return true;
447}
448
449// Toggle fullscreen mode
450void 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
478void 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
503void MaximizeWindow(void)
504{
505 SDL_MaximizeWindow(platform.window);
506 CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
507}
508
509// Set window state: minimized
510void MinimizeWindow(void)
511{
512 SDL_MinimizeWindow(platform.window);
513 CORE.Window.flags |= FLAG_WINDOW_MINIMIZED;
514}
515
516// Set window state: not minimized/maximized
517void RestoreWindow(void)
518{
519 SDL_ShowWindow(platform.window);
520}
521
522// Set window configuration state using flags
523void 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
620void 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
696void 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
784void SetWindowIcons(Image *images, int count)
785{
786 TRACELOG(LOG_WARNING, "SetWindowIcons() not available on target platform");
787}
788
789// Set title for window
790void 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)
798void 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
807void 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)
861void 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)
870void 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
879void 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
888void 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
897void SetWindowFocused(void)
898{
899 SDL_RaiseWindow(platform.window);
900}
901
902// Get native window handle
903void *GetWindowHandle(void)
904{
905 return (void *)platform.window;
906}
907
908// Get number of monitors
909int GetMonitorCount(void)
910{
911 int monitorCount = 0;
912
913 monitorCount = SDL_GetNumVideoDisplays();
914
915 return monitorCount;
916}
917
918// Get number of monitors
919int 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
930Vector2 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)
951int 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)
968int 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
985int 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
1005int 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
1025int 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
1042const 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
1053Vector2 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
1064Vector2 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
1083void SetClipboardText(const char *text)
1084{
1085 SDL_SetClipboardText(text);
1086}
1087
1088// Get clipboard text content
1089const 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
1110Image 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
1151void 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
1162void 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)
1173void 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)
1189void 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)
1198void 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
1208double 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
1220void 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
1232int SetGamepadMappings(const char *mappings)
1233{
1234 return SDL_GameControllerAddMapping(mappings);
1235}
1236
1237// Set gamepad vibration
1238void 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
1253void 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
1262void 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.
1271const char *GetKeyName(int key)
1272{
1273 return SDL_GetKeyName(key);
1274}
1275
1276static 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
1310void 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
1774int 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
1960void 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
1969static 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

Generated with cgit - Back to sebastiano.tronto.net