diff --git a/CMakeOptions.txt b/CMakeOptions.txt index 47cb6c559..f39d17a1e 100644 --- a/CMakeOptions.txt +++ b/CMakeOptions.txt @@ -38,6 +38,7 @@ option(SUPPORT_GIF_RECORDING "Allow automatic gif recording of current screen pr option(SUPPORT_BUSY_WAIT_LOOP "Use busy wait loop for timing sync instead of a high-resolution timer" OFF) option(SUPPORT_EVENTS_WAITING "Wait for events passively (sleeping while no events) instead of polling them actively every frame" OFF) option(SUPPORT_HIGH_DPI "Support high DPI displays" OFF) +option(SUPPORT_DATA_STORAGE "Support for persistent data storage" ON) # rlgl.h option(SUPPORT_VR_SIMULATOR "Support VR simulation functionality (stereo rendering)" ON) diff --git a/src/config.h.in b/src/config.h.in index 5f645233e..4cb217b5c 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -21,6 +21,8 @@ #cmakedefine SUPPORT_HIGH_DPI 1 // Support CompressData() and DecompressData() functions #cmakedefine SUPPORT_COMPRESSION_API 1 +// Support for persistent data storage +#cmakedefine SUPPORT_DATA_STORAGE 1 // rlgl.h // Support VR simulation functionality (stereo rendering) diff --git a/src/core.c b/src/core.c index e9c682757..32b30191b 100644 --- a/src/core.c +++ b/src/core.c @@ -333,12 +333,6 @@ typedef struct { bool isKeyboard; // True if device has letter keycodes bool isGamepad; // True if device has gamepad buttons } InputEventWorker; - -typedef struct { - int contents[8]; // Key events FIFO contents (8 positions) - char head; // Key events FIFO head position - char tail; // Key events FIFO tail position -} KeyEventFifo; #endif typedef struct { int x; int y; } Point; @@ -420,7 +414,7 @@ typedef struct CoreData { #if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) int defaultMode; // Default keyboard mode struct termios defaultSettings; // Default keyboard settings - KeyEventFifo lastKeyPressed; // Buffer for holding keydown events as they arrive (Needed due to multitreading of event workers) + int fd; // File descriptor for the evdev keyboard #endif } Keyboard; struct { @@ -559,7 +553,8 @@ static void RestoreTerminal(void); // Restore terminal #endif static void InitEvdevInput(void); // Evdev inputs initialization -static void EventThreadSpawn(char *device); // Identifies a input device and spawns a thread to handle it if needed +static void ConfigureEvdevDevice(char *device); // Identifies a input device and configures it for use if appropriate +static void PollKeyboardEvents(void); // Process evdev keyboard events. static void *EventThread(void *arg); // Input device events reading thread static void InitGamepad(void); // Init raw gamepad input @@ -899,6 +894,13 @@ 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) + { + close(CORE.Input.Keyboard.fd); + CORE.Input.Keyboard.fd = -1; + } + for (int i = 0; i < sizeof(CORE.Input.eventWorker)/sizeof(InputEventWorker); ++i) { if (CORE.Input.eventWorker[i].threadId) @@ -906,6 +908,7 @@ void CloseWindow(void) pthread_join(CORE.Input.eventWorker[i].threadId, NULL); } } + if (CORE.Input.Gamepad.threadId) pthread_join(CORE.Input.Gamepad.threadId, NULL); #endif @@ -4274,15 +4277,8 @@ static void PollInputEvents(void) #if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) // Register previous keys states for (int i = 0; i < 512; i++) CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i]; - - // Grab a keypress from the evdev fifo if avalable - if (CORE.Input.Keyboard.lastKeyPressed.head != CORE.Input.Keyboard.lastKeyPressed.tail) - { - CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = CORE.Input.Keyboard.lastKeyPressed.contents[CORE.Input.Keyboard.lastKeyPressed.tail]; // Read the key from the buffer - CORE.Input.Keyboard.keyPressedQueueCount++; - - CORE.Input.Keyboard.lastKeyPressed.tail = (CORE.Input.Keyboard.lastKeyPressed.tail + 1) & 0x07; // Increment the tail pointer forwards and binary wraparound after 7 (fifo is 8 elements long) - } + + PollKeyboardEvents(); // Register previous mouse states CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove; @@ -5352,6 +5348,9 @@ static void InitEvdevInput(void) char path[MAX_FILEPATH_LENGTH]; DIR *directory; struct dirent *entity; + + // Initialise keyboard file descriptor + CORE.Input.Keyboard.fd = -1; // Reset variables for (int i = 0; i < MAX_TOUCH_POINTS; ++i) @@ -5360,10 +5359,6 @@ static void InitEvdevInput(void) CORE.Input.Touch.position[i].y = -1; } - // Reset keypress buffer - CORE.Input.Keyboard.lastKeyPressed.head = 0; - CORE.Input.Keyboard.lastKeyPressed.tail = 0; - // Reset keyboard key state for (int i = 0; i < 512; i++) CORE.Input.Keyboard.currentKeyState[i] = 0; @@ -5377,7 +5372,7 @@ static void InitEvdevInput(void) if (strncmp("event", entity->d_name, strlen("event")) == 0) // Search for devices named "event*" { sprintf(path, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name); - EventThreadSpawn(path); // Identify the device and spawn a thread for it + ConfigureEvdevDevice(path); // Configure the device if appropriate } } @@ -5386,8 +5381,8 @@ static void InitEvdevInput(void) else TRACELOG(LOG_WARNING, "RPI: Failed to open linux event directory: %s", DEFAULT_EVDEV_PATH); } -// Identifies a input device and spawns a thread to handle it if needed -static void EventThreadSpawn(char *device) +// Identifies a input device and configures it for use if appropriate +static void ConfigureEvdevDevice(char *device) { #define BITS_PER_LONG (8*sizeof(long)) #define NBITS(x) ((((x) - 1)/BITS_PER_LONG) + 1) @@ -5459,7 +5454,7 @@ static void EventThreadSpawn(char *device) // Identify the device //------------------------------------------------------------------------------------------------------- - ioctl(fd, EVIOCGBIT(0, sizeof(evBits)), evBits); // Read a bitfield of the avalable device properties + ioctl(fd, EVIOCGBIT(0, sizeof(evBits)), evBits); // Read a bitfield of the available device properties // Check for absolute input devices if (TEST_BIT(evBits, EV_ABS)) @@ -5535,15 +5530,22 @@ static void EventThreadSpawn(char *device) // Decide what to do with the device //------------------------------------------------------------------------------------------------------- - if (worker->isTouch || worker->isMouse || worker->isKeyboard) + if (worker->isKeyboard && CORE.Input.Keyboard.fd == -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; + } + else if (worker->isTouch || worker->isMouse) { // Looks like an interesting device - TRACELOG(LOG_INFO, "RPI: Opening input device: %s (%s%s%s%s%s)", device, + TRACELOG(LOG_INFO, "RPI: Opening input device: %s (%s%s%s%s)", device, worker->isMouse? "mouse " : "", worker->isMultitouch? "multitouch " : "", worker->isTouch? "touchscreen " : "", - worker->isGamepad? "gamepad " : "", - worker->isKeyboard? "keyboard " : ""); + worker->isGamepad? "gamepad " : ""); // Create a thread for this device int error = pthread_create(&worker->threadId, NULL, &EventThread, (void *)worker); @@ -5563,7 +5565,7 @@ static void EventThreadSpawn(char *device) if (CORE.Input.eventWorker[i].isTouch && (CORE.Input.eventWorker[i].eventNum > maxTouchNumber)) maxTouchNumber = CORE.Input.eventWorker[i].eventNum; } - // Find toucnscreens with lower indexes + // Find touchscreens with lower indexes for (int i = 0; i < sizeof(CORE.Input.eventWorker)/sizeof(InputEventWorker); ++i) { if (CORE.Input.eventWorker[i].isTouch && (CORE.Input.eventWorker[i].eventNum < maxTouchNumber)) @@ -5582,8 +5584,7 @@ static void EventThreadSpawn(char *device) //------------------------------------------------------------------------------------------------------- } -// Input device events reading thread -static void *EventThread(void *arg) +static void PollKeyboardEvents(void) { // Scancode to keycode mapping for US keyboards // TODO: Probably replace this with a keymap from the X11 to get the correct regional map for the keyboard: @@ -5605,12 +5606,62 @@ static void *EventThread(void *arg) 227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242, 243,244,245,246,247,248,0,0,0,0,0,0,0, }; + int fd = CORE.Input.Keyboard.fd; + if (fd == -1) return; + + struct input_event event; + int keycode; + + // Try to read data from the keyboard and only continue if successful + while (read(fd, &event, sizeof(event)) == (int)sizeof(event)) + { + // Button parsing + if (event.type == EV_KEY) + { + // Keyboard button parsing + if ((event.code >= 1) && (event.code <= 255)) //Keyboard keys appear for codes 1 to 255 + { + keycode = keymap_US[event.code & 0xFF]; // The code we get is a scancode so we look up the apropriate keycode + + // Make sure we got a valid keycode + if ((keycode > 0) && (keycode < sizeof(CORE.Input.Keyboard.currentKeyState))) + { + // WARNING: https://www.kernel.org/doc/Documentation/input/input.txt + // Event interface: 'value' is the value the event carries. Either a relative change for EV_REL, + // absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for release, 1 for keypress and 2 for autorepeat + CORE.Input.Keyboard.currentKeyState[keycode] = (event.value >= 1)? 1 : 0; + if (event.value >= 1) + { + CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = keycode; // Register last key pressed + CORE.Input.Keyboard.keyPressedQueueCount++; + } + + #if defined(SUPPORT_SCREEN_CAPTURE) + // Check screen capture key (raylib key: KEY_F12) + if (CORE.Input.Keyboard.currentKeyState[301] == 1) + { + TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter)); + screenshotCounter++; + } + #endif + + if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey] == 1) CORE.Window.shouldClose = true; + + TRACELOGD("RPI: KEY_%s ScanCode: %4i KeyCode: %4i", event.value == 0 ? "UP":"DOWN", event.code, keycode); + } + } + } + } +} + +// Input device events reading thread +static void *EventThread(void *arg) +{ struct input_event event; InputEventWorker *worker = (InputEventWorker *)arg; int touchAction = -1; bool gestureUpdate = false; - int keycode; while (!CORE.Window.shouldClose) { @@ -5710,39 +5761,6 @@ static void *EventThread(void *arg) if (event.code == BTN_RIGHT) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_RIGHT_BUTTON] = event.value; if (event.code == BTN_MIDDLE) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_MIDDLE_BUTTON] = event.value; - - // Keyboard button parsing - if ((event.code >= 1) && (event.code <= 255)) //Keyboard keys appear for codes 1 to 255 - { - keycode = keymap_US[event.code & 0xFF]; // The code we get is a scancode so we look up the apropriate keycode - - // Make sure we got a valid keycode - if ((keycode > 0) && (keycode < sizeof(CORE.Input.Keyboard.currentKeyState))) - { - // WARNING: https://www.kernel.org/doc/Documentation/input/input.txt - // Event interface: 'value' is the value the event carries. Either a relative change for EV_REL, - // absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for release, 1 for keypress and 2 for autorepeat - CORE.Input.Keyboard.currentKeyState[keycode] = (event.value >= 1)? 1 : 0; - if (event.value >= 1) - { - CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = keycode; // Register last key pressed - CORE.Input.Keyboard.keyPressedQueueCount++; - } - - #if defined(SUPPORT_SCREEN_CAPTURE) - // Check screen capture key (raylib key: KEY_F12) - if (CORE.Input.Keyboard.currentKeyState[301] == 1) - { - TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter)); - screenshotCounter++; - } - #endif - - if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey] == 1) CORE.Window.shouldClose = true; - - TRACELOGD("RPI: KEY_%s ScanCode: %4i KeyCode: %4i", event.value == 0 ? "UP":"DOWN", event.code, keycode); - } - } } // Screen confinement diff --git a/src/rlgl.h b/src/rlgl.h index 3d327a6f9..572e86c47 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -1100,9 +1100,12 @@ void rlFrustum(double left, double right, double bottom, double top, double znea // Multiply the current matrix by an orthographic matrix generated by parameters void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar) { - Matrix matOrtho = MatrixOrtho(left, right, bottom, top, znear, zfar); - - *RLGL.State.currentMatrix = MatrixMultiply(*RLGL.State.currentMatrix, matOrtho); + if (((right - left) > 0) && ((bottom - top) > 0)) + { + Matrix matOrtho = MatrixOrtho(left, right, bottom, top, znear, zfar); + *RLGL.State.currentMatrix = MatrixMultiply(*RLGL.State.currentMatrix, matOrtho); + } + else *RLGL.State.currentMatrix = MatrixIdentity(); } #endif @@ -4788,8 +4791,8 @@ static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight) // Count mipmap levels required while ((width != 1) && (height != 1)) { - if (width != 1) width /= 2; - if (height != 1) height /= 2; + width /= 2; + height /= 2; TRACELOGD("TEXTURE: Next mipmap size: %i x %i", width, height);