aboutsummaryrefslogtreecommitdiff
path: root/raylib/src/rcore.c
diff options
context:
space:
mode:
authorUneven Prankster <unevenprankster@protonmail.com>2023-11-16 21:12:27 -0300
committerUneven Prankster <unevenprankster@protonmail.com>2023-11-16 21:12:27 -0300
commit2bbf92ad5ae7708bf18ac7ef333e9a979d8d1bde (patch)
treec9d22bb0d73d9cc0c8586e4d31c93a561ea8e910 /raylib/src/rcore.c
parent1c0cc775732201f4c4d3ee0d6772be786b3b4aa1 (diff)
Working so hard like a soldiermain
Can't afford a thing on TV
Diffstat (limited to 'raylib/src/rcore.c')
-rw-r--r--raylib/src/rcore.c1319
1 files changed, 954 insertions, 365 deletions
diff --git a/raylib/src/rcore.c b/raylib/src/rcore.c
index f94731f..4539889 100644
--- a/raylib/src/rcore.c
+++ b/raylib/src/rcore.c
@@ -3,14 +3,22 @@
* 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_DESKTOP (GLFW backend):
+* - Windows (Win32, Win64)
+* - Linux (X11/Wayland desktop mode)
+* - macOS/OSX (x64, arm64)
+* - FreeBSD, OpenBSD, NetBSD, DragonFly (X11 desktop)
+* > PLATFORM_DESKTOP_SDL (SDL backend):
+* - Windows (Win32, Win64)
+* - Linux (X11/Wayland desktop mode)
+* - Others (not tested)
+* > PLATFORM_WEB:
+* - HTML5 (WebAssembly)
+* > PLATFORM_DRM:
+* - Raspberry Pi 0-5 (DRM/KMS)
+* - Linux DRM subsystem (KMS mode)
+* > PLATFORM_ANDROID:
+* - Android (ARM, ARM64)
*
* CONFIGURATION:
* #define SUPPORT_DEFAULT_FONT (default)
@@ -44,8 +52,8 @@
* provided by stb_image and stb_image_write libraries, so, those libraries must be enabled on textures module
* for linkage
*
-* #define SUPPORT_EVENTS_AUTOMATION
-* Support automatic generated events, loading and recording of those events when required
+* #define SUPPORT_AUTOMATION_EVENTS
+* Support automatic events recording and playing, useful for automated testing systems or AI based game playing
*
* DEPENDENCIES:
* raymath - 3D math functionality (Vector2, Vector3, Matrix, Quaternion)
@@ -81,12 +89,19 @@
#include "config.h" // Defines module configuration flags
#endif
-#include "rcore.h" // Defines types and globals
+#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()]
#define RLGL_IMPLEMENTATION
#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
-#include "raymath.h" // Vector3, Quaternion and Matrix functionality
+#define RAYMATH_IMPLEMENTATION
+#include "raymath.h" // Vector2, Vector3, Quaternion and Matrix functionality
#if defined(SUPPORT_GESTURES_SYSTEM)
#define RGESTURES_IMPLEMENTATION
@@ -116,6 +131,11 @@
#include "external/sdefl.h" // Deflate (RFC 1951) compressor
#endif
+#if defined(SUPPORT_RPRAND_GENERATOR)
+ #define RPRAND_IMPLEMENTATION
+ #include "external/rprand.h"
+#endif
+
#if defined(__linux__) && !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
@@ -163,6 +183,166 @@ __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigne
#endif
//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+#ifndef MAX_FILEPATH_CAPACITY
+ #define MAX_FILEPATH_CAPACITY 8192 // Maximum capacity for filepath
+#endif
+#ifndef MAX_FILEPATH_LENGTH
+ #if defined(_WIN32)
+ #define MAX_FILEPATH_LENGTH 256 // On Win32, MAX_PATH = 260 (limits.h) but Windows 10, Version 1607 enables long paths...
+ #else
+ #define MAX_FILEPATH_LENGTH 4096 // On Linux, PATH_MAX = 4096 by default (limits.h)
+ #endif
+#endif
+
+#ifndef MAX_KEYBOARD_KEYS
+ #define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported
+#endif
+#ifndef MAX_MOUSE_BUTTONS
+ #define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported
+#endif
+#ifndef MAX_GAMEPADS
+ #define MAX_GAMEPADS 4 // Maximum number of gamepads supported
+#endif
+#ifndef MAX_GAMEPAD_AXIS
+ #define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad)
+#endif
+#ifndef MAX_GAMEPAD_BUTTONS
+ #define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
+#endif
+#ifndef MAX_TOUCH_POINTS
+ #define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
+#endif
+#ifndef MAX_KEY_PRESSED_QUEUE
+ #define MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue
+#endif
+#ifndef MAX_CHAR_PRESSED_QUEUE
+ #define MAX_CHAR_PRESSED_QUEUE 16 // Maximum number of characters in the char input queue
+#endif
+
+#ifndef MAX_DECOMPRESSION_SIZE
+ #define MAX_DECOMPRESSION_SIZE 64 // Maximum size allocated for decompression in MB
+#endif
+
+#ifndef MAX_AUTOMATION_EVENTS
+ #define MAX_AUTOMATION_EVENTS 16384 // Maximum number of automation events to record
+#endif
+
+// Flags operation macros
+#define FLAG_SET(n, f) ((n) |= (f))
+#define FLAG_CLEAR(n, f) ((n) &= ~(f))
+#define FLAG_TOGGLE(n, f) ((n) ^= (f))
+#define FLAG_CHECK(n, f) ((n) & (f))
+
+#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.
+#endif
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef struct { int x; int y; } Point;
+typedef struct { unsigned int width; unsigned int height; } Size;
+
+// Core global state context data
+typedef struct CoreData {
+ struct {
+ 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
+ bool fullscreen; // Check if fullscreen mode is enabled
+ bool shouldClose; // Check if window set for closing
+ bool resizedLastFrame; // Check if window has been resized last frame
+ bool eventWaiting; // Wait for events before ending frame
+ bool usingFbo; // Using FBO (RenderTexture) for rendering instead of default framebuffer
+
+ Point position; // Window position (required on fullscreen toggle)
+ Point previousPosition; // Window previous position (required on borderless windowed toggle)
+ Size display; // Display width and height (monitor, device-screen, LCD, ...)
+ Size screen; // Screen width and height (used render area)
+ Size previousScreen; // Screen previous width and height (required on borderless windowed toggle)
+ Size currentFbo; // Current render width and height (depends on active fbo)
+ Size render; // Framebuffer width and height (render area, including black bars if required)
+ Point renderOffset; // Offset from render area (must be divided by 2)
+ Size screenMin; // Screen minimum width and height (for resizable window)
+ Size screenMax; // Screen maximum width and height (for resizable window)
+ Matrix screenScale; // Matrix to scale screen (framebuffer rendering)
+
+ char **dropFilepaths; // Store dropped files paths pointers (provided by GLFW)
+ unsigned int dropFileCount; // Count dropped files strings
+
+ } Window;
+ struct {
+ const char *basePath; // Base path for data storage
+
+ } Storage;
+ struct {
+ 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.
+
+ int keyPressedQueue[MAX_KEY_PRESSED_QUEUE]; // Input keys queue
+ int keyPressedQueueCount; // Input keys queue count
+
+ int charPressedQueue[MAX_CHAR_PRESSED_QUEUE]; // Input characters queue (unicode)
+ int charPressedQueueCount; // Input characters queue count
+
+ } Keyboard;
+ struct {
+ Vector2 offset; // Mouse offset
+ Vector2 scale; // Mouse scaling
+ Vector2 currentPosition; // Mouse position on screen
+ Vector2 previousPosition; // Previous mouse position
+
+ int cursor; // Tracks current mouse cursor
+ bool cursorHidden; // Track if cursor is hidden
+ bool cursorOnScreen; // Tracks if cursor is inside client area
+
+ char currentButtonState[MAX_MOUSE_BUTTONS]; // Registers current mouse button state
+ char previousButtonState[MAX_MOUSE_BUTTONS]; // Registers previous mouse button state
+ Vector2 currentWheelMove; // Registers current mouse wheel variation
+ Vector2 previousWheelMove; // Registers previous mouse wheel variation
+
+ } Mouse;
+ struct {
+ int pointCount; // Number of touch points active
+ int pointId[MAX_TOUCH_POINTS]; // Point identifiers
+ 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
+ int axisCount[MAX_GAMEPADS]; // Register number of available gamepad axis
+ bool ready[MAX_GAMEPADS]; // Flag to know if gamepad is ready
+ char name[MAX_GAMEPADS][64]; // Gamepad name holder
+ 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
+
+ } Gamepad;
+ } Input;
+ struct {
+ double current; // Current time measure
+ double previous; // Previous time measure
+ double update; // Time measure for frame update
+ 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
+ unsigned long long int base; // Base time measure for hi-res timer (PLATFORM_ANDROID, PLATFORM_DRM)
+ unsigned int frameCounter; // Frame counter
+
+ } Time;
+} CoreData;
+
+//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
RLAPI const char *raylib_version = RAYLIB_VERSION; // raylib version exported symbol, required for some bindings
@@ -179,9 +359,8 @@ bool gifRecording = false; // GIF recording state
MsfGifState gifState = { 0 }; // MSGIF context state
#endif
-#if defined(SUPPORT_EVENTS_AUTOMATION)
-#define MAX_CODE_AUTOMATION_EVENTS 16384
-
+#if defined(SUPPORT_AUTOMATION_EVENTS)
+// Automation events type
typedef enum AutomationEventType {
EVENT_NONE = 0,
// Input events
@@ -208,12 +387,12 @@ typedef enum AutomationEventType {
WINDOW_MINIMIZE, // no params
WINDOW_RESIZE, // param[0]: width, param[1]: height
// Custom events
- ACTION_TAKE_SCREENSHOT,
- ACTION_SETTARGETFPS
+ ACTION_TAKE_SCREENSHOT, // no params
+ ACTION_SETTARGETFPS // param[0]: fps
} AutomationEventType;
-// Event type
-// Used to enable events flags
+// Event type to config events flags
+// TODO: Not used at the moment
typedef enum {
EVENT_INPUT_KEYBOARD = 0,
EVENT_INPUT_MOUSE = 1,
@@ -224,6 +403,7 @@ typedef enum {
EVENT_CUSTOM = 32
} EventType;
+// Event type name strings, required for export
static const char *autoEventTypeName[] = {
"EVENT_NONE",
"INPUT_KEY_UP",
@@ -251,19 +431,19 @@ static const char *autoEventTypeName[] = {
"ACTION_SETTARGETFPS"
};
+/*
// Automation event (24 bytes)
-typedef struct AutomationEvent {
+// NOTE: Opaque struct, internal to raylib
+struct AutomationEvent {
unsigned int frame; // Event frame
unsigned int type; // Event type (AutomationEventType)
int params[4]; // Event parameters (if required)
-} AutomationEvent;
-
-static AutomationEvent *events = NULL; // Events array
-static unsigned int eventCount = 0; // Events count
-static bool eventsPlaying = false; // Play events
-static bool eventsRecording = false; // Record events
+};
+*/
-//static short eventsEnabled = 0b0000001111111111; // Events enabled for checking
+static AutomationEventList *currentEventList = NULL; // Current automation events list, set by user, keep internal pointer
+static bool automationEventRecording = false; // Recording automation events flag
+//static short automationEventEnabled = 0b0000001111111111; // TODO: Automation events enabled for recording/playing
#endif
//-----------------------------------------------------------------------------------
@@ -277,18 +457,18 @@ extern void LoadFontDefault(void); // [Module: text] Loads default font on
extern void UnloadFontDefault(void); // [Module: text] Unloads default font from GPU memory
#endif
-static void InitTimer(void); // Initialize timer (hi-resolution if available)
-static void SetupFramebuffer(int width, int height); // Setup main framebuffer
+extern int InitPlatform(void); // Initialize platform (graphics, inputs and more)
+extern void ClosePlatform(void); // Close platform
+
+static void InitTimer(void); // Initialize timer, hi-resolution if available (required by InitPlatform())
+static void SetupFramebuffer(int width, int height); // Setup main framebuffer (required by InitPlatform())
static void SetupViewport(int width, int height); // Set viewport for a provided width and height
static void ScanDirectoryFiles(const char *basePath, FilePathList *list, const char *filter); // Scan all files and directories in a base path
static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *list, const char *filter); // Scan all files and directories recursively from a base path
-#if defined(SUPPORT_EVENTS_AUTOMATION)
-static void LoadAutomationEvents(const char *fileName); // Load automation events from file
-static void ExportAutomationEvents(const char *fileName); // Export recorded automation events into a file
-static void RecordAutomationEvent(unsigned int frame); // Record frame events (to internal events array)
-static void PlayAutomationEvent(unsigned int frame); // Play frame events (from internal events array)
+#if defined(SUPPORT_AUTOMATION_EVENTS)
+static void RecordAutomationEvent(void); // Record frame events (to internal events array)
#endif
#if defined(_WIN32)
@@ -297,18 +477,20 @@ void __stdcall Sleep(unsigned long msTimeout); // Required for: Wai
#endif
#if !defined(SUPPORT_MODULE_RTEXT)
-const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed'
+const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed'
#endif // !SUPPORT_MODULE_RTEXT
// Include platform-specific submodules
#if defined(PLATFORM_DESKTOP)
- #include "rcore_desktop.c"
+ #include "platforms/rcore_desktop.c"
+#elif defined(PLATFORM_DESKTOP_SDL)
+ #include "platforms/rcore_desktop_sdl.c"
#elif defined(PLATFORM_WEB)
- #include "rcore_web.c"
+ #include "platforms/rcore_web.c"
#elif defined(PLATFORM_DRM)
- #include "rcore_drm.c"
+ #include "platforms/rcore_drm.c"
#elif defined(PLATFORM_ANDROID)
- #include "rcore_android.c"
+ #include "platforms/rcore_android.c"
#else
// TODO: Include your custom platform backend!
// i.e software rendering backend or console backend!
@@ -319,8 +501,6 @@ const char *TextFormat(const char *text, ...); // Formatting of text with
//----------------------------------------------------------------------------------
// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
-//void InitWindow(int width, int height, const char *title)
-//void CloseWindow(void)
//bool WindowShouldClose(void)
//void ToggleFullscreen(void)
//void ToggleBorderlessWindowed(void)
@@ -363,6 +543,154 @@ const char *TextFormat(const char *text, ...); // Formatting of text with
//void EnableCursor(void)
//void DisableCursor(void)
+// Initialize window and OpenGL context
+// NOTE: data parameter could be used to pass any kind of required data to the initialization
+void InitWindow(int width, int height, const char *title)
+{
+ TRACELOG(LOG_INFO, "Initializing raylib %s", RAYLIB_VERSION);
+
+#if defined(PLATFORM_DESKTOP)
+ TRACELOG(LOG_INFO, "Platform backend: DESKTOP (GLFW)");
+#elif defined(PLATFORM_DESKTOP_SDL)
+ TRACELOG(LOG_INFO, "Platform backend: DESKTOP (SDL)");
+#elif defined(PLATFORM_WEB)
+ TRACELOG(LOG_INFO, "Platform backend: WEB (HTML5)");
+#elif defined(PLATFORM_DRM)
+ TRACELOG(LOG_INFO, "Platform backend: NATIVE DRM");
+#elif defined(PLATFORM_ANDROID)
+ TRACELOG(LOG_INFO, "Platform backend: ANDROID");
+#else
+ // TODO: Include your custom platform backend!
+ // i.e software rendering backend or console backend!
+ TRACELOG(LOG_INFO, "Platform backend: CUSTOM");
+#endif
+
+ TRACELOG(LOG_INFO, "Supported raylib modules:");
+ TRACELOG(LOG_INFO, " > rcore:..... loaded (mandatory)");
+ TRACELOG(LOG_INFO, " > rlgl:...... loaded (mandatory)");
+#if defined(SUPPORT_MODULE_RSHAPES)
+ TRACELOG(LOG_INFO, " > rshapes:... loaded (optional)");
+#else
+ TRACELOG(LOG_INFO, " > rshapes:... not loaded (optional)");
+#endif
+#if defined(SUPPORT_MODULE_RTEXTURES)
+ TRACELOG(LOG_INFO, " > rtextures:. loaded (optional)");
+#else
+ TRACELOG(LOG_INFO, " > rtextures:. not loaded (optional)");
+#endif
+#if defined(SUPPORT_MODULE_RTEXT)
+ TRACELOG(LOG_INFO, " > rtext:..... loaded (optional)");
+#else
+ TRACELOG(LOG_INFO, " > rtext:..... not loaded (optional)");
+#endif
+#if defined(SUPPORT_MODULE_RMODELS)
+ TRACELOG(LOG_INFO, " > rmodels:... loaded (optional)");
+#else
+ TRACELOG(LOG_INFO, " > rmodels:... not loaded (optional)");
+#endif
+#if defined(SUPPORT_MODULE_RAUDIO)
+ TRACELOG(LOG_INFO, " > raudio:.... loaded (optional)");
+#else
+ TRACELOG(LOG_INFO, " > raudio:.... not loaded (optional)");
+#endif
+
+ // Initialize window data
+ CORE.Window.screen.width = width;
+ CORE.Window.screen.height = height;
+ CORE.Window.eventWaiting = false;
+ CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default
+ if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title;
+
+ // Initialize global input state
+ memset(&CORE.Input, 0, sizeof(CORE.Input)); // Reset CORE.Input structure to 0
+ CORE.Input.Keyboard.exitKey = KEY_ESCAPE;
+ CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f };
+ CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW;
+ CORE.Input.Gamepad.lastButtonPressed = GAMEPAD_BUTTON_UNKNOWN;
+
+ // Initialize platform
+ //--------------------------------------------------------------
+ InitPlatform();
+ //--------------------------------------------------------------
+
+ // Initialize rlgl default data (buffers and shaders)
+ // NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
+ rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
+
+ // Setup default viewport
+ SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
+
+#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
+ // Load default font
+ // WARNING: External function: Module required: rtext
+ LoadFontDefault();
+ #if defined(SUPPORT_MODULE_RSHAPES)
+ // Set font white rectangle for shapes drawing, so shapes and text can be batched together
+ // WARNING: rshapes module is required, if not available, default internal white rectangle is used
+ Rectangle rec = GetFontDefault().recs[95];
+ if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
+ {
+ // NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering
+ SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 });
+ }
+ else
+ {
+ // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding
+ SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 });
+ }
+ #endif
+#else
+ #if defined(SUPPORT_MODULE_RSHAPES)
+ // Set default texture and rectangle to be used for shapes drawing
+ // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
+ Texture2D texture = { rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
+ SetShapesTexture(texture, (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f }); // WARNING: Module required: rshapes
+ #endif
+#endif
+#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
+ if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
+ {
+ // Set default font texture filter for HighDPI (blurry)
+ // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
+ rlTextureParameters(GetFontDefault().texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR);
+ rlTextureParameters(GetFontDefault().texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);
+ }
+#endif
+
+ CORE.Time.frameCounter = 0;
+ CORE.Window.shouldClose = false;
+
+ // Initialize random seed
+ SetRandomSeed((unsigned int)time(NULL));
+}
+
+// Close window and unload OpenGL context
+void CloseWindow(void)
+{
+#if defined(SUPPORT_GIF_RECORDING)
+ if (gifRecording)
+ {
+ MsfGifResult result = msf_gif_end(&gifState);
+ msf_gif_free(result);
+ gifRecording = false;
+ }
+#endif
+
+#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
+ UnloadFontDefault(); // WARNING: Module required: rtext
+#endif
+
+ rlglClose(); // De-init rlgl
+
+ // De-initialize platform
+ //--------------------------------------------------------------
+ ClosePlatform();
+ //--------------------------------------------------------------
+
+ CORE.Window.ready = false;
+ TRACELOG(LOG_INFO, "Window closed successfully");
+}
+
// Check if window has been initialized successfully
bool IsWindowReady(void)
{
@@ -426,13 +754,27 @@ int GetScreenHeight(void)
// Get current render width which is equal to screen width*dpi scale
int GetRenderWidth(void)
{
- return CORE.Window.render.width;
+ int width = 0;
+#if defined(__APPLE__)
+ Vector2 scale = GetWindowScaleDPI();
+ width = (int)((float)CORE.Window.render.width*scale.x);
+#else
+ width = CORE.Window.render.width;
+#endif
+ return width;
}
// Get current screen height which is equal to screen height*dpi scale
int GetRenderHeight(void)
{
- return CORE.Window.render.height;
+ int height = 0;
+#if defined(__APPLE__)
+ Vector2 scale = GetWindowScaleDPI();
+ height = (int)((float)CORE.Window.render.height*scale.y);
+#else
+ height = CORE.Window.render.height;
+#endif
+ return height;
}
// Enable waiting for events on EndDrawing(), no automatic event polling
@@ -523,32 +865,8 @@ void EndDrawing(void)
}
#endif
-#if defined(SUPPORT_EVENTS_AUTOMATION)
- // Draw record/play indicator
- if (eventsRecording)
- {
- gifFrameCounter++;
-
- if (((gifFrameCounter/15)%2) == 1)
- {
- DrawCircle(30, CORE.Window.screen.height - 20, 10, MAROON);
- DrawText("EVENTS RECORDING", 50, CORE.Window.screen.height - 25, 10, RED);
- }
-
- rlDrawRenderBatchActive(); // Update and draw internal render batch
- }
- else if (eventsPlaying)
- {
- gifFrameCounter++;
-
- if (((gifFrameCounter/15)%2) == 1)
- {
- DrawCircle(30, CORE.Window.screen.height - 20, 10, LIME);
- DrawText("EVENTS PLAYING", 50, CORE.Window.screen.height - 25, 10, GREEN);
- }
-
- rlDrawRenderBatchActive(); // Update and draw internal render batch
- }
+#if defined(SUPPORT_AUTOMATION_EVENTS)
+ if (automationEventRecording) RecordAutomationEvent(); // Event recording
#endif
#if !defined(SUPPORT_CUSTOM_FRAME_CONTROL)
@@ -576,16 +894,43 @@ void EndDrawing(void)
PollInputEvents(); // Poll user events (before next frame update)
#endif
-#if defined(SUPPORT_EVENTS_AUTOMATION)
- // Events recording and playing logic
- if (eventsRecording) RecordAutomationEvent(CORE.Time.frameCounter);
- else if (eventsPlaying)
+#if defined(SUPPORT_SCREEN_CAPTURE)
+ if (IsKeyPressed(KEY_F12))
{
- // TODO: When should we play? After/before/replace PollInputEvents()?
- if (CORE.Time.frameCounter >= eventCount) eventsPlaying = false;
- PlayAutomationEvent(CORE.Time.frameCounter);
+#if defined(SUPPORT_GIF_RECORDING)
+ if (IsKeyDown(KEY_LEFT_CONTROL))
+ {
+ if (gifRecording)
+ {
+ gifRecording = false;
+
+ MsfGifResult result = msf_gif_end(&gifState);
+
+ SaveFileData(TextFormat("%s/screenrec%03i.gif", CORE.Storage.basePath, screenshotCounter), result.data, (unsigned int)result.dataSize);
+ msf_gif_free(result);
+
+ TRACELOG(LOG_INFO, "SYSTEM: Finish animated GIF recording");
+ }
+ else
+ {
+ gifRecording = true;
+ gifFrameCounter = 0;
+
+ Vector2 scale = GetWindowScaleDPI();
+ msf_gif_begin(&gifState, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y));
+ screenshotCounter++;
+
+ TRACELOG(LOG_INFO, "SYSTEM: Start animated GIF recording: %s", TextFormat("screenrec%03i.gif", screenshotCounter));
+ }
+ }
+ else
+#endif // SUPPORT_GIF_RECORDING
+ {
+ TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter));
+ screenshotCounter++;
+ }
}
-#endif
+#endif // SUPPORT_SCREEN_CAPTURE
CORE.Time.frameCounter++;
}
@@ -696,6 +1041,7 @@ void BeginTextureMode(RenderTexture2D target)
// calculation when using BeginMode3D()
CORE.Window.currentFbo.width = target.texture.width;
CORE.Window.currentFbo.height = target.texture.height;
+ CORE.Window.usingFbo = true;
}
// Ends drawing to render texture
@@ -711,6 +1057,7 @@ void EndTextureMode(void)
// Reset current fbo to screen size
CORE.Window.currentFbo.width = CORE.Window.render.width;
CORE.Window.currentFbo.height = CORE.Window.render.height;
+ CORE.Window.usingFbo = false;
}
// Begin custom shader mode
@@ -747,19 +1094,22 @@ void BeginScissorMode(int x, int y, int width, int height)
rlEnableScissorTest();
#if defined(__APPLE__)
- Vector2 scale = GetWindowScaleDPI();
- rlScissor((int)(x*scale.x), (int)(GetScreenHeight()*scale.y - (((y + height)*scale.y))), (int)(width*scale.x), (int)(height*scale.y));
+ if (!CORE.Window.usingFbo)
+ {
+ Vector2 scale = GetWindowScaleDPI();
+ rlScissor((int)(x*scale.x), (int)(GetScreenHeight()*scale.y - (((y + height)*scale.y))), (int)(width*scale.x), (int)(height*scale.y));
+ }
#else
- if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
+ if (!CORE.Window.usingFbo && ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0))
{
Vector2 scale = GetWindowScaleDPI();
rlScissor((int)(x*scale.x), (int)(CORE.Window.currentFbo.height - (y + height)*scale.y), (int)(width*scale.x), (int)(height*scale.y));
}
+#endif
else
{
rlScissor(x, CORE.Window.currentFbo.height - (y + height), width, height);
}
-#endif
}
// End scissor mode
@@ -1233,6 +1583,16 @@ int GetFPS(void)
static float average = 0, last = 0;
float fpsFrame = GetFrameTime();
+ // if we reset the window, reset the FPS info
+ if (CORE.Time.frameCounter == 0)
+ {
+ average = 0;
+ last = 0;
+ index = 0;
+
+ for (int i = 0; i < FPS_CAPTURE_FRAMES_COUNT; i++) history[i] = 0;
+ }
+
if (fpsFrame == 0) return 0;
if ((GetTime() - last) > FPS_STEP)
@@ -1261,7 +1621,7 @@ float GetFrameTime(void)
//----------------------------------------------------------------------------------
// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
-//void SwapScreenBuffer(void);
+//void SwapScreenBuffer(void);
//void PollInputEvents(void);
// Wait for some time (stop program execution)
@@ -1272,7 +1632,7 @@ float GetFrameTime(void)
void WaitTime(double seconds)
{
if (seconds < 0) return;
-
+
#if defined(SUPPORT_BUSY_WAIT_LOOP) || defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
double destinationTime = GetTime() + seconds;
#endif
@@ -1317,12 +1677,22 @@ void WaitTime(double seconds)
// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
//void OpenURL(const char *url)
-// Get a random value between min and max (both included)
-// WARNING: Ranges higher than RAND_MAX will return invalid results
-// More specifically, if (max - min) > INT_MAX there will be an overflow,
-// and otherwise if (max - min) > RAND_MAX the random value will incorrectly never exceed a certain threshold
+
+// Set the seed for the random number generator
+void SetRandomSeed(unsigned int seed)
+{
+#if defined(SUPPORT_RPRAND_GENERATOR)
+ rprand_set_seed(seed);
+#else
+ srand(seed);
+#endif
+}
+
+// Get a random value between min and max included
int GetRandomValue(int min, int max)
{
+ int value = 0;
+
if (min > max)
{
int tmp = max;
@@ -1330,21 +1700,74 @@ int GetRandomValue(int min, int max)
min = tmp;
}
+#if defined(SUPPORT_RPRAND_GENERATOR)
+ value = rprand_get_value(min, max);
+#else
+ // WARNING: Ranges higher than RAND_MAX will return invalid results
+ // More specifically, if (max - min) > INT_MAX there will be an overflow,
+ // and otherwise if (max - min) > RAND_MAX the random value will incorrectly never exceed a certain threshold
+ // NOTE: Depending on the library it can be as low as 32767
if ((unsigned int)(max - min) > (unsigned int)RAND_MAX)
{
TRACELOG(LOG_WARNING, "Invalid GetRandomValue() arguments, range should not be higher than %i", RAND_MAX);
}
- return (rand()%(abs(max - min) + 1) + min);
+ value = (rand()%(abs(max - min) + 1) + min);
+#endif
+ return value;
}
-// Set the seed for the random number generator
-void SetRandomSeed(unsigned int seed)
+// Load random values sequence, no values repeated, min and max included
+int *LoadRandomSequence(unsigned int count, int min, int max)
{
- srand(seed);
+ int *values = NULL;
+
+#if defined(SUPPORT_RPRAND_GENERATOR)
+ values = rprand_load_sequence(count, min, max);
+#else
+ if (count > ((unsigned int)abs(max - min) + 1)) return values;
+
+ values = (int *)RL_CALLOC(count, sizeof(int));
+
+ int value = 0;
+ bool dupValue = false;
+
+ for (int i = 0; i < (int)count;)
+ {
+ value = (rand()%(abs(max - min) + 1) + min);
+ dupValue = false;
+
+ for (int j = 0; j < i; j++)
+ {
+ if (values[j] == value)
+ {
+ dupValue = true;
+ break;
+ }
+ }
+
+ if (!dupValue)
+ {
+ values[i] = value;
+ i++;
+ }
+ }
+#endif
+ return values;
}
-// Takes a screenshot of current screen (saved a .png)
+// Unload random values sequence
+void UnloadRandomSequence(int *sequence)
+{
+#if defined(SUPPORT_RPRAND_GENERATOR)
+ rprand_unload_sequence(sequence);
+#else
+ RL_FREE(sequence);
+#endif
+}
+
+// Takes a screenshot of current screen
+// NOTE: Provided fileName should not contain paths, saving to working directory
void TakeScreenshot(const char *fileName)
{
#if defined(SUPPORT_MODULE_RTEXTURES)
@@ -1356,12 +1779,13 @@ void TakeScreenshot(const char *fileName)
Image image = { imgData, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y), 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
char path[512] = { 0 };
- strcpy(path, TextFormat("%s/%s", CORE.Storage.basePath, fileName));
-
+ strcpy(path, TextFormat("%s/%s", CORE.Storage.basePath, GetFileName(fileName)));
+
ExportImage(image, path); // WARNING: Module required: rtextures
RL_FREE(imgData);
- TRACELOG(LOG_INFO, "SYSTEM: [%s] Screenshot taken successfully", path);
+ if (FileExists(path)) TRACELOG(LOG_INFO, "SYSTEM: [%s] Screenshot taken successfully", path);
+ else TRACELOG(LOG_WARNING, "SYSTEM: [%s] Screenshot could not be saved", path);
#else
TRACELOG(LOG_WARNING,"IMAGE: ExportImage() requires module: rtextures");
#endif
@@ -1414,10 +1838,10 @@ bool IsFileExtension(const char *fileName, const char *ext)
{
#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_TEXT_MANIPULATION)
int extCount = 0;
- const char **checkExts = TextSplit(ext, ';', &extCount); // WARNING: Module required: rtext
+ const char **checkExts = TextSplit(ext, ';', &extCount); // WARNING: Module required: rtext
char fileExtLower[MAX_FILE_EXTENSION_SIZE + 1] = { 0 };
- strncpy(fileExtLower, TextToLower(fileExt), MAX_FILE_EXTENSION_SIZE); // WARNING: Module required: rtext
+ strncpy(fileExtLower, TextToLower(fileExt), MAX_FILE_EXTENSION_SIZE); // WARNING: Module required: rtext
for (int i = 0; i < extCount; i++)
{
@@ -1972,6 +2396,255 @@ unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize)
}
//----------------------------------------------------------------------------------
+// Module Functions Definition: Automation Events Recording and Playing
+//----------------------------------------------------------------------------------
+
+// Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS
+AutomationEventList LoadAutomationEventList(const char *fileName)
+{
+ AutomationEventList list = { 0 };
+
+ // Allocate and empty automation event list, ready to record new events
+ list.events = (AutomationEvent *)RL_CALLOC(MAX_AUTOMATION_EVENTS, sizeof(AutomationEvent));
+ list.capacity = MAX_AUTOMATION_EVENTS;
+
+#if defined(SUPPORT_AUTOMATION_EVENTS)
+ if (fileName == NULL) TRACELOG(LOG_INFO, "AUTOMATION: New empty events list loaded successfully");
+ else
+ {
+ // Load automation events file (binary)
+ /*
+ //int dataSize = 0;
+ //unsigned char *data = LoadFileData(fileName, &dataSize);
+
+ FILE *raeFile = fopen(fileName, "rb");
+ unsigned char fileId[4] = { 0 };
+
+ fread(fileId, 1, 4, raeFile);
+
+ if ((fileId[0] == 'r') && (fileId[1] == 'A') && (fileId[2] == 'E') && (fileId[1] == ' '))
+ {
+ fread(&eventCount, sizeof(int), 1, raeFile);
+ TRACELOG(LOG_WARNING, "Events loaded: %i\n", eventCount);
+ fread(events, sizeof(AutomationEvent), eventCount, raeFile);
+ }
+
+ fclose(raeFile);
+ */
+
+ // Load events file (text)
+ //unsigned char *buffer = LoadFileText(fileName);
+ FILE *raeFile = fopen(fileName, "rt");
+
+ if (raeFile != NULL)
+ {
+ unsigned int counter = 0;
+ char buffer[256] = { 0 };
+ char eventDesc[64] = { 0 };
+
+ fgets(buffer, 256, raeFile);
+
+ while (!feof(raeFile))
+ {
+ switch (buffer[0])
+ {
+ case 'c': sscanf(buffer, "c %i", &list.count); break;
+ case 'e':
+ {
+ sscanf(buffer, "e %d %d %d %d %d %d %[^\n]s", &list.events[counter].frame, &list.events[counter].type,
+ &list.events[counter].params[0], &list.events[counter].params[1], &list.events[counter].params[2], &list.events[counter].params[3], eventDesc);
+
+ counter++;
+ } break;
+ default: break;
+ }
+
+ fgets(buffer, 256, raeFile);
+ }
+
+ if (counter != list.count)
+ {
+ TRACELOG(LOG_WARNING, "AUTOMATION: Events read from file [%i] do not mach event count specified [%i]", counter, list.count);
+ list.count = counter;
+ }
+
+ fclose(raeFile);
+
+ TRACELOG(LOG_INFO, "AUTOMATION: Events file loaded successfully");
+ }
+
+ TRACELOG(LOG_INFO, "AUTOMATION: Events loaded from file: %i", list.count);
+ }
+#endif
+ return list;
+}
+
+// Unload automation events list from file
+void UnloadAutomationEventList(AutomationEventList *list)
+{
+#if defined(SUPPORT_AUTOMATION_EVENTS)
+ RL_FREE(list->events);
+ list->events = NULL;
+ list->count = 0;
+ list->capacity = 0;
+#endif
+}
+
+// Export automation events list as text file
+bool ExportAutomationEventList(AutomationEventList list, const char *fileName)
+{
+ bool success = false;
+
+#if defined(SUPPORT_AUTOMATION_EVENTS)
+ // Export events as binary file
+ // TODO: Save to memory buffer and SaveFileData()
+ /*
+ unsigned char fileId[4] = "rAE ";
+ FILE *raeFile = fopen(fileName, "wb");
+ fwrite(fileId, sizeof(unsigned char), 4, raeFile);
+ fwrite(&eventCount, sizeof(int), 1, raeFile);
+ fwrite(events, sizeof(AutomationEvent), eventCount, raeFile);
+ fclose(raeFile);
+ */
+
+ // Export events as text
+ // TODO: Save to memory buffer and SaveFileText()
+ char *txtData = (char *)RL_CALLOC(256*list.count + 2048, sizeof(char)); // 256 characters per line plus some header
+
+ int byteCount = 0;
+ byteCount += sprintf(txtData + byteCount, "#\n");
+ byteCount += sprintf(txtData + byteCount, "# Automation events exporter v1.0 - raylib automation events list\n");
+ byteCount += sprintf(txtData + byteCount, "#\n");
+ byteCount += sprintf(txtData + byteCount, "# c <events_count>\n");
+ byteCount += sprintf(txtData + byteCount, "# e <frame> <event_type> <param0> <param1> <param2> <param3> // <event_type_name>\n");
+ byteCount += sprintf(txtData + byteCount, "#\n");
+ byteCount += sprintf(txtData + byteCount, "# more info and bugs-report: github.com/raysan5/raylib\n");
+ byteCount += sprintf(txtData + byteCount, "# feedback and support: ray[at]raylib.com\n");
+ byteCount += sprintf(txtData + byteCount, "#\n");
+ byteCount += sprintf(txtData + byteCount, "# Copyright (c) 2023-2024 Ramon Santamaria (@raysan5)\n");
+ byteCount += sprintf(txtData + byteCount, "#\n\n");
+
+ // Add events data
+ byteCount += sprintf(txtData + byteCount, "c %i\n", list.count);
+ for (unsigned int i = 0; i < list.count; i++)
+ {
+ byteCount += snprintf(txtData + byteCount, 256, "e %i %i %i %i %i %i // Event: %s\n", list.events[i].frame, list.events[i].type,
+ list.events[i].params[0], list.events[i].params[1], list.events[i].params[2], list.events[i].params[3], autoEventTypeName[list.events[i].type]);
+ }
+
+ // NOTE: Text data size exported is determined by '\0' (NULL) character
+ success = SaveFileText(fileName, txtData);
+
+ RL_FREE(txtData);
+#endif
+
+ return success;
+}
+
+// Setup automation event list to record to
+void SetAutomationEventList(AutomationEventList *list)
+{
+#if defined(SUPPORT_AUTOMATION_EVENTS)
+ currentEventList = list;
+#endif
+}
+
+// Set automation event internal base frame to start recording
+void SetAutomationEventBaseFrame(int frame)
+{
+ CORE.Time.frameCounter = frame;
+}
+
+// Start recording automation events (AutomationEventList must be set)
+void StartAutomationEventRecording(void)
+{
+#if defined(SUPPORT_AUTOMATION_EVENTS)
+ automationEventRecording = true;
+#endif
+}
+
+// Stop recording automation events
+void StopAutomationEventRecording(void)
+{
+#if defined(SUPPORT_AUTOMATION_EVENTS)
+ automationEventRecording = false;
+#endif
+}
+
+// Play a recorded automation event
+void PlayAutomationEvent(AutomationEvent event)
+{
+#if defined(SUPPORT_AUTOMATION_EVENTS)
+ // WARNING: When should event be played? After/before/replace PollInputEvents()? -> Up to the user!
+
+ if (!automationEventRecording) // TODO: Allow recording events while playing?
+ {
+ switch (event.type)
+ {
+ // Input event
+ case INPUT_KEY_UP: CORE.Input.Keyboard.currentKeyState[event.params[0]] = false; break; // param[0]: key
+ case INPUT_KEY_DOWN: { // param[0]: key
+ CORE.Input.Keyboard.currentKeyState[event.params[0]] = true;
+
+ if (CORE.Input.Keyboard.previousKeyState[event.params[0]] == false)
+ {
+ if (CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE)
+ {
+ // Add character to the queue
+ CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = event.params[0];
+ CORE.Input.Keyboard.keyPressedQueueCount++;
+ }
+ }
+ } break;
+ case INPUT_MOUSE_BUTTON_UP: CORE.Input.Mouse.currentButtonState[event.params[0]] = false; break; // param[0]: key
+ case INPUT_MOUSE_BUTTON_DOWN: CORE.Input.Mouse.currentButtonState[event.params[0]] = true; break; // param[0]: key
+ case INPUT_MOUSE_POSITION: // param[0]: x, param[1]: y
+ {
+ CORE.Input.Mouse.currentPosition.x = (float)event.params[0];
+ CORE.Input.Mouse.currentPosition.y = (float)event.params[1];
+ } break;
+ case INPUT_MOUSE_WHEEL_MOTION: // param[0]: x delta, param[1]: y delta
+ {
+ CORE.Input.Mouse.currentWheelMove.x = (float)event.params[0]; break;
+ CORE.Input.Mouse.currentWheelMove.y = (float)event.params[1]; break;
+ } break;
+ case INPUT_TOUCH_UP: CORE.Input.Touch.currentTouchState[event.params[0]] = false; break; // param[0]: id
+ case INPUT_TOUCH_DOWN: CORE.Input.Touch.currentTouchState[event.params[0]] = true; break; // param[0]: id
+ case INPUT_TOUCH_POSITION: // param[0]: id, param[1]: x, param[2]: y
+ {
+ CORE.Input.Touch.position[event.params[0]].x = (float)event.params[1];
+ CORE.Input.Touch.position[event.params[0]].y = (float)event.params[2];
+ } break;
+ case INPUT_GAMEPAD_CONNECT: CORE.Input.Gamepad.ready[event.params[0]] = true; break; // param[0]: gamepad
+ case INPUT_GAMEPAD_DISCONNECT: CORE.Input.Gamepad.ready[event.params[0]] = false; break; // param[0]: gamepad
+ case INPUT_GAMEPAD_BUTTON_UP: CORE.Input.Gamepad.currentButtonState[event.params[0]][event.params[1]] = false; break; // param[0]: gamepad, param[1]: button
+ case INPUT_GAMEPAD_BUTTON_DOWN: CORE.Input.Gamepad.currentButtonState[event.params[0]][event.params[1]] = true; break; // param[0]: gamepad, param[1]: button
+ case INPUT_GAMEPAD_AXIS_MOTION: // param[0]: gamepad, param[1]: axis, param[2]: delta
+ {
+ CORE.Input.Gamepad.axisState[event.params[0]][event.params[1]] = ((float)event.params[2]/32768.0f);
+ } break;
+ case INPUT_GESTURE: GESTURES.current = event.params[0]; break; // param[0]: gesture (enum Gesture) -> rgestures.h: GESTURES.current
+
+ // Window event
+ case WINDOW_CLOSE: CORE.Window.shouldClose = true; break;
+ case WINDOW_MAXIMIZE: MaximizeWindow(); break;
+ case WINDOW_MINIMIZE: MinimizeWindow(); break;
+ case WINDOW_RESIZE: SetWindowSize(event.params[0], event.params[1]); break;
+
+ // Custom event
+ case ACTION_TAKE_SCREENSHOT:
+ {
+ TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter));
+ screenshotCounter++;
+ } break;
+ case ACTION_SETTARGETFPS: SetTargetFPS(event.params[0]); break;
+ default: break;
+ }
+ }
+#endif
+}
+
+//----------------------------------------------------------------------------------
// Module Functions Definition: Input Handling: Keyboard
//----------------------------------------------------------------------------------
@@ -2360,7 +3033,8 @@ int GetTouchPointCount(void)
//----------------------------------------------------------------------------------
// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
-//static bool InitPlatform(void)
+//int InitPlatform(void)
+//void ClosePlatform(void)
// Initialize hi-resolution timer
void InitTimer(void)
@@ -2369,7 +3043,7 @@ void InitTimer(void)
// However, it can also reduce overall system performance, because the thread scheduler switches tasks more often.
// High resolutions can also prevent the CPU power management system from entering power-saving modes.
// Setting a higher resolution does not improve the accuracy of the high-resolution performance counter.
-#if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP)
+#if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP) && !defined(PLATFORM_DESKTOP_SDL)
timeBeginPeriod(1); // Setup high-resolution timer to 1ms (granularity of 1-2 ms)
#endif
@@ -2396,8 +3070,6 @@ void SetupViewport(int width, int height)
// NOTE: We consider render size (scaled) and offset in case black bars are required and
// render area does not match full display area (this situation is only applicable on fullscreen mode)
#if defined(__APPLE__)
- //float xScale = 1.0f, yScale = 1.0f;
- //glfwGetWindowContentScale(CORE.Window.handle, &xScale, &yScale);
Vector2 scale = GetWindowScaleDPI();
rlViewport(CORE.Window.renderOffset.x/2*scale.x, CORE.Window.renderOffset.y/2*scale.y, (CORE.Window.render.width)*scale.x, (CORE.Window.render.height)*scale.y);
#else
@@ -2511,7 +3183,11 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const
if ((strcmp(dp->d_name, ".") != 0) &&
(strcmp(dp->d_name, "..") != 0))
{
+ #if defined(_WIN32)
+ sprintf(path, "%s\\%s", basePath, dp->d_name);
+ #else
sprintf(path, "%s/%s", basePath, dp->d_name);
+ #endif
if (filter != NULL)
{
@@ -2550,7 +3226,11 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi
if ((strcmp(dp->d_name, ".") != 0) && (strcmp(dp->d_name, "..") != 0))
{
// Construct new path from our base path
+ #if defined(_WIN32)
+ sprintf(path, "%s\\%s", basePath, dp->d_name);
+ #else
sprintf(path, "%s/%s", basePath, dp->d_name);
+ #endif
if (IsPathFile(path))
{
@@ -2583,233 +3263,180 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi
else TRACELOG(LOG_WARNING, "FILEIO: Directory cannot be opened (%s)", basePath);
}
-#if defined(SUPPORT_EVENTS_AUTOMATION)
-// NOTE: Loading happens over AutomationEvent *events
-// TODO: This system should probably be redesigned
-static void LoadAutomationEvents(const char *fileName)
-{
- // Load events file (binary)
- /*
- FILE *repFile = fopen(fileName, "rb");
- unsigned char fileId[4] = { 0 };
-
- fread(fileId, 1, 4, repFile);
-
- if ((fileId[0] == 'r') && (fileId[1] == 'E') && (fileId[2] == 'P') && (fileId[1] == ' '))
- {
- fread(&eventCount, sizeof(int), 1, repFile);
- TRACELOG(LOG_WARNING, "Events loaded: %i\n", eventCount);
- fread(events, sizeof(AutomationEvent), eventCount, repFile);
- }
-
- fclose(repFile);
- */
-
- // Load events file (text)
- FILE *repFile = fopen(fileName, "rt");
-
- if (repFile != NULL)
- {
- unsigned int count = 0;
- char buffer[256] = { 0 };
-
- fgets(buffer, 256, repFile);
-
- while (!feof(repFile))
- {
- if (buffer[0] == 'c') sscanf(buffer, "c %i", &eventCount);
- else if (buffer[0] == 'e')
- {
- sscanf(buffer, "e %d %d %d %d %d", &events[count].frame, &events[count].type,
- &events[count].params[0], &events[count].params[1], &events[count].params[2]);
-
- count++;
- }
-
- fgets(buffer, 256, repFile);
- }
-
- if (count != eventCount) TRACELOG(LOG_WARNING, "Events count provided is different than count");
-
- fclose(repFile);
- }
-
- TRACELOG(LOG_WARNING, "Events loaded: %i", eventCount);
-}
-
-// Export recorded events into a file
-static void ExportAutomationEvents(const char *fileName)
+#if defined(SUPPORT_AUTOMATION_EVENTS)
+// Automation event recording
+// NOTE: Recording is by default done at EndDrawing(), after PollInputEvents()
+static void RecordAutomationEvent(void)
{
- unsigned char fileId[4] = "rEP ";
-
- // Save as binary
- /*
- FILE *repFile = fopen(fileName, "wb");
- fwrite(fileId, sizeof(unsigned char), 4, repFile);
- fwrite(&eventCount, sizeof(int), 1, repFile);
- fwrite(events, sizeof(AutomationEvent), eventCount, repFile);
- fclose(repFile);
- */
-
- // Export events as text
- FILE *repFile = fopen(fileName, "wt");
-
- if (repFile != NULL)
- {
- fprintf(repFile, "# Automation events list\n");
- fprintf(repFile, "# c <events_count>\n");
- fprintf(repFile, "# e <frame> <event_type> <param0> <param1> <param2> // <event_type_name>\n");
-
- fprintf(repFile, "c %i\n", eventCount);
- for (int i = 0; i < eventCount; i++)
- {
- fprintf(repFile, "e %i %i %i %i %i // %s\n", events[i].frame, events[i].type,
- events[i].params[0], events[i].params[1], events[i].params[2], autoEventTypeName[events[i].type]);
- }
+ // Checking events in current frame and save them into currentEventList
+ // TODO: How important is the current frame? Could it be modified?
- fclose(repFile);
- }
-}
+ if (currentEventList->count == currentEventList->capacity) return; // Security check
-// EndDrawing() -> After PollInputEvents()
-// Check event in current frame and save into the events[i] array
-static void RecordAutomationEvent(unsigned int frame)
-{
+ // Keyboard input events recording
+ //-------------------------------------------------------------------------------------
for (int key = 0; key < MAX_KEYBOARD_KEYS; key++)
{
- // INPUT_KEY_UP (only saved once)
+ // Event type: INPUT_KEY_UP (only saved once)
if (CORE.Input.Keyboard.previousKeyState[key] && !CORE.Input.Keyboard.currentKeyState[key])
{
- events[eventCount].frame = frame;
- events[eventCount].type = INPUT_KEY_UP;
- events[eventCount].params[0] = key;
- events[eventCount].params[1] = 0;
- events[eventCount].params[2] = 0;
-
- TRACELOG(LOG_INFO, "[%i] INPUT_KEY_UP: %i, %i, %i", events[eventCount].frame, events[eventCount].params[0], events[eventCount].params[1], events[eventCount].params[2]);
- eventCount++;
+ currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+ currentEventList->events[currentEventList->count].type = INPUT_KEY_UP;
+ currentEventList->events[currentEventList->count].params[0] = key;
+ currentEventList->events[currentEventList->count].params[1] = 0;
+ currentEventList->events[currentEventList->count].params[2] = 0;
+
+ TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_KEY_UP | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+ currentEventList->count++;
}
- // INPUT_KEY_DOWN
+ if (currentEventList->count == currentEventList->capacity) return; // Security check
+
+ // Event type: INPUT_KEY_DOWN
if (CORE.Input.Keyboard.currentKeyState[key])
{
- events[eventCount].frame = frame;
- events[eventCount].type = INPUT_KEY_DOWN;
- events[eventCount].params[0] = key;
- events[eventCount].params[1] = 0;
- events[eventCount].params[2] = 0;
-
- TRACELOG(LOG_INFO, "[%i] INPUT_KEY_DOWN: %i, %i, %i", events[eventCount].frame, events[eventCount].params[0], events[eventCount].params[1], events[eventCount].params[2]);
- eventCount++;
+ currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+ currentEventList->events[currentEventList->count].type = INPUT_KEY_DOWN;
+ currentEventList->events[currentEventList->count].params[0] = key;
+ currentEventList->events[currentEventList->count].params[1] = 0;
+ currentEventList->events[currentEventList->count].params[2] = 0;
+
+ TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_KEY_DOWN | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+ currentEventList->count++;
}
+
+ if (currentEventList->count == currentEventList->capacity) return; // Security check
}
+ //-------------------------------------------------------------------------------------
+ // Mouse input currentEventList->events recording
+ //-------------------------------------------------------------------------------------
for (int button = 0; button < MAX_MOUSE_BUTTONS; button++)
{
- // INPUT_MOUSE_BUTTON_UP
+ // Event type: INPUT_MOUSE_BUTTON_UP
if (CORE.Input.Mouse.previousButtonState[button] && !CORE.Input.Mouse.currentButtonState[button])
{
- events[eventCount].frame = frame;
- events[eventCount].type = INPUT_MOUSE_BUTTON_UP;
- events[eventCount].params[0] = button;
- events[eventCount].params[1] = 0;
- events[eventCount].params[2] = 0;
-
- TRACELOG(LOG_INFO, "[%i] INPUT_MOUSE_BUTTON_UP: %i, %i, %i", events[eventCount].frame, events[eventCount].params[0], events[eventCount].params[1], events[eventCount].params[2]);
- eventCount++;
+ currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+ currentEventList->events[currentEventList->count].type = INPUT_MOUSE_BUTTON_UP;
+ currentEventList->events[currentEventList->count].params[0] = button;
+ currentEventList->events[currentEventList->count].params[1] = 0;
+ currentEventList->events[currentEventList->count].params[2] = 0;
+
+ TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_MOUSE_BUTTON_UP | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+ currentEventList->count++;
}
- // INPUT_MOUSE_BUTTON_DOWN
+ if (currentEventList->count == currentEventList->capacity) return; // Security check
+
+ // Event type: INPUT_MOUSE_BUTTON_DOWN
if (CORE.Input.Mouse.currentButtonState[button])
{
- events[eventCount].frame = frame;
- events[eventCount].type = INPUT_MOUSE_BUTTON_DOWN;
- events[eventCount].params[0] = button;
- events[eventCount].params[1] = 0;
- events[eventCount].params[2] = 0;
-
- TRACELOG(LOG_INFO, "[%i] INPUT_MOUSE_BUTTON_DOWN: %i, %i, %i", events[eventCount].frame, events[eventCount].params[0], events[eventCount].params[1], events[eventCount].params[2]);
- eventCount++;
+ currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+ currentEventList->events[currentEventList->count].type = INPUT_MOUSE_BUTTON_DOWN;
+ currentEventList->events[currentEventList->count].params[0] = button;
+ currentEventList->events[currentEventList->count].params[1] = 0;
+ currentEventList->events[currentEventList->count].params[2] = 0;
+
+ TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_MOUSE_BUTTON_DOWN | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+ currentEventList->count++;
}
+
+ if (currentEventList->count == currentEventList->capacity) return; // Security check
}
- // INPUT_MOUSE_POSITION (only saved if changed)
+ // Event type: INPUT_MOUSE_POSITION (only saved if changed)
if (((int)CORE.Input.Mouse.currentPosition.x != (int)CORE.Input.Mouse.previousPosition.x) ||
((int)CORE.Input.Mouse.currentPosition.y != (int)CORE.Input.Mouse.previousPosition.y))
{
- events[eventCount].frame = frame;
- events[eventCount].type = INPUT_MOUSE_POSITION;
- events[eventCount].params[0] = (int)CORE.Input.Mouse.currentPosition.x;
- events[eventCount].params[1] = (int)CORE.Input.Mouse.currentPosition.y;
- events[eventCount].params[2] = 0;
+ currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+ currentEventList->events[currentEventList->count].type = INPUT_MOUSE_POSITION;
+ currentEventList->events[currentEventList->count].params[0] = (int)CORE.Input.Mouse.currentPosition.x;
+ currentEventList->events[currentEventList->count].params[1] = (int)CORE.Input.Mouse.currentPosition.y;
+ currentEventList->events[currentEventList->count].params[2] = 0;
- TRACELOG(LOG_INFO, "[%i] INPUT_MOUSE_POSITION: %i, %i, %i", events[eventCount].frame, events[eventCount].params[0], events[eventCount].params[1], events[eventCount].params[2]);
- eventCount++;
+ TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_MOUSE_POSITION | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+ currentEventList->count++;
+
+ if (currentEventList->count == currentEventList->capacity) return; // Security check
}
- // INPUT_MOUSE_WHEEL_MOTION
+ // Event type: INPUT_MOUSE_WHEEL_MOTION
if (((int)CORE.Input.Mouse.currentWheelMove.x != (int)CORE.Input.Mouse.previousWheelMove.x) ||
((int)CORE.Input.Mouse.currentWheelMove.y != (int)CORE.Input.Mouse.previousWheelMove.y))
{
- events[eventCount].frame = frame;
- events[eventCount].type = INPUT_MOUSE_WHEEL_MOTION;
- events[eventCount].params[0] = (int)CORE.Input.Mouse.currentWheelMove.x;
- events[eventCount].params[1] = (int)CORE.Input.Mouse.currentWheelMove.y;;
- events[eventCount].params[2] = 0;
+ currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+ currentEventList->events[currentEventList->count].type = INPUT_MOUSE_WHEEL_MOTION;
+ currentEventList->events[currentEventList->count].params[0] = (int)CORE.Input.Mouse.currentWheelMove.x;
+ currentEventList->events[currentEventList->count].params[1] = (int)CORE.Input.Mouse.currentWheelMove.y;;
+ currentEventList->events[currentEventList->count].params[2] = 0;
+
+ TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_MOUSE_WHEEL_MOTION | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+ currentEventList->count++;
- TRACELOG(LOG_INFO, "[%i] INPUT_MOUSE_WHEEL_MOTION: %i, %i, %i", events[eventCount].frame, events[eventCount].params[0], events[eventCount].params[1], events[eventCount].params[2]);
- eventCount++;
+ if (currentEventList->count == currentEventList->capacity) return; // Security check
}
+ //-------------------------------------------------------------------------------------
+ // Touch input currentEventList->events recording
+ //-------------------------------------------------------------------------------------
for (int id = 0; id < MAX_TOUCH_POINTS; id++)
{
- // INPUT_TOUCH_UP
+ // Event type: INPUT_TOUCH_UP
if (CORE.Input.Touch.previousTouchState[id] && !CORE.Input.Touch.currentTouchState[id])
{
- events[eventCount].frame = frame;
- events[eventCount].type = INPUT_TOUCH_UP;
- events[eventCount].params[0] = id;
- events[eventCount].params[1] = 0;
- events[eventCount].params[2] = 0;
-
- TRACELOG(LOG_INFO, "[%i] INPUT_TOUCH_UP: %i, %i, %i", events[eventCount].frame, events[eventCount].params[0], events[eventCount].params[1], events[eventCount].params[2]);
- eventCount++;
+ currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+ currentEventList->events[currentEventList->count].type = INPUT_TOUCH_UP;
+ currentEventList->events[currentEventList->count].params[0] = id;
+ currentEventList->events[currentEventList->count].params[1] = 0;
+ currentEventList->events[currentEventList->count].params[2] = 0;
+
+ TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_TOUCH_UP | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+ currentEventList->count++;
}
- // INPUT_TOUCH_DOWN
+ if (currentEventList->count == currentEventList->capacity) return; // Security check
+
+ // Event type: INPUT_TOUCH_DOWN
if (CORE.Input.Touch.currentTouchState[id])
{
- events[eventCount].frame = frame;
- events[eventCount].type = INPUT_TOUCH_DOWN;
- events[eventCount].params[0] = id;
- events[eventCount].params[1] = 0;
- events[eventCount].params[2] = 0;
-
- TRACELOG(LOG_INFO, "[%i] INPUT_TOUCH_DOWN: %i, %i, %i", events[eventCount].frame, events[eventCount].params[0], events[eventCount].params[1], events[eventCount].params[2]);
- eventCount++;
+ currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+ currentEventList->events[currentEventList->count].type = INPUT_TOUCH_DOWN;
+ currentEventList->events[currentEventList->count].params[0] = id;
+ currentEventList->events[currentEventList->count].params[1] = 0;
+ currentEventList->events[currentEventList->count].params[2] = 0;
+
+ TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_TOUCH_DOWN | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+ currentEventList->count++;
}
- // INPUT_TOUCH_POSITION
+ if (currentEventList->count == currentEventList->capacity) return; // Security check
+
+ // Event type: INPUT_TOUCH_POSITION
// TODO: It requires the id!
/*
if (((int)CORE.Input.Touch.currentPosition[id].x != (int)CORE.Input.Touch.previousPosition[id].x) ||
((int)CORE.Input.Touch.currentPosition[id].y != (int)CORE.Input.Touch.previousPosition[id].y))
{
- events[eventCount].frame = frame;
- events[eventCount].type = INPUT_TOUCH_POSITION;
- events[eventCount].params[0] = id;
- events[eventCount].params[1] = (int)CORE.Input.Touch.currentPosition[id].x;
- events[eventCount].params[2] = (int)CORE.Input.Touch.currentPosition[id].y;
-
- TRACELOG(LOG_INFO, "[%i] INPUT_TOUCH_POSITION: %i, %i, %i", events[eventCount].frame, events[eventCount].params[0], events[eventCount].params[1], events[eventCount].params[2]);
- eventCount++;
+ currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+ currentEventList->events[currentEventList->count].type = INPUT_TOUCH_POSITION;
+ currentEventList->events[currentEventList->count].params[0] = id;
+ currentEventList->events[currentEventList->count].params[1] = (int)CORE.Input.Touch.currentPosition[id].x;
+ currentEventList->events[currentEventList->count].params[2] = (int)CORE.Input.Touch.currentPosition[id].y;
+
+ TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_TOUCH_POSITION | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+ currentEventList->count++;
}
*/
+
+ if (currentEventList->count == currentEventList->capacity) return; // Security check
}
+ //-------------------------------------------------------------------------------------
+ // Gamepad input currentEventList->events recording
+ //-------------------------------------------------------------------------------------
for (int gamepad = 0; gamepad < MAX_GAMEPADS; gamepad++)
{
- // INPUT_GAMEPAD_CONNECT
+ // Event type: INPUT_GAMEPAD_CONNECT
/*
if ((CORE.Input.Gamepad.currentState[gamepad] != CORE.Input.Gamepad.previousState[gamepad]) &&
(CORE.Input.Gamepad.currentState[gamepad])) // Check if changed to ready
@@ -2818,7 +3445,7 @@ static void RecordAutomationEvent(unsigned int frame)
}
*/
- // INPUT_GAMEPAD_DISCONNECT
+ // Event type: INPUT_GAMEPAD_DISCONNECT
/*
if ((CORE.Input.Gamepad.currentState[gamepad] != CORE.Input.Gamepad.previousState[gamepad]) &&
(!CORE.Input.Gamepad.currentState[gamepad])) // Check if changed to not-ready
@@ -2829,122 +3456,84 @@ static void RecordAutomationEvent(unsigned int frame)
for (int button = 0; button < MAX_GAMEPAD_BUTTONS; button++)
{
- // INPUT_GAMEPAD_BUTTON_UP
+ // Event type: INPUT_GAMEPAD_BUTTON_UP
if (CORE.Input.Gamepad.previousButtonState[gamepad][button] && !CORE.Input.Gamepad.currentButtonState[gamepad][button])
{
- events[eventCount].frame = frame;
- events[eventCount].type = INPUT_GAMEPAD_BUTTON_UP;
- events[eventCount].params[0] = gamepad;
- events[eventCount].params[1] = button;
- events[eventCount].params[2] = 0;
-
- TRACELOG(LOG_INFO, "[%i] INPUT_GAMEPAD_BUTTON_UP: %i, %i, %i", events[eventCount].frame, events[eventCount].params[0], events[eventCount].params[1], events[eventCount].params[2]);
- eventCount++;
+ currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+ currentEventList->events[currentEventList->count].type = INPUT_GAMEPAD_BUTTON_UP;
+ currentEventList->events[currentEventList->count].params[0] = gamepad;
+ currentEventList->events[currentEventList->count].params[1] = button;
+ currentEventList->events[currentEventList->count].params[2] = 0;
+
+ TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_GAMEPAD_BUTTON_UP | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+ currentEventList->count++;
}
- // INPUT_GAMEPAD_BUTTON_DOWN
+ if (currentEventList->count == currentEventList->capacity) return; // Security check
+
+ // Event type: INPUT_GAMEPAD_BUTTON_DOWN
if (CORE.Input.Gamepad.currentButtonState[gamepad][button])
{
- events[eventCount].frame = frame;
- events[eventCount].type = INPUT_GAMEPAD_BUTTON_DOWN;
- events[eventCount].params[0] = gamepad;
- events[eventCount].params[1] = button;
- events[eventCount].params[2] = 0;
-
- TRACELOG(LOG_INFO, "[%i] INPUT_GAMEPAD_BUTTON_DOWN: %i, %i, %i", events[eventCount].frame, events[eventCount].params[0], events[eventCount].params[1], events[eventCount].params[2]);
- eventCount++;
+ currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+ currentEventList->events[currentEventList->count].type = INPUT_GAMEPAD_BUTTON_DOWN;
+ currentEventList->events[currentEventList->count].params[0] = gamepad;
+ currentEventList->events[currentEventList->count].params[1] = button;
+ currentEventList->events[currentEventList->count].params[2] = 0;
+
+ TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_GAMEPAD_BUTTON_DOWN | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+ currentEventList->count++;
}
+
+ if (currentEventList->count == currentEventList->capacity) return; // Security check
}
for (int axis = 0; axis < MAX_GAMEPAD_AXIS; axis++)
{
- // INPUT_GAMEPAD_AXIS_MOTION
+ // Event type: INPUT_GAMEPAD_AXIS_MOTION
if (CORE.Input.Gamepad.axisState[gamepad][axis] > 0.1f)
{
- events[eventCount].frame = frame;
- events[eventCount].type = INPUT_GAMEPAD_AXIS_MOTION;
- events[eventCount].params[0] = gamepad;
- events[eventCount].params[1] = axis;
- events[eventCount].params[2] = (int)(CORE.Input.Gamepad.axisState[gamepad][axis]*32768.0f);
-
- TRACELOG(LOG_INFO, "[%i] INPUT_GAMEPAD_AXIS_MOTION: %i, %i, %i", events[eventCount].frame, events[eventCount].params[0], events[eventCount].params[1], events[eventCount].params[2]);
- eventCount++;
+ currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+ currentEventList->events[currentEventList->count].type = INPUT_GAMEPAD_AXIS_MOTION;
+ currentEventList->events[currentEventList->count].params[0] = gamepad;
+ currentEventList->events[currentEventList->count].params[1] = axis;
+ currentEventList->events[currentEventList->count].params[2] = (int)(CORE.Input.Gamepad.axisState[gamepad][axis]*32768.0f);
+
+ TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_GAMEPAD_AXIS_MOTION | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+ currentEventList->count++;
}
+
+ if (currentEventList->count == currentEventList->capacity) return; // Security check
}
}
+ //-------------------------------------------------------------------------------------
- // INPUT_GESTURE
+ // Gestures input currentEventList->events recording
+ //-------------------------------------------------------------------------------------
if (GESTURES.current != GESTURE_NONE)
{
- events[eventCount].frame = frame;
- events[eventCount].type = INPUT_GESTURE;
- events[eventCount].params[0] = GESTURES.current;
- events[eventCount].params[1] = 0;
- events[eventCount].params[2] = 0;
+ // Event type: INPUT_GESTURE
+ currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+ currentEventList->events[currentEventList->count].type = INPUT_GESTURE;
+ currentEventList->events[currentEventList->count].params[0] = GESTURES.current;
+ currentEventList->events[currentEventList->count].params[1] = 0;
+ currentEventList->events[currentEventList->count].params[2] = 0;
- TRACELOG(LOG_INFO, "[%i] INPUT_GESTURE: %i, %i, %i", events[eventCount].frame, events[eventCount].params[0], events[eventCount].params[1], events[eventCount].params[2]);
- eventCount++;
- }
-}
+ TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_GESTURE | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+ currentEventList->count++;
-// Play automation event
-static void PlayAutomationEvent(unsigned int frame)
-{
- for (unsigned int i = 0; i < eventCount; i++)
- {
- if (events[i].frame == frame)
- {
- switch (events[i].type)
- {
- // Input events
- case INPUT_KEY_UP: CORE.Input.Keyboard.currentKeyState[events[i].params[0]] = false; break; // param[0]: key
- case INPUT_KEY_DOWN: CORE.Input.Keyboard.currentKeyState[events[i].params[0]] = true; break; // param[0]: key
- case INPUT_MOUSE_BUTTON_UP: CORE.Input.Mouse.currentButtonState[events[i].params[0]] = false; break; // param[0]: key
- case INPUT_MOUSE_BUTTON_DOWN: CORE.Input.Mouse.currentButtonState[events[i].params[0]] = true; break; // param[0]: key
- case INPUT_MOUSE_POSITION: // param[0]: x, param[1]: y
- {
- CORE.Input.Mouse.currentPosition.x = (float)events[i].params[0];
- CORE.Input.Mouse.currentPosition.y = (float)events[i].params[1];
- } break;
- case INPUT_MOUSE_WHEEL_MOTION: // param[0]: x delta, param[1]: y delta
- {
- CORE.Input.Mouse.currentWheelMove.x = (float)events[i].params[0]; break;
- CORE.Input.Mouse.currentWheelMove.y = (float)events[i].params[1]; break;
- } break;
- case INPUT_TOUCH_UP: CORE.Input.Touch.currentTouchState[events[i].params[0]] = false; break; // param[0]: id
- case INPUT_TOUCH_DOWN: CORE.Input.Touch.currentTouchState[events[i].params[0]] = true; break; // param[0]: id
- case INPUT_TOUCH_POSITION: // param[0]: id, param[1]: x, param[2]: y
- {
- CORE.Input.Touch.position[events[i].params[0]].x = (float)events[i].params[1];
- CORE.Input.Touch.position[events[i].params[0]].y = (float)events[i].params[2];
- } break;
- case INPUT_GAMEPAD_CONNECT: CORE.Input.Gamepad.ready[events[i].params[0]] = true; break; // param[0]: gamepad
- case INPUT_GAMEPAD_DISCONNECT: CORE.Input.Gamepad.ready[events[i].params[0]] = false; break; // param[0]: gamepad
- case INPUT_GAMEPAD_BUTTON_UP: CORE.Input.Gamepad.currentButtonState[events[i].params[0]][events[i].params[1]] = false; break; // param[0]: gamepad, param[1]: button
- case INPUT_GAMEPAD_BUTTON_DOWN: CORE.Input.Gamepad.currentButtonState[events[i].params[0]][events[i].params[1]] = true; break; // param[0]: gamepad, param[1]: button
- case INPUT_GAMEPAD_AXIS_MOTION: // param[0]: gamepad, param[1]: axis, param[2]: delta
- {
- CORE.Input.Gamepad.axisState[events[i].params[0]][events[i].params[1]] = ((float)events[i].params[2]/32768.0f);
- } break;
- case INPUT_GESTURE: GESTURES.current = events[i].params[0]; break; // param[0]: gesture (enum Gesture) -> rgestures.h: GESTURES.current
-
- // Window events
- case WINDOW_CLOSE: CORE.Window.shouldClose = true; break;
- case WINDOW_MAXIMIZE: MaximizeWindow(); break;
- case WINDOW_MINIMIZE: MinimizeWindow(); break;
- case WINDOW_RESIZE: SetWindowSize(events[i].params[0], events[i].params[1]); break;
-
- // Custom events
- case ACTION_TAKE_SCREENSHOT:
- {
- TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter));
- screenshotCounter++;
- } break;
- case ACTION_SETTARGETFPS: SetTargetFPS(events[i].params[0]); break;
- default: break;
- }
- }
+ if (currentEventList->count == currentEventList->capacity) return; // Security check
}
+ //-------------------------------------------------------------------------------------
+
+ // Window events recording
+ //-------------------------------------------------------------------------------------
+ // TODO.
+ //-------------------------------------------------------------------------------------
+
+ // Custom actions events recording
+ //-------------------------------------------------------------------------------------
+ // TODO.
+ //-------------------------------------------------------------------------------------
}
#endif