summaryrefslogtreecommitdiffhomepage
path: root/src/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core.c')
-rw-r--r--src/core.c659
1 files changed, 445 insertions, 214 deletions
diff --git a/src/core.c b/src/core.c
index a3b5f486..07f3bb07 100644
--- a/src/core.c
+++ b/src/core.c
@@ -2,7 +2,13 @@
*
* raylib.core - Basic functions to manage windows, OpenGL context and input on multiple platforms
*
-* The following platforms are supported: Windows, Linux, Mac (OSX), Android, Raspberry Pi, HTML5, Oculus Rift CV1
+* PLATFORMS SUPPORTED:
+* - Windows (win32/Win64)
+* - Linux (tested on Ubuntu)
+* - OSX (Mac)
+* - Android (ARM or ARM64)
+* - Raspberry Pi (Raspbian)
+* - HTML5 (Chrome, Firefox)
*
* CONFIGURATION:
*
@@ -22,17 +28,25 @@
* 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 LOAD_DEFAULT_FONT (defined by default)
+* #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)
*
-* #define INCLUDE_CAMERA_SYSTEM / SUPPORT_CAMERA_SYSTEM
+* #define SUPPORT_CAMERA_SYSTEM
+* Camera module is included (camera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital
*
-* #define INCLUDE_GESTURES_SYSTEM / SUPPORT_GESTURES_SYSTEM
+* #define SUPPORT_GESTURES_SYSTEM
+* Gestures module is included (gestures.h) to support gestures detection: tap, hold, swipe, drag
*
* #define SUPPORT_MOUSE_GESTURES
* Mouse gestures are directly mapped like touches and processed by gestures system.
*
+* #define SUPPORT_BUSY_WAIT_LOOP
+* Use busy wait loop for timming sync, if not defined, a high-resolution timer is setup and used
+*
+* #define SUPPORT_GIF_RECORDING
+* Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback()
+*
* DEPENDENCIES:
* GLFW3 - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX)
* raymath - 3D math functionality (Vector3, Matrix, Quaternion)
@@ -42,7 +56,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
+* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5)
*
* 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.
@@ -61,21 +75,38 @@
*
**********************************************************************************************/
+// Default configuration flags (supported features)
+//-------------------------------------------------
+#define SUPPORT_DEFAULT_FONT
+#define SUPPORT_MOUSE_GESTURES
+#define SUPPORT_CAMERA_SYSTEM
+#define SUPPORT_GESTURES_SYSTEM
+#define SUPPORT_BUSY_WAIT_LOOP
+#define SUPPORT_GIF_RECORDING
+//-------------------------------------------------
+
#include "raylib.h"
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
-#include "utils.h" // Required for: fopen() Android mapping, TraceLog()
+#include "utils.h" // Required for: fopen() Android mapping
#define RAYMATH_IMPLEMENTATION // Use raymath as a header-only library (includes implementation)
#define RAYMATH_EXTERN_INLINE // Compile raymath functions as static inline (remember, it's a compiler hint)
#include "raymath.h" // Required for: Vector3 and Matrix functions
-#define GESTURES_IMPLEMENTATION
-#include "gestures.h" // Gestures detection functionality
+#if defined(SUPPORT_GESTURES_SYSTEM)
+ #define GESTURES_IMPLEMENTATION
+ #include "gestures.h" // Gestures detection functionality
+#endif
-#if !defined(PLATFORM_ANDROID)
+#if defined(SUPPORT_CAMERA_SYSTEM) && !defined(PLATFORM_ANDROID)
#define CAMERA_IMPLEMENTATION
- #include "camera.h" // Camera system functionality
+ #include "camera.h" // Camera system functionality
+#endif
+
+#if defined(SUPPORT_GIF_RECORDING)
+ #define GIF_IMPLEMENTATION
+ #include "external/gif.h" // Support GIF recording
#endif
#include <stdio.h> // Standard input / output lib
@@ -83,12 +114,22 @@
#include <stdint.h> // Required for: typedef unsigned long long int uint64_t, used by hi-res timer
#include <time.h> // Required for: time() - Android/RPI hi-res timer (NOTE: Linux only!)
#include <math.h> // Required for: tan() [Used in Begin3dMode() to set perspective]
-#include <string.h> // Required for: strcmp()
+#include <string.h> // Required for: strrchr(), strcmp()
//#include <errno.h> // Macros for reporting and retrieving error conditions through error codes
-#if defined __linux || defined(PLATFORM_WEB)
+#ifdef _WIN32
+ #include <direct.h> // Required for: _getch(), _chdir()
+ #define GETCWD _getcwd // NOTE: MSDN recommends not to use getcwd(), chdir()
+ #define CHDIR _chdir
+#else
+ #include "unistd.h" // Required for: getch(), chdir() (POSIX)
+ #define GETCWD getcwd
+ #define CHDIR chdir
+#endif
+
+#if defined(__linux__) || defined(PLATFORM_WEB)
#include <sys/time.h> // Required for: timespec, nanosleep(), select() - POSIX
-#elif defined __APPLE__
+#elif defined(__APPLE__)
#include <unistd.h> // Required for: usleep()
#endif
@@ -96,13 +137,19 @@
//#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3
#include <GLFW/glfw3.h> // GLFW3 library: Windows, OpenGL context and Input management
- #ifdef __linux
+ #if defined(__linux__)
#define GLFW_EXPOSE_NATIVE_X11 // Linux specific definitions for getting
#define GLFW_EXPOSE_NATIVE_GLX // native functions like glfwGetX11Window
#include <GLFW/glfw3native.h> // which are required for hiding mouse
#endif
//#include <GL/gl.h> // OpenGL functions (GLFW3 already includes gl.h)
//#define GLFW_DLL // Using GLFW DLL on Windows -> No, we use static version!
+
+ #if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32)
+ // NOTE: Those functions require linking with winmm library
+ __stdcall unsigned int timeBeginPeriod(unsigned int uPeriod);
+ __stdcall unsigned int timeEndPeriod(unsigned int uPeriod);
+ #endif
#endif
#if defined(PLATFORM_ANDROID)
@@ -140,8 +187,6 @@
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
-#define STORAGE_FILENAME "storage.data"
-
#if defined(PLATFORM_RPI)
// Old device inputs system
#define DEFAULT_KEYBOARD_DEV STDIN_FILENO // Standard input
@@ -161,7 +206,7 @@
#define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad)
#define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad)
-#define LOAD_DEFAULT_FONT // Load default font on window initialization (module: text)
+#define STORAGE_FILENAME "storage.data"
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -233,6 +278,7 @@ static Matrix downscaleView; // Matrix to downscale view (in case
static const char *windowTitle; // Window text title...
static bool cursorOnScreen = false; // Tracks if cursor is inside client area
static bool cursorHidden = false; // Track if cursor is hidden
+static int screenshotCounter = 0; // Screenshots counter
// Register mouse states
static char previousMouseState[3] = { 0 }; // Registers previous mouse button state
@@ -259,7 +305,14 @@ static int lastGamepadButtonPressed = -1; // Register last gamepad button pres
static int gamepadAxisCount = 0; // Register number of available gamepad axis
static Vector2 mousePosition; // Mouse position on screen
+
+#if defined(PLATFORM_WEB)
+static bool toggleCursorLock = false; // Ask for cursor pointer lock on next click
+#endif
+
+#if defined(SUPPORT_GESTURES_SYSTEM)
static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen
+#endif
#if defined(PLATFORM_DESKTOP)
static char **dropFilesPath; // Store dropped files paths as strings
@@ -274,10 +327,16 @@ static double targetTime = 0.0; // Desired time for one frame, if 0
static char configFlags = 0; // Configuration flags (bit based)
static bool showLogo = false; // Track if showing logo at init is enabled
+#if defined(SUPPORT_GIF_RECORDING)
+static GifWriter gifWriter;
+static int gifFramesCounter = 0;
+static bool gifRecording = false;
+#endif
+
//----------------------------------------------------------------------------------
// Other Modules Functions Declaration (required by core)
//----------------------------------------------------------------------------------
-#if defined(LOAD_DEFAULT_FONT)
+#if defined(SUPPORT_DEFAULT_FONT)
extern void LoadDefaultFont(void); // [Module: text] Loads default font on InitWindow()
extern void UnloadDefaultFont(void); // [Module: text] Unloads default font from GPU memory
#endif
@@ -296,9 +355,6 @@ static void PollInputEvents(void); // Register user events
static void SwapBuffers(void); // Copy back buffer to front buffers
static void LogoAnimation(void); // Plays raylib logo appearing animation
static void SetupViewport(void); // Set viewport parameters
-#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
-static void TakeScreenshot(void); // Takes a screenshot and saves it in the same folder as executable
-#endif
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
@@ -323,7 +379,9 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
#if defined(PLATFORM_WEB)
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *e, void *userData);
-static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
+static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData);
+static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
+static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData);
#endif
@@ -348,7 +406,7 @@ static void *GamepadThread(void *arg); // Mouse reading thread
// Module Functions Definition - Window and OpenGL Context Functions
//----------------------------------------------------------------------------------
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB)
-// Initialize Window and Graphics Context (OpenGL)
+// Initialize window and OpenGL context
void InitWindow(int width, int height, const char *title)
{
TraceLog(INFO, "Initializing raylib (v1.7.0)");
@@ -359,7 +417,7 @@ void InitWindow(int width, int height, const char *title)
// Init graphics device (display device and OpenGL context)
InitGraphicsDevice(width, height);
-#if defined(LOAD_DEFAULT_FONT)
+#if defined(SUPPORT_DEFAULT_FONT)
// Load default font
// NOTE: External function (defined in module: text)
LoadDefaultFont();
@@ -378,16 +436,22 @@ void InitWindow(int width, int height, const char *title)
#if defined(PLATFORM_WEB)
emscripten_set_fullscreenchange_callback(0, 0, 1, EmscriptenFullscreenChangeCallback);
-
- // NOTE: Some code examples
+
+ // Support keyboard events
+ emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
+
+ // Support mouse events
+ emscripten_set_click_callback("#canvas", NULL, 1, EmscriptenMouseCallback);
+
+ // Support touch events
+ emscripten_set_touchstart_callback("#canvas", NULL, 1, EmscriptenTouchCallback);
+ emscripten_set_touchend_callback("#canvas", NULL, 1, EmscriptenTouchCallback);
+ emscripten_set_touchmove_callback("#canvas", NULL, 1, EmscriptenTouchCallback);
+ emscripten_set_touchcancel_callback("#canvas", NULL, 1, EmscriptenTouchCallback);
//emscripten_set_touchstart_callback(0, NULL, 1, Emscripten_HandleTouch);
//emscripten_set_touchend_callback("#canvas", data, 0, Emscripten_HandleTouch);
- emscripten_set_touchstart_callback("#canvas", NULL, 1, EmscriptenInputCallback);
- emscripten_set_touchend_callback("#canvas", NULL, 1, EmscriptenInputCallback);
- emscripten_set_touchmove_callback("#canvas", NULL, 1, EmscriptenInputCallback);
- emscripten_set_touchcancel_callback("#canvas", NULL, 1, EmscriptenInputCallback);
- // Support gamepad (not provided by GLFW3 on emscripten)
+ // Support gamepad events (not provided by GLFW3 on emscripten)
emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenGamepadCallback);
emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback);
#endif
@@ -405,7 +469,7 @@ void InitWindow(int width, int height, const char *title)
#endif
#if defined(PLATFORM_ANDROID)
-// Android activity initialization
+// Initialize Android activity
void InitWindow(int width, int height, void *state)
{
TraceLog(INFO, "Initializing raylib (v1.7.0)");
@@ -468,10 +532,18 @@ void InitWindow(int width, int height, void *state)
}
#endif
-// Close Window and Terminate Context
+// Close window and unload OpenGL context
void CloseWindow(void)
{
-#if defined(LOAD_DEFAULT_FONT)
+#if defined(SUPPORT_GIF_RECORDING)
+ if (gifRecording)
+ {
+ GifEnd(&gifWriter);
+ gifRecording = false;
+ }
+#endif
+
+#if defined(SUPPORT_DEFAULT_FONT)
UnloadDefaultFont();
#endif
@@ -482,6 +554,10 @@ void CloseWindow(void)
glfwTerminate();
#endif
+#if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32)
+ timeEndPeriod(1); // Restore time period
+#endif
+
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
// Close surface, context and display
if (display != EGL_NO_DISPLAY)
@@ -520,7 +596,7 @@ void CloseWindow(void)
TraceLog(INFO, "Window closed successfully");
}
-// Detect if KEY_ESCAPE pressed or Close icon pressed
+// Check if KEY_ESCAPE pressed or Close icon pressed
bool WindowShouldClose(void)
{
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
@@ -535,7 +611,7 @@ bool WindowShouldClose(void)
#endif
}
-// Detect if window has been minimized (or lost focus)
+// Check if window has been minimized (or lost focus)
bool IsWindowMinimized(void)
{
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
@@ -545,7 +621,7 @@ bool IsWindowMinimized(void)
#endif
}
-// Fullscreen toggle (only PLATFORM_DESKTOP)
+// Toggle fullscreen mode (only PLATFORM_DESKTOP)
void ToggleFullscreen(void)
{
#if defined(PLATFORM_DESKTOP)
@@ -583,12 +659,15 @@ void SetWindowIcon(Image image)
// Set window position on screen (windowed mode)
void SetWindowPosition(int x, int y)
{
+#if defined(PLATFORM_DESKTOP)
glfwSetWindowPos(window, x, y);
+#endif
}
// Set monitor for the current window (fullscreen mode)
void SetWindowMonitor(int monitor)
{
+#if defined(PLATFORM_DESKTOP)
int monitorCount;
GLFWmonitor** monitors = glfwGetMonitors(&monitorCount);
@@ -598,6 +677,16 @@ void SetWindowMonitor(int monitor)
TraceLog(INFO, "Selected fullscreen monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor]));
}
else TraceLog(WARNING, "Selected monitor not found");
+#endif
+}
+
+// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
+void SetWindowMinSize(int width, int height)
+{
+#if defined(PLATFORM_DESKTOP)
+ const GLFWvidmode *mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
+ glfwSetWindowSizeLimits(window, width, height, mode->width, mode->height);
+#endif
}
// Get current screen width
@@ -617,7 +706,7 @@ int GetScreenHeight(void)
void ShowCursor()
{
#if defined(PLATFORM_DESKTOP)
- #ifdef __linux
+ #if defined(__linux__)
XUndefineCursor(glfwGetX11Display(), glfwGetX11Window(window));
#else
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
@@ -626,11 +715,11 @@ void ShowCursor()
cursorHidden = false;
}
-// Hide mouse cursor
+// Hides mouse cursor
void HideCursor()
{
#if defined(PLATFORM_DESKTOP)
- #ifdef __linux
+ #if defined(__linux__)
XColor col;
const char nil[] = {0};
@@ -646,39 +735,45 @@ void HideCursor()
cursorHidden = true;
}
-// Check if mouse cursor is hidden
+// Check if cursor is not visible
bool IsCursorHidden()
{
return cursorHidden;
}
-// Enable mouse cursor
+// Enables cursor (unlock cursor)
void EnableCursor()
{
#if defined(PLATFORM_DESKTOP)
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
#endif
+#if defined(PLATFORM_WEB)
+ toggleCursorLock = true;
+#endif
cursorHidden = false;
}
-// Disable mouse cursor
+// Disables cursor (lock cursor)
void DisableCursor()
{
#if defined(PLATFORM_DESKTOP)
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
#endif
+#if defined(PLATFORM_WEB)
+ toggleCursorLock = true;
+#endif
cursorHidden = true;
}
#endif // !defined(PLATFORM_ANDROID)
-// Sets Background Color
+// Set background color (framebuffer clear color)
void ClearBackground(Color color)
{
// Clear full framebuffer (not only render area) to color
rlClearColor(color.r, color.g, color.b, color.a);
}
-// Setup drawing canvas to start drawing
+// Setup canvas (framebuffer) to start drawing
void BeginDrawing(void)
{
currentTime = GetTime(); // Number of elapsed seconds since InitTimer() was called
@@ -693,11 +788,40 @@ void BeginDrawing(void)
// NOTE: Not required with OpenGL 3.3+
}
-// End canvas drawing and Swap Buffers (Double Buffering)
+// End canvas drawing and swap buffers (double buffering)
void EndDrawing(void)
{
rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
+#if defined(SUPPORT_GIF_RECORDING)
+
+ #define GIF_RECORD_FRAMERATE 10
+
+ if (gifRecording)
+ {
+ gifFramesCounter++;
+
+ // NOTE: We record one gif frame every 10 game frames
+ if ((gifFramesCounter%GIF_RECORD_FRAMERATE) == 0)
+ {
+ // Get image data for the current frame (from backbuffer)
+ // NOTE: This process is very slow... :(
+ unsigned char *screenData = rlglReadScreenPixels(screenWidth, screenHeight);
+ GifWriteFrame(&gifWriter, screenData, screenWidth, screenHeight, 10, 8, false);
+
+ free(screenData); // Free image data
+ }
+
+ if (((gifFramesCounter/15)%2) == 1)
+ {
+ DrawCircle(30, screenHeight - 20, 10, RED);
+ DrawText("RECORDING", 50, screenHeight - 25, 10, MAROON);
+ }
+
+ rlglDraw(); // Draw RECORDING message
+ }
+#endif
+
SwapBuffers(); // Copy back buffer to front buffer
PollInputEvents(); // Poll user events
@@ -721,7 +845,7 @@ void EndDrawing(void)
}
}
-// Initialize 2D mode with custom camera
+// Initialize 2D mode with custom camera (2D)
void Begin2dMode(Camera2D camera)
{
rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
@@ -739,7 +863,7 @@ void Begin2dMode(Camera2D camera)
rlMultMatrixf(MatrixToFloat(matTransform));
}
-// Ends 2D mode custom camera usage
+// Ends 2D mode with custom camera
void End2dMode(void)
{
rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
@@ -747,15 +871,12 @@ void End2dMode(void)
rlLoadIdentity(); // Reset current matrix (MODELVIEW)
}
-// Initializes 3D mode for drawing (Camera setup)
+// Initializes 3D mode with custom camera (3D)
void Begin3dMode(Camera camera)
{
rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
-
- if (IsVrDeviceReady() || IsVrSimulator()) BeginVrDrawing();
-
+
rlMatrixMode(RL_PROJECTION); // Switch to projection matrix
-
rlPushMatrix(); // Save previous matrix, which contains the settings for the 2d ortho projection
rlLoadIdentity(); // Reset current matrix (PROJECTION)
@@ -782,8 +903,6 @@ void End3dMode(void)
{
rlglDraw(); // Process internal buffers (update + draw)
- if (IsVrDeviceReady() || IsVrSimulator()) EndVrDrawing();
-
rlMatrixMode(RL_PROJECTION); // Switch to projection matrix
rlPopMatrix(); // Restore previous matrix (PROJECTION) from matrix stack
@@ -841,7 +960,107 @@ void EndTextureMode(void)
rlLoadIdentity(); // Reset current matrix (MODELVIEW)
}
-// Set target FPS for the game
+// Returns a ray trace from mouse position
+Ray GetMouseRay(Vector2 mousePosition, Camera camera)
+{
+ Ray ray;
+
+ // Calculate normalized device coordinates
+ // NOTE: y value is negative
+ float x = (2.0f*mousePosition.x)/(float)GetScreenWidth() - 1.0f;
+ float y = 1.0f - (2.0f*mousePosition.y)/(float)GetScreenHeight();
+ float z = 1.0f;
+
+ // Store values in a vector
+ Vector3 deviceCoords = { x, y, z };
+
+ TraceLog(DEBUG, "Device coordinates: (%f, %f, %f)", deviceCoords.x, deviceCoords.y, deviceCoords.z);
+
+ // Calculate projection matrix (from perspective instead of frustum)
+ Matrix matProj = MatrixPerspective(camera.fovy, ((double)GetScreenWidth()/(double)GetScreenHeight()), 0.01, 1000.0);
+
+ // Calculate view matrix from camera look at
+ Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
+
+ // Do I need to transpose it? It seems that yes...
+ // NOTE: matrix order may be incorrect... In OpenGL to get world position from
+ // camera view it just needs to get inverted, but here we need to transpose it too.
+ // For example, if you get view matrix, transpose and inverted and you transform it
+ // to a vector, you will get its 3d world position coordinates (camera.position).
+ // If you don't transpose, final position will be wrong.
+ MatrixTranspose(&matView);
+
+//#define USE_RLGL_UNPROJECT
+#if defined(USE_RLGL_UNPROJECT) // OPTION 1: Use rlglUnproject()
+
+ Vector3 nearPoint = rlglUnproject((Vector3){ deviceCoords.x, deviceCoords.y, 0.0f }, matProj, matView);
+ Vector3 farPoint = rlglUnproject((Vector3){ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView);
+
+#else // OPTION 2: Compute unprojection directly here
+
+ // Calculate unproject matrix (multiply projection matrix and view matrix) and invert it
+ Matrix matProjView = MatrixMultiply(matProj, matView);
+ MatrixInvert(&matProjView);
+
+ // Calculate far and near points
+ Quaternion qNear = { deviceCoords.x, deviceCoords.y, 0.0f, 1.0f };
+ Quaternion qFar = { deviceCoords.x, deviceCoords.y, 1.0f, 1.0f };
+
+ // Multiply points by unproject matrix
+ QuaternionTransform(&qNear, matProjView);
+ QuaternionTransform(&qFar, matProjView);
+
+ // Calculate normalized world points in vectors
+ Vector3 nearPoint = { qNear.x/qNear.w, qNear.y/qNear.w, qNear.z/qNear.w};
+ Vector3 farPoint = { qFar.x/qFar.w, qFar.y/qFar.w, qFar.z/qFar.w};
+#endif
+
+ // Calculate normalized direction vector
+ Vector3 direction = VectorSubtract(farPoint, nearPoint);
+ VectorNormalize(&direction);
+
+ // Apply calculated vectors to ray
+ ray.position = camera.position;
+ ray.direction = direction;
+
+ return ray;
+}
+
+// Returns the screen space position from a 3d world space position
+Vector2 GetWorldToScreen(Vector3 position, Camera camera)
+{
+ // Calculate projection matrix (from perspective instead of frustum
+ Matrix matProj = MatrixPerspective(camera.fovy, (double)GetScreenWidth()/(double)GetScreenHeight(), 0.01, 1000.0);
+
+ // Calculate view matrix from camera look at (and transpose it)
+ Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
+ MatrixTranspose(&matView);
+
+ // Convert world position vector to quaternion
+ Quaternion worldPos = { position.x, position.y, position.z, 1.0f };
+
+ // Transform world position to view
+ QuaternionTransform(&worldPos, matView);
+
+ // Transform result to projection (clip space position)
+ QuaternionTransform(&worldPos, matProj);
+
+ // Calculate normalized device coordinates (inverted y)
+ Vector3 ndcPos = { worldPos.x/worldPos.w, -worldPos.y/worldPos.w, worldPos.z/worldPos.w };
+
+ // Calculate 2d screen position vector
+ Vector2 screenPosition = { (ndcPos.x + 1.0f)/2.0f*(float)GetScreenWidth(), (ndcPos.y + 1.0f)/2.0f*(float)GetScreenHeight() };
+
+ return screenPosition;
+}
+
+// Get transform matrix for camera
+Matrix GetCameraMatrix(Camera camera)
+{
+ return MatrixLookAt(camera.position, camera.target, camera.up);
+}
+
+// Set target FPS (maximum)
void SetTargetFPS(int fps)
{
if (fps < 1) targetTime = 0.0;
@@ -856,7 +1075,7 @@ int GetFPS(void)
return (int)(1.0f/GetFrameTime());
}
-// Returns time in seconds for one frame
+// Returns time in seconds for last frame drawn
float GetFrameTime(void)
{
// NOTE: We round value to milliseconds
@@ -888,7 +1107,6 @@ float *VectorToFloat(Vector3 vec)
return buffer;
}
-// Converts Matrix to float array
// NOTE: Returned vector is a transposed version of the Matrix struct,
// it should be this way because, despite raymath use OpenGL column-major convention,
// Matrix struct memory alignment and variables naming are not coherent
@@ -948,7 +1166,7 @@ int GetRandomValue(int min, int max)
return (rand()%(abs(max-min)+1) + min);
}
-// Fades color by a percentadge
+// Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
Color Fade(Color color, float alpha)
{
if (alpha < 0.0f) alpha = 0.0f;
@@ -959,7 +1177,13 @@ Color Fade(Color color, float alpha)
return (Color){color.r, color.g, color.b, (unsigned char)colorAlpha};
}
-// Enable some window/system configurations
+// Activate raylib logo at startup (can be done with flags)
+void ShowLogo(void)
+{
+ showLogo = true;
+}
+
+// Setup window configuration flags (view FLAGS)
void SetConfigFlags(char flags)
{
configFlags = flags;
@@ -968,21 +1192,74 @@ void SetConfigFlags(char flags)
if (configFlags & FLAG_FULLSCREEN_MODE) fullscreen = true;
}
-// Activates raylib logo at startup
-void ShowLogo(void)
+// NOTE TraceLog() function is located in [utils.h]
+
+// Takes a screenshot of current screen (saved a .png)
+void TakeScreenshot(const char *fileName)
{
- showLogo = true;
+#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
+ unsigned char *imgData = rlglReadScreenPixels(renderWidth, renderHeight);
+ SavePNG(fileName, imgData, renderWidth, renderHeight, 4); // Save image as PNG
+ free(imgData);
+
+ TraceLog(INFO, "Screenshot taken: %s", fileName);
+#endif
+}
+
+// Check file extension
+bool IsFileExtension(const char *fileName, const char *ext)
+{
+ bool result = false;
+ const char *fileExt;
+
+ if ((fileExt = strrchr(fileName, '.')) != NULL)
+ {
+ if (strcmp(fileExt, ext) == 0) result = true;
+ }
+
+ return result;
+}
+
+// Get directory for a given fileName (with path)
+const char *GetDirectoryPath(const char *fileName)
+{
+ char *lastSlash = NULL;
+ static char filePath[256]; // MAX_DIRECTORY_PATH_SIZE = 256
+ memset(filePath, 0, 256);
+
+ lastSlash = strrchr(fileName, '\\');
+ strncpy(filePath, fileName, strlen(fileName) - (strlen(lastSlash) - 1));
+ filePath[strlen(fileName) - strlen(lastSlash)] = '\0';
+
+ return filePath;
+}
+
+// Get current working directory
+const char *GetWorkingDirectory(void)
+{
+ static char currentDir[256]; // MAX_DIRECTORY_PATH_SIZE = 256
+ memset(currentDir, 0, 256);
+
+ GETCWD(currentDir, 256 - 1);
+
+ return currentDir;
+}
+
+// Change working directory, returns true if success
+bool ChangeDirectory(const char *dir)
+{
+ return (CHDIR(dir) == 0);
}
#if defined(PLATFORM_DESKTOP)
-// Check if a file have been dropped into window
+// Check if a file has been dropped into window
bool IsFileDropped(void)
{
if (dropFilesCount > 0) return true;
else return false;
}
-// Retrieve dropped files into window
+// Get dropped files names
char **GetDroppedFiles(int *count)
{
*count = dropFilesCount;
@@ -1003,7 +1280,7 @@ void ClearDroppedFiles(void)
}
#endif
-// Storage save integer value (to defined position)
+// Save integer value to storage file (to defined position)
// NOTE: Storage positions is directly related to file memory layout (4 bytes each integer)
void StorageSaveValue(int position, int value)
{
@@ -1043,7 +1320,7 @@ void StorageSaveValue(int position, int value)
}
}
-// Storage load integer value (from defined position)
+// Load integer value from storage file (from defined position)
// NOTE: If requested position could not be found, value 0 is returned
int StorageLoadValue(int position)
{
@@ -1082,106 +1359,6 @@ int StorageLoadValue(int position)
return value;
}
-// Returns a ray trace from mouse position
-Ray GetMouseRay(Vector2 mousePosition, Camera camera)
-{
- Ray ray;
-
- // Calculate normalized device coordinates
- // NOTE: y value is negative
- float x = (2.0f*mousePosition.x)/(float)GetScreenWidth() - 1.0f;
- float y = 1.0f - (2.0f*mousePosition.y)/(float)GetScreenHeight();
- float z = 1.0f;
-
- // Store values in a vector
- Vector3 deviceCoords = { x, y, z };
-
- TraceLog(DEBUG, "Device coordinates: (%f, %f, %f)", deviceCoords.x, deviceCoords.y, deviceCoords.z);
-
- // Calculate projection matrix (from perspective instead of frustum)
- Matrix matProj = MatrixPerspective(camera.fovy, ((double)GetScreenWidth()/(double)GetScreenHeight()), 0.01, 1000.0);
-
- // Calculate view matrix from camera look at
- Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
-
- // Do I need to transpose it? It seems that yes...
- // NOTE: matrix order may be incorrect... In OpenGL to get world position from
- // camera view it just needs to get inverted, but here we need to transpose it too.
- // For example, if you get view matrix, transpose and inverted and you transform it
- // to a vector, you will get its 3d world position coordinates (camera.position).
- // If you don't transpose, final position will be wrong.
- MatrixTranspose(&matView);
-
-//#define USE_RLGL_UNPROJECT
-#if defined(USE_RLGL_UNPROJECT) // OPTION 1: Use rlglUnproject()
-
- Vector3 nearPoint = rlglUnproject((Vector3){ deviceCoords.x, deviceCoords.y, 0.0f }, matProj, matView);
- Vector3 farPoint = rlglUnproject((Vector3){ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView);
-
-#else // OPTION 2: Compute unprojection directly here
-
- // Calculate unproject matrix (multiply projection matrix and view matrix) and invert it
- Matrix matProjView = MatrixMultiply(matProj, matView);
- MatrixInvert(&matProjView);
-
- // Calculate far and near points
- Quaternion near = { deviceCoords.x, deviceCoords.y, 0.0f, 1.0f };
- Quaternion far = { deviceCoords.x, deviceCoords.y, 1.0f, 1.0f };
-
- // Multiply points by unproject matrix
- QuaternionTransform(&near, matProjView);
- QuaternionTransform(&far, matProjView);
-
- // Calculate normalized world points in vectors
- Vector3 nearPoint = { near.x/near.w, near.y/near.w, near.z/near.w};
- Vector3 farPoint = { far.x/far.w, far.y/far.w, far.z/far.w};
-#endif
-
- // Calculate normalized direction vector
- Vector3 direction = VectorSubtract(farPoint, nearPoint);
- VectorNormalize(&direction);
-
- // Apply calculated vectors to ray
- ray.position = camera.position;
- ray.direction = direction;
-
- return ray;
-}
-
-// Returns the screen space position from a 3d world space position
-Vector2 GetWorldToScreen(Vector3 position, Camera camera)
-{
- // Calculate projection matrix (from perspective instead of frustum
- Matrix matProj = MatrixPerspective(camera.fovy, (double)GetScreenWidth()/(double)GetScreenHeight(), 0.01, 1000.0);
-
- // Calculate view matrix from camera look at (and transpose it)
- Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
- MatrixTranspose(&matView);
-
- // Convert world position vector to quaternion
- Quaternion worldPos = { position.x, position.y, position.z, 1.0f };
-
- // Transform world position to view
- QuaternionTransform(&worldPos, matView);
-
- // Transform result to projection (clip space position)
- QuaternionTransform(&worldPos, matProj);
-
- // Calculate normalized device coordinates (inverted y)
- Vector3 ndcPos = { worldPos.x/worldPos.w, -worldPos.y/worldPos.w, worldPos.z/worldPos.w };
-
- // Calculate 2d screen position vector
- Vector2 screenPosition = { (ndcPos.x + 1.0f)/2.0f*(float)GetScreenWidth(), (ndcPos.y + 1.0f)/2.0f*(float)GetScreenHeight() };
-
- return screenPosition;
-}
-
-// Get transform matrix for camera
-Matrix GetCameraMatrix(Camera camera)
-{
- return MatrixLookAt(camera.position, camera.target, camera.up);
-}
-
//----------------------------------------------------------------------------------
// Module Functions Definition - Input (Keyboard, Mouse, Gamepad) Functions
//----------------------------------------------------------------------------------
@@ -1467,7 +1644,7 @@ int GetMouseWheelMove(void)
#endif
}
-// Returns touch position X
+// Returns touch position X for touch point 0 (relative to screen size)
int GetTouchX(void)
{
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB)
@@ -1477,7 +1654,7 @@ int GetTouchX(void)
#endif
}
-// Returns touch position Y
+// Returns touch position Y for touch point 0 (relative to screen size)
int GetTouchY(void)
{
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB)
@@ -1487,7 +1664,7 @@ int GetTouchY(void)
#endif
}
-// Returns touch position XY
+// Returns touch position XY for a touch point index (relative to screen size)
// TODO: Touch position should be scaled depending on display size and render size
Vector2 GetTouchPosition(int index)
{
@@ -1597,7 +1774,7 @@ static void InitGraphicsDevice(int width, int height)
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint)
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Profiles Hint: Only 3.3 and above!
// Other values: GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE
-#ifdef __APPLE__
+#if defined(__APPLE__)
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // OSX Requires
#else
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE); // Fordward Compatibility Hint: Only 3.3 and above!
@@ -1739,12 +1916,13 @@ static void InitGraphicsDevice(int width, int height)
const EGLint framebufferAttribs[] =
{
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, // Type of context support -> Required on RPI?
- //EGL_SURFACE_TYPE, EGL_WINDOW_BIT, // Don't use it on Android!
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, // Type of context support -> Required on RPI?
+ //EGL_SURFACE_TYPE, EGL_WINDOW_BIT, // Don't use it on Android!
EGL_RED_SIZE, 8, // RED color bit depth (alternative: 5)
EGL_GREEN_SIZE, 8, // GREEN color bit depth (alternative: 6)
EGL_BLUE_SIZE, 8, // BLUE color bit depth (alternative: 5)
- //EGL_ALPHA_SIZE, 8, // ALPHA bit depth
+ //EGL_ALPHA_SIZE, 8, // ALPHA bit depth (required for transparent framebuffer)
+ //EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI)
EGL_DEPTH_SIZE, 16, // Depth buffer size (Required to use Depth testing!)
//EGL_STENCIL_SIZE, 8, // Stencil buffer size
EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA
@@ -1819,7 +1997,7 @@ static void InitGraphicsDevice(int width, int height)
VC_DISPMANX_ALPHA_T alpha;
alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS;
- alpha.opacity = 255;
+ alpha.opacity = 255; // Set transparency level for framebuffer, requires EGLAttrib: EGL_TRANSPARENT_TYPE
alpha.mask = 0;
dispmanDisplay = vc_dispmanx_display_open(0); // LCD
@@ -1882,7 +2060,7 @@ static void InitGraphicsDevice(int width, int height)
// Set viewport parameters
static void SetupViewport(void)
{
-#ifdef __APPLE__
+#if defined(__APPLE__)
// Get framebuffer size of current window
// NOTE: Required to handle HighDPI display correctly on OSX because framebuffer
// is automatically reasized to adapt to new DPI.
@@ -1974,6 +2152,10 @@ static void SetupFramebufferSize(int displayWidth, int displayHeight)
static void InitTimer(void)
{
srand(time(NULL)); // Initialize random seed
+
+#if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32)
+ timeBeginPeriod(1); // Setup high-resolution timer to 1ms (granularity of 1-2 ms)
+#endif
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
struct timespec now;
@@ -2005,9 +2187,11 @@ static double GetTime(void)
}
// Wait for some milliseconds (stop program execution)
+// NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could
+// take longer than expected... for that reason we use the busy wait loop
+// http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected
static void Wait(float ms)
{
-#define SUPPORT_BUSY_WAIT_LOOP
#if defined(SUPPORT_BUSY_WAIT_LOOP)
double prevTime = GetTime();
double nextTime = 0.0;
@@ -2015,9 +2199,9 @@ static void Wait(float ms)
// Busy wait loop
while ((nextTime - prevTime) < ms/1000.0f) nextTime = GetTime();
#else
- #if defined _WIN32
- Sleep(ms);
- #elif defined __linux || defined(PLATFORM_WEB)
+ #if defined(_WIN32)
+ Sleep((unsigned int)ms);
+ #elif defined(__linux__) || defined(PLATFORM_WEB)
struct timespec req = { 0 };
time_t sec = (int)(ms/1000.0f);
ms -= (sec*1000);
@@ -2026,7 +2210,7 @@ static void Wait(float ms)
// NOTE: Use nanosleep() on Unix platforms... usleep() it's deprecated.
while (nanosleep(&req, &req) == -1) continue;
- #elif defined __APPLE__
+ #elif defined(__APPLE__)
usleep(ms*1000.0f);
#endif
#endif
@@ -2065,9 +2249,11 @@ static bool GetMouseButtonStatus(int button)
// Poll (store) all input events
static void PollInputEvents(void)
{
+#if defined(SUPPORT_GESTURES_SYSTEM)
// NOTE: Gestures update must be called every frame to reset gestures correctly
// because ProcessGestureEvent() is just called on an event, not every frame
UpdateGestures();
+#endif
// Reset last key pressed registered
lastKeyPressed = -1;
@@ -2238,28 +2424,6 @@ static void SwapBuffers(void)
#endif
}
-#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
-// Takes a screenshot and saves it in the same folder as executable
-static void TakeScreenshot(void)
-{
- static int shotNum = 0; // Screenshot number, increments every screenshot take during program execution
- char buffer[20]; // Buffer to store file name
-
- unsigned char *imgData = rlglReadScreenPixels(renderWidth, renderHeight);
-
- sprintf(buffer, "screenshot%03i.png", shotNum);
-
- // Save image as PNG
- SavePNG(buffer, imgData, renderWidth, renderHeight, 4);
-
- free(imgData);
-
- shotNum++;
-
- TraceLog(INFO, "[%s] Screenshot taken!", buffer);
-}
-#endif
-
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
// GLFW3 Error Callback, runs on GLFW3 error
static void ErrorCallback(int error, const char *description)
@@ -2283,8 +2447,39 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
// NOTE: Before closing window, while loop must be left!
}
#if defined(PLATFORM_DESKTOP)
- else if (key == GLFW_KEY_F12 && action == GLFW_PRESS) TakeScreenshot();
-#endif
+ else if (key == GLFW_KEY_F12 && action == GLFW_PRESS)
+ {
+ #if defined(SUPPORT_GIF_RECORDING)
+ if (mods == GLFW_MOD_CONTROL)
+ {
+ if (gifRecording)
+ {
+ GifEnd(&gifWriter);
+ gifRecording = false;
+
+ TraceLog(INFO, "End animated GIF recording");
+ }
+ else
+ {
+ gifRecording = true;
+ gifFramesCounter = 0;
+
+ // NOTE: delay represents the time between frames in the gif, if we capture a gif frame every
+ // 10 game frames and each frame trakes 16.6ms (60fps), delay between gif frames should be ~16.6*10.
+ GifBegin(&gifWriter, FormatText("screenrec%03i.gif", screenshotCounter), screenWidth, screenHeight, (int)(GetFrameTime()*10.0f), 8, false);
+ screenshotCounter++;
+
+ TraceLog(INFO, "Begin animated GIF recording: %s", FormatText("screenrec%03i.gif", screenshotCounter));
+ }
+ }
+ else
+ #endif // SUPPORT_GIF_RECORDING
+ {
+ TakeScreenshot(FormatText("screenshot%03i.png", screenshotCounter));
+ screenshotCounter++;
+ }
+ }
+#endif // PLATFORM_DESKTOP
else
{
currentKeyState[key] = action;
@@ -2297,8 +2492,7 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int
{
currentMouseState[button] = action;
-#define ENABLE_MOUSE_GESTURES
-#if defined(ENABLE_MOUSE_GESTURES)
+#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
// Process mouse events as touches to be able to use mouse-gestures
GestureEvent gestureEvent;
@@ -2329,8 +2523,7 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int
// GLFW3 Cursor Position Callback, runs on mouse move
static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
{
-#define ENABLE_MOUSE_GESTURES
-#if defined(ENABLE_MOUSE_GESTURES)
+#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
// Process mouse events as touches to be able to use mouse-gestures
GestureEvent gestureEvent;
@@ -2460,7 +2653,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
// Init graphics device (display device and OpenGL context)
InitGraphicsDevice(screenWidth, screenHeight);
- #if defined(LOAD_DEFAULT_FONT)
+ #if defined(SUPPORT_DEFAULT_FONT)
// Load default font
// NOTE: External function (defined in module: text)
LoadDefaultFont();
@@ -2664,8 +2857,42 @@ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const Emscripte
return 0;
}
+// Register keyboard input events
+static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
+{
+ if ((eventType == EMSCRIPTEN_EVENT_KEYPRESS) && (strcmp(keyEvent->code, "Escape") == 0))
+ {
+ emscripten_exit_pointerlock();
+ }
+
+ return 0;
+}
+
+// Register mouse input events
+static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
+{
+ // Lock mouse pointer when click on screen
+ if ((eventType == EMSCRIPTEN_EVENT_CLICK) && toggleCursorLock)
+ {
+ EmscriptenPointerlockChangeEvent plce;
+ emscripten_get_pointerlock_status(&plce);
+
+ if (!plce.isActive) emscripten_request_pointerlock(0, 1);
+ else
+ {
+ emscripten_exit_pointerlock();
+ emscripten_get_pointerlock_status(&plce);
+ //if (plce.isActive) TraceLog(WARNING, "Pointer lock exit did not work!");
+ }
+
+ toggleCursorLock = false;
+ }
+
+ return 0;
+}
+
// Register touch input events
-static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
+static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
{
/*
for (int i = 0; i < touchEvent->numTouches; i++)
@@ -2891,8 +3118,12 @@ static void ProcessKeyboard(void)
// Check exit key (same functionality as GLFW3 KeyCallback())
if (currentKeyState[exitKey] == 1) windowShouldClose = true;
- // Check screen capture key
- if (currentKeyState[301] == 1) TakeScreenshot(); // raylib key: KEY_F12 (GLFW_KEY_F12)
+ // Check screen capture key (raylib key: KEY_F12)
+ if (currentKeyState[301] == 1)
+ {
+ TakeScreenshot(FormatText("screenshot%03i.png", screenshotCounter));
+ screenshotCounter++;
+ }
}
// Restore default keyboard input
@@ -3179,7 +3410,7 @@ static void *GamepadThread(void *arg)
// Plays raylib logo appearing animation
static void LogoAnimation(void)
{
-#ifndef PLATFORM_WEB
+#if !defined(PLATFORM_WEB)
int logoPositionX = screenWidth/2 - 128;
int logoPositionY = screenHeight/2 - 128;