Update C sources

This commit is contained in:
Milan Nikolic 2025-06-09 15:53:56 +02:00
parent e08c4cd054
commit 3327fcaf9f
No known key found for this signature in database
GPG key ID: 9229D0EAA3AA4E75
22 changed files with 14167 additions and 10920 deletions

View file

@ -6,7 +6,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2018-2024 Ahmad Fatoum & Ramon Santamaria (@raysan5)
* Copyright (c) 2018-2025 Ahmad Fatoum & 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.
@ -71,6 +71,30 @@
// Enabling this flag allows manual control of the frame processes, use at your own risk
//#define SUPPORT_CUSTOM_FRAME_CONTROL 1
// Support for clipboard image loading
// NOTE: Only working on SDL3, GLFW (Windows) and RGFW (Windows)
#define SUPPORT_CLIPBOARD_IMAGE 1
// NOTE: Clipboard image loading requires support for some image file formats
// TODO: Those defines should probably be removed from here, I prefer to let the user manage them
#if defined(SUPPORT_CLIPBOARD_IMAGE)
#ifndef SUPPORT_MODULE_RTEXTURES
#define SUPPORT_MODULE_RTEXTURES 1
#endif
#ifndef STBI_REQUIRED
#define STBI_REQUIRED
#endif
#ifndef SUPPORT_FILEFORMAT_BMP // For clipboard image on Windows
#define SUPPORT_FILEFORMAT_BMP 1
#endif
#ifndef SUPPORT_FILEFORMAT_PNG // Wayland uses png for prints, at least it was on 22 LTS ubuntu
#define SUPPORT_FILEFORMAT_PNG 1
#endif
#ifndef SUPPORT_FILEFORMAT_JPG
#define SUPPORT_FILEFORMAT_JPG 1
#endif
#endif
// rcore: Configuration values
//------------------------------------------------------------------------------------
@ -80,7 +104,7 @@
#define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported
#define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported
#define MAX_GAMEPADS 4 // Maximum number of gamepads supported
#define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad)
#define MAX_GAMEPAD_AXES 8 // Maximum number of axes supported (per gamepad)
#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
#define MAX_GAMEPAD_VIBRATION_TIME 2.0f // Maximum vibration time in seconds
#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
@ -112,8 +136,8 @@
#define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported
#define RL_CULL_DISTANCE_NEAR 0.01 // Default projection matrix near cull distance
#define RL_CULL_DISTANCE_FAR 1000.0 // Default projection matrix far cull distance
#define RL_CULL_DISTANCE_NEAR 0.001 // Default projection matrix near cull distance
#define RL_CULL_DISTANCE_FAR 10000.0 // Default projection matrix far cull distance
// Default shader vertex attribute locations
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0
@ -127,6 +151,8 @@
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 7
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8
#endif
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX 9
// Default shader vertex attribute names to set location points
// NOTE: When a new shader is loaded, the following locations are tried to be set for convenience
@ -273,31 +299,4 @@
//------------------------------------------------------------------------------------
#define MAX_TRACELOG_MSG_LENGTH 256 // Max length of one trace-log message
// Enable partial support for clipboard image, only working on SDL3 or
// being on both Windows OS + GLFW or Windows OS + RGFW
#define SUPPORT_CLIPBOARD_IMAGE 1
#if defined(SUPPORT_CLIPBOARD_IMAGE)
#ifndef STBI_REQUIRED
#define STBI_REQUIRED
#endif
#ifndef SUPPORT_FILEFORMAT_BMP // For clipboard image on Windows
#define SUPPORT_FILEFORMAT_BMP 1
#endif
#ifndef SUPPORT_FILEFORMAT_PNG // Wayland uses png for prints, at least it was on 22 LTS ubuntu
#define SUPPORT_FILEFORMAT_PNG 1
#endif
#ifndef SUPPORT_FILEFORMAT_JPG
#define SUPPORT_FILEFORMAT_JPG 1
#endif
#ifndef SUPPORT_MODULE_RTEXTURES
#define SUPPORT_MODULE_RTEXTURES 1
#endif
#endif
#endif // CONFIG_H

15670
raylib/external/RGFW.h vendored

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -171,10 +171,11 @@ extern int zsinflate(void *out, int cap, const void *in, int size);
static int
sinfl_bsr(unsigned n) {
#if defined(_MSC_VER) && !defined(__clang__)
_BitScanReverse(&n, n);
return n;
#elif defined(__GNUC__) || defined(__clang__)
#ifdef _MSC_VER
unsigned long uln = 0;
_BitScanReverse(&uln, n);
return (int)(uln);
#else // defined(__GNUC__) || defined(__clang__) || defined(__TINYC__)
return 31 - __builtin_clz(n);
#endif
}

View file

@ -1863,11 +1863,11 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
stbtt_vertex* v = &comp_verts[i];
stbtt_vertex_type x,y;
x=v->x; y=v->y;
v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
v->x = (stbtt_vertex_type)(mtx[0]*x + mtx[2]*y + mtx[4]*m);
v->y = (stbtt_vertex_type)(mtx[1]*x + mtx[3]*y + mtx[5]*n);
x=v->cx; y=v->cy;
v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
v->cx = (stbtt_vertex_type)(mtx[0]*x + mtx[2]*y + mtx[4]*m);
v->cy = (stbtt_vertex_type)(mtx[1]*x + mtx[3]*y + mtx[5]*n);
}
// Append vertices.
tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata);

View file

@ -27,7 +27,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) and contributors
* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@ -70,6 +70,16 @@ typedef struct {
EGLConfig config; // Graphic config
} PlatformData;
typedef struct {
// Store data for both Hover and Touch events
// Used to ignore Hover events which are interpreted as Touch events
int32_t pointCount; // Number of touch points active
int32_t pointId[MAX_TOUCH_POINTS]; // Point identifiers
Vector2 position[MAX_TOUCH_POINTS]; // Touch position on screen
int32_t hoverPoints[MAX_TOUCH_POINTS]; // Hover Points
} TouchRaw;
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
@ -246,6 +256,8 @@ static const KeyboardKey mapKeycode[KEYCODE_MAP_SIZE] = {
KEY_KP_EQUAL // AKEYCODE_NUMPAD_EQUALS
};
static TouchRaw touchRaw = { 0 };
//----------------------------------------------------------------------------------
// Module Internal Functions Declaration
//----------------------------------------------------------------------------------
@ -339,7 +351,7 @@ void MinimizeWindow(void)
TRACELOG(LOG_WARNING, "MinimizeWindow() not available on target platform");
}
// Set window state: not minimized/maximized
// Restore window from being minimized/maximized
void RestoreWindow(void)
{
TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform");
@ -433,7 +445,7 @@ int GetMonitorCount(void)
return 1;
}
// Get number of monitors
// Get current monitor where window is placed
int GetCurrentMonitor(void)
{
TRACELOG(LOG_WARNING, "GetCurrentMonitor() not implemented on target platform");
@ -462,17 +474,21 @@ int GetMonitorHeight(int monitor)
}
// Get selected monitor physical width in millimetres
// NOTE: It seems to return a slightly underestimated value on some devices
int GetMonitorPhysicalWidth(int monitor)
{
TRACELOG(LOG_WARNING, "GetMonitorPhysicalWidth() not implemented on target platform");
return 0;
int widthPixels = ANativeWindow_getWidth(platform.app->window);
float dpi = AConfiguration_getDensity(platform.app->config);
return (widthPixels/dpi)*25.4f;
}
// Get selected monitor physical height in millimetres
// NOTE: It seems to return a slightly underestimated value on some devices
int GetMonitorPhysicalHeight(int monitor)
{
TRACELOG(LOG_WARNING, "GetMonitorPhysicalHeight() not implemented on target platform");
return 0;
int heightPixels = ANativeWindow_getHeight(platform.app->window);
float dpi = AConfiguration_getDensity(platform.app->config);
return (heightPixels/dpi)*25.4f;
}
// Get selected monitor refresh rate
@ -499,8 +515,9 @@ Vector2 GetWindowPosition(void)
// Get window scale DPI factor for current monitor
Vector2 GetWindowScaleDPI(void)
{
TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform");
return (Vector2){ 1.0f, 1.0f };
int density = AConfiguration_getDensity(platform.app->config);
float scale = (float)density/160;
return (Vector2){ scale, scale };
}
// Set clipboard text content
@ -629,7 +646,7 @@ int SetGamepadMappings(const char *mappings)
// Set gamepad vibration
void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration)
{
TRACELOG(LOG_WARNING, "GamepadSetVibration() not implemented on target platform");
TRACELOG(LOG_WARNING, "SetGamepadVibration() not implemented on target platform");
}
// Set mouse position XY
@ -701,7 +718,7 @@ void PollInputEvents(void)
// Poll Events (registered events) until we reach TIMEOUT which indicates there are no events left to poll
// NOTE: Activity is paused if not enabled (platform.appEnabled)
while ((pollResult = ALooper_pollOnce(platform.appEnabled? 0 : -1, NULL, &pollEvents, (void**)&platform.source)) > ALOOPER_POLL_TIMEOUT)
while ((pollResult = ALooper_pollOnce(platform.appEnabled? 0 : -1, NULL, &pollEvents, ((void **)&platform.source)) > ALOOPER_POLL_TIMEOUT))
{
// Process this event
if (platform.source != NULL) platform.source->process(platform.app, platform.source);
@ -788,7 +805,7 @@ int InitPlatform(void)
while (!CORE.Window.ready)
{
// Process events until we reach TIMEOUT, which indicates no more events queued.
while ((pollResult = ALooper_pollOnce(0, NULL, &pollEvents, (void**)&platform.source)) > ALOOPER_POLL_TIMEOUT)
while ((pollResult = ALooper_pollOnce(0, NULL, &pollEvents, ((void **)&platform.source)) > ALOOPER_POLL_TIMEOUT))
{
// Process this event
if (platform.source != NULL) platform.source->process(platform.app, platform.source);
@ -798,6 +815,8 @@ int InitPlatform(void)
}
}
for (int i = 0; i < MAX_TOUCH_POINTS; i++) touchRaw.hoverPoints[i] = -1;
return 0;
}
@ -850,22 +869,20 @@ static int InitGraphicsDevice(void)
TRACELOG(LOG_INFO, "DISPLAY: Trying to enable MSAA x4");
}
const EGLint framebufferAttribs[] =
{
EGL_RENDERABLE_TYPE, (rlGetVersion() == RL_OPENGL_ES_30)? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT, // Type of context support
const EGLint framebufferAttribs[] = {
EGL_RENDERABLE_TYPE, (rlGetVersion() == RL_OPENGL_ES_30)? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT, // Type of context support
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_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_DEPTH_SIZE, 24, // Depth buffer size (Required to use Depth testing!)
//EGL_STENCIL_SIZE, 8, // Stencil buffer size
EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA
EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA
EGL_SAMPLES, samples, // 4x Antialiasing if activated (Free on MALI GPUs)
EGL_NONE
};
const EGLint contextAttribs[] =
{
const EGLint contextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
@ -1228,7 +1245,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
return 1; // Handled gamepad button
}
KeyboardKey key = (keycode > 0 && keycode < KEYCODE_MAP_SIZE)? mapKeycode[keycode] : KEY_NULL;
KeyboardKey key = ((keycode > 0) && (keycode < KEYCODE_MAP_SIZE))? mapKeycode[keycode] : KEY_NULL;
if (key != KEY_NULL)
{
// Save current key and its state
@ -1268,25 +1285,85 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
}
// Register touch points count
CORE.Input.Touch.pointCount = AMotionEvent_getPointerCount(event);
touchRaw.pointCount = AMotionEvent_getPointerCount(event);
for (int i = 0; (i < CORE.Input.Touch.pointCount) && (i < MAX_TOUCH_POINTS); i++)
for (int i = 0; (i < touchRaw.pointCount) && (i < MAX_TOUCH_POINTS); i++)
{
// Register touch points id
CORE.Input.Touch.pointId[i] = AMotionEvent_getPointerId(event, i);
touchRaw.pointId[i] = AMotionEvent_getPointerId(event, i);
// Register touch points position
CORE.Input.Touch.position[i] = (Vector2){ AMotionEvent_getX(event, i), AMotionEvent_getY(event, i) };
touchRaw.position[i] = (Vector2){ AMotionEvent_getX(event, i), AMotionEvent_getY(event, i) };
// Normalize CORE.Input.Touch.position[i] for CORE.Window.screen.width and CORE.Window.screen.height
float widthRatio = (float)(CORE.Window.screen.width + CORE.Window.renderOffset.x)/(float)CORE.Window.display.width;
float heightRatio = (float)(CORE.Window.screen.height + CORE.Window.renderOffset.y)/(float)CORE.Window.display.height;
CORE.Input.Touch.position[i].x = CORE.Input.Touch.position[i].x*widthRatio - (float)CORE.Window.renderOffset.x/2;
CORE.Input.Touch.position[i].y = CORE.Input.Touch.position[i].y*heightRatio - (float)CORE.Window.renderOffset.y/2;
touchRaw.position[i].x = touchRaw.position[i].x*widthRatio - (float)CORE.Window.renderOffset.x/2;
touchRaw.position[i].y = touchRaw.position[i].y*heightRatio - (float)CORE.Window.renderOffset.y/2;
}
int32_t action = AMotionEvent_getAction(event);
unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
if (flags == AMOTION_EVENT_ACTION_HOVER_ENTER)
{
// The new pointer is hover
// So add it to hoverPoints
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
{
if (touchRaw.hoverPoints[i] == -1)
{
touchRaw.hoverPoints[i] = touchRaw.pointId[pointerIndex];
break;
}
}
}
if ((flags == AMOTION_EVENT_ACTION_POINTER_UP) || (flags == AMOTION_EVENT_ACTION_UP) || (flags == AMOTION_EVENT_ACTION_HOVER_EXIT))
{
// One of the touchpoints is released, remove it from touch point arrays
if (flags == AMOTION_EVENT_ACTION_HOVER_EXIT)
{
// If the touchPoint is hover, remove it from hoverPoints
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
{
if (touchRaw.hoverPoints[i] == touchRaw.pointId[pointerIndex])
{
touchRaw.hoverPoints[i] = -1;
break;
}
}
}
for (int i = pointerIndex; (i < touchRaw.pointCount - 1) && (i < MAX_TOUCH_POINTS - 1); i++)
{
touchRaw.pointId[i] = touchRaw.pointId[i+1];
touchRaw.position[i] = touchRaw.position[i+1];
}
touchRaw.pointCount--;
}
int pointCount = 0;
for (int i = 0; (i < touchRaw.pointCount) && (i < MAX_TOUCH_POINTS); i++)
{
// If the touchPoint is hover, Ignore it
bool hover = false;
for (int j = 0; j < MAX_TOUCH_POINTS; j++)
{
// Check if the touchPoint is in hoverPointers
if (touchRaw.hoverPoints[j] == touchRaw.pointId[i])
{
hover = true;
break;
}
}
if (hover) continue;
CORE.Input.Touch.pointId[pointCount] = touchRaw.pointId[i];
CORE.Input.Touch.position[pointCount] = touchRaw.position[i];
pointCount++;
}
CORE.Input.Touch.pointCount = pointCount;
#if defined(SUPPORT_GESTURES_SYSTEM)
GestureEvent gestureEvent = { 0 };
@ -1311,20 +1388,6 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
ProcessGestureEvent(gestureEvent);
#endif
int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
if (flags == AMOTION_EVENT_ACTION_POINTER_UP || flags == AMOTION_EVENT_ACTION_UP)
{
// One of the touchpoints is released, remove it from touch point arrays
for (int i = pointerIndex; (i < CORE.Input.Touch.pointCount - 1) && (i < MAX_TOUCH_POINTS); i++)
{
CORE.Input.Touch.pointId[i] = CORE.Input.Touch.pointId[i+1];
CORE.Input.Touch.position[i] = CORE.Input.Touch.position[i+1];
}
CORE.Input.Touch.pointCount--;
}
// When all touchpoints are tapped and released really quickly, this event is generated
if (flags == AMOTION_EVENT_ACTION_CANCEL) CORE.Input.Touch.pointCount = 0;

View file

@ -1,6 +1,6 @@
/**********************************************************************************************
*
* rcore_desktop - Functions to manage window, graphics device and inputs
* rcore_desktop_glfw - Functions to manage window, graphics device and inputs
*
* PLATFORM: DESKTOP: GLFW
* - Windows (Win32, Win64)
@ -30,7 +30,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) and contributors
* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@ -86,6 +86,8 @@
#include "GLFW/glfw3native.h" // Required for: glfwGetCocoaWindow()
#endif
#include <stddef.h> // Required for: size_t
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
@ -127,6 +129,11 @@ static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffs
static void CursorEnterCallback(GLFWwindow *window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area
static void JoystickCallback(int jid, int event); // GLFW3 Joystick Connected/Disconnected Callback
// Wrappers used by glfwInitAllocator
static void *AllocateWrapper(size_t size, void *user); // GLFW3 GLFWallocatefun, wrapps around RL_MALLOC macro
static void *ReallocateWrapper(void *block, size_t size, void *user); // GLFW3 GLFWreallocatefun, wrapps around RL_MALLOC macro
static void DeallocateWrapper(void *block, void *user); // GLFW3 GLFWdeallocatefun, wraps around RL_FREE macro
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
@ -223,11 +230,9 @@ void ToggleBorderlessWindowed(void)
if (!wasOnFullscreen) CORE.Window.previousPosition = CORE.Window.position;
CORE.Window.previousScreen = CORE.Window.screen;
// Set undecorated and topmost modes and flags
// Set undecorated flag
glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_FALSE);
CORE.Window.flags |= FLAG_WINDOW_UNDECORATED;
glfwSetWindowAttrib(platform.handle, GLFW_FLOATING, GLFW_TRUE);
CORE.Window.flags |= FLAG_WINDOW_TOPMOST;
// Get monitor position and size
int monitorPosX = 0;
@ -247,9 +252,7 @@ void ToggleBorderlessWindowed(void)
}
else
{
// Remove topmost and undecorated modes and flags
glfwSetWindowAttrib(platform.handle, GLFW_FLOATING, GLFW_FALSE);
CORE.Window.flags &= ~FLAG_WINDOW_TOPMOST;
// Remove undecorated flag
glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE);
CORE.Window.flags &= ~FLAG_WINDOW_UNDECORATED;
@ -289,7 +292,7 @@ void MinimizeWindow(void)
glfwIconifyWindow(platform.handle);
}
// Set window state: not minimized/maximized
// Restore window from being minimized/maximized
void RestoreWindow(void)
{
if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE)
@ -304,6 +307,8 @@ void RestoreWindow(void)
// Set window configuration state using flags
void SetWindowState(unsigned int flags)
{
if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
// Check previous state and requested state to apply required changes
// NOTE: In most cases the functions already change the flags internally
@ -322,7 +327,7 @@ void SetWindowState(unsigned int flags)
}
// State change: FLAG_FULLSCREEN_MODE
if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) != (flags & FLAG_FULLSCREEN_MODE))
if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) != (flags & FLAG_FULLSCREEN_MODE) && ((flags & FLAG_FULLSCREEN_MODE) > 0))
{
ToggleFullscreen(); // NOTE: Window state flag updated inside function
}
@ -571,7 +576,7 @@ void SetWindowIcons(Image *images, int count)
else
{
int valid = 0;
GLFWimage *icons = RL_CALLOC(count, sizeof(GLFWimage));
GLFWimage *icons = (GLFWimage *)RL_CALLOC(count, sizeof(GLFWimage));
for (int i = 0; i < count; i++)
{
@ -733,7 +738,7 @@ int GetMonitorCount(void)
return monitorCount;
}
// Get number of monitors
// Get current monitor where window is placed
int GetCurrentMonitor(void)
{
int index = 0;
@ -967,32 +972,29 @@ const char *GetClipboardText(void)
return glfwGetClipboardString(platform.handle);
}
#if defined(SUPPORT_CLIPBOARD_IMAGE)
// Get clipboard image
Image GetClipboardImage(void)
{
Image image = {0};
Image image = { 0 };
#if defined(SUPPORT_CLIPBOARD_IMAGE)
#if defined(_WIN32)
unsigned long long int dataSize = 0;
void* fileData = NULL;
void *fileData = NULL;
int width = 0;
int height = 0;
#ifdef _WIN32
int width, height;
fileData = (void*)Win32GetClipboardImageData(&width, &height, &dataSize);
#else
TRACELOG(LOG_WARNING, "Clipboard image: PLATFORM_DESKTOP_GLFW doesn't implement `GetClipboardImage` for this OS");
#endif
if (fileData == NULL)
{
TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data.");
}
else
{
image = LoadImageFromMemory(".bmp", fileData, (int)dataSize);
}
if (fileData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data.");
else image = LoadImageFromMemory(".bmp", fileData, (int)dataSize);
#else
TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform");
#endif
#endif // SUPPORT_CLIPBOARD_IMAGE
return image;
}
#endif // SUPPORT_CLIPBOARD_IMAGE
// Show mouse cursor
void ShowCursor(void)
@ -1024,6 +1026,9 @@ void EnableCursor(void)
// Disables cursor (lock cursor)
void DisableCursor(void)
{
// Reset mouse position within the window area before disabling cursor
SetMousePosition(CORE.Window.screen.width, CORE.Window.screen.height);
glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// Set cursor position in the middle
@ -1091,7 +1096,7 @@ int SetGamepadMappings(const char *mappings)
// Set gamepad vibration
void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration)
{
TRACELOG(LOG_WARNING, "GamepadSetVibration() not available on target platform");
TRACELOG(LOG_WARNING, "SetGamepadVibration() not available on target platform");
}
// Set mouse position XY
@ -1233,7 +1238,7 @@ void PollInputEvents(void)
}
}
// Get current axis state
// Get current state of axes
const float *axes = state.axes;
for (int k = 0; (axes != NULL) && (k < GLFW_GAMEPAD_AXIS_LAST + 1); k++)
@ -1241,9 +1246,19 @@ void PollInputEvents(void)
CORE.Input.Gamepad.axisState[i][k] = axes[k];
}
// Register buttons for 2nd triggers (because GLFW doesn't count these as buttons but rather axis)
CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_LEFT_TRIGGER_2] = (char)(CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] > 0.1f);
CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_RIGHT_TRIGGER_2] = (char)(CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] > 0.1f);
// Register buttons for 2nd triggers (because GLFW doesn't count these as buttons but rather as axes)
if (CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] > 0.1f)
{
CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_LEFT_TRIGGER_2] = 1;
CORE.Input.Gamepad.lastButtonPressed = GAMEPAD_BUTTON_LEFT_TRIGGER_2;
}
else CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_LEFT_TRIGGER_2] = 0;
if (CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] > 0.1f)
{
CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_RIGHT_TRIGGER_2] = 1;
CORE.Input.Gamepad.lastButtonPressed = GAMEPAD_BUTTON_RIGHT_TRIGGER_2;
}
else CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_RIGHT_TRIGGER_2] = 0;
CORE.Input.Gamepad.axisCount[i] = GLFW_GAMEPAD_AXIS_LAST + 1;
}
@ -1251,12 +1266,13 @@ void PollInputEvents(void)
CORE.Window.resizedLastFrame = false;
if (CORE.Window.eventWaiting) glfwWaitEvents(); // Wait for in input events before continue (drawing is paused)
if ((CORE.Window.eventWaiting) || (IsWindowState(FLAG_WINDOW_MINIMIZED) && !IsWindowState(FLAG_WINDOW_ALWAYS_RUN)))
{
glfwWaitEvents(); // Wait for in input events before continue (drawing is paused)
CORE.Time.previous = GetTime();
}
else glfwPollEvents(); // Poll input events: keyboard/mouse/window events (callbacks) -> Update keys state
// While window minimized, stop loop execution
while (IsWindowState(FLAG_WINDOW_MINIMIZED) && !IsWindowState(FLAG_WINDOW_ALWAYS_RUN)) glfwWaitEvents();
CORE.Window.shouldClose = glfwWindowShouldClose(platform.handle);
// Reset close status for next frame
@ -1280,21 +1296,39 @@ static void SetDimensionsFromMonitor(GLFWmonitor *monitor)
if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height;
}
// Function wrappers around RL_*alloc macros, used by glfwInitAllocator() inside of InitPlatform()
// We need to provide these because GLFWallocator expects function pointers with specific signatures.
// Similar wrappers exist in utils.c but we cannot reuse them here due to declaration mismatch.
// https://www.glfw.org/docs/latest/intro_guide.html#init_allocator
static void *AllocateWrapper(size_t size, void *user)
{
(void)user;
return RL_MALLOC(size);
}
static void *ReallocateWrapper(void *block, size_t size, void *user)
{
(void)user;
return RL_REALLOC(block, size);
}
static void DeallocateWrapper(void *block, void *user)
{
(void)user;
RL_FREE(block);
}
// Initialize platform: graphics, inputs and more
int InitPlatform(void)
{
glfwSetErrorCallback(ErrorCallback);
/*
// TODO: Setup GLFW custom allocators to match raylib ones
const GLFWallocator allocator = {
.allocate = MemAlloc,
.deallocate = MemFree,
.reallocate = MemRealloc,
.user = NULL
.allocate = AllocateWrapper,
.deallocate = DeallocateWrapper,
.reallocate = ReallocateWrapper,
.user = NULL, // RL_*ALLOC macros are not capable of handling user-provided data
};
glfwInitAllocator(&allocator);
*/
#if defined(__APPLE__)
glfwInitHint(GLFW_COCOA_CHDIR_RESOURCES, GLFW_FALSE);
@ -1348,6 +1382,12 @@ int InitPlatform(void)
if ((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); // Transparent framebuffer
else glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_FALSE); // Opaque framebuffer
// HACK: Most of this was written before GLFW_SCALE_FRAMEBUFFER existed and
// was enabled by default. Disabling it gets back the old behavior. A
// complete fix will require removing a lot of CORE.Window.render
// manipulation code.
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
{
// Resize window content area based on the monitor content scale.
@ -1355,7 +1395,7 @@ int InitPlatform(void)
// On platforms like macOS the resolution of the framebuffer is changed independently of the window size.
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // Scale content area based on the monitor content scale where window is placed on
#if defined(__APPLE__)
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE);
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
#endif
}
else glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE);
@ -1490,6 +1530,12 @@ int InitPlatform(void)
SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
platform.handle = glfwCreateWindow(CORE.Window.display.width, CORE.Window.display.height, (CORE.Window.title != 0)? CORE.Window.title : " ", monitor, NULL);
if (!platform.handle)
{
glfwTerminate();
TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window");
return -1;
}
// NOTE: Full-screen change, not working properly...
//glfwSetWindowMonitor(platform.handle, glfwGetPrimaryMonitor(), 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
@ -1504,6 +1550,12 @@ int InitPlatform(void)
int creationHeight = CORE.Window.screen.height != 0 ? CORE.Window.screen.height : 1;
platform.handle = glfwCreateWindow(creationWidth, creationHeight, (CORE.Window.title != 0)? CORE.Window.title : " ", NULL, NULL);
if (!platform.handle)
{
glfwTerminate();
TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window");
return -1;
}
// After the window was created, determine the monitor that the window manager assigned.
// Derive display sizes, and, if possible, window size in case it was zero at beginning.
@ -1527,18 +1579,8 @@ int InitPlatform(void)
return -1;
}
if (platform.handle)
{
CORE.Window.render.width = CORE.Window.screen.width;
CORE.Window.render.height = CORE.Window.screen.height;
}
}
if (!platform.handle)
{
glfwTerminate();
TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window");
return -1;
CORE.Window.render.width = CORE.Window.screen.width;
CORE.Window.render.height = CORE.Window.screen.height;
}
glfwMakeContextCurrent(platform.handle);
@ -1567,7 +1609,7 @@ int InitPlatform(void)
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
{
// NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling.
// Framebuffer scaling should be activated with: glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE);
// Framebuffer scaling should be activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
#if !defined(__APPLE__)
glfwGetFramebufferSize(platform.handle, &fbWidth, &fbHeight);
@ -1655,7 +1697,9 @@ int InitPlatform(void)
// Retrieve gamepad names
for (int i = 0; i < MAX_GAMEPADS; i++)
{
if (glfwJoystickPresent(i)) strcpy(CORE.Input.Gamepad.name[i], glfwGetJoystickName(i));
// WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
// we can get a not-NULL terminated string, so, we only copy up to (MAX_GAMEPAD_NAME_LENGTH - 1)
if (glfwJoystickPresent(i)) strncpy(CORE.Input.Gamepad.name[i], glfwGetJoystickName(i), MAX_GAMEPAD_NAME_LENGTH - 1);
}
//----------------------------------------------------------------------------
@ -1708,9 +1752,13 @@ static void ErrorCallback(int error, const char *description)
}
// GLFW3 WindowSize Callback, runs when window is resizedLastFrame
// NOTE: Window resizing not allowed by default
// NOTE: Window resizing not enabled by default, use SetConfigFlags()
static void WindowSizeCallback(GLFWwindow *window, int width, int height)
{
// WARNING: On window minimization, callback is called,
// but we don't want to change internal screen values, it breaks things
if ((width == 0) || (height == 0)) return;
// Reset viewport and projection matrix for new size
SetupViewport(width, height);
@ -1720,12 +1768,22 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height)
if (IsWindowFullscreen()) return;
// Set current screen size
// if we are doing automatic DPI scaling, then the "screen" size is divided by the window scale
if (IsWindowState(FLAG_WINDOW_HIGHDPI))
{
width = (int)(width/GetWindowScaleDPI().x);
height = (int)(height/GetWindowScaleDPI().y);
}
// Set render size
CORE.Window.render.width = width;
CORE.Window.render.height = height;
// Set current screen size
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
// NOTE: Postprocessing texture is not scaled to new size
// WARNING: If using a render texture, it is not scaled to new size
}
static void WindowPosCallback(GLFWwindow* window, int x, int y)
{
@ -1918,11 +1976,14 @@ static void JoystickCallback(int jid, int event)
{
if (event == GLFW_CONNECTED)
{
strcpy(CORE.Input.Gamepad.name[jid], glfwGetJoystickName(jid));
// WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
// we can get a not-NULL terminated string, so, we clean destination and only copy up to -1
memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH);
strncpy(CORE.Input.Gamepad.name[jid], glfwGetJoystickName(jid), MAX_GAMEPAD_NAME_LENGTH - 1);
}
else if (event == GLFW_DISCONNECTED)
{
memset(CORE.Input.Gamepad.name[jid], 0, 64);
memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH);
}
}

File diff suppressed because it is too large Load diff

View file

@ -23,13 +23,13 @@
* Custom flag for rcore on target platform -not used-
*
* DEPENDENCIES:
* - SDL 2 or SLD 3 (main library): Windowing and inputs management
* - SDL 2 or SDL 3 (main library): Windowing and inputs management
* - gestures: Gestures system for touch-ready devices (or simulated from mouse inputs)
*
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) and contributors
* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@ -68,13 +68,12 @@
#define MAX_CLIPBOARD_BUFFER_LENGTH 1024 // Size of the clipboard buffer used on GetClipboardText()
#endif
#if ((defined(SDL_MAJOR_VERSION) && SDL_MAJOR_VERSION == 3) && (defined(SDL_MINOR_VERSION) && SDL_MINOR_VERSION >= 1))
#if ((defined(SDL_MAJOR_VERSION) && (SDL_MAJOR_VERSION == 3)) && (defined(SDL_MINOR_VERSION) && (SDL_MINOR_VERSION >= 1)))
#ifndef PLATFORM_DESKTOP_SDL3
#define PLATFORM_DESKTOP_SDL3
#endif
#endif
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
@ -83,6 +82,7 @@ typedef struct {
SDL_GLContext glContext;
SDL_GameController *gamepad[MAX_GAMEPADS];
SDL_JoystickID gamepadId[MAX_GAMEPADS]; // Joystick instance ids
SDL_Cursor *cursor;
bool cursorRelative;
} PlatformData;
@ -240,7 +240,7 @@ static const int CursorsLUT[] = {
// SDL3 Migration Layer made to avoid `ifdefs` inside functions when we can.
#ifdef PLATFORM_DESKTOP_SDL3
#if defined(PLATFORM_DESKTOP_SDL3)
// SDL3 Migration:
// SDL_WINDOW_FULLSCREEN_DESKTOP has been removed,
@ -249,7 +249,6 @@ static const int CursorsLUT[] = {
// or the borderless fullscreen desktop mode will be used
#define SDL_WINDOW_FULLSCREEN_DESKTOP SDL_WINDOW_FULLSCREEN
#define SDL_IGNORE false
#define SDL_DISABLE false
#define SDL_ENABLE true
@ -260,27 +259,29 @@ static const int CursorsLUT[] = {
// SDL3 Migration: The SDL_WINDOW_SHOWN flag has been removed. Windows are shown by default and can be created hidden by using the SDL_WINDOW_HIDDEN flag.
#define SDL_WINDOW_SHOWN 0x0 // It's a flag, so no problem in setting it to zero if we use in a bitor (|)
//
// SDL3 Migration: Renamed
// IMPORTANT:
// Might need to call SDL_CleanupEvent somewhere see :https://github.com/libsdl-org/SDL/issues/3540#issuecomment-1793449852
//
// IMPORTANT: Might need to call SDL_CleanupEvent somewhere see :https://github.com/libsdl-org/SDL/issues/3540#issuecomment-1793449852
#define SDL_DROPFILE SDL_EVENT_DROP_FILE
const char* SDL_GameControllerNameForIndex(int joystickIndex)
// SDL2 implementation for SDL3 function
const char *SDL_GameControllerNameForIndex(int joystickIndex)
{
// NOTE: SDL3 uses the IDs itself (SDL_JoystickID) instead of SDL2 joystick_index
const char* name = NULL;
const char *name = NULL;
int numJoysticks = 0;
SDL_JoystickID *joysticks = SDL_GetJoysticks(&numJoysticks);
if (joysticks) {
if (joystickIndex < numJoysticks) {
if (joysticks)
{
if (joystickIndex < numJoysticks)
{
SDL_JoystickID instance_id = joysticks[joystickIndex];
name = SDL_GetGamepadNameForID(instance_id);
}
SDL_free(joysticks);
}
return name;
}
@ -288,45 +289,40 @@ int SDL_GetNumVideoDisplays(void)
{
int monitorCount = 0;
SDL_DisplayID *displays = SDL_GetDisplays(&monitorCount);
// Safe because If `mem` is NULL, SDL_free does nothing.
// Safe because If `mem` is NULL, SDL_free does nothing
SDL_free(displays);
return monitorCount;
}
// SLD3 Migration:
// To emulate SDL2 this function should return `SDL_DISABLE` or `SDL_ENABLE`
// representing the *processing state* of the event before this function makes any changes to it.
Uint8 SDL_EventState(Uint32 type, int state) {
// SLD3 Migration: To emulate SDL2 this function should return `SDL_DISABLE` or `SDL_ENABLE`
// representing the *processing state* of the event before this function makes any changes to it
Uint8 SDL_EventState(Uint32 type, int state)
{
Uint8 stateBefore = SDL_EventEnabled(type);
switch (state)
{
case SDL_DISABLE: SDL_SetEventEnabled(type, false); break;
case SDL_ENABLE: SDL_SetEventEnabled(type, true); break;
default: TRACELOG(LOG_WARNING, "Event sate: unknow type");
}
return stateBefore;
}
void SDL_GetCurrentDisplayMode_Adapter(SDL_DisplayID displayID, SDL_DisplayMode* mode)
{
const SDL_DisplayMode* currMode = SDL_GetCurrentDisplayMode(displayID);
if (currMode == NULL)
{
TRACELOG(LOG_WARNING, "No current display mode");
}
else
{
*mode = *currMode;
}
if (currMode == NULL) TRACELOG(LOG_WARNING, "No current display mode");
else *mode = *currMode;
}
// SDL3 Migration: Renamed
#define SDL_GetCurrentDisplayMode SDL_GetCurrentDisplayMode_Adapter
SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
{
return SDL_CreateSurface(width, height, SDL_GetPixelFormatForMasks(depth, Rmask, Gmask, Bmask, Amask));
@ -337,11 +333,14 @@ SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth
// not reliable across platforms, approximately replaced by multiplying
// SDL_GetWindowDisplayScale() times 160 on iPhone and Android, and 96 on other platforms.
// returns 0 on success or a negative error code on failure
int SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi) {
float dpi = SDL_GetWindowDisplayScale(platform.window) * 96.0;
int SDL_GetDisplayDPI(int displayIndex, float *ddpi, float *hdpi, float *vdpi)
{
float dpi = SDL_GetWindowDisplayScale(platform.window)*96.0;
if (ddpi != NULL) *ddpi = dpi;
if (hdpi != NULL) *hdpi = dpi;
if (vdpi != NULL) *vdpi = dpi;
return 0;
}
@ -368,17 +367,13 @@ int SDL_NumJoysticks(void)
return numJoysticks;
}
// SDL_SetRelativeMouseMode
// returns 0 on success or a negative error code on failure
// If relative mode is not supported, this returns -1.
int SDL_SetRelativeMouseMode_Adapter(SDL_bool enabled)
{
//
// SDL_SetWindowRelativeMouseMode(SDL_Window *window, bool enabled)
// \returns true on success or false on failure; call SDL_GetError() for more
//
if (SDL_SetWindowRelativeMouseMode(platform.window, enabled))
{
return 0; // success
@ -398,7 +393,6 @@ bool SDL_GetRelativeMouseMode_Adapter(void)
#define SDL_GetRelativeMouseMode SDL_GetRelativeMouseMode_Adapter
int SDL_GetNumTouchFingers(SDL_TouchID touchID)
{
// SDL_Finger **SDL_GetTouchFingers(SDL_TouchID touchID, int *count)
@ -412,16 +406,16 @@ int SDL_GetNumTouchFingers(SDL_TouchID touchID)
// Since SDL2 doesn't have this function we leave a stub
// SDL_GetClipboardData function is available since SDL 3.1.3. (e.g. SDL3)
void* SDL_GetClipboardData(const char *mime_type, size_t *size) {
void *SDL_GetClipboardData(const char *mime_type, size_t *size)
{
TRACELOG(LOG_WARNING, "Getting clipboard data that is not text is only available in SDL3");
// We could possibly implement it ourselves in this case for some easier platforms
return NULL;
}
#endif // PLATFORM_DESKTOP_SDL3
//----------------------------------------------------------------------------------
// Module Internal Functions Declaration
//----------------------------------------------------------------------------------
@ -452,7 +446,7 @@ void ToggleFullscreen(void)
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
const int monitorCount = SDL_GetNumVideoDisplays();
#ifdef PLATFORM_DESKTOP_SDL3 // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
#if defined(PLATFORM_DESKTOP_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
if ((monitor > 0) && (monitor <= monitorCount))
#else
if ((monitor >= 0) && (monitor < monitorCount))
@ -479,7 +473,8 @@ void ToggleBorderlessWindowed(void)
{
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
const int monitorCount = SDL_GetNumVideoDisplays();
#ifdef PLATFORM_DESKTOP_SDL3 // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
#if defined(PLATFORM_DESKTOP_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
if ((monitor > 0) && (monitor <= monitorCount))
#else
if ((monitor >= 0) && (monitor < monitorCount))
@ -503,25 +498,28 @@ void ToggleBorderlessWindowed(void)
void MaximizeWindow(void)
{
SDL_MaximizeWindow(platform.window);
CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) == 0) CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
}
// Set window state: minimized
void MinimizeWindow(void)
{
SDL_MinimizeWindow(platform.window);
CORE.Window.flags |= FLAG_WINDOW_MINIMIZED;
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) == 0) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED;
}
// Set window state: not minimized/maximized
// Restore window from being minimized/maximized
void RestoreWindow(void)
{
SDL_ShowWindow(platform.window);
SDL_RestoreWindow(platform.window);
// CORE.Window.flags will be removed on PollInputEvents()
}
// Set window configuration state using flags
void SetWindowState(unsigned int flags)
{
if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
CORE.Window.flags |= flags;
if (flags & FLAG_VSYNC_HINT)
@ -532,7 +530,8 @@ void SetWindowState(unsigned int flags)
{
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
const int monitorCount = SDL_GetNumVideoDisplays();
#ifdef PLATFORM_DESKTOP_SDL3 // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
#if defined(PLATFORM_DESKTOP_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
if ((monitor > 0) && (monitor <= monitorCount))
#else
if ((monitor >= 0) && (monitor < monitorCount))
@ -575,7 +574,7 @@ void SetWindowState(unsigned int flags)
}
if (flags & FLAG_WINDOW_ALWAYS_RUN)
{
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_ALWAYS_RUN is not supported on PLATFORM_DESKTOP_SDL");
CORE.Window.flags |= FLAG_WINDOW_ALWAYS_RUN;
}
if (flags & FLAG_WINDOW_TRANSPARENT)
{
@ -595,7 +594,8 @@ void SetWindowState(unsigned int flags)
{
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
const int monitorCount = SDL_GetNumVideoDisplays();
#ifdef PLATFORM_DESKTOP_SDL3 // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
#if defined(PLATFORM_DESKTOP_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
if ((monitor > 0) && (monitor <= monitorCount))
#else
if ((monitor >= 0) && (monitor < monitorCount))
@ -661,7 +661,7 @@ void ClearWindowState(unsigned int flags)
}
if (flags & FLAG_WINDOW_ALWAYS_RUN)
{
TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_ALWAYS_RUN is not supported on PLATFORM_DESKTOP_SDL");
CORE.Window.flags &= ~FLAG_WINDOW_ALWAYS_RUN;
}
if (flags & FLAG_WINDOW_TRANSPARENT)
{
@ -704,70 +704,84 @@ void SetWindowIcon(Image image)
switch (image.format)
{
case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
{
rmask = 0xFF, gmask = 0;
bmask = 0, amask = 0;
depth = 8, pitch = image.width;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
{
rmask = 0xFF, gmask = 0xFF00;
bmask = 0, amask = 0;
depth = 16, pitch = image.width*2;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
{
rmask = 0xF800, gmask = 0x07E0;
bmask = 0x001F, amask = 0;
depth = 16, pitch = image.width*2;
break;
case PIXELFORMAT_UNCOMPRESSED_R8G8B8: // Uses BGR for 24-bit
rmask = 0x0000FF, gmask = 0x00FF00;
bmask = 0xFF0000, amask = 0;
} break;
case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
{
// WARNING: SDL2 could be using BGR but SDL3 RGB
rmask = 0xFF0000, gmask = 0x00FF00;
bmask = 0x0000FF, amask = 0;
depth = 24, pitch = image.width*3;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
{
rmask = 0xF800, gmask = 0x07C0;
bmask = 0x003E, amask = 0x0001;
depth = 16, pitch = image.width*2;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
{
rmask = 0xF000, gmask = 0x0F00;
bmask = 0x00F0, amask = 0x000F;
depth = 16, pitch = image.width*2;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
{
rmask = 0xFF000000, gmask = 0x00FF0000;
bmask = 0x0000FF00, amask = 0x000000FF;
depth = 32, pitch = image.width*4;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R32:
{
rmask = 0xFFFFFFFF, gmask = 0;
bmask = 0, amask = 0;
depth = 32, pitch = image.width*4;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
{
rmask = 0xFFFFFFFF, gmask = 0xFFFFFFFF;
bmask = 0xFFFFFFFF, amask = 0;
depth = 96, pitch = image.width*12;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
{
rmask = 0xFFFFFFFF, gmask = 0xFFFFFFFF;
bmask = 0xFFFFFFFF, amask = 0xFFFFFFFF;
depth = 128, pitch = image.width*16;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R16:
{
rmask = 0xFFFF, gmask = 0;
bmask = 0, amask = 0;
depth = 16, pitch = image.width*2;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
{
rmask = 0xFFFF, gmask = 0xFFFF;
bmask = 0xFFFF, amask = 0;
depth = 48, pitch = image.width*6;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
{
rmask = 0xFFFF, gmask = 0xFFFF;
bmask = 0xFFFF, amask = 0xFFFF;
depth = 64, pitch = image.width*8;
break;
} break;
default: return; // Compressed formats are not supported
}
@ -818,7 +832,8 @@ void SetWindowMonitor(int monitor)
const int screenWidth = CORE.Window.screen.width;
const int screenHeight = CORE.Window.screen.height;
SDL_Rect usableBounds;
#ifdef PLATFORM_DESKTOP_SDL3 // Different style for success checking
#if defined(PLATFORM_DESKTOP_SDL3) // Different style for success checking
if (SDL_GetDisplayUsableBounds(monitor, &usableBounds))
#else
if (SDL_GetDisplayUsableBounds(monitor, &usableBounds) == 0)
@ -915,7 +930,7 @@ int GetMonitorCount(void)
return monitorCount;
}
// Get number of monitors
// Get current monitor where window is placed
int GetCurrentMonitor(void)
{
int currentMonitor = 0;
@ -933,7 +948,8 @@ Vector2 GetMonitorPosition(int monitor)
if ((monitor >= 0) && (monitor < monitorCount))
{
SDL_Rect displayBounds;
#ifdef PLATFORM_DESKTOP_SDL3
#if defined(PLATFORM_DESKTOP_SDL3)
if (SDL_GetDisplayUsableBounds(monitor, &displayBounds))
#else
if (SDL_GetDisplayUsableBounds(monitor, &displayBounds) == 0)
@ -1104,53 +1120,55 @@ const char *GetClipboardText(void)
return buffer;
}
#if defined(SUPPORT_CLIPBOARD_IMAGE)
// Get clipboard image
Image GetClipboardImage(void)
{
Image image = { 0 };
#if defined(SUPPORT_CLIPBOARD_IMAGE)
// Let's hope compiler put these arrays in static memory
const char *image_formats[] = {
const char *imageFormats[] = {
"image/bmp",
"image/png",
"image/jpg",
"image/tiff",
};
const char *image_extensions[] = {
const char *imageExtensions[] = {
".bmp",
".png",
".jpg",
".tiff",
};
Image image = {0};
size_t dataSize = 0;
void *fileData = NULL;
for (int i = 0; i < SDL_arraysize(image_formats); ++i)
for (int i = 0; i < SDL_arraysize(imageFormats); ++i)
{
// NOTE: This pointer should be free with SDL_free() at some point.
fileData = SDL_GetClipboardData(image_formats[i], &dataSize);
if (fileData) {
image = LoadImageFromMemory(image_extensions[i], fileData, dataSize);
// NOTE: This pointer should be free with SDL_free() at some point
fileData = SDL_GetClipboardData(imageFormats[i], &dataSize);
if (fileData)
{
image = LoadImageFromMemory(imageExtensions[i], fileData, dataSize);
if (IsImageValid(image))
{
TRACELOG(LOG_INFO, "Clipboard image: Got image from clipboard as a `%s` successfully", image_extensions[i]);
TRACELOG(LOG_INFO, "Clipboard image: Got image from clipboard as a `%s` successfully", imageExtensions[i]);
return image;
}
}
}
TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data. %s", SDL_GetError());
return image;
}
if (!IsImageValid(image)) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data. Error: %s", SDL_GetError());
#endif
return image;
}
// Show mouse cursor
void ShowCursor(void)
{
#ifdef PLATFORM_DESKTOP_SDL3
#if defined(PLATFORM_DESKTOP_SDL3)
SDL_ShowCursor();
#else
SDL_ShowCursor(SDL_ENABLE);
@ -1161,7 +1179,7 @@ void ShowCursor(void)
// Hides mouse cursor
void HideCursor(void)
{
#ifdef PLATFORM_DESKTOP_SDL3
#if defined(PLATFORM_DESKTOP_SDL3)
SDL_HideCursor();
#else
SDL_ShowCursor(SDL_DISABLE);
@ -1174,7 +1192,7 @@ void EnableCursor(void)
{
SDL_SetRelativeMouseMode(SDL_FALSE);
#ifdef PLATFORM_DESKTOP_SDL3
#if defined(PLATFORM_DESKTOP_SDL3)
// SDL_ShowCursor() has been split into three functions: SDL_ShowCursor(), SDL_HideCursor(), and SDL_CursorVisible()
SDL_ShowCursor();
#else
@ -1275,7 +1293,7 @@ const char *GetKeyName(int key)
static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event)
{
#ifdef PLATFORM_DESKTOP_SDL3 // SDL3
#if defined(PLATFORM_DESKTOP_SDL3) // SDL3
int count = 0;
SDL_Finger **fingers = SDL_GetTouchFingers(event.touchID, &count);
CORE.Input.Touch.pointCount = count;
@ -1288,7 +1306,9 @@ static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event)
CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height;
CORE.Input.Touch.currentTouchState[i] = 1;
}
SDL_free(fingers);
#else // SDL2
CORE.Input.Touch.pointCount = SDL_GetNumTouchFingers(event.touchId);
@ -1345,7 +1365,7 @@ void PollInputEvents(void)
for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i];
// Map touch position to mouse position for convenience
CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
if (CORE.Input.Touch.pointCount == 0) CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
int touchAction = -1; // 0-TOUCH_ACTION_UP, 1-TOUCH_ACTION_DOWN, 2-TOUCH_ACTION_MOVE
bool realTouch = false; // Flag to differentiate real touch gestures from mouse ones
@ -1375,6 +1395,12 @@ void PollInputEvents(void)
CORE.Window.resizedLastFrame = false;
if ((CORE.Window.eventWaiting) || (((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) && ((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) == 0)))
{
SDL_WaitEvent(NULL);
CORE.Time.previous = GetTime();
}
SDL_Event event = { 0 };
while (SDL_PollEvent(&event) != 0)
{
@ -1393,7 +1419,8 @@ void PollInputEvents(void)
CORE.Window.dropFilepaths = (char **)RL_CALLOC(1024, sizeof(char *));
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
#ifdef PLATFORM_DESKTOP_SDL3
#if defined(PLATFORM_DESKTOP_SDL3)
// const char *data; /**< The text for SDL_EVENT_DROP_TEXT and the file name for SDL_EVENT_DROP_FILE, NULL for other events */
// Event memory is now managed by SDL, so you should not free the data in SDL_EVENT_DROP_FILE, and if you want to hold onto the text in SDL_EVENT_TEXT_EDITING and SDL_EVENT_TEXT_INPUT events, you should make a copy of it. SDL_TEXTINPUTEVENT_TEXT_SIZE is no longer necessary and has been removed.
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data);
@ -1407,7 +1434,8 @@ void PollInputEvents(void)
else if (CORE.Window.dropFileCount < 1024)
{
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
#ifdef PLATFORM_DESKTOP_SDL3
#if defined(PLATFORM_DESKTOP_SDL3)
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data);
#else
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file);
@ -1422,7 +1450,7 @@ void PollInputEvents(void)
// Window events are also polled (Minimized, maximized, close...)
#ifndef PLATFORM_DESKTOP_SDL3
#ifndef PLATFORM_DESKTOP_SDL3
// SDL3 states:
// The SDL_WINDOWEVENT_* events have been moved to top level events,
// and SDL_WINDOWEVENT has been removed.
@ -1432,19 +1460,45 @@ void PollInputEvents(void)
{
switch (event.window.event)
{
#endif
#endif
case SDL_WINDOWEVENT_RESIZED:
case SDL_WINDOWEVENT_SIZE_CHANGED:
{
const int width = event.window.data1;
const int height = event.window.data2;
SetupViewport(width, height);
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
// if we are doing automatic DPI scaling, then the "screen" size is divided by the window scale
if (IsWindowState(FLAG_WINDOW_HIGHDPI))
{
CORE.Window.screen.width = (int)(width / GetWindowScaleDPI().x);
CORE.Window.screen.height = (int)(height / GetWindowScaleDPI().y);
}
else
{
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
}
CORE.Window.currentFbo.width = width;
CORE.Window.currentFbo.height = height;
CORE.Window.resizedLastFrame = true;
#ifndef PLATFORM_DESKTOP_SDL3
// Manually detect if the window was maximized (due to SDL2 restore being unreliable on some platforms) to remove the FLAG_WINDOW_MAXIMIZED accordingly
if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0)
{
int borderTop = 0;
int borderLeft = 0;
int borderBottom = 0;
int borderRight = 0;
SDL_GetWindowBordersSize(platform.window, &borderTop, &borderLeft, &borderBottom, &borderRight);
SDL_Rect usableBounds;
SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(platform.window), &usableBounds);
if ((width + borderLeft + borderRight != usableBounds.w) && (height + borderTop + borderBottom != usableBounds.h)) CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED;
}
#endif
} break;
case SDL_WINDOWEVENT_ENTER:
{
CORE.Input.Mouse.cursorOnScreen = true;
@ -1453,16 +1507,49 @@ void PollInputEvents(void)
{
CORE.Input.Mouse.cursorOnScreen = false;
} break;
case SDL_WINDOWEVENT_HIDDEN:
case SDL_WINDOWEVENT_MINIMIZED:
case SDL_WINDOWEVENT_FOCUS_LOST:
case SDL_WINDOWEVENT_SHOWN:
case SDL_WINDOWEVENT_FOCUS_GAINED:
{
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) == 0) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED;
} break;
case SDL_WINDOWEVENT_MAXIMIZED:
{
if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) == 0) CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
} break;
case SDL_WINDOWEVENT_RESTORED:
#ifdef PLATFORM_DESKTOP_SDL3
break;
#else
{
if ((SDL_GetWindowFlags(platform.window) & SDL_WINDOW_MINIMIZED) == 0)
{
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED;
}
#ifdef PLATFORM_DESKTOP_SDL3
if ((SDL_GetWindowFlags(platform.window) & SDL_WINDOW_MAXIMIZED) == 0)
{
if ((CORE.Window.flags & SDL_WINDOW_MAXIMIZED) > 0) CORE.Window.flags &= ~SDL_WINDOW_MAXIMIZED;
}
#endif
} break;
case SDL_WINDOWEVENT_HIDDEN:
{
if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) == 0) CORE.Window.flags |= FLAG_WINDOW_HIDDEN;
} break;
case SDL_WINDOWEVENT_SHOWN:
{
if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN;
} break;
case SDL_WINDOWEVENT_FOCUS_GAINED:
{
if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED;
} break;
case SDL_WINDOWEVENT_FOCUS_LOST:
{
if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) == 0) CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED;
} break;
#ifndef PLATFORM_DESKTOP_SDL3
default: break;
}
} break;
@ -1471,7 +1558,7 @@ void PollInputEvents(void)
// Keyboard events
case SDL_KEYDOWN:
{
#ifdef PLATFORM_DESKTOP_SDL3
#if defined(PLATFORM_DESKTOP_SDL3)
// SDL3 Migration: The following structures have been removed: * SDL_Keysym
KeyboardKey key = ConvertScancodeToKey(event.key.scancode);
#else
@ -1502,7 +1589,7 @@ void PollInputEvents(void)
case SDL_KEYUP:
{
#ifdef PLATFORM_DESKTOP_SDL3
#if defined(PLATFORM_DESKTOP_SDL3)
KeyboardKey key = ConvertScancodeToKey(event.key.scancode);
#else
KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode);
@ -1597,11 +1684,12 @@ void PollInputEvents(void)
// Check gamepad events
case SDL_JOYDEVICEADDED:
{
int jid = event.jdevice.which;
int jid = event.jdevice.which; // Joystick device index
if (!CORE.Input.Gamepad.ready[jid] && (jid < MAX_GAMEPADS))
if (CORE.Input.Gamepad.ready[jid] && (jid < MAX_GAMEPADS))
{
platform.gamepad[jid] = SDL_GameControllerOpen(jid);
platform.gamepadId[jid] = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[jid]));
if (platform.gamepad[jid])
{
@ -1609,8 +1697,8 @@ void PollInputEvents(void)
CORE.Input.Gamepad.axisCount[jid] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[jid]));
CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
strncpy(CORE.Input.Gamepad.name[jid], SDL_GameControllerNameForIndex(jid), 63);
CORE.Input.Gamepad.name[jid][63] = '\0';
memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH);
strncpy(CORE.Input.Gamepad.name[jid], SDL_GameControllerNameForIndex(jid), MAX_GAMEPAD_NAME_LENGTH - 1);
}
else
{
@ -1620,14 +1708,18 @@ void PollInputEvents(void)
} break;
case SDL_JOYDEVICEREMOVED:
{
int jid = event.jdevice.which;
int jid = event.jdevice.which; // Joystick instance id
if (jid == SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[jid])))
for (int i = 0; i < MAX_GAMEPADS; i++)
{
SDL_GameControllerClose(platform.gamepad[jid]);
platform.gamepad[jid] = SDL_GameControllerOpen(0);
CORE.Input.Gamepad.ready[jid] = false;
memset(CORE.Input.Gamepad.name[jid], 0, 64);
if (platform.gamepadId[i] == jid)
{
SDL_GameControllerClose(platform.gamepad[i]);
CORE.Input.Gamepad.ready[i] = false;
memset(CORE.Input.Gamepad.name[i], 0, MAX_GAMEPAD_NAME_LENGTH);
platform.gamepadId[i] = -1;
break;
}
}
} break;
case SDL_CONTROLLERBUTTONDOWN:
@ -1660,8 +1752,15 @@ void PollInputEvents(void)
if (button >= 0)
{
CORE.Input.Gamepad.currentButtonState[event.jbutton.which][button] = 1;
CORE.Input.Gamepad.lastButtonPressed = button;
for (int i = 0; i < MAX_GAMEPADS; i++)
{
if (platform.gamepadId[i] == event.jbutton.which)
{
CORE.Input.Gamepad.currentButtonState[i][button] = 1;
CORE.Input.Gamepad.lastButtonPressed = button;
break;
}
}
}
} break;
case SDL_CONTROLLERBUTTONUP:
@ -1694,8 +1793,15 @@ void PollInputEvents(void)
if (button >= 0)
{
CORE.Input.Gamepad.currentButtonState[event.jbutton.which][button] = 0;
if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
for (int i = 0; i < MAX_GAMEPADS; i++)
{
if (platform.gamepadId[i] == event.jbutton.which)
{
CORE.Input.Gamepad.currentButtonState[i][button] = 0;
if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
break;
}
}
}
} break;
case SDL_CONTROLLERAXISMOTION:
@ -1715,18 +1821,25 @@ void PollInputEvents(void)
if (axis >= 0)
{
// SDL axis value range is -32768 to 32767, we normalize it to RayLib's -1.0 to 1.0f range
float value = event.jaxis.value/(float)32767;
CORE.Input.Gamepad.axisState[event.jaxis.which][axis] = value;
// Register button state for triggers in addition to their axes
if ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))
for (int i = 0; i < MAX_GAMEPADS; i++)
{
int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER)? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2;
int pressed = (value > 0.1f);
CORE.Input.Gamepad.currentButtonState[event.jaxis.which][button] = pressed;
if (pressed) CORE.Input.Gamepad.lastButtonPressed = button;
else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
if (platform.gamepadId[i] == event.jaxis.which)
{
// SDL axis value range is -32768 to 32767, we normalize it to raylib's -1.0 to 1.0f range
float value = event.jaxis.value/(float)32767;
CORE.Input.Gamepad.axisState[i][axis] = value;
// Register button state for triggers in addition to their axes
if ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))
{
int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER)? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2;
int pressed = (value > 0.1f);
CORE.Input.Gamepad.currentButtonState[i][button] = pressed;
if (pressed) CORE.Input.Gamepad.lastButtonPressed = button;
else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
}
break;
}
}
}
} break;
@ -1858,7 +1971,7 @@ int InitPlatform(void)
}
// Init window
#ifdef PLATFORM_DESKTOP_SDL3
#if defined(PLATFORM_DESKTOP_SDL3)
platform.window = SDL_CreateWindow(CORE.Window.title, CORE.Window.screen.width, CORE.Window.screen.height, flags);
#else
platform.window = SDL_CreateWindow(CORE.Window.title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, CORE.Window.screen.width, CORE.Window.screen.height, flags);
@ -1906,9 +2019,15 @@ int InitPlatform(void)
// Initialize input events system
//----------------------------------------------------------------------------
// Initialize gamepads
for (int i = 0; i < MAX_GAMEPADS; i++)
{
platform.gamepadId[i] = -1; // Set all gamepad initial instance ids as invalid to not conflict with instance id zero
}
for (int i = 0; (i < SDL_NumJoysticks()) && (i < MAX_GAMEPADS); i++)
{
platform.gamepad[i] = SDL_GameControllerOpen(i);
platform.gamepadId[i] = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[i]));
if (platform.gamepad[i])
{
@ -1916,8 +2035,8 @@ int InitPlatform(void)
CORE.Input.Gamepad.axisCount[i] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[i]));
CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
strncpy(CORE.Input.Gamepad.name[i], SDL_GameControllerNameForIndex(i), 63);
CORE.Input.Gamepad.name[i][63] = '\0';
strncpy(CORE.Input.Gamepad.name[i], SDL_GameControllerNameForIndex(i), MAX_GAMEPAD_NAME_LENGTH - 1);
CORE.Input.Gamepad.name[i][MAX_GAMEPAD_NAME_LENGTH - 1] = '\0';
}
else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
}
@ -1946,11 +2065,10 @@ int InitPlatform(void)
CORE.Storage.basePath = SDL_GetBasePath(); // Alternative: GetWorkingDirectory();
//----------------------------------------------------------------------------
#ifdef PLATFORM_DESKTOP_SDL3
#if defined(PLATFORM_DESKTOP_SDL3)
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL3): Initialized successfully");
#else
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL): Initialized successfully");
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL2): Initialized successfully");
#endif
return 0;
@ -1968,7 +2086,7 @@ void ClosePlatform(void)
// Scancode to keycode mapping
static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode)
{
if (sdlScancode >= 0 && sdlScancode < SCANCODE_MAPPED_NUM)
if ((sdlScancode >= 0) && (sdlScancode < SCANCODE_MAPPED_NUM))
{
return mapScancodeToKey[sdlScancode];
}

View file

@ -29,7 +29,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) and contributors
* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@ -125,7 +125,7 @@ typedef struct {
// Gamepad data
int gamepadStreamFd[MAX_GAMEPADS]; // Gamepad device file descriptor
int gamepadAbsAxisRange[MAX_GAMEPADS][MAX_GAMEPAD_AXIS][2]; // [0] = min, [1] = range value of the axis
int gamepadAbsAxisRange[MAX_GAMEPADS][MAX_GAMEPAD_AXES][2]; // [0] = min, [1] = range value of the axes
int gamepadAbsAxisMap[MAX_GAMEPADS][ABS_CNT]; // Maps the axes gamepads from the evdev api to a sequential one
int gamepadCount; // The number of gamepads registered
} PlatformData;
@ -278,7 +278,7 @@ void MinimizeWindow(void)
TRACELOG(LOG_WARNING, "MinimizeWindow() not available on target platform");
}
// Set window state: not minimized/maximized
// Restore window from being minimized/maximized
void RestoreWindow(void)
{
TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform");
@ -372,7 +372,7 @@ int GetMonitorCount(void)
return 1;
}
// Get number of monitors
// Get current monitor where window is placed
int GetCurrentMonitor(void)
{
TRACELOG(LOG_WARNING, "GetCurrentMonitor() not implemented on target platform");
@ -623,7 +623,7 @@ int SetGamepadMappings(const char *mappings)
// Set gamepad vibration
void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration)
{
TRACELOG(LOG_WARNING, "GamepadSetVibration() not implemented on target platform");
TRACELOG(LOG_WARNING, "SetGamepadVibration() not implemented on target platform");
}
// Set mouse position XY
@ -736,20 +736,24 @@ int InitPlatform(void)
#if defined(DEFAULT_GRAPHIC_DEVICE_DRM)
platform.fd = open(DEFAULT_GRAPHIC_DEVICE_DRM, O_RDWR);
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: Default graphic device DRM opened successfully");
#else
TRACELOG(LOG_INFO, "DISPLAY: No graphic card set, trying platform-gpu-card");
TRACELOG(LOG_WARNING, "DISPLAY: No graphic card set, trying platform-gpu-card");
platform.fd = open("/dev/dri/by-path/platform-gpu-card", O_RDWR); // VideoCore VI (Raspberry Pi 4)
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: platform-gpu-card opened successfully");
if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
{
TRACELOG(LOG_INFO, "DISPLAY: Failed to open platform-gpu-card, trying card1");
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open platform-gpu-card, trying card1");
platform.fd = open("/dev/dri/card1", O_RDWR); // Other Embedded
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card1 opened successfully");
}
if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
{
TRACELOG(LOG_INFO, "DISPLAY: Failed to open graphic card1, trying card0");
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card1, trying card0");
platform.fd = open("/dev/dri/card0", O_RDWR); // VideoCore IV (Raspberry Pi 1-3)
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card0 opened successfully");
}
#endif
@ -899,18 +903,17 @@ int InitPlatform(void)
TRACELOG(LOG_INFO, "DISPLAY: Trying to enable MSAA x4");
}
const EGLint framebufferAttribs[] =
{
EGL_RENDERABLE_TYPE, (rlGetVersion() == RL_OPENGL_ES_30)? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT, // Type of context support
EGL_SURFACE_TYPE, EGL_WINDOW_BIT, // Don't use it on Android!
const EGLint framebufferAttribs[] = {
EGL_RENDERABLE_TYPE, (rlGetVersion() == RL_OPENGL_ES_30)? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT, // Type of context support
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 (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_DEPTH_SIZE, 24, // Depth buffer size (Required to use Depth testing!)
//EGL_STENCIL_SIZE, 8, // Stencil buffer size
EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA
EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA
EGL_SAMPLES, samples, // 4x Antialiasing if activated (Free on MALI GPUs)
EGL_NONE
};
@ -946,7 +949,7 @@ int InitPlatform(void)
TRACELOG(LOG_TRACE, "DISPLAY: EGL configs available: %d", numConfigs);
EGLConfig *configs = RL_CALLOC(numConfigs, sizeof(*configs));
EGLConfig *configs = (EGLConfig *)RL_CALLOC(numConfigs, sizeof(*configs));
if (!configs)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get memory for EGL configs");
@ -1372,7 +1375,7 @@ static void InitEvdevInput(void)
if ((strncmp("event", entity->d_name, strlen("event")) == 0) || // Search for devices named "event*"
(strncmp("mouse", entity->d_name, strlen("mouse")) == 0)) // Search for devices named "mouse*"
{
sprintf(path, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name);
snprintf(path, MAX_FILEPATH_LENGTH, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name);
ConfigureEvdevDevice(path); // Configure the device if appropriate
}
}
@ -1401,7 +1404,7 @@ static void ConfigureEvdevDevice(char *device)
int fd = open(device, O_RDONLY | O_NONBLOCK);
if (fd < 0)
{
TRACELOG(LOG_WARNING, "DRM: Failed to open input device: %s", device);
TRACELOG(LOG_WARNING, "SYSTEM: Failed to open input device: %s", device);
return;
}
@ -1458,7 +1461,7 @@ static void ConfigureEvdevDevice(char *device)
// matter if we support them
else if (hasAbsXY && TEST_BIT(keyBits, BTN_MOUSE)) isMouse = true;
// If any of the common joystick axis is present, we assume it's a gamepad
// If any of the common joystick axes are present, we assume it's a gamepad
else
{
for (int axis = (hasAbsXY? ABS_Z : ABS_X); axis < ABS_PRESSURE; axis++)
@ -1530,7 +1533,7 @@ static void ConfigureEvdevDevice(char *device)
platform.absRange.height = absinfo[ABS_Y].info.maximum - absinfo[ABS_Y].info.minimum;
}
}
else if (isGamepad && !isMouse && !isKeyboard && platform.gamepadCount < MAX_GAMEPADS)
else if (isGamepad && !isMouse && !isKeyboard && (platform.gamepadCount < MAX_GAMEPADS))
{
deviceKindStr = "gamepad";
int index = platform.gamepadCount++;
@ -1544,7 +1547,7 @@ static void ConfigureEvdevDevice(char *device)
if (absAxisCount > 0)
{
// TODO / NOTE
// So gamepad axis (as in the actual linux joydev.c) are just simply enumerated
// So gamepad axes (as in the actual linux joydev.c) are just simply enumerated
// and (at least for some input drivers like xpat) it's convention to use
// ABS_X, ABX_Y for one joystick ABS_RX, ABS_RY for the other and the Z axes for the
// shoulder buttons
@ -1679,7 +1682,7 @@ static void PollGamepadEvents(void)
TRACELOG(LOG_DEBUG, "INPUT: Gamepad %2i: Axis: %2i Value: %i", i, axisRaylib, event.value);
if (axisRaylib < MAX_GAMEPAD_AXIS)
if (axisRaylib < MAX_GAMEPAD_AXES)
{
int min = platform.gamepadAbsAxisRange[i][event.code][0];
int range = platform.gamepadAbsAxisRange[i][event.code][1];
@ -1894,7 +1897,7 @@ static int FindExactConnectorMode(const drmModeConnector *connector, uint width,
TRACELOG(LOG_TRACE, "DISPLAY: DRM Mode %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh, (mode->flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive");
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && (!allowInterlaced)) continue;
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && !allowInterlaced) continue;
if ((mode->hdisplay == width) && (mode->vdisplay == height) && (mode->vrefresh == fps)) return i;
}
@ -1924,7 +1927,7 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
continue;
}
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && (!allowInterlaced))
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && !allowInterlaced)
{
TRACELOG(LOG_TRACE, "DISPLAY: DRM shouldn't choose an interlaced mode");
continue;

View file

@ -53,7 +53,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5)
* Copyright (c) 2013-2025 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.
@ -607,6 +607,7 @@ AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam
audioBuffer->usage = usage;
audioBuffer->frameCursorPos = 0;
audioBuffer->framesProcessed = 0;
audioBuffer->sizeInFrames = sizeInFrames;
// Buffers should be marked as processed by default so that a call to
@ -653,6 +654,9 @@ void PlayAudioBuffer(AudioBuffer *buffer)
buffer->playing = true;
buffer->paused = false;
buffer->frameCursorPos = 0;
buffer->framesProcessed = 0;
buffer->isSubBufferProcessed[0] = true;
buffer->isSubBufferProcessed[1] = true;
ma_mutex_unlock(&AUDIO.System.lock);
}
}
@ -804,10 +808,10 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int
wave.sampleRate = wav.sampleRate;
wave.sampleSize = 16;
wave.channels = wav.channels;
wave.data = (short *)RL_MALLOC(wave.frameCount*wave.channels*sizeof(short));
wave.data = (short *)RL_MALLOC((size_t)wave.frameCount*wave.channels*sizeof(short));
// NOTE: We are forcing conversion to 16bit sample size on reading
drwav_read_pcm_frames_s16(&wav, wav.totalPCMFrameCount, wave.data);
drwav_read_pcm_frames_s16(&wav, wave.frameCount, wave.data);
}
else TRACELOG(LOG_WARNING, "WAVE: Failed to load WAV data");
@ -1128,7 +1132,7 @@ bool ExportWaveAsCode(Wave wave, const char *fileName)
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) 2018-2024 Ramon Santamaria (@raysan5) //\n");
byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2025 Ramon Santamaria (@raysan5) //\n");
byteCount += sprintf(txtData + byteCount, "// //\n");
byteCount += sprintf(txtData + byteCount, "//////////////////////////////////////////////////////////////////////////////////\n\n");
@ -1243,6 +1247,7 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels)
frameCount = (ma_uint32)ma_convert_frames(data, frameCount, formatOut, channels, sampleRate, wave->data, frameCountIn, formatIn, wave->channels, wave->sampleRate);
if (frameCount == 0)
{
RL_FREE(wave->data);
TRACELOG(LOG_WARNING, "WAVE: Failed format conversion");
return;
}
@ -1335,7 +1340,7 @@ Music LoadMusicStream(const char *fileName)
#if defined(SUPPORT_FILEFORMAT_WAV)
else if (IsFileExtension(fileName, ".wav"))
{
drwav *ctxWav = RL_CALLOC(1, sizeof(drwav));
drwav *ctxWav = (drwav *)RL_CALLOC(1, sizeof(drwav));
bool success = drwav_init_file(ctxWav, fileName, NULL);
if (success)
@ -1385,7 +1390,7 @@ Music LoadMusicStream(const char *fileName)
#if defined(SUPPORT_FILEFORMAT_MP3)
else if (IsFileExtension(fileName, ".mp3"))
{
drmp3 *ctxMp3 = RL_CALLOC(1, sizeof(drmp3));
drmp3 *ctxMp3 = (drmp3 *)RL_CALLOC(1, sizeof(drmp3));
int result = drmp3_init_file(ctxMp3, fileName, NULL);
if (result > 0)
@ -1476,7 +1481,7 @@ Music LoadMusicStream(const char *fileName)
#if defined(SUPPORT_FILEFORMAT_MOD)
else if (IsFileExtension(fileName, ".mod"))
{
jar_mod_context_t *ctxMod = RL_CALLOC(1, sizeof(jar_mod_context_t));
jar_mod_context_t *ctxMod = (jar_mod_context_t *)RL_CALLOC(1, sizeof(jar_mod_context_t));
jar_mod_init(ctxMod);
int result = jar_mod_load_file(ctxMod, fileName);
@ -1527,7 +1532,7 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data,
#if defined(SUPPORT_FILEFORMAT_WAV)
else if ((strcmp(fileType, ".wav") == 0) || (strcmp(fileType, ".WAV") == 0))
{
drwav *ctxWav = RL_CALLOC(1, sizeof(drwav));
drwav *ctxWav = (drwav *)RL_CALLOC(1, sizeof(drwav));
bool success = drwav_init_memory(ctxWav, (const void *)data, dataSize, NULL);
@ -1553,7 +1558,7 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data,
else if ((strcmp(fileType, ".ogg") == 0) || (strcmp(fileType, ".OGG") == 0))
{
// Open ogg audio stream
stb_vorbis* ctxOgg = stb_vorbis_open_memory((const unsigned char *)data, dataSize, NULL, NULL);
stb_vorbis *ctxOgg = stb_vorbis_open_memory((const unsigned char *)data, dataSize, NULL, NULL);
if (ctxOgg != NULL)
{
@ -1578,7 +1583,7 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data,
#if defined(SUPPORT_FILEFORMAT_MP3)
else if ((strcmp(fileType, ".mp3") == 0) || (strcmp(fileType, ".MP3") == 0))
{
drmp3 *ctxMp3 = RL_CALLOC(1, sizeof(drmp3));
drmp3 *ctxMp3 = (drmp3 *)RL_CALLOC(1, sizeof(drmp3));
int success = drmp3_init_memory(ctxMp3, (const void*)data, dataSize, NULL);
if (success)
@ -1858,6 +1863,8 @@ void SeekMusicStream(Music music, float position)
ma_mutex_lock(&AUDIO.System.lock);
music.stream.buffer->framesProcessed = positionInFrames;
music.stream.buffer->isSubBufferProcessed[0] = true;
music.stream.buffer->isSubBufferProcessed[1] = true;
ma_mutex_unlock(&AUDIO.System.lock);
}
@ -2104,8 +2111,12 @@ AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
// The size of a streaming buffer must be at least double the size of a period
unsigned int periodSize = AUDIO.System.device.playback.internalPeriodSizeInFrames;
// If the buffer is not set, compute one that would give us a buffer good enough for a decent frame rate
unsigned int subBufferSize = (AUDIO.Buffer.defaultSize == 0)? AUDIO.System.device.sampleRate/30 : AUDIO.Buffer.defaultSize;
// If the buffer is not set, compute one that would give us a buffer good enough for a decent frame rate at the device bit size/rate
int deviceBitsPerSample = AUDIO.System.device.playback.format;
if (deviceBitsPerSample > 4) deviceBitsPerSample = 4;
deviceBitsPerSample *= AUDIO.System.device.playback.channels;
unsigned int subBufferSize = (AUDIO.Buffer.defaultSize == 0) ? (AUDIO.System.device.sampleRate/30*deviceBitsPerSample) : AUDIO.Buffer.defaultSize;
if (subBufferSize < periodSize) subBufferSize = periodSize;
@ -2462,23 +2473,18 @@ static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, f
float *runningFramesOut = framesOut + (totalOutputFramesProcessed*audioBuffer->converter.channelsOut);
/* At this point we can convert the data to our mixing format. */
ma_uint64 inputFramesProcessedThisIteration = ReadAudioBufferFramesInInternalFormat(audioBuffer, inputBuffer, (ma_uint32)inputFramesToProcessThisIteration); /* Safe cast. */
// At this point we can convert the data to our mixing format
ma_uint64 inputFramesProcessedThisIteration = ReadAudioBufferFramesInInternalFormat(audioBuffer, inputBuffer, (ma_uint32)inputFramesToProcessThisIteration);
ma_uint64 outputFramesProcessedThisIteration = outputFramesToProcessThisIteration;
ma_data_converter_process_pcm_frames(&audioBuffer->converter, inputBuffer, &inputFramesProcessedThisIteration, runningFramesOut, &outputFramesProcessedThisIteration);
totalOutputFramesProcessed += (ma_uint32)outputFramesProcessedThisIteration; /* Safe cast. */
totalOutputFramesProcessed += (ma_uint32)outputFramesProcessedThisIteration; // Safe cast
if (inputFramesProcessedThisIteration < inputFramesToProcessThisIteration)
{
break; /* Ran out of input data. */
}
if (inputFramesProcessedThisIteration < inputFramesToProcessThisIteration) break; // Ran out of input data
/* This should never be hit, but will add it here for safety. Ensures we get out of the loop when no input nor output frames are processed. */
if (inputFramesProcessedThisIteration == 0 && outputFramesProcessedThisIteration == 0)
{
break;
}
// This should never be hit, but added here for safety
// Ensures we get out of the loop when no input nor output frames are processed
if ((inputFramesProcessedThisIteration == 0) && (outputFramesProcessedThisIteration == 0)) break;
}
return totalOutputFramesProcessed;

View file

@ -1,6 +1,6 @@
/**********************************************************************************************
*
* raylib v5.5 - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com)
* raylib v5.6-dev - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com)
*
* FEATURES:
* - NO external dependencies, all required libraries included with raylib
@ -63,7 +63,7 @@
* raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software:
*
* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5)
* Copyright (c) 2013-2025 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.
@ -88,9 +88,9 @@
#include <stdarg.h> // Required for: va_list - Only used by TraceLogCallback
#define RAYLIB_VERSION_MAJOR 5
#define RAYLIB_VERSION_MINOR 5
#define RAYLIB_VERSION_MINOR 6
#define RAYLIB_VERSION_PATCH 0
#define RAYLIB_VERSION "5.5"
#define RAYLIB_VERSION "5.6-dev"
// Function specifiers in case library is build/used as a shared library
// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
@ -743,7 +743,7 @@ typedef enum {
GAMEPAD_BUTTON_RIGHT_THUMB // Gamepad joystick pressed button right
} GamepadButton;
// Gamepad axis
// Gamepad axes
typedef enum {
GAMEPAD_AXIS_LEFT_X = 0, // Gamepad left stick X axis
GAMEPAD_AXIS_LEFT_Y = 1, // Gamepad left stick Y axis
@ -801,7 +801,8 @@ typedef enum {
SHADER_LOC_MAP_BRDF, // Shader location: sampler2d texture: brdf
SHADER_LOC_VERTEX_BONEIDS, // Shader location: vertex attribute: boneIds
SHADER_LOC_VERTEX_BONEWEIGHTS, // Shader location: vertex attribute: boneWeights
SHADER_LOC_BONE_MATRICES // Shader location: array of matrices uniform: boneMatrices
SHADER_LOC_BONE_MATRICES, // Shader location: array of matrices uniform: boneMatrices
SHADER_LOC_VERTEX_INSTANCE_TX // Shader location: vertex attribute: instanceTransform
} ShaderLocationIndex;
#define SHADER_LOC_MAP_DIFFUSE SHADER_LOC_MAP_ALBEDO
@ -817,6 +818,10 @@ typedef enum {
SHADER_UNIFORM_IVEC2, // Shader uniform type: ivec2 (2 int)
SHADER_UNIFORM_IVEC3, // Shader uniform type: ivec3 (3 int)
SHADER_UNIFORM_IVEC4, // Shader uniform type: ivec4 (4 int)
SHADER_UNIFORM_UINT, // Shader uniform type: unsigned int
SHADER_UNIFORM_UIVEC2, // Shader uniform type: uivec2 (2 unsigned int)
SHADER_UNIFORM_UIVEC3, // Shader uniform type: uivec3 (3 unsigned int)
SHADER_UNIFORM_UIVEC4, // Shader uniform type: uivec4 (4 unsigned int)
SHADER_UNIFORM_SAMPLER2D // Shader uniform type: sampler2d
} ShaderUniformDataType;
@ -949,7 +954,7 @@ typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args);
typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, int *dataSize); // FileIO: Load binary data
typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, int dataSize); // FileIO: Save binary data
typedef char *(*LoadFileTextCallback)(const char *fileName); // FileIO: Load text data
typedef bool (*SaveFileTextCallback)(const char *fileName, char *text); // FileIO: Save text data
typedef bool (*SaveFileTextCallback)(const char *fileName, const char *text); // FileIO: Save text data
//------------------------------------------------------------------------------------
// Global Variables Definition
@ -982,7 +987,7 @@ RLAPI void ToggleFullscreen(void); // Toggle wind
RLAPI void ToggleBorderlessWindowed(void); // Toggle window state: borderless windowed, resizes window to match monitor resolution
RLAPI void MaximizeWindow(void); // Set window state: maximized, if resizable
RLAPI void MinimizeWindow(void); // Set window state: minimized, if resizable
RLAPI void RestoreWindow(void); // Set window state: not minimized/maximized
RLAPI void RestoreWindow(void); // Restore window from being minimized/maximized
RLAPI void SetWindowIcon(Image image); // Set icon for window (single image, RGBA 32bit)
RLAPI void SetWindowIcons(Image *images, int count); // Set icon for window (multiple images, RGBA 32bit)
RLAPI void SetWindowTitle(const char *title); // Set title for window
@ -1056,7 +1061,7 @@ RLAPI int GetShaderLocationAttrib(Shader shader, const char *attribName); // Ge
RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType); // Set shader uniform value
RLAPI void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count); // Set shader uniform value vector
RLAPI void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat); // Set shader uniform value (matrix 4x4)
RLAPI void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture); // Set shader uniform value for texture (sampler2d)
RLAPI void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture); // Set shader uniform value and bind the texture (sampler2d)
RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM)
// Screen-space-related functions
@ -1118,7 +1123,7 @@ RLAPI bool SaveFileData(const char *fileName, void *data, int dataSize); // Save
RLAPI bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName); // Export data to code (.h), returns true on success
RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string
RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText()
RLAPI bool SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success
RLAPI bool SaveFileText(const char *fileName, const char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success
//------------------------------------------------------------------
// File system functions
@ -1148,22 +1153,21 @@ RLAPI long GetFileModTime(const char *fileName); // Get file mo
// Compression/Encoding functionality
RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize); // Compress data (DEFLATE algorithm), memory must be MemFree()
RLAPI unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // Decompress data (DEFLATE algorithm), memory must be MemFree()
RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string, memory must be MemFree()
RLAPI unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize); // Decode Base64 string data, memory must be MemFree()
RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize); // Compute CRC32 hash code
RLAPI unsigned int *ComputeMD5(unsigned char *data, int dataSize); // Compute MD5 hash code, returns static int[4] (16 bytes)
RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes)
RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string (includes NULL terminator), memory must be MemFree()
RLAPI unsigned char *DecodeDataBase64(const char *text, int *outputSize); // Decode Base64 string (expected NULL terminated), memory must be MemFree()
RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize); // Compute CRC32 hash code
RLAPI unsigned int *ComputeMD5(unsigned char *data, int dataSize); // Compute MD5 hash code, returns static int[4] (16 bytes)
RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes)
// Automation events functionality
RLAPI AutomationEventList LoadAutomationEventList(const char *fileName); // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS
RLAPI void UnloadAutomationEventList(AutomationEventList list); // Unload automation events list from file
RLAPI bool ExportAutomationEventList(AutomationEventList list, const char *fileName); // Export automation events list as text file
RLAPI void SetAutomationEventList(AutomationEventList *list); // Set automation event list to record to
RLAPI void SetAutomationEventBaseFrame(int frame); // Set automation event internal base frame to start recording
RLAPI void StartAutomationEventRecording(void); // Start recording automation events (AutomationEventList must be set)
RLAPI void StopAutomationEventRecording(void); // Stop recording automation events
RLAPI void PlayAutomationEvent(AutomationEvent event); // Play a recorded automation event
RLAPI AutomationEventList LoadAutomationEventList(const char *fileName); // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS
RLAPI void UnloadAutomationEventList(AutomationEventList list); // Unload automation events list from file
RLAPI bool ExportAutomationEventList(AutomationEventList list, const char *fileName); // Export automation events list as text file
RLAPI void SetAutomationEventList(AutomationEventList *list); // Set automation event list to record to
RLAPI void SetAutomationEventBaseFrame(int frame); // Set automation event internal base frame to start recording
RLAPI void StartAutomationEventRecording(void); // Start recording automation events (AutomationEventList must be set)
RLAPI void StopAutomationEventRecording(void); // Stop recording automation events
RLAPI void PlayAutomationEvent(AutomationEvent event); // Play a recorded automation event
//------------------------------------------------------------------------------------
// Input Handling Functions (Module: core)
@ -1177,19 +1181,20 @@ RLAPI bool IsKeyReleased(int key); // Check if a key
RLAPI bool IsKeyUp(int key); // Check if a key is NOT being pressed
RLAPI int GetKeyPressed(void); // Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty
RLAPI int GetCharPressed(void); // Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty
RLAPI const char *GetKeyName(int key); // Get name of a QWERTY key on the current keyboard layout (eg returns string 'q' for KEY_A on an AZERTY keyboard)
RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC)
// Input-related functions: gamepads
RLAPI bool IsGamepadAvailable(int gamepad); // Check if a gamepad is available
RLAPI const char *GetGamepadName(int gamepad); // Get gamepad internal name id
RLAPI bool IsGamepadButtonPressed(int gamepad, int button); // Check if a gamepad button has been pressed once
RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Check if a gamepad button is being pressed
RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Check if a gamepad button has been released once
RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Check if a gamepad button is NOT being pressed
RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed
RLAPI int GetGamepadAxisCount(int gamepad); // Get gamepad axis count for a gamepad
RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Get axis movement value for a gamepad axis
RLAPI int SetGamepadMappings(const char *mappings); // Set internal gamepad mappings (SDL_GameControllerDB)
RLAPI bool IsGamepadAvailable(int gamepad); // Check if a gamepad is available
RLAPI const char *GetGamepadName(int gamepad); // Get gamepad internal name id
RLAPI bool IsGamepadButtonPressed(int gamepad, int button); // Check if a gamepad button has been pressed once
RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Check if a gamepad button is being pressed
RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Check if a gamepad button has been released once
RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Check if a gamepad button is NOT being pressed
RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed
RLAPI int GetGamepadAxisCount(int gamepad); // Get axis count for a gamepad
RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Get movement value for a gamepad axis
RLAPI int SetGamepadMappings(const char *mappings); // Set internal gamepad mappings (SDL_GameControllerDB)
RLAPI void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration); // Set gamepad vibration for both motors (duration in seconds)
// Input-related functions: mouse
@ -1218,19 +1223,19 @@ RLAPI int GetTouchPointCount(void); // Get number of t
//------------------------------------------------------------------------------------
// Gestures and Touch Handling Functions (Module: rgestures)
//------------------------------------------------------------------------------------
RLAPI void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags
RLAPI bool IsGestureDetected(unsigned int gesture); // Check if a gesture have been detected
RLAPI int GetGestureDetected(void); // Get latest detected gesture
RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in seconds
RLAPI Vector2 GetGestureDragVector(void); // Get gesture drag vector
RLAPI float GetGestureDragAngle(void); // Get gesture drag angle
RLAPI Vector2 GetGesturePinchVector(void); // Get gesture pinch delta
RLAPI float GetGesturePinchAngle(void); // Get gesture pinch angle
RLAPI void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags
RLAPI bool IsGestureDetected(unsigned int gesture); // Check if a gesture have been detected
RLAPI int GetGestureDetected(void); // Get latest detected gesture
RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in seconds
RLAPI Vector2 GetGestureDragVector(void); // Get gesture drag vector
RLAPI float GetGestureDragAngle(void); // Get gesture drag angle
RLAPI Vector2 GetGesturePinchVector(void); // Get gesture pinch delta
RLAPI float GetGesturePinchAngle(void); // Get gesture pinch angle
//------------------------------------------------------------------------------------
// Camera System Functions (Module: rcamera)
//------------------------------------------------------------------------------------
RLAPI void UpdateCamera(Camera *camera, int mode); // Update camera position for selected mode
RLAPI void UpdateCamera(Camera *camera, int mode); // Update camera position for selected mode
RLAPI void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, float zoom); // Update camera movement/rotation
//------------------------------------------------------------------------------------
@ -1239,9 +1244,9 @@ RLAPI void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, f
// Set texture and rectangle to be used on shapes drawing
// NOTE: It can be useful when using basic shapes and one single font,
// defining a font char white rectangle would allow drawing everything in a single draw call
RLAPI void SetShapesTexture(Texture2D texture, Rectangle source); // Set texture and rectangle to be used on shapes drawing
RLAPI Texture2D GetShapesTexture(void); // Get texture that is used for shapes drawing
RLAPI Rectangle GetShapesTextureRectangle(void); // Get texture source rectangle that is used for shapes drawing
RLAPI void SetShapesTexture(Texture2D texture, Rectangle source); // Set texture and rectangle to be used on shapes drawing
RLAPI Texture2D GetShapesTexture(void); // Get texture that is used for shapes drawing
RLAPI Rectangle GetShapesTextureRectangle(void); // Get texture source rectangle that is used for shapes drawing
// Basic shapes drawing functions
RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel using geometry [Can be slow, use with care]
@ -1259,7 +1264,9 @@ RLAPI void DrawCircleV(Vector2 center, float radius, Color color);
RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline
RLAPI void DrawCircleLinesV(Vector2 center, float radius, Color color); // Draw circle outline (Vector version)
RLAPI void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse
RLAPI void DrawEllipseV(Vector2 center, float radiusH, float radiusV, Color color); // Draw ellipse (Vector version)
RLAPI void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse outline
RLAPI void DrawEllipseLinesV(Vector2 center, float radiusH, float radiusV, Color color); // Draw ellipse outline (Vector version)
RLAPI void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring
RLAPI void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring outline
RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle
@ -1268,7 +1275,7 @@ RLAPI void DrawRectangleRec(Rectangle rec, Color color);
RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters
RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color top, Color bottom); // Draw a vertical-gradient-filled rectangle
RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color left, Color right); // Draw a horizontal-gradient-filled rectangle
RLAPI void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color topRight, Color bottomRight); // Draw a gradient-filled rectangle with custom vertex colors
RLAPI void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color bottomRight, Color topRight); // Draw a gradient-filled rectangle with custom vertex colors
RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline
RLAPI void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color); // Draw rectangle outline with extended parameters
RLAPI void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color); // Draw rectangle with rounded edges
@ -1283,11 +1290,11 @@ RLAPI void DrawPolyLines(Vector2 center, int sides, float radius, float rotation
RLAPI void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float lineThick, Color color); // Draw a polygon outline of n sides with extended parameters
// Splines drawing functions
RLAPI void DrawSplineLinear(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Linear, minimum 2 points
RLAPI void DrawSplineBasis(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: B-Spline, minimum 4 points
RLAPI void DrawSplineCatmullRom(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Catmull-Rom, minimum 4 points
RLAPI void DrawSplineBezierQuadratic(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...]
RLAPI void DrawSplineBezierCubic(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...]
RLAPI void DrawSplineLinear(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Linear, minimum 2 points
RLAPI void DrawSplineBasis(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: B-Spline, minimum 4 points
RLAPI void DrawSplineCatmullRom(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Catmull-Rom, minimum 4 points
RLAPI void DrawSplineBezierQuadratic(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...]
RLAPI void DrawSplineBezierCubic(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...]
RLAPI void DrawSplineSegmentLinear(Vector2 p1, Vector2 p2, float thick, Color color); // Draw spline segment: Linear, 2 points
RLAPI void DrawSplineSegmentBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color); // Draw spline segment: B-Spline, 4 points
RLAPI void DrawSplineSegmentCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color); // Draw spline segment: Catmull-Rom, 4 points
@ -1360,7 +1367,7 @@ RLAPI void ImageAlphaPremultiply(Image *image);
RLAPI void ImageBlurGaussian(Image *image, int blurSize); // Apply Gaussian blur using a box blur approximation
RLAPI void ImageKernelConvolution(Image *image, const float *kernel, int kernelSize); // Apply custom square convolution kernel to image
RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize image (Bicubic scaling algorithm)
RLAPI void ImageResizeNN(Image *image, int newWidth,int newHeight); // Resize image (Nearest-Neighbor scaling algorithm)
RLAPI void ImageResizeNN(Image *image, int newWidth, int newHeight); // Resize image (Nearest-Neighbor scaling algorithm)
RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill); // Resize canvas and fill with color
RLAPI void ImageMipmaps(Image *image); // Compute all mipmap levels for a provided image
RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
@ -1401,8 +1408,8 @@ RLAPI void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color c
RLAPI void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle within an image
RLAPI void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3); // Draw triangle with interpolated colors within an image
RLAPI void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline within an image
RLAPI void ImageDrawTriangleFan(Image *dst, Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points within an image (first vertex is the center)
RLAPI void ImageDrawTriangleStrip(Image *dst, Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points within an image
RLAPI void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points within an image (first vertex is the center)
RLAPI void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points within an image
RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source)
RLAPI void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination)
RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination)
@ -1486,18 +1493,19 @@ RLAPI GlyphInfo GetGlyphInfo(Font font, int codepoint);
RLAPI Rectangle GetGlyphAtlasRec(Font font, int codepoint); // Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found
// Text codepoints management functions (unicode characters)
RLAPI char *LoadUTF8(const int *codepoints, int length); // Load UTF-8 text encoded from codepoints array
RLAPI void UnloadUTF8(char *text); // Unload UTF-8 text encoded from codepoints array
RLAPI int *LoadCodepoints(const char *text, int *count); // Load all codepoints from a UTF-8 text string, codepoints count returned by parameter
RLAPI void UnloadCodepoints(int *codepoints); // Unload codepoints data from memory
RLAPI int GetCodepointCount(const char *text); // Get total number of codepoints in a UTF-8 encoded string
RLAPI int GetCodepoint(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
RLAPI int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
RLAPI int GetCodepointPrevious(const char *text, int *codepointSize); // Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
RLAPI const char *CodepointToUTF8(int codepoint, int *utf8Size); // Encode one codepoint into UTF-8 byte array (array length returned as parameter)
RLAPI char *LoadUTF8(const int *codepoints, int length); // Load UTF-8 text encoded from codepoints array
RLAPI void UnloadUTF8(char *text); // Unload UTF-8 text encoded from codepoints array
RLAPI int *LoadCodepoints(const char *text, int *count); // Load all codepoints from a UTF-8 text string, codepoints count returned by parameter
RLAPI void UnloadCodepoints(int *codepoints); // Unload codepoints data from memory
RLAPI int GetCodepointCount(const char *text); // Get total number of codepoints in a UTF-8 encoded string
RLAPI int GetCodepoint(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
RLAPI int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
RLAPI int GetCodepointPrevious(const char *text, int *codepointSize); // Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
RLAPI const char *CodepointToUTF8(int codepoint, int *utf8Size); // Encode one codepoint into UTF-8 byte array (array length returned as parameter)
// Text strings management functions (no UTF-8 strings, only byte chars)
// NOTE: Some strings allocate memory internally for returned strings, just be careful!
// WARNING 1: Most of these functions use internal static buffers, it's recommended to store returned data on user-side for re-use
// WARNING 2: Some strings allocate memory internally for the returned strings, those strings must be free by user using MemFree()
RLAPI int TextCopy(char *dst, const char *src); // Copy one string to another, returns bytes copied
RLAPI bool TextIsEqual(const char *text1, const char *text2); // Check if two text string are equal
RLAPI unsigned int TextLength(const char *text); // Get text length, checks for '\0' ending
@ -1505,18 +1513,18 @@ RLAPI const char *TextFormat(const char *text, ...);
RLAPI const char *TextSubtext(const char *text, int position, int length); // Get a piece of a text string
RLAPI char *TextReplace(const char *text, const char *replace, const char *by); // Replace text string (WARNING: memory must be freed!)
RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a position (WARNING: memory must be freed!)
RLAPI const char *TextJoin(const char **textList, int count, const char *delimiter); // Join text strings with delimiter
RLAPI const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings
RLAPI char *TextJoin(char **textList, int count, const char *delimiter); // Join text strings with delimiter
RLAPI char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings
RLAPI void TextAppend(char *text, const char *append, int *position); // Append text at specific position and move cursor!
RLAPI int TextFindIndex(const char *text, const char *find); // Find first text occurrence within a string
RLAPI const char *TextToUpper(const char *text); // Get upper case version of provided string
RLAPI const char *TextToLower(const char *text); // Get lower case version of provided string
RLAPI const char *TextToPascal(const char *text); // Get Pascal case notation version of provided string
RLAPI const char *TextToSnake(const char *text); // Get Snake case notation version of provided string
RLAPI const char *TextToCamel(const char *text); // Get Camel case notation version of provided string
RLAPI char *TextToUpper(const char *text); // Get upper case version of provided string
RLAPI char *TextToLower(const char *text); // Get lower case version of provided string
RLAPI char *TextToPascal(const char *text); // Get Pascal case notation version of provided string
RLAPI char *TextToSnake(const char *text); // Get Snake case notation version of provided string
RLAPI char *TextToCamel(const char *text); // Get Camel case notation version of provided string
RLAPI int TextToInteger(const char *text); // Get integer value from text (negative values not supported)
RLAPI float TextToFloat(const char *text); // Get float value from text (negative values not supported)
RLAPI int TextToInteger(const char *text); // Get integer value from text
RLAPI float TextToFloat(const char *text); // Get float value from text
//------------------------------------------------------------------------------------
// Basic 3d Shapes Drawing Functions (Module: models)
@ -1609,14 +1617,14 @@ RLAPI void UnloadModelAnimations(ModelAnimation *animations, int animCount);
RLAPI bool IsModelAnimationValid(Model model, ModelAnimation anim); // Check model animation skeleton match
// Collision detection functions
RLAPI bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2); // Check collision between two spheres
RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Check collision between two bounding boxes
RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius); // Check collision between box and sphere
RLAPI RayCollision GetRayCollisionSphere(Ray ray, Vector3 center, float radius); // Get collision info between ray and sphere
RLAPI RayCollision GetRayCollisionBox(Ray ray, BoundingBox box); // Get collision info between ray and box
RLAPI RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform); // Get collision info between ray and mesh
RLAPI RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3); // Get collision info between ray and triangle
RLAPI RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4); // Get collision info between ray and quad
RLAPI bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2); // Check collision between two spheres
RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Check collision between two bounding boxes
RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius); // Check collision between box and sphere
RLAPI RayCollision GetRayCollisionSphere(Ray ray, Vector3 center, float radius); // Get collision info between ray and sphere
RLAPI RayCollision GetRayCollisionBox(Ray ray, BoundingBox box); // Get collision info between ray and box
RLAPI RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform); // Get collision info between ray and mesh
RLAPI RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3); // Get collision info between ray and triangle
RLAPI RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4); // Get collision info between ray and quad
//------------------------------------------------------------------------------------
// Audio Loading and Playing Functions (Module: audio)
@ -1695,10 +1703,10 @@ RLAPI void SetAudioStreamPan(AudioStream stream, float pan); // Set pan
RLAPI void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams
RLAPI void SetAudioStreamCallback(AudioStream stream, AudioCallback callback); // Audio thread callback to request new data
RLAPI void AttachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Attach audio stream processor to stream, receives the samples as 'float'
RLAPI void AttachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Attach audio stream processor to stream, receives frames x 2 samples as 'float' (stereo)
RLAPI void DetachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Detach audio stream processor from stream
RLAPI void AttachAudioMixedProcessor(AudioCallback processor); // Attach audio stream processor to the entire audio pipeline, receives the samples as 'float'
RLAPI void AttachAudioMixedProcessor(AudioCallback processor); // Attach audio stream processor to the entire audio pipeline, receives frames x 2 samples as 'float' (stereo)
RLAPI void DetachAudioMixedProcessor(AudioCallback processor); // Detach audio stream processor from the entire audio pipeline
#if defined(__cplusplus)

View file

@ -32,7 +32,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2015-2024 Ramon Santamaria (@raysan5)
* Copyright (c) 2015-2025 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.
@ -304,6 +304,14 @@ RMAPI float Vector2DotProduct(Vector2 v1, Vector2 v2)
return result;
}
// Calculate two vectors cross product
RMAPI float Vector2CrossProduct(Vector2 v1, Vector2 v2)
{
float result = (v1.x*v2.y - v1.y*v2.x);
return result;
}
// Calculate distance between two vectors
RMAPI float Vector2Distance(Vector2 v1, Vector2 v2)
{
@ -320,8 +328,9 @@ RMAPI float Vector2DistanceSqr(Vector2 v1, Vector2 v2)
return result;
}
// Calculate angle between two vectors
// NOTE: Angle is calculated from origin point (0, 0)
// Calculate the signed angle from v1 to v2, relative to the origin (0, 0)
// NOTE: Coordinate system convention: positive X right, positive Y down,
// positive angles appear clockwise, and negative angles appear counterclockwise
RMAPI float Vector2Angle(Vector2 v1, Vector2 v2)
{
float result = 0.0f;
@ -1459,19 +1468,35 @@ RMAPI int Vector4Equals(Vector4 p, Vector4 q)
RMAPI float MatrixDeterminant(Matrix mat)
{
float result = 0.0f;
/*
// Cache the matrix values (speed optimization)
float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3;
float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7;
float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11;
float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15;
// NOTE: It takes 72 multiplication to calculate 4x4 matrix determinant
result = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 +
a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 +
a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 +
a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 +
a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 +
a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33;
*/
// Using Laplace expansion (https://en.wikipedia.org/wiki/Laplace_expansion),
// previous operation can be simplified to 40 multiplications, decreasing matrix
// size from 4x4 to 2x2 using minors
// Cache the matrix values (speed optimization)
float m0 = mat.m0, m1 = mat.m1, m2 = mat.m2, m3 = mat.m3;
float m4 = mat.m4, m5 = mat.m5, m6 = mat.m6, m7 = mat.m7;
float m8 = mat.m8, m9 = mat.m9, m10 = mat.m10, m11 = mat.m11;
float m12 = mat.m12, m13 = mat.m13, m14 = mat.m14, m15 = mat.m15;
result = (m0*((m5*(m10*m15 - m11*m14) - m9*(m6*m15 - m7*m14) + m13*(m6*m11 - m7*m10))) -
m4*((m1*(m10*m15 - m11*m14) - m9*(m2*m15 - m3*m14) + m13*(m2*m11 - m3*m10))) +
m8*((m1*(m6*m15 - m7*m14) - m5*(m2*m15 - m3*m14) + m13*(m2*m7 - m3*m6))) -
m12*((m1*(m6*m11 - m7*m10) - m5*(m2*m11 - m3*m10) + m9*(m2*m7 - m3*m6))));
return result;
}
@ -2648,7 +2673,7 @@ inline Vector2 operator * (const Vector2& lhs, const Matrix& rhs)
return Vector2Transform(lhs, rhs);
}
inline const Vector2& operator -= (Vector2& lhs, const Matrix& rhs)
inline const Vector2& operator *= (Vector2& lhs, const Matrix& rhs)
{
lhs = Vector2Transform(lhs, rhs);
return lhs;
@ -2656,12 +2681,12 @@ inline const Vector2& operator -= (Vector2& lhs, const Matrix& rhs)
inline Vector2 operator / (const Vector2& lhs, const float& rhs)
{
return Vector2Scale(lhs, 1.0f / rhs);
return Vector2Scale(lhs, 1.0f/rhs);
}
inline const Vector2& operator /= (Vector2& lhs, const float& rhs)
{
lhs = Vector2Scale(lhs, rhs);
lhs = Vector2Scale(lhs, 1.0f/rhs);
return lhs;
}
@ -2742,7 +2767,7 @@ inline Vector3 operator * (const Vector3& lhs, const Matrix& rhs)
return Vector3Transform(lhs, rhs);
}
inline const Vector3& operator -= (Vector3& lhs, const Matrix& rhs)
inline const Vector3& operator *= (Vector3& lhs, const Matrix& rhs)
{
lhs = Vector3Transform(lhs, rhs);
return lhs;
@ -2750,12 +2775,12 @@ inline const Vector3& operator -= (Vector3& lhs, const Matrix& rhs)
inline Vector3 operator / (const Vector3& lhs, const float& rhs)
{
return Vector3Scale(lhs, 1.0f / rhs);
return Vector3Scale(lhs, 1.0f/rhs);
}
inline const Vector3& operator /= (Vector3& lhs, const float& rhs)
{
lhs = Vector3Scale(lhs, rhs);
lhs = Vector3Scale(lhs, 1.0f/rhs);
return lhs;
}
@ -2834,12 +2859,12 @@ inline const Vector4& operator *= (Vector4& lhs, const Vector4& rhs)
inline Vector4 operator / (const Vector4& lhs, const float& rhs)
{
return Vector4Scale(lhs, 1.0f / rhs);
return Vector4Scale(lhs, 1.0f/rhs);
}
inline const Vector4& operator /= (Vector4& lhs, const float& rhs)
{
lhs = Vector4Scale(lhs, rhs);
lhs = Vector4Scale(lhs, 1.0f/rhs);
return lhs;
}

View file

@ -20,7 +20,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2022-2024 Christoph Wagner (@Crydsch) & Ramon Santamaria (@raysan5)
* Copyright (c) 2022-2025 Christoph Wagner (@Crydsch) & 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.
@ -154,7 +154,7 @@ RLAPI void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAr
RLAPI void CameraRoll(Camera *camera, float angle);
RLAPI Matrix GetCameraViewMatrix(Camera *camera);
RLAPI Matrix GetCameraProjectionMatrix(Camera* camera, float aspect);
RLAPI Matrix GetCameraProjectionMatrix(Camera *camera, float aspect);
#if defined(__cplusplus)
}

View file

@ -12,6 +12,13 @@
* - Windows (Win32, Win64)
* - Linux (X11/Wayland desktop mode)
* - Others (not tested)
* > PLATFORM_DESKTOP_RGFW (RGFW backend):
* - Windows (Win32, Win64)
* - Linux (X11/Wayland desktop mode)
* - macOS/OSX (x64, arm64)
* - Others (not tested)
* > PLATFORM_WEB_RGFW:
* - HTML5 (WebAssembly)
* > PLATFORM_WEB:
* - HTML5 (WebAssembly)
* > PLATFORM_DRM:
@ -63,7 +70,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) and contributors
* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@ -85,12 +92,12 @@
//----------------------------------------------------------------------------------
// Feature Test Macros required for this module
//----------------------------------------------------------------------------------
#if (defined(__linux__) || defined(PLATFORM_WEB)) && (_XOPEN_SOURCE < 500)
#if (defined(__linux__) || defined(PLATFORM_WEB) || defined(PLATFORM_WEB_RGFW)) && (_XOPEN_SOURCE < 500)
#undef _XOPEN_SOURCE
#define _XOPEN_SOURCE 500 // Required for: readlink if compiled with c99 without gnu ext.
#endif
#if (defined(__linux__) || defined(PLATFORM_WEB)) && (_POSIX_C_SOURCE < 199309L)
#if (defined(__linux__) || defined(PLATFORM_WEB) || defined(PLATFORM_WEB_RGFW)) && (_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
@ -158,9 +165,10 @@
#ifndef MAX_PATH
#define MAX_PATH 1025
#endif
__declspec(dllimport) unsigned long __stdcall GetModuleFileNameA(void *hModule, void *lpFilename, unsigned long nSize);
__declspec(dllimport) unsigned long __stdcall GetModuleFileNameW(void *hModule, void *lpFilename, unsigned long nSize);
__declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, void *widestr, int cchwide, void *str, int cbmb, void *defchar, int *used_default);
struct HINSTANCE__;
__declspec(dllimport) unsigned long __stdcall GetModuleFileNameA(struct HINSTANCE__ *hModule, char *lpFilename, unsigned long nSize);
__declspec(dllimport) unsigned long __stdcall GetModuleFileNameW(struct HINSTANCE__ *hModule, wchar_t *lpFilename, unsigned long nSize);
__declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);
__declspec(dllimport) unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod);
__declspec(dllimport) unsigned int __stdcall timeEndPeriod(unsigned int uPeriod);
#elif defined(__linux__)
@ -226,8 +234,11 @@ __declspec(dllimport) unsigned int __stdcall timeEndPeriod(unsigned int uPeriod)
#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)
#ifndef MAX_GAMEPAD_NAME_LENGTH
#define MAX_GAMEPAD_NAME_LENGTH 128 // Maximum number of characters in a gamepad name (byte size)
#endif
#ifndef MAX_GAMEPAD_AXES
#define MAX_GAMEPAD_AXES 8 // Maximum number of axes supported (per gamepad)
#endif
#ifndef MAX_GAMEPAD_BUTTONS
#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
@ -343,12 +354,12 @@ typedef struct CoreData {
} Touch;
struct {
int lastButtonPressed; // Register last gamepad button pressed
int axisCount[MAX_GAMEPADS]; // Register number of available gamepad axis
int axisCount[MAX_GAMEPADS]; // Register number of available gamepad axes
bool ready[MAX_GAMEPADS]; // Flag to know if gamepad is ready
char name[MAX_GAMEPADS][64]; // Gamepad name holder
char name[MAX_GAMEPADS][MAX_GAMEPAD_NAME_LENGTH]; // 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
float axisState[MAX_GAMEPADS][MAX_GAMEPAD_AXES]; // Gamepad axes state
} Gamepad;
} Input;
@ -501,7 +512,7 @@ static void RecordAutomationEvent(void); // Record frame events (to internal eve
#if defined(_WIN32) && !defined(PLATFORM_DESKTOP_RGFW)
// NOTE: We declare Sleep() function symbol to avoid including windows.h (kernel32.lib linkage required)
void __stdcall Sleep(unsigned long msTimeout); // Required for: WaitTime()
__declspec(dllimport) void __stdcall Sleep(unsigned long msTimeout); // Required for: WaitTime()
#endif
#if !defined(SUPPORT_MODULE_RTEXT)
@ -512,25 +523,25 @@ const char *TextFormat(const char *text, ...); // Formatting of tex
#define PLATFORM_DESKTOP_GLFW
#endif
// We're using `#pragma message` because `#warning` is not adopted by MSVC.
// We're using '#pragma message' because '#warning' is not adopted by MSVC
#if defined(SUPPORT_CLIPBOARD_IMAGE)
#if !defined(SUPPORT_MODULE_RTEXTURES)
#pragma message ("Warning: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly")
#pragma message ("WARNING: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly")
#endif
// It's nice to have support Bitmap on Linux as well, but not as necessary as Windows
#if !defined(SUPPORT_FILEFORMAT_BMP) && defined(_WIN32)
#pragma message ("Warning: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_FILEFORMAT_BMP, specially on Windows")
#pragma message ("WARNING: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_FILEFORMAT_BMP, specially on Windows")
#endif
// From what I've tested applications on Wayland saves images on clipboard as PNG.
// From what I've tested applications on Wayland saves images on clipboard as PNG
#if (!defined(SUPPORT_FILEFORMAT_PNG) || !defined(SUPPORT_FILEFORMAT_JPG)) && !defined(_WIN32)
#pragma message ("Warning: Getting image from the clipboard might not work without SUPPORT_FILEFORMAT_PNG or SUPPORT_FILEFORMAT_JPG")
#pragma message ("WARNING: Getting image from the clipboard might not work without SUPPORT_FILEFORMAT_PNG or SUPPORT_FILEFORMAT_JPG")
#endif
// Not needed because `rtexture.c` will automatically defined STBI_REQUIRED when any SUPPORT_FILEFORMAT_* is defined.
// Not needed because `rtexture.c` will automatically defined STBI_REQUIRED when any SUPPORT_FILEFORMAT_* is defined
// #if !defined(STBI_REQUIRED)
// #pragma message ("Warning: "STBI_REQUIRED is not defined, that means we can't load images from clipbard"
// #pragma message ("WARNING: "STBI_REQUIRED is not defined, that means we can't load images from clipbard"
// #endif
#endif // SUPPORT_CLIPBOARD_IMAGE
@ -540,7 +551,7 @@ const char *TextFormat(const char *text, ...); // Formatting of tex
#include "platforms/rcore_desktop_glfw.c"
#elif defined(PLATFORM_DESKTOP_SDL)
#include "platforms/rcore_desktop_sdl.c"
#elif defined(PLATFORM_DESKTOP_RGFW)
#elif (defined(PLATFORM_DESKTOP_RGFW) || defined(PLATFORM_WEB_RGFW))
#include "platforms/rcore_desktop_rgfw.c"
#elif defined(PLATFORM_WEB)
#include "platforms/rcore_web.c"
@ -611,6 +622,8 @@ void InitWindow(int width, int height, const char *title)
TRACELOG(LOG_INFO, "Platform backend: DESKTOP (SDL)");
#elif defined(PLATFORM_DESKTOP_RGFW)
TRACELOG(LOG_INFO, "Platform backend: DESKTOP (RGFW)");
#elif defined(PLATFORM_WEB_RGFW)
TRACELOG(LOG_INFO, "Platform backend: WEB (RGFW) (HTML5)");
#elif defined(PLATFORM_WEB)
TRACELOG(LOG_INFO, "Platform backend: WEB (HTML5)");
#elif defined(PLATFORM_DRM)
@ -668,7 +681,13 @@ void InitWindow(int width, int height, const char *title)
// Initialize platform
//--------------------------------------------------------------
InitPlatform();
int result = InitPlatform();
if (result != 0)
{
TRACELOG(LOG_WARNING, "SYSTEM: Failed to initialize Platform");
return;
}
//--------------------------------------------------------------
// Initialize rlgl default data (buffers and shaders)
@ -1100,7 +1119,7 @@ void BeginTextureMode(RenderTexture2D target)
//rlScalef(0.0f, -1.0f, 0.0f); // Flip Y-drawing (?)
// Setup current width/height for proper aspect ratio
// calculation when using BeginMode3D()
// calculation when using BeginTextureMode()
CORE.Window.currentFbo.width = target.texture.width;
CORE.Window.currentFbo.height = target.texture.height;
CORE.Window.usingFbo = true;
@ -1302,6 +1321,8 @@ Shader LoadShader(const char *vsFileName, const char *fsFileName)
if (vsFileName != NULL) vShaderStr = LoadFileText(vsFileName);
if (fsFileName != NULL) fShaderStr = LoadFileText(fsFileName);
if ((vShaderStr == NULL) && (fShaderStr == NULL)) TraceLog(LOG_WARNING, "SHADER: Shader files provided are not valid, using default shader");
shader = LoadShaderFromMemory(vShaderStr, fShaderStr);
UnloadFileText(vShaderStr);
@ -1317,9 +1338,10 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
shader.id = rlLoadShaderCode(vsCode, fsCode);
// After shader loading, we TRY to set default location names
if (shader.id > 0)
if (shader.id == rlGetShaderIdDefault()) shader.locs = rlGetShaderLocsDefault();
else if (shader.id > 0)
{
// After custom shader loading, we TRY to set default location names
// Default shader attribute locations have been binded before linking:
// vertex position location = 0
// vertex texcoord location = 1
@ -1346,6 +1368,7 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
shader.locs[SHADER_LOC_VERTEX_COLOR] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR);
shader.locs[SHADER_LOC_VERTEX_BONEIDS] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS);
shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS);
shader.locs[SHADER_LOC_VERTEX_INSTANCE_TX] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX);
// Get handles to GLSL uniform locations (vertex shader)
shader.locs[SHADER_LOC_MATRIX_MVP] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_MVP);
@ -1856,12 +1879,15 @@ void TakeScreenshot(const char *fileName)
// Security check to (partially) avoid malicious code
if (strchr(fileName, '\'') != NULL) { TRACELOG(LOG_WARNING, "SYSTEM: Provided fileName could be potentially malicious, avoid [\'] character"); return; }
Vector2 scale = GetWindowScaleDPI();
// Apply a scale if we are doing HIGHDPI auto-scaling
Vector2 scale = { 1.0f, 1.0f };
if (IsWindowState(FLAG_WINDOW_HIGHDPI)) scale = GetWindowScaleDPI();
unsigned char *imgData = rlReadScreenPixels((int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y));
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, GetFileName(fileName)));
strcpy(path, TextFormat("%s/%s", CORE.Storage.basePath, fileName));
ExportImage(image, path); // WARNING: Module required: rtextures
RL_FREE(imgData);
@ -1879,6 +1905,8 @@ void TakeScreenshot(const char *fileName)
// To configure window states after creation, just use SetWindowState()
void SetConfigFlags(unsigned int flags)
{
if (CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetConfigFlags called after window initialization, Use \"SetWindowState\" to set flags instead");
// Selected flags are set but not evaluated at this point,
// flag evaluation happens at InitWindow() or SetWindowState()
CORE.Window.flags |= flags;
@ -1920,7 +1948,7 @@ 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
char **checkExts = TextSplit(ext, ';', &extCount); // WARNING: Module required: rtext
char fileExtLower[MAX_FILE_EXTENSION_LENGTH + 1] = { 0 };
strncpy(fileExtLower, TextToLower(fileExt), MAX_FILE_EXTENSION_LENGTH); // WARNING: Module required: rtext
@ -2062,7 +2090,7 @@ const char *GetDirectoryPath(const char *filePath)
// In case provided path does not contain a root drive letter (C:\, D:\) nor leading path separator (\, /),
// we add the current directory path to dirPath
if (filePath[1] != ':' && filePath[0] != '\\' && filePath[0] != '/')
if ((filePath[1] != ':') && (filePath[0] != '\\') && (filePath[0] != '/'))
{
// For security, we set starting path to current directory,
// obtained path will be concatenated to this
@ -2286,9 +2314,12 @@ FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool
// WARNING: files.count is not reseted to 0 after unloading
void UnloadDirectoryFiles(FilePathList files)
{
for (unsigned int i = 0; i < files.capacity; i++) RL_FREE(files.paths[i]);
if (files.paths != NULL)
{
for (unsigned int i = 0; i < files.capacity; i++) RL_FREE(files.paths[i]);
RL_FREE(files.paths);
RL_FREE(files.paths);
}
}
// Create directories (including full path requested), returns 0 on success
@ -2331,6 +2362,7 @@ bool ChangeDirectory(const char *dir)
bool result = CHDIR(dir);
if (result != 0) TRACELOG(LOG_WARNING, "SYSTEM: Failed to change to directory: %s", dir);
else TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", dir);
return (result == 0);
}
@ -2468,7 +2500,7 @@ unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDa
#if defined(SUPPORT_COMPRESSION_API)
// Compress data and generate a valid DEFLATE stream
struct sdefl *sdefl = RL_CALLOC(1, sizeof(struct sdefl)); // WARNING: Possible stack overflow, struct sdefl is almost 1MB
struct sdefl *sdefl = (struct sdefl *)RL_CALLOC(1, sizeof(struct sdefl)); // WARNING: Possible stack overflow, struct sdefl is almost 1MB
int bounds = sdefl_bound(dataSize);
compData = (unsigned char *)RL_CALLOC(bounds, 1);
@ -2507,96 +2539,112 @@ unsigned char *DecompressData(const unsigned char *compData, int compDataSize, i
}
// Encode data to Base64 string
// NOTE: Returned string includes NULL terminator, considered on outputSize
char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize)
{
static const unsigned char base64encodeTable[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};
// Base64 conversion table from RFC 4648 [0..63]
// NOTE: They represent 64 values (6 bits), to encode 3 bytes of data into 4 "sixtets" (6bit characters)
static const char base64EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const int modTable[] = { 0, 2, 1 };
// Compute expected size and padding
int paddedSize = dataSize;
while (paddedSize%3 != 0) paddedSize++; // Padding bytes to round 4*(dataSize/3) to 4 bytes
int estimatedOutputSize = 4*(paddedSize/3);
int padding = paddedSize - dataSize;
*outputSize = 4*((dataSize + 2)/3);
// Adding null terminator to string
estimatedOutputSize += 1;
char *encodedData = (char *)RL_MALLOC(*outputSize);
// Load some memory to store encoded string
char *encodedData = (char *)RL_CALLOC(estimatedOutputSize, 1);
if (encodedData == NULL) return NULL;
if (encodedData == NULL) return NULL; // Security check
for (int i = 0, j = 0; i < dataSize;)
int outputCount = 0;
for (int i = 0; i < dataSize;)
{
unsigned int octetA = (i < dataSize)? (unsigned char)data[i++] : 0;
unsigned int octetB = (i < dataSize)? (unsigned char)data[i++] : 0;
unsigned int octetC = (i < dataSize)? (unsigned char)data[i++] : 0;
unsigned int octetA = 0;
unsigned int octetB = 0;
unsigned int octetC = 0;
unsigned int octetPack = 0;
unsigned int triple = (octetA << 0x10) + (octetB << 0x08) + octetC;
octetA = data[i]; // Generates 2 sextets
octetB = ((i + 1) < dataSize)? data[i + 1] : 0; // Generates 3 sextets
octetC = ((i + 2) < dataSize)? data[i + 2] : 0; // Generates 4 sextets
encodedData[j++] = base64encodeTable[(triple >> 3*6) & 0x3F];
encodedData[j++] = base64encodeTable[(triple >> 2*6) & 0x3F];
encodedData[j++] = base64encodeTable[(triple >> 1*6) & 0x3F];
encodedData[j++] = base64encodeTable[(triple >> 0*6) & 0x3F];
octetPack = (octetA << 16) | (octetB << 8) | octetC;
encodedData[outputCount + 0] = (unsigned char)(base64EncodeTable[(octetPack >> 18) & 0x3f]);
encodedData[outputCount + 1] = (unsigned char)(base64EncodeTable[(octetPack >> 12) & 0x3f]);
encodedData[outputCount + 2] = (unsigned char)(base64EncodeTable[(octetPack >> 6) & 0x3f]);
encodedData[outputCount + 3] = (unsigned char)(base64EncodeTable[octetPack & 0x3f]);
outputCount += 4;
i += 3;
}
for (int i = 0; i < modTable[dataSize%3]; i++) encodedData[*outputSize - 1 - i] = '='; // Padding character
// Add required padding bytes
for (int p = 0; p < padding; p++) encodedData[outputCount - p - 1] = '=';
// Add null terminator to string
encodedData[outputCount] = '\0';
outputCount++;
if (outputCount != estimatedOutputSize) TRACELOG(LOG_WARNING, "BASE64: Output size differs from estimation");
*outputSize = estimatedOutputSize;
return encodedData;
}
// Decode Base64 string data
unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize)
// Decode Base64 string (expected NULL terminated)
unsigned char *DecodeDataBase64(const char *text, int *outputSize)
{
static const unsigned char base64decodeTable[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
// Base64 decode table
// NOTE: Following ASCII order [0..255] assigning the expected sixtet value to
// every character in the corresponding ASCII position
static const unsigned char base64DecodeTable[256] = {
['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4, ['F'] = 5, ['G'] = 6, ['H'] = 7,
['I'] = 8, ['J'] = 9, ['K'] = 10, ['L'] = 11, ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15,
['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19, ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24, ['Z'] = 25,
['a'] = 26, ['b'] = 27, ['c'] = 28, ['d'] = 29, ['e'] = 30, ['f'] = 31, ['g'] = 32, ['h'] = 33,
['i'] = 34, ['j'] = 35, ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39, ['o'] = 40, ['p'] = 41,
['q'] = 42, ['r'] = 43, ['s'] = 44, ['t'] = 45, ['u'] = 46, ['v'] = 47, ['w'] = 48, ['x'] = 49, ['y'] = 50, ['z'] = 51,
['0'] = 52, ['1'] = 53, ['2'] = 54, ['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59,
['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63
};
// Get output size of Base64 input data
int outSize = 0;
for (int i = 0; data[4*i] != 0; i++)
// Compute expected size and padding
int dataSize = (int)strlen(text); // WARNING: Expecting NULL terminated strings!
int ending = dataSize - 1;
int padding = 0;
while (text[ending] == '=') { padding++; ending--; }
int estimatedOutputSize = 3*(dataSize/4) - padding;
int maxOutputSize = 3*(dataSize/4);
// Load some memory to store decoded data
// NOTE: Allocated enough size to include padding
unsigned char *decodedData = (unsigned char *)RL_CALLOC(maxOutputSize, 1);
if (decodedData == NULL) return NULL;
int outputCount = 0;
for (int i = 0; i < dataSize;)
{
if (data[4*i + 3] == '=')
{
if (data[4*i + 2] == '=') outSize += 1;
else outSize += 2;
}
else outSize += 3;
// Every 4 sixtets must generate 3 octets
unsigned int sixtetA = base64DecodeTable[(unsigned char)text[i]];
unsigned int sixtetB = base64DecodeTable[(unsigned char)text[i + 1]];
unsigned int sixtetC = ((unsigned char)text[i + 2] != '=')? base64DecodeTable[(unsigned char)text[i + 2]] : 0;
unsigned int sixtetD = ((unsigned char)text[i + 3] != '=')? base64DecodeTable[(unsigned char)text[i + 3]] : 0;
unsigned int octetPack = (sixtetA << 18) | (sixtetB << 12) | (sixtetC << 6) | sixtetD;
decodedData[outputCount + 0] = (octetPack >> 16) & 0xff;
decodedData[outputCount + 1] = (octetPack >> 8) & 0xff;
decodedData[outputCount + 2] = octetPack & 0xff;
outputCount += 3;
i += 4;
}
// Allocate memory to store decoded Base64 data
unsigned char *decodedData = (unsigned char *)RL_MALLOC(outSize);
if (estimatedOutputSize != (outputCount - padding)) TRACELOG(LOG_WARNING, "BASE64: Decoded size differs from estimation");
for (int i = 0; i < outSize/3; i++)
{
unsigned char a = base64decodeTable[(int)data[4*i]];
unsigned char b = base64decodeTable[(int)data[4*i + 1]];
unsigned char c = base64decodeTable[(int)data[4*i + 2]];
unsigned char d = base64decodeTable[(int)data[4*i + 3]];
decodedData[3*i] = (a << 2) | (b >> 4);
decodedData[3*i + 1] = (b << 4) | (c >> 2);
decodedData[3*i + 2] = (c << 6) | d;
}
if (outSize%3 == 1)
{
int n = outSize/3;
unsigned char a = base64decodeTable[(int)data[4*n]];
unsigned char b = base64decodeTable[(int)data[4*n + 1]];
decodedData[outSize - 1] = (a << 2) | (b >> 4);
}
else if (outSize%3 == 2)
{
int n = outSize/3;
unsigned char a = base64decodeTable[(int)data[4*n]];
unsigned char b = base64decodeTable[(int)data[4*n + 1]];
unsigned char c = base64decodeTable[(int)data[4*n + 2]];
decodedData[outSize - 2] = (a << 2) | (b >> 4);
decodedData[outSize - 1] = (b << 4) | (c >> 2);
}
*outputSize = outSize;
*outputSize = estimatedOutputSize;
return decodedData;
}
@ -2604,38 +2652,38 @@ unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize)
unsigned int ComputeCRC32(unsigned char *data, int dataSize)
{
static unsigned int crcTable[256] = {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
unsigned int crc = ~0u;
@ -2699,7 +2747,7 @@ unsigned int *ComputeMD5(unsigned char *data, int dataSize)
int newDataSize = ((((dataSize + 8)/64) + 1)*64) - 8;
unsigned char *msg = RL_CALLOC(newDataSize + 64, 1); // Initialize with '0' bits, allocating 64 extra bytes
unsigned char *msg = (unsigned char *)RL_CALLOC(newDataSize + 64, 1); // Initialize with '0' bits, allocating 64 extra bytes
memcpy(msg, data, dataSize);
msg[dataSize] = 128; // Write the '1' bit
@ -2765,7 +2813,8 @@ unsigned int *ComputeMD5(unsigned char *data, int dataSize)
// Compute SHA-1 hash code
// NOTE: Returns a static int[5] array (20 bytes)
unsigned int *ComputeSHA1(unsigned char *data, int dataSize) {
unsigned int *ComputeSHA1(unsigned char *data, int dataSize)
{
#define ROTATE_LEFT(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
static unsigned int hash[5] = { 0 }; // Hash to be returned
@ -2788,7 +2837,7 @@ unsigned int *ComputeSHA1(unsigned char *data, int dataSize) {
int newDataSize = ((((dataSize + 8)/64) + 1)*64);
unsigned char *msg = RL_CALLOC(newDataSize, 1); // Initialize with '0' bits
unsigned char *msg = (unsigned char *)RL_CALLOC(newDataSize, 1); // Initialize with '0' bits
memcpy(msg, data, dataSize);
msg[dataSize] = 128; // Write the '1' bit
@ -2800,17 +2849,16 @@ unsigned int *ComputeSHA1(unsigned char *data, int dataSize) {
{
// Break chunk into sixteen 32-bit words w[j], 0 <= j <= 15
unsigned int w[80] = {0};
for (int i = 0; i < 16; i++) {
w[i] = (msg[offset + (i * 4) + 0] << 24) |
(msg[offset + (i * 4) + 1] << 16) |
(msg[offset + (i * 4) + 2] << 8) |
(msg[offset + (i * 4) + 3]);
for (int i = 0; i < 16; i++)
{
w[i] = (msg[offset + (i*4) + 0] << 24) |
(msg[offset + (i*4) + 1] << 16) |
(msg[offset + (i*4) + 2] << 8) |
(msg[offset + (i*4) + 3]);
}
// Message schedule: extend the sixteen 32-bit words into eighty 32-bit words:
for (int i = 16; i < 80; ++i) {
w[i] = ROTATE_LEFT(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1);
}
for (int i = 16; i < 80; i++) w[i] = ROTATE_LEFT(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1);
// Initialize hash value for this chunk
unsigned int a = hash[0];
@ -2824,16 +2872,23 @@ unsigned int *ComputeSHA1(unsigned char *data, int dataSize) {
unsigned int f = 0;
unsigned int k = 0;
if (i < 20) {
if (i < 20)
{
f = (b & c) | ((~b) & d);
k = 0x5A827999;
} else if (i < 40) {
}
else if (i < 40)
{
f = b ^ c ^ d;
k = 0x6ED9EBA1;
} else if (i < 60) {
}
else if (i < 60)
{
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
} else {
}
else
{
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
@ -2982,7 +3037,7 @@ bool ExportAutomationEventList(AutomationEventList list, const char *fileName)
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, "# Copyright (c) 2023-2025 Ramon Santamaria (@raysan5)\n");
byteCount += sprintf(txtData + byteCount, "#\n\n");
// Add events data
@ -3313,10 +3368,11 @@ int GetGamepadAxisCount(int gamepad)
// Get axis movement vector for a gamepad
float GetGamepadAxisMovement(int gamepad, int axis)
{
float value = (axis == GAMEPAD_AXIS_LEFT_TRIGGER || axis == GAMEPAD_AXIS_RIGHT_TRIGGER)? -1.0f : 0.0f;
float value = ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))? -1.0f : 0.0f;
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXIS)) {
float movement = value < 0.0f ? CORE.Input.Gamepad.axisState[gamepad][axis] : fabsf(CORE.Input.Gamepad.axisState[gamepad][axis]);
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXES))
{
float movement = (value < 0.0f)? CORE.Input.Gamepad.axisState[gamepad][axis] : fabsf(CORE.Input.Gamepad.axisState[gamepad][axis]);
if (movement > value) value = CORE.Input.Gamepad.axisState[gamepad][axis];
}
@ -3657,12 +3713,16 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const
(strcmp(dp->d_name, "..") != 0))
{
#if defined(_WIN32)
sprintf(path, "%s\\%s", basePath, dp->d_name);
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s\\%s", basePath, dp->d_name);
#else
sprintf(path, "%s/%s", basePath, dp->d_name);
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s/%s", basePath, dp->d_name);
#endif
if (filter != NULL)
if ((pathLength < 0) || (pathLength >= MAX_FILEPATH_LENGTH))
{
TRACELOG(LOG_WARNING, "FILEIO: Path longer than %d characters (%s...)", MAX_FILEPATH_LENGTH, basePath);
}
else if (filter != NULL)
{
if (IsPathFile(path))
{
@ -3674,7 +3734,7 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const
}
else
{
if (TextFindIndex(filter, DIRECTORY_FILTER_TAG) >= 0)
if (strstr(filter, DIRECTORY_FILTER_TAG) != NULL)
{
strcpy(files->paths[files->count], path);
files->count++;
@ -3697,7 +3757,7 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const
// Scan all files and directories recursively from a base path
static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *files, const char *filter)
{
char path[MAX_FILEPATH_LENGTH] = { 0 };
static char path[MAX_FILEPATH_LENGTH] = { 0 };
memset(path, 0, MAX_FILEPATH_LENGTH);
struct dirent *dp = NULL;
@ -3711,12 +3771,16 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi
{
// Construct new path from our base path
#if defined(_WIN32)
sprintf(path, "%s\\%s", basePath, dp->d_name);
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s\\%s", basePath, dp->d_name);
#else
sprintf(path, "%s/%s", basePath, dp->d_name);
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s/%s", basePath, dp->d_name);
#endif
if (IsPathFile(path))
if ((pathLength < 0) || (pathLength >= MAX_FILEPATH_LENGTH))
{
TRACELOG(LOG_WARNING, "FILEIO: Path longer than %d characters (%s...)", MAX_FILEPATH_LENGTH, basePath);
}
else if (IsPathFile(path))
{
if (filter != NULL)
{
@ -3740,7 +3804,7 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi
}
else
{
if ((filter != NULL) && (TextFindIndex(filter, DIRECTORY_FILTER_TAG) >= 0))
if ((filter != NULL) && (strstr(filter, DIRECTORY_FILTER_TAG) != NULL))
{
strcpy(files->paths[files->count], path);
files->count++;
@ -3986,10 +4050,10 @@ static void RecordAutomationEvent(void)
if (currentEventList->count == currentEventList->capacity) return; // Security check
}
for (int axis = 0; axis < MAX_GAMEPAD_AXIS; axis++)
for (int axis = 0; axis < MAX_GAMEPAD_AXES; axis++)
{
// Event type: INPUT_GAMEPAD_AXIS_MOTION
float defaultMovement = (axis == GAMEPAD_AXIS_LEFT_TRIGGER || axis == GAMEPAD_AXIS_RIGHT_TRIGGER)? -1.0f : 0.0f;
float defaultMovement = ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))? -1.0f : 0.0f;
if (GetGamepadAxisMovement(gamepad, axis) != defaultMovement)
{
currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;

View file

@ -21,7 +21,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2024 Ramon Santamaria (@raysan5)
* Copyright (c) 2014-2025 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.

View file

@ -3,14 +3,14 @@
* rlgl v5.0 - A multi-OpenGL abstraction layer with an immediate-mode style API
*
* DESCRIPTION:
* An abstraction layer for multiple OpenGL versions (1.1, 2.1, 3.3 Core, 4.3 Core, ES 2.0)
* An abstraction layer for multiple OpenGL versions (1.1, 2.1, 3.3 Core, 4.3 Core, ES 2.0, ES 3.0)
* that provides a pseudo-OpenGL 1.1 immediate-mode style API (rlVertex, rlTranslate, rlRotate...)
*
* ADDITIONAL NOTES:
* When choosing an OpenGL backend different than OpenGL 1.1, some internal buffer are
* initialized on rlglInit() to accumulate vertex data
*
* When an internal state change is required all the stored vertex data is renderer in batch,
* When an internal state change is required all the stored vertex data is rendered in batch,
* additionally, rlDrawRenderBatchActive() could be called to force flushing of the batch
*
* Some resources are also loaded for convenience, here the complete list:
@ -56,8 +56,8 @@
*
* #define RL_MAX_MATRIX_STACK_SIZE 32 // Maximum size of internal Matrix stack
* #define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported
* #define RL_CULL_DISTANCE_NEAR 0.01 // Default projection matrix near cull distance
* #define RL_CULL_DISTANCE_FAR 1000.0 // Default projection matrix far cull distance
* #define RL_CULL_DISTANCE_NEAR 0.05 // Default projection matrix near cull distance
* #define RL_CULL_DISTANCE_FAR 4000.0 // Default projection matrix far cull distance
*
* When loading a shader, the following vertex attributes and uniform
* location names are tried to be set automatically:
@ -88,7 +88,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2024 Ramon Santamaria (@raysan5)
* Copyright (c) 2014-2025 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.
@ -234,10 +234,10 @@
// Projection matrix culling
#ifndef RL_CULL_DISTANCE_NEAR
#define RL_CULL_DISTANCE_NEAR 0.01 // Default near cull distance
#define RL_CULL_DISTANCE_NEAR 0.05 // Default near cull distance
#endif
#ifndef RL_CULL_DISTANCE_FAR
#define RL_CULL_DISTANCE_FAR 1000.0 // Default far cull distance
#define RL_CULL_DISTANCE_FAR 4000.0 // Default far cull distance
#endif
// Texture parameters (equivalent to OpenGL defines)
@ -355,6 +355,9 @@
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8
#endif
#endif
#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX 9
#endif
//----------------------------------------------------------------------------------
// Types and Structures Definition
@ -681,9 +684,10 @@ RLAPI void rlSetCullFace(int mode); // Set face culling mode
RLAPI void rlEnableScissorTest(void); // Enable scissor test
RLAPI void rlDisableScissorTest(void); // Disable scissor test
RLAPI void rlScissor(int x, int y, int width, int height); // Scissor test
RLAPI void rlEnableWireMode(void); // Enable wire mode
RLAPI void rlEnablePointMode(void); // Enable point mode
RLAPI void rlDisableWireMode(void); // Disable wire (and point) mode
RLAPI void rlDisablePointMode(void); // Disable point mode
RLAPI void rlEnableWireMode(void); // Enable wire mode
RLAPI void rlDisableWireMode(void); // Disable wire mode
RLAPI void rlSetLineWidth(float width); // Set the line drawing width
RLAPI float rlGetLineWidth(void); // Get the line drawing width
RLAPI void rlEnableSmoothLines(void); // Enable line aliasing
@ -998,6 +1002,9 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS
#define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS
#endif
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX
#define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX "instanceTransform" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX
#endif
#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_MVP
#define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix
@ -1741,7 +1748,6 @@ void rlTextureParameters(unsigned int id, int param, int value)
#endif
}
else glTexParameteri(GL_TEXTURE_2D, param, value);
} break;
case RL_TEXTURE_MAG_FILTER:
case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_2D, param, value); break;
@ -1786,7 +1792,6 @@ void rlCubemapParameters(unsigned int id, int param, int value)
else TRACELOG(RL_LOG_WARNING, "GL: Clamp mirror wrap mode not supported (GL_MIRROR_CLAMP_EXT)");
}
else glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value);
} break;
case RL_TEXTURE_MAG_FILTER:
case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value); break;
@ -1884,16 +1889,6 @@ void rlActiveDrawBuffers(int count)
else
{
unsigned int buffers[8] = {
#if defined(GRAPHICS_API_OPENGL_ES3)
GL_COLOR_ATTACHMENT0_EXT,
GL_COLOR_ATTACHMENT1_EXT,
GL_COLOR_ATTACHMENT2_EXT,
GL_COLOR_ATTACHMENT3_EXT,
GL_COLOR_ATTACHMENT4_EXT,
GL_COLOR_ATTACHMENT5_EXT,
GL_COLOR_ATTACHMENT6_EXT,
GL_COLOR_ATTACHMENT7_EXT,
#else
GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2,
@ -1902,14 +1897,9 @@ void rlActiveDrawBuffers(int count)
GL_COLOR_ATTACHMENT5,
GL_COLOR_ATTACHMENT6,
GL_COLOR_ATTACHMENT7,
#endif
};
#if defined(GRAPHICS_API_OPENGL_ES3)
glDrawBuffersEXT(count, buffers);
#else
glDrawBuffers(count, buffers);
#endif
}
}
else TRACELOG(LOG_WARNING, "GL: One color buffer active by default");
@ -1976,6 +1966,15 @@ void rlEnableWireMode(void)
#endif
}
// Disable wire mode
void rlDisableWireMode(void)
{
#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
// NOTE: glPolygonMode() not available on OpenGL ES
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif
}
// Enable point mode
void rlEnablePointMode(void)
{
@ -1986,8 +1985,8 @@ void rlEnablePointMode(void)
#endif
}
// Disable wire mode
void rlDisableWireMode(void)
// Disable point mode
void rlDisablePointMode(void)
{
#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
// NOTE: glPolygonMode() not available on OpenGL ES
@ -2111,14 +2110,12 @@ void rlSetBlendMode(int mode)
{
// NOTE: Using GL blend src/dst factors and GL equation configured with rlSetBlendFactors()
glBlendFunc(RLGL.State.glBlendSrcFactor, RLGL.State.glBlendDstFactor); glBlendEquation(RLGL.State.glBlendEquation);
} break;
case RL_BLEND_CUSTOM_SEPARATE:
{
// NOTE: Using GL blend src/dst factors and GL equation configured with rlSetBlendFactorsSeparate()
glBlendFuncSeparate(RLGL.State.glBlendSrcFactorRGB, RLGL.State.glBlendDestFactorRGB, RLGL.State.glBlendSrcFactorAlpha, RLGL.State.glBlendDestFactorAlpha);
glBlendEquationSeparate(RLGL.State.glBlendEquationRGB, RLGL.State.glBlendEquationAlpha);
} break;
default: break;
}
@ -2428,7 +2425,7 @@ void rlLoadExtensions(void *loader)
// Get supported extensions list
GLint numExt = 0;
const char **extList = RL_MALLOC(512*sizeof(const char *)); // Allocate 512 strings pointers (2 KB)
const char **extList = (const char **)RL_MALLOC(512*sizeof(const char *)); // Allocate 512 strings pointers (2 KB)
const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string
// NOTE: We have to duplicate string because glGetString() returns a const string
@ -2525,11 +2522,11 @@ void rlLoadExtensions(void *loader)
// Check depth texture support
if (strcmp(extList[i], (const char *)"GL_OES_depth_texture") == 0) RLGL.ExtSupported.texDepth = true;
if (strcmp(extList[i], (const char *)"GL_WEBGL_depth_texture") == 0) RLGL.ExtSupported.texDepthWebGL = true; // WebGL requires unsized internal format
if (strcmp(extList[i], (const char *)"GL_WEBGL_depth_texture") == 0) RLGL.ExtSupported.texDepthWebGL = true; // WebGL requires unsized internal format
if (RLGL.ExtSupported.texDepthWebGL) RLGL.ExtSupported.texDepth = true;
if (strcmp(extList[i], (const char *)"GL_OES_depth24") == 0) RLGL.ExtSupported.maxDepthBits = 24; // Not available on WebGL
if (strcmp(extList[i], (const char *)"GL_OES_depth32") == 0) RLGL.ExtSupported.maxDepthBits = 32; // Not available on WebGL
if (strcmp(extList[i], (const char *)"GL_OES_depth24") == 0) RLGL.ExtSupported.maxDepthBits = 24; // Not available on WebGL
if (strcmp(extList[i], (const char *)"GL_OES_depth32") == 0) RLGL.ExtSupported.maxDepthBits = 32; // Not available on WebGL
// Check texture compression support: DXT
if ((strcmp(extList[i], (const char *)"GL_EXT_texture_compression_s3tc") == 0) ||
@ -3054,7 +3051,7 @@ void rlDrawRenderBatch(rlRenderBatch *batch)
for (int i = 0, vertexOffset = 0; i < batch->drawCounter; i++)
{
// Bind current draw call texture, activated as GL_TEXTURE0 and Bound to sampler2D texture0 by default
// Bind current draw call texture, activated as GL_TEXTURE0 and bound to sampler2D texture0 by default
glBindTexture(GL_TEXTURE_2D, batch->draws[i].textureId);
if ((batch->draws[i].mode == RL_LINES) || (batch->draws[i].mode == RL_TRIANGLES)) glDrawArrays(batch->draws[i].mode, vertexOffset, batch->draws[i].vertexCount);
@ -3310,6 +3307,7 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format,
// Activate Trilinear filtering if mipmaps are available
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmapCount); // Required for user-defined mip count
}
#endif
@ -3674,29 +3672,37 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format)
// Read screen pixel data (color buffer)
unsigned char *rlReadScreenPixels(int width, int height)
{
unsigned char *screenData = (unsigned char *)RL_CALLOC(width*height*4, sizeof(unsigned char));
unsigned char *imgData = (unsigned char *)RL_CALLOC(width*height*4, sizeof(unsigned char));
// NOTE 1: glReadPixels returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer
// NOTE 2: We are getting alpha channel! Be careful, it can be transparent if not cleared properly!
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, screenData);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, imgData);
// Flip image vertically!
unsigned char *imgData = (unsigned char *)RL_MALLOC(width*height*4*sizeof(unsigned char));
for (int y = height - 1; y >= 0; y--)
// NOTE: Alpha value has already been applied to RGB in framebuffer, we don't need it!
for (int y = height - 1; y >= height/2; y--)
{
for (int x = 0; x < (width*4); x++)
for (int x = 0; x < (width*4); x += 4)
{
imgData[((height - 1) - y)*width*4 + x] = screenData[(y*width*4) + x]; // Flip line
unsigned int s = ((height - 1) - y)*width*4 + x;
unsigned int e = y*width*4 + x;
// Set alpha component value to 255 (no trasparent image retrieval)
// NOTE: Alpha value has already been applied to RGB in framebuffer, we don't need it!
if (((x + 1)%4) == 0) imgData[((height - 1) - y)*width*4 + x] = 255;
unsigned char r = imgData[s];
unsigned char g = imgData[s+1];
unsigned char b = imgData[s+2];
imgData[s] = imgData[e];
imgData[s+1] = imgData[e+1];
imgData[s+2] = imgData[e+2];
imgData[s+3] = 255; // Set alpha component value to 255 (no trasparent image retrieval)
imgData[e] = r;
imgData[e+1] = g;
imgData[e+2] = b;
imgData[e+3] = 255; // Ditto
}
}
RL_FREE(screenData);
return imgData; // NOTE: image data should be freed
}
@ -3737,19 +3743,16 @@ void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType,
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_2D, texId, mipLevel);
else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_RENDERBUFFER, texId);
else if (texType >= RL_ATTACHMENT_CUBEMAP_POSITIVE_X) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_CUBE_MAP_POSITIVE_X + texType, texId, mipLevel);
} break;
case RL_ATTACHMENT_DEPTH:
{
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texId, mipLevel);
else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, texId);
} break;
case RL_ATTACHMENT_STENCIL:
{
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texId, mipLevel);
else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, texId);
} break;
default: break;
}
@ -3959,7 +3962,7 @@ void rlDrawVertexArrayElements(int offset, int count, const void *buffer)
void rlDrawVertexArrayInstanced(int offset, int count, int instances)
{
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glDrawArraysInstanced(GL_TRIANGLES, 0, count, instances);
glDrawArraysInstanced(GL_TRIANGLES, offset, count, instances);
#endif
}
@ -4216,6 +4219,7 @@ unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId)
glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR);
glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT);
glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2);
glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX, RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX);
#ifdef RL_SUPPORT_MESH_GPU_SKINNING
glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS);

File diff suppressed because it is too large Load diff

View file

@ -25,7 +25,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5)
* Copyright (c) 2013-2025 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.
@ -285,6 +285,7 @@ void DrawCircleV(Vector2 center, float radius, Color color)
// Draw a piece of a circle
void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color)
{
if (startAngle == endAngle) return;
if (radius <= 0.0f) radius = 0.1f; // Avoid div by zero
// Function expects (endAngle > startAngle)
@ -376,6 +377,7 @@ void DrawCircleSector(Vector2 center, float radius, float startAngle, float endA
// Draw a piece of a circle outlines
void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color)
{
if (startAngle == endAngle) return;
if (radius <= 0.0f) radius = 0.1f; // Avoid div by zero issue
// Function expects (endAngle > startAngle)
@ -468,27 +470,39 @@ void DrawCircleLinesV(Vector2 center, float radius, Color color)
// Draw ellipse
void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color)
{
DrawEllipseV((Vector2){ (float)centerX, (float)centerY }, radiusH, radiusV, color);
}
// Draw ellipse (Vector version)
void DrawEllipseV(Vector2 center, float radiusH, float radiusV, Color color)
{
rlBegin(RL_TRIANGLES);
for (int i = 0; i < 360; i += 10)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f((float)centerX, (float)centerY);
rlVertex2f((float)centerX + cosf(DEG2RAD*(i + 10))*radiusH, (float)centerY + sinf(DEG2RAD*(i + 10))*radiusV);
rlVertex2f((float)centerX + cosf(DEG2RAD*i)*radiusH, (float)centerY + sinf(DEG2RAD*i)*radiusV);
rlVertex2f(center.x, center.y);
rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radiusH, center.y + sinf(DEG2RAD*(i + 10))*radiusV);
rlVertex2f(center.x + cosf(DEG2RAD*i)*radiusH, center.y + sinf(DEG2RAD*i)*radiusV);
}
rlEnd();
}
// Draw ellipse outline
void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color)
{
DrawEllipseLinesV((Vector2){ (float)centerX, (float)centerY }, radiusH, radiusV, color);
}
// Draw ellipse outline
void DrawEllipseLinesV(Vector2 center, float radiusH, float radiusV, Color color)
{
rlBegin(RL_LINES);
for (int i = 0; i < 360; i += 10)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(centerX + cosf(DEG2RAD*(i + 10))*radiusH, centerY + sinf(DEG2RAD*(i + 10))*radiusV);
rlVertex2f(centerX + cosf(DEG2RAD*i)*radiusH, centerY + sinf(DEG2RAD*i)*radiusV);
rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radiusH, center.y + sinf(DEG2RAD*(i + 10))*radiusV);
rlVertex2f(center.x + cosf(DEG2RAD*i)*radiusH, center.y + sinf(DEG2RAD*i)*radiusV);
}
rlEnd();
}
@ -772,7 +786,7 @@ void DrawRectangleGradientH(int posX, int posY, int width, int height, Color lef
}
// Draw a gradient-filled rectangle
void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color topRight, Color bottomRight)
void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color bottomRight, Color topRight)
{
rlSetTexture(GetShapesTexture().id);
Rectangle shapeRect = GetShapesTextureRectangle();
@ -789,11 +803,11 @@ void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Col
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
rlVertex2f(rec.x, rec.y + rec.height);
rlColor4ub(topRight.r, topRight.g, topRight.b, topRight.a);
rlColor4ub(bottomRight.r, bottomRight.g, bottomRight.b, bottomRight.a);
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
rlVertex2f(rec.x + rec.width, rec.y + rec.height);
rlColor4ub(bottomRight.r, bottomRight.g, bottomRight.b, bottomRight.a);
rlColor4ub(topRight.r, topRight.g, topRight.b, topRight.a);
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(rec.x + rec.width, rec.y);
rlEnd();
@ -807,22 +821,25 @@ void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Col
// but it solves another issue: https://github.com/raysan5/raylib/issues/3884
void DrawRectangleLines(int posX, int posY, int width, int height, Color color)
{
Matrix mat = rlGetMatrixModelview();
float zoomFactor = 0.5f/mat.m0;
Matrix mat = rlGetMatrixTransform();
float xOffset = 0.5f/mat.m0;
float yOffset = 0.5f/mat.m5;
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f((float)posX - zoomFactor, (float)posY);
rlVertex2f((float)posX + (float)width + zoomFactor, (float)posY);
rlVertex2f((float)posX + xOffset, (float)posY + yOffset);
rlVertex2f((float)posX + (float)width - xOffset, (float)posY + yOffset);
rlVertex2f((float)posX + (float)width, (float)posY - zoomFactor);
rlVertex2f((float)posX + (float)width, (float)posY + (float)height + zoomFactor);
rlVertex2f((float)posX + (float)width - xOffset, (float)posY + yOffset);
rlVertex2f((float)posX + (float)width - xOffset, (float)posY + (float)height - yOffset);
rlVertex2f((float)posX + (float)width + zoomFactor, (float)posY + (float)height);
rlVertex2f((float)posX - zoomFactor, (float)posY + (float)height);
rlVertex2f((float)posX + (float)width - xOffset, (float)posY + (float)height - yOffset);
rlVertex2f((float)posX + xOffset, (float)posY + (float)height - yOffset);
rlVertex2f((float)posX, (float)posY + (float)height + zoomFactor);
rlVertex2f((float)posX, (float)posY - zoomFactor);
rlVertex2f((float)posX + xOffset, (float)posY + (float)height - yOffset);
rlVertex2f((float)posX + xOffset, (float)posY + yOffset);
rlEnd();
/*
// Previous implementation, it has issues... but it does not require view matrix...
#if defined(SUPPORT_QUADS_DRAW_MODE)
@ -845,7 +862,7 @@ void DrawRectangleLines(int posX, int posY, int width, int height, Color color)
rlVertex2f((float)posX + 1, (float)posY + (float)height);
rlVertex2f((float)posX + 1, (float)posY + 1);
rlEnd();
//#endif
#endif
*/
}
@ -884,7 +901,7 @@ void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color)
void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color)
{
// Not a rounded rectangle
if ((roundness <= 0.0f) || (rec.width < 1) || (rec.height < 1 ))
if (roundness <= 0.0f)
{
DrawRectangleRec(rec, color);
return;
@ -1160,18 +1177,29 @@ void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, f
P5 ================== P4
*/
const Vector2 point[16] = {
{(float)rec.x + innerRadius, rec.y - lineThick}, {(float)(rec.x + rec.width) - innerRadius, rec.y - lineThick}, { rec.x + rec.width + lineThick, (float)rec.y + innerRadius }, // PO, P1, P2
{rec.x + rec.width + lineThick, (float)(rec.y + rec.height) - innerRadius}, {(float)(rec.x + rec.width) - innerRadius, rec.y + rec.height + lineThick}, // P3, P4
{(float)rec.x + innerRadius, rec.y + rec.height + lineThick}, { rec.x - lineThick, (float)(rec.y + rec.height) - innerRadius}, {rec.x - lineThick, (float)rec.y + innerRadius}, // P5, P6, P7
{(float)rec.x + innerRadius, rec.y}, {(float)(rec.x + rec.width) - innerRadius, rec.y}, // P8, P9
{ rec.x + rec.width, (float)rec.y + innerRadius }, {rec.x + rec.width, (float)(rec.y + rec.height) - innerRadius}, // P10, P11
{(float)(rec.x + rec.width) - innerRadius, rec.y + rec.height}, {(float)rec.x + innerRadius, rec.y + rec.height}, // P12, P13
{ rec.x, (float)(rec.y + rec.height) - innerRadius}, {rec.x, (float)rec.y + innerRadius} // P14, P15
{(float)rec.x + innerRadius + 0.5f, rec.y - lineThick + 0.5f},
{(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y - lineThick + 0.5f},
{rec.x + rec.width + lineThick - 0.5f, (float)rec.y + innerRadius + 0.5f}, // PO, P1, P2
{rec.x + rec.width + lineThick - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f},
{(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + rec.height + lineThick - 0.5f}, // P3, P4
{(float)rec.x + innerRadius + 0.5f, rec.y + rec.height + lineThick - 0.5f},
{rec.x - lineThick + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f},
{rec.x - lineThick + 0.5f, (float)rec.y + innerRadius + 0.5f}, // P5, P6, P7
{(float)rec.x + innerRadius + 0.5f, rec.y + 0.5f},
{(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + 0.5f}, // P8, P9
{rec.x + rec.width - 0.5f, (float)rec.y + innerRadius + 0.5f},
{rec.x + rec.width - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, // P10, P11
{(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + rec.height - 0.5f},
{(float)rec.x + innerRadius + 0.5f, rec.y + rec.height - 0.5f}, // P12, P13
{rec.x + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f},
{rec.x + 0.5f, (float)rec.y + innerRadius + 0.5f} // P14, P15
};
const Vector2 centers[4] = {
{(float)rec.x + innerRadius, (float)rec.y + innerRadius}, {(float)(rec.x + rec.width) - innerRadius, (float)rec.y + innerRadius}, // P16, P17
{(float)(rec.x + rec.width) - innerRadius, (float)(rec.y + rec.height) - innerRadius}, {(float)rec.x + innerRadius, (float)(rec.y + rec.height) - innerRadius} // P18, P19
{(float)rec.x + innerRadius + 0.5f, (float)rec.y + innerRadius + 0.5f},
{(float)(rec.x + rec.width) - innerRadius - 0.5f, (float)rec.y + innerRadius + 0.5f}, // P16, P17
{(float)(rec.x + rec.width) - innerRadius - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f},
{(float)rec.x + innerRadius + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f} // P18, P19
};
const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f };
@ -2223,7 +2251,7 @@ bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2
// NOTE: Based on http://jeffreythompson.org/collision-detection/poly-point.php
bool CheckCollisionPointPoly(Vector2 point, const Vector2 *points, int pointCount)
{
bool inside = false;
bool collision = false;
if (pointCount > 2)
{
@ -2232,12 +2260,12 @@ bool CheckCollisionPointPoly(Vector2 point, const Vector2 *points, int pointCoun
if ((points[i].y > point.y) != (points[j].y > point.y) &&
(point.x < (points[j].x - points[i].x)*(point.y - points[i].y)/(points[j].y - points[i].y) + points[i].x))
{
inside = !inside;
collision = !collision;
}
}
}
return inside;
return collision;
}
// Check collision between two rectangles
@ -2342,7 +2370,7 @@ bool CheckCollisionPointLine(Vector2 point, Vector2 p1, Vector2 p2, int threshol
return collision;
}
// Check if circle collides with a line created betweeen two points [p1] and [p2]
// Check if circle collides with a line created between two points [p1] and [p2]
RLAPI bool CheckCollisionCircleLine(Vector2 center, float radius, Vector2 p1, Vector2 p2)
{
float dx = p1.x - p2.x;

View file

@ -34,7 +34,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5)
* Copyright (c) 2013-2025 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.
@ -161,6 +161,10 @@ extern void LoadFontDefault(void)
{
#define BIT_CHECK(a,b) ((a) & (1u << (b)))
// check to see if we have allready allocated the font for an image, and if we don't need to upload, then just return
if (defaultFont.glyphs != NULL && !isGpuReady)
return;
// NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement
// Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl
@ -247,13 +251,28 @@ extern void LoadFontDefault(void)
// we must consider data as little-endian order (alpha + gray)
((unsigned short *)imFont.data)[i + j] = 0xffff;
}
else ((unsigned short *)imFont.data)[i + j] = 0x00ff;
else
{
((unsigned char *)imFont.data)[(i + j)*sizeof(short)] = 0xff;
((unsigned char *)imFont.data)[(i + j)*sizeof(short) + 1] = 0x00;
}
}
counter++;
}
if (isGpuReady) defaultFont.texture = LoadTextureFromImage(imFont);
if (isGpuReady)
{
defaultFont.texture = LoadTextureFromImage(imFont);
// we have already loaded the font glyph data an image, and the GPU is ready, we are done
// if we don't do this, we will leak memory by reallocating the glyphs and rects
if (defaultFont.glyphs != NULL)
{
UnloadImage(imFont);
return;
}
}
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount
//------------------------------------------------------------------------------
@ -278,7 +297,7 @@ extern void LoadFontDefault(void)
testPosX += (int)(defaultFont.recs[i].width + (float)charsDivisor);
if (testPosX >= defaultFont.texture.width)
if (testPosX >= imFont.width)
{
currentLine++;
currentPosX = 2*charsDivisor + charsWidth[i];
@ -312,6 +331,9 @@ extern void UnloadFontDefault(void)
if (isGpuReady) UnloadTexture(defaultFont.texture);
RL_FREE(defaultFont.glyphs);
RL_FREE(defaultFont.recs);
defaultFont.glyphCount = 0;
defaultFont.glyphs = NULL;
defaultFont.recs = NULL;
}
#endif // SUPPORT_DEFAULT_FONT
@ -985,7 +1007,7 @@ bool ExportFontAsCode(Font font, const char *fileName)
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) 2018-2024 Ramon Santamaria (@raysan5) //\n");
byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2025 Ramon Santamaria (@raysan5) //\n");
byteCount += sprintf(txtData + byteCount, "// //\n");
byteCount += sprintf(txtData + byteCount, "// ---------------------------------------------------------------------------------- //\n");
byteCount += sprintf(txtData + byteCount, "// //\n");
@ -1071,7 +1093,7 @@ bool ExportFontAsCode(Font font, const char *fileName)
byteCount += sprintf(txtData + byteCount, " Image imFont = { fontImageData_%s, %i, %i, 1, %i };\n\n", styleName, image.width, image.height, image.format);
#endif
byteCount += sprintf(txtData + byteCount, " // Load texture from image\n");
byteCount += sprintf(txtData + byteCount, " if (isGpuReady) font.texture = LoadTextureFromImage(imFont);\n");
byteCount += sprintf(txtData + byteCount, " font.texture = LoadTextureFromImage(imFont);\n");
#if defined(SUPPORT_COMPRESSED_FONT_ATLAS)
byteCount += sprintf(txtData + byteCount, " UnloadImage(imFont); // Uncompressed data can be unloaded from memory\n\n");
#endif
@ -1339,6 +1361,7 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
int GetGlyphIndex(Font font, int codepoint)
{
int index = 0;
if (!IsFontValid(font)) return index;
#define SUPPORT_UNORDERED_CHARSET
#if defined(SUPPORT_UNORDERED_CHARSET)
@ -1535,27 +1558,27 @@ const char *TextSubtext(const char *text, int position, int length)
if (position >= textLength)
{
position = textLength - 1;
length = 0;
return buffer; //First char is already '\0' by memset
}
if (length >= textLength) length = textLength;
int maxLength = textLength - position;
if (length > maxLength) length = maxLength;
if (length >= MAX_TEXT_BUFFER_LENGTH) length = MAX_TEXT_BUFFER_LENGTH - 1;
// NOTE: Alternative: memcpy(buffer, text + position, length)
for (int c = 0 ; c < length ; c++)
{
*(buffer + c) = *(text + position);
text++;
buffer[c] = text[position + c];
}
*(buffer + length) = '\0';
buffer[length] = '\0';
return buffer;
}
// Replace text string
// REQUIRES: strlen(), strstr(), strncpy(), strcpy()
// REQUIRES: strstr(), strncpy(), strcpy()
// WARNING: Allocated memory must be manually freed
char *TextReplace(const char *text, const char *replace, const char *by)
{
@ -1624,7 +1647,7 @@ char *TextInsert(const char *text, const char *insert, int position)
// Join text strings with delimiter
// REQUIRES: memset(), memcpy()
const char *TextJoin(const char **textList, int count, const char *delimiter)
char *TextJoin(char **textList, int count, const char *delimiter)
{
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
@ -1658,7 +1681,7 @@ const char *TextJoin(const char **textList, int count, const char *delimiter)
// Split string into multiple strings
// REQUIRES: memset()
const char **TextSplit(const char *text, char delimiter, int *count)
char **TextSplit(const char *text, char delimiter, int *count)
{
// NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
// inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
@ -1666,7 +1689,7 @@ const char **TextSplit(const char *text, char delimiter, int *count)
// 1. Maximum number of possible split strings is set by MAX_TEXTSPLIT_COUNT
// 2. Maximum size of text to split is MAX_TEXT_BUFFER_LENGTH
static const char *result[MAX_TEXTSPLIT_COUNT] = { NULL };
static char *result[MAX_TEXTSPLIT_COUNT] = { NULL };
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
@ -1722,7 +1745,7 @@ int TextFindIndex(const char *text, const char *find)
// Get upper case version of provided string
// WARNING: Limited functionality, only basic characters set
// TODO: Support UTF-8 diacritics to upper-case, check codepoints
const char *TextToUpper(const char *text)
char *TextToUpper(const char *text)
{
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
@ -1741,7 +1764,7 @@ const char *TextToUpper(const char *text)
// Get lower case version of provided string
// WARNING: Limited functionality, only basic characters set
const char *TextToLower(const char *text)
char *TextToLower(const char *text)
{
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
@ -1760,7 +1783,7 @@ const char *TextToLower(const char *text)
// Get Pascal case notation version of provided string
// WARNING: Limited functionality, only basic characters set
const char *TextToPascal(const char *text)
char *TextToPascal(const char *text)
{
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
@ -1788,7 +1811,7 @@ const char *TextToPascal(const char *text)
// Get snake case notation version of provided string
// WARNING: Limited functionality, only basic characters set
const char *TextToSnake(const char *text)
char *TextToSnake(const char *text)
{
static char buffer[MAX_TEXT_BUFFER_LENGTH] = {0};
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
@ -1816,7 +1839,7 @@ const char *TextToSnake(const char *text)
// Get Camel case notation version of provided string
// WARNING: Limited functionality, only basic characters set
const char *TextToCamel(const char *text)
char *TextToCamel(const char *text)
{
static char buffer[MAX_TEXT_BUFFER_LENGTH] = {0};
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
@ -1910,7 +1933,7 @@ void UnloadCodepoints(int *codepoints)
int GetCodepointCount(const char *text)
{
unsigned int length = 0;
char *ptr = (char *)&text[0];
const char *ptr = text;
while (*ptr != '\0')
{
@ -2324,9 +2347,9 @@ static Font LoadBMFont(const char *fileName)
// Convert hexadecimal to decimal (single digit)
static unsigned char HexToInt(char hex)
{
if (hex >= '0' && hex <= '9') return hex - '0';
else if (hex >= 'a' && hex <= 'f') return hex - 'a' + 10;
else if (hex >= 'A' && hex <= 'F') return hex - 'A' + 10;
if ((hex >= '0') && (hex <= '9')) return hex - '0';
else if ((hex >= 'a') && (hex <= 'f')) return hex - 'a' + 10;
else if ((hex >= 'A') && (hex <= 'F')) return hex - 'A' + 10;
else return 0;
}

View file

@ -42,7 +42,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5)
* Copyright (c) 2013-2025 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.
@ -124,10 +124,6 @@
#endif
// Image fileformats not supported by default
#if defined(__TINYC__)
#define STBI_NO_SIMD
#endif
#if (defined(SUPPORT_FILEFORMAT_BMP) || \
defined(SUPPORT_FILEFORMAT_PNG) || \
defined(SUPPORT_FILEFORMAT_TGA) || \
@ -149,6 +145,10 @@
#define STBI_NO_THREAD_LOCALS
#if defined(__TINYC__)
#define STBI_NO_SIMD
#endif
#define STB_IMAGE_IMPLEMENTATION
#include "external/stb_image.h" // Required for: stbi_load_from_file()
// NOTE: Used to read image data (multiple formats support)
@ -218,6 +218,9 @@
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
#if defined(__TINYC__)
#define STBIR_NO_SIMD
#endif
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "external/stb_image_resize2.h" // Required for: stbir_resize_uint8_linear() [ImageResize()]
@ -761,7 +764,7 @@ bool ExportImageAsCode(Image image, const char *fileName)
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) 2018-2024 Ramon Santamaria (@raysan5) //\n");
byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2025 Ramon Santamaria (@raysan5) //\n");
byteCount += sprintf(txtData + byteCount, "// //\n");
byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
@ -829,25 +832,23 @@ Image GenImageGradientLinear(int width, int height, int direction, Color start,
// Calculate how far the top-left pixel is along the gradient direction from the center of said gradient
float startingPos = 0.5f - (cosDir*width/2) - (sinDir*height/2);
// With directions that lie in the first or third quadrant (i.e. from top-left to
// bottom-right or vice-versa), pixel (0, 0) is the farthest point on the gradient
// (i.e. the pixel which should become one of the gradient's ends color); while for
// directions that lie in the second or fourth quadrant, that point is pixel (width, 0).
float maxPosValue =
((signbit(sinDir) != 0) == (signbit(cosDir) != 0))
? fabsf(startingPos)
: fabsf(startingPos+width*cosDir);
// directions that lie in the second or fourth quadrant, that point is pixel (width, 0)
float maxPosValue = ((signbit(sinDir) != 0) == (signbit(cosDir) != 0))? fabsf(startingPos) : fabsf(startingPos + width*cosDir);
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
// Calculate the relative position of the pixel along the gradient direction
float pos = (startingPos + (i*cosDir + j*sinDir)) / maxPosValue;
float pos = (startingPos + (i*cosDir + j*sinDir))/maxPosValue;
float factor = pos;
factor = (factor > 1.0f)? 1.0f : factor; // Clamp to [-1,1]
factor = (factor < -1.0f)? -1.0f : factor; // Clamp to [-1,1]
factor = factor / 2 + 0.5f;
factor = factor/2.0f + 0.5f;
// Generate the color for this pixel
pixels[j*width + i].r = (int)((float)end.r*factor + (float)start.r*(1.0f - factor));
@ -1007,7 +1008,8 @@ Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float
{
Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
float aspectRatio = (float)width / (float)height;
float aspectRatio = (float)width/(float)height;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
@ -2100,8 +2102,8 @@ void ImageBlurGaussian(Image *image, int blurSize)
Color *pixels = LoadImageColors(*image);
// Loop switches between pixelsCopy1 and pixelsCopy2
Vector4 *pixelsCopy1 = RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
Vector4 *pixelsCopy2 = RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
Vector4 *pixelsCopy1 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
Vector4 *pixelsCopy2 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
for (int i = 0; i < (image->height*image->width); i++)
{
@ -2249,8 +2251,8 @@ void ImageKernelConvolution(Image *image, const float *kernel, int kernelSize)
Color *pixels = LoadImageColors(*image);
Vector4 *imageCopy2 = RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
Vector4 *temp = RL_MALLOC(kernelSize*sizeof(Vector4));
Vector4 *imageCopy2 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
Vector4 *temp = (Vector4 *)RL_MALLOC(kernelSize*sizeof(Vector4));
for (int i = 0; i < kernelSize; i++)
{
@ -3567,7 +3569,7 @@ void ImageDrawLineEx(Image *dst, Vector2 start, Vector2 end, int thick, Color co
ImageDrawLine(dst, x1, y1, x2, y2, color);
// Determine if the line is more horizontal or vertical
if (dx != 0 && abs(dy/dx) < 1)
if ((dx != 0) && (abs(dy/dx) < 1))
{
// Line is more horizontal
// Calculate half the width of the line
@ -3834,7 +3836,7 @@ void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c
// Calculate the inverse of the sum of the barycentric coordinates for normalization
// NOTE 1: Here, we act as if we multiply by 255 the reciprocal, which avoids additional
// calculations in the loop. This is acceptable because we are only interpolating colors.
// calculations in the loop. This is acceptable because we are only interpolating colors
// NOTE 2: This sum remains constant throughout the triangle
float wInvSum = 255.0f/(w1Row + w2Row + w3Row);
@ -3889,7 +3891,7 @@ void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Colo
}
// Draw a triangle fan defined by points within an image (first vertex is the center)
void ImageDrawTriangleFan(Image *dst, Vector2 *points, int pointCount, Color color)
void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color)
{
if (pointCount >= 3)
{
@ -3901,7 +3903,7 @@ void ImageDrawTriangleFan(Image *dst, Vector2 *points, int pointCount, Color col
}
// Draw a triangle strip defined by points within an image
void ImageDrawTriangleStrip(Image *dst, Vector2 *points, int pointCount, Color color)
void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color)
{
if (pointCount >= 3)
{
@ -4206,8 +4208,13 @@ TextureCubemap LoadTextureCubemap(Image image, int layout)
ImageFormat(&faces, image.format);
Image mipmapped = ImageCopy(image);
ImageMipmaps(&mipmapped);
ImageMipmaps(&faces);
#if defined(SUPPORT_IMAGE_MANIPULATION)
if (image.mipmaps > 1)
{
ImageMipmaps(&mipmapped);
ImageMipmaps(&faces);
}
#endif
// NOTE: Image formatting does not work with compressed textures
@ -4223,7 +4230,7 @@ TextureCubemap LoadTextureCubemap(Image image, int layout)
if (cubemap.id != 0)
{
cubemap.format = faces.format;
cubemap.mipmaps = 1;
cubemap.mipmaps = faces.mipmaps;
}
else TRACELOG(LOG_WARNING, "IMAGE: Failed to load cubemap image");
@ -5141,10 +5148,10 @@ Color GetColor(unsigned int hexValue)
{
Color color;
color.r = (unsigned char)(hexValue >> 24) & 0xFF;
color.g = (unsigned char)(hexValue >> 16) & 0xFF;
color.b = (unsigned char)(hexValue >> 8) & 0xFF;
color.a = (unsigned char)hexValue & 0xFF;
color.r = (unsigned char)(hexValue >> 24) & 0xff;
color.g = (unsigned char)(hexValue >> 16) & 0xff;
color.b = (unsigned char)(hexValue >> 8) & 0xff;
color.a = (unsigned char)hexValue & 0xff;
return color;
}
@ -5384,13 +5391,18 @@ static float HalfToFloat(unsigned short x)
{
float result = 0.0f;
const unsigned int e = (x & 0x7C00) >> 10; // Exponent
const unsigned int m = (x & 0x03FF) << 13; // Mantissa
const float fm = (float)m;
const unsigned int v = (*(unsigned int*)&fm) >> 23; // Evil log2 bit hack to count leading zeros in denormalized format
const unsigned int r = (x & 0x8000) << 16 | (e != 0)*((e + 112) << 23 | m) | ((e == 0)&(m != 0))*((v - 37) << 23 | ((m << (150 - v)) & 0x007FE000)); // sign : normalized : denormalized
union {
float fm;
unsigned int ui;
} uni;
result = *(float *)&r;
const unsigned int e = (x & 0x7c00) >> 10; // Exponent
const unsigned int m = (x & 0x03cc) << 13; // Mantissa
uni.fm = (float)m;
const unsigned int v = uni.ui >> 23; // Evil log2 bit hack to count leading zeros in denormalized format
uni.ui = (x & 0x8000) << 16 | (e != 0)*((e + 112) << 23 | m) | ((e == 0)&(m != 0))*((v - 37) << 23 | ((m << (150 - v)) & 0x007fe000)); // sign : normalized : denormalized
result = uni.fm;
return result;
}
@ -5400,11 +5412,17 @@ static unsigned short FloatToHalf(float x)
{
unsigned short result = 0;
const unsigned int b = (*(unsigned int*) & x) + 0x00001000; // Round-to-nearest-even: add last bit after truncated mantissa
const unsigned int e = (b & 0x7F800000) >> 23; // Exponent
const unsigned int m = b & 0x007FFFFF; // Mantissa; in line below: 0x007FF000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding
union {
float fm;
unsigned int ui;
} uni;
uni.fm = x;
result = (b & 0x80000000) >> 16 | (e > 112)*((((e - 112) << 10) & 0x7C00) | m >> 13) | ((e < 113) & (e > 101))*((((0x007FF000 + m) >> (125 - e)) + 1) >> 1) | (e > 143)*0x7FFF; // sign : normalized : denormalized : saturate
const unsigned int b = uni.ui + 0x00001000; // Round-to-nearest-even: add last bit after truncated mantissa
const unsigned int e = (b & 0x7f800000) >> 23; // Exponent
const unsigned int m = b & 0x007fffff; // Mantissa; in line below: 0x007ff000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding
result = (b & 0x80000000) >> 16 | (e > 112)*((((e - 112) << 10) & 0x7c00) | m >> 13) | ((e < 113) & (e > 101))*((((0x007ff000 + m) >> (125 - e)) + 1) >> 1) | (e > 143)*0x7fff; // sign : normalized : denormalized : saturate
return result;
}
@ -5493,6 +5511,7 @@ static Vector4 *LoadImageDataNormalized(Image image)
pixels[i].z = 0.0f;
pixels[i].w = 1.0f;
k += 1;
} break;
case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
{
@ -5518,6 +5537,8 @@ static Vector4 *LoadImageDataNormalized(Image image)
pixels[i].y = 0.0f;
pixels[i].z = 0.0f;
pixels[i].w = 1.0f;
k += 1;
} break;
case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
{

View file

@ -10,7 +10,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2024 Ramon Santamaria (@raysan5)
* Copyright (c) 2014-2025 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.
@ -308,7 +308,7 @@ bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileN
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) 2022-2024 Ramon Santamaria (@raysan5) //\n");
byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2022-2025 Ramon Santamaria (@raysan5) //\n");
byteCount += sprintf(txtData + byteCount, "// //\n");
byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
@ -405,7 +405,7 @@ void UnloadFileText(char *text)
}
// Save text data to file (write), string must be '\0' terminated
bool SaveFileText(const char *fileName, char *text)
bool SaveFileText(const char *fileName, const char *text)
{
bool success = false;