WARNING: REDESIGN: Move platform specific data to platform submodules #3313

REVIEWED: Defines, macros, types and tweaks
This commit is contained in:
Ray 2023-10-09 00:41:06 +02:00
parent bbbaae5562
commit d445fdaa19
7 changed files with 519 additions and 520 deletions

View file

@ -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)
#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__)
__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 <unistd.h>
#elif defined(__APPLE__)
#elif defined(__APPLE__)
#include <sys/syslimits.h>
#include <mach-o/dyld.h>
#endif // OSs
#endif // PLATFORM_DESKTOP
#endif // OSs
#define _CRT_INTERNAL_NONSTDC_NAMES 1
#include <sys/stat.h> // 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

View file

@ -35,64 +35,6 @@
#ifndef RCORE_H
#define RCORE_H
#include <stdlib.h> // Required for: srand(), rand(), atexit()
#include <stdio.h> // Required for: sprintf() [Used in OpenURL()]
#include <string.h> // Required for: strrchr(), strcmp(), strlen(), memset()
#include <time.h> // Required for: time() [Used in InitTimer()]
#include <math.h> // 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 <EGL/egl.h> // Native platform windowing system interface
//#include <GLES2/gl2.h> // OpenGL ES 2.0 library (not required in this module, only in rlgl)
#endif
#if defined(PLATFORM_DRM)
#include <fcntl.h> // POSIX file control definitions - open(), creat(), fcntl()
#include <unistd.h> // POSIX standard function definitions - read(), close(), STDIN_FILENO
#include <termios.h> // POSIX terminal control definitions - tcgetattr(), tcsetattr()
#include <pthread.h> // POSIX threads management (inputs reading)
#include <dirent.h> // POSIX directory browsing
#include <sys/ioctl.h> // Required for: ioctl() - UNIX System call for device-specific input/output operations
#include <linux/kd.h> // Linux: KDSKBMODE, K_MEDIUMRAM constants definition
#include <linux/input.h> // Linux: Keycodes constants definition (KEY_A, ...)
#include <linux/joystick.h> // Linux: Joystick support library
#include <gbm.h> // Generic Buffer Management (native platform for EGL on DRM)
#include <xf86drm.h> // Direct Rendering Manager user-level library interface
#include <xf86drmMode.h> // 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<N>' 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 <stdlib.h> // Required for: srand(), rand(), atexit()
#include <stdio.h> // Required for: sprintf() [Used in OpenURL()]
#include <string.h> // Required for: strrchr(), strcmp(), strlen(), memset()
#include <time.h> // Required for: time() [Used in InitTimer()]
#include <math.h> // 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<N> 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
@ -217,25 +135,16 @@ typedef struct CoreData {
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<N>"
#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
// 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.
@ -245,15 +154,6 @@ typedef struct CoreData {
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;

View file

@ -53,16 +53,32 @@
#include <android_native_app_glue.h> // Required for: android_app struct and activity management
#include <jni.h> // Required for: JNIEnv and JavaVM [Used in OpenURL()]
#include <EGL/egl.h> // 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
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;

View file

@ -85,16 +85,29 @@
#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
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))

View file

@ -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,16 +49,94 @@
#include "rcore.h"
#include <fcntl.h> // POSIX file control definitions - open(), creat(), fcntl()
#include <unistd.h> // POSIX standard function definitions - read(), close(), STDIN_FILENO
#include <termios.h> // POSIX terminal control definitions - tcgetattr(), tcsetattr()
#include <pthread.h> // POSIX threads management (inputs reading)
#include <dirent.h> // POSIX directory browsing
#include <sys/ioctl.h> // Required for: ioctl() - UNIX System call for device-specific input/output operations
#include <linux/kd.h> // Linux: KDSKBMODE, K_MEDIUMRAM constants definition
#include <linux/input.h> // Linux: Keycodes constants definition (KEY_A, ...)
#include <linux/joystick.h> // Linux: Joystick support library
#include <gbm.h> // Generic Buffer Management (native platform for EGL on DRM)
#include <xf86drm.h> // Direct Rendering Manager user-level library interface
#include <xf86drmMode.h> // 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<N> 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<N>' 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<N>"
// 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
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;

View file

@ -50,21 +50,40 @@
#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 <sys/time.h> // Required for: timespec, nanosleep(), select() - POSIX
#include <emscripten/emscripten.h> // Emscripten functionality for C
#include <emscripten/html5.h> // Emscripten HTML5 library
#include <sys/time.h> // Required for: timespec, nanosleep(), select() - POSIX
//----------------------------------------------------------------------------------
// 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
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))

View file

@ -32,7 +32,7 @@
#include <android/asset_manager.h> // 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)