From d445fdaa199eae6540621b5a35f2d498f5ffab5c Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 9 Oct 2023 00:41:06 +0200 Subject: [PATCH] WARNING: REDESIGN: Move platform specific data to platform submodules #3313 REVIEWED: Defines, macros, types and tweaks --- src/rcore.c | 70 +++----- src/rcore.h | 149 +++-------------- src/rcore_android.c | 156 +++++++++-------- src/rcore_desktop.c | 189 +++++++++++---------- src/rcore_drm.c | 398 ++++++++++++++++++++++++++------------------ src/rcore_web.c | 75 +++++---- src/utils.h | 2 +- 7 files changed, 519 insertions(+), 520 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index ff7558dc3..f28aff74f 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1,33 +1,18 @@ /********************************************************************************************** * -* rcore - Basic functions to manage windows, OpenGL context and input on multiple platforms +* rcore - Window/display management, Graphic device/context management and input management * * PLATFORMS SUPPORTED: * - PLATFORM_DESKTOP: Windows (Win32, Win64) * - PLATFORM_DESKTOP: Linux (X11 desktop mode) * - PLATFORM_DESKTOP: FreeBSD, OpenBSD, NetBSD, DragonFly (X11 desktop) * - PLATFORM_DESKTOP: OSX/macOS +* - PLATFORM_WEB: HTML5 (WebAssembly) +* - PLATFORM_DRM: Raspberry Pi 0-5 +* - PLATFORM_DRM: Linux native mode (KMS driver) * - PLATFORM_ANDROID: Android (ARM, ARM64) -* - PLATFORM_DRM: Linux native mode, including Raspberry Pi 4 with V3D fkms driver -* - PLATFORM_WEB: HTML5 with WebAssembly * * CONFIGURATION: -* #define PLATFORM_DESKTOP -* Windowing and input system configured for desktop platforms: -* Windows, Linux, OSX, FreeBSD, OpenBSD, NetBSD, DragonFly -* -* #define PLATFORM_ANDROID -* Windowing and input system configured for Android device, app activity managed internally in this module. -* NOTE: OpenGL ES 2.0 is required and graphic device is managed by EGL -* -* #define PLATFORM_DRM -* Windowing and input system configured for DRM native mode (RPI4 and other devices) -* graphic device is managed by EGL and inputs are processed is raw mode, reading from /dev/input/ -* -* #define PLATFORM_WEB -* Windowing and input system configured for HTML5 (run on browser), code converted from C to asm.js -* using emscripten compiler. OpenGL ES 2.0 required for direct translation to WebGL equivalent code. -* * #define SUPPORT_DEFAULT_FONT (default) * Default font is loaded on window initialization to be available for the user to render simple text. * NOTE: If enabled, uses external module functions to load default raylib font (module: text) @@ -42,11 +27,6 @@ * #define SUPPORT_MOUSE_GESTURES * Mouse gestures are directly mapped like touches and processed by gestures system. * -* #define SUPPORT_SSH_KEYBOARD_RPI (Raspberry Pi only) -* 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. -* * #define SUPPORT_BUSY_WAIT_LOOP * Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used * @@ -68,7 +48,6 @@ * Support automatic generated events, loading and recording of those events when required * * DEPENDENCIES: -* rglfw - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX, FreeBSD...) * raymath - 3D math functionality (Vector2, Vector3, Matrix, Quaternion) * camera - Multiple 3D camera modes (free, orbital, 1st person, 3rd person) * gestures - Gestures system for touch-ready devices (or simulated from mouse inputs) @@ -76,7 +55,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5) and contributors * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -102,7 +81,7 @@ #include "config.h" // Defines module configuration flags #endif -#include "rcore.h" +#include "rcore.h" // Defines types and globals #define RLGL_IMPLEMENTATION #include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2 @@ -142,21 +121,19 @@ #endif // Platform specific defines to handle GetApplicationDirectory() -#if defined (PLATFORM_DESKTOP) - #if defined(_WIN32) - #ifndef MAX_PATH - #define MAX_PATH 1025 - #endif - __declspec(dllimport) unsigned long __stdcall GetModuleFileNameA(void *hModule, void *lpFilename, unsigned long nSize); - __declspec(dllimport) unsigned long __stdcall GetModuleFileNameW(void *hModule, void *lpFilename, unsigned long nSize); - __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, void *widestr, int cchwide, void *str, int cbmb, void *defchar, int *used_default); - #elif defined(__linux__) - #include - #elif defined(__APPLE__) - #include - #include - #endif // OSs -#endif // PLATFORM_DESKTOP +#if defined(_WIN32) + #ifndef MAX_PATH + #define MAX_PATH 1025 + #endif +__declspec(dllimport) unsigned long __stdcall GetModuleFileNameA(void *hModule, void *lpFilename, unsigned long nSize); +__declspec(dllimport) unsigned long __stdcall GetModuleFileNameW(void *hModule, void *lpFilename, unsigned long nSize); +__declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, void *widestr, int cchwide, void *str, int cbmb, void *defchar, int *used_default); +#elif defined(__linux__) + #include +#elif defined(__APPLE__) + #include + #include +#endif // OSs #define _CRT_INTERNAL_NONSTDC_NAMES 1 #include // Required for: stat(), S_ISREG [Used in GetFileModTime(), IsFilePath()] @@ -165,7 +142,7 @@ #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #endif -#if defined(PLATFORM_DESKTOP) && defined(_WIN32) && (defined(_MSC_VER) || defined(__TINYC__)) +#if defined(_WIN32) && (defined(_MSC_VER) || defined(__TINYC__)) #define DIRENT_MALLOC RL_MALLOC #define DIRENT_FREE RL_FREE @@ -333,7 +310,8 @@ const char *TextFormat(const char *text, ...); // Formatting of text with #elif defined(PLATFORM_ANDROID) #include "rcore_android.c" #else - // Software rendering backend, user needs to provide buffer ;) + // TODO: Include your custom platform backend! + // i.e software rendering backend or console backend! #endif //---------------------------------------------------------------------------------- @@ -1897,7 +1875,7 @@ bool IsKeyPressed(int key) return pressed; } -// Check if a key has been pressed again (only PLATFORM_DESKTOP) +// Check if a key has been pressed again bool IsKeyPressedRepeat(int key) { bool repeat = false; @@ -2291,7 +2269,7 @@ void InitTimer(void) timeBeginPeriod(1); // Setup high-resolution timer to 1ms (granularity of 1-2 ms) #endif -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_DRM) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__) struct timespec now = { 0 }; if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) // Success diff --git a/src/rcore.h b/src/rcore.h index 5d9e3bd74..132c8e007 100644 --- a/src/rcore.h +++ b/src/rcore.h @@ -35,64 +35,6 @@ #ifndef RCORE_H #define RCORE_H -#include // Required for: srand(), rand(), atexit() -#include // Required for: sprintf() [Used in OpenURL()] -#include // Required for: strrchr(), strcmp(), strlen(), memset() -#include // Required for: time() [Used in InitTimer()] -#include // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()] - -#include "utils.h" // Required for: TRACELOG() macros - -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - #define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3 - // NOTE: Already provided by rlgl implementation (on glad.h) - #include "GLFW/glfw3.h" // GLFW3 library: Windows, OpenGL context and Input management - // NOTE: GLFW3 already includes gl.h (OpenGL) headers -#endif - -#if defined(PLATFORM_ANDROID) - #include // Native platform windowing system interface - //#include // OpenGL ES 2.0 library (not required in this module, only in rlgl) -#endif - -#if defined(PLATFORM_DRM) - - #include // POSIX file control definitions - open(), creat(), fcntl() - #include // POSIX standard function definitions - read(), close(), STDIN_FILENO - #include // POSIX terminal control definitions - tcgetattr(), tcsetattr() - #include // POSIX threads management (inputs reading) - #include // POSIX directory browsing - - #include // Required for: ioctl() - UNIX System call for device-specific input/output operations - #include // Linux: KDSKBMODE, K_MEDIUMRAM constants definition - #include // Linux: Keycodes constants definition (KEY_A, ...) - #include // Linux: Joystick support library - - #include // Generic Buffer Management (native platform for EGL on DRM) - #include // Direct Rendering Manager user-level library interface - #include // Direct Rendering Manager mode setting (KMS) interface - - #include "EGL/egl.h" // Native platform windowing system interface - #include "EGL/eglext.h" // EGL extensions - - typedef struct - { - pthread_t threadId; // Event reading thread id - int fd; // File descriptor to the device it is assigned to - int eventNum; // Number of 'event' device - Rectangle absRange; // Range of values for absolute pointing devices (touchscreens) - int touchSlot; // Hold the touch slot number of the currently being sent multitouch block - bool isMouse; // True if device supports relative X Y movements - bool isTouch; // True if device supports absolute X Y movements and has BTN_TOUCH - bool isMultitouch; // True if device supports multiple absolute movevents and has BTN_TOUCH - bool isKeyboard; // True if device has letter keycodes - bool isGamepad; // True if device has gamepad buttons - } InputEventWorker; - -#endif - -// TODO: PROVIDE A HEADER TO BE USED BY ALL THE rcore_* IMPLEMENTATIONS - #include "raylib.h" #include "rlgl.h" @@ -100,16 +42,17 @@ #define RAYMATH_IMPLEMENTATION #include "raymath.h" +#include "utils.h" // Required for: TRACELOG() macros + +#include // Required for: srand(), rand(), atexit() +#include // Required for: sprintf() [Used in OpenURL()] +#include // Required for: strrchr(), strcmp(), strlen(), memset() +#include // Required for: time() [Used in InitTimer()] +#include // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()] + //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#if defined(PLATFORM_DRM) - #define USE_LAST_TOUCH_DEVICE // When multiple touchscreens are connected, only use the one with the highest event number - - #define DEFAULT_GAMEPAD_DEV "/dev/input/js" // Gamepad input (base dev for all gamepads: js0, js1, ...) - #define DEFAULT_EVDEV_PATH "/dev/input/" // Path to the linux input events -#endif - #ifndef MAX_FILEPATH_CAPACITY #define MAX_FILEPATH_CAPACITY 8192 // Maximum capacity for filepath #endif @@ -152,12 +95,6 @@ #define FLAG_TOGGLE(n, f) ((n) ^= (f)) #define FLAG_CHECK(n, f) ((n) & (f)) -// TODO: HACK: Added flag if not provided by GLFW when using external library -// Latest GLFW release (GLFW 3.3.8) does not implement this flag, it was added for 3.4.0-dev -#if !defined(GLFW_MOUSE_PASSTHROUGH) - #define GLFW_MOUSE_PASSTHROUGH 0x0002000D -#endif - #if (defined(__linux__) || defined(PLATFORM_WEB)) && (_POSIX_C_SOURCE < 199309L) #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 199309L // Required for: CLOCK_MONOTONIC if compiled with c99 without gnu ext. @@ -172,25 +109,6 @@ typedef struct { unsigned int width; unsigned int height; } Size; // Core global state context data typedef struct CoreData { struct { -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - GLFWwindow *handle; // GLFW window handle (graphic device) -#endif -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_DRM) -#if defined(PLATFORM_DRM) - int fd; // File descriptor for /dev/dri/... - drmModeConnector *connector; // Direct Rendering Manager (DRM) mode connector - drmModeCrtc *crtc; // CRT Controller - int modeIndex; // Index of the used mode of connector->modes - struct gbm_device *gbmDevice; // GBM device - struct gbm_surface *gbmSurface; // GBM surface - struct gbm_bo *prevBO; // Previous GBM buffer object (during frame swapping) - uint32_t prevFB; // Previous GBM framebufer (during frame swapping) -#endif // PLATFORM_DRM - EGLDisplay device; // Native display device (physical screen connection) - EGLSurface surface; // Surface to draw on, framebuffers (connected to context) - EGLContext context; // Graphic context, mode in which drawing can be done - EGLConfig config; // Graphic config -#endif const char *title; // Window text title const pointer unsigned int flags; // Configuration flags (bit based), keeps window state bool ready; // Check if window has been initialized successfully @@ -215,45 +133,27 @@ typedef struct CoreData { char **dropFilepaths; // Store dropped files paths pointers (provided by GLFW) unsigned int dropFileCount; // Count dropped files strings - + } Window; -#if defined(PLATFORM_ANDROID) - struct { - bool appEnabled; // Flag to detect if app is active ** = true - struct android_app *app; // Android activity - struct android_poll_source *source; // Android events polling source - bool contextRebindRequired; // Used to know context rebind required - } Android; -#endif struct { const char *basePath; // Base path for data storage + } Storage; struct { -#if defined(PLATFORM_DRM) - InputEventWorker eventWorker[10]; // List of worker threads for every monitored "/dev/input/event" -#endif struct { int exitKey; // Default exit key - char currentKeyState[MAX_KEYBOARD_KEYS]; // Registers current frame key state - char previousKeyState[MAX_KEYBOARD_KEYS]; // Registers previous frame key state + char currentKeyState[MAX_KEYBOARD_KEYS]; // Registers current frame key state + char previousKeyState[MAX_KEYBOARD_KEYS]; // Registers previous frame key state + // NOTE: Since key press logic involves comparing prev vs cur key state, we need to handle key repeats specially - char keyRepeatInFrame[MAX_KEYBOARD_KEYS]; // Registers key repeats for current frame. + char keyRepeatInFrame[MAX_KEYBOARD_KEYS]; // Registers key repeats for current frame. - int keyPressedQueue[MAX_KEY_PRESSED_QUEUE]; // Input keys queue + int keyPressedQueue[MAX_KEY_PRESSED_QUEUE]; // Input keys queue int keyPressedQueueCount; // Input keys queue count - int charPressedQueue[MAX_CHAR_PRESSED_QUEUE]; // Input characters queue (unicode) + int charPressedQueue[MAX_CHAR_PRESSED_QUEUE]; // Input characters queue (unicode) int charPressedQueueCount; // Input characters queue count -#if defined(PLATFORM_DRM) - int defaultMode; // Default keyboard mode -#if defined(SUPPORT_SSH_KEYBOARD_RPI) - bool evtMode; // Keyboard in event mode -#endif - int defaultFileFlags; // Default IO file flags - struct termios defaultSettings; // Default keyboard settings - int fd; // File descriptor for the evdev keyboard -#endif } Keyboard; struct { Vector2 offset; // Mouse offset @@ -269,11 +169,7 @@ typedef struct CoreData { char previousButtonState[MAX_MOUSE_BUTTONS]; // Registers previous mouse button state Vector2 currentWheelMove; // Registers current mouse wheel variation Vector2 previousWheelMove; // Registers previous mouse wheel variation -#if defined(PLATFORM_DRM) - Vector2 eventWheelMove; // Registers the event mouse wheel variation - // NOTE: currentButtonState[] can't be written directly due to multithreading, app could miss the update - char currentButtonStateEvdev[MAX_MOUSE_BUTTONS]; // Holds the new mouse state for the next polling event to grab -#endif + } Mouse; struct { int pointCount; // Number of touch points active @@ -281,6 +177,7 @@ typedef struct CoreData { Vector2 position[MAX_TOUCH_POINTS]; // Touch position on screen char currentTouchState[MAX_TOUCH_POINTS]; // Registers current touch state char previousTouchState[MAX_TOUCH_POINTS]; // Registers previous touch state + } Touch; struct { int lastButtonPressed; // Register last gamepad button pressed @@ -290,10 +187,7 @@ typedef struct CoreData { char currentButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Current gamepad buttons state char previousButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Previous gamepad buttons state float axisState[MAX_GAMEPADS][MAX_GAMEPAD_AXIS]; // Gamepad axis state -#if defined(PLATFORM_DRM) - pthread_t threadId; // Gamepad reading thread id - int streamId[MAX_GAMEPADS]; // Gamepad device file descriptor -#endif + } Gamepad; } Input; struct { @@ -303,10 +197,9 @@ typedef struct CoreData { double draw; // Time measure for frame draw double frame; // Time measure for one frame double target; // Desired time for one frame, if 0 not applied -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_DRM) - unsigned long long int base; // Base time measure for hi-res timer -#endif + unsigned long long int base; // Base time measure for hi-res timer (PLATFORM_ANDROID, PLATFORM_DRM) unsigned int frameCounter; // Frame counter + } Time; } CoreData; diff --git a/src/rcore_android.c b/src/rcore_android.c index 61d729a1c..ad7a905c1 100644 --- a/src/rcore_android.c +++ b/src/rcore_android.c @@ -53,15 +53,31 @@ #include // Required for: android_app struct and activity management #include // Required for: JNIEnv and JavaVM [Used in OpenURL()] +#include // Native platform windowing system interface + //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -//... +typedef struct { + // Application data + struct android_app *app; // Android activity + struct android_poll_source *source; // Android events polling source + bool appEnabled; // Flag to detect if app is active ** = true + bool contextRebindRequired; // Used to know context rebind required + + // Display data + EGLDisplay device; // Native display device (physical screen connection) + EGLSurface surface; // Surface to draw on, framebuffers (connected to context) + EGLContext context; // Graphic context, mode in which drawing can be done + EGLConfig config; // Graphic config +} PlatformData; //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -extern CoreData CORE; // Global CORE state context +extern CoreData CORE; // Global CORE state context + +static PlatformData platform = { 0 }; // Platform specific data //---------------------------------------------------------------------------------- // Module Internal Functions Declaration @@ -89,7 +105,7 @@ extern int main(int argc, char *argv[]); void android_main(struct android_app *app) { char arg0[] = "raylib"; // NOTE: argv[] are mutable - CORE.Android.app = app; + platform.app = app; // NOTE: Return from main is ignored (void)main(1, (char *[]) { arg0, NULL }); @@ -104,9 +120,9 @@ void android_main(struct android_app *app) // Waiting for application events before complete finishing while (!app->destroyRequested) { - while ((pollResult = ALooper_pollAll(0, NULL, &pollEvents, (void **)&CORE.Android.source)) >= 0) + while ((pollResult = ALooper_pollAll(0, NULL, &pollEvents, (void **)&platform.source)) >= 0) { - if (CORE.Android.source != NULL) CORE.Android.source->process(app, CORE.Android.source); + if (platform.source != NULL) platform.source->process(app, platform.source); } } } @@ -114,7 +130,7 @@ void android_main(struct android_app *app) // NOTE: Add this to header (if apps really need it) struct android_app *GetAndroidApp(void) { - return CORE.Android.app; + return platform.app; } // Initialize window and OpenGL context @@ -169,9 +185,9 @@ void InitWindow(int width, int height, const char *title) CORE.Window.currentFbo.height = height; // Set desired windows flags before initializing anything - ANativeActivity_setWindowFlags(CORE.Android.app->activity, AWINDOW_FLAG_FULLSCREEN, 0); //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER + ANativeActivity_setWindowFlags(platform.app->activity, AWINDOW_FLAG_FULLSCREEN, 0); //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER - int orientation = AConfiguration_getOrientation(CORE.Android.app->config); + int orientation = AConfiguration_getOrientation(platform.app->config); if (orientation == ACONFIGURATION_ORIENTATION_PORT) TRACELOG(LOG_INFO, "ANDROID: Window orientation set as portrait"); else if (orientation == ACONFIGURATION_ORIENTATION_LAND) TRACELOG(LOG_INFO, "ANDROID: Window orientation set as landscape"); @@ -179,32 +195,32 @@ void InitWindow(int width, int height, const char *title) // TODO: Automatic orientation doesn't seem to work if (width <= height) { - AConfiguration_setOrientation(CORE.Android.app->config, ACONFIGURATION_ORIENTATION_PORT); + AConfiguration_setOrientation(platform.app->config, ACONFIGURATION_ORIENTATION_PORT); TRACELOG(LOG_WARNING, "ANDROID: Window orientation changed to portrait"); } else { - AConfiguration_setOrientation(CORE.Android.app->config, ACONFIGURATION_ORIENTATION_LAND); + AConfiguration_setOrientation(platform.app->config, ACONFIGURATION_ORIENTATION_LAND); TRACELOG(LOG_WARNING, "ANDROID: Window orientation changed to landscape"); } - //AConfiguration_getDensity(CORE.Android.app->config); - //AConfiguration_getKeyboard(CORE.Android.app->config); - //AConfiguration_getScreenSize(CORE.Android.app->config); - //AConfiguration_getScreenLong(CORE.Android.app->config); + //AConfiguration_getDensity(platform.app->config); + //AConfiguration_getKeyboard(platform.app->config); + //AConfiguration_getScreenSize(platform.app->config); + //AConfiguration_getScreenLong(platform.app->config); // Initialize App command system // NOTE: On APP_CMD_INIT_WINDOW -> InitGraphicsDevice(), InitTimer(), LoadFontDefault()... - CORE.Android.app->onAppCmd = AndroidCommandCallback; + platform.app->onAppCmd = AndroidCommandCallback; // Initialize input events system - CORE.Android.app->onInputEvent = AndroidInputCallback; + platform.app->onInputEvent = AndroidInputCallback; // Initialize assets manager - InitAssetManager(CORE.Android.app->activity->assetManager, CORE.Android.app->activity->internalDataPath); + InitAssetManager(platform.app->activity->assetManager, platform.app->activity->internalDataPath); // Initialize base path for storage - CORE.Storage.basePath = CORE.Android.app->activity->internalDataPath; + CORE.Storage.basePath = platform.app->activity->internalDataPath; TRACELOG(LOG_INFO, "ANDROID: App initialized successfully"); @@ -216,13 +232,13 @@ void InitWindow(int width, int height, const char *title) while (!CORE.Window.ready) { // Process events loop - while ((pollResult = ALooper_pollAll(0, NULL, &pollEvents, (void**)&CORE.Android.source)) >= 0) + while ((pollResult = ALooper_pollAll(0, NULL, &pollEvents, (void**)&platform.source)) >= 0) { // Process this event - if (CORE.Android.source != NULL) CORE.Android.source->process(CORE.Android.app, CORE.Android.source); + if (platform.source != NULL) platform.source->process(platform.app, platform.source); // NOTE: Never close window, native activity is controlled by the system! - //if (CORE.Android.app->destroyRequested != 0) CORE.Window.shouldClose = true; + //if (platform.app->destroyRequested != 0) CORE.Window.shouldClose = true; } } } @@ -250,24 +266,24 @@ void CloseWindow(void) #endif // Close surface, context and display - if (CORE.Window.device != EGL_NO_DISPLAY) + if (platform.device != EGL_NO_DISPLAY) { - eglMakeCurrent(CORE.Window.device, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglMakeCurrent(platform.device, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (CORE.Window.surface != EGL_NO_SURFACE) + if (platform.surface != EGL_NO_SURFACE) { - eglDestroySurface(CORE.Window.device, CORE.Window.surface); - CORE.Window.surface = EGL_NO_SURFACE; + eglDestroySurface(platform.device, platform.surface); + platform.surface = EGL_NO_SURFACE; } - if (CORE.Window.context != EGL_NO_CONTEXT) + if (platform.context != EGL_NO_CONTEXT) { - eglDestroyContext(CORE.Window.device, CORE.Window.context); - CORE.Window.context = EGL_NO_CONTEXT; + eglDestroyContext(platform.device, platform.context); + platform.context = EGL_NO_CONTEXT; } - eglTerminate(CORE.Window.device); - CORE.Window.device = EGL_NO_DISPLAY; + eglTerminate(platform.device); + platform.device = EGL_NO_DISPLAY; } #if defined(SUPPORT_EVENTS_AUTOMATION) @@ -306,7 +322,7 @@ bool IsWindowMaximized(void) // Check if window has the focus bool IsWindowFocused(void) { - return CORE.Android.appEnabled; + return platform.appEnabled; } // Check if window has been resizedLastFrame @@ -595,7 +611,7 @@ void OpenURL(const char *url) else { JNIEnv *env = NULL; - JavaVM *vm = CORE.Android.app->activity->vm; + JavaVM *vm = platform.app->activity->vm; (*vm)->AttachCurrentThread(vm, &env, NULL); jstring urlString = (*env)->NewStringUTF(env, url); @@ -612,7 +628,7 @@ void OpenURL(const char *url) (*env)->CallVoidMethod(env, intent, newIntent, actionView, uri); jclass activityClass = (*env)->FindClass(env, "android/app/Activity"); jmethodID startActivity = (*env)->GetMethodID(env, activityClass, "startActivity", "(Landroid/content/Intent;)V"); - (*env)->CallVoidMethod(env, CORE.Android.app->activity->clazz, startActivity, intent); + (*env)->CallVoidMethod(env, platform.app->activity->clazz, startActivity, intent); (*vm)->DetachCurrentThread(vm); } @@ -713,7 +729,7 @@ Vector2 GetTouchPosition(int index) // Swap back buffer with front buffer (screen drawing) void SwapScreenBuffer(void) { - eglSwapBuffers(CORE.Window.device, CORE.Window.surface); + eglSwapBuffers(platform.device, platform.surface); } // Register all input events @@ -756,17 +772,17 @@ void PollInputEvents(void) int pollEvents = 0; // Poll Events (registered events) - // NOTE: Activity is paused if not enabled (CORE.Android.appEnabled) - while ((pollResult = ALooper_pollAll(CORE.Android.appEnabled? 0 : -1, NULL, &pollEvents, (void**)&CORE.Android.source)) >= 0) + // NOTE: Activity is paused if not enabled (platform.appEnabled) + while ((pollResult = ALooper_pollAll(platform.appEnabled? 0 : -1, NULL, &pollEvents, (void**)&platform.source)) >= 0) { // Process this event - if (CORE.Android.source != NULL) CORE.Android.source->process(CORE.Android.app, CORE.Android.source); + if (platform.source != NULL) platform.source->process(platform.app, platform.source); // NOTE: Never close window, native activity is controlled by the system! - if (CORE.Android.app->destroyRequested != 0) + if (platform.app->destroyRequested != 0) { //CORE.Window.shouldClose = true; - //ANativeActivity_finish(CORE.Android.app->activity); + //ANativeActivity_finish(platform.app->activity); } } } @@ -829,15 +845,15 @@ static bool InitGraphicsDevice(int width, int height) EGLint numConfigs = 0; // Get an EGL device connection - CORE.Window.device = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (CORE.Window.device == EGL_NO_DISPLAY) + platform.device = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (platform.device == EGL_NO_DISPLAY) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device"); return false; } // Initialize the EGL device connection - if (eglInitialize(CORE.Window.device, NULL, NULL) == EGL_FALSE) + if (eglInitialize(platform.device, NULL, NULL) == EGL_FALSE) { // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred. TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device"); @@ -845,14 +861,14 @@ static bool InitGraphicsDevice(int width, int height) } // Get an appropriate EGL framebuffer configuration - eglChooseConfig(CORE.Window.device, framebufferAttribs, &CORE.Window.config, 1, &numConfigs); + eglChooseConfig(platform.device, framebufferAttribs, &platform.config, 1, &numConfigs); // Set rendering API eglBindAPI(EGL_OPENGL_ES_API); // Create an EGL rendering context - CORE.Window.context = eglCreateContext(CORE.Window.device, CORE.Window.config, EGL_NO_CONTEXT, contextAttribs); - if (CORE.Window.context == EGL_NO_CONTEXT) + platform.context = eglCreateContext(platform.device, platform.config, EGL_NO_CONTEXT, contextAttribs); + if (platform.context == EGL_NO_CONTEXT) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL context"); return false; @@ -864,7 +880,7 @@ static bool InitGraphicsDevice(int width, int height) // EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is guaranteed to be accepted by ANativeWindow_setBuffersGeometry() // As soon as we picked a EGLConfig, we can safely reconfigure the ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID - eglGetConfigAttrib(CORE.Window.device, CORE.Window.config, EGL_NATIVE_VISUAL_ID, &displayFormat); + eglGetConfigAttrib(platform.device, platform.config, EGL_NATIVE_VISUAL_ID, &displayFormat); // At this point we need to manage render size vs screen size // NOTE: This function use and modify global module variables: @@ -873,15 +889,15 @@ static bool InitGraphicsDevice(int width, int height) // -> CORE.Window.screenScale SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); - ANativeWindow_setBuffersGeometry(CORE.Android.app->window, CORE.Window.render.width, CORE.Window.render.height, displayFormat); - //ANativeWindow_setBuffersGeometry(CORE.Android.app->window, 0, 0, displayFormat); // Force use of native display size + ANativeWindow_setBuffersGeometry(platform.app->window, CORE.Window.render.width, CORE.Window.render.height, displayFormat); + //ANativeWindow_setBuffersGeometry(platform.app->window, 0, 0, displayFormat); // Force use of native display size - CORE.Window.surface = eglCreateWindowSurface(CORE.Window.device, CORE.Window.config, CORE.Android.app->window, NULL); + platform.surface = eglCreateWindowSurface(platform.device, platform.config, platform.app->window, NULL); // There must be at least one frame displayed before the buffers are swapped - //eglSwapInterval(CORE.Window.device, 1); + //eglSwapInterval(platform.device, 1); - if (eglMakeCurrent(CORE.Window.device, CORE.Window.surface, CORE.Window.surface, CORE.Window.context) == EGL_FALSE) + if (eglMakeCurrent(platform.device, platform.surface, platform.surface, platform.context) == EGL_FALSE) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to attach EGL rendering context to EGL surface"); return false; @@ -933,11 +949,11 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) { if (app->window != NULL) { - if (CORE.Android.contextRebindRequired) + if (platform.contextRebindRequired) { // Reset screen scaling to full display size EGLint displayFormat = 0; - eglGetConfigAttrib(CORE.Window.device, CORE.Window.config, EGL_NATIVE_VISUAL_ID, &displayFormat); + eglGetConfigAttrib(platform.device, platform.config, EGL_NATIVE_VISUAL_ID, &displayFormat); // Adding renderOffset here feels rather hackish, but the viewport scaling is wrong after the // context rebinding if the screen is scaled unless offsets are added. There's probably a more @@ -948,15 +964,15 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) displayFormat); // Recreate display surface and re-attach OpenGL context - CORE.Window.surface = eglCreateWindowSurface(CORE.Window.device, CORE.Window.config, app->window, NULL); - eglMakeCurrent(CORE.Window.device, CORE.Window.surface, CORE.Window.surface, CORE.Window.context); + platform.surface = eglCreateWindowSurface(platform.device, platform.config, app->window, NULL); + eglMakeCurrent(platform.device, platform.surface, platform.surface, platform.context); - CORE.Android.contextRebindRequired = false; + platform.contextRebindRequired = false; } else { - CORE.Window.display.width = ANativeWindow_getWidth(CORE.Android.app->window); - CORE.Window.display.height = ANativeWindow_getHeight(CORE.Android.app->window); + CORE.Window.display.width = ANativeWindow_getWidth(platform.app->window); + CORE.Window.display.height = ANativeWindow_getHeight(platform.app->window); // Initialize graphics device (display device and OpenGL context) InitGraphicsDevice(CORE.Window.screen.width, CORE.Window.screen.height); @@ -997,13 +1013,13 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) } break; case APP_CMD_GAINED_FOCUS: { - CORE.Android.appEnabled = true; + platform.appEnabled = true; //ResumeMusicStream(); } break; case APP_CMD_PAUSE: break; case APP_CMD_LOST_FOCUS: { - CORE.Android.appEnabled = false; + platform.appEnabled = false; //PauseMusicStream(); } break; case APP_CMD_TERM_WINDOW: @@ -1012,19 +1028,19 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) // NOTE 1: This case is used when the user exits the app without closing it. We detach the context to ensure everything is recoverable upon resuming. // NOTE 2: Detaching context before destroying display surface avoids losing our resources (textures, shaders, VBOs...) // NOTE 3: In some cases (too many context loaded), OS could unload context automatically... :( - if (CORE.Window.device != EGL_NO_DISPLAY) + if (platform.device != EGL_NO_DISPLAY) { - eglMakeCurrent(CORE.Window.device, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglMakeCurrent(platform.device, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (CORE.Window.surface != EGL_NO_SURFACE) + if (platform.surface != EGL_NO_SURFACE) { - eglDestroySurface(CORE.Window.device, CORE.Window.surface); - CORE.Window.surface = EGL_NO_SURFACE; + eglDestroySurface(platform.device, platform.surface); + platform.surface = EGL_NO_SURFACE; } - CORE.Android.contextRebindRequired = true; + platform.contextRebindRequired = true; } - // If 'CORE.Window.device' is already set to 'EGL_NO_DISPLAY' + // If 'platform.device' is already set to 'EGL_NO_DISPLAY' // this means that the user has already called 'CloseWindow()' } break; @@ -1033,8 +1049,8 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) case APP_CMD_DESTROY: break; case APP_CMD_CONFIG_CHANGED: { - //AConfiguration_fromAssetManager(CORE.Android.app->config, CORE.Android.app->activity->assetManager); - //print_cur_config(CORE.Android.app); + //AConfiguration_fromAssetManager(platform.app->config, platform.app->activity->assetManager); + //print_cur_config(platform.app); // Check screen orientation here! } break; diff --git a/src/rcore_desktop.c b/src/rcore_desktop.c index f8c6b0e2c..33a4aab0e 100644 --- a/src/rcore_desktop.c +++ b/src/rcore_desktop.c @@ -85,15 +85,28 @@ #include "GLFW/glfw3native.h" // Required for: glfwGetCocoaWindow() #endif +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +// TODO: HACK: Added flag if not provided by GLFW when using external library +// Latest GLFW release (GLFW 3.3.8) does not implement this flag, it was added for 3.4.0-dev +#if !defined(GLFW_MOUSE_PASSTHROUGH) + #define GLFW_MOUSE_PASSTHROUGH 0x0002000D +#endif + //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -//... +typedef struct { + GLFWwindow *handle; // GLFW window handle (graphic device) +} PlatformData; //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -extern CoreData CORE; // Global CORE state context +extern CoreData CORE; // Global CORE state context + +static PlatformData platform = { 0 }; // Platform specific data //---------------------------------------------------------------------------------- // Module Internal Functions Declaration @@ -255,7 +268,7 @@ void CloseWindow(void) rlglClose(); // De-init rlgl - glfwDestroyWindow(CORE.Window.handle); + glfwDestroyWindow(platform.handle); glfwTerminate(); #if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP) @@ -279,10 +292,10 @@ bool WindowShouldClose(void) // While window minimized, stop loop execution while (IsWindowState(FLAG_WINDOW_MINIMIZED) && !IsWindowState(FLAG_WINDOW_ALWAYS_RUN)) glfwWaitEvents(); - CORE.Window.shouldClose = glfwWindowShouldClose(CORE.Window.handle); + CORE.Window.shouldClose = glfwWindowShouldClose(platform.handle); // Reset close status for next frame - glfwSetWindowShouldClose(CORE.Window.handle, GLFW_FALSE); + glfwSetWindowShouldClose(platform.handle, GLFW_FALSE); return CORE.Window.shouldClose; } @@ -325,7 +338,7 @@ void ToggleFullscreen(void) if (!CORE.Window.fullscreen) { // Store previous window position (in case we exit fullscreen) - glfwGetWindowPos(CORE.Window.handle, &CORE.Window.position.x, &CORE.Window.position.y); + glfwGetWindowPos(platform.handle, &CORE.Window.position.x, &CORE.Window.position.y); int monitorCount = 0; int monitorIndex = GetCurrentMonitor(); @@ -341,14 +354,14 @@ void ToggleFullscreen(void) CORE.Window.fullscreen = false; CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE; - glfwSetWindowMonitor(CORE.Window.handle, NULL, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); + glfwSetWindowMonitor(platform.handle, NULL, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); } else { CORE.Window.fullscreen = true; CORE.Window.flags |= FLAG_FULLSCREEN_MODE; - glfwSetWindowMonitor(CORE.Window.handle, monitor, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); + glfwSetWindowMonitor(platform.handle, monitor, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); } } @@ -357,7 +370,7 @@ void ToggleFullscreen(void) CORE.Window.fullscreen = false; CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE; - glfwSetWindowMonitor(CORE.Window.handle, NULL, CORE.Window.position.x, CORE.Window.position.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); + glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.position.x, CORE.Window.position.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); } // Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS) @@ -368,9 +381,9 @@ void ToggleFullscreen(void) // Set window state: maximized, if resizable void MaximizeWindow(void) { - if (glfwGetWindowAttrib(CORE.Window.handle, GLFW_RESIZABLE) == GLFW_TRUE) + if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) { - glfwMaximizeWindow(CORE.Window.handle); + glfwMaximizeWindow(platform.handle); CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; } } @@ -379,16 +392,16 @@ void MaximizeWindow(void) void MinimizeWindow(void) { // NOTE: Following function launches callback that sets appropriate flag! - glfwIconifyWindow(CORE.Window.handle); + glfwIconifyWindow(platform.handle); } // Set window state: not minimized/maximized void RestoreWindow(void) { - if (glfwGetWindowAttrib(CORE.Window.handle, GLFW_RESIZABLE) == GLFW_TRUE) + if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) { // Restores the specified window if it was previously iconified (minimized) or maximized - glfwRestoreWindow(CORE.Window.handle); + glfwRestoreWindow(platform.handle); CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED; } @@ -420,13 +433,13 @@ void ToggleBorderlessWindowed(void) { // Store screen position and size // NOTE: If it was on fullscreen, screen position was already stored, so skip setting it here - if (!wasOnFullscreen) glfwGetWindowPos(CORE.Window.handle, &CORE.Window.previousPosition.x, &CORE.Window.previousPosition.y); + if (!wasOnFullscreen) glfwGetWindowPos(platform.handle, &CORE.Window.previousPosition.x, &CORE.Window.previousPosition.y); CORE.Window.previousScreen = CORE.Window.screen; // Set undecorated and topmost modes and flags - glfwSetWindowAttrib(CORE.Window.handle, GLFW_DECORATED, GLFW_FALSE); + glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_FALSE); CORE.Window.flags |= FLAG_WINDOW_UNDECORATED; - glfwSetWindowAttrib(CORE.Window.handle, GLFW_FLOATING, GLFW_TRUE); + glfwSetWindowAttrib(platform.handle, GLFW_FLOATING, GLFW_TRUE); CORE.Window.flags |= FLAG_WINDOW_TOPMOST; // Get monitor position and size @@ -437,29 +450,29 @@ void ToggleBorderlessWindowed(void) const int monitorHeight = mode->height; // Set screen position and size - glfwSetWindowPos(CORE.Window.handle, monitorPosX, monitorPosY); - glfwSetWindowSize(CORE.Window.handle, monitorWidth, monitorHeight); + glfwSetWindowPos(platform.handle, monitorPosX, monitorPosY); + glfwSetWindowSize(platform.handle, monitorWidth, monitorHeight); // Refocus window - glfwFocusWindow(CORE.Window.handle); + glfwFocusWindow(platform.handle); CORE.Window.flags |= FLAG_BORDERLESS_WINDOWED_MODE; } else { // Remove topmost and undecorated modes and flags - glfwSetWindowAttrib(CORE.Window.handle, GLFW_FLOATING, GLFW_FALSE); + glfwSetWindowAttrib(platform.handle, GLFW_FLOATING, GLFW_FALSE); CORE.Window.flags &= ~FLAG_WINDOW_TOPMOST; - glfwSetWindowAttrib(CORE.Window.handle, GLFW_DECORATED, GLFW_TRUE); + glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE); CORE.Window.flags &= ~FLAG_WINDOW_UNDECORATED; // Return previous screen size and position // NOTE: The order matters here, it must set size first, then set position, otherwise the screen will be positioned incorrectly - glfwSetWindowSize(CORE.Window.handle, CORE.Window.previousScreen.width, CORE.Window.previousScreen.height); - glfwSetWindowPos(CORE.Window.handle, CORE.Window.previousPosition.x, CORE.Window.previousPosition.y); + glfwSetWindowSize(platform.handle, CORE.Window.previousScreen.width, CORE.Window.previousScreen.height); + glfwSetWindowPos(platform.handle, CORE.Window.previousPosition.x, CORE.Window.previousPosition.y); // Refocus window - glfwFocusWindow(CORE.Window.handle); + glfwFocusWindow(platform.handle); CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE; } @@ -498,21 +511,21 @@ void SetWindowState(unsigned int flags) // State change: FLAG_WINDOW_RESIZABLE if (((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) != (flags & FLAG_WINDOW_RESIZABLE)) && ((flags & FLAG_WINDOW_RESIZABLE) > 0)) { - glfwSetWindowAttrib(CORE.Window.handle, GLFW_RESIZABLE, GLFW_TRUE); + glfwSetWindowAttrib(platform.handle, GLFW_RESIZABLE, GLFW_TRUE); CORE.Window.flags |= FLAG_WINDOW_RESIZABLE; } // State change: FLAG_WINDOW_UNDECORATED if (((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) != (flags & FLAG_WINDOW_UNDECORATED)) && (flags & FLAG_WINDOW_UNDECORATED)) { - glfwSetWindowAttrib(CORE.Window.handle, GLFW_DECORATED, GLFW_FALSE); + glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_FALSE); CORE.Window.flags |= FLAG_WINDOW_UNDECORATED; } // State change: FLAG_WINDOW_HIDDEN if (((CORE.Window.flags & FLAG_WINDOW_HIDDEN) != (flags & FLAG_WINDOW_HIDDEN)) && ((flags & FLAG_WINDOW_HIDDEN) > 0)) { - glfwHideWindow(CORE.Window.handle); + glfwHideWindow(platform.handle); CORE.Window.flags |= FLAG_WINDOW_HIDDEN; } @@ -533,14 +546,14 @@ void SetWindowState(unsigned int flags) // State change: FLAG_WINDOW_UNFOCUSED if (((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) != (flags & FLAG_WINDOW_UNFOCUSED)) && ((flags & FLAG_WINDOW_UNFOCUSED) > 0)) { - glfwSetWindowAttrib(CORE.Window.handle, GLFW_FOCUS_ON_SHOW, GLFW_FALSE); + glfwSetWindowAttrib(platform.handle, GLFW_FOCUS_ON_SHOW, GLFW_FALSE); CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED; } // State change: FLAG_WINDOW_TOPMOST if (((CORE.Window.flags & FLAG_WINDOW_TOPMOST) != (flags & FLAG_WINDOW_TOPMOST)) && ((flags & FLAG_WINDOW_TOPMOST) > 0)) { - glfwSetWindowAttrib(CORE.Window.handle, GLFW_FLOATING, GLFW_TRUE); + glfwSetWindowAttrib(platform.handle, GLFW_FLOATING, GLFW_TRUE); CORE.Window.flags |= FLAG_WINDOW_TOPMOST; } @@ -567,7 +580,7 @@ void SetWindowState(unsigned int flags) // State change: FLAG_WINDOW_MOUSE_PASSTHROUGH if (((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) != (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH)) && ((flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0)) { - glfwSetWindowAttrib(CORE.Window.handle, GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE); + glfwSetWindowAttrib(platform.handle, GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE); CORE.Window.flags |= FLAG_WINDOW_MOUSE_PASSTHROUGH; } @@ -613,14 +626,14 @@ void ClearWindowState(unsigned int flags) // State change: FLAG_WINDOW_RESIZABLE if (((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) && ((flags & FLAG_WINDOW_RESIZABLE) > 0)) { - glfwSetWindowAttrib(CORE.Window.handle, GLFW_RESIZABLE, GLFW_FALSE); + glfwSetWindowAttrib(platform.handle, GLFW_RESIZABLE, GLFW_FALSE); CORE.Window.flags &= ~FLAG_WINDOW_RESIZABLE; } // State change: FLAG_WINDOW_HIDDEN if (((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) && ((flags & FLAG_WINDOW_HIDDEN) > 0)) { - glfwShowWindow(CORE.Window.handle); + glfwShowWindow(platform.handle); CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; } @@ -639,21 +652,21 @@ void ClearWindowState(unsigned int flags) // State change: FLAG_WINDOW_UNDECORATED if (((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) && ((flags & FLAG_WINDOW_UNDECORATED) > 0)) { - glfwSetWindowAttrib(CORE.Window.handle, GLFW_DECORATED, GLFW_TRUE); + glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE); CORE.Window.flags &= ~FLAG_WINDOW_UNDECORATED; } // State change: FLAG_WINDOW_UNFOCUSED if (((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0) && ((flags & FLAG_WINDOW_UNFOCUSED) > 0)) { - glfwSetWindowAttrib(CORE.Window.handle, GLFW_FOCUS_ON_SHOW, GLFW_TRUE); + glfwSetWindowAttrib(platform.handle, GLFW_FOCUS_ON_SHOW, GLFW_TRUE); CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; } // State change: FLAG_WINDOW_TOPMOST if (((CORE.Window.flags & FLAG_WINDOW_TOPMOST) > 0) && ((flags & FLAG_WINDOW_TOPMOST) > 0)) { - glfwSetWindowAttrib(CORE.Window.handle, GLFW_FLOATING, GLFW_FALSE); + glfwSetWindowAttrib(platform.handle, GLFW_FLOATING, GLFW_FALSE); CORE.Window.flags &= ~FLAG_WINDOW_TOPMOST; } @@ -680,7 +693,7 @@ void ClearWindowState(unsigned int flags) // State change: FLAG_WINDOW_MOUSE_PASSTHROUGH if (((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0) && ((flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0)) { - glfwSetWindowAttrib(CORE.Window.handle, GLFW_MOUSE_PASSTHROUGH, GLFW_FALSE); + glfwSetWindowAttrib(platform.handle, GLFW_MOUSE_PASSTHROUGH, GLFW_FALSE); CORE.Window.flags &= ~FLAG_WINDOW_MOUSE_PASSTHROUGH; } @@ -705,7 +718,7 @@ void SetWindowIcon(Image image) if (image.data == NULL) { // Revert to the default window icon, pass in an empty image array - glfwSetWindowIcon(CORE.Window.handle, 0, NULL); + glfwSetWindowIcon(platform.handle, 0, NULL); } else { @@ -719,7 +732,7 @@ void SetWindowIcon(Image image) // NOTE 1: We only support one image icon // NOTE 2: The specified image data is copied before this function returns - glfwSetWindowIcon(CORE.Window.handle, 1, icon); + glfwSetWindowIcon(platform.handle, 1, icon); } else TRACELOG(LOG_WARNING, "GLFW: Window icon image must be in R8G8B8A8 pixel format"); } @@ -734,7 +747,7 @@ void SetWindowIcons(Image *images, int count) if ((images == NULL) || (count <= 0)) { // Revert to the default window icon, pass in an empty image array - glfwSetWindowIcon(CORE.Window.handle, 0, NULL); + glfwSetWindowIcon(platform.handle, 0, NULL); } else { @@ -754,7 +767,7 @@ void SetWindowIcons(Image *images, int count) else TRACELOG(LOG_WARNING, "GLFW: Window icon image must be in R8G8B8A8 pixel format"); } // NOTE: Images data is copied internally before this function returns - glfwSetWindowIcon(CORE.Window.handle, valid, icons); + glfwSetWindowIcon(platform.handle, valid, icons); RL_FREE(icons); } @@ -764,13 +777,13 @@ void SetWindowIcons(Image *images, int count) void SetWindowTitle(const char *title) { CORE.Window.title = title; - glfwSetWindowTitle(CORE.Window.handle, title); + glfwSetWindowTitle(platform.handle, title); } // Set window position on screen (windowed mode) void SetWindowPosition(int x, int y) { - glfwSetWindowPos(CORE.Window.handle, x, y); + glfwSetWindowPos(platform.handle, x, y); } // Set monitor for the current window @@ -786,7 +799,7 @@ void SetWindowMonitor(int monitor) TRACELOG(LOG_INFO, "GLFW: Selected fullscreen monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor])); const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]); - glfwSetWindowMonitor(CORE.Window.handle, monitors[monitor], 0, 0, mode->width, mode->height, mode->refreshRate); + glfwSetWindowMonitor(platform.handle, monitors[monitor], 0, 0, mode->width, mode->height, mode->refreshRate); } else { @@ -801,12 +814,12 @@ void SetWindowMonitor(int monitor) glfwGetMonitorWorkarea(monitors[monitor], &monitorWorkareaX, &monitorWorkareaY, &monitorWorkareaWidth, &monitorWorkareaHeight); // If the screen size is larger than the monitor workarea, anchor it on the top left corner, otherwise, center it - if ((screenWidth >= monitorWorkareaWidth) || (screenHeight >= monitorWorkareaHeight)) glfwSetWindowPos(CORE.Window.handle, monitorWorkareaX, monitorWorkareaY); + if ((screenWidth >= monitorWorkareaWidth) || (screenHeight >= monitorWorkareaHeight)) glfwSetWindowPos(platform.handle, monitorWorkareaX, monitorWorkareaY); else { const int x = monitorWorkareaX + (monitorWorkareaWidth/2) - (screenWidth/2); const int y = monitorWorkareaY + (monitorWorkareaHeight/2) - (screenHeight/2); - glfwSetWindowPos(CORE.Window.handle, x, y); + glfwSetWindowPos(platform.handle, x, y); } } } @@ -822,7 +835,7 @@ void SetWindowMinSize(int width, int height) int minHeight = (CORE.Window.screenMin.height == 0)? GLFW_DONT_CARE : CORE.Window.screenMin.height; int maxWidth = (CORE.Window.screenMax.width == 0)? GLFW_DONT_CARE : CORE.Window.screenMax.width; int maxHeight = (CORE.Window.screenMax.height == 0)? GLFW_DONT_CARE : CORE.Window.screenMax.height; - glfwSetWindowSizeLimits(CORE.Window.handle, minWidth, minHeight, maxWidth, maxHeight); + glfwSetWindowSizeLimits(platform.handle, minWidth, minHeight, maxWidth, maxHeight); } // Set window maximum dimensions (FLAG_WINDOW_RESIZABLE) @@ -834,13 +847,13 @@ void SetWindowMaxSize(int width, int height) int minHeight = (CORE.Window.screenMin.height == 0)? GLFW_DONT_CARE : CORE.Window.screenMin.height; int maxWidth = (CORE.Window.screenMax.width == 0)? GLFW_DONT_CARE : CORE.Window.screenMax.width; int maxHeight = (CORE.Window.screenMax.height == 0)? GLFW_DONT_CARE : CORE.Window.screenMax.height; - glfwSetWindowSizeLimits(CORE.Window.handle, minWidth, minHeight, maxWidth, maxHeight); + glfwSetWindowSizeLimits(platform.handle, minWidth, minHeight, maxWidth, maxHeight); } // Set window dimensions void SetWindowSize(int width, int height) { - glfwSetWindowSize(CORE.Window.handle, width, height); + glfwSetWindowSize(platform.handle, width, height); } // Set window opacity, value opacity is between 0.0 and 1.0 @@ -848,13 +861,13 @@ void SetWindowOpacity(float opacity) { if (opacity >= 1.0f) opacity = 1.0f; else if (opacity <= 0.0f) opacity = 0.0f; - glfwSetWindowOpacity(CORE.Window.handle, opacity); + glfwSetWindowOpacity(platform.handle, opacity); } // Set window focused void SetWindowFocused(void) { - glfwFocusWindow(CORE.Window.handle); + glfwFocusWindow(platform.handle); } // Get native window handle @@ -862,19 +875,19 @@ void *GetWindowHandle(void) { #if defined(_WIN32) // NOTE: Returned handle is: void *HWND (windows.h) - return glfwGetWin32Window(CORE.Window.handle); + 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(CORE.Window.handle); + //unsigned long id = (unsigned long)glfwGetX11Window(platform.handle); //return NULL; // TODO: Find a way to return value... cast to void *? - return (void *)CORE.Window.handle; + return (void *)platform.handle; #endif #if defined(__APPLE__) // NOTE: Returned handle is: (objc_object *) - return (void *)glfwGetCocoaWindow(CORE.Window.handle); + return (void *)glfwGetCocoaWindow(platform.handle); #endif return NULL; @@ -903,7 +916,7 @@ int GetCurrentMonitor(void) if (IsWindowFullscreen()) { // Get the handle of the monitor that the specified window is in full screen on - monitor = glfwGetWindowMonitor(CORE.Window.handle); + monitor = glfwGetWindowMonitor(platform.handle); for (int i = 0; i < monitorCount; i++) { @@ -919,7 +932,7 @@ int GetCurrentMonitor(void) int x = 0; int y = 0; - glfwGetWindowPos(CORE.Window.handle, &x, &y); + glfwGetWindowPos(platform.handle, &x, &y); for (int i = 0; i < monitorCount; i++) { @@ -1070,7 +1083,7 @@ Vector2 GetWindowPosition(void) int x = 0; int y = 0; - glfwGetWindowPos(CORE.Window.handle, &x, &y); + glfwGetWindowPos(platform.handle, &x, &y); return (Vector2){ (float)x, (float)y }; } @@ -1109,34 +1122,34 @@ Vector2 GetWindowScaleDPI(void) // Set clipboard text content void SetClipboardText(const char *text) { - glfwSetClipboardString(CORE.Window.handle, text); + glfwSetClipboardString(platform.handle, text); } // Get clipboard text content // NOTE: returned string is allocated and freed by GLFW const char *GetClipboardText(void) { - return glfwGetClipboardString(CORE.Window.handle); + return glfwGetClipboardString(platform.handle); } // Show mouse cursor void ShowCursor(void) { - glfwSetInputMode(CORE.Window.handle, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_NORMAL); CORE.Input.Mouse.cursorHidden = false; } // Hides mouse cursor void HideCursor(void) { - glfwSetInputMode(CORE.Window.handle, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); CORE.Input.Mouse.cursorHidden = true; } // Enables cursor (unlock cursor) void EnableCursor(void) { - glfwSetInputMode(CORE.Window.handle, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_NORMAL); // Set cursor position in the middle SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); @@ -1147,7 +1160,7 @@ void EnableCursor(void) // Disables cursor (lock cursor) void DisableCursor(void) { - glfwSetInputMode(CORE.Window.handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED); // Set cursor position in the middle SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); @@ -1276,7 +1289,7 @@ void SetMousePosition(int x, int y) CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; // NOTE: emscripten not implemented - glfwSetCursorPos(CORE.Window.handle, CORE.Input.Mouse.currentPosition.x, CORE.Input.Mouse.currentPosition.y); + glfwSetCursorPos(platform.handle, CORE.Input.Mouse.currentPosition.x, CORE.Input.Mouse.currentPosition.y); } // Get mouse wheel movement Y @@ -1294,11 +1307,11 @@ float GetMouseWheelMove(void) void SetMouseCursor(int cursor) { CORE.Input.Mouse.cursor = cursor; - if (cursor == MOUSE_CURSOR_DEFAULT) glfwSetCursor(CORE.Window.handle, NULL); + if (cursor == MOUSE_CURSOR_DEFAULT) glfwSetCursor(platform.handle, NULL); else { // NOTE: We are relating internal GLFW enum values to our MouseCursor enum values - glfwSetCursor(CORE.Window.handle, glfwCreateStandardCursor(0x00036000 + cursor)); + glfwSetCursor(platform.handle, glfwCreateStandardCursor(0x00036000 + cursor)); } } @@ -1331,7 +1344,7 @@ Vector2 GetTouchPosition(int index) // Swap back buffer with front buffer (screen drawing) void SwapScreenBuffer(void) { - glfwSwapBuffers(CORE.Window.handle); + glfwSwapBuffers(platform.handle); } // Register all input events @@ -1691,10 +1704,10 @@ static bool InitGraphicsDevice(int width, int height) // HighDPI monitors are properly considered in a following similar function: SetupViewport() SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); - CORE.Window.handle = glfwCreateWindow(CORE.Window.display.width, CORE.Window.display.height, (CORE.Window.title != 0)? CORE.Window.title : " ", glfwGetPrimaryMonitor(), NULL); + platform.handle = glfwCreateWindow(CORE.Window.display.width, CORE.Window.display.height, (CORE.Window.title != 0)? CORE.Window.title : " ", glfwGetPrimaryMonitor(), NULL); // NOTE: Full-screen change, not working properly... - //glfwSetWindowMonitor(CORE.Window.handle, glfwGetPrimaryMonitor(), 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); + //glfwSetWindowMonitor(platform.handle, glfwGetPrimaryMonitor(), 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); } else { @@ -1705,16 +1718,16 @@ static bool InitGraphicsDevice(int width, int height) } // No-fullscreen window creation - CORE.Window.handle = glfwCreateWindow(CORE.Window.screen.width, CORE.Window.screen.height, (CORE.Window.title != 0)? CORE.Window.title : " ", NULL, NULL); + platform.handle = glfwCreateWindow(CORE.Window.screen.width, CORE.Window.screen.height, (CORE.Window.title != 0)? CORE.Window.title : " ", NULL, NULL); - if (CORE.Window.handle) + if (platform.handle) { CORE.Window.render.width = CORE.Window.screen.width; CORE.Window.render.height = CORE.Window.screen.height; } } - if (!CORE.Window.handle) + if (!platform.handle) { glfwTerminate(); TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window"); @@ -1722,23 +1735,23 @@ static bool InitGraphicsDevice(int width, int height) } // Set window callback events - glfwSetWindowSizeCallback(CORE.Window.handle, WindowSizeCallback); // NOTE: Resizing not allowed by default! - glfwSetWindowMaximizeCallback(CORE.Window.handle, WindowMaximizeCallback); - glfwSetWindowIconifyCallback(CORE.Window.handle, WindowIconifyCallback); - glfwSetWindowFocusCallback(CORE.Window.handle, WindowFocusCallback); - glfwSetDropCallback(CORE.Window.handle, WindowDropCallback); + glfwSetWindowSizeCallback(platform.handle, WindowSizeCallback); // NOTE: Resizing not allowed by default! + glfwSetWindowMaximizeCallback(platform.handle, WindowMaximizeCallback); + glfwSetWindowIconifyCallback(platform.handle, WindowIconifyCallback); + glfwSetWindowFocusCallback(platform.handle, WindowFocusCallback); + glfwSetDropCallback(platform.handle, WindowDropCallback); // Set input callback events - glfwSetKeyCallback(CORE.Window.handle, KeyCallback); - glfwSetCharCallback(CORE.Window.handle, CharCallback); - glfwSetMouseButtonCallback(CORE.Window.handle, MouseButtonCallback); - glfwSetCursorPosCallback(CORE.Window.handle, MouseCursorPosCallback); // Track mouse position changes - glfwSetScrollCallback(CORE.Window.handle, MouseScrollCallback); - glfwSetCursorEnterCallback(CORE.Window.handle, CursorEnterCallback); + glfwSetKeyCallback(platform.handle, KeyCallback); + glfwSetCharCallback(platform.handle, CharCallback); + glfwSetMouseButtonCallback(platform.handle, MouseButtonCallback); + glfwSetCursorPosCallback(platform.handle, MouseCursorPosCallback); // Track mouse position changes + glfwSetScrollCallback(platform.handle, MouseScrollCallback); + glfwSetCursorEnterCallback(platform.handle, CursorEnterCallback); - glfwMakeContextCurrent(CORE.Window.handle); + glfwMakeContextCurrent(platform.handle); - glfwSetInputMode(CORE.Window.handle, GLFW_LOCK_KEY_MODS, GLFW_TRUE); // Enable lock keys modifiers (CAPS, NUM) + glfwSetInputMode(platform.handle, GLFW_LOCK_KEY_MODS, GLFW_TRUE); // Enable lock keys modifiers (CAPS, NUM) glfwSwapInterval(0); // No V-Sync by default @@ -1760,7 +1773,7 @@ static bool InitGraphicsDevice(int width, int height) // NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling. // Framebuffer scaling should be activated with: glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE); #if !defined(__APPLE__) - glfwGetFramebufferSize(CORE.Window.handle, &fbWidth, &fbHeight); + glfwGetFramebufferSize(platform.handle, &fbWidth, &fbHeight); // Screen scaling matrix is required in case desired screen area is different from display area CORE.Window.screenScale = MatrixScale((float)fbWidth/CORE.Window.screen.width, (float)fbHeight/CORE.Window.screen.height, 1.0f); @@ -1913,7 +1926,7 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i } // Check the exit key to set close window - if ((key == CORE.Input.Keyboard.exitKey) && (action == GLFW_PRESS)) glfwSetWindowShouldClose(CORE.Window.handle, GLFW_TRUE); + if ((key == CORE.Input.Keyboard.exitKey) && (action == GLFW_PRESS)) glfwSetWindowShouldClose(platform.handle, GLFW_TRUE); #if defined(SUPPORT_SCREEN_CAPTURE) if ((key == GLFW_KEY_F12) && (action == GLFW_PRESS)) diff --git a/src/rcore_drm.c b/src/rcore_drm.c index 2c05ab46e..8c63b63da 100644 --- a/src/rcore_drm.c +++ b/src/rcore_drm.c @@ -17,8 +17,10 @@ * - TRACELOG() function is located in raylib [utils] module * * CONFIGURATION: -* #define RCORE_DRM_CUSTOM_FLAG -* Custom flag for rcore on PLATFORM_DRM -not used- +* #define SUPPORT_SSH_KEYBOARD_RPI (Raspberry Pi only) +* 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. * * DEPENDENCIES: * gestures - Gestures system for touch-ready devices (or simulated from mouse inputs) @@ -47,15 +49,93 @@ #include "rcore.h" +#include // POSIX file control definitions - open(), creat(), fcntl() +#include // POSIX standard function definitions - read(), close(), STDIN_FILENO +#include // POSIX terminal control definitions - tcgetattr(), tcsetattr() +#include // POSIX threads management (inputs reading) +#include // POSIX directory browsing + +#include // Required for: ioctl() - UNIX System call for device-specific input/output operations +#include // Linux: KDSKBMODE, K_MEDIUMRAM constants definition +#include // Linux: Keycodes constants definition (KEY_A, ...) +#include // Linux: Joystick support library + +#include // Generic Buffer Management (native platform for EGL on DRM) +#include // Direct Rendering Manager user-level library interface +#include // Direct Rendering Manager mode setting (KMS) interface + +#include "EGL/egl.h" // Native platform windowing system interface +#include "EGL/eglext.h" // EGL extensions + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#define USE_LAST_TOUCH_DEVICE // When multiple touchscreens are connected, only use the one with the highest event number + +#define DEFAULT_GAMEPAD_DEV "/dev/input/js" // Gamepad input (base dev for all gamepads: js0, js1, ...) +#define DEFAULT_EVDEV_PATH "/dev/input/" // Path to the linux input events + //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -//... + +typedef struct { + pthread_t threadId; // Event reading thread id + + int fd; // File descriptor to the device it is assigned to + int eventNum; // Number of 'event' device + Rectangle absRange; // Range of values for absolute pointing devices (touchscreens) + int touchSlot; // Hold the touch slot number of the currently being sent multitouch block + bool isMouse; // True if device supports relative X Y movements + bool isTouch; // True if device supports absolute X Y movements and has BTN_TOUCH + bool isMultitouch; // True if device supports multiple absolute movevents and has BTN_TOUCH + bool isKeyboard; // True if device has letter keycodes + bool isGamepad; // True if device has gamepad buttons +} InputEventWorker; + +typedef struct { + // Display data + int fd; // File descriptor for /dev/dri/... + drmModeConnector *connector; // Direct Rendering Manager (DRM) mode connector + drmModeCrtc *crtc; // CRT Controller + int modeIndex; // Index of the used mode of connector->modes + struct gbm_device *gbmDevice; // GBM device + struct gbm_surface *gbmSurface; // GBM surface + struct gbm_bo *prevBO; // Previous GBM buffer object (during frame swapping) + uint32_t prevFB; // Previous GBM framebufer (during frame swapping) + + EGLDisplay device; // Native display device (physical screen connection) + EGLSurface surface; // Surface to draw on, framebuffers (connected to context) + EGLContext context; // Graphic context, mode in which drawing can be done + EGLConfig config; // Graphic config + + // Input data + InputEventWorker eventWorker[10]; // List of worker threads for every monitored "/dev/input/event" + + // Keyboard data + int defaultKeyboardMode; // Default keyboard mode + bool eventKeyboardMode; // Keyboard in event mode + int defaultFileFlags; // Default IO file flags + struct termios defaultSettings; // Default keyboard settings + int keyboardFd; // File descriptor for the evdev keyboard + + // Mouse data + Vector2 eventWheelMove; // Registers the event mouse wheel variation + // NOTE: currentButtonState[] can't be written directly due to multithreading, app could miss the update + char currentButtonStateEvdev[MAX_MOUSE_BUTTONS]; // Holds the new mouse state for the next polling event to grab + + // Gamepad data + pthread_t gamepadThreadId; // Gamepad reading thread id + int gamepadStreamFd[MAX_GAMEPADS]; // Gamepad device file descriptor + +} PlatformData; //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -extern CoreData CORE; // Global CORE state context +extern CoreData CORE; // Global CORE state context + +static PlatformData platform = { 0 }; // Platform specific data //---------------------------------------------------------------------------------- // Module Internal Functions Declaration @@ -227,67 +307,67 @@ void CloseWindow(void) timeEndPeriod(1); // Restore time period #endif - if (CORE.Window.prevFB) + if (platform.prevFB) { - drmModeRmFB(CORE.Window.fd, CORE.Window.prevFB); - CORE.Window.prevFB = 0; + drmModeRmFB(platform.fd, platform.prevFB); + platform.prevFB = 0; } - if (CORE.Window.prevBO) + if (platform.prevBO) { - gbm_surface_release_buffer(CORE.Window.gbmSurface, CORE.Window.prevBO); - CORE.Window.prevBO = NULL; + gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO); + platform.prevBO = NULL; } - if (CORE.Window.gbmSurface) + if (platform.gbmSurface) { - gbm_surface_destroy(CORE.Window.gbmSurface); - CORE.Window.gbmSurface = NULL; + gbm_surface_destroy(platform.gbmSurface); + platform.gbmSurface = NULL; } - if (CORE.Window.gbmDevice) + if (platform.gbmDevice) { - gbm_device_destroy(CORE.Window.gbmDevice); - CORE.Window.gbmDevice = NULL; + gbm_device_destroy(platform.gbmDevice); + platform.gbmDevice = NULL; } - if (CORE.Window.crtc) + if (platform.crtc) { - if (CORE.Window.connector) + if (platform.connector) { - drmModeSetCrtc(CORE.Window.fd, CORE.Window.crtc->crtc_id, CORE.Window.crtc->buffer_id, - CORE.Window.crtc->x, CORE.Window.crtc->y, &CORE.Window.connector->connector_id, 1, &CORE.Window.crtc->mode); - drmModeFreeConnector(CORE.Window.connector); - CORE.Window.connector = NULL; + drmModeSetCrtc(platform.fd, platform.crtc->crtc_id, platform.crtc->buffer_id, + platform.crtc->x, platform.crtc->y, &platform.connector->connector_id, 1, &platform.crtc->mode); + drmModeFreeConnector(platform.connector); + platform.connector = NULL; } - drmModeFreeCrtc(CORE.Window.crtc); - CORE.Window.crtc = NULL; + drmModeFreeCrtc(platform.crtc); + platform.crtc = NULL; } - if (CORE.Window.fd != -1) + if (platform.fd != -1) { - close(CORE.Window.fd); - CORE.Window.fd = -1; + close(platform.fd); + platform.fd = -1; } // Close surface, context and display - if (CORE.Window.device != EGL_NO_DISPLAY) + if (platform.device != EGL_NO_DISPLAY) { - if (CORE.Window.surface != EGL_NO_SURFACE) + if (platform.surface != EGL_NO_SURFACE) { - eglDestroySurface(CORE.Window.device, CORE.Window.surface); - CORE.Window.surface = EGL_NO_SURFACE; + eglDestroySurface(platform.device, platform.surface); + platform.surface = EGL_NO_SURFACE; } - if (CORE.Window.context != EGL_NO_CONTEXT) + if (platform.context != EGL_NO_CONTEXT) { - eglDestroyContext(CORE.Window.device, CORE.Window.context); - CORE.Window.context = EGL_NO_CONTEXT; + eglDestroyContext(platform.device, platform.context); + platform.context = EGL_NO_CONTEXT; } - eglTerminate(CORE.Window.device); - CORE.Window.device = EGL_NO_DISPLAY; + eglTerminate(platform.device); + platform.device = EGL_NO_DISPLAY; } // Wait for mouse and gamepad threads to finish before closing @@ -297,21 +377,21 @@ void CloseWindow(void) CORE.Window.shouldClose = true; // Added to force threads to exit when the close window is called // Close the evdev keyboard - if (CORE.Input.Keyboard.fd != -1) + if (platform.keyboardFd != -1) { - close(CORE.Input.Keyboard.fd); - CORE.Input.Keyboard.fd = -1; + close(platform.keyboardFd); + platform.keyboardFd = -1; } - for (int i = 0; i < sizeof(CORE.Input.eventWorker)/sizeof(InputEventWorker); ++i) + for (int i = 0; i < sizeof(platform.eventWorker)/sizeof(InputEventWorker); ++i) { - if (CORE.Input.eventWorker[i].threadId) + if (platform.eventWorker[i].threadId) { - pthread_join(CORE.Input.eventWorker[i].threadId, NULL); + pthread_join(platform.eventWorker[i].threadId, NULL); } } - if (CORE.Input.Gamepad.threadId) pthread_join(CORE.Input.Gamepad.threadId, NULL); + if (platform.gamepadThreadId) pthread_join(platform.gamepadThreadId, NULL); #if defined(SUPPORT_EVENTS_AUTOMATION) RL_FREE(events); @@ -524,9 +604,9 @@ int GetMonitorRefreshRate(int monitor) { int refresh = 0; - if ((CORE.Window.connector) && (CORE.Window.modeIndex >= 0)) + if ((platform.connector) && (platform.modeIndex >= 0)) { - refresh = CORE.Window.connector->modes[CORE.Window.modeIndex].vrefresh; + refresh = platform.connector->modes[platform.modeIndex].vrefresh; } return refresh; @@ -659,7 +739,7 @@ const char *GetGamepadName(int gamepad) if (CORE.Input.Gamepad.ready[gamepad]) { - ioctl(CORE.Input.Gamepad.streamId[gamepad], JSIOCGNAME(64), &CORE.Input.Gamepad.name[gamepad]); + ioctl(platform.gamepadStreamFd[gamepad], JSIOCGNAME(64), &CORE.Input.Gamepad.name[gamepad]); name = CORE.Input.Gamepad.name[gamepad]; } @@ -670,7 +750,7 @@ const char *GetGamepadName(int gamepad) int GetGamepadAxisCount(int gamepad) { int axisCount = 0; - if (CORE.Input.Gamepad.ready[gamepad]) ioctl(CORE.Input.Gamepad.streamId[gamepad], JSIOCGAXES, &axisCount); + if (CORE.Input.Gamepad.ready[gamepad]) ioctl(platform.gamepadStreamFd[gamepad], JSIOCGAXES, &axisCount); CORE.Input.Gamepad.axisCount = axisCount; return CORE.Input.Gamepad.axisCount; @@ -756,31 +836,31 @@ Vector2 GetTouchPosition(int index) // Swap back buffer with front buffer (screen drawing) void SwapScreenBuffer(void) { - eglSwapBuffers(CORE.Window.device, CORE.Window.surface); + eglSwapBuffers(platform.device, platform.surface); - if (!CORE.Window.gbmSurface || (-1 == CORE.Window.fd) || !CORE.Window.connector || !CORE.Window.crtc) TRACELOG(LOG_ERROR, "DISPLAY: DRM initialization failed to swap"); + if (!platform.gbmSurface || (-1 == platform.fd) || !platform.connector || !platform.crtc) TRACELOG(LOG_ERROR, "DISPLAY: DRM initialization failed to swap"); - struct gbm_bo *bo = gbm_surface_lock_front_buffer(CORE.Window.gbmSurface); + struct gbm_bo *bo = gbm_surface_lock_front_buffer(platform.gbmSurface); if (!bo) TRACELOG(LOG_ERROR, "DISPLAY: Failed GBM to lock front buffer"); uint32_t fb = 0; - int result = drmModeAddFB(CORE.Window.fd, CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay, CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay, 24, 32, gbm_bo_get_stride(bo), gbm_bo_get_handle(bo).u32, &fb); + int result = drmModeAddFB(platform.fd, platform.connector->modes[platform.modeIndex].hdisplay, platform.connector->modes[platform.modeIndex].vdisplay, 24, 32, gbm_bo_get_stride(bo), gbm_bo_get_handle(bo).u32, &fb); if (result != 0) TRACELOG(LOG_ERROR, "DISPLAY: drmModeAddFB() failed with result: %d", result); - result = drmModeSetCrtc(CORE.Window.fd, CORE.Window.crtc->crtc_id, fb, 0, 0, &CORE.Window.connector->connector_id, 1, &CORE.Window.connector->modes[CORE.Window.modeIndex]); + result = drmModeSetCrtc(platform.fd, platform.crtc->crtc_id, fb, 0, 0, &platform.connector->connector_id, 1, &platform.connector->modes[platform.modeIndex]); if (result != 0) TRACELOG(LOG_ERROR, "DISPLAY: drmModeSetCrtc() failed with result: %d", result); - if (CORE.Window.prevFB) + if (platform.prevFB) { - result = drmModeRmFB(CORE.Window.fd, CORE.Window.prevFB); + result = drmModeRmFB(platform.fd, platform.prevFB); if (result != 0) TRACELOG(LOG_ERROR, "DISPLAY: drmModeRmFB() failed with result: %d", result); } - CORE.Window.prevFB = fb; + platform.prevFB = fb; - if (CORE.Window.prevBO) gbm_surface_release_buffer(CORE.Window.gbmSurface, CORE.Window.prevBO); + if (platform.prevBO) gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO); - CORE.Window.prevBO = bo; + platform.prevBO = bo; } // Register all input events @@ -814,12 +894,12 @@ void PollInputEvents(void) // Register previous mouse states CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove; - CORE.Input.Mouse.currentWheelMove = CORE.Input.Mouse.eventWheelMove; - CORE.Input.Mouse.eventWheelMove = (Vector2){ 0.0f, 0.0f }; + CORE.Input.Mouse.currentWheelMove = platform.eventWheelMove; + platform.eventWheelMove = (Vector2){ 0.0f, 0.0f }; for (int i = 0; i < MAX_MOUSE_BUTTONS; i++) { CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i]; - CORE.Input.Mouse.currentButtonState[i] = CORE.Input.Mouse.currentButtonStateEvdev[i]; + CORE.Input.Mouse.currentButtonState[i] = platform.currentButtonStateEvdev[i]; } // Register gamepads buttons events @@ -844,7 +924,7 @@ void PollInputEvents(void) // 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 (!CORE.Input.Keyboard.evtMode) ProcessKeyboard(); + if (!platform.eventKeyboardMode) ProcessKeyboard(); // NOTE: Mouse input events polling is done asynchronously in another pthread - EventThread() // NOTE: Gamepad (Joystick) input events polling is done asynchonously in another pthread - GamepadThread() @@ -877,41 +957,41 @@ static bool InitGraphicsDevice(int width, int height) CORE.Window.fullscreen = true; CORE.Window.flags |= FLAG_FULLSCREEN_MODE; - CORE.Window.fd = -1; - CORE.Window.connector = NULL; - CORE.Window.modeIndex = -1; - CORE.Window.crtc = NULL; - CORE.Window.gbmDevice = NULL; - CORE.Window.gbmSurface = NULL; - CORE.Window.prevBO = NULL; - CORE.Window.prevFB = 0; + platform.fd = -1; + platform.connector = NULL; + platform.modeIndex = -1; + platform.crtc = NULL; + platform.gbmDevice = NULL; + platform.gbmSurface = NULL; + platform.prevBO = NULL; + platform.prevFB = 0; #if defined(DEFAULT_GRAPHIC_DEVICE_DRM) - CORE.Window.fd = open(DEFAULT_GRAPHIC_DEVICE_DRM, O_RDWR); + platform.fd = open(DEFAULT_GRAPHIC_DEVICE_DRM, O_RDWR); #else TRACELOG(LOG_INFO, "DISPLAY: No graphic card set, trying platform-gpu-card"); - CORE.Window.fd = open("/dev/dri/by-path/platform-gpu-card", O_RDWR); // VideoCore VI (Raspberry Pi 4) + platform.fd = open("/dev/dri/by-path/platform-gpu-card", O_RDWR); // VideoCore VI (Raspberry Pi 4) - if ((CORE.Window.fd == -1) || (drmModeGetResources(CORE.Window.fd) == NULL)) + if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL)) { TRACELOG(LOG_INFO, "DISPLAY: Failed to open platform-gpu-card, trying card1"); - CORE.Window.fd = open("/dev/dri/card1", O_RDWR); // Other Embedded + platform.fd = open("/dev/dri/card1", O_RDWR); // Other Embedded } - if ((CORE.Window.fd == -1) || (drmModeGetResources(CORE.Window.fd) == NULL)) + if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL)) { TRACELOG(LOG_INFO, "DISPLAY: Failed to open graphic card1, trying card0"); - CORE.Window.fd = open("/dev/dri/card0", O_RDWR); // VideoCore IV (Raspberry Pi 1-3) + platform.fd = open("/dev/dri/card0", O_RDWR); // VideoCore IV (Raspberry Pi 1-3) } #endif - if (CORE.Window.fd == -1) + if (platform.fd == -1) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card"); return false; } - drmModeRes *res = drmModeGetResources(CORE.Window.fd); + drmModeRes *res = drmModeGetResources(platform.fd); if (!res) { TRACELOG(LOG_WARNING, "DISPLAY: Failed get DRM resources"); @@ -924,13 +1004,13 @@ static bool InitGraphicsDevice(int width, int height) { TRACELOG(LOG_TRACE, "DISPLAY: Connector index %i", i); - drmModeConnector *con = drmModeGetConnector(CORE.Window.fd, res->connectors[i]); + drmModeConnector *con = drmModeGetConnector(platform.fd, res->connectors[i]); TRACELOG(LOG_TRACE, "DISPLAY: Connector modes detected: %i", con->count_modes); if ((con->connection == DRM_MODE_CONNECTED) && (con->encoder_id)) { TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected"); - CORE.Window.connector = con; + platform.connector = con; break; } else @@ -940,14 +1020,14 @@ static bool InitGraphicsDevice(int width, int height) } } - if (!CORE.Window.connector) + if (!platform.connector) { TRACELOG(LOG_WARNING, "DISPLAY: No suitable DRM connector found"); drmModeFreeResources(res); return false; } - drmModeEncoder *enc = drmModeGetEncoder(CORE.Window.fd, CORE.Window.connector->encoder_id); + drmModeEncoder *enc = drmModeGetEncoder(platform.fd, platform.connector->encoder_id); if (!enc) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode encoder"); @@ -955,8 +1035,8 @@ static bool InitGraphicsDevice(int width, int height) return false; } - CORE.Window.crtc = drmModeGetCrtc(CORE.Window.fd, enc->crtc_id); - if (!CORE.Window.crtc) + platform.crtc = drmModeGetCrtc(platform.fd, enc->crtc_id); + if (!platform.crtc) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc"); drmModeFreeEncoder(enc); @@ -969,9 +1049,9 @@ static bool InitGraphicsDevice(int width, int height) { TRACELOG(LOG_TRACE, "DISPLAY: Selecting DRM connector mode for current used mode..."); - CORE.Window.modeIndex = FindMatchingConnectorMode(CORE.Window.connector, &CORE.Window.crtc->mode); + platform.modeIndex = FindMatchingConnectorMode(platform.connector, &platform.crtc->mode); - if (CORE.Window.modeIndex < 0) + if (platform.modeIndex < 0) { TRACELOG(LOG_WARNING, "DISPLAY: No matching DRM connector mode found"); drmModeFreeEncoder(enc); @@ -987,19 +1067,19 @@ static bool InitGraphicsDevice(int width, int height) const int fps = (CORE.Time.target > 0)? (1.0/CORE.Time.target) : 60; // Try to find an exact matching mode - CORE.Window.modeIndex = FindExactConnectorMode(CORE.Window.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); // If nothing found, try to find a nearly matching mode - if (CORE.Window.modeIndex < 0) CORE.Window.modeIndex = FindNearestConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced); + if (platform.modeIndex < 0) platform.modeIndex = FindNearestConnectorMode(platform.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced); // If nothing found, try to find an exactly matching mode including interlaced - if (CORE.Window.modeIndex < 0) CORE.Window.modeIndex = FindExactConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, true); + if (platform.modeIndex < 0) platform.modeIndex = FindExactConnectorMode(platform.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, true); // If nothing found, try to find a nearly matching mode including interlaced - if (CORE.Window.modeIndex < 0) CORE.Window.modeIndex = FindNearestConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, true); + if (platform.modeIndex < 0) platform.modeIndex = FindNearestConnectorMode(platform.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, true); // If nothing found, there is no suitable mode - if (CORE.Window.modeIndex < 0) + if (platform.modeIndex < 0) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to find a suitable DRM connector mode"); drmModeFreeEncoder(enc); @@ -1007,13 +1087,13 @@ static bool InitGraphicsDevice(int width, int height) return false; } - CORE.Window.display.width = CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay; - CORE.Window.display.height = CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay; + CORE.Window.display.width = platform.connector->modes[platform.modeIndex].hdisplay; + CORE.Window.display.height = platform.connector->modes[platform.modeIndex].vdisplay; - TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u)", CORE.Window.connector->modes[CORE.Window.modeIndex].name, - CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay, CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay, - (CORE.Window.connector->modes[CORE.Window.modeIndex].flags & DRM_MODE_FLAG_INTERLACE)? 'i' : 'p', - CORE.Window.connector->modes[CORE.Window.modeIndex].vrefresh); + 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].flags & DRM_MODE_FLAG_INTERLACE)? 'i' : 'p', + platform.connector->modes[platform.modeIndex].vrefresh); // Use the width and height of the surface for render CORE.Window.render.width = CORE.Window.screen.width; @@ -1025,16 +1105,16 @@ static bool InitGraphicsDevice(int width, int height) drmModeFreeResources(res); res = NULL; - CORE.Window.gbmDevice = gbm_create_device(CORE.Window.fd); - if (!CORE.Window.gbmDevice) + platform.gbmDevice = gbm_create_device(platform.fd); + if (!platform.gbmDevice) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to create GBM device"); return false; } - CORE.Window.gbmSurface = gbm_surface_create(CORE.Window.gbmDevice, CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay, - CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay, GBM_FORMAT_ARGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); - if (!CORE.Window.gbmSurface) + platform.gbmSurface = gbm_surface_create(platform.gbmDevice, platform.connector->modes[platform.modeIndex].hdisplay, + platform.connector->modes[platform.modeIndex].vdisplay, GBM_FORMAT_ARGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + if (!platform.gbmSurface) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to create GBM surface"); return false; @@ -1073,22 +1153,22 @@ static bool InitGraphicsDevice(int width, int height) EGLint numConfigs = 0; // Get an EGL device connection - CORE.Window.device = eglGetDisplay((EGLNativeDisplayType)CORE.Window.gbmDevice); - if (CORE.Window.device == EGL_NO_DISPLAY) + platform.device = eglGetDisplay((EGLNativeDisplayType)platform.gbmDevice); + if (platform.device == EGL_NO_DISPLAY) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device"); return false; } // Initialize the EGL device connection - if (eglInitialize(CORE.Window.device, NULL, NULL) == EGL_FALSE) + if (eglInitialize(platform.device, NULL, NULL) == EGL_FALSE) { // 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 false; } - if (!eglChooseConfig(CORE.Window.device, NULL, NULL, 0, &numConfigs)) + if (!eglChooseConfig(platform.device, NULL, NULL, 0, &numConfigs)) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to get EGL config count: 0x%x", eglGetError()); return false; @@ -1104,7 +1184,7 @@ static bool InitGraphicsDevice(int width, int height) } EGLint matchingNumConfigs = 0; - if (!eglChooseConfig(CORE.Window.device, framebufferAttribs, configs, numConfigs, &matchingNumConfigs)) + if (!eglChooseConfig(platform.device, framebufferAttribs, configs, numConfigs, &matchingNumConfigs)) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to choose EGL config: 0x%x", eglGetError()); free(configs); @@ -1118,7 +1198,7 @@ static bool InitGraphicsDevice(int width, int height) for (EGLint i = 0; i < matchingNumConfigs; ++i) { EGLint id = 0; - if (!eglGetConfigAttrib(CORE.Window.device, configs[i], EGL_NATIVE_VISUAL_ID, &id)) + if (!eglGetConfigAttrib(platform.device, configs[i], EGL_NATIVE_VISUAL_ID, &id)) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to get EGL config attribute: 0x%x", eglGetError()); continue; @@ -1127,7 +1207,7 @@ static bool InitGraphicsDevice(int width, int height) if (GBM_FORMAT_ARGB8888 == id) { TRACELOG(LOG_TRACE, "DISPLAY: Using EGL config: %d", i); - CORE.Window.config = configs[i]; + platform.config = configs[i]; found = 1; break; } @@ -1145,8 +1225,8 @@ static bool InitGraphicsDevice(int width, int height) eglBindAPI(EGL_OPENGL_ES_API); // Create an EGL rendering context - CORE.Window.context = eglCreateContext(CORE.Window.device, CORE.Window.config, EGL_NO_CONTEXT, contextAttribs); - if (CORE.Window.context == EGL_NO_CONTEXT) + platform.context = eglCreateContext(platform.device, platform.config, EGL_NO_CONTEXT, contextAttribs); + if (platform.context == EGL_NO_CONTEXT) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL context"); return false; @@ -1154,8 +1234,8 @@ static bool InitGraphicsDevice(int width, int height) // Create an EGL window surface //--------------------------------------------------------------------------------- - CORE.Window.surface = eglCreateWindowSurface(CORE.Window.device, CORE.Window.config, (EGLNativeWindowType)CORE.Window.gbmSurface, NULL); - if (EGL_NO_SURFACE == CORE.Window.surface) + platform.surface = eglCreateWindowSurface(platform.device, platform.config, (EGLNativeWindowType)platform.gbmSurface, NULL); + if (EGL_NO_SURFACE == platform.surface) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL window surface: 0x%04x", eglGetError()); return false; @@ -1169,9 +1249,9 @@ static bool InitGraphicsDevice(int width, int height) SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); // There must be at least one frame displayed before the buffers are swapped - //eglSwapInterval(CORE.Window.device, 1); + //eglSwapInterval(platform.device, 1); - if (eglMakeCurrent(CORE.Window.device, CORE.Window.surface, CORE.Window.surface, CORE.Window.context) == EGL_FALSE) + if (eglMakeCurrent(platform.device, platform.surface, platform.surface, platform.context) == EGL_FALSE) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to attach EGL rendering context to EGL surface"); return false; @@ -1214,11 +1294,11 @@ static void InitKeyboard(void) // Reading directly from stdin will give chars already key-mapped by kernel to ASCII or UNICODE // Save terminal keyboard settings - tcgetattr(STDIN_FILENO, &CORE.Input.Keyboard.defaultSettings); + tcgetattr(STDIN_FILENO, &platform.defaultSettings); // Reconfigure terminal with new settings struct termios keyboardNewSettings = { 0 }; - keyboardNewSettings = CORE.Input.Keyboard.defaultSettings; + keyboardNewSettings = platform.defaultSettings; // 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 @@ -1231,11 +1311,11 @@ static void InitKeyboard(void) tcsetattr(STDIN_FILENO, TCSANOW, &keyboardNewSettings); // Save old keyboard mode to restore it at the end - CORE.Input.Keyboard.defaultFileFlags = fcntl(STDIN_FILENO, F_GETFL, 0); // F_GETFL: Get the file access mode and the file status flags - fcntl(STDIN_FILENO, F_SETFL, CORE.Input.Keyboard.defaultFileFlags | O_NONBLOCK); // F_SETFL: Set the file status flags to the value specified + platform.defaultFileFlags = fcntl(STDIN_FILENO, F_GETFL, 0); // F_GETFL: Get the file access mode and the file status flags + fcntl(STDIN_FILENO, F_SETFL, platform.defaultFileFlags | O_NONBLOCK); // F_SETFL: Set the file status flags to the value specified // NOTE: If ioctl() returns -1, it means the call failed for some reason (error code set in errno) - int result = ioctl(STDIN_FILENO, KDGKBMODE, &CORE.Input.Keyboard.defaultMode); + int result = ioctl(STDIN_FILENO, KDGKBMODE, &platform.defaultKeyboardMode); // In case of failure, it could mean a remote keyboard is used (SSH) if (result < 0) TRACELOG(LOG_WARNING, "RPI: Failed to change keyboard mode, an SSH keyboard is probably used"); @@ -1257,11 +1337,11 @@ static void InitKeyboard(void) static void RestoreKeyboard(void) { // Reset to default keyboard settings - tcsetattr(STDIN_FILENO, TCSANOW, &CORE.Input.Keyboard.defaultSettings); + tcsetattr(STDIN_FILENO, TCSANOW, &platform.defaultSettings); // Reconfigure keyboard to default mode - fcntl(STDIN_FILENO, F_SETFL, CORE.Input.Keyboard.defaultFileFlags); - ioctl(STDIN_FILENO, KDSKBMODE, CORE.Input.Keyboard.defaultMode); + fcntl(STDIN_FILENO, F_SETFL, platform.defaultFileFlags); + ioctl(STDIN_FILENO, KDSKBMODE, platform.defaultKeyboardMode); } #if defined(SUPPORT_SSH_KEYBOARD_RPI) @@ -1389,7 +1469,7 @@ static void InitEvdevInput(void) struct dirent *entity = NULL; // Initialise keyboard file descriptor - CORE.Input.Keyboard.fd = -1; + platform.keyboardFd = -1; // Reset variables for (int i = 0; i < MAX_TOUCH_POINTS; ++i) @@ -1451,9 +1531,9 @@ static void ConfigureEvdevDevice(char *device) // Open the device and allocate worker //------------------------------------------------------------------------------------------------------- // Find a free spot in the workers array - for (int i = 0; i < sizeof(CORE.Input.eventWorker)/sizeof(InputEventWorker); ++i) + for (int i = 0; i < sizeof(platform.eventWorker)/sizeof(InputEventWorker); ++i) { - if (CORE.Input.eventWorker[i].threadId == 0) + if (platform.eventWorker[i].threadId == 0) { freeWorkerId = i; break; @@ -1463,7 +1543,7 @@ static void ConfigureEvdevDevice(char *device) // Select the free worker from array if (freeWorkerId >= 0) { - worker = &(CORE.Input.eventWorker[freeWorkerId]); // Grab a pointer to the worker + worker = &(platform.eventWorker[freeWorkerId]); // Grab a pointer to the worker memset(worker, 0, sizeof(InputEventWorker)); // Clear the worker } else @@ -1574,13 +1654,13 @@ static void ConfigureEvdevDevice(char *device) // Decide what to do with the device //------------------------------------------------------------------------------------------------------- - if (worker->isKeyboard && (CORE.Input.Keyboard.fd == -1)) + if (worker->isKeyboard && (platform.keyboardFd == -1)) { // Use the first keyboard encountered. This assumes that a device that says it's a keyboard is just a // keyboard. The keyboard is polled synchronously, whereas other input devices are polled in separate // threads so that they don't drop events when the frame rate is slow. TRACELOG(LOG_INFO, "RPI: Opening keyboard device: %s", device); - CORE.Input.Keyboard.fd = worker->fd; + platform.keyboardFd = worker->fd; } else if (worker->isTouch || worker->isMouse) { @@ -1604,21 +1684,21 @@ static void ConfigureEvdevDevice(char *device) // Find touchscreen with the highest index int maxTouchNumber = -1; - for (int i = 0; i < sizeof(CORE.Input.eventWorker)/sizeof(InputEventWorker); ++i) + for (int i = 0; i < sizeof(platform.eventWorker)/sizeof(InputEventWorker); ++i) { - if (CORE.Input.eventWorker[i].isTouch && (CORE.Input.eventWorker[i].eventNum > maxTouchNumber)) maxTouchNumber = CORE.Input.eventWorker[i].eventNum; + if (platform.eventWorker[i].isTouch && (platform.eventWorker[i].eventNum > maxTouchNumber)) maxTouchNumber = platform.eventWorker[i].eventNum; } // Find touchscreens with lower indexes - for (int i = 0; i < sizeof(CORE.Input.eventWorker)/sizeof(InputEventWorker); ++i) + for (int i = 0; i < sizeof(platform.eventWorker)/sizeof(InputEventWorker); ++i) { - if (CORE.Input.eventWorker[i].isTouch && (CORE.Input.eventWorker[i].eventNum < maxTouchNumber)) + if (platform.eventWorker[i].isTouch && (platform.eventWorker[i].eventNum < maxTouchNumber)) { - if (CORE.Input.eventWorker[i].threadId != 0) + if (platform.eventWorker[i].threadId != 0) { TRACELOG(LOG_WARNING, "RPI: Found duplicate touchscreen, killing touchscreen on event: %d", i); - pthread_cancel(CORE.Input.eventWorker[i].threadId); - close(CORE.Input.eventWorker[i].fd); + pthread_cancel(platform.eventWorker[i].threadId); + close(platform.eventWorker[i].fd); } } } @@ -1652,7 +1732,7 @@ static void PollKeyboardEvents(void) 243, 244, 245, 246, 247, 248, 0, 0, 0, 0, 0, 0, 0 }; - int fd = CORE.Input.Keyboard.fd; + int fd = platform.keyboardFd; if (fd == -1) return; struct input_event event = { 0 }; @@ -1666,7 +1746,7 @@ static void PollKeyboardEvents(void) { #if defined(SUPPORT_SSH_KEYBOARD_RPI) // Change keyboard mode to events - CORE.Input.Keyboard.evtMode = true; + platform.eventKeyboardMode = true; #endif // Keyboard button parsing if ((event.code >= 1) && (event.code <= 255)) //Keyboard keys appear for codes 1 to 255 @@ -1739,7 +1819,7 @@ static void *EventThread(void *arg) gestureUpdate = true; } - if (event.code == REL_WHEEL) CORE.Input.Mouse.eventWheelMove.y += event.value; + if (event.code == REL_WHEEL) platform.eventWheelMove.y += event.value; } // Absolute movement parsing @@ -1790,11 +1870,11 @@ static void *EventThread(void *arg) // Touchscreen tap if (event.code == ABS_PRESSURE) { - int previousMouseLeftButtonState = CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_LEFT]; + int previousMouseLeftButtonState = platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT]; if (!event.value && previousMouseLeftButtonState) { - CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 0; + platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 0; touchAction = 0; // TOUCH_ACTION_UP gestureUpdate = true; @@ -1802,7 +1882,7 @@ static void *EventThread(void *arg) if (event.value && !previousMouseLeftButtonState) { - CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 1; + platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 1; touchAction = 1; // TOUCH_ACTION_DOWN gestureUpdate = true; @@ -1817,19 +1897,19 @@ static void *EventThread(void *arg) // Mouse button parsing if ((event.code == BTN_TOUCH) || (event.code == BTN_LEFT)) { - CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = event.value; + platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = event.value; if (event.value > 0) touchAction = 1; // TOUCH_ACTION_DOWN else touchAction = 0; // TOUCH_ACTION_UP gestureUpdate = true; } - if (event.code == BTN_RIGHT) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_RIGHT] = event.value; - if (event.code == BTN_MIDDLE) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_MIDDLE] = event.value; - if (event.code == BTN_SIDE) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_SIDE] = event.value; - if (event.code == BTN_EXTRA) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_EXTRA] = event.value; - if (event.code == BTN_FORWARD) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_FORWARD] = event.value; - if (event.code == BTN_BACK) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_BACK] = event.value; + if (event.code == BTN_RIGHT) platform.currentButtonStateEvdev[MOUSE_BUTTON_RIGHT] = event.value; + if (event.code == BTN_MIDDLE) platform.currentButtonStateEvdev[MOUSE_BUTTON_MIDDLE] = event.value; + if (event.code == BTN_SIDE) platform.currentButtonStateEvdev[MOUSE_BUTTON_SIDE] = event.value; + if (event.code == BTN_EXTRA) platform.currentButtonStateEvdev[MOUSE_BUTTON_EXTRA] = event.value; + if (event.code == BTN_FORWARD) platform.currentButtonStateEvdev[MOUSE_BUTTON_FORWARD] = event.value; + if (event.code == BTN_BACK) platform.currentButtonStateEvdev[MOUSE_BUTTON_BACK] = event.value; } // Screen confinement @@ -1885,7 +1965,7 @@ static void InitGamepad(void) { sprintf(gamepadDev, "%s%i", DEFAULT_GAMEPAD_DEV, i); - if ((CORE.Input.Gamepad.streamId[i] = open(gamepadDev, O_RDONLY | O_NONBLOCK)) < 0) + if ((platform.gamepadStreamFd[i] = open(gamepadDev, O_RDONLY | O_NONBLOCK)) < 0) { // NOTE: Only show message for first gamepad if (i == 0) TRACELOG(LOG_WARNING, "RPI: Failed to open Gamepad device, no gamepad available"); @@ -1897,7 +1977,7 @@ static void InitGamepad(void) // NOTE: Only create one thread if (i == 0) { - int error = pthread_create(&CORE.Input.Gamepad.threadId, NULL, &GamepadThread, NULL); + int error = pthread_create(&platform.gamepadThreadId, NULL, &GamepadThread, NULL); if (error != 0) TRACELOG(LOG_WARNING, "RPI: Failed to create gamepad input event thread"); else TRACELOG(LOG_INFO, "RPI: Gamepad device initialized successfully"); @@ -1927,7 +2007,7 @@ static void *GamepadThread(void *arg) { for (int i = 0; i < MAX_GAMEPADS; i++) { - if (read(CORE.Input.Gamepad.streamId[i], &gamepadEvent, sizeof(struct js_event)) == (int)sizeof(struct js_event)) + if (read(platform.gamepadStreamFd[i], &gamepadEvent, sizeof(struct js_event)) == (int)sizeof(struct js_event)) { gamepadEvent.type &= ~JS_EVENT_INIT; // Ignore synthetic events @@ -1977,7 +2057,7 @@ static int FindMatchingConnectorMode(const drmModeConnector *connector, const dr TRACELOG(LOG_TRACE, "DISPLAY: DRM mode: %d %ux%u@%u %s", i, connector->modes[i].hdisplay, connector->modes[i].vdisplay, connector->modes[i].vrefresh, (connector->modes[i].flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive"); - if (0 == BINCMP(&CORE.Window.crtc->mode, &CORE.Window.connector->modes[i])) return i; + if (0 == BINCMP(&platform.crtc->mode, &platform.connector->modes[i])) return i; } return -1; @@ -1992,9 +2072,9 @@ static int FindExactConnectorMode(const drmModeConnector *connector, uint width, if (NULL == connector) return -1; - for (int i = 0; i < CORE.Window.connector->count_modes; i++) + for (int i = 0; i < platform.connector->count_modes; i++) { - const drmModeModeInfo *const mode = &CORE.Window.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, (mode->flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive"); @@ -2015,9 +2095,9 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt if (NULL == connector) return -1; int nearestIndex = -1; - for (int i = 0; i < CORE.Window.connector->count_modes; i++) + for (int i = 0; i < platform.connector->count_modes; i++) { - const drmModeModeInfo *const mode = &CORE.Window.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, (mode->flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive"); @@ -2044,9 +2124,9 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt const int heightDiff = abs(mode->vdisplay - height); const int fpsDiff = abs(mode->vrefresh - fps); - const int nearestWidthDiff = abs(CORE.Window.connector->modes[nearestIndex].hdisplay - width); - const int nearestHeightDiff = abs(CORE.Window.connector->modes[nearestIndex].vdisplay - height); - const int nearestFpsDiff = abs(CORE.Window.connector->modes[nearestIndex].vrefresh - fps); + const int nearestWidthDiff = abs(platform.connector->modes[nearestIndex].hdisplay - width); + const int nearestHeightDiff = abs(platform.connector->modes[nearestIndex].vdisplay - height); + const int nearestFpsDiff = abs(platform.connector->modes[nearestIndex].vrefresh - fps); if ((widthDiff < nearestWidthDiff) || (heightDiff < nearestHeightDiff) || (fpsDiff < nearestFpsDiff)) { nearestIndex = i; diff --git a/src/rcore_web.c b/src/rcore_web.c index baafd60d6..fa296b90b 100644 --- a/src/rcore_web.c +++ b/src/rcore_web.c @@ -47,23 +47,42 @@ #include "rcore.h" -#define GLFW_INCLUDE_ES2 // GLFW3: Enable OpenGL ES 2.0 (translated to WebGL) -// #define GLFW_INCLUDE_ES3 // GLFW3: Enable OpenGL ES 3.0 (transalted to WebGL2?) -#include "GLFW/glfw3.h" // GLFW3: Windows, OpenGL context and Input management +#define GLFW_INCLUDE_ES2 // GLFW3: Enable OpenGL ES 2.0 (translated to WebGL) +// #define GLFW_INCLUDE_ES3 // GLFW3: Enable OpenGL ES 3.0 (transalted to WebGL2?) +#include "GLFW/glfw3.h" // GLFW3: Windows, OpenGL context and Input management + +#include // Emscripten functionality for C +#include // Emscripten HTML5 library + #include // Required for: timespec, nanosleep(), select() - POSIX -#include // Emscripten functionality for C -#include // Emscripten HTML5 library +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +// TODO: HACK: Added flag if not provided by GLFW when using external library +// Latest GLFW release (GLFW 3.3.8) does not implement this flag, it was added for 3.4.0-dev +#if !defined(GLFW_MOUSE_PASSTHROUGH) + #define GLFW_MOUSE_PASSTHROUGH 0x0002000D +#endif + +#if (_POSIX_C_SOURCE < 199309L) + #undef _POSIX_C_SOURCE + #define _POSIX_C_SOURCE 199309L // Required for: CLOCK_MONOTONIC if compiled with c99 without gnu ext. +#endif //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -//... +typedef struct { + GLFWwindow *handle; // GLFW window handle (graphic device) +} PlatformData; //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -extern CoreData CORE; // Global CORE state context +extern CoreData CORE; // Global CORE state context + +static PlatformData platform = { 0 }; // Platform specific data //---------------------------------------------------------------------------------- // Module Internal Functions Declaration @@ -263,7 +282,7 @@ void CloseWindow(void) rlglClose(); // De-init rlgl - glfwDestroyWindow(CORE.Window.handle); + glfwDestroyWindow(platform.handle); glfwTerminate(); #if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP) @@ -481,7 +500,7 @@ void SetWindowMaxSize(int width, int height) // Set window dimensions void SetWindowSize(int width, int height) { - glfwSetWindowSize(CORE.Window.handle, width, height); + glfwSetWindowSize(platform.handle, width, height); } // Set window opacity, value opacity is between 0.0 and 1.0 @@ -759,7 +778,7 @@ void SetMousePosition(int x, int y) CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; // NOTE: emscripten not implemented - glfwSetCursorPos(CORE.Window.handle, CORE.Input.Mouse.currentPosition.x, CORE.Input.Mouse.currentPosition.y); + glfwSetCursorPos(platform.handle, CORE.Input.Mouse.currentPosition.x, CORE.Input.Mouse.currentPosition.y); } // Get mouse wheel movement Y @@ -806,7 +825,7 @@ Vector2 GetTouchPosition(int index) // Swap back buffer with front buffer (screen drawing) void SwapScreenBuffer(void) { - glfwSwapBuffers(CORE.Window.handle); + glfwSwapBuffers(platform.handle); } // Register all input events @@ -1110,24 +1129,24 @@ static bool InitGraphicsDevice(int width, int height) // HighDPI monitors are properly considered in a following similar function: SetupViewport() SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); - CORE.Window.handle = glfwCreateWindow(CORE.Window.display.width, CORE.Window.display.height, (CORE.Window.title != 0)? CORE.Window.title : " ", glfwGetPrimaryMonitor(), NULL); + platform.handle = glfwCreateWindow(CORE.Window.display.width, CORE.Window.display.height, (CORE.Window.title != 0)? CORE.Window.title : " ", glfwGetPrimaryMonitor(), NULL); // NOTE: Full-screen change, not working properly... - // glfwSetWindowMonitor(CORE.Window.handle, glfwGetPrimaryMonitor(), 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); + // glfwSetWindowMonitor(platform.handle, glfwGetPrimaryMonitor(), 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); } else { // No-fullscreen window creation - CORE.Window.handle = glfwCreateWindow(CORE.Window.screen.width, CORE.Window.screen.height, (CORE.Window.title != 0)? CORE.Window.title : " ", NULL, NULL); + platform.handle = glfwCreateWindow(CORE.Window.screen.width, CORE.Window.screen.height, (CORE.Window.title != 0)? CORE.Window.title : " ", NULL, NULL); - if (CORE.Window.handle) + if (platform.handle) { CORE.Window.render.width = CORE.Window.screen.width; CORE.Window.render.height = CORE.Window.screen.height; } } - if (!CORE.Window.handle) + if (!platform.handle) { glfwTerminate(); TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window"); @@ -1138,20 +1157,20 @@ static bool InitGraphicsDevice(int width, int height) emscripten_set_window_title((CORE.Window.title != 0)? CORE.Window.title : " "); // Set window callback events - glfwSetWindowSizeCallback(CORE.Window.handle, WindowSizeCallback); // NOTE: Resizing not allowed by default! - glfwSetWindowIconifyCallback(CORE.Window.handle, WindowIconifyCallback); - glfwSetWindowFocusCallback(CORE.Window.handle, WindowFocusCallback); - glfwSetDropCallback(CORE.Window.handle, WindowDropCallback); + glfwSetWindowSizeCallback(platform.handle, WindowSizeCallback); // NOTE: Resizing not allowed by default! + glfwSetWindowIconifyCallback(platform.handle, WindowIconifyCallback); + glfwSetWindowFocusCallback(platform.handle, WindowFocusCallback); + glfwSetDropCallback(platform.handle, WindowDropCallback); // Set input callback events - glfwSetKeyCallback(CORE.Window.handle, KeyCallback); - glfwSetCharCallback(CORE.Window.handle, CharCallback); - glfwSetMouseButtonCallback(CORE.Window.handle, MouseButtonCallback); - glfwSetCursorPosCallback(CORE.Window.handle, MouseCursorPosCallback); // Track mouse position changes - glfwSetScrollCallback(CORE.Window.handle, MouseScrollCallback); - glfwSetCursorEnterCallback(CORE.Window.handle, CursorEnterCallback); + glfwSetKeyCallback(platform.handle, KeyCallback); + glfwSetCharCallback(platform.handle, CharCallback); + glfwSetMouseButtonCallback(platform.handle, MouseButtonCallback); + glfwSetCursorPosCallback(platform.handle, MouseCursorPosCallback); // Track mouse position changes + glfwSetScrollCallback(platform.handle, MouseScrollCallback); + glfwSetCursorEnterCallback(platform.handle, CursorEnterCallback); - glfwMakeContextCurrent(CORE.Window.handle); + glfwMakeContextCurrent(platform.handle); // 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 @@ -1293,7 +1312,7 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i } // Check the exit key to set close window - if ((key == CORE.Input.Keyboard.exitKey) && (action == GLFW_PRESS)) glfwSetWindowShouldClose(CORE.Window.handle, GLFW_TRUE); + if ((key == CORE.Input.Keyboard.exitKey) && (action == GLFW_PRESS)) glfwSetWindowShouldClose(platform.handle, GLFW_TRUE); #if defined(SUPPORT_SCREEN_CAPTURE) if ((key == GLFW_KEY_F12) && (action == GLFW_PRESS)) diff --git a/src/utils.h b/src/utils.h index ff8246a7b..6ec0f7f1b 100644 --- a/src/utils.h +++ b/src/utils.h @@ -32,7 +32,7 @@ #include // Required for: AAssetManager #endif -#if defined(SUPPORT_TRACELOG) +#if defined(SUPPORT_TRACELOG) && !defined(TRACELOG) #define TRACELOG(level, ...) TraceLog(level, __VA_ARGS__) #if defined(SUPPORT_TRACELOG_DEBUG)