platforms c-source files updated

This commit is contained in:
JupiterRider 2024-11-23 17:07:41 +01:00
parent 614ed9f942
commit fc50e055c0
5 changed files with 981 additions and 685 deletions

View file

@ -74,14 +74,14 @@ typedef struct {
// Global Variables Definition // Global Variables Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
extern CoreData CORE; // Global CORE state context extern CoreData CORE; // Global CORE state context
extern bool isGpuReady; // Flag to note GPU has been initialized successfully
static PlatformData platform = { 0 }; // Platform specific data static PlatformData platform = { 0 }; // Platform specific data
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Local Variables Definition // Local Variables Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#define KEYCODE_MAP_SIZE 162 #define KEYCODE_MAP_SIZE 162
static const KeyboardKey KeycodeMap[KEYCODE_MAP_SIZE] = { static const KeyboardKey mapKeycode[KEYCODE_MAP_SIZE] = {
KEY_NULL, // AKEYCODE_UNKNOWN KEY_NULL, // AKEYCODE_UNKNOWN
0, // AKEYCODE_SOFT_LEFT 0, // AKEYCODE_SOFT_LEFT
0, // AKEYCODE_SOFT_RIGHT 0, // AKEYCODE_SOFT_RIGHT
@ -267,8 +267,7 @@ static GamepadButton AndroidTranslateGamepadButton(int button);
// To allow easier porting to android, we allow the user to define a // To allow easier porting to android, we allow the user to define a
// main function which we call from android_main, defined by ourselves // main function which we call from android_main, defined by ourselves
//extern int main(int argc, char *argv[]); extern int main(int argc, char *argv[]);
extern void android_run();
// Android main function // Android main function
void android_main(struct android_app *app) void android_main(struct android_app *app)
@ -276,21 +275,21 @@ void android_main(struct android_app *app)
char arg0[] = "raylib"; // NOTE: argv[] are mutable char arg0[] = "raylib"; // NOTE: argv[] are mutable
platform.app = app; platform.app = app;
(void)android_run();
// NOTE: Return from main is ignored // NOTE: Return from main is ignored
//(void)main(1, (char *[]) { arg0, NULL }); (void)main(1, (char *[]) { arg0, NULL });
// Request to end the native activity // Request to end the native activity
ANativeActivity_finish(app->activity); ANativeActivity_finish(app->activity);
// Android ALooper_pollAll() variables // Android ALooper_pollOnce() variables
int pollResult = 0; int pollResult = 0;
int pollEvents = 0; int pollEvents = 0;
// Waiting for application events before complete finishing // Waiting for application events before complete finishing
while (!app->destroyRequested) while (!app->destroyRequested)
{ {
while ((pollResult = ALooper_pollAll(0, NULL, &pollEvents, (void **)&platform.source)) >= 0) // Poll all events until we reach return value TIMEOUT, meaning no events left to process
while ((pollResult = ALooper_pollOnce(0, NULL, &pollEvents, (void **)&platform.source)) > ALOOPER_POLL_TIMEOUT)
{ {
if (platform.source != NULL) platform.source->process(app, platform.source); if (platform.source != NULL) platform.source->process(app, platform.source);
} }
@ -616,7 +615,7 @@ int SetGamepadMappings(const char *mappings)
} }
// Set gamepad vibration // Set gamepad vibration
void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor) void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration)
{ {
TRACELOG(LOG_WARNING, "GamepadSetVibration() not implemented on target platform"); TRACELOG(LOG_WARNING, "GamepadSetVibration() not implemented on target platform");
} }
@ -634,6 +633,13 @@ void SetMouseCursor(int cursor)
TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform"); TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform");
} }
// Get physical key name.
const char *GetKeyName(int key)
{
TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform");
return "";
}
// Register all input events // Register all input events
void PollInputEvents(void) void PollInputEvents(void)
{ {
@ -677,27 +683,27 @@ void PollInputEvents(void)
CORE.Input.Keyboard.keyRepeatInFrame[i] = 0; CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;
} }
// Android ALooper_pollAll() variables // Android ALooper_pollOnce() variables
int pollResult = 0; int pollResult = 0;
int pollEvents = 0; int pollEvents = 0;
// Poll Events (registered events) // Poll Events (registered events) until we reach TIMEOUT which indicates there are no events left to poll
// NOTE: Activity is paused if not enabled (platform.appEnabled) // NOTE: Activity is paused if not enabled (platform.appEnabled)
while ((pollResult = ALooper_pollAll(platform.appEnabled? 0 : -1, NULL, &pollEvents, (void**)&platform.source)) >= 0) while ((pollResult = ALooper_pollOnce(platform.appEnabled? 0 : -1, NULL, &pollEvents, (void**)&platform.source)) > ALOOPER_POLL_TIMEOUT)
{ {
// Process this event // Process this event
if (platform.source != NULL) platform.source->process(platform.app, platform.source); if (platform.source != NULL) platform.source->process(platform.app, platform.source);
// NOTE: Never close window, native activity is controlled by the system! // NOTE: Allow closing the window in case a configuration change happened.
// The android_main function should be allowed to return to its caller in order for the
// Android OS to relaunch the activity.
if (platform.app->destroyRequested != 0) if (platform.app->destroyRequested != 0)
{ {
//CORE.Window.shouldClose = true; CORE.Window.shouldClose = true;
//ANativeActivity_finish(platform.app->activity);
} }
} }
} }
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Internal Functions Definition // Module Internal Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -762,20 +768,20 @@ int InitPlatform(void)
TRACELOG(LOG_INFO, "PLATFORM: ANDROID: Initialized successfully"); TRACELOG(LOG_INFO, "PLATFORM: ANDROID: Initialized successfully");
// Android ALooper_pollAll() variables // Android ALooper_pollOnce() variables
int pollResult = 0; int pollResult = 0;
int pollEvents = 0; int pollEvents = 0;
// Wait for window to be initialized (display and context) // Wait for window to be initialized (display and context)
while (!CORE.Window.ready) while (!CORE.Window.ready)
{ {
// Process events loop // Process events until we reach TIMEOUT, which indicates no more events queued.
while ((pollResult = ALooper_pollAll(0, NULL, &pollEvents, (void**)&platform.source)) >= 0) while ((pollResult = ALooper_pollOnce(0, NULL, &pollEvents, (void**)&platform.source)) > ALOOPER_POLL_TIMEOUT)
{ {
// Process this event // Process this event
if (platform.source != NULL) platform.source->process(platform.app, platform.source); if (platform.source != NULL) platform.source->process(platform.app, platform.source);
// NOTE: Never close window, native activity is controlled by the system! // NOTE: It's highly likely destroyRequested will never be non-zero at the start of the activity lifecycle.
//if (platform.app->destroyRequested != 0) CORE.Window.shouldClose = true; //if (platform.app->destroyRequested != 0) CORE.Window.shouldClose = true;
} }
} }
@ -806,6 +812,12 @@ void ClosePlatform(void)
eglTerminate(platform.device); eglTerminate(platform.device);
platform.device = EGL_NO_DISPLAY; platform.device = EGL_NO_DISPLAY;
} }
// NOTE: Reset global state in case the activity is being relaunched.
if (platform.app->destroyRequested != 0) {
CORE = (CoreData){0};
platform = (PlatformData){0};
}
} }
// Initialize display device and framebuffer // Initialize display device and framebuffer
@ -976,6 +988,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
// Initialize OpenGL context (states and resources) // Initialize OpenGL context (states and resources)
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl // NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height); rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
isGpuReady = true;
// Setup default viewport // Setup default viewport
// NOTE: It updated CORE.Window.render.width and CORE.Window.render.height // NOTE: It updated CORE.Window.render.width and CORE.Window.render.height
@ -1135,9 +1148,9 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_RIGHT_Y] = AMotionEvent_getAxisValue( CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_RIGHT_Y] = AMotionEvent_getAxisValue(
event, AMOTION_EVENT_AXIS_RZ, 0); event, AMOTION_EVENT_AXIS_RZ, 0);
CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_LEFT_TRIGGER] = AMotionEvent_getAxisValue( CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_LEFT_TRIGGER] = AMotionEvent_getAxisValue(
event, AMOTION_EVENT_AXIS_BRAKE, 0) * 2.0f - 1.0f; event, AMOTION_EVENT_AXIS_BRAKE, 0)*2.0f - 1.0f;
CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_RIGHT_TRIGGER] = AMotionEvent_getAxisValue( CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_RIGHT_TRIGGER] = AMotionEvent_getAxisValue(
event, AMOTION_EVENT_AXIS_GAS, 0) * 2.0f - 1.0f; event, AMOTION_EVENT_AXIS_GAS, 0)*2.0f - 1.0f;
// dpad is reported as an axis on android // dpad is reported as an axis on android
float dpadX = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_HAT_X, 0); float dpadX = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_HAT_X, 0);
@ -1203,7 +1216,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
return 1; // Handled gamepad button return 1; // Handled gamepad button
} }
KeyboardKey key = (keycode > 0 && keycode < KEYCODE_MAP_SIZE) ? KeycodeMap[keycode] : KEY_NULL; KeyboardKey key = (keycode > 0 && keycode < KEYCODE_MAP_SIZE)? mapKeycode[keycode] : KEY_NULL;
if (key != KEY_NULL) if (key != KEY_NULL)
{ {
// Save current key and its state // Save current key and its state
@ -1254,10 +1267,10 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
CORE.Input.Touch.position[i] = (Vector2){ AMotionEvent_getX(event, i), AMotionEvent_getY(event, i) }; CORE.Input.Touch.position[i] = (Vector2){ AMotionEvent_getX(event, i), AMotionEvent_getY(event, i) };
// Normalize CORE.Input.Touch.position[i] for CORE.Window.screen.width and CORE.Window.screen.height // Normalize CORE.Input.Touch.position[i] for CORE.Window.screen.width and CORE.Window.screen.height
float widthRatio = (float)(CORE.Window.screen.width + CORE.Window.renderOffset.x) / (float)CORE.Window.display.width; float widthRatio = (float)(CORE.Window.screen.width + CORE.Window.renderOffset.x)/(float)CORE.Window.display.width;
float heightRatio = (float)(CORE.Window.screen.height + CORE.Window.renderOffset.y) / (float)CORE.Window.display.height; float heightRatio = (float)(CORE.Window.screen.height + CORE.Window.renderOffset.y)/(float)CORE.Window.display.height;
CORE.Input.Touch.position[i].x = CORE.Input.Touch.position[i].x * widthRatio - (float)CORE.Window.renderOffset.x / 2; CORE.Input.Touch.position[i].x = CORE.Input.Touch.position[i].x*widthRatio - (float)CORE.Window.renderOffset.x/2;
CORE.Input.Touch.position[i].y = CORE.Input.Touch.position[i].y * heightRatio - (float)CORE.Window.renderOffset.y / 2; CORE.Input.Touch.position[i].y = CORE.Input.Touch.position[i].y*heightRatio - (float)CORE.Window.renderOffset.y/2;
} }
int32_t action = AMotionEvent_getAction(event); int32_t action = AMotionEvent_getAction(event);

View file

@ -58,6 +58,7 @@
#if defined(_WIN32) #if defined(_WIN32)
typedef void *PVOID; typedef void *PVOID;
typedef PVOID HANDLE; typedef PVOID HANDLE;
#include "../external/win32_clipboard.h"
typedef HANDLE HWND; typedef HANDLE HWND;
#define GLFW_EXPOSE_NATIVE_WIN32 #define GLFW_EXPOSE_NATIVE_WIN32
#define GLFW_NATIVE_INCLUDE_NONE // To avoid some symbols re-definition in windows.h #define GLFW_NATIVE_INCLUDE_NONE // To avoid some symbols re-definition in windows.h
@ -65,8 +66,9 @@
#if defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP) #if defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP)
// NOTE: Those functions require linking with winmm library // NOTE: Those functions require linking with winmm library
unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod); //#pragma warning(disable: 4273)
unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); __declspec(dllimport) unsigned int __stdcall timeEndPeriod(unsigned int uPeriod);
//#pragma warning(default: 4273)
#endif #endif
#endif #endif
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
@ -109,6 +111,7 @@ static void ErrorCallback(int error, const char *description);
// Window callbacks events // Window callbacks events
static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized
static void WindowPosCallback(GLFWwindow* window, int x, int y); // GLFW3 WindowPos Callback, runs when window is moved
static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored
static void WindowMaximizeCallback(GLFWwindow* window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized static void WindowMaximizeCallback(GLFWwindow* window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized
static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus
@ -147,7 +150,7 @@ void ToggleFullscreen(void)
if (!CORE.Window.fullscreen) if (!CORE.Window.fullscreen)
{ {
// Store previous window position (in case we exit fullscreen) // Store previous window position (in case we exit fullscreen)
glfwGetWindowPos(platform.handle, &CORE.Window.position.x, &CORE.Window.position.y); CORE.Window.previousPosition = CORE.Window.position;
int monitorCount = 0; int monitorCount = 0;
int monitorIndex = GetCurrentMonitor(); int monitorIndex = GetCurrentMonitor();
@ -179,7 +182,11 @@ void ToggleFullscreen(void)
CORE.Window.fullscreen = false; CORE.Window.fullscreen = false;
CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE; CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.position.x, CORE.Window.position.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.previousPosition.x, CORE.Window.previousPosition.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
// we update the window position right away
CORE.Window.position.x = CORE.Window.previousPosition.x;
CORE.Window.position.y = CORE.Window.previousPosition.y;
} }
// Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS) // Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)
@ -190,11 +197,11 @@ void ToggleFullscreen(void)
// Toggle borderless windowed mode // Toggle borderless windowed mode
void ToggleBorderlessWindowed(void) void ToggleBorderlessWindowed(void)
{ {
// Leave fullscreen before attempting to set borderless windowed mode and get screen position from it // Leave fullscreen before attempting to set borderless windowed mode
bool wasOnFullscreen = false; bool wasOnFullscreen = false;
if (CORE.Window.fullscreen) if (CORE.Window.fullscreen)
{ {
CORE.Window.previousPosition = CORE.Window.position; // fullscreen already saves the previous position so it does not need to be set here again
ToggleFullscreen(); ToggleFullscreen();
wasOnFullscreen = true; wasOnFullscreen = true;
} }
@ -213,7 +220,7 @@ void ToggleBorderlessWindowed(void)
{ {
// Store screen position and size // Store screen position and size
// NOTE: If it was on fullscreen, screen position was already stored, so skip setting it here // NOTE: If it was on fullscreen, screen position was already stored, so skip setting it here
if (!wasOnFullscreen) glfwGetWindowPos(platform.handle, &CORE.Window.previousPosition.x, &CORE.Window.previousPosition.y); if (!wasOnFullscreen) CORE.Window.previousPosition = CORE.Window.position;
CORE.Window.previousScreen = CORE.Window.screen; CORE.Window.previousScreen = CORE.Window.screen;
// Set undecorated and topmost modes and flags // Set undecorated and topmost modes and flags
@ -255,6 +262,9 @@ void ToggleBorderlessWindowed(void)
glfwFocusWindow(platform.handle); glfwFocusWindow(platform.handle);
CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE; CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
CORE.Window.position.x = CORE.Window.previousPosition.x;
CORE.Window.position.y = CORE.Window.previousPosition.y;
} }
} }
else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor"); else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor");
@ -592,6 +602,9 @@ void SetWindowTitle(const char *title)
// Set window position on screen (windowed mode) // Set window position on screen (windowed mode)
void SetWindowPosition(int x, int y) void SetWindowPosition(int x, int y)
{ {
// Update CORE.Window.position as well
CORE.Window.position.x = x;
CORE.Window.position.y = y;
glfwSetWindowPos(platform.handle, x, y); glfwSetWindowPos(platform.handle, x, y);
} }
@ -614,8 +627,9 @@ void SetWindowMonitor(int monitor)
{ {
TRACELOG(LOG_INFO, "GLFW: Selected monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor])); TRACELOG(LOG_INFO, "GLFW: Selected monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor]));
const int screenWidth = CORE.Window.screen.width; // Here the render width has to be used again in case high dpi flag is enabled
const int screenHeight = CORE.Window.screen.height; const int screenWidth = CORE.Window.render.width;
const int screenHeight = CORE.Window.render.height;
int monitorWorkareaX = 0; int monitorWorkareaX = 0;
int monitorWorkareaY = 0; int monitorWorkareaY = 0;
int monitorWorkareaWidth = 0; int monitorWorkareaWidth = 0;
@ -666,6 +680,9 @@ void SetWindowMaxSize(int width, int height)
// Set window dimensions // Set window dimensions
void SetWindowSize(int width, int height) void SetWindowSize(int width, int height)
{ {
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
glfwSetWindowSize(platform.handle, width, height); glfwSetWindowSize(platform.handle, width, height);
} }
@ -950,6 +967,33 @@ const char *GetClipboardText(void)
return glfwGetClipboardString(platform.handle); return glfwGetClipboardString(platform.handle);
} }
#if defined(SUPPORT_CLIPBOARD_IMAGE)
// Get clipboard image
Image GetClipboardImage(void)
{
Image image = {0};
unsigned long long int dataSize = 0;
void* fileData = NULL;
#ifdef _WIN32
int width, height;
fileData = (void*)Win32GetClipboardImageData(&width, &height, &dataSize);
#else
TRACELOG(LOG_WARNING, "Clipboard image: PLATFORM_DESKTOP_GLFW doesn't implement `GetClipboardImage` for this OS");
#endif
if (fileData == NULL)
{
TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data.");
}
else
{
image = LoadImageFromMemory(".bmp", fileData, (int)dataSize);
}
return image;
}
#endif // SUPPORT_CLIPBOARD_IMAGE
// Show mouse cursor // Show mouse cursor
void ShowCursor(void) void ShowCursor(void)
{ {
@ -1045,7 +1089,7 @@ int SetGamepadMappings(const char *mappings)
} }
// Set gamepad vibration // Set gamepad vibration
void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor) void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration)
{ {
TRACELOG(LOG_WARNING, "GamepadSetVibration() not available on target platform"); TRACELOG(LOG_WARNING, "GamepadSetVibration() not available on target platform");
} }
@ -1072,6 +1116,12 @@ void SetMouseCursor(int cursor)
} }
} }
// Get physical key name.
const char *GetKeyName(int key)
{
return glfwGetKeyName(key, glfwGetKeyScancode(key));
}
// Register all input events // Register all input events
void PollInputEvents(void) void PollInputEvents(void)
{ {
@ -1144,7 +1194,7 @@ void PollInputEvents(void)
const unsigned char *buttons = state.buttons; const unsigned char *buttons = state.buttons;
for (int k = 0; (buttons != NULL) && (k < GLFW_GAMEPAD_BUTTON_DPAD_LEFT + 1) && (k < MAX_GAMEPAD_BUTTONS); k++) for (int k = 0; (buttons != NULL) && (k < MAX_GAMEPAD_BUTTONS); k++)
{ {
int button = -1; // GamepadButton enum values assigned int button = -1; // GamepadButton enum values assigned
@ -1186,7 +1236,7 @@ void PollInputEvents(void)
// Get current axis state // Get current axis state
const float *axes = state.axes; const float *axes = state.axes;
for (int k = 0; (axes != NULL) && (k < GLFW_GAMEPAD_AXIS_LAST + 1) && (k < MAX_GAMEPAD_AXIS); k++) for (int k = 0; (axes != NULL) && (k < GLFW_GAMEPAD_AXIS_LAST + 1); k++)
{ {
CORE.Input.Gamepad.axisState[i][k] = axes[k]; CORE.Input.Gamepad.axisState[i][k] = axes[k];
} }
@ -1213,7 +1263,6 @@ void PollInputEvents(void)
glfwSetWindowShouldClose(platform.handle, GLFW_FALSE); glfwSetWindowShouldClose(platform.handle, GLFW_FALSE);
} }
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Internal Functions Definition // Module Internal Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -1266,6 +1315,11 @@ int InitPlatform(void)
//glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); // OpenGL API to use. Alternative: GLFW_OPENGL_ES_API //glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); // OpenGL API to use. Alternative: GLFW_OPENGL_ES_API
//glfwWindowHint(GLFW_AUX_BUFFERS, 0); // Number of auxiliar buffers //glfwWindowHint(GLFW_AUX_BUFFERS, 0); // Number of auxiliar buffers
// Disable GlFW auto iconify behaviour
// Auto Iconify automatically minimizes (iconifies) the window if the window loses focus
// additionally auto iconify restores the hardware resolution of the monitor if the window that loses focus is a fullscreen window
glfwWindowHint(GLFW_AUTO_ICONIFY, 0);
// Check window creation flags // Check window creation flags
if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) CORE.Window.fullscreen = true; if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) CORE.Window.fullscreen = true;
@ -1421,7 +1475,7 @@ int InitPlatform(void)
} }
} }
TRACELOG(LOG_WARNING, "SYSTEM: Closest fullscreen videomode: %i x %i", CORE.Window.display.width, CORE.Window.display.height); TRACELOG(LOG_INFO, "SYSTEM: Closest fullscreen videomode: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
// NOTE: ISSUE: Closest videomode could not match monitor aspect-ratio, for example, // NOTE: ISSUE: Closest videomode could not match monitor aspect-ratio, for example,
// for a desired screen size of 800x450 (16:9), closest supported videomode is 800x600 (4:3), // for a desired screen size of 800x450 (16:9), closest supported videomode is 800x600 (4:3),
@ -1443,15 +1497,7 @@ int InitPlatform(void)
else else
{ {
// No-fullscreen window creation // No-fullscreen window creation
bool wantWindowedFullscreen = (CORE.Window.screen.height == 0) && (CORE.Window.screen.width == 0); bool requestWindowedFullscreen = (CORE.Window.screen.height == 0) && (CORE.Window.screen.width == 0);
// If we are windowed fullscreen, ensures that window does not minimize when focus is lost.
// This hinting code will not work if the user already specified the correct monitor dimensions;
// at this point we don't know the monitor's dimensions. (Though, how did the user then?)
if (wantWindowedFullscreen)
{
glfwWindowHint(GLFW_AUTO_ICONIFY, 0);
}
// Default to at least one pixel in size, as creation with a zero dimension is not allowed. // Default to at least one pixel in size, as creation with a zero dimension is not allowed.
int creationWidth = CORE.Window.screen.width != 0 ? CORE.Window.screen.width : 1; int creationWidth = CORE.Window.screen.width != 0 ? CORE.Window.screen.width : 1;
@ -1471,11 +1517,7 @@ int InitPlatform(void)
monitor = monitors[monitorIndex]; monitor = monitors[monitorIndex];
SetDimensionsFromMonitor(monitor); SetDimensionsFromMonitor(monitor);
TRACELOG(LOG_INFO, "wantWindowed: %d, size: %dx%d", wantWindowedFullscreen, CORE.Window.screen.width, CORE.Window.screen.height); if (requestWindowedFullscreen) glfwSetWindowSize(platform.handle, CORE.Window.screen.width, CORE.Window.screen.height);
if (wantWindowedFullscreen)
{
glfwSetWindowSize(platform.handle, CORE.Window.screen.width, CORE.Window.screen.height);
}
} }
else else
{ {
@ -1567,11 +1609,16 @@ int InitPlatform(void)
int monitorHeight = 0; int monitorHeight = 0;
glfwGetMonitorWorkarea(monitor, &monitorX, &monitorY, &monitorWidth, &monitorHeight); glfwGetMonitorWorkarea(monitor, &monitorX, &monitorY, &monitorWidth, &monitorHeight);
int posX = monitorX + (monitorWidth - (int)CORE.Window.screen.width)/2; // Here CORE.Window.render.width/height should be used instead of CORE.Window.screen.width/height to center the window correctly when the high dpi flag is enabled.
int posY = monitorY + (monitorHeight - (int)CORE.Window.screen.height)/2; int posX = monitorX + (monitorWidth - (int)CORE.Window.render.width)/2;
int posY = monitorY + (monitorHeight - (int)CORE.Window.render.height)/2;
if (posX < monitorX) posX = monitorX; if (posX < monitorX) posX = monitorX;
if (posY < monitorY) posY = monitorY; if (posY < monitorY) posY = monitorY;
SetWindowPosition(posX, posY); SetWindowPosition(posX, posY);
// Update CORE.Window.position here so it is correct from the start
CORE.Window.position.x = posX;
CORE.Window.position.y = posY;
} }
// Load OpenGL extensions // Load OpenGL extensions
@ -1583,6 +1630,7 @@ int InitPlatform(void)
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// Set window callback events // Set window callback events
glfwSetWindowSizeCallback(platform.handle, WindowSizeCallback); // NOTE: Resizing not allowed by default! glfwSetWindowSizeCallback(platform.handle, WindowSizeCallback); // NOTE: Resizing not allowed by default!
glfwSetWindowPosCallback(platform.handle, WindowPosCallback);
glfwSetWindowMaximizeCallback(platform.handle, WindowMaximizeCallback); glfwSetWindowMaximizeCallback(platform.handle, WindowMaximizeCallback);
glfwSetWindowIconifyCallback(platform.handle, WindowIconifyCallback); glfwSetWindowIconifyCallback(platform.handle, WindowIconifyCallback);
glfwSetWindowFocusCallback(platform.handle, WindowFocusCallback); glfwSetWindowFocusCallback(platform.handle, WindowFocusCallback);
@ -1621,7 +1669,11 @@ int InitPlatform(void)
CORE.Storage.basePath = GetWorkingDirectory(); CORE.Storage.basePath = GetWorkingDirectory();
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
char* glfwPlatform = ""; #if defined(__NetBSD__)
// Workaround for NetBSD
char *glfwPlatform = "X11";
#else
char *glfwPlatform = "";
switch (glfwGetPlatform()) switch (glfwGetPlatform())
{ {
case GLFW_PLATFORM_WIN32: glfwPlatform = "Win32"; break; case GLFW_PLATFORM_WIN32: glfwPlatform = "Win32"; break;
@ -1629,10 +1681,11 @@ int InitPlatform(void)
case GLFW_PLATFORM_WAYLAND: glfwPlatform = "Wayland"; break; case GLFW_PLATFORM_WAYLAND: glfwPlatform = "Wayland"; break;
case GLFW_PLATFORM_X11: glfwPlatform = "X11"; break; case GLFW_PLATFORM_X11: glfwPlatform = "X11"; break;
case GLFW_PLATFORM_NULL: glfwPlatform = "Null"; break; case GLFW_PLATFORM_NULL: glfwPlatform = "Null"; break;
default: break;
} }
#endif
TRACELOG(LOG_INFO, "GLFW platform: %s", glfwPlatform); TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (GLFW - %s): Initialized successfully", glfwPlatform);
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (GLFW): Initialized successfully");
return 0; return 0;
} }
@ -1668,27 +1721,18 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height)
if (IsWindowFullscreen()) return; if (IsWindowFullscreen()) return;
// Set current screen size // Set current screen size
#if defined(__APPLE__)
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
#else
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
{
Vector2 windowScaleDPI = GetWindowScaleDPI();
CORE.Window.screen.width = (unsigned int)(width/windowScaleDPI.x);
CORE.Window.screen.height = (unsigned int)(height/windowScaleDPI.y);
}
else
{
CORE.Window.screen.width = width; CORE.Window.screen.width = width;
CORE.Window.screen.height = height; CORE.Window.screen.height = height;
}
#endif
// NOTE: Postprocessing texture is not scaled to new size // NOTE: Postprocessing texture is not scaled to new size
} }
static void WindowPosCallback(GLFWwindow* window, int x, int y)
{
// Set current window position
CORE.Window.position.x = x;
CORE.Window.position.y = y;
}
static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley) static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley)
{ {
CORE.Window.screenScale = MatrixScale(scalex, scaley, 1.0f); CORE.Window.screenScale = MatrixScale(scalex, scaley, 1.0f);
@ -1882,4 +1926,8 @@ static void JoystickCallback(int jid, int event)
} }
} }
#ifdef _WIN32
# define WIN32_CLIPBOARD_IMPLEMENTATION
# include "../external/win32_clipboard.h"
#endif
// EOF // EOF

File diff suppressed because it is too large Load diff

View file

@ -23,7 +23,7 @@
* Custom flag for rcore on target platform -not used- * Custom flag for rcore on target platform -not used-
* *
* DEPENDENCIES: * DEPENDENCIES:
* - SDL 2 (main library): Windowing and inputs management * - SDL 2 or SLD 3 (main library): Windowing and inputs management
* - gestures: Gestures system for touch-ready devices (or simulated from mouse inputs) * - gestures: Gestures system for touch-ready devices (or simulated from mouse inputs)
* *
* *
@ -48,6 +48,10 @@
* *
**********************************************************************************************/ **********************************************************************************************/
#ifndef SDL_ENABLE_OLD_NAMES
#define SDL_ENABLE_OLD_NAMES // Just in case we're on SDL3, we need some in-between compatibily
#endif
#include "SDL.h" // SDL base library (window/rendered, input, timing... functionality) #include "SDL.h" // SDL base library (window/rendered, input, timing... functionality)
#if defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_ES2)
@ -57,6 +61,20 @@
#include "SDL_opengl.h" // SDL OpenGL functionality (if required, instead of internal renderer) #include "SDL_opengl.h" // SDL OpenGL functionality (if required, instead of internal renderer)
#endif #endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#ifndef MAX_CLIPBOARD_BUFFER_LENGTH
#define MAX_CLIPBOARD_BUFFER_LENGTH 1024 // Size of the clipboard buffer used on GetClipboardText()
#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
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -64,7 +82,7 @@ typedef struct {
SDL_Window *window; SDL_Window *window;
SDL_GLContext glContext; SDL_GLContext glContext;
SDL_Joystick *gamepad[MAX_GAMEPADS]; SDL_GameController *gamepad[MAX_GAMEPADS];
SDL_Cursor *cursor; SDL_Cursor *cursor;
bool cursorRelative; bool cursorRelative;
} PlatformData; } PlatformData;
@ -80,7 +98,7 @@ static PlatformData platform = { 0 }; // Platform specific data
// Local Variables Definition // Local Variables Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#define SCANCODE_MAPPED_NUM 232 #define SCANCODE_MAPPED_NUM 232
static const KeyboardKey ScancodeToKey[SCANCODE_MAPPED_NUM] = { static const KeyboardKey mapScancodeToKey[SCANCODE_MAPPED_NUM] = {
KEY_NULL, // SDL_SCANCODE_UNKNOWN KEY_NULL, // SDL_SCANCODE_UNKNOWN
0, 0,
0, 0,
@ -220,6 +238,190 @@ static const int CursorsLUT[] = {
//SDL_SYSTEM_CURSOR_WAITARROW, // No equivalent implemented on MouseCursor enum on raylib.h //SDL_SYSTEM_CURSOR_WAITARROW, // No equivalent implemented on MouseCursor enum on raylib.h
}; };
// SDL3 Migration Layer made to avoid `ifdefs` inside functions when we can.
#ifdef PLATFORM_DESKTOP_SDL3
// SDL3 Migration:
// SDL_WINDOW_FULLSCREEN_DESKTOP has been removed,
// and you can call SDL_GetWindowFullscreenMode()
// to see whether an exclusive fullscreen mode will be used
// or the borderless fullscreen desktop mode will be used
#define SDL_WINDOW_FULLSCREEN_DESKTOP SDL_WINDOW_FULLSCREEN
#define SDL_IGNORE false
#define SDL_DISABLE false
#define SDL_ENABLE true
// SDL3 Migration: SDL_INIT_TIMER - no longer needed before calling SDL_AddTimer()
#define SDL_INIT_TIMER 0x0 // It's a flag, so no problem in setting it to zero if we use in a bitor (|)
// 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.
#define SDL_WINDOW_SHOWN 0x0 // It's a flag, so no problem in setting it to zero if we use in a bitor (|)
//
// SDL3 Migration: Renamed
// IMPORTANT:
// Might need to call SDL_CleanupEvent somewhere see :https://github.com/libsdl-org/SDL/issues/3540#issuecomment-1793449852
//
#define SDL_DROPFILE SDL_EVENT_DROP_FILE
const char* SDL_GameControllerNameForIndex(int joystickIndex)
{
// NOTE: SDL3 uses the IDs itself (SDL_JoystickID) instead of SDL2 joystick_index
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);
// Safe because If `mem` is NULL, SDL_free does nothing.
SDL_free(displays);
return monitorCount;
}
// SLD3 Migration:
// To emulate SDL2 this function should return `SDL_DISABLE` or `SDL_ENABLE`
// representing the *processing state* of the event before this function makes any changes to it.
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;
}
}
// SDL3 Migration: Renamed
#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));
}
// SDL3 Migration:
// SDL_GetDisplayDPI() -
// not reliable across platforms, approximately replaced by multiplying
// SDL_GetWindowDisplayScale() times 160 on iPhone and Android, and 96 on other platforms.
// returns 0 on success or a negative error code on failure
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;
}
// SDL_SetRelativeMouseMode
// returns 0 on success or a negative error code on failure
// If relative mode is not supported, this returns -1.
int SDL_SetRelativeMouseMode_Adapter(SDL_bool enabled)
{
//
// SDL_SetWindowRelativeMouseMode(SDL_Window *window, bool enabled)
// \returns true on success or false on failure; call SDL_GetError() for more
//
if (SDL_SetWindowRelativeMouseMode(platform.window, enabled))
{
return 0; // success
}
else
{
return -1; // failure
}
}
#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)
{
// SDL_Finger **SDL_GetTouchFingers(SDL_TouchID touchID, int *count)
int count = 0;
SDL_Finger **fingers = SDL_GetTouchFingers(touchID, &count);
SDL_free(fingers);
return count;
}
#else // We're on SDL2
// Since SDL2 doesn't have this function we leave a stub
// SDL_GetClipboardData function is available since SDL 3.1.3. (e.g. SDL3)
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");
// We could possibly implement it ourselves in this case for some easier platforms
return NULL;
}
#endif // PLATFORM_DESKTOP_SDL3
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Internal Functions Declaration // Module Internal Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -249,7 +451,12 @@ void ToggleFullscreen(void)
{ {
const int monitor = SDL_GetWindowDisplayIndex(platform.window); const int monitor = SDL_GetWindowDisplayIndex(platform.window);
const int monitorCount = SDL_GetNumVideoDisplays(); const int monitorCount = SDL_GetNumVideoDisplays();
#ifdef PLATFORM_DESKTOP_SDL3 // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
if ((monitor > 0) && (monitor <= monitorCount))
#else
if ((monitor >= 0) && (monitor < monitorCount)) if ((monitor >= 0) && (monitor < monitorCount))
#endif
{ {
if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)
{ {
@ -272,7 +479,11 @@ void ToggleBorderlessWindowed(void)
{ {
const int monitor = SDL_GetWindowDisplayIndex(platform.window); const int monitor = SDL_GetWindowDisplayIndex(platform.window);
const int monitorCount = SDL_GetNumVideoDisplays(); const int monitorCount = SDL_GetNumVideoDisplays();
#ifdef PLATFORM_DESKTOP_SDL3 // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
if ((monitor > 0) && (monitor <= monitorCount))
#else
if ((monitor >= 0) && (monitor < monitorCount)) if ((monitor >= 0) && (monitor < monitorCount))
#endif
{ {
if ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0) if ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0)
{ {
@ -321,7 +532,11 @@ void SetWindowState(unsigned int flags)
{ {
const int monitor = SDL_GetWindowDisplayIndex(platform.window); const int monitor = SDL_GetWindowDisplayIndex(platform.window);
const int monitorCount = SDL_GetNumVideoDisplays(); const int monitorCount = SDL_GetNumVideoDisplays();
#ifdef PLATFORM_DESKTOP_SDL3 // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
if ((monitor > 0) && (monitor <= monitorCount))
#else
if ((monitor >= 0) && (monitor < monitorCount)) if ((monitor >= 0) && (monitor < monitorCount))
#endif
{ {
SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN); SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN);
CORE.Window.fullscreen = true; CORE.Window.fullscreen = true;
@ -380,7 +595,11 @@ void SetWindowState(unsigned int flags)
{ {
const int monitor = SDL_GetWindowDisplayIndex(platform.window); const int monitor = SDL_GetWindowDisplayIndex(platform.window);
const int monitorCount = SDL_GetNumVideoDisplays(); const int monitorCount = SDL_GetNumVideoDisplays();
#ifdef PLATFORM_DESKTOP_SDL3 // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
if ((monitor > 0) && (monitor <= monitorCount))
#else
if ((monitor >= 0) && (monitor < monitorCount)) if ((monitor >= 0) && (monitor < monitorCount))
#endif
{ {
SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN_DESKTOP); SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN_DESKTOP);
} }
@ -476,9 +695,9 @@ void ClearWindowState(unsigned int flags)
// Set icon for window // Set icon for window
void SetWindowIcon(Image image) void SetWindowIcon(Image image)
{ {
SDL_Surface* iconSurface = NULL; SDL_Surface *iconSurface = NULL;
Uint32 rmask, gmask, bmask, amask; unsigned int rmask = 0, gmask = 0, bmask = 0, amask = 0;
int depth = 0; // Depth in bits int depth = 0; // Depth in bits
int pitch = 0; // Pixel spacing (pitch) in bytes int pitch = 0; // Pixel spacing (pitch) in bytes
@ -492,72 +711,67 @@ void SetWindowIcon(Image image)
case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
rmask = 0xFF, gmask = 0xFF00; rmask = 0xFF, gmask = 0xFF00;
bmask = 0, amask = 0; bmask = 0, amask = 0;
depth = 16, pitch = image.width * 2; depth = 16, pitch = image.width*2;
break; break;
case PIXELFORMAT_UNCOMPRESSED_R5G6B5: case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
rmask = 0xF800, gmask = 0x07E0; rmask = 0xF800, gmask = 0x07E0;
bmask = 0x001F, amask = 0; bmask = 0x001F, amask = 0;
depth = 16, pitch = image.width * 2; depth = 16, pitch = image.width*2;
break; break;
case PIXELFORMAT_UNCOMPRESSED_R8G8B8: // Uses BGR for 24-bit case PIXELFORMAT_UNCOMPRESSED_R8G8B8: // Uses BGR for 24-bit
rmask = 0x0000FF, gmask = 0x00FF00; rmask = 0x0000FF, gmask = 0x00FF00;
bmask = 0xFF0000, amask = 0; bmask = 0xFF0000, amask = 0;
depth = 24, pitch = image.width * 3; depth = 24, pitch = image.width*3;
break; break;
case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
rmask = 0xF800, gmask = 0x07C0; rmask = 0xF800, gmask = 0x07C0;
bmask = 0x003E, amask = 0x0001; bmask = 0x003E, amask = 0x0001;
depth = 16, pitch = image.width * 2; depth = 16, pitch = image.width*2;
break; break;
case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
rmask = 0xF000, gmask = 0x0F00; rmask = 0xF000, gmask = 0x0F00;
bmask = 0x00F0, amask = 0x000F; bmask = 0x00F0, amask = 0x000F;
depth = 16, pitch = image.width * 2; depth = 16, pitch = image.width*2;
break; break;
case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
rmask = 0xFF000000, gmask = 0x00FF0000; rmask = 0xFF000000, gmask = 0x00FF0000;
bmask = 0x0000FF00, amask = 0x000000FF; bmask = 0x0000FF00, amask = 0x000000FF;
depth = 32, pitch = image.width * 4; depth = 32, pitch = image.width*4;
break; break;
case PIXELFORMAT_UNCOMPRESSED_R32: case PIXELFORMAT_UNCOMPRESSED_R32:
rmask = 0xFFFFFFFF, gmask = 0; rmask = 0xFFFFFFFF, gmask = 0;
bmask = 0, amask = 0; bmask = 0, amask = 0;
depth = 32, pitch = image.width * 4; depth = 32, pitch = image.width*4;
break; break;
case PIXELFORMAT_UNCOMPRESSED_R32G32B32: case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
rmask = 0xFFFFFFFF, gmask = 0xFFFFFFFF; rmask = 0xFFFFFFFF, gmask = 0xFFFFFFFF;
bmask = 0xFFFFFFFF, amask = 0; bmask = 0xFFFFFFFF, amask = 0;
depth = 96, pitch = image.width * 12; depth = 96, pitch = image.width*12;
break; break;
case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
rmask = 0xFFFFFFFF, gmask = 0xFFFFFFFF; rmask = 0xFFFFFFFF, gmask = 0xFFFFFFFF;
bmask = 0xFFFFFFFF, amask = 0xFFFFFFFF; bmask = 0xFFFFFFFF, amask = 0xFFFFFFFF;
depth = 128, pitch = image.width * 16; depth = 128, pitch = image.width*16;
break; break;
case PIXELFORMAT_UNCOMPRESSED_R16: case PIXELFORMAT_UNCOMPRESSED_R16:
rmask = 0xFFFF, gmask = 0; rmask = 0xFFFF, gmask = 0;
bmask = 0, amask = 0; bmask = 0, amask = 0;
depth = 16, pitch = image.width * 2; depth = 16, pitch = image.width*2;
break; break;
case PIXELFORMAT_UNCOMPRESSED_R16G16B16: case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
rmask = 0xFFFF, gmask = 0xFFFF; rmask = 0xFFFF, gmask = 0xFFFF;
bmask = 0xFFFF, amask = 0; bmask = 0xFFFF, amask = 0;
depth = 48, pitch = image.width * 6; depth = 48, pitch = image.width*6;
break; break;
case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
rmask = 0xFFFF, gmask = 0xFFFF; rmask = 0xFFFF, gmask = 0xFFFF;
bmask = 0xFFFF, amask = 0xFFFF; bmask = 0xFFFF, amask = 0xFFFF;
depth = 64, pitch = image.width * 8; depth = 64, pitch = image.width*8;
break; break;
default: default: return; // Compressed formats are not supported
// Compressed formats are not supported
return;
} }
iconSurface = SDL_CreateRGBSurfaceFrom( iconSurface = SDL_CreateRGBSurfaceFrom( image.data, image.width, image.height, depth, pitch, rmask, gmask, bmask, amask );
image.data, image.width, image.height, depth, pitch,
rmask, gmask, bmask, amask
);
if (iconSurface) if (iconSurface)
{ {
@ -599,12 +813,16 @@ void SetWindowMonitor(int monitor)
// 1. SDL started supporting moving exclusive fullscreen windows between displays on SDL3, // 1. SDL started supporting moving exclusive fullscreen windows between displays on SDL3,
// see commit https://github.com/libsdl-org/SDL/commit/3f5ef7dd422057edbcf3e736107e34be4b75d9ba // see commit https://github.com/libsdl-org/SDL/commit/3f5ef7dd422057edbcf3e736107e34be4b75d9ba
// 2. A workaround for SDL2 is leaving fullscreen, moving the window, then entering full screen again. // 2. A workaround for SDL2 is leaving fullscreen, moving the window, then entering full screen again.
const bool wasFullscreen = ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) ? true : false; const bool wasFullscreen = ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)? true : false;
const int screenWidth = CORE.Window.screen.width; const int screenWidth = CORE.Window.screen.width;
const int screenHeight = CORE.Window.screen.height; const int screenHeight = CORE.Window.screen.height;
SDL_Rect usableBounds; SDL_Rect usableBounds;
#ifdef PLATFORM_DESKTOP_SDL3 // Different style for success checking
if (SDL_GetDisplayUsableBounds(monitor, &usableBounds))
#else
if (SDL_GetDisplayUsableBounds(monitor, &usableBounds) == 0) if (SDL_GetDisplayUsableBounds(monitor, &usableBounds) == 0)
#endif
{ {
if (wasFullscreen == 1) ToggleFullscreen(); // Leave fullscreen. if (wasFullscreen == 1) ToggleFullscreen(); // Leave fullscreen.
@ -702,6 +920,7 @@ int GetCurrentMonitor(void)
{ {
int currentMonitor = 0; int currentMonitor = 0;
// Be aware that this returns an ID in SDL3 and a Index in SDL2
currentMonitor = SDL_GetWindowDisplayIndex(platform.window); currentMonitor = SDL_GetWindowDisplayIndex(platform.window);
return currentMonitor; return currentMonitor;
@ -714,7 +933,11 @@ Vector2 GetMonitorPosition(int monitor)
if ((monitor >= 0) && (monitor < monitorCount)) if ((monitor >= 0) && (monitor < monitorCount))
{ {
SDL_Rect displayBounds; SDL_Rect displayBounds;
#ifdef PLATFORM_DESKTOP_SDL3
if (SDL_GetDisplayUsableBounds(monitor, &displayBounds))
#else
if (SDL_GetDisplayUsableBounds(monitor, &displayBounds) == 0) if (SDL_GetDisplayUsableBounds(monitor, &displayBounds) == 0)
#endif
{ {
return (Vector2){ (float)displayBounds.x, (float)displayBounds.y }; return (Vector2){ (float)displayBounds.x, (float)displayBounds.y };
} }
@ -842,10 +1065,16 @@ Vector2 GetWindowScaleDPI(void)
{ {
Vector2 scale = { 1.0f, 1.0f }; Vector2 scale = { 1.0f, 1.0f };
#ifndef PLATFORM_DESKTOP_SDL3
// NOTE: SDL_GetWindowDisplayScale was only added on SDL3 // NOTE: SDL_GetWindowDisplayScale was only added on SDL3
// see https://wiki.libsdl.org/SDL3/SDL_GetWindowDisplayScale // see https://wiki.libsdl.org/SDL3/SDL_GetWindowDisplayScale
// TODO: Implement the window scale factor calculation manually. // TODO: Implement the window scale factor calculation manually.
TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform"); 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; return scale;
} }
@ -857,25 +1086,86 @@ void SetClipboardText(const char *text)
} }
// Get clipboard text content // Get clipboard text content
// NOTE: returned string must be freed with SDL_free()
const char *GetClipboardText(void) const char *GetClipboardText(void)
{ {
return SDL_GetClipboardText(); 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;
} }
#if defined(SUPPORT_CLIPBOARD_IMAGE)
// Get clipboard image
Image GetClipboardImage(void)
{
// Let's hope compiler put these arrays in static memory
const char *image_formats[] = {
"image/bmp",
"image/png",
"image/jpg",
"image/tiff",
};
const char *image_extensions[] = {
".bmp",
".png",
".jpg",
".tiff",
};
Image image = {0};
size_t dataSize = 0;
void *fileData = NULL;
for (int i = 0; i < SDL_arraysize(image_formats); ++i)
{
// NOTE: This pointer should be free with SDL_free() at some point.
fileData = SDL_GetClipboardData(image_formats[i], &dataSize);
if (fileData) {
image = LoadImageFromMemory(image_extensions[i], fileData, dataSize);
if (IsImageValid(image))
{
TRACELOG(LOG_INFO, "Clipboard image: Got image from clipboard as a `%s` successfully", image_extensions[i]);
return image;
}
}
}
TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data. %s", SDL_GetError());
return image;
}
#endif
// Show mouse cursor // Show mouse cursor
void ShowCursor(void) void ShowCursor(void)
{ {
#ifdef PLATFORM_DESKTOP_SDL3
SDL_ShowCursor();
#else
SDL_ShowCursor(SDL_ENABLE); SDL_ShowCursor(SDL_ENABLE);
#endif
CORE.Input.Mouse.cursorHidden = false; CORE.Input.Mouse.cursorHidden = false;
} }
// Hides mouse cursor // Hides mouse cursor
void HideCursor(void) void HideCursor(void)
{ {
#ifdef PLATFORM_DESKTOP_SDL3
SDL_HideCursor();
#else
SDL_ShowCursor(SDL_DISABLE); SDL_ShowCursor(SDL_DISABLE);
#endif
CORE.Input.Mouse.cursorHidden = true; CORE.Input.Mouse.cursorHidden = true;
} }
@ -883,7 +1173,13 @@ void HideCursor(void)
void EnableCursor(void) void EnableCursor(void)
{ {
SDL_SetRelativeMouseMode(SDL_FALSE); SDL_SetRelativeMouseMode(SDL_FALSE);
#ifdef PLATFORM_DESKTOP_SDL3
// SDL_ShowCursor() has been split into three functions: SDL_ShowCursor(), SDL_HideCursor(), and SDL_CursorVisible()
SDL_ShowCursor();
#else
SDL_ShowCursor(SDL_ENABLE); SDL_ShowCursor(SDL_ENABLE);
#endif
platform.cursorRelative = false; platform.cursorRelative = false;
CORE.Input.Mouse.cursorHidden = false; CORE.Input.Mouse.cursorHidden = false;
@ -939,17 +1235,17 @@ int SetGamepadMappings(const char *mappings)
} }
// Set gamepad vibration // Set gamepad vibration
void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor) void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration)
{ {
//Limit input values to between 0.0f and 1.0f if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (duration > 0.0f))
leftMotor = (0.0f > leftMotor) ? 0.0f : leftMotor;
rightMotor = (0.0f > rightMotor) ? 0.0f : rightMotor;
leftMotor = (1.0f < leftMotor) ? 1.0f : leftMotor;
rightMotor = (1.0f < rightMotor) ? 1.0f : rightMotor;
if (IsGamepadAvailable(gamepad))
{ {
SDL_JoystickRumble(platform.gamepad[gamepad], (Uint16)(leftMotor*65535.0f), (Uint16)(rightMotor*65535.0f), (Uint32)(MAX_GAMEPAD_VIBRATION_TIME*1000.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));
} }
} }
@ -971,8 +1267,30 @@ void SetMouseCursor(int cursor)
CORE.Input.Mouse.cursor = cursor; CORE.Input.Mouse.cursor = cursor;
} }
// Get physical key name.
const char *GetKeyName(int key)
{
return SDL_GetKeyName(key);
}
static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event) static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event)
{ {
#ifdef PLATFORM_DESKTOP_SDL3 // 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 // SDL2
CORE.Input.Touch.pointCount = SDL_GetNumTouchFingers(event.touchId); CORE.Input.Touch.pointCount = SDL_GetNumTouchFingers(event.touchId);
for (int i = 0; i < CORE.Input.Touch.pointCount; i++) for (int i = 0; i < CORE.Input.Touch.pointCount; i++)
@ -983,6 +1301,7 @@ static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event)
CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height; CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height;
CORE.Input.Touch.currentTouchState[i] = 1; 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; for (int i = CORE.Input.Touch.pointCount; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.currentTouchState[i] = 0;
} }
@ -1074,16 +1393,26 @@ void PollInputEvents(void)
CORE.Window.dropFilepaths = (char **)RL_CALLOC(1024, sizeof(char *)); CORE.Window.dropFilepaths = (char **)RL_CALLOC(1024, sizeof(char *));
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
#ifdef PLATFORM_DESKTOP_SDL3
// const char *data; /**< The text for SDL_EVENT_DROP_TEXT and the file name for SDL_EVENT_DROP_FILE, NULL for other events */
// 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.
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data);
#else
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file); strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file);
SDL_free(event.drop.file); SDL_free(event.drop.file);
#endif
CORE.Window.dropFileCount++; CORE.Window.dropFileCount++;
} }
else if (CORE.Window.dropFileCount < 1024) else if (CORE.Window.dropFileCount < 1024)
{ {
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
#ifdef PLATFORM_DESKTOP_SDL3
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data);
#else
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file); strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file);
SDL_free(event.drop.file); SDL_free(event.drop.file);
#endif
CORE.Window.dropFileCount++; CORE.Window.dropFileCount++;
} }
@ -1092,10 +1421,18 @@ void PollInputEvents(void)
} break; } break;
// Window events are also polled (Minimized, maximized, close...) // Window events are also polled (Minimized, maximized, close...)
#ifndef PLATFORM_DESKTOP_SDL3
// SDL3 states:
// The SDL_WINDOWEVENT_* events have been moved to top level events,
// and SDL_WINDOWEVENT has been removed.
// In general, handling this change just means checking for the individual events instead of first checking for SDL_WINDOWEVENT
// 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.
case SDL_WINDOWEVENT: case SDL_WINDOWEVENT:
{ {
switch (event.window.event) switch (event.window.event)
{ {
#endif
case SDL_WINDOWEVENT_RESIZED: case SDL_WINDOWEVENT_RESIZED:
case SDL_WINDOWEVENT_SIZE_CHANGED: case SDL_WINDOWEVENT_SIZE_CHANGED:
{ {
@ -1123,16 +1460,26 @@ void PollInputEvents(void)
case SDL_WINDOWEVENT_FOCUS_GAINED: case SDL_WINDOWEVENT_FOCUS_GAINED:
case SDL_WINDOWEVENT_MAXIMIZED: case SDL_WINDOWEVENT_MAXIMIZED:
case SDL_WINDOWEVENT_RESTORED: case SDL_WINDOWEVENT_RESTORED:
#ifdef PLATFORM_DESKTOP_SDL3
break;
#else
default: break; default: break;
} }
} break; } break;
#endif
// Keyboard events // Keyboard events
case SDL_KEYDOWN: case SDL_KEYDOWN:
{ {
#ifdef PLATFORM_DESKTOP_SDL3
// SDL3 Migration: The following structures have been removed: * SDL_Keysym
KeyboardKey key = ConvertScancodeToKey(event.key.scancode);
#else
KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode); KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode);
#endif
if (key != KEY_NULL) { if (key != KEY_NULL)
{
// If key was up, add it to the key pressed queue // If key was up, add it to the key pressed queue
if ((CORE.Input.Keyboard.currentKeyState[key] == 0) && (CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE)) if ((CORE.Input.Keyboard.currentKeyState[key] == 0) && (CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE))
{ {
@ -1154,7 +1501,12 @@ void PollInputEvents(void)
case SDL_KEYUP: case SDL_KEYUP:
{ {
#ifdef PLATFORM_DESKTOP_SDL3
KeyboardKey key = ConvertScancodeToKey(event.key.scancode);
#else
KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode); KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode);
#endif
if (key != KEY_NULL) CORE.Input.Keyboard.currentKeyState[key] = 0; if (key != KEY_NULL) CORE.Input.Keyboard.currentKeyState[key] = 0;
} break; } break;
@ -1249,15 +1601,15 @@ void PollInputEvents(void)
if (!CORE.Input.Gamepad.ready[jid] && (jid < MAX_GAMEPADS)) if (!CORE.Input.Gamepad.ready[jid] && (jid < MAX_GAMEPADS))
{ {
platform.gamepad[jid] = SDL_JoystickOpen(jid); platform.gamepad[jid] = SDL_GameControllerOpen(jid);
if (platform.gamepad[jid]) if (platform.gamepad[jid])
{ {
CORE.Input.Gamepad.ready[jid] = true; CORE.Input.Gamepad.ready[jid] = true;
CORE.Input.Gamepad.axisCount[jid] = SDL_JoystickNumAxes(platform.gamepad[jid]); 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_LEFT_TRIGGER] = -1.0f;
CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f; CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
strncpy(CORE.Input.Gamepad.name[jid], SDL_JoystickName(platform.gamepad[jid]), 63); strncpy(CORE.Input.Gamepad.name[jid], SDL_GameControllerNameForIndex(jid), 63);
CORE.Input.Gamepad.name[jid][63] = '\0'; CORE.Input.Gamepad.name[jid][63] = '\0';
} }
else else
@ -1270,15 +1622,15 @@ void PollInputEvents(void)
{ {
int jid = event.jdevice.which; int jid = event.jdevice.which;
if (jid == SDL_JoystickInstanceID(platform.gamepad[jid])) if (jid == SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[jid])))
{ {
SDL_JoystickClose(platform.gamepad[jid]); SDL_GameControllerClose(platform.gamepad[jid]);
platform.gamepad[jid] = SDL_JoystickOpen(0); platform.gamepad[jid] = SDL_GameControllerOpen(0);
CORE.Input.Gamepad.ready[jid] = false; CORE.Input.Gamepad.ready[jid] = false;
memset(CORE.Input.Gamepad.name[jid], 0, 64); memset(CORE.Input.Gamepad.name[jid], 0, 64);
} }
} break; } break;
case SDL_JOYBUTTONDOWN: case SDL_CONTROLLERBUTTONDOWN:
{ {
int button = -1; int button = -1;
@ -1312,7 +1664,7 @@ void PollInputEvents(void)
CORE.Input.Gamepad.lastButtonPressed = button; CORE.Input.Gamepad.lastButtonPressed = button;
} }
} break; } break;
case SDL_JOYBUTTONUP: case SDL_CONTROLLERBUTTONUP:
{ {
int button = -1; int button = -1;
@ -1346,7 +1698,7 @@ void PollInputEvents(void)
if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0; if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
} }
} break; } break;
case SDL_JOYAXISMOTION: case SDL_CONTROLLERAXISMOTION:
{ {
int axis = -1; int axis = -1;
@ -1364,13 +1716,13 @@ void PollInputEvents(void)
if (axis >= 0) if (axis >= 0)
{ {
// SDL axis value range is -32768 to 32767, we normalize it to RayLib's -1.0 to 1.0f range // SDL axis value range is -32768 to 32767, we normalize it to RayLib's -1.0 to 1.0f range
float value = event.jaxis.value / (float) 32767; float value = event.jaxis.value/(float)32767;
CORE.Input.Gamepad.axisState[event.jaxis.which][axis] = value; CORE.Input.Gamepad.axisState[event.jaxis.which][axis] = value;
// Register button state for triggers in addition to their axes // Register button state for triggers in addition to their axes
if ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER)) 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 button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER)? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2;
int pressed = (value > 0.1f); int pressed = (value > 0.1f);
CORE.Input.Gamepad.currentButtonState[event.jaxis.which][button] = pressed; CORE.Input.Gamepad.currentButtonState[event.jaxis.which][button] = pressed;
if (pressed) CORE.Input.Gamepad.lastButtonPressed = button; if (pressed) CORE.Input.Gamepad.lastButtonPressed = button;
@ -1499,11 +1851,6 @@ int InitPlatform(void)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
} }
if (CORE.Window.flags & FLAG_VSYNC_HINT)
{
SDL_GL_SetSwapInterval(1);
}
if (CORE.Window.flags & FLAG_MSAA_4X_HINT) if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
{ {
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
@ -1511,7 +1858,11 @@ int InitPlatform(void)
} }
// Init window // Init window
#ifdef 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); platform.window = SDL_CreateWindow(CORE.Window.title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, CORE.Window.screen.width, CORE.Window.screen.height, flags);
#endif
// Init OpenGL context // Init OpenGL context
platform.glContext = SDL_GL_CreateContext(platform.window); platform.glContext = SDL_GL_CreateContext(platform.window);
@ -1537,6 +1888,9 @@ int InitPlatform(void)
TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.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, " > 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); 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 else
{ {
@ -1554,14 +1908,15 @@ int InitPlatform(void)
// Initialize gamepads // Initialize gamepads
for (int i = 0; (i < SDL_NumJoysticks()) && (i < MAX_GAMEPADS); i++) for (int i = 0; (i < SDL_NumJoysticks()) && (i < MAX_GAMEPADS); i++)
{ {
platform.gamepad[i] = SDL_JoystickOpen(i); platform.gamepad[i] = SDL_GameControllerOpen(i);
if (platform.gamepad[i]) if (platform.gamepad[i])
{ {
CORE.Input.Gamepad.ready[i] = true; CORE.Input.Gamepad.ready[i] = true;
CORE.Input.Gamepad.axisCount[i] = SDL_JoystickNumAxes(platform.gamepad[i]); 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_LEFT_TRIGGER] = -1.0f;
CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f; CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
strncpy(CORE.Input.Gamepad.name[i], SDL_JoystickName(platform.gamepad[i]), 63); strncpy(CORE.Input.Gamepad.name[i], SDL_GameControllerNameForIndex(i), 63);
CORE.Input.Gamepad.name[i][63] = '\0'; CORE.Input.Gamepad.name[i][63] = '\0';
} }
else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError()); else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
@ -1587,10 +1942,16 @@ int InitPlatform(void)
// Initialize storage system // Initialize storage system
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
CORE.Storage.basePath = GetWorkingDirectory(); // Define base path for storage // Define base path for storage
CORE.Storage.basePath = SDL_GetBasePath(); // Alternative: GetWorkingDirectory();
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
#ifdef PLATFORM_DESKTOP_SDL3
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL3): Initialized successfully");
#else
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL): Initialized successfully"); TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL): Initialized successfully");
#endif
return 0; return 0;
} }
@ -1609,8 +1970,9 @@ static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode)
{ {
if (sdlScancode >= 0 && sdlScancode < SCANCODE_MAPPED_NUM) if (sdlScancode >= 0 && sdlScancode < SCANCODE_MAPPED_NUM)
{ {
return ScancodeToKey[sdlScancode]; return mapScancodeToKey[sdlScancode];
} }
return KEY_NULL; // No equivalent key in Raylib return KEY_NULL; // No equivalent key in Raylib
} }
// EOF // EOF

View file

@ -89,7 +89,6 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
typedef unsigned int uint;
typedef struct { typedef struct {
// Display data // Display data
@ -207,7 +206,7 @@ static const short linuxToRaylibMap[KEYMAP_SIZE] = {
[BTN_TL] = GAMEPAD_BUTTON_LEFT_TRIGGER_1, [BTN_TL] = GAMEPAD_BUTTON_LEFT_TRIGGER_1,
[BTN_TL2] = GAMEPAD_BUTTON_LEFT_TRIGGER_2, [BTN_TL2] = GAMEPAD_BUTTON_LEFT_TRIGGER_2,
[BTN_TR] = GAMEPAD_BUTTON_RIGHT_TRIGGER_1, [BTN_TR] = GAMEPAD_BUTTON_RIGHT_TRIGGER_1,
[BTN_TR2] GAMEPAD_BUTTON_RIGHT_TRIGGER_2, [BTN_TR2] = GAMEPAD_BUTTON_RIGHT_TRIGGER_2,
[BTN_SELECT] = GAMEPAD_BUTTON_MIDDLE_LEFT, [BTN_SELECT] = GAMEPAD_BUTTON_MIDDLE_LEFT,
[BTN_MODE] = GAMEPAD_BUTTON_MIDDLE, [BTN_MODE] = GAMEPAD_BUTTON_MIDDLE,
[BTN_START] = GAMEPAD_BUTTON_MIDDLE_RIGHT, [BTN_START] = GAMEPAD_BUTTON_MIDDLE_RIGHT,
@ -611,7 +610,7 @@ int SetGamepadMappings(const char *mappings)
} }
// Set gamepad vibration // Set gamepad vibration
void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor) void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration)
{ {
TRACELOG(LOG_WARNING, "GamepadSetVibration() not implemented on target platform"); TRACELOG(LOG_WARNING, "GamepadSetVibration() not implemented on target platform");
} }
@ -629,6 +628,13 @@ void SetMouseCursor(int cursor)
TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform"); TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform");
} }
// Get physical key name.
const char *GetKeyName(int key)
{
TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform");
return "";
}
// Register all input events // Register all input events
void PollInputEvents(void) void PollInputEvents(void)
{ {
@ -758,7 +764,9 @@ int InitPlatform(void)
drmModeConnector *con = drmModeGetConnector(platform.fd, res->connectors[i]); drmModeConnector *con = drmModeGetConnector(platform.fd, res->connectors[i]);
TRACELOG(LOG_TRACE, "DISPLAY: Connector modes detected: %i", con->count_modes); TRACELOG(LOG_TRACE, "DISPLAY: Connector modes detected: %i", con->count_modes);
if ((con->connection == DRM_MODE_CONNECTED) && (con->encoder_id)) // In certain cases the status of the conneciton is reported as UKNOWN, but it is still connected.
// This might be a hardware or software limitation like on Raspberry Pi Zero with composite output.
if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->encoder_id))
{ {
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected"); TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected");
platform.connector = con; platform.connector = con;
@ -1029,7 +1037,7 @@ int InitPlatform(void)
// If graphic device is no properly initialized, we end program // If graphic device is no properly initialized, we end program
if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return -1; } if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return -1; }
else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor()) / 2 - CORE.Window.screen.width / 2, GetMonitorHeight(GetCurrentMonitor()) / 2 - CORE.Window.screen.height / 2); else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor())/2 - CORE.Window.screen.width/2, GetMonitorHeight(GetCurrentMonitor())/2 - CORE.Window.screen.height/2);
// Set some default window flags // Set some default window flags
CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; // false CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; // false
@ -1137,7 +1145,8 @@ void ClosePlatform(void)
// Close the evdev devices // Close the evdev devices
if (platform.mouseFd != -1) { if (platform.mouseFd != -1)
{
close(platform.mouseFd); close(platform.mouseFd);
platform.mouseFd = -1; platform.mouseFd = -1;
} }
@ -1471,7 +1480,6 @@ static void ConfigureEvdevDevice(char *device)
TEST_BIT(keyBits, BTN_MOUSE)) isMouse = true; TEST_BIT(keyBits, BTN_MOUSE)) isMouse = true;
} }
if (TEST_BIT(evBits, EV_KEY)) if (TEST_BIT(evBits, EV_KEY))
{ {
// The first 32 keys as defined in input-event-codes.h are pretty much // The first 32 keys as defined in input-event-codes.h are pretty much
@ -1614,7 +1622,7 @@ static void PollKeyboardEvents(void)
} }
} }
TRACELOG(LOG_DEBUG, "INPUT: KEY_%s Keycode(linux): %4i KeyCode(raylib): %4i", (event.value == 0) ? "UP " : "DOWN", event.code, keycode); TRACELOG(LOG_DEBUG, "INPUT: KEY_%s Keycode(linux): %4i KeyCode(raylib): %4i", (event.value == 0)? "UP " : "DOWN", event.code, keycode);
} }
} }
} }
@ -1641,7 +1649,7 @@ static void PollGamepadEvents(void)
{ {
short keycodeRaylib = linuxToRaylibMap[event.code]; short keycodeRaylib = linuxToRaylibMap[event.code];
TRACELOG(LOG_DEBUG, "INPUT: Gamepad %2i: KEY_%s Keycode(linux): %4i Keycode(raylib): %4i", i, (event.value == 0) ? "UP " : "DOWN", event.code, keycodeRaylib); TRACELOG(LOG_DEBUG, "INPUT: Gamepad %2i: KEY_%s Keycode(linux): %4i Keycode(raylib): %4i", i, (event.value == 0)? "UP" : "DOWN", event.code, keycodeRaylib);
if ((keycodeRaylib != 0) && (keycodeRaylib < MAX_GAMEPAD_BUTTONS)) if ((keycodeRaylib != 0) && (keycodeRaylib < MAX_GAMEPAD_BUTTONS))
{ {
@ -1666,7 +1674,7 @@ static void PollGamepadEvents(void)
int range = platform.gamepadAbsAxisRange[i][event.code][1]; int range = platform.gamepadAbsAxisRange[i][event.code][1];
// NOTE: Scaling of event.value to get values between -1..1 // NOTE: Scaling of event.value to get values between -1..1
CORE.Input.Gamepad.axisState[i][axisRaylib] = (2 * (float)(event.value - min) / range) - 1; CORE.Input.Gamepad.axisState[i][axisRaylib] = (2*(float)(event.value - min)/range) - 1;
} }
} }
} }
@ -1925,9 +1933,7 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
const int nearestHeightDiff = abs(platform.connector->modes[nearestIndex].vdisplay - height); const int nearestHeightDiff = abs(platform.connector->modes[nearestIndex].vdisplay - height);
const int nearestFpsDiff = abs(platform.connector->modes[nearestIndex].vrefresh - fps); const int nearestFpsDiff = abs(platform.connector->modes[nearestIndex].vrefresh - fps);
if ((widthDiff < nearestWidthDiff) || (heightDiff < nearestHeightDiff) || (fpsDiff < nearestFpsDiff)) { if ((widthDiff < nearestWidthDiff) || (heightDiff < nearestHeightDiff) || (fpsDiff < nearestFpsDiff)) nearestIndex = i;
nearestIndex = i;
}
} }
return nearestIndex; return nearestIndex;