Improved touch input handling and multitouch support in drm platform
This commit is contained in:
parent
11c248aa82
commit
a54bb22846
|
|
@ -135,8 +135,12 @@ typedef struct {
|
||||||
char currentButtonStateEvdev[MAX_MOUSE_BUTTONS]; // Holds the new mouse state for the next polling event to grab
|
char currentButtonStateEvdev[MAX_MOUSE_BUTTONS]; // Holds the new mouse state for the next polling event to grab
|
||||||
bool cursorRelative; // Relative cursor mode
|
bool cursorRelative; // Relative cursor mode
|
||||||
int mouseFd; // File descriptor for the evdev mouse/touch/gestures
|
int mouseFd; // File descriptor for the evdev mouse/touch/gestures
|
||||||
|
bool mouseIsTouch; // Check if the current mouse device is actually a touchscreen
|
||||||
Rectangle absRange; // Range of values for absolute pointing devices (touchscreens)
|
Rectangle absRange; // Range of values for absolute pointing devices (touchscreens)
|
||||||
int touchSlot; // Hold the touch slot number of the currently being sent multitouch block
|
int touchSlot; // Hold the touch slot number of the currently being sent multitouch block
|
||||||
|
bool touchActive[MAX_TOUCH_POINTS]; // Track which touch points are currently active
|
||||||
|
Vector2 touchPosition[MAX_TOUCH_POINTS]; // Track touch positions for each slot
|
||||||
|
int touchId[MAX_TOUCH_POINTS]; // Track touch IDs for each slot
|
||||||
|
|
||||||
// Gamepad data
|
// Gamepad data
|
||||||
int gamepadStreamFd[MAX_GAMEPADS]; // Gamepad device file descriptor
|
int gamepadStreamFd[MAX_GAMEPADS]; // Gamepad device file descriptor
|
||||||
|
|
@ -220,7 +224,7 @@ static const short linuxToRaylibMap[KEYMAP_SIZE] = {
|
||||||
248, 0, 0, 0, 0, 0, 0, 0,
|
248, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
|
||||||
// Gamepads are mapped according to:
|
// Gamepads are mapped according to:
|
||||||
// REF: https://www.kernel.org/doc/html/next/input/gamepad.html
|
// https://www.kernel.org/doc/html/next/input/gamepad.html
|
||||||
// Those mappings are standardized, but that doesn't mean people follow
|
// Those mappings are standardized, but that doesn't mean people follow
|
||||||
// the standards, so this is more of an approximation
|
// the standards, so this is more of an approximation
|
||||||
[BTN_DPAD_UP] = GAMEPAD_BUTTON_LEFT_FACE_UP,
|
[BTN_DPAD_UP] = GAMEPAD_BUTTON_LEFT_FACE_UP,
|
||||||
|
|
@ -265,8 +269,6 @@ static int FindMatchingConnectorMode(const drmModeConnector *connector, const dr
|
||||||
static int FindExactConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search exactly matching DRM connector mode in connector's list
|
static int FindExactConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search exactly matching DRM connector mode in connector's list
|
||||||
static int FindNearestConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search the nearest matching DRM connector mode in connector's list
|
static int FindNearestConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search the nearest matching DRM connector mode in connector's list
|
||||||
|
|
||||||
static void SetupFramebuffer(int width, int height); // Setup main framebuffer (required by InitPlatform())
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module Functions Declaration
|
// Module Functions Declaration
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -639,7 +641,7 @@ static uint32_t GetOrCreateFbForBo(struct gbm_bo *bo)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renders a blank frame to allocate initial buffers
|
// Renders a blank frame to allocate initial buffers
|
||||||
// TODO: WARNING: Platform backend should not include OpenGL code
|
// TODO: WARNING: Platform layers do not include OpenGL code!
|
||||||
void RenderBlankFrame()
|
void RenderBlankFrame()
|
||||||
{
|
{
|
||||||
glClearColor(0, 0, 0, 1);
|
glClearColor(0, 0, 0, 1);
|
||||||
|
|
@ -826,6 +828,15 @@ void SwapScreenBuffer(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the software rendered color buffer
|
||||||
|
int bufferWidth = 0, bufferHeight = 0;
|
||||||
|
void *colorBuffer = swGetColorBuffer(&bufferWidth, &bufferHeight);
|
||||||
|
if (!colorBuffer)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_ERROR, "DISPLAY: Failed to get software color buffer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Retrieving the dimensions of the display mode used
|
// Retrieving the dimensions of the display mode used
|
||||||
drmModeModeInfo *mode = &platform.connector->modes[platform.modeIndex];
|
drmModeModeInfo *mode = &platform.connector->modes[platform.modeIndex];
|
||||||
uint32_t width = mode->hdisplay;
|
uint32_t width = mode->hdisplay;
|
||||||
|
|
@ -893,8 +904,16 @@ void SwapScreenBuffer(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the software rendered buffer to the dumb buffer with scaling if needed
|
// Copy the software rendered buffer to the dumb buffer with scaling if needed
|
||||||
// NOTE: RLSW will make a simple copy if the dimensions match
|
if (bufferWidth == width && bufferHeight == height)
|
||||||
swBlitFramebuffer(0, 0, width, height, 0, 0, width, height, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
|
{
|
||||||
|
// Direct copy if sizes match
|
||||||
|
swCopyFramebuffer(0, 0, bufferWidth, bufferHeight, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Scale the software buffer to match the display mode
|
||||||
|
swBlitFramebuffer(0, 0, width, height, 0, 0, bufferWidth, bufferHeight, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
// Unmap the buffer
|
// Unmap the buffer
|
||||||
munmap(dumbBuffer, creq.size);
|
munmap(dumbBuffer, creq.size);
|
||||||
|
|
@ -1015,7 +1034,7 @@ double GetTime(void)
|
||||||
// NOTE: This function is only safe to use if you control the URL given
|
// NOTE: This function is only safe to use if you control the URL given
|
||||||
// A user could craft a malicious string performing another action
|
// 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
|
// 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
|
// Ref: https://github.com/raysan5/raylib/issues/686
|
||||||
void OpenURL(const char *url)
|
void OpenURL(const char *url)
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "OpenURL() not implemented on target platform");
|
TRACELOG(LOG_WARNING, "OpenURL() not implemented on target platform");
|
||||||
|
|
@ -1115,9 +1134,6 @@ void PollInputEvents(void)
|
||||||
// Register previous touch states
|
// Register previous touch states
|
||||||
for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i];
|
for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i];
|
||||||
|
|
||||||
// Reset touch positions to invalid state
|
|
||||||
for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ -1, -1 };
|
|
||||||
|
|
||||||
// Map touch position to mouse position for convenience
|
// Map touch position to mouse position for convenience
|
||||||
// NOTE: For DRM touchscreen devices, this mapping is disabled to avoid false touch detection
|
// NOTE: For DRM touchscreen devices, this mapping is disabled to avoid false touch detection
|
||||||
// CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
|
// CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
|
||||||
|
|
@ -1149,7 +1165,8 @@ int InitPlatform(void)
|
||||||
|
|
||||||
// Initialize graphic device: display/window and graphic context
|
// Initialize graphic device: display/window and graphic context
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
|
CORE.Window.fullscreen = true;
|
||||||
|
CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
|
||||||
|
|
||||||
#if defined(DEFAULT_GRAPHIC_DEVICE_DRM)
|
#if defined(DEFAULT_GRAPHIC_DEVICE_DRM)
|
||||||
platform.fd = open(DEFAULT_GRAPHIC_DEVICE_DRM, O_RDWR);
|
platform.fd = open(DEFAULT_GRAPHIC_DEVICE_DRM, O_RDWR);
|
||||||
|
|
@ -1214,9 +1231,9 @@ int InitPlatform(void)
|
||||||
|
|
||||||
TRACELOG(LOG_TRACE, "DISPLAY: Connector %i modes detected: %i", i, con->count_modes);
|
TRACELOG(LOG_TRACE, "DISPLAY: Connector %i modes detected: %i", i, con->count_modes);
|
||||||
TRACELOG(LOG_TRACE, "DISPLAY: Connector %i status: %s", i,
|
TRACELOG(LOG_TRACE, "DISPLAY: Connector %i status: %s", i,
|
||||||
(con->connection == DRM_MODE_CONNECTED)? "CONNECTED" :
|
(con->connection == DRM_MODE_CONNECTED) ? "CONNECTED" :
|
||||||
(con->connection == DRM_MODE_DISCONNECTED)? "DISCONNECTED" :
|
(con->connection == DRM_MODE_DISCONNECTED) ? "DISCONNECTED" :
|
||||||
(con->connection == DRM_MODE_UNKNOWNCONNECTION)? "UNKNOWN" : "OTHER");
|
(con->connection == DRM_MODE_UNKNOWNCONNECTION) ? "UNKNOWN" : "OTHER");
|
||||||
|
|
||||||
// In certain cases the status of the conneciton is reported as UKNOWN, but it is still connected
|
// 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
|
// This might be a hardware or software limitation like on Raspberry Pi Zero with composite output
|
||||||
|
|
@ -1298,8 +1315,8 @@ int InitPlatform(void)
|
||||||
CORE.Window.screen.height = CORE.Window.display.height;
|
CORE.Window.screen.height = CORE.Window.display.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool allowInterlaced = FLAG_IS_SET(CORE.Window.flags, FLAG_INTERLACED_HINT);
|
const bool allowInterlaced = CORE.Window.flags & FLAG_INTERLACED_HINT;
|
||||||
const int fps = (CORE.Time.target > 0)? (1.0/CORE.Time.target) : 60;
|
const int fps = (CORE.Time.target > 0) ? (1.0/CORE.Time.target) : 60;
|
||||||
|
|
||||||
// Try to find an exact matching mode
|
// Try to find an exact matching mode
|
||||||
platform.modeIndex = FindExactConnectorMode(platform.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced);
|
platform.modeIndex = FindExactConnectorMode(platform.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced);
|
||||||
|
|
@ -1329,7 +1346,7 @@ int InitPlatform(void)
|
||||||
|
|
||||||
TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u)", platform.connector->modes[platform.modeIndex].name,
|
TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u)", platform.connector->modes[platform.modeIndex].name,
|
||||||
platform.connector->modes[platform.modeIndex].hdisplay, platform.connector->modes[platform.modeIndex].vdisplay,
|
platform.connector->modes[platform.modeIndex].hdisplay, platform.connector->modes[platform.modeIndex].vdisplay,
|
||||||
FLAG_IS_SET(platform.connector->modes[platform.modeIndex].flags, DRM_MODE_FLAG_INTERLACE)? 'i' : 'p',
|
(platform.connector->modes[platform.modeIndex].flags & DRM_MODE_FLAG_INTERLACE) ? 'i' : 'p',
|
||||||
platform.connector->modes[platform.modeIndex].vrefresh);
|
platform.connector->modes[platform.modeIndex].vrefresh);
|
||||||
|
|
||||||
drmModeFreeEncoder(enc);
|
drmModeFreeEncoder(enc);
|
||||||
|
|
@ -1346,7 +1363,7 @@ int InitPlatform(void)
|
||||||
platform.connector->modes[0].name,
|
platform.connector->modes[0].name,
|
||||||
platform.connector->modes[0].hdisplay,
|
platform.connector->modes[0].hdisplay,
|
||||||
platform.connector->modes[0].vdisplay,
|
platform.connector->modes[0].vdisplay,
|
||||||
(platform.connector->modes[0].flags & DRM_MODE_FLAG_INTERLACE)? 'i' : 'p',
|
(platform.connector->modes[0].flags & DRM_MODE_FLAG_INTERLACE) ? 'i' : 'p',
|
||||||
platform.connector->modes[0].vrefresh);
|
platform.connector->modes[0].vrefresh);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -1385,7 +1402,7 @@ int InitPlatform(void)
|
||||||
|
|
||||||
EGLint samples = 0;
|
EGLint samples = 0;
|
||||||
EGLint sampleBuffer = 0;
|
EGLint sampleBuffer = 0;
|
||||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
|
if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
|
||||||
{
|
{
|
||||||
samples = 4;
|
samples = 4;
|
||||||
sampleBuffer = 1;
|
sampleBuffer = 1;
|
||||||
|
|
@ -1457,7 +1474,7 @@ int InitPlatform(void)
|
||||||
|
|
||||||
// find the EGL config that matches the previously setup GBM format
|
// find the EGL config that matches the previously setup GBM format
|
||||||
int found = 0;
|
int found = 0;
|
||||||
for (EGLint i = 0; i < matchingNumConfigs; i++)
|
for (EGLint i = 0; i < matchingNumConfigs; ++i)
|
||||||
{
|
{
|
||||||
EGLint id = 0;
|
EGLint id = 0;
|
||||||
if (!eglGetConfigAttrib(platform.device, configs[i], EGL_NATIVE_VISUAL_ID, &id))
|
if (!eglGetConfigAttrib(platform.device, configs[i], EGL_NATIVE_VISUAL_ID, &id))
|
||||||
|
|
@ -1562,17 +1579,17 @@ int InitPlatform(void)
|
||||||
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
|
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) MinimizeWindow();
|
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow();
|
||||||
|
|
||||||
// If graphic device is no properly initialized, we end program
|
// If graphic device is no properly initialized, we end program
|
||||||
if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return -1; }
|
if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return -1; }
|
||||||
else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor())/2 - CORE.Window.screen.width/2, GetMonitorHeight(GetCurrentMonitor())/2 - CORE.Window.screen.height/2);
|
else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor())/2 - CORE.Window.screen.width/2, GetMonitorHeight(GetCurrentMonitor())/2 - CORE.Window.screen.height/2);
|
||||||
|
|
||||||
// Set some default window flags
|
// Set some default window flags
|
||||||
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_HIDDEN); // false
|
CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; // false
|
||||||
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // false
|
CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // false
|
||||||
FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED); // true
|
CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // true
|
||||||
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); // false
|
CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // false
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// Initialize timing system
|
// Initialize timing system
|
||||||
|
|
@ -1721,8 +1738,8 @@ static void InitKeyboard(void)
|
||||||
|
|
||||||
// New terminal settings for keyboard: turn off buffering (non-canonical mode), echo and key processing
|
// New terminal settings for keyboard: turn off buffering (non-canonical mode), echo and key processing
|
||||||
// NOTE: ISIG controls if ^C and ^Z generate break signals or not
|
// NOTE: ISIG controls if ^C and ^Z generate break signals or not
|
||||||
FLAG_CLEAR(keyboardNewSettings.c_lflag, ICANON | ECHO | ISIG);
|
keyboardNewSettings.c_lflag &= ~(ICANON | ECHO | ISIG);
|
||||||
//FLAG_CLEAR(keyboardNewSettings.c_iflag, ISTRIP | INLCR | ICRNL | IGNCR | IXON | IXOFF);
|
//keyboardNewSettings.c_iflag &= ~(ISTRIP | INLCR | ICRNL | IGNCR | IXON | IXOFF);
|
||||||
keyboardNewSettings.c_cc[VMIN] = 1;
|
keyboardNewSettings.c_cc[VMIN] = 1;
|
||||||
keyboardNewSettings.c_cc[VTIME] = 0;
|
keyboardNewSettings.c_cc[VTIME] = 0;
|
||||||
|
|
||||||
|
|
@ -1866,7 +1883,7 @@ static void ProcessKeyboard(void)
|
||||||
}
|
}
|
||||||
#endif // SUPPORT_SSH_KEYBOARD_RPI
|
#endif // SUPPORT_SSH_KEYBOARD_RPI
|
||||||
|
|
||||||
// Initialize user input from evdev(/dev/input/event<N>)
|
// Initialise user input from evdev(/dev/input/event<N>)
|
||||||
// this means mouse, keyboard or gamepad devices
|
// this means mouse, keyboard or gamepad devices
|
||||||
static void InitEvdevInput(void)
|
static void InitEvdevInput(void)
|
||||||
{
|
{
|
||||||
|
|
@ -1874,17 +1891,24 @@ static void InitEvdevInput(void)
|
||||||
DIR *directory = NULL;
|
DIR *directory = NULL;
|
||||||
struct dirent *entity = NULL;
|
struct dirent *entity = NULL;
|
||||||
|
|
||||||
// Initialize keyboard file descriptor
|
// Initialise keyboard file descriptor
|
||||||
platform.keyboardFd = -1;
|
platform.keyboardFd = -1;
|
||||||
platform.mouseFd = -1;
|
platform.mouseFd = -1;
|
||||||
|
|
||||||
// Reset variables
|
// Reset variables
|
||||||
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
for (int i = 0; i < MAX_TOUCH_POINTS; ++i)
|
||||||
{
|
{
|
||||||
CORE.Input.Touch.position[i].x = -1;
|
CORE.Input.Touch.position[i].x = -1;
|
||||||
CORE.Input.Touch.position[i].y = -1;
|
CORE.Input.Touch.position[i].y = -1;
|
||||||
|
platform.touchActive[i] = false;
|
||||||
|
platform.touchPosition[i].x = -1;
|
||||||
|
platform.touchPosition[i].y = -1;
|
||||||
|
platform.touchId[i] = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize touch slot
|
||||||
|
platform.touchSlot = 0;
|
||||||
|
|
||||||
// Reset keyboard key state
|
// Reset keyboard key state
|
||||||
for (int i = 0; i < MAX_KEYBOARD_KEYS; i++)
|
for (int i = 0; i < MAX_KEYBOARD_KEYS; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -2047,9 +2071,32 @@ static void ConfigureEvdevDevice(char *device)
|
||||||
const char *deviceKindStr = "unknown";
|
const char *deviceKindStr = "unknown";
|
||||||
if (isMouse || isTouch)
|
if (isMouse || isTouch)
|
||||||
{
|
{
|
||||||
deviceKindStr = "mouse";
|
bool prioritize = false;
|
||||||
if (platform.mouseFd != -1) close(platform.mouseFd);
|
|
||||||
|
// Priority logic: Touchscreens override Mice.
|
||||||
|
// 1. No device set yet? Take it.
|
||||||
|
if (platform.mouseFd == -1) prioritize = true;
|
||||||
|
// 2. Current is Mouse, New is Touch? Upgrade to Touch.
|
||||||
|
else if (isTouch && !platform.mouseIsTouch) prioritize = true;
|
||||||
|
// 3. Current is Touch, New is Touch? Use the new one (Last one found wins, standard behavior).
|
||||||
|
else if (isTouch && platform.mouseIsTouch) prioritize = true;
|
||||||
|
// 4. Current is Mouse, New is Mouse? Use the new one.
|
||||||
|
else if (!isTouch && !platform.mouseIsTouch) prioritize = true;
|
||||||
|
// 5. Current is Touch, New is Mouse? IGNORE the mouse. Keep the touchscreen.
|
||||||
|
else prioritize = false;
|
||||||
|
|
||||||
|
if (prioritize)
|
||||||
|
{
|
||||||
|
deviceKindStr = isTouch ? "touchscreen" : "mouse";
|
||||||
|
|
||||||
|
if (platform.mouseFd != -1)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_INFO, "INPUT: Overwriting previous input device with new %s", deviceKindStr);
|
||||||
|
close(platform.mouseFd);
|
||||||
|
}
|
||||||
|
|
||||||
platform.mouseFd = fd;
|
platform.mouseFd = fd;
|
||||||
|
platform.mouseIsTouch = isTouch;
|
||||||
|
|
||||||
if (absAxisCount > 0)
|
if (absAxisCount > 0)
|
||||||
{
|
{
|
||||||
|
|
@ -2059,6 +2106,15 @@ static void ConfigureEvdevDevice(char *device)
|
||||||
platform.absRange.y = absinfo[ABS_Y].info.minimum;
|
platform.absRange.y = absinfo[ABS_Y].info.minimum;
|
||||||
platform.absRange.height = absinfo[ABS_Y].info.maximum - absinfo[ABS_Y].info.minimum;
|
platform.absRange.height = absinfo[ABS_Y].info.maximum - absinfo[ABS_Y].info.minimum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TRACELOG(LOG_INFO, "INPUT: Initialized input device %s as %s", device, deviceKindStr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_INFO, "INPUT: Ignoring device %s (keeping higher priority %s device)", device, platform.mouseIsTouch ? "touchscreen" : "mouse");
|
||||||
|
close(fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (isGamepad && !isMouse && !isKeyboard && (platform.gamepadCount < MAX_GAMEPADS))
|
else if (isGamepad && !isMouse && !isKeyboard && (platform.gamepadCount < MAX_GAMEPADS))
|
||||||
{
|
{
|
||||||
|
|
@ -2231,6 +2287,7 @@ static void PollMouseEvents(void)
|
||||||
|
|
||||||
struct input_event event = { 0 };
|
struct input_event event = { 0 };
|
||||||
int touchAction = -1; // 0-TOUCH_ACTION_UP, 1-TOUCH_ACTION_DOWN, 2-TOUCH_ACTION_MOVE
|
int touchAction = -1; // 0-TOUCH_ACTION_UP, 1-TOUCH_ACTION_DOWN, 2-TOUCH_ACTION_MOVE
|
||||||
|
static bool isMultitouch = false; // Detect if device supports MT events
|
||||||
|
|
||||||
// Try to read data from the mouse/touch/gesture and only continue if successful
|
// Try to read data from the mouse/touch/gesture and only continue if successful
|
||||||
while (read(fd, &event, sizeof(event)) == (int)sizeof(event))
|
while (read(fd, &event, sizeof(event)) == (int)sizeof(event))
|
||||||
|
|
@ -2276,39 +2333,97 @@ static void PollMouseEvents(void)
|
||||||
if (event.code == ABS_X)
|
if (event.code == ABS_X)
|
||||||
{
|
{
|
||||||
CORE.Input.Mouse.currentPosition.x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange
|
CORE.Input.Mouse.currentPosition.x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange
|
||||||
CORE.Input.Touch.position[0].x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange
|
|
||||||
|
|
||||||
touchAction = 2; // TOUCH_ACTION_MOVE
|
// Update single touch position only if it's active and no MT events are being used
|
||||||
|
if (platform.touchActive[0] && !isMultitouch) {
|
||||||
|
platform.touchPosition[0].x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width;
|
||||||
|
if (touchAction == -1) touchAction = 2; // TOUCH_ACTION_MOVE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.code == ABS_Y)
|
if (event.code == ABS_Y)
|
||||||
{
|
{
|
||||||
CORE.Input.Mouse.currentPosition.y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange
|
CORE.Input.Mouse.currentPosition.y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange
|
||||||
CORE.Input.Touch.position[0].y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange
|
|
||||||
|
|
||||||
touchAction = 2; // TOUCH_ACTION_MOVE
|
// Update single touch position only if it's active and no MT events are being used
|
||||||
|
if (platform.touchActive[0] && !isMultitouch) {
|
||||||
|
platform.touchPosition[0].y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height;
|
||||||
|
if (touchAction == -1) touchAction = 2; // TOUCH_ACTION_MOVE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multitouch movement
|
// Multitouch movement
|
||||||
if (event.code == ABS_MT_SLOT) platform.touchSlot = event.value; // Remember the slot number for the folowing events
|
if (event.code == ABS_MT_SLOT) {
|
||||||
|
platform.touchSlot = event.value;
|
||||||
|
isMultitouch = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (event.code == ABS_MT_POSITION_X)
|
if (event.code == ABS_MT_POSITION_X)
|
||||||
{
|
{
|
||||||
if (platform.touchSlot < MAX_TOUCH_POINTS) CORE.Input.Touch.position[platform.touchSlot].x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange
|
isMultitouch = true;
|
||||||
|
if (platform.touchSlot < MAX_TOUCH_POINTS) {
|
||||||
|
platform.touchPosition[platform.touchSlot].x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width;
|
||||||
|
|
||||||
|
// If this slot is active, it's a move. If not, we are just updating the buffer for when it becomes active.
|
||||||
|
// Only set to MOVE if we haven't already detected a DOWN or UP event this frame
|
||||||
|
if (platform.touchActive[platform.touchSlot] && touchAction == -1) touchAction = 2; // TOUCH_ACTION_MOVE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.code == ABS_MT_POSITION_Y)
|
if (event.code == ABS_MT_POSITION_Y)
|
||||||
{
|
{
|
||||||
if (platform.touchSlot < MAX_TOUCH_POINTS) CORE.Input.Touch.position[platform.touchSlot].y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange
|
if (platform.touchSlot < MAX_TOUCH_POINTS) {
|
||||||
|
platform.touchPosition[platform.touchSlot].y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height;
|
||||||
|
|
||||||
|
// If this slot is active, it's a move. If not, we are just updating the buffer for when it becomes active.
|
||||||
|
// Only set to MOVE if we haven't already detected a DOWN or UP event this frame
|
||||||
|
if (platform.touchActive[platform.touchSlot] && touchAction == -1) touchAction = 2; // TOUCH_ACTION_MOVE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.code == ABS_MT_TRACKING_ID)
|
if (event.code == ABS_MT_TRACKING_ID)
|
||||||
{
|
{
|
||||||
if ((event.value < 0) && (platform.touchSlot < MAX_TOUCH_POINTS))
|
if (platform.touchSlot < MAX_TOUCH_POINTS)
|
||||||
|
{
|
||||||
|
if (event.value >= 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
platform.touchActive[platform.touchSlot] = true;
|
||||||
|
platform.touchId[platform.touchSlot] = event.value; // Use Tracking ID for unique IDs
|
||||||
|
|
||||||
|
touchAction = 1; // TOUCH_ACTION_DOWN
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// Touch has ended for this point
|
// Touch has ended for this point
|
||||||
CORE.Input.Touch.position[platform.touchSlot].x = -1;
|
platform.touchActive[platform.touchSlot] = false;
|
||||||
CORE.Input.Touch.position[platform.touchSlot].y = -1;
|
platform.touchPosition[platform.touchSlot].x = -1;
|
||||||
|
platform.touchPosition[platform.touchSlot].y = -1;
|
||||||
|
platform.touchId[platform.touchSlot] = -1;
|
||||||
|
|
||||||
|
// Force UP action if we haven't already set a DOWN action
|
||||||
|
// (DOWN takes priority over UP if both happen in one frame, though rare)
|
||||||
|
if (touchAction != 1) touchAction = 0; // TOUCH_ACTION_UP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle ABS_MT_PRESSURE (0x3a) if available, as some devices use it for lift-off
|
||||||
|
#ifndef ABS_MT_PRESSURE
|
||||||
|
#define ABS_MT_PRESSURE 0x3a
|
||||||
|
#endif
|
||||||
|
if (event.code == ABS_MT_PRESSURE)
|
||||||
|
{
|
||||||
|
if (platform.touchSlot < MAX_TOUCH_POINTS)
|
||||||
|
{
|
||||||
|
if (event.value <= 0) // Pressure 0 means lift
|
||||||
|
{
|
||||||
|
platform.touchActive[platform.touchSlot] = false;
|
||||||
|
platform.touchPosition[platform.touchSlot].x = -1;
|
||||||
|
platform.touchPosition[platform.touchSlot].y = -1;
|
||||||
|
platform.touchId[platform.touchSlot] = -1;
|
||||||
|
if (touchAction != 1) touchAction = 0; // TOUCH_ACTION_UP
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2320,7 +2435,8 @@ static void PollMouseEvents(void)
|
||||||
if (!event.value && previousMouseLeftButtonState)
|
if (!event.value && previousMouseLeftButtonState)
|
||||||
{
|
{
|
||||||
platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 0;
|
platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 0;
|
||||||
touchAction = 0; // TOUCH_ACTION_UP
|
|
||||||
|
if (touchAction != 1) touchAction = 0; // TOUCH_ACTION_UP
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.value && !previousMouseLeftButtonState)
|
if (event.value && !previousMouseLeftButtonState)
|
||||||
|
|
@ -2340,8 +2456,46 @@ static void PollMouseEvents(void)
|
||||||
{
|
{
|
||||||
platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = event.value;
|
platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = event.value;
|
||||||
|
|
||||||
if (event.value > 0) touchAction = 1; // TOUCH_ACTION_DOWN
|
if (event.value > 0)
|
||||||
else touchAction = 0; // TOUCH_ACTION_UP
|
{
|
||||||
|
bool activateSlot0 = false;
|
||||||
|
|
||||||
|
if (event.code == BTN_LEFT)
|
||||||
|
{
|
||||||
|
activateSlot0 = true; // Mouse click always activates
|
||||||
|
}
|
||||||
|
else if (event.code == BTN_TOUCH)
|
||||||
|
{
|
||||||
|
bool anyActive = false;
|
||||||
|
for (int i = 0; i < MAX_TOUCH_POINTS; i++) {
|
||||||
|
if (platform.touchActive[i]) { anyActive = true; break; }
|
||||||
|
}
|
||||||
|
if (!anyActive) activateSlot0 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activateSlot0)
|
||||||
|
{
|
||||||
|
platform.touchActive[0] = true;
|
||||||
|
platform.touchId[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
touchAction = 1; // TOUCH_ACTION_DOWN
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Only clear touch 0 for actual mouse clicks (BTN_LEFT)
|
||||||
|
if (event.code == BTN_LEFT)
|
||||||
|
{
|
||||||
|
platform.touchActive[0] = false;
|
||||||
|
platform.touchPosition[0].x = -1;
|
||||||
|
platform.touchPosition[0].y = -1;
|
||||||
|
}
|
||||||
|
else if (event.code == BTN_TOUCH)
|
||||||
|
{
|
||||||
|
platform.touchSlot = 0; // Reset slot index to 0
|
||||||
|
}
|
||||||
|
touchAction = 0; // TOUCH_ACTION_UP
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.code == BTN_RIGHT) platform.currentButtonStateEvdev[MOUSE_BUTTON_RIGHT] = event.value;
|
if (event.code == BTN_RIGHT) platform.currentButtonStateEvdev[MOUSE_BUTTON_RIGHT] = event.value;
|
||||||
|
|
@ -2362,11 +2516,32 @@ static void PollMouseEvents(void)
|
||||||
if (CORE.Input.Mouse.currentPosition.y > CORE.Window.screen.height/CORE.Input.Mouse.scale.y) CORE.Input.Mouse.currentPosition.y = CORE.Window.screen.height/CORE.Input.Mouse.scale.y;
|
if (CORE.Input.Mouse.currentPosition.y > CORE.Window.screen.height/CORE.Input.Mouse.scale.y) CORE.Input.Mouse.currentPosition.y = CORE.Window.screen.height/CORE.Input.Mouse.scale.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update touch point count
|
// Repack active touches into CORE.Input.Touch
|
||||||
CORE.Input.Touch.pointCount = 0;
|
int k = 0;
|
||||||
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
||||||
{
|
{
|
||||||
if (CORE.Input.Touch.position[i].x >= 0) CORE.Input.Touch.pointCount++;
|
if (platform.touchActive[i])
|
||||||
|
{
|
||||||
|
CORE.Input.Touch.position[k] = platform.touchPosition[i];
|
||||||
|
CORE.Input.Touch.pointId[k] = platform.touchId[i];
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CORE.Input.Touch.pointCount = k;
|
||||||
|
|
||||||
|
// Clear remaining slots
|
||||||
|
for (int i = k; i < MAX_TOUCH_POINTS; i++)
|
||||||
|
{
|
||||||
|
CORE.Input.Touch.position[i].x = -1;
|
||||||
|
CORE.Input.Touch.position[i].y = -1;
|
||||||
|
CORE.Input.Touch.pointId[i] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug logging
|
||||||
|
static int lastTouchCount = 0;
|
||||||
|
if (CORE.Input.Touch.pointCount != lastTouchCount && (touchAction == 0 || touchAction == 1)) {
|
||||||
|
TRACELOG(LOG_DEBUG, "TOUCH: Count changed from %d to %d (action: %d)", lastTouchCount, CORE.Input.Touch.pointCount, touchAction);
|
||||||
|
lastTouchCount = CORE.Input.Touch.pointCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(SUPPORT_GESTURES_SYSTEM)
|
#if defined(SUPPORT_GESTURES_SYSTEM)
|
||||||
|
|
@ -2403,7 +2578,7 @@ static int FindMatchingConnectorMode(const drmModeConnector *connector, const dr
|
||||||
for (size_t i = 0; i < connector->count_modes; i++)
|
for (size_t i = 0; i < connector->count_modes; i++)
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode: %d %ux%u@%u %s", i, connector->modes[i].hdisplay, connector->modes[i].vdisplay,
|
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode: %d %ux%u@%u %s", i, connector->modes[i].hdisplay, connector->modes[i].vdisplay,
|
||||||
connector->modes[i].vrefresh, (FLAG_IS_SET(connector->modes[i].flags, DRM_MODE_FLAG_INTERLACE) > 0)? "interlaced" : "progressive");
|
connector->modes[i].vrefresh, (connector->modes[i].flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive");
|
||||||
|
|
||||||
if (0 == BINCMP(&platform.crtc->mode, &platform.connector->modes[i])) return i;
|
if (0 == BINCMP(&platform.crtc->mode, &platform.connector->modes[i])) return i;
|
||||||
}
|
}
|
||||||
|
|
@ -2424,9 +2599,9 @@ static int FindExactConnectorMode(const drmModeConnector *connector, uint width,
|
||||||
{
|
{
|
||||||
const drmModeModeInfo *const mode = &platform.connector->modes[i];
|
const drmModeModeInfo *const mode = &platform.connector->modes[i];
|
||||||
|
|
||||||
TRACELOG(LOG_TRACE, "DISPLAY: DRM Mode %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh, (FLAG_IS_SET(mode->flags, DRM_MODE_FLAG_INTERLACE) > 0)? "interlaced" : "progressive");
|
TRACELOG(LOG_TRACE, "DISPLAY: DRM Mode %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh, (mode->flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive");
|
||||||
|
|
||||||
if ((FLAG_IS_SET(mode->flags, DRM_MODE_FLAG_INTERLACE) > 0) && !allowInterlaced) continue;
|
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && !allowInterlaced) continue;
|
||||||
|
|
||||||
if ((mode->hdisplay == width) && (mode->vdisplay == height) && (mode->vrefresh == fps)) return i;
|
if ((mode->hdisplay == width) && (mode->vdisplay == height) && (mode->vrefresh == fps)) return i;
|
||||||
}
|
}
|
||||||
|
|
@ -2450,7 +2625,7 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
|
||||||
const drmModeModeInfo *const mode = &platform.connector->modes[i];
|
const drmModeModeInfo *const mode = &platform.connector->modes[i];
|
||||||
|
|
||||||
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode: %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh,
|
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode: %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh,
|
||||||
(FLAG_IS_SET(mode->flags, DRM_MODE_FLAG_INTERLACE) > 0)? "interlaced" : "progressive");
|
(mode->flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive");
|
||||||
|
|
||||||
if ((mode->hdisplay < width) || (mode->vdisplay < height))
|
if ((mode->hdisplay < width) || (mode->vdisplay < height))
|
||||||
{
|
{
|
||||||
|
|
@ -2458,13 +2633,13 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((FLAG_IS_SET(mode->flags, DRM_MODE_FLAG_INTERLACE) > 0) && !allowInterlaced)
|
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && !allowInterlaced)
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_TRACE, "DISPLAY: DRM shouldn't choose an interlaced mode");
|
TRACELOG(LOG_TRACE, "DISPLAY: DRM shouldn't choose an interlaced mode");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int unusedPixels = (mode->hdisplay - width)*(mode->vdisplay - height);
|
const int unusedPixels = (mode->hdisplay - width) * (mode->vdisplay - height);
|
||||||
const int fpsDiff = mode->vrefresh - fps;
|
const int fpsDiff = mode->vrefresh - fps;
|
||||||
|
|
||||||
if ((unusedPixels < minUnusedPixels) ||
|
if ((unusedPixels < minUnusedPixels) ||
|
||||||
|
|
@ -2480,82 +2655,4 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
|
||||||
return nearestIndex;
|
return nearestIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute framebuffer size relative to screen size and display size
|
|
||||||
// NOTE: Global variables CORE.Window.render.width/CORE.Window.render.height and CORE.Window.renderOffset.x/CORE.Window.renderOffset.y can be modified
|
|
||||||
static void SetupFramebuffer(int width, int height)
|
|
||||||
{
|
|
||||||
// Calculate CORE.Window.render.width and CORE.Window.render.height, we have the display size (input params) and the desired screen size (global var)
|
|
||||||
if ((CORE.Window.screen.width > CORE.Window.display.width) || (CORE.Window.screen.height > CORE.Window.display.height))
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_WARNING, "DISPLAY: Downscaling required: Screen size (%ix%i) is bigger than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height);
|
|
||||||
|
|
||||||
// Downscaling to fit display with border-bars
|
|
||||||
float widthRatio = (float)CORE.Window.display.width/(float)CORE.Window.screen.width;
|
|
||||||
float heightRatio = (float)CORE.Window.display.height/(float)CORE.Window.screen.height;
|
|
||||||
|
|
||||||
if (widthRatio <= heightRatio)
|
|
||||||
{
|
|
||||||
CORE.Window.render.width = CORE.Window.display.width;
|
|
||||||
CORE.Window.render.height = (int)round((float)CORE.Window.screen.height*widthRatio);
|
|
||||||
CORE.Window.renderOffset.x = 0;
|
|
||||||
CORE.Window.renderOffset.y = (CORE.Window.display.height - CORE.Window.render.height);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CORE.Window.render.width = (int)round((float)CORE.Window.screen.width*heightRatio);
|
|
||||||
CORE.Window.render.height = CORE.Window.display.height;
|
|
||||||
CORE.Window.renderOffset.x = (CORE.Window.display.width - CORE.Window.render.width);
|
|
||||||
CORE.Window.renderOffset.y = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Screen scaling required
|
|
||||||
float scaleRatio = (float)CORE.Window.render.width/(float)CORE.Window.screen.width;
|
|
||||||
CORE.Window.screenScale = MatrixScale(scaleRatio, scaleRatio, 1.0f);
|
|
||||||
|
|
||||||
// NOTE: We render to full display resolution!
|
|
||||||
// We just need to calculate above parameters for downscale matrix and offsets
|
|
||||||
CORE.Window.render.width = CORE.Window.display.width;
|
|
||||||
CORE.Window.render.height = CORE.Window.display.height;
|
|
||||||
|
|
||||||
TRACELOG(LOG_WARNING, "DISPLAY: Downscale matrix generated, content will be rendered at (%ix%i)", CORE.Window.render.width, CORE.Window.render.height);
|
|
||||||
}
|
|
||||||
else if ((CORE.Window.screen.width < CORE.Window.display.width) || (CORE.Window.screen.height < CORE.Window.display.height))
|
|
||||||
{
|
|
||||||
// Required screen size is smaller than display size
|
|
||||||
TRACELOG(LOG_INFO, "DISPLAY: Upscaling required: Screen size (%ix%i) smaller than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height);
|
|
||||||
|
|
||||||
if ((CORE.Window.screen.width == 0) || (CORE.Window.screen.height == 0))
|
|
||||||
{
|
|
||||||
CORE.Window.screen.width = CORE.Window.display.width;
|
|
||||||
CORE.Window.screen.height = CORE.Window.display.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upscaling to fit display with border-bars
|
|
||||||
float displayRatio = (float)CORE.Window.display.width/(float)CORE.Window.display.height;
|
|
||||||
float screenRatio = (float)CORE.Window.screen.width/(float)CORE.Window.screen.height;
|
|
||||||
|
|
||||||
if (displayRatio <= screenRatio)
|
|
||||||
{
|
|
||||||
CORE.Window.render.width = CORE.Window.screen.width;
|
|
||||||
CORE.Window.render.height = (int)round((float)CORE.Window.screen.width/displayRatio);
|
|
||||||
CORE.Window.renderOffset.x = 0;
|
|
||||||
CORE.Window.renderOffset.y = (CORE.Window.render.height - CORE.Window.screen.height);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CORE.Window.render.width = (int)round((float)CORE.Window.screen.height*displayRatio);
|
|
||||||
CORE.Window.render.height = CORE.Window.screen.height;
|
|
||||||
CORE.Window.renderOffset.x = (CORE.Window.render.width - CORE.Window.screen.width);
|
|
||||||
CORE.Window.renderOffset.y = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CORE.Window.render.width = CORE.Window.screen.width;
|
|
||||||
CORE.Window.render.height = CORE.Window.screen.height;
|
|
||||||
CORE.Window.renderOffset.x = 0;
|
|
||||||
CORE.Window.renderOffset.y = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// EOF
|
// EOF
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user