mirror of
https://github.com/raysan5/raylib.git
synced 2025-12-25 10:22:33 -05:00
Merge branch 'master' into master
This commit is contained in:
@ -70,6 +70,16 @@ typedef struct {
|
||||
EGLConfig config; // Graphic config
|
||||
} PlatformData;
|
||||
|
||||
typedef struct {
|
||||
// Store data for both Hover and Touch events
|
||||
// Used to ignore Hover events which are interpreted as Touch events
|
||||
int32_t pointCount; // Number of touch points active
|
||||
int32_t pointId[MAX_TOUCH_POINTS]; // Point identifiers
|
||||
Vector2 position[MAX_TOUCH_POINTS]; // Touch position on screen
|
||||
|
||||
int32_t hoverPoints[MAX_TOUCH_POINTS]; // Hover Points
|
||||
} TouchRaw;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Global Variables Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
@ -246,6 +256,8 @@ static const KeyboardKey mapKeycode[KEYCODE_MAP_SIZE] = {
|
||||
KEY_KP_EQUAL // AKEYCODE_NUMPAD_EQUALS
|
||||
};
|
||||
|
||||
static TouchRaw touchRaw = { 0 };
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Internal Functions Declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
@ -801,6 +813,8 @@ int InitPlatform(void)
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_TOUCH_POINTS; i++) touchRaw.hoverPoints[i] = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1269,25 +1283,85 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
||||
}
|
||||
|
||||
// Register touch points count
|
||||
CORE.Input.Touch.pointCount = AMotionEvent_getPointerCount(event);
|
||||
touchRaw.pointCount = AMotionEvent_getPointerCount(event);
|
||||
|
||||
for (int i = 0; (i < CORE.Input.Touch.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
||||
for (int i = 0; (i < touchRaw.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
||||
{
|
||||
// Register touch points id
|
||||
CORE.Input.Touch.pointId[i] = AMotionEvent_getPointerId(event, i);
|
||||
touchRaw.pointId[i] = AMotionEvent_getPointerId(event, i);
|
||||
|
||||
// Register touch points position
|
||||
CORE.Input.Touch.position[i] = (Vector2){ AMotionEvent_getX(event, i), AMotionEvent_getY(event, i) };
|
||||
touchRaw.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
|
||||
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;
|
||||
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;
|
||||
touchRaw.position[i].x = touchRaw.position[i].x*widthRatio - (float)CORE.Window.renderOffset.x/2;
|
||||
touchRaw.position[i].y = touchRaw.position[i].y*heightRatio - (float)CORE.Window.renderOffset.y/2;
|
||||
}
|
||||
|
||||
int32_t action = AMotionEvent_getAction(event);
|
||||
unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
|
||||
int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
||||
|
||||
if (flags == AMOTION_EVENT_ACTION_HOVER_ENTER)
|
||||
{
|
||||
// The new pointer is hover
|
||||
// So add it to hoverPoints
|
||||
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
||||
{
|
||||
if (touchRaw.hoverPoints[i] == -1)
|
||||
{
|
||||
touchRaw.hoverPoints[i] = touchRaw.pointId[pointerIndex];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags == AMOTION_EVENT_ACTION_POINTER_UP) || (flags == AMOTION_EVENT_ACTION_UP) || (flags == AMOTION_EVENT_ACTION_HOVER_EXIT))
|
||||
{
|
||||
// One of the touchpoints is released, remove it from touch point arrays
|
||||
if (flags == AMOTION_EVENT_ACTION_HOVER_EXIT)
|
||||
{
|
||||
// If the touchPoint is hover, remove it from hoverPoints
|
||||
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
||||
{
|
||||
if (touchRaw.hoverPoints[i] == touchRaw.pointId[pointerIndex])
|
||||
{
|
||||
touchRaw.hoverPoints[i] = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = pointerIndex; (i < touchRaw.pointCount - 1) && (i < MAX_TOUCH_POINTS - 1); i++)
|
||||
{
|
||||
touchRaw.pointId[i] = touchRaw.pointId[i+1];
|
||||
touchRaw.position[i] = touchRaw.position[i+1];
|
||||
}
|
||||
touchRaw.pointCount--;
|
||||
}
|
||||
|
||||
int pointCount = 0;
|
||||
for (int i = 0; (i < touchRaw.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
||||
{
|
||||
// If the touchPoint is hover, Ignore it
|
||||
bool hover = false;
|
||||
for (int j = 0; j < MAX_TOUCH_POINTS; j++)
|
||||
{
|
||||
// Check if the touchPoint is in hoverPointers
|
||||
if (touchRaw.hoverPoints[j] == touchRaw.pointId[i])
|
||||
{
|
||||
hover = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hover) continue;
|
||||
|
||||
CORE.Input.Touch.pointId[pointCount] = touchRaw.pointId[i];
|
||||
CORE.Input.Touch.position[pointCount] = touchRaw.position[i];
|
||||
pointCount++;
|
||||
}
|
||||
CORE.Input.Touch.pointCount = pointCount;
|
||||
|
||||
#if defined(SUPPORT_GESTURES_SYSTEM)
|
||||
GestureEvent gestureEvent = { 0 };
|
||||
@ -1312,20 +1386,6 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
||||
ProcessGestureEvent(gestureEvent);
|
||||
#endif
|
||||
|
||||
int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
||||
|
||||
if (flags == AMOTION_EVENT_ACTION_POINTER_UP || flags == AMOTION_EVENT_ACTION_UP)
|
||||
{
|
||||
// One of the touchpoints is released, remove it from touch point arrays
|
||||
for (int i = pointerIndex; (i < CORE.Input.Touch.pointCount - 1) && (i < MAX_TOUCH_POINTS); i++)
|
||||
{
|
||||
CORE.Input.Touch.pointId[i] = CORE.Input.Touch.pointId[i+1];
|
||||
CORE.Input.Touch.position[i] = CORE.Input.Touch.position[i+1];
|
||||
}
|
||||
|
||||
CORE.Input.Touch.pointCount--;
|
||||
}
|
||||
|
||||
// When all touchpoints are tapped and released really quickly, this event is generated
|
||||
if (flags == AMOTION_EVENT_ACTION_CANCEL) CORE.Input.Touch.pointCount = 0;
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/**********************************************************************************************
|
||||
*
|
||||
* rcore_desktop - Functions to manage window, graphics device and inputs
|
||||
* rcore_desktop_glfw - Functions to manage window, graphics device and inputs
|
||||
*
|
||||
* PLATFORM: DESKTOP: GLFW
|
||||
* - Windows (Win32, Win64)
|
||||
@ -74,9 +74,14 @@
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
#include <sys/time.h> // Required for: timespec, nanosleep(), select() - POSIX
|
||||
|
||||
//#define GLFW_EXPOSE_NATIVE_X11 // WARNING: Exposing Xlib.h > X.h results in dup symbols for Font type
|
||||
//#define GLFW_EXPOSE_NATIVE_WAYLAND
|
||||
#define GLFW_EXPOSE_NATIVE_X11
|
||||
#define Font X11Font // Hack to fix 'Font' name collision
|
||||
// The definition and references to the X11 Font type will be replaced by 'X11Font'
|
||||
// Works as long as the current file consistently references any X11 Font as X11Font
|
||||
// Since it is never referenced (as of writting), this does not pose an issue
|
||||
#include "GLFW/glfw3native.h" // Required for: glfwGetX11Window()
|
||||
#undef Font // Revert hack and allow normal raylib Font usage
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
#include <unistd.h> // Required for: usleep()
|
||||
@ -130,9 +135,9 @@ static void CursorEnterCallback(GLFWwindow *window, int enter);
|
||||
static void JoystickCallback(int jid, int event); // GLFW3 Joystick Connected/Disconnected Callback
|
||||
|
||||
// Wrappers used by glfwInitAllocator
|
||||
static void* AllocateWrapper(size_t size, void* user); // GLFW3 GLFWallocatefun, wrapps around RL_MALLOC macro
|
||||
static void* ReallocateWrapper(void* block, size_t size, void* user); // GLFW3 GLFWreallocatefun, wrapps around RL_MALLOC macro
|
||||
static void DeallocateWrapper(void* block, void* user); // GLFW3 GLFWdeallocatefun, wraps around RL_FREE macro
|
||||
static void *AllocateWrapper(size_t size, void *user); // GLFW3 GLFWallocatefun, wrapps around RL_MALLOC macro
|
||||
static void *ReallocateWrapper(void *block, size_t size, void *user); // GLFW3 GLFWreallocatefun, wrapps around RL_MALLOC macro
|
||||
static void DeallocateWrapper(void *block, void *user); // GLFW3 GLFWdeallocatefun, wraps around RL_FREE macro
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Declaration
|
||||
@ -576,7 +581,7 @@ void SetWindowIcons(Image *images, int count)
|
||||
else
|
||||
{
|
||||
int valid = 0;
|
||||
GLFWimage *icons = RL_CALLOC(count, sizeof(GLFWimage));
|
||||
GLFWimage *icons = (GLFWimage *)RL_CALLOC(count, sizeof(GLFWimage));
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
@ -705,6 +710,12 @@ void SetWindowFocused(void)
|
||||
glfwFocusWindow(platform.handle);
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
// Local storage for the window handle returned by glfwGetX11Window
|
||||
// This is needed as X11 handles are integers and may not fit inside a pointer depending on platform
|
||||
// Storing the handle locally and returning a pointer in GetWindowHandle allows the code to work regardless of pointer width
|
||||
static XID X11WindowHandle;
|
||||
#endif
|
||||
// Get native window handle
|
||||
void *GetWindowHandle(void)
|
||||
{
|
||||
@ -713,12 +724,10 @@ void *GetWindowHandle(void)
|
||||
return glfwGetWin32Window(platform.handle);
|
||||
#endif
|
||||
#if defined(__linux__)
|
||||
// NOTE: Returned handle is: unsigned long Window (X.h)
|
||||
// typedef unsigned long XID;
|
||||
// typedef XID Window;
|
||||
//unsigned long id = (unsigned long)glfwGetX11Window(platform.handle);
|
||||
//return NULL; // TODO: Find a way to return value... cast to void *?
|
||||
return (void *)platform.handle;
|
||||
// Store the window handle localy and return a pointer to the variable instead
|
||||
// Reasoning detailed in the declaration of X11WindowHandle
|
||||
X11WindowHandle = glfwGetX11Window(platform.handle);
|
||||
return &X11WindowHandle;
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
// NOTE: Returned handle is: (objc_object *)
|
||||
@ -1057,9 +1066,9 @@ double GetTime(void)
|
||||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
// NOTE: This function is only safe to use if you control the URL given.
|
||||
// A user could craft a malicious string performing another action.
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself.
|
||||
// NOTE: This function is only safe to use if you control the URL given
|
||||
// A user could craft a malicious string performing another action
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself
|
||||
// Ref: https://github.com/raysan5/raylib/issues/686
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
@ -1121,7 +1130,7 @@ void SetMouseCursor(int cursor)
|
||||
}
|
||||
}
|
||||
|
||||
// Get physical key name.
|
||||
// Get physical key name
|
||||
const char *GetKeyName(int key)
|
||||
{
|
||||
return glfwGetKeyName(key, glfwGetKeyScancode(key));
|
||||
@ -1238,7 +1247,7 @@ void PollInputEvents(void)
|
||||
}
|
||||
}
|
||||
|
||||
// Get current axis state
|
||||
// Get current state of axes
|
||||
const float *axes = state.axes;
|
||||
|
||||
for (int k = 0; (axes != NULL) && (k < GLFW_GAMEPAD_AXIS_LAST + 1); k++)
|
||||
@ -1246,7 +1255,7 @@ void PollInputEvents(void)
|
||||
CORE.Input.Gamepad.axisState[i][k] = axes[k];
|
||||
}
|
||||
|
||||
// Register buttons for 2nd triggers (because GLFW doesn't count these as buttons but rather axis)
|
||||
// Register buttons for 2nd triggers (because GLFW doesn't count these as buttons but rather as axes)
|
||||
if (CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] > 0.1f)
|
||||
{
|
||||
CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_LEFT_TRIGGER_2] = 1;
|
||||
@ -1297,20 +1306,20 @@ static void SetDimensionsFromMonitor(GLFWmonitor *monitor)
|
||||
}
|
||||
|
||||
// Function wrappers around RL_*alloc macros, used by glfwInitAllocator() inside of InitPlatform()
|
||||
// We need to provide these because GLFWallocator expects function pointers with specific signatures.
|
||||
// Similar wrappers exist in utils.c but we cannot reuse them here due to declaration mismatch.
|
||||
// We need to provide these because GLFWallocator expects function pointers with specific signatures
|
||||
// Similar wrappers exist in utils.c but we cannot reuse them here due to declaration mismatch
|
||||
// https://www.glfw.org/docs/latest/intro_guide.html#init_allocator
|
||||
static void* AllocateWrapper(size_t size, void* user)
|
||||
static void *AllocateWrapper(size_t size, void *user)
|
||||
{
|
||||
(void)user;
|
||||
return RL_MALLOC(size);
|
||||
}
|
||||
static void* ReallocateWrapper(void* block, size_t size, void* user)
|
||||
static void *ReallocateWrapper(void *block, size_t size, void *user)
|
||||
{
|
||||
(void)user;
|
||||
return RL_REALLOC(block, size);
|
||||
}
|
||||
static void DeallocateWrapper(void* block, void* user)
|
||||
static void DeallocateWrapper(void *block, void *user)
|
||||
{
|
||||
(void)user;
|
||||
RL_FREE(block);
|
||||
@ -1327,6 +1336,7 @@ int InitPlatform(void)
|
||||
.reallocate = ReallocateWrapper,
|
||||
.user = NULL, // RL_*ALLOC macros are not capable of handling user-provided data
|
||||
};
|
||||
|
||||
glfwInitAllocator(&allocator);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
@ -1384,15 +1394,15 @@ int InitPlatform(void)
|
||||
// HACK: Most of this was written before GLFW_SCALE_FRAMEBUFFER existed and
|
||||
// was enabled by default. Disabling it gets back the old behavior. A
|
||||
// complete fix will require removing a lot of CORE.Window.render
|
||||
// manipulation code.
|
||||
// manipulation code
|
||||
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
{
|
||||
// Resize window content area based on the monitor content scale.
|
||||
// NOTE: This hint only has an effect on platforms where screen coordinates and pixels always map 1:1 such as Windows and X11.
|
||||
// On platforms like macOS the resolution of the framebuffer is changed independently of the window size.
|
||||
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // Scale content area based on the monitor content scale where window is placed on
|
||||
// Resize window content area based on the monitor content scale
|
||||
// NOTE: This hint only has an effect on platforms where screen coordinates and pixels always map 1:1 such as Windows and X11
|
||||
// On platforms like macOS the resolution of the framebuffer is changed independently of the window size
|
||||
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // Scale content area based on the monitor content scale where window is placed on
|
||||
#if defined(__APPLE__)
|
||||
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
|
||||
#endif
|
||||
@ -1411,8 +1421,8 @@ int InitPlatform(void)
|
||||
}
|
||||
|
||||
// NOTE: When asking for an OpenGL context version, most drivers provide the highest supported version
|
||||
// with backward compatibility to older OpenGL versions.
|
||||
// For example, if using OpenGL 1.1, driver can provide a 4.3 backwards compatible context.
|
||||
// with backward compatibility to older OpenGL versions
|
||||
// For example, if using OpenGL 1.1, driver can provide a 4.3 backwards compatible context
|
||||
|
||||
// Check selection OpenGL version
|
||||
if (rlGetVersion() == RL_OPENGL_21)
|
||||
@ -1458,9 +1468,9 @@ int InitPlatform(void)
|
||||
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
|
||||
}
|
||||
|
||||
// NOTE: GLFW 3.4+ defers initialization of the Joystick subsystem on the first call to any Joystick related functions.
|
||||
// Forcing this initialization here avoids doing it on PollInputEvents() called by EndDrawing() after first frame has been just drawn.
|
||||
// The initialization will still happen and possible delays still occur, but before the window is shown, which is a nicer experience.
|
||||
// NOTE: GLFW 3.4+ defers initialization of the Joystick subsystem on the first call to any Joystick related functions
|
||||
// Forcing this initialization here avoids doing it on PollInputEvents() called by EndDrawing() after first frame has been just drawn
|
||||
// The initialization will still happen and possible delays still occur, but before the window is shown, which is a nicer experience
|
||||
// REF: https://github.com/raysan5/raylib/issues/1554
|
||||
glfwSetJoystickCallback(NULL);
|
||||
|
||||
@ -1468,7 +1478,7 @@ int InitPlatform(void)
|
||||
if (CORE.Window.fullscreen)
|
||||
{
|
||||
// According to glfwCreateWindow(), if the user does not have a choice, fullscreen applications
|
||||
// should default to the primary monitor.
|
||||
// should default to the primary monitor
|
||||
|
||||
monitor = glfwGetPrimaryMonitor();
|
||||
if (!monitor)
|
||||
@ -1482,8 +1492,8 @@ int InitPlatform(void)
|
||||
// Remember center for switching from fullscreen to window
|
||||
if ((CORE.Window.screen.height == CORE.Window.display.height) && (CORE.Window.screen.width == CORE.Window.display.width))
|
||||
{
|
||||
// If screen width/height equal to the display, we can't calculate the window pos for toggling full-screened/windowed.
|
||||
// Toggling full-screened/windowed with pos(0, 0) can cause problems in some platforms, such as X11.
|
||||
// If screen width/height equal to the display, we can't calculate the window pos for toggling full-screened/windowed
|
||||
// Toggling full-screened/windowed with pos(0, 0) can cause problems in some platforms, such as X11
|
||||
CORE.Window.position.x = CORE.Window.display.width/4;
|
||||
CORE.Window.position.y = CORE.Window.display.height/4;
|
||||
}
|
||||
@ -1544,7 +1554,7 @@ int InitPlatform(void)
|
||||
// No-fullscreen window creation
|
||||
bool requestWindowedFullscreen = (CORE.Window.screen.height == 0) && (CORE.Window.screen.width == 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 creationHeight = CORE.Window.screen.height != 0 ? CORE.Window.screen.height : 1;
|
||||
|
||||
@ -1556,8 +1566,8 @@ int InitPlatform(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// After the window was created, determine the monitor that the window manager assigned.
|
||||
// Derive display sizes, and, if possible, window size in case it was zero at beginning.
|
||||
// After the window was created, determine the monitor that the window manager assigned
|
||||
// Derive display sizes, and, if possible, window size in case it was zero at beginning
|
||||
|
||||
int monitorCount = 0;
|
||||
int monitorIndex = GetCurrentMonitor();
|
||||
@ -1572,7 +1582,7 @@ int InitPlatform(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
// The monitor for the window-manager-created window can not be determined, so it can not be centered.
|
||||
// The monitor for the window-manager-created window can not be determined, so it can not be centered
|
||||
glfwTerminate();
|
||||
TRACELOG(LOG_WARNING, "GLFW: Failed to determine Monitor to center Window");
|
||||
return -1;
|
||||
@ -1594,7 +1604,7 @@ int InitPlatform(void)
|
||||
|
||||
// Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)
|
||||
// NOTE: V-Sync can be enabled by graphic driver configuration, it doesn't need
|
||||
// to be activated on web platforms since VSync is enforced there.
|
||||
// to be activated on web platforms since VSync is enforced there
|
||||
if (CORE.Window.flags & FLAG_VSYNC_HINT)
|
||||
{
|
||||
// WARNING: It seems to hit a critical render path in Intel HD Graphics
|
||||
@ -1607,7 +1617,7 @@ int InitPlatform(void)
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
{
|
||||
// NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling.
|
||||
// NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling
|
||||
// Framebuffer scaling should be activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
|
||||
#if !defined(__APPLE__)
|
||||
glfwGetFramebufferSize(platform.handle, &fbWidth, &fbHeight);
|
||||
@ -1650,7 +1660,8 @@ int InitPlatform(void)
|
||||
int monitorHeight = 0;
|
||||
glfwGetMonitorWorkarea(monitor, &monitorX, &monitorY, &monitorWidth, &monitorHeight);
|
||||
|
||||
// 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.
|
||||
// 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 posX = monitorX + (monitorWidth - (int)CORE.Window.render.width)/2;
|
||||
int posY = monitorY + (monitorHeight - (int)CORE.Window.render.height)/2;
|
||||
if (posX < monitorX) posX = monitorX;
|
||||
@ -1696,6 +1707,8 @@ int InitPlatform(void)
|
||||
// Retrieve gamepad names
|
||||
for (int i = 0; i < MAX_GAMEPADS; i++)
|
||||
{
|
||||
// WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
|
||||
// we can get a not-NULL terminated string, so, we only copy up to (MAX_GAMEPAD_NAME_LENGTH - 1)
|
||||
if (glfwJoystickPresent(i)) strncpy(CORE.Input.Gamepad.name[i], glfwGetJoystickName(i), MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
@ -1753,7 +1766,7 @@ static void ErrorCallback(int error, const char *description)
|
||||
static void WindowSizeCallback(GLFWwindow *window, int width, int height)
|
||||
{
|
||||
// WARNING: On window minimization, callback is called,
|
||||
// but we don't want to change internal screen values, it breaks things
|
||||
// but we don't want to change internal screen values, it breaks things
|
||||
if ((width == 0) || (height == 0)) return;
|
||||
|
||||
// Reset viewport and projection matrix for new size
|
||||
@ -1850,8 +1863,8 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
|
||||
// WARNING: GLFW could return GLFW_REPEAT, we need to consider it as 1
|
||||
// to work properly with our implementation (IsKeyDown/IsKeyUp checks)
|
||||
if (action == GLFW_RELEASE) CORE.Input.Keyboard.currentKeyState[key] = 0;
|
||||
else if(action == GLFW_PRESS) CORE.Input.Keyboard.currentKeyState[key] = 1;
|
||||
else if(action == GLFW_REPEAT) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1;
|
||||
else if (action == GLFW_PRESS) CORE.Input.Keyboard.currentKeyState[key] = 1;
|
||||
else if (action == GLFW_REPEAT) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1;
|
||||
|
||||
// WARNING: Check if CAPS/NUM key modifiers are enabled and force down state for those keys
|
||||
if (((key == KEY_CAPS_LOCK) && ((mods & GLFW_MOD_CAPS_LOCK) > 0)) ||
|
||||
@ -1973,6 +1986,9 @@ static void JoystickCallback(int jid, int event)
|
||||
{
|
||||
if (event == GLFW_CONNECTED)
|
||||
{
|
||||
// WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
|
||||
// we can get a not-NULL terminated string, so, we clean destination and only copy up to -1
|
||||
memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH);
|
||||
strncpy(CORE.Input.Gamepad.name[jid], glfwGetJoystickName(jid), MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||
}
|
||||
else if (event == GLFW_DISCONNECTED)
|
||||
|
||||
@ -175,7 +175,9 @@ static const unsigned short keyMappingRGFW[] = {
|
||||
[RGFW_superL] = KEY_LEFT_SUPER,
|
||||
#ifndef RGFW_MACOS
|
||||
[RGFW_shiftR] = KEY_RIGHT_SHIFT,
|
||||
[RGFW_controlR] = KEY_RIGHT_CONTROL,
|
||||
[RGFW_altR] = KEY_RIGHT_ALT,
|
||||
[RGFW_superR] = KEY_RIGHT_SUPER,
|
||||
#endif
|
||||
[RGFW_space] = KEY_SPACE,
|
||||
|
||||
@ -583,7 +585,7 @@ void SetWindowPosition(int x, int y)
|
||||
// Set monitor for the current window
|
||||
void SetWindowMonitor(int monitor)
|
||||
{
|
||||
RGFW_window_moveToMonitor(platform.window, RGFW_getMonitors()[monitor]);
|
||||
RGFW_window_moveToMonitor(platform.window, RGFW_getMonitors(NULL)[monitor]);
|
||||
}
|
||||
|
||||
// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
|
||||
@ -640,7 +642,7 @@ int GetMonitorCount(void)
|
||||
#define MAX_MONITORS_SUPPORTED 6
|
||||
|
||||
int count = MAX_MONITORS_SUPPORTED;
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
@ -657,7 +659,7 @@ int GetMonitorCount(void)
|
||||
// Get current monitor where window is placed
|
||||
int GetCurrentMonitor(void)
|
||||
{
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
RGFW_monitor mon = { 0 };
|
||||
|
||||
if (platform.window) mon = RGFW_window_getMonitor(platform.window);
|
||||
@ -674,7 +676,7 @@ int GetCurrentMonitor(void)
|
||||
// Get selected monitor position
|
||||
Vector2 GetMonitorPosition(int monitor)
|
||||
{
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
|
||||
return (Vector2){ (float)mons[monitor].x, (float)mons[monitor].y };
|
||||
}
|
||||
@ -682,7 +684,7 @@ Vector2 GetMonitorPosition(int monitor)
|
||||
// Get selected monitor width (currently used by monitor)
|
||||
int GetMonitorWidth(int monitor)
|
||||
{
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
|
||||
return mons[monitor].mode.area.w;
|
||||
}
|
||||
@ -690,7 +692,7 @@ int GetMonitorWidth(int monitor)
|
||||
// Get selected monitor height (currently used by monitor)
|
||||
int GetMonitorHeight(int monitor)
|
||||
{
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
|
||||
return mons[monitor].mode.area.h;
|
||||
}
|
||||
@ -698,7 +700,7 @@ int GetMonitorHeight(int monitor)
|
||||
// Get selected monitor physical width in millimetres
|
||||
int GetMonitorPhysicalWidth(int monitor)
|
||||
{
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
|
||||
return mons[monitor].physW;
|
||||
}
|
||||
@ -706,7 +708,7 @@ int GetMonitorPhysicalWidth(int monitor)
|
||||
// Get selected monitor physical height in millimetres
|
||||
int GetMonitorPhysicalHeight(int monitor)
|
||||
{
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
|
||||
return (int)mons[monitor].physH;
|
||||
}
|
||||
@ -714,7 +716,7 @@ int GetMonitorPhysicalHeight(int monitor)
|
||||
// Get selected monitor refresh rate
|
||||
int GetMonitorRefreshRate(int monitor)
|
||||
{
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
|
||||
return (int)mons[monitor].mode.refreshRate;
|
||||
}
|
||||
@ -722,7 +724,7 @@ int GetMonitorRefreshRate(int monitor)
|
||||
// Get the human-readable, UTF-8 encoded name of the selected monitor
|
||||
const char *GetMonitorName(int monitor)
|
||||
{
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
|
||||
return mons[monitor].name;
|
||||
}
|
||||
@ -987,7 +989,7 @@ void PollInputEvents(void)
|
||||
|
||||
if ((CORE.Window.eventWaiting) || (IsWindowState(FLAG_WINDOW_MINIMIZED) && !IsWindowState(FLAG_WINDOW_ALWAYS_RUN)))
|
||||
{
|
||||
RGFW_window_eventWait(platform.window, 0); // Wait for input events: keyboard/mouse/window events (callbacks) -> Update keys state
|
||||
RGFW_window_eventWait(platform.window, -1); // Wait for input events: keyboard/mouse/window events (callbacks) -> Update keys state
|
||||
CORE.Time.previous = GetTime();
|
||||
}
|
||||
|
||||
@ -1319,6 +1321,13 @@ int InitPlatform(void)
|
||||
platform.window = RGFW_createWindow(CORE.Window.title, RGFW_RECT(0, 0, CORE.Window.screen.width, CORE.Window.screen.height), flags);
|
||||
platform.mon.mode.area.w = 0;
|
||||
|
||||
if (platform.window != NULL)
|
||||
{
|
||||
// NOTE: RGFW's exit key is distinct from raylib's exit key (which can
|
||||
// be set with SetExitKey()) and defaults to Escape
|
||||
platform.window->exitKey = RGFW_keyNULL;
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_WEB_RGFW
|
||||
RGFW_area screenSize = RGFW_getScreenSize();
|
||||
CORE.Window.display.width = screenSize.w;
|
||||
|
||||
@ -52,13 +52,27 @@
|
||||
#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)
|
||||
// SDL base library (window/rendered, input, timing... functionality)
|
||||
#ifdef USING_SDL3_PROJECT
|
||||
#include "SDL3/SDL.h"
|
||||
#elif USING_SDL2_PROJECT
|
||||
#include "SDL2/SDL.h"
|
||||
#else
|
||||
#include "SDL.h"
|
||||
#endif
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_ES2)
|
||||
// It seems it does not need to be included to work
|
||||
//#include "SDL_opengles2.h"
|
||||
#else
|
||||
#include "SDL_opengl.h" // SDL OpenGL functionality (if required, instead of internal renderer)
|
||||
// SDL OpenGL functionality (if required, instead of internal renderer)
|
||||
#ifdef USING_SDL3_PROJECT
|
||||
#include "SDL3/SDL_opengl.h"
|
||||
#elif USING_SDL2_PROJECT
|
||||
#include "SDL2/SDL_opengl.h"
|
||||
#else
|
||||
#include "SDL_opengl.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
@ -238,8 +252,7 @@ static const int CursorsLUT[] = {
|
||||
//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.
|
||||
// SDL3 Migration Layer made to avoid 'ifdefs' inside functions when we can
|
||||
#if defined(PLATFORM_DESKTOP_SDL3)
|
||||
|
||||
// SDL3 Migration:
|
||||
@ -256,7 +269,7 @@ static const int CursorsLUT[] = {
|
||||
// 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.
|
||||
// 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
|
||||
@ -290,13 +303,13 @@ int SDL_GetNumVideoDisplays(void)
|
||||
int monitorCount = 0;
|
||||
SDL_DisplayID *displays = SDL_GetDisplays(&monitorCount);
|
||||
|
||||
// Safe because If `mem` is NULL, SDL_free does nothing
|
||||
// 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`
|
||||
// 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)
|
||||
{
|
||||
@ -331,7 +344,7 @@ SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth
|
||||
// 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.
|
||||
// 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)
|
||||
{
|
||||
@ -369,7 +382,7 @@ int SDL_NumJoysticks(void)
|
||||
|
||||
// SDL_SetRelativeMouseMode
|
||||
// returns 0 on success or a negative error code on failure
|
||||
// If relative mode is not supported, this returns -1.
|
||||
// If relative mode is not supported, this returns -1
|
||||
int SDL_SetRelativeMouseMode_Adapter(SDL_bool enabled)
|
||||
{
|
||||
// SDL_SetWindowRelativeMouseMode(SDL_Window *window, bool enabled)
|
||||
@ -424,6 +437,8 @@ void ClosePlatform(void); // Close platform
|
||||
|
||||
static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode); // Help convert SDL scancodes to raylib key
|
||||
|
||||
static int GetCodepointNextSDL(const char *text, int *codepointSize); // Get next codepoint in a byte sequence and bytes processed
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
@ -565,7 +580,7 @@ void SetWindowState(unsigned int flags)
|
||||
if (flags & FLAG_WINDOW_UNFOCUSED)
|
||||
{
|
||||
// NOTE: To be able to implement this part it seems that we should
|
||||
// do it ourselves, via `Windows.h`, `X11/Xlib.h` or even `Cocoa.h`
|
||||
// do it ourselves, via 'windows.h', 'X11/Xlib.h' or even 'Cocoa.h'
|
||||
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_UNFOCUSED is not supported on PLATFORM_DESKTOP_SDL");
|
||||
}
|
||||
if (flags & FLAG_WINDOW_TOPMOST)
|
||||
@ -721,7 +736,7 @@ void SetWindowIcon(Image image)
|
||||
bmask = 0x001F, amask = 0;
|
||||
depth = 16, pitch = image.width*2;
|
||||
} break;
|
||||
case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
|
||||
case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
|
||||
{
|
||||
// WARNING: SDL2 could be using BGR but SDL3 RGB
|
||||
rmask = 0xFF0000, gmask = 0x00FF00;
|
||||
@ -826,7 +841,7 @@ void SetWindowMonitor(int monitor)
|
||||
// NOTE:
|
||||
// 1. SDL started supporting moving exclusive fullscreen windows between displays on SDL3,
|
||||
// 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 int screenWidth = CORE.Window.screen.width;
|
||||
@ -839,7 +854,7 @@ void SetWindowMonitor(int monitor)
|
||||
if (SDL_GetDisplayUsableBounds(monitor, &usableBounds) == 0)
|
||||
#endif
|
||||
{
|
||||
if (wasFullscreen == 1) ToggleFullscreen(); // Leave fullscreen.
|
||||
if (wasFullscreen == 1) ToggleFullscreen(); // Leave fullscreen
|
||||
|
||||
// If the screen size is larger than the monitor usable area, anchor it on the top left corner, otherwise, center it
|
||||
if ((screenWidth >= usableBounds.w) || (screenHeight >= usableBounds.h))
|
||||
@ -847,11 +862,11 @@ void SetWindowMonitor(int monitor)
|
||||
// NOTE:
|
||||
// 1. There's a known issue where if the window larger than the target display bounds,
|
||||
// when moving the windows to that display, the window could be clipped back
|
||||
// ending up positioned partly outside the target display.
|
||||
// ending up positioned partly outside the target display
|
||||
// 2. The workaround for that is, previously to moving the window,
|
||||
// setting the window size to the target display size, so they match.
|
||||
// setting the window size to the target display size, so they match
|
||||
// 3. It wasn't done here because we can't assume changing the window size automatically
|
||||
// is acceptable behavior by the user.
|
||||
// is acceptable behavior by the user
|
||||
SDL_SetWindowPosition(platform.window, usableBounds.x, usableBounds.y);
|
||||
CORE.Window.position.x = usableBounds.x;
|
||||
CORE.Window.position.y = usableBounds.y;
|
||||
@ -1084,12 +1099,11 @@ Vector2 GetWindowScaleDPI(void)
|
||||
#ifndef PLATFORM_DESKTOP_SDL3
|
||||
// NOTE: SDL_GetWindowDisplayScale was only added on SDL3
|
||||
// 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");
|
||||
#else
|
||||
scale.x = SDL_GetWindowDisplayScale(platform.window);
|
||||
scale.y = scale.x;
|
||||
TRACELOG(LOG_INFO, "WindowScaleDPI is %f", scale.x);
|
||||
scale.y = scale.x;
|
||||
#endif
|
||||
|
||||
return scale;
|
||||
@ -1153,13 +1167,13 @@ Image GetClipboardImage(void)
|
||||
image = LoadImageFromMemory(imageExtensions[i], fileData, dataSize);
|
||||
if (IsImageValid(image))
|
||||
{
|
||||
TRACELOG(LOG_INFO, "Clipboard image: Got image from clipboard as a `%s` successfully", imageExtensions[i]);
|
||||
TRACELOG(LOG_INFO, "Clipboard: Got image from clipboard successfully: %s", imageExtensions[i]);
|
||||
return image;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsImageValid(image)) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data. Error: %s", SDL_GetError());
|
||||
if (!IsImageValid(image)) TRACELOG(LOG_WARNING, "Clipboard: Couldn't get clipboard data. ERROR: %s", SDL_GetError());
|
||||
#endif
|
||||
|
||||
return image;
|
||||
@ -1231,9 +1245,9 @@ double GetTime(void)
|
||||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
// NOTE: This function is only safe to use if you control the URL given.
|
||||
// A user could craft a malicious string performing another action.
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself.
|
||||
// NOTE: This function is only safe to use if you control the URL given
|
||||
// A user could craft a malicious string performing another action
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself
|
||||
// Ref: https://github.com/raysan5/raylib/issues/686
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
@ -1285,7 +1299,7 @@ void SetMouseCursor(int cursor)
|
||||
CORE.Input.Mouse.cursor = cursor;
|
||||
}
|
||||
|
||||
// Get physical key name.
|
||||
// Get physical key name
|
||||
const char *GetKeyName(int key)
|
||||
{
|
||||
return SDL_GetKeyName(key);
|
||||
@ -1452,10 +1466,9 @@ void PollInputEvents(void)
|
||||
|
||||
#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.
|
||||
// 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:
|
||||
{
|
||||
switch (event.window.event)
|
||||
@ -1601,13 +1614,18 @@ void PollInputEvents(void)
|
||||
{
|
||||
// NOTE: event.text.text data comes an UTF-8 text sequence but we register codepoints (int)
|
||||
|
||||
int codepointSize = 0;
|
||||
|
||||
// Check if there is space available in the queue
|
||||
if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
|
||||
{
|
||||
// Add character (codepoint) to the queue
|
||||
CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = GetCodepointNext(event.text.text, &codepointSize);
|
||||
#if defined(PLATFORM_DESKTOP_SDL3)
|
||||
unsigned int textLen = strlen(event.text.text);
|
||||
unsigned int codepoint = (unsigned int)SDL_StepUTF8(&event.text.text, textLen);
|
||||
#else
|
||||
int codepointSize = 0;
|
||||
int codepoint = GetCodepointNextSDL(event.text.text, &codepointSize);
|
||||
#endif
|
||||
CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = codepoint;
|
||||
CORE.Input.Keyboard.charPressedQueueCount++;
|
||||
}
|
||||
} break;
|
||||
@ -1697,8 +1715,8 @@ void PollInputEvents(void)
|
||||
CORE.Input.Gamepad.axisCount[jid] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[jid]));
|
||||
CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
|
||||
CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
|
||||
memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH);
|
||||
strncpy(CORE.Input.Gamepad.name[jid], SDL_GameControllerNameForIndex(jid), MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||
CORE.Input.Gamepad.name[jid][MAX_GAMEPAD_NAME_LENGTH - 1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1825,7 +1843,7 @@ void PollInputEvents(void)
|
||||
{
|
||||
if (platform.gamepadId[i] == event.jaxis.which)
|
||||
{
|
||||
// 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;
|
||||
CORE.Input.Gamepad.axisState[i][axis] = value;
|
||||
|
||||
@ -2093,4 +2111,42 @@ static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode)
|
||||
|
||||
return KEY_NULL; // No equivalent key in Raylib
|
||||
}
|
||||
// EOF
|
||||
|
||||
// Get next codepoint in a byte sequence and bytes processed
|
||||
static int GetCodepointNextSDL(const char *text, int *codepointSize)
|
||||
{
|
||||
const char *ptr = text;
|
||||
int codepoint = 0x3f; // Codepoint (defaults to '?')
|
||||
*codepointSize = 1;
|
||||
|
||||
// Get current codepoint and bytes processed
|
||||
if (0xf0 == (0xf8 & ptr[0]))
|
||||
{
|
||||
// 4 byte UTF-8 codepoint
|
||||
if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80) || ((ptr[3] & 0xC0) ^ 0x80)) { return codepoint; } // 10xxxxxx checks
|
||||
codepoint = ((0x07 & ptr[0]) << 18) | ((0x3f & ptr[1]) << 12) | ((0x3f & ptr[2]) << 6) | (0x3f & ptr[3]);
|
||||
*codepointSize = 4;
|
||||
}
|
||||
else if (0xe0 == (0xf0 & ptr[0]))
|
||||
{
|
||||
// 3 byte UTF-8 codepoint */
|
||||
if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } // 10xxxxxx checks
|
||||
codepoint = ((0x0f & ptr[0]) << 12) | ((0x3f & ptr[1]) << 6) | (0x3f & ptr[2]);
|
||||
*codepointSize = 3;
|
||||
}
|
||||
else if (0xc0 == (0xe0 & ptr[0]))
|
||||
{
|
||||
// 2 byte UTF-8 codepoint
|
||||
if ((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } // 10xxxxxx checks
|
||||
codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]);
|
||||
*codepointSize = 2;
|
||||
}
|
||||
else if (0x00 == (0x80 & ptr[0]))
|
||||
{
|
||||
// 1 byte UTF-8 codepoint
|
||||
codepoint = ptr[0];
|
||||
*codepointSize = 1;
|
||||
}
|
||||
|
||||
return codepoint;
|
||||
}
|
||||
|
||||
@ -18,9 +18,9 @@
|
||||
*
|
||||
* CONFIGURATION:
|
||||
* #define SUPPORT_SSH_KEYBOARD_RPI (Raspberry Pi only)
|
||||
* Reconfigure standard input to receive key inputs, works with SSH connection.
|
||||
* Reconfigure standard input to receive key inputs, works with SSH connection
|
||||
* WARNING: Reconfiguring standard input could lead to undesired effects, like breaking other
|
||||
* running processes orblocking the device if not restored properly. Use with care.
|
||||
* running processes orblocking the device if not restored properly. Use with care
|
||||
*
|
||||
* DEPENDENCIES:
|
||||
* - DRM and GLM: System libraries for display initialization and configuration
|
||||
@ -48,11 +48,11 @@
|
||||
*
|
||||
**********************************************************************************************/
|
||||
|
||||
#include <fcntl.h> // POSIX file control definitions - open(), creat(), fcntl()
|
||||
#include <unistd.h> // POSIX standard function definitions - read(), close(), STDIN_FILENO
|
||||
#include <termios.h> // POSIX terminal control definitions - tcgetattr(), tcsetattr()
|
||||
#include <pthread.h> // POSIX threads management (inputs reading)
|
||||
#include <dirent.h> // POSIX directory browsing
|
||||
#include <fcntl.h> // POSIX file control definitions - open(), creat(), fcntl()
|
||||
#include <unistd.h> // POSIX standard function definitions - read(), close(), STDIN_FILENO
|
||||
#include <termios.h> // POSIX terminal control definitions - tcgetattr(), tcsetattr()
|
||||
#include <pthread.h> // POSIX threads management (inputs reading)
|
||||
#include <dirent.h> // POSIX directory browsing
|
||||
|
||||
#include <sys/ioctl.h> // Required for: ioctl() - UNIX System call for device-specific input/output operations
|
||||
#include <linux/kd.h> // Linux: KDSKBMODE, K_MEDIUMRAM constants definition
|
||||
@ -71,6 +71,14 @@
|
||||
#include "EGL/egl.h" // Native platform windowing system interface
|
||||
#include "EGL/eglext.h" // EGL extensions
|
||||
|
||||
// NOTE: DRM cache enables triple buffered DRM caching
|
||||
#if defined(SUPPORT_DRM_CACHE)
|
||||
#include <poll.h> // Required for: drmHandleEvent() poll
|
||||
#include <errno.h> // Required for: EBUSY, EAGAIN
|
||||
|
||||
#define MAX_DRM_CACHED_BUFFERS 3
|
||||
#endif // SUPPORT_DRM_CACHE
|
||||
|
||||
#ifndef EGL_OPENGL_ES3_BIT
|
||||
#define EGL_OPENGL_ES3_BIT 0x40
|
||||
#endif
|
||||
@ -78,18 +86,16 @@
|
||||
//----------------------------------------------------------------------------------
|
||||
// Defines and Macros
|
||||
//----------------------------------------------------------------------------------
|
||||
#define USE_LAST_TOUCH_DEVICE // When multiple touchscreens are connected, only use the one with the highest event<N> number
|
||||
#define USE_LAST_TOUCH_DEVICE // When multiple touchscreens are connected, only use the one with the highest event<N> number
|
||||
|
||||
#define DEFAULT_EVDEV_PATH "/dev/input/" // Path to the linux input events
|
||||
#define DEFAULT_EVDEV_PATH "/dev/input/" // Path to the linux input events
|
||||
|
||||
// So actually the biggest key is KEY_CNT but we only really map the keys up to
|
||||
// KEY_ALS_TOGGLE
|
||||
// Actually biggest key is KEY_CNT but we only really map the keys up to KEY_ALS_TOGGLE
|
||||
#define KEYMAP_SIZE KEY_ALS_TOGGLE
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
typedef struct {
|
||||
// Display data
|
||||
int fd; // File descriptor for /dev/dri/...
|
||||
@ -124,11 +130,23 @@ typedef struct {
|
||||
|
||||
// Gamepad data
|
||||
int gamepadStreamFd[MAX_GAMEPADS]; // Gamepad device file descriptor
|
||||
int gamepadAbsAxisRange[MAX_GAMEPADS][MAX_GAMEPAD_AXIS][2]; // [0] = min, [1] = range value of the axis
|
||||
int gamepadAbsAxisRange[MAX_GAMEPADS][MAX_GAMEPAD_AXES][2]; // [0] = min, [1] = range value of the axes
|
||||
int gamepadAbsAxisMap[MAX_GAMEPADS][ABS_CNT]; // Maps the axes gamepads from the evdev api to a sequential one
|
||||
int gamepadCount; // The number of gamepads registered
|
||||
} PlatformData;
|
||||
|
||||
#if defined(SUPPORT_DRM_CACHE)
|
||||
typedef struct {
|
||||
struct gbm_bo *bo; // Graphics buffer object
|
||||
uint32_t fbId; // DRM framebuffer ID
|
||||
} FramebufferCache;
|
||||
|
||||
static FramebufferCache fbCache[MAX_DRM_CACHED_BUFFERS] = { 0 };
|
||||
static volatile int fbCacheCount = 0;
|
||||
static volatile bool pendingFlip = false;
|
||||
static bool crtcSet = false;
|
||||
#endif // SUPPORT_DRM_CACHE
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Global Variables Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
@ -551,6 +569,212 @@ void DisableCursor(void)
|
||||
CORE.Input.Mouse.cursorHidden = true;
|
||||
}
|
||||
|
||||
#if defined(SUPPORT_DRM_CACHE)
|
||||
|
||||
// Destroy cached framebuffer callback, set by gbm_bo_set_user_data()
|
||||
static void DestroyFrameBufferCallback(struct gbm_bo *bo, void *data)
|
||||
{
|
||||
uint32_t fbId = (uintptr_t)data;
|
||||
|
||||
// Remove from cache
|
||||
for (int i = 0; i < fbCacheCount; i++)
|
||||
{
|
||||
if (fbCache[i].bo == bo)
|
||||
{
|
||||
TRACELOG(LOG_INFO, "DISPLAY: DRM: Framebuffer removed [%u]", (uintptr_t)fbId);
|
||||
drmModeRmFB(platform.fd, fbCache[i].fbId); // Release DRM FB
|
||||
|
||||
// Shift remaining entries
|
||||
for (int j = i; j < fbCacheCount - 1; j++) fbCache[j] = fbCache[j + 1];
|
||||
|
||||
fbCacheCount--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create or retrieve cached DRM FB for BO
|
||||
static uint32_t GetOrCreateFbForBo(struct gbm_bo *bo)
|
||||
{
|
||||
// Try to find existing cache entry
|
||||
for (int i = 0; i < fbCacheCount; i++)
|
||||
{
|
||||
if (fbCache[i].bo == bo) return fbCache[i].fbId;
|
||||
}
|
||||
|
||||
// Create new entry if cache not full
|
||||
if (fbCacheCount >= MAX_DRM_CACHED_BUFFERS) return 0; // FB cache full
|
||||
|
||||
uint32_t handle = gbm_bo_get_handle(bo).u32;
|
||||
uint32_t stride = gbm_bo_get_stride(bo);
|
||||
uint32_t width = gbm_bo_get_width(bo);
|
||||
uint32_t height = gbm_bo_get_height(bo);
|
||||
|
||||
uint32_t fbId = 0;
|
||||
if (drmModeAddFB(platform.fd, width, height, 24, 32, stride, handle, &fbId)) return 0;
|
||||
|
||||
// Store in cache
|
||||
fbCache[fbCacheCount] = (FramebufferCache){ .bo = bo, .fbId = fbId };
|
||||
fbCacheCount++;
|
||||
|
||||
// Set destroy callback to auto-cleanup
|
||||
gbm_bo_set_user_data(bo, (void *)(uintptr_t)fbId, DestroyFrameBufferCallback);
|
||||
|
||||
TRACELOG(LOG_INFO, "DISPLAY: DRM: Added new buffer object [%u]" , (uintptr_t)fbId);
|
||||
|
||||
return fbId;
|
||||
}
|
||||
|
||||
// Renders a blank frame to allocate initial buffers
|
||||
// TODO: WARNING: Platform layers do not include OpenGL code!
|
||||
void RenderBlankFrame()
|
||||
{
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
eglSwapBuffers(platform.device, platform.surface);
|
||||
glFinish(); // Ensure the buffer is processed
|
||||
}
|
||||
|
||||
// Initialize with first buffer only
|
||||
int InitSwapScreenBuffer()
|
||||
{
|
||||
if (!platform.gbmSurface || (platform.fd < 0))
|
||||
{
|
||||
TRACELOG(LOG_ERROR, "DISPLAY: DRM: Swap buffers can not be initialized");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Render a blank frame to allocate buffers
|
||||
RenderBlankFrame();
|
||||
|
||||
// Get first buffer
|
||||
struct gbm_bo *bo = gbm_surface_lock_front_buffer(platform.gbmSurface);
|
||||
if (!bo)
|
||||
{
|
||||
TRACELOG(LOG_ERROR, "DISPLAY: DRM: Failed to lock initial swap buffer");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create FB for first buffer
|
||||
uint32_t fbId = GetOrCreateFbForBo(bo);
|
||||
if (!fbId)
|
||||
{
|
||||
gbm_surface_release_buffer(platform.gbmSurface, bo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Initial CRTC setup
|
||||
if (drmModeSetCrtc(platform.fd, platform.crtc->crtc_id, fbId, 0, 0, &platform.connector->connector_id, 1, &platform.connector->modes[platform.modeIndex]))
|
||||
{
|
||||
TRACELOG(LOG_ERROR, "DISPLAY: DRM: Failed to initialize CRTC setup. ERROR: %s", strerror(errno));
|
||||
gbm_surface_release_buffer(platform.gbmSurface, bo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Keep first buffer locked until flipped
|
||||
platform.prevBO = bo;
|
||||
crtcSet = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Static page flip handler
|
||||
// NOTE: Called once the drmModePageFlip() finished from the drmHandleEvent() context
|
||||
static void PageFlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data)
|
||||
{
|
||||
// Unused inputs
|
||||
(void)fd;
|
||||
(void)frame;
|
||||
(void)sec;
|
||||
(void)usec;
|
||||
|
||||
pendingFlip = false;
|
||||
struct gbm_bo *boToRelease = (struct gbm_bo *)data;
|
||||
|
||||
// Buffers are released after the flip completes (via page_flip_handler), ensuring they're no longer in use
|
||||
// Prevents the GPU from writing to a buffer being scanned out
|
||||
if (boToRelease) gbm_surface_release_buffer(platform.gbmSurface, boToRelease);
|
||||
}
|
||||
|
||||
// Swap implementation with proper caching
|
||||
void SwapScreenBuffer()
|
||||
{
|
||||
if (!crtcSet || !platform.gbmSurface) return;
|
||||
|
||||
static int loopCnt = 0;
|
||||
static int errCnt[5] = {0};
|
||||
loopCnt++;
|
||||
|
||||
// Call this only, if pendingFlip is not set
|
||||
eglSwapBuffers(platform.device, platform.surface);
|
||||
|
||||
// Process pending events non-blocking
|
||||
drmEventContext evctx = {
|
||||
.version = DRM_EVENT_CONTEXT_VERSION,
|
||||
.page_flip_handler = PageFlipHandler
|
||||
};
|
||||
|
||||
struct pollfd pfd = { .fd = platform.fd, .events = POLLIN };
|
||||
|
||||
// Polling for event for 0ms
|
||||
while (poll(&pfd, 1, 0) > 0) drmHandleEvent(platform.fd, &evctx);
|
||||
|
||||
// Skip if previous flip pending
|
||||
if (pendingFlip)
|
||||
{
|
||||
errCnt[0]++; // Skip frame: flip pending
|
||||
return;
|
||||
}
|
||||
|
||||
// Get new front buffer
|
||||
struct gbm_bo *nextBO = gbm_surface_lock_front_buffer(platform.gbmSurface);
|
||||
if (!nextBO) // Failed to lock front buffer
|
||||
{
|
||||
errCnt[1]++;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get FB ID (creates new one if needed)
|
||||
uint32_t fbId = GetOrCreateFbForBo(nextBO);
|
||||
if (!fbId)
|
||||
{
|
||||
gbm_surface_release_buffer(platform.gbmSurface, nextBO);
|
||||
errCnt[2]++;
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempt page flip
|
||||
// NOTE: rmModePageFlip() schedules a buffer-flip for the next vblank and then notifies us about it
|
||||
// It takes a CRTC-id, fb-id and an arbitrary data-pointer and then schedules the page-flip
|
||||
// This is fully asynchronous and when the page-flip happens, the DRM-fd will become readable and we can call drmHandleEvent()
|
||||
// This will read all vblank/page-flip events and call our modeset_page_flip_event() callback with the data-pointer that we passed to drmModePageFlip()
|
||||
// We simply call modeset_draw_dev() then so the next frame is rendered... returns immediately
|
||||
if (drmModePageFlip(platform.fd, platform.crtc->crtc_id, fbId, DRM_MODE_PAGE_FLIP_EVENT, platform.prevBO))
|
||||
{
|
||||
if (errno == EBUSY) errCnt[3]++; // Display busy - skip flip
|
||||
else errCnt[4]++; // Page flip failed
|
||||
|
||||
gbm_surface_release_buffer(platform.gbmSurface, nextBO);
|
||||
return;
|
||||
}
|
||||
|
||||
// Success: update state
|
||||
pendingFlip = true;
|
||||
platform.prevBO = nextBO;
|
||||
|
||||
/*
|
||||
// Some benchmarking code
|
||||
if (loopCnt >= 600)
|
||||
{
|
||||
TRACELOG(LOG_INFO, "DRM: Error counters: %d, %d, %d, %d, %d, %d", errCnt[0], errCnt[1], errCnt[2], errCnt[3], errCnt[4], loopCnt);
|
||||
for (int i = 0; i < 5; i++) errCnt[i] = 0;
|
||||
loopCnt = 0;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
#else // !SUPPORT_DRM_CACHE
|
||||
|
||||
// Swap back buffer with front buffer (screen drawing)
|
||||
void SwapScreenBuffer(void)
|
||||
{
|
||||
@ -580,6 +804,7 @@ void SwapScreenBuffer(void)
|
||||
|
||||
platform.prevBO = bo;
|
||||
}
|
||||
#endif // SUPPORT_DRM_CACHE
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition: Misc
|
||||
@ -599,9 +824,9 @@ double GetTime(void)
|
||||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
// NOTE: This function is only safe to use if you control the URL given.
|
||||
// A user could craft a malicious string performing another action.
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself.
|
||||
// NOTE: This function is only safe to use if you control the URL given
|
||||
// A user could craft a malicious string performing another action
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself
|
||||
// Ref: https://github.com/raysan5/raylib/issues/686
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
@ -638,7 +863,7 @@ void SetMouseCursor(int cursor)
|
||||
TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform");
|
||||
}
|
||||
|
||||
// Get physical key name.
|
||||
// Get physical key name
|
||||
const char *GetKeyName(int key)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform");
|
||||
@ -672,7 +897,7 @@ void PollInputEvents(void)
|
||||
PollKeyboardEvents();
|
||||
|
||||
#if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
||||
// NOTE: Keyboard reading could be done using input_event(s) or just read from stdin, both methods are used here.
|
||||
// NOTE: Keyboard reading could be done using input_event(s) or just read from stdin, both methods are used here
|
||||
// stdin reading is still used for legacy purposes, it allows keyboard input trough SSH console
|
||||
if (!platform.eventKeyboardMode) ProcessKeyboard();
|
||||
#endif
|
||||
@ -778,8 +1003,8 @@ int InitPlatform(void)
|
||||
drmModeConnector *con = drmModeGetConnector(platform.fd, res->connectors[i]);
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: Connector modes detected: %i", con->count_modes);
|
||||
|
||||
// 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.
|
||||
// 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");
|
||||
@ -935,7 +1160,7 @@ int InitPlatform(void)
|
||||
// Initialize the EGL device connection
|
||||
if (eglInitialize(platform.device, NULL, NULL) == EGL_FALSE)
|
||||
{
|
||||
// If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred.
|
||||
// If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device");
|
||||
return -1;
|
||||
}
|
||||
@ -948,7 +1173,7 @@ int InitPlatform(void)
|
||||
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: EGL configs available: %d", numConfigs);
|
||||
|
||||
EGLConfig *configs = RL_CALLOC(numConfigs, sizeof(*configs));
|
||||
EGLConfig *configs = (EGLConfig *)RL_CALLOC(numConfigs, sizeof(*configs));
|
||||
if (!configs)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get memory for EGL configs");
|
||||
@ -1083,9 +1308,21 @@ int InitPlatform(void)
|
||||
CORE.Storage.basePath = GetWorkingDirectory();
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#if defined(SUPPORT_DRM_CACHE)
|
||||
if (InitSwapScreenBuffer() == 0)
|
||||
{
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DRM: Initialized successfully");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DRM: Initialized failed");
|
||||
return -1;
|
||||
}
|
||||
#else // !SUPPORT_DRM_CACHE
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DRM: Initialized successfully");
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Close platform
|
||||
@ -1319,7 +1556,7 @@ static void ProcessKeyboard(void)
|
||||
{
|
||||
CORE.Input.Keyboard.currentKeyState[259] = 1;
|
||||
|
||||
CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = 257; // Add keys pressed into queue
|
||||
CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = 259; // Add keys pressed into queue
|
||||
CORE.Input.Keyboard.keyPressedQueueCount++;
|
||||
}
|
||||
else
|
||||
@ -1374,7 +1611,7 @@ static void InitEvdevInput(void)
|
||||
if ((strncmp("event", entity->d_name, strlen("event")) == 0) || // Search for devices named "event*"
|
||||
(strncmp("mouse", entity->d_name, strlen("mouse")) == 0)) // Search for devices named "mouse*"
|
||||
{
|
||||
sprintf(path, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name);
|
||||
snprintf(path, MAX_FILEPATH_LENGTH, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name);
|
||||
ConfigureEvdevDevice(path); // Configure the device if appropriate
|
||||
}
|
||||
}
|
||||
@ -1407,7 +1644,7 @@ static void ConfigureEvdevDevice(char *device)
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point we have a connection to the device, but we don't yet know what the device is.
|
||||
// At this point we have a connection to the device, but we don't yet know what the device is
|
||||
// It could be many things, even as simple as a power button...
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -1460,7 +1697,7 @@ static void ConfigureEvdevDevice(char *device)
|
||||
// matter if we support them
|
||||
else if (hasAbsXY && TEST_BIT(keyBits, BTN_MOUSE)) isMouse = true;
|
||||
|
||||
// If any of the common joystick axis is present, we assume it's a gamepad
|
||||
// If any of the common joystick axes are present, we assume it's a gamepad
|
||||
else
|
||||
{
|
||||
for (int axis = (hasAbsXY? ABS_Z : ABS_X); axis < ABS_PRESSURE; axis++)
|
||||
@ -1546,7 +1783,7 @@ static void ConfigureEvdevDevice(char *device)
|
||||
if (absAxisCount > 0)
|
||||
{
|
||||
// TODO / NOTE
|
||||
// So gamepad axis (as in the actual linux joydev.c) are just simply enumerated
|
||||
// So gamepad axes (as in the actual linux joydev.c) are just simply enumerated
|
||||
// and (at least for some input drivers like xpat) it's convention to use
|
||||
// ABS_X, ABX_Y for one joystick ABS_RX, ABS_RY for the other and the Z axes for the
|
||||
// shoulder buttons
|
||||
@ -1681,7 +1918,7 @@ static void PollGamepadEvents(void)
|
||||
|
||||
TRACELOG(LOG_DEBUG, "INPUT: Gamepad %2i: Axis: %2i Value: %i", i, axisRaylib, event.value);
|
||||
|
||||
if (axisRaylib < MAX_GAMEPAD_AXIS)
|
||||
if (axisRaylib < MAX_GAMEPAD_AXES)
|
||||
{
|
||||
int min = platform.gamepadAbsAxisRange[i][event.code][0];
|
||||
int range = platform.gamepadAbsAxisRange[i][event.code][1];
|
||||
|
||||
@ -111,23 +111,23 @@ int InitPlatform(void); // Initialize platform (graphics, inputs and mo
|
||||
void ClosePlatform(void); // Close platform
|
||||
|
||||
// Error callback event
|
||||
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
|
||||
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
|
||||
|
||||
// Window callbacks events
|
||||
static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized
|
||||
static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored
|
||||
static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 Window Size Callback, runs when window is resized
|
||||
static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 Window Iconify 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 WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus
|
||||
static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 Window Focus Callback, runs when window get/lose focus
|
||||
static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window
|
||||
static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley); // GLFW3 Window Content Scale Callback, runs when window changes scale
|
||||
|
||||
// Input callbacks events
|
||||
static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed
|
||||
static void CharCallback(GLFWwindow *window, unsigned int key); // GLFW3 Char Key Callback, runs on key pressed (get char value)
|
||||
static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods); // GLFW3 Mouse Button Callback, runs on mouse button pressed
|
||||
static void MouseCursorPosCallback(GLFWwindow *window, double x, double y); // GLFW3 Cursor Position Callback, runs on mouse move
|
||||
static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Srolling Callback, runs on mouse wheel
|
||||
static void CursorEnterCallback(GLFWwindow *window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area
|
||||
static void CharCallback(GLFWwindow *window, unsigned int key); // GLFW3 Char Key Callback, runs on key pressed (get char value)
|
||||
static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods); // GLFW3 Mouse Button Callback, runs on mouse button pressed
|
||||
static void MouseMoveCallback(GLFWwindow *window, double x, double y); // GLFW3 Mouse Move Callback, runs on mouse move
|
||||
static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Mouse Scrolling Callback, runs on mouse wheel
|
||||
static void MouseEnterCallback(GLFWwindow *window, int enter); // GLFW3 Mouse Enter Callback, cursor enters client area
|
||||
|
||||
// Emscripten window callback events
|
||||
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData);
|
||||
@ -137,6 +137,7 @@ static EM_BOOL EmscriptenFocusCallback(int eventType, const EmscriptenFocusEvent
|
||||
static EM_BOOL EmscriptenVisibilityChangeCallback(int eventType, const EmscriptenVisibilityChangeEvent *visibilityChangeEvent, void *userData);
|
||||
|
||||
// Emscripten input callback events
|
||||
//static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyboardEvent, void *userData);
|
||||
static EM_BOOL EmscriptenMouseMoveCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
|
||||
static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
|
||||
static EM_BOOL EmscriptenPointerlockCallback(int eventType, const EmscriptenPointerlockChangeEvent *pointerlockChangeEvent, void *userData);
|
||||
@ -163,13 +164,13 @@ bool WindowShouldClose(void)
|
||||
// REF: https://emscripten.org/docs/porting/asyncify.html
|
||||
|
||||
// WindowShouldClose() is not called on a web-ready raylib application if using emscripten_set_main_loop()
|
||||
// and encapsulating one frame execution on a UpdateDrawFrame() function,
|
||||
// and encapsulating one frame execution on a UpdateDrawFrame() function,
|
||||
// allowing the browser to manage execution asynchronously
|
||||
|
||||
// Optionally we can manage the time we give-control-back-to-browser if required,
|
||||
// but it seems below line could generate stuttering on some browsers
|
||||
emscripten_sleep(12);
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1081,7 +1082,7 @@ void PollInputEvents(void)
|
||||
}
|
||||
|
||||
// Register axis data for every connected gamepad
|
||||
for (int j = 0; (j < gamepadState.numAxes) && (j < MAX_GAMEPAD_AXIS); j++)
|
||||
for (int j = 0; (j < gamepadState.numAxes) && (j < MAX_GAMEPAD_AXES); j++)
|
||||
{
|
||||
CORE.Input.Gamepad.axisState[i][j] = gamepadState.axis[j];
|
||||
}
|
||||
@ -1300,23 +1301,24 @@ int InitPlatform(void)
|
||||
emscripten_set_window_title((CORE.Window.title != 0)? CORE.Window.title : " ");
|
||||
|
||||
// Set window callback events
|
||||
glfwSetWindowSizeCallback(platform.handle, WindowSizeCallback); // NOTE: Resizing not allowed by default!
|
||||
glfwSetWindowSizeCallback(platform.handle, WindowSizeCallback);
|
||||
glfwSetWindowIconifyCallback(platform.handle, WindowIconifyCallback);
|
||||
glfwSetWindowFocusCallback(platform.handle, WindowFocusCallback);
|
||||
glfwSetDropCallback(platform.handle, WindowDropCallback);
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
{
|
||||
glfwSetWindowContentScaleCallback(platform.handle, WindowContentScaleCallback);
|
||||
// Window content (framebuffer) scale callback
|
||||
glfwSetWindowContentScaleCallback(platform.handle, WindowContentScaleCallback);
|
||||
}
|
||||
|
||||
// Set input callback events
|
||||
glfwSetKeyCallback(platform.handle, KeyCallback);
|
||||
glfwSetCharCallback(platform.handle, CharCallback);
|
||||
glfwSetMouseButtonCallback(platform.handle, MouseButtonCallback);
|
||||
glfwSetCursorPosCallback(platform.handle, MouseCursorPosCallback); // Track mouse position changes
|
||||
glfwSetCursorPosCallback(platform.handle, MouseMoveCallback);
|
||||
glfwSetScrollCallback(platform.handle, MouseScrollCallback);
|
||||
glfwSetCursorEnterCallback(platform.handle, CursorEnterCallback);
|
||||
glfwSetCursorEnterCallback(platform.handle, MouseEnterCallback);
|
||||
|
||||
glfwMakeContextCurrent(platform.handle);
|
||||
result = true; // TODO: WARNING: glfwGetError(NULL); symbol can not be found in Web
|
||||
@ -1356,48 +1358,36 @@ int InitPlatform(void)
|
||||
rlLoadExtensions(glfwGetProcAddress);
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Initialize input events callbacks
|
||||
// Initialize events callbacks
|
||||
//----------------------------------------------------------------------------
|
||||
// Setup callback functions for the DOM events
|
||||
// Setup window events callbacks
|
||||
emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenFullscreenChangeCallback);
|
||||
|
||||
emscripten_set_blur_callback(GetCanvasId(), platform.handle, 1, EmscriptenFocusCallback);
|
||||
emscripten_set_focus_callback(GetCanvasId(), platform.handle, 1, EmscriptenFocusCallback);
|
||||
emscripten_set_visibilitychange_callback(NULL, 1, EmscriptenVisibilityChangeCallback);
|
||||
|
||||
// WARNING: Below resize code was breaking fullscreen mode for sample games and examples, it needs review
|
||||
// Check fullscreen change events(note this is done on the window since most browsers don't support this on #canvas)
|
||||
// emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
|
||||
// Check Resize event (note this is done on the window since most browsers don't support this on #canvas)
|
||||
emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
|
||||
|
||||
// Trigger this once to get initial window sizing
|
||||
// Trigger resize callback to force initial size
|
||||
EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
|
||||
|
||||
// Support keyboard events -> Not used, GLFW.JS takes care of that
|
||||
// emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
|
||||
// emscripten_set_keydown_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
|
||||
|
||||
// Support mouse events
|
||||
// Setup input events
|
||||
// NOTE: Keyboard callbacks only used to consume some events, libglfw.js takes care of the actual input
|
||||
//emscripten_set_keypress_callback(GetCanvasId(), NULL, 1, EmscriptenKeyboardCallback); // WRNING: Breaks input
|
||||
//emscripten_set_keydown_callback(GetCanvasId(), NULL, 1, EmscriptenKeyboardCallback);
|
||||
emscripten_set_click_callback(GetCanvasId(), NULL, 1, EmscriptenMouseCallback);
|
||||
emscripten_set_pointerlockchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenPointerlockCallback);
|
||||
|
||||
// Following the mouse delta when the mouse is locked
|
||||
emscripten_set_mousemove_callback(GetCanvasId(), NULL, 1, EmscriptenMouseMoveCallback);
|
||||
|
||||
// Support touch events
|
||||
emscripten_set_touchstart_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback);
|
||||
emscripten_set_touchend_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback);
|
||||
emscripten_set_touchmove_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback);
|
||||
emscripten_set_touchcancel_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback);
|
||||
|
||||
// Support gamepad events (not provided by GLFW3 on emscripten)
|
||||
emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenGamepadCallback);
|
||||
emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback);
|
||||
|
||||
// Support focus events
|
||||
emscripten_set_blur_callback(GetCanvasId(), platform.handle, 1, EmscriptenFocusCallback);
|
||||
emscripten_set_focus_callback(GetCanvasId(), platform.handle, 1, EmscriptenFocusCallback);
|
||||
|
||||
// Support visibility events
|
||||
emscripten_set_visibilitychange_callback(NULL, 1, EmscriptenVisibilityChangeCallback);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Initialize timing system
|
||||
@ -1422,14 +1412,15 @@ void ClosePlatform(void)
|
||||
glfwTerminate();
|
||||
}
|
||||
|
||||
// GLFW3 Error Callback, runs on GLFW3 error
|
||||
// GLFW3 callback functions, called on GLFW registered events
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
// GLFW3: Called on errors
|
||||
static void ErrorCallback(int error, const char *description)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GLFW: Error: %i Description: %s", error, description);
|
||||
}
|
||||
|
||||
// GLFW3 WindowSize Callback, runs when window is resizedLastFrame
|
||||
// NOTE: Window resizing not allowed by default
|
||||
// GLFW3: Called on window resizing, runs when window is resizedLastFrame
|
||||
static void WindowSizeCallback(GLFWwindow *window, int width, int height)
|
||||
{
|
||||
// Reset viewport and projection matrix for new size
|
||||
@ -1458,34 +1449,27 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height)
|
||||
// NOTE: Postprocessing texture is not scaled to new size
|
||||
}
|
||||
|
||||
// GLFW3: Called on window content (framebuffer) scaled
|
||||
static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley)
|
||||
{
|
||||
CORE.Window.screenScale = MatrixScale(scalex, scaley, 1.0f);
|
||||
}
|
||||
|
||||
// GLFW3 WindowIconify Callback, runs when window is minimized/restored
|
||||
// GLFW3: Called on windows minimized/restored
|
||||
static void WindowIconifyCallback(GLFWwindow *window, int iconified)
|
||||
{
|
||||
if (iconified) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; // The window was iconified
|
||||
else CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored
|
||||
}
|
||||
|
||||
/*
|
||||
// GLFW3 Window Maximize Callback, runs when window is maximized
|
||||
static void WindowMaximizeCallback(GLFWwindow *window, int maximized)
|
||||
{
|
||||
// TODO.
|
||||
}
|
||||
*/
|
||||
|
||||
// GLFW3 WindowFocus Callback, runs when window get/lose focus
|
||||
// GLFW3: Called on windows get/lose focus
|
||||
static void WindowFocusCallback(GLFWwindow *window, int focused)
|
||||
{
|
||||
if (focused) CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // The window was focused
|
||||
else CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED; // The window lost focus
|
||||
}
|
||||
|
||||
// GLFW3 Window Drop Callback, runs when drop files into window
|
||||
// GLFW3: Called on file-drop over the window
|
||||
static void WindowDropCallback(GLFWwindow *window, int count, const char **paths)
|
||||
{
|
||||
if (count > 0)
|
||||
@ -1513,7 +1497,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths
|
||||
}
|
||||
}
|
||||
|
||||
// GLFW3 Keyboard Callback, runs on key pressed
|
||||
// GLFW3: Called on keyboard interaction
|
||||
static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
if (key < 0) return; // Security check, macOS fn key generates -1
|
||||
@ -1536,7 +1520,7 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
|
||||
if ((key == CORE.Input.Keyboard.exitKey) && (action == GLFW_PRESS)) glfwSetWindowShouldClose(platform.handle, GLFW_TRUE);
|
||||
}
|
||||
|
||||
// GLFW3 Char Key Callback, runs on key down (gets equivalent unicode char value)
|
||||
// GLFW3: Called on key down interaction, gets equivalent unicode char value for the key
|
||||
static void CharCallback(GLFWwindow *window, unsigned int key)
|
||||
{
|
||||
//TRACELOG(LOG_DEBUG, "Char Callback: KEY:%i(%c)", key, key);
|
||||
@ -1555,7 +1539,7 @@ static void CharCallback(GLFWwindow *window, unsigned int key)
|
||||
}
|
||||
}
|
||||
|
||||
// GLFW3 Mouse Button Callback, runs on mouse button pressed
|
||||
// GLFW3: Called on mouse button interaction
|
||||
static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods)
|
||||
{
|
||||
// WARNING: GLFW could only return GLFW_PRESS (1) or GLFW_RELEASE (0) for now,
|
||||
@ -1571,7 +1555,7 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int
|
||||
if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) gestureEvent.touchAction = TOUCH_ACTION_DOWN;
|
||||
else if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) gestureEvent.touchAction = TOUCH_ACTION_UP;
|
||||
|
||||
// NOTE: TOUCH_ACTION_MOVE event is registered in MouseCursorPosCallback()
|
||||
// NOTE: TOUCH_ACTION_MOVE event is registered in MouseMoveCallback()
|
||||
|
||||
// Assign a pointer ID
|
||||
gestureEvent.pointId[0] = 0;
|
||||
@ -1593,8 +1577,8 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int
|
||||
#endif
|
||||
}
|
||||
|
||||
// GLFW3 Cursor Position Callback, runs on mouse move
|
||||
static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
|
||||
// GLFW3: Called on mouse move
|
||||
static void MouseMoveCallback(GLFWwindow *window, double x, double y)
|
||||
{
|
||||
// If the pointer is not locked, follow the position
|
||||
if (!CORE.Input.Mouse.cursorHidden)
|
||||
@ -1628,34 +1612,28 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
|
||||
#endif
|
||||
}
|
||||
|
||||
static EM_BOOL EmscriptenMouseMoveCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
|
||||
{
|
||||
// To emulate the GLFW_RAW_MOUSE_MOTION property.
|
||||
if (CORE.Input.Mouse.cursorHidden)
|
||||
{
|
||||
CORE.Input.Mouse.previousPosition.x = lockedMousePos.x - mouseEvent->movementX;
|
||||
CORE.Input.Mouse.previousPosition.y = lockedMousePos.y - mouseEvent->movementY;
|
||||
}
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// GLFW3 Scrolling Callback, runs on mouse wheel
|
||||
// GLFW3: Called on mouse wheel scrolling
|
||||
static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset)
|
||||
{
|
||||
CORE.Input.Mouse.currentWheelMove = (Vector2){ (float)xoffset, (float)yoffset };
|
||||
}
|
||||
|
||||
// GLFW3 CursorEnter Callback, when cursor enters the window
|
||||
static void CursorEnterCallback(GLFWwindow *window, int enter)
|
||||
// GLFW3: Called on mouse entering the window
|
||||
static void MouseEnterCallback(GLFWwindow *window, int enter)
|
||||
{
|
||||
if (enter) CORE.Input.Mouse.cursorOnScreen = true;
|
||||
else CORE.Input.Mouse.cursorOnScreen = false;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Register fullscreen change events
|
||||
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData)
|
||||
// Emscripten callback functions, called on specific browser events
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
// Emscripten: Called on key events
|
||||
static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyboardEvent, void *userData)
|
||||
{
|
||||
// WARNING: Keyboard inputs already processed through GLFW callback
|
||||
|
||||
// NOTE: 1. Reset the fullscreen flags if the user left fullscreen manually by pressing the Escape key
|
||||
// 2. Which is a necessary safeguard because that case will bypass the toggles CORE.Window.flags resets
|
||||
if (platform.ourFullscreen) platform.ourFullscreen = false;
|
||||
@ -1670,23 +1648,21 @@ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const Emscripte
|
||||
}
|
||||
}
|
||||
|
||||
// trigger resize event after a brief pause to ensure the canvas exists to resize
|
||||
// Trigger resize event after a brief pause to ensure the canvas exists to resize
|
||||
EM_ASM({ setTimeout(function() { window.dispatchEvent(new Event("resize")); }, 50); });
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
*/
|
||||
|
||||
// Register window resize event
|
||||
// static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData)
|
||||
// {
|
||||
// // TODO: Implement EmscriptenWindowResizedCallback()?
|
||||
|
||||
// return 1; // The event was consumed by the callback handler
|
||||
// }
|
||||
|
||||
// Register DOM element resize event
|
||||
static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData)
|
||||
// Emscripten: Called on mouse input events
|
||||
static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
|
||||
{
|
||||
// NOTE: Current code solves mouse position problems with the 3 possible approaches to canvas scaling
|
||||
// 1. Canvas not scaled, framebuffer size is fixed
|
||||
// 2. Canvas is scaled to 100% browser size, framebuffer size is fixed
|
||||
// 3. Canvas is resized to browser size, framebuffer is resized
|
||||
|
||||
// Don't resize non-resizeable windows
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) == 0) return 1;
|
||||
|
||||
@ -1703,7 +1679,7 @@ static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *
|
||||
|
||||
emscripten_set_canvas_element_size(GetCanvasId(), width, height);
|
||||
|
||||
glfwSetWindowSize(platform.handle, width, height); // inform glfw of the new size
|
||||
glfwSetWindowSize(platform.handle, width, height); // Inform glfw of the new size
|
||||
|
||||
SetupViewport(width, height); // Reset viewport and projection matrix for new size
|
||||
|
||||
@ -1717,20 +1693,25 @@ static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *
|
||||
CORE.Window.screen.width = width;
|
||||
CORE.Window.screen.height = height;
|
||||
|
||||
// NOTE: Postprocessing texture is not scaled to new size
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Register mouse input events
|
||||
static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
|
||||
{
|
||||
// This is only for registering mouse click events with emscripten and doesn't need to do anything
|
||||
// WARNING: RenderTextures are not scaled to new size
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// Register pointer lock events
|
||||
// Emscripten: Called on mouse move events
|
||||
static EM_BOOL EmscriptenMouseMoveCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
|
||||
{
|
||||
// To emulate the GLFW_RAW_MOUSE_MOTION property.
|
||||
if (CORE.Input.Mouse.cursorHidden)
|
||||
{
|
||||
CORE.Input.Mouse.previousPosition.x = lockedMousePos.x - mouseEvent->movementX;
|
||||
CORE.Input.Mouse.previousPosition.y = lockedMousePos.y - mouseEvent->movementY;
|
||||
}
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// Emscripten: Called on pointer lock events
|
||||
static EM_BOOL EmscriptenPointerlockCallback(int eventType, const EmscriptenPointerlockChangeEvent *pointerlockChangeEvent, void *userData)
|
||||
{
|
||||
CORE.Input.Mouse.cursorHidden = EM_ASM_INT( { if (document.pointerLockElement) return 1; }, 0);
|
||||
@ -1744,7 +1725,7 @@ static EM_BOOL EmscriptenPointerlockCallback(int eventType, const EmscriptenPoin
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// Register connected/disconnected gamepads events
|
||||
// Emscripten: Called on connect/disconnect gamepads events
|
||||
static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
|
||||
{
|
||||
/*
|
||||
@ -1759,33 +1740,14 @@ static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadE
|
||||
if (gamepadEvent->connected && (gamepadEvent->index < MAX_GAMEPADS))
|
||||
{
|
||||
CORE.Input.Gamepad.ready[gamepadEvent->index] = true;
|
||||
sprintf(CORE.Input.Gamepad.name[gamepadEvent->index], "%s", gamepadEvent->id);
|
||||
snprintf(CORE.Input.Gamepad.name[gamepadEvent->index], MAX_GAMEPAD_NAME_LENGTH, "%s", gamepadEvent->id);
|
||||
}
|
||||
else CORE.Input.Gamepad.ready[gamepadEvent->index] = false;
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
static EM_BOOL EmscriptenFocusCallback(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)
|
||||
{
|
||||
EM_BOOL consumed = 1;
|
||||
switch (eventType)
|
||||
{
|
||||
case EMSCRIPTEN_EVENT_BLUR: WindowFocusCallback(userData, 0); break;
|
||||
case EMSCRIPTEN_EVENT_FOCUS: WindowFocusCallback(userData, 1); break;
|
||||
default: consumed = 0; break;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
static EM_BOOL EmscriptenVisibilityChangeCallback(int eventType, const EmscriptenVisibilityChangeEvent *visibilityChangeEvent, void *userData)
|
||||
{
|
||||
if (visibilityChangeEvent->hidden) CORE.Window.flags |= FLAG_WINDOW_HIDDEN; // The window was hidden
|
||||
else CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; // The window was restored
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// Register touch input events
|
||||
// Emscripten: Called on touch input events
|
||||
static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
|
||||
{
|
||||
// Register touch points count
|
||||
@ -1871,7 +1833,85 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// obtaining the canvas id provided by the module configuration
|
||||
// Emscripten: Called on fullscreen change events
|
||||
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData)
|
||||
{
|
||||
// NOTE: 1. Reset the fullscreen flags if the user left fullscreen manually by pressing the Escape key
|
||||
// 2. Which is a necessary safeguard because that case will bypass the toggles CORE.Window.flags resets
|
||||
if (platform.ourFullscreen) platform.ourFullscreen = false;
|
||||
else
|
||||
{
|
||||
const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
|
||||
if (!wasFullscreen)
|
||||
{
|
||||
CORE.Window.fullscreen = false;
|
||||
CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
|
||||
CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
|
||||
}
|
||||
}
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// Emscripten: Called on resize event
|
||||
static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData)
|
||||
{
|
||||
// Don't resize non-resizeable windows
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) == 0) return 1;
|
||||
|
||||
// This event is called whenever the window changes sizes,
|
||||
// so the size of the canvas object is explicitly retrieved below
|
||||
int width = EM_ASM_INT( return window.innerWidth; );
|
||||
int height = EM_ASM_INT( return window.innerHeight; );
|
||||
|
||||
if (width < (int)CORE.Window.screenMin.width) width = CORE.Window.screenMin.width;
|
||||
else if ((width > (int)CORE.Window.screenMax.width) && (CORE.Window.screenMax.width > 0)) width = CORE.Window.screenMax.width;
|
||||
|
||||
if (height < (int)CORE.Window.screenMin.height) height = CORE.Window.screenMin.height;
|
||||
else if ((height > (int)CORE.Window.screenMax.height) && (CORE.Window.screenMax.height > 0)) height = CORE.Window.screenMax.height;
|
||||
|
||||
emscripten_set_canvas_element_size(GetCanvasId(), width, height);
|
||||
|
||||
SetupViewport(width, height); // Reset viewport and projection matrix for new size
|
||||
|
||||
CORE.Window.currentFbo.width = width;
|
||||
CORE.Window.currentFbo.height = height;
|
||||
CORE.Window.resizedLastFrame = true;
|
||||
|
||||
if (IsWindowFullscreen()) return 1;
|
||||
|
||||
// Set current screen size
|
||||
CORE.Window.screen.width = width;
|
||||
CORE.Window.screen.height = height;
|
||||
|
||||
// NOTE: Postprocessing texture is not scaled to new size
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Emscripten: Called on windows focus change events
|
||||
static EM_BOOL EmscriptenFocusCallback(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)
|
||||
{
|
||||
EM_BOOL consumed = 1;
|
||||
switch (eventType)
|
||||
{
|
||||
case EMSCRIPTEN_EVENT_BLUR: WindowFocusCallback(userData, 0); break;
|
||||
case EMSCRIPTEN_EVENT_FOCUS: WindowFocusCallback(userData, 1); break;
|
||||
default: consumed = 0; break;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
// Emscripten: Called on visibility change events
|
||||
static EM_BOOL EmscriptenVisibilityChangeCallback(int eventType, const EmscriptenVisibilityChangeEvent *visibilityChangeEvent, void *userData)
|
||||
{
|
||||
if (visibilityChangeEvent->hidden) CORE.Window.flags |= FLAG_WINDOW_HIDDEN; // The window was hidden
|
||||
else CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; // The window was restored
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
|
||||
// JS: Get the canvas id provided by the module configuration
|
||||
EM_JS(char*, GetCanvasIdJs, (), {
|
||||
var canvasId = "#" + Module.canvas.id;
|
||||
var lengthBytes = lengthBytesUTF8(canvasId) + 1;
|
||||
@ -1880,6 +1920,7 @@ EM_JS(char*, GetCanvasIdJs, (), {
|
||||
return stringOnWasmHeap;
|
||||
});
|
||||
|
||||
// Get canvas id (using embedded JS function)
|
||||
static const char *GetCanvasId(void)
|
||||
{
|
||||
static char *canvasId = NULL;
|
||||
|
||||
Reference in New Issue
Block a user