Merge branch 'master' into flag-macros

This commit is contained in:
JohnnyCena123 2025-09-28 11:54:05 +03:00 • committed by GitHub
commit bcde2885d1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 19685 additions and 17673 deletions

View file

@ -69,7 +69,7 @@ else()
endif()
if (${PLATFORM} MATCHES "Web")
target_link_options(raylib PUBLIC "-sUSE_GLFW=3")
target_link_options(raylib PUBLIC "-sUSE_GLFW=3" -sEXPORTED_RUNTIME_METHODS=ccall)
if(${GRAPHICS} MATCHES "GRAPHICS_API_OPENGL_ES3")
target_link_options(raylib PUBLIC "-sMIN_WEBGL_VERSION=2")
target_link_options(raylib PUBLIC "-sMAX_WEBGL_VERSION=2")
@ -91,7 +91,8 @@ if (BUILD_SHARED_LIBS)
set_property(TARGET raylib PROPERTY C_VISIBILITY_PRESET hidden)
endif ()
target_link_libraries(raylib "${LIBS_PRIVATE}")
target_link_libraries(raylib PRIVATE $<BUILD_INTERFACE:${LIBS_PRIVATE}>)
target_link_libraries(raylib PUBLIC ${LIBS_PUBLIC})
# Sets some compile time definitions for the pre-processor
# If CUSTOMIZE_BUILD option is on you will not use config.h by default

View file

@ -49,7 +49,7 @@
#include <android_native_app_glue.h> // Required for: android_app struct and activity management
#include <android/window.h> // Required for: AWINDOW_FLAG_FULLSCREEN definition and others
//#include <android/sensor.h> // Required for: Android sensors functions (accelerometer, gyroscope, light...)
#include <jni.h> // Required for: JNIEnv and JavaVM [Used in OpenURL()]
#include <jni.h> // Required for: JNIEnv and JavaVM [Used in OpenURL() and GetCurrentMonitor()]
#include <EGL/egl.h> // Native platform windowing system interface
@ -446,8 +446,35 @@ int GetMonitorCount(void)
// Get current monitor where window is placed
int GetCurrentMonitor(void)
{
TRACELOG(LOG_WARNING, "GetCurrentMonitor() not implemented on target platform");
return 0;
int displayId = -1;
JNIEnv *env = NULL;
JavaVM *vm = platform.app->activity->vm;
(*vm)->AttachCurrentThread(vm, &env, NULL);
jobject activity = platform.app->activity->clazz;
jclass activityClass = (*env)->GetObjectClass(env, activity);
jmethodID getDisplayMethod = (*env)->GetMethodID(env, activityClass, "getDisplay", "()Landroid/view/Display;");
jobject display = (*env)->CallObjectMethod(env, activity, getDisplayMethod);
if (display == NULL)
{
TRACELOG(LOG_ERROR, "GetCurrentMonitor() couldn't get the display object");
}
else
{
jclass displayClass = (*env)->FindClass(env, "android/view/Display");
jmethodID getDisplayIdMethod = (*env)->GetMethodID(env, displayClass, "getDisplayId", "()I");
displayId = (int)(*env)->CallIntMethod(env, display, getDisplayIdMethod);
(*env)->DeleteLocalRef(env, displayClass);
}
(*env)->DeleteLocalRef(env, activityClass);
(*env)->DeleteLocalRef(env, display);
(*vm)->DetachCurrentThread(vm);
return displayId;
}
// Get selected monitor position

View file

@ -81,16 +81,16 @@
#define Font X11Font // Hack to fix 'Font' name collision
// The definition and references to the X11 Font type will be replaced by 'X11Font'
// Works as long as the current file consistently references any X11 Font as X11Font
// Since it is never referenced (as of writting), this does not pose an issue
// Since it is never referenced (as of writing), this does not pose an issue
#endif
#if defined(_GLFW_WAYLAND)
#define GLFW_EXPOSE_NATIVE_WAYLAND
#endif
#include "GLFW/glfw3native.h" // Include native header only once, regardless of how many backends are defined
// Required for: glfwGetX11Window() and glfwGetWaylandWindow()
#if defined(_GLFW_X11) // Clean up X11-specific hacks
#undef Font // Revert hack and allow normal raylib Font usage
#endif
@ -130,27 +130,29 @@ void ClosePlatform(void); // Close platform
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
// Window callbacks events
static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized
static void WindowPosCallback(GLFWwindow* window, int x, int y); // GLFW3 WindowPos Callback, runs when window is moved
static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored
static void WindowMaximizeCallback(GLFWwindow* window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized
static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus
static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window
static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley); // GLFW3 Window Content Scale Callback, runs when window changes scale
static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized
static void WindowPosCallback(GLFWwindow* window, int x, int y); // GLFW3 WindowPos Callback, runs when window is moved
static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored
static void WindowMaximizeCallback(GLFWwindow* window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized
static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus
static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window
static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley); // GLFW3 Window Content Scale Callback, runs when window changes scale
// Input callbacks events
static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed
static void CharCallback(GLFWwindow *window, unsigned int codepoint); // GLFW3 Char Callback, runs on key pressed (get codepoint value)
static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods); // GLFW3 Mouse Button Callback, runs on mouse button pressed
static void MouseCursorPosCallback(GLFWwindow *window, double x, double y); // GLFW3 Cursor Position Callback, runs on mouse move
static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Scrolling Callback, runs on mouse wheel
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
static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed
static void CharCallback(GLFWwindow *window, unsigned int codepoint); // GLFW3 Char Callback, runs on key pressed (get codepoint value)
static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods); // GLFW3 Mouse Button Callback, runs on mouse button pressed
static void MouseCursorPosCallback(GLFWwindow *window, double x, double y); // GLFW3 Cursor Position Callback, runs on mouse move
static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Scrolling Callback, runs on mouse wheel
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
// Memory allocator wrappers [used by glfwInitAllocator()]
static void *AllocateWrapper(size_t size, void *user); // GLFW3 GLFWallocatefun, wrapps around RL_CALLOC macro
static void *ReallocateWrapper(void *block, size_t size, void *user); // GLFW3 GLFWreallocatefun, wrapps around RL_REALLOC macro
static void DeallocateWrapper(void *block, void *user); // GLFW3 GLFWdeallocatefun, wraps around RL_FREE macro
static void SetDimensionsFromMonitor(GLFWmonitor *monitor); // Set screen dimensions from monitor/display dimensions
//----------------------------------------------------------------------------------
// Module Functions Declaration
@ -435,7 +437,7 @@ void SetWindowState(unsigned int flags)
// State change: FLAG_INTERLACED_HINT
if ((FLAG_CHECK(CORE.Window.flags, FLAG_INTERLACED_HINT) != FLAG_CHECK(flags, FLAG_INTERLACED_HINT)) && FLAG_CHECK(flags, FLAG_INTERLACED_HINT) > 0)
{
TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization");
TRACELOG(LOG_WARNING, "WINDOW: Interlaced mode can only be configured before window initialization");
}
}
@ -993,7 +995,7 @@ Vector2 GetWindowPosition(void)
// Get window scale DPI factor for current monitor
Vector2 GetWindowScaleDPI(void)
{
Vector2 scale = {0};
Vector2 scale = { 0 };
glfwGetWindowContentScale(platform.handle, &scale.x, &scale.y);
return scale;
}
@ -1321,20 +1323,6 @@ void PollInputEvents(void)
//----------------------------------------------------------------------------------
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
static void SetDimensionsFromMonitor(GLFWmonitor *monitor)
{
const GLFWvidmode *mode = glfwGetVideoMode(monitor);
// Default display resolution to that of the current mode
CORE.Window.display.width = mode->width;
CORE.Window.display.height = mode->height;
// Set screen width/height to the display width/height if they are 0
if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width;
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
@ -1342,7 +1330,7 @@ static void SetDimensionsFromMonitor(GLFWmonitor *monitor)
static void *AllocateWrapper(size_t size, void *user)
{
(void)user;
return RL_MALLOC(size);
return RL_CALLOC(size, 1);
}
static void *ReallocateWrapper(void *block, size_t size, void *user)
{
@ -1428,10 +1416,18 @@ int InitPlatform(void)
// 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);
// NOTE: This currently doesn't work on macOS(see #5185), so we skip it there
// when FLAG_WINDOW_HIGHDPI is *unset*
#if !defined(__APPLE__)
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);
#endif
if (FLAG_CHECK(CORE.Window.flags, FLAG_WINDOW_HIGHDPI) > 0)
{
// since we skipped it before, now make sure to set this on macOS
#if defined(__APPLE__)
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);
#endif
// Resize window content area based on the monitor content scale
// NOTE: This hint only has an effect on platforms where screen coordinates and pixels always map 1:1 such as Windows and X11
// On platforms like macOS the resolution of the framebuffer is changed independently of the window size
@ -1921,8 +1917,6 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
// GLFW3 Char Callback, get unicode codepoint value
static void CharCallback(GLFWwindow *window, unsigned int codepoint)
{
//TRACELOG(LOG_DEBUG, "Char Callback: Codepoint: %i", codepoint);
// NOTE: Registers any key down considering OS keyboard layout but
// does not detect action events, those should be managed by user...
// Ref: https://github.com/glfw/glfw/issues/668#issuecomment-166794907
@ -2033,6 +2027,20 @@ static void JoystickCallback(int jid, int event)
}
}
// Set screen dimensions from monitor/display dimensions
static void SetDimensionsFromMonitor(GLFWmonitor *monitor)
{
const GLFWvidmode *mode = glfwGetVideoMode(monitor);
// Default display resolution to that of the current mode
CORE.Window.display.width = mode->width;
CORE.Window.display.height = mode->height;
// Set screen width/height to the display width/height if they are 0
if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width;
if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height;
}
#ifdef _WIN32
# define WIN32_CLIPBOARD_IMPLEMENTATION
# include "../external/win32_clipboard.h"

View file

@ -240,12 +240,34 @@ static const unsigned short keyMappingRGFW[] = {
[RGFW_scrollLock] = KEY_SCROLL_LOCK,
};
static int RGFW_gpConvTable[18] = {
[RGFW_gamepadY] = GAMEPAD_BUTTON_RIGHT_FACE_UP,
[RGFW_gamepadB] = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT,
[RGFW_gamepadA] = GAMEPAD_BUTTON_RIGHT_FACE_DOWN,
[RGFW_gamepadX] = GAMEPAD_BUTTON_RIGHT_FACE_LEFT,
[RGFW_gamepadL1] = GAMEPAD_BUTTON_LEFT_TRIGGER_1,
[RGFW_gamepadR1] = GAMEPAD_BUTTON_RIGHT_TRIGGER_1,
[RGFW_gamepadL2] = GAMEPAD_BUTTON_LEFT_TRIGGER_2,
[RGFW_gamepadR2] = GAMEPAD_BUTTON_RIGHT_TRIGGER_2,
[RGFW_gamepadSelect] = GAMEPAD_BUTTON_MIDDLE_LEFT,
[RGFW_gamepadHome] = GAMEPAD_BUTTON_MIDDLE,
[RGFW_gamepadStart] = GAMEPAD_BUTTON_MIDDLE_RIGHT,
[RGFW_gamepadUp] = GAMEPAD_BUTTON_LEFT_FACE_UP,
[RGFW_gamepadRight] = GAMEPAD_BUTTON_LEFT_FACE_RIGHT,
[RGFW_gamepadDown] = GAMEPAD_BUTTON_LEFT_FACE_DOWN,
[RGFW_gamepadLeft] = GAMEPAD_BUTTON_LEFT_FACE_LEFT,
[RGFW_gamepadL3] = GAMEPAD_BUTTON_LEFT_THUMB,
[RGFW_gamepadR3] = GAMEPAD_BUTTON_RIGHT_THUMB,
};
//----------------------------------------------------------------------------------
// Module Internal Functions Declaration
//----------------------------------------------------------------------------------
int InitPlatform(void); // Initialize platform (graphics, inputs and more)
bool InitGraphicsDevice(void); // Initialize graphics device
static KeyboardKey ConvertScancodeToKey(u32 keycode);
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
@ -888,28 +910,6 @@ const char *GetKeyName(int key)
return "";
}
static KeyboardKey ConvertScancodeToKey(u32 keycode);
int RGFW_gpConvTable[18] = {
[RGFW_gamepadY] = GAMEPAD_BUTTON_RIGHT_FACE_UP,
[RGFW_gamepadB] = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT,
[RGFW_gamepadA] = GAMEPAD_BUTTON_RIGHT_FACE_DOWN,
[RGFW_gamepadX] = GAMEPAD_BUTTON_RIGHT_FACE_LEFT,
[RGFW_gamepadL1] = GAMEPAD_BUTTON_LEFT_TRIGGER_1,
[RGFW_gamepadR1] = GAMEPAD_BUTTON_RIGHT_TRIGGER_1,
[RGFW_gamepadL2] = GAMEPAD_BUTTON_LEFT_TRIGGER_2,
[RGFW_gamepadR2] = GAMEPAD_BUTTON_RIGHT_TRIGGER_2,
[RGFW_gamepadSelect] = GAMEPAD_BUTTON_MIDDLE_LEFT,
[RGFW_gamepadHome] = GAMEPAD_BUTTON_MIDDLE,
[RGFW_gamepadStart] = GAMEPAD_BUTTON_MIDDLE_RIGHT,
[RGFW_gamepadUp] = GAMEPAD_BUTTON_LEFT_FACE_UP,
[RGFW_gamepadRight] = GAMEPAD_BUTTON_LEFT_FACE_RIGHT,
[RGFW_gamepadDown] = GAMEPAD_BUTTON_LEFT_FACE_DOWN,
[RGFW_gamepadLeft] = GAMEPAD_BUTTON_LEFT_FACE_LEFT,
[RGFW_gamepadL3] = GAMEPAD_BUTTON_LEFT_THUMB,
[RGFW_gamepadR3] = GAMEPAD_BUTTON_RIGHT_THUMB,
};
// Register all input events
void PollInputEvents(void)
{

View file

@ -85,11 +85,13 @@
#endif
#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
#ifndef USING_VERSION_SDL3
#define USING_VERSION_SDL3
#endif
#endif
#define SCANCODE_MAPPED_NUM 232
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
@ -98,7 +100,7 @@ typedef struct {
SDL_GLContext glContext;
SDL_GameController *gamepad[MAX_GAMEPADS];
SDL_JoystickID gamepadId[MAX_GAMEPADS]; // Joystick instance ids
SDL_JoystickID gamepadId[MAX_GAMEPADS]; // Joystick instance ids, they do not start from 0
SDL_Cursor *cursor;
bool cursorRelative;
} PlatformData;
@ -110,10 +112,6 @@ extern CoreData CORE; // Global CORE state context
static PlatformData platform = { 0 }; // Platform specific data
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
#define SCANCODE_MAPPED_NUM 232
static const KeyboardKey mapScancodeToKey[SCANCODE_MAPPED_NUM] = {
KEY_NULL, // SDL_SCANCODE_UNKNOWN
0,
@ -255,7 +253,7 @@ static const int CursorsLUT[] = {
};
// SDL3 Migration Layer made to avoid 'ifdefs' inside functions when we can
#if defined(PLATFORM_DESKTOP_SDL3)
#if defined(USING_VERSION_SDL3)
// SDL3 Migration:
// SDL_WINDOW_FULLSCREEN_DESKTOP has been removed,
@ -321,7 +319,7 @@ Uint8 SDL_EventState(Uint32 type, int 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");
default: TRACELOG(LOG_WARNING, "SDL: Event state of unknow type");
}
return stateBefore;
@ -329,10 +327,10 @@ Uint8 SDL_EventState(Uint32 type, int state)
void SDL_GetCurrentDisplayMode_Adapter(SDL_DisplayID displayID, SDL_DisplayMode* mode)
{
const SDL_DisplayMode* currMode = SDL_GetCurrentDisplayMode(displayID);
const SDL_DisplayMode *currentMode = SDL_GetCurrentDisplayMode(displayID);
if (currMode == NULL) TRACELOG(LOG_WARNING, "No current display mode");
else *mode = *currMode;
if (currentMode == NULL) TRACELOG(LOG_WARNING, "SDL: No possible to get current display mode");
else *mode = *currentMode;
}
// SDL3 Migration: Renamed
@ -423,13 +421,13 @@ int SDL_GetNumTouchFingers(SDL_TouchID touchID)
// SDL_GetClipboardData function is available since SDL 3.1.3. (e.g. SDL3)
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");
TRACELOG(LOG_WARNING, "SDL: Getting clipboard data that is not text not available in SDL2");
// We could possibly implement it ourselves in this case for some easier platforms
return NULL;
}
#endif // PLATFORM_DESKTOP_SDL3
#endif // USING_VERSION_SDL3
//----------------------------------------------------------------------------------
// Module Internal Functions Declaration
@ -438,8 +436,8 @@ int InitPlatform(void); // Initialize platf
void ClosePlatform(void); // Close platform
static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode); // Help convert SDL scancodes to raylib key
static int GetCodepointNextSDL(const char *text, int *codepointSize); // Get next codepoint in a byte sequence and bytes processed
static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event); // Update CORE input touch point info from SDL touch data
//----------------------------------------------------------------------------------
// Module Functions Declaration
@ -463,7 +461,7 @@ void ToggleFullscreen(void)
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(PLATFORM_DESKTOP_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
#if defined(USING_VERSION_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))
@ -491,7 +489,7 @@ void ToggleBorderlessWindowed(void)
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(PLATFORM_DESKTOP_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
#if defined(USING_VERSION_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))
@ -548,7 +546,7 @@ void SetWindowState(unsigned int flags)
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(PLATFORM_DESKTOP_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
#if defined(USING_VERSION_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))
@ -608,7 +606,7 @@ void SetWindowState(unsigned int flags)
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(PLATFORM_DESKTOP_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
#if defined(USING_VERSION_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))
@ -841,7 +839,7 @@ void SetWindowMonitor(int monitor)
const int screenHeight = CORE.Window.screen.height;
SDL_Rect usableBounds;
#if defined(PLATFORM_DESKTOP_SDL3) // Different style for success checking
#if defined(USING_VERSION_SDL3) // Different style for success checking
if (SDL_GetDisplayUsableBounds(monitor, &usableBounds))
#else
if (SDL_GetDisplayUsableBounds(monitor, &usableBounds) == 0)
@ -957,7 +955,7 @@ Vector2 GetMonitorPosition(int monitor)
{
SDL_Rect displayBounds;
#if defined(PLATFORM_DESKTOP_SDL3)
#if defined(USING_VERSION_SDL3)
if (SDL_GetDisplayUsableBounds(monitor, &displayBounds))
#else
if (SDL_GetDisplayUsableBounds(monitor, &displayBounds) == 0)
@ -1089,7 +1087,7 @@ Vector2 GetWindowScaleDPI(void)
{
Vector2 scale = { 1.0f, 1.0f };
#ifndef PLATFORM_DESKTOP_SDL3
#ifndef USING_VERSION_SDL3
// NOTE: SDL_GetWindowDisplayScale was only added on SDL3
// see https://wiki.libsdl.org/SDL3/SDL_GetWindowDisplayScale
// TODO: Implement the window scale factor calculation manually
@ -1175,7 +1173,7 @@ Image GetClipboardImage(void)
// Show mouse cursor
void ShowCursor(void)
{
#if defined(PLATFORM_DESKTOP_SDL3)
#if defined(USING_VERSION_SDL3)
SDL_ShowCursor();
#else
SDL_ShowCursor(SDL_ENABLE);
@ -1186,7 +1184,7 @@ void ShowCursor(void)
// Hides mouse cursor
void HideCursor(void)
{
#if defined(PLATFORM_DESKTOP_SDL3)
#if defined(USING_VERSION_SDL3)
SDL_HideCursor();
#else
SDL_ShowCursor(SDL_DISABLE);
@ -1199,7 +1197,7 @@ void EnableCursor(void)
{
SDL_SetRelativeMouseMode(SDL_FALSE);
#if defined(PLATFORM_DESKTOP_SDL3)
#if defined(USING_VERSION_SDL3)
// SDL_ShowCursor() has been split into three functions: SDL_ShowCursor(), SDL_HideCursor(), and SDL_CursorVisible()
SDL_ShowCursor();
#else
@ -1298,41 +1296,6 @@ const char *GetKeyName(int key)
return SDL_GetKeyName(key);
}
static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event)
{
#if defined(PLATFORM_DESKTOP_SDL3) // SDL3
int count = 0;
SDL_Finger **fingers = SDL_GetTouchFingers(event.touchID, &count);
CORE.Input.Touch.pointCount = count;
for (int i = 0; i < CORE.Input.Touch.pointCount; i++)
{
SDL_Finger *finger = fingers[i];
CORE.Input.Touch.pointId[i] = finger->id;
CORE.Input.Touch.position[i].x = finger->x*CORE.Window.screen.width;
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);
for (int i = 0; i < CORE.Input.Touch.pointCount; i++)
{
SDL_Finger *finger = SDL_GetTouchFinger(event.touchId, i);
CORE.Input.Touch.pointId[i] = finger->id;
CORE.Input.Touch.position[i].x = finger->x*CORE.Window.screen.width;
CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height;
CORE.Input.Touch.currentTouchState[i] = 1;
}
#endif
for (int i = CORE.Input.Touch.pointCount; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.currentTouchState[i] = 0;
}
// Register all input events
void PollInputEvents(void)
{
@ -1390,15 +1353,9 @@ void PollInputEvents(void)
// Poll input events for current platform
//-----------------------------------------------------------------------------
/*
// WARNING: Indexes into this array are obtained by using SDL_Scancode values, not SDL_Keycode values
const Uint8 *keys = SDL_GetKeyboardState(NULL);
for (int i = 0; i < 256; ++i)
{
CORE.Input.Keyboard.currentKeyState[i] = keys[i];
//if (keys[i]) TRACELOG(LOG_WARNING, "Pressed key: %i", i);
}
*/
//const Uint8 *keys = SDL_GetKeyboardState(NULL);
//for (int i = 0; i < 256; ++i) CORE.Input.Keyboard.currentKeyState[i] = keys[i];
CORE.Window.resizedLastFrame = false;
@ -1427,7 +1384,7 @@ void PollInputEvents(void)
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
#if defined(PLATFORM_DESKTOP_SDL3)
#if defined(USING_VERSION_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);
@ -1442,7 +1399,7 @@ void PollInputEvents(void)
{
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
#if defined(PLATFORM_DESKTOP_SDL3)
#if defined(USING_VERSION_SDL3)
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data);
#else
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file);
@ -1457,7 +1414,7 @@ void PollInputEvents(void)
// Window events are also polled (Minimized, maximized, close...)
#ifndef PLATFORM_DESKTOP_SDL3
#ifndef USING_VERSION_SDL3
// SDL3 states:
// The SDL_WINDOWEVENT_* events have been moved to top level events, and SDL_WINDOWEVENT has been removed
// In general, handling this change just means checking for the individual events instead of first checking for SDL_WINDOWEVENT
@ -1488,7 +1445,7 @@ void PollInputEvents(void)
CORE.Window.currentFbo.height = height;
CORE.Window.resizedLastFrame = true;
#ifndef PLATFORM_DESKTOP_SDL3
#ifndef USING_VERSION_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 (FLAG_CHECK(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED) > 0)
{
@ -1529,8 +1486,8 @@ void PollInputEvents(void)
if (FLAG_CHECK(CORE.Window.flags, FLAG_WINDOW_MINIMIZED) > 0) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);
}
#ifdef PLATFORM_DESKTOP_SDL3
if ((SDL_GetWindowFlags(platform.window), SDL_WINDOW_MAXIMIZED) == 0)
#ifdef USING_VERSION_SDL3
if (FLAG_CHECK(SDL_GetWindowFlags(platform.window), SDL_WINDOW_MAXIMIZED) == 0)
{
if (FLAG_CHECK(CORE.Window.flags, SDL_WINDOW_MAXIMIZED) > 0) FLAG_CLEAR(CORE.Window.flags, SDL_WINDOW_MAXIMIZED);
}
@ -1555,7 +1512,7 @@ void PollInputEvents(void)
if (FLAG_CHECK(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED) == 0) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
} break;
#ifndef PLATFORM_DESKTOP_SDL3
#ifndef USING_VERSION_SDL3
default: break;
}
} break;
@ -1564,7 +1521,7 @@ void PollInputEvents(void)
// Keyboard events
case SDL_KEYDOWN:
{
#if defined(PLATFORM_DESKTOP_SDL3)
#if defined(USING_VERSION_SDL3)
// SDL3 Migration: The following structures have been removed: * SDL_Keysym
KeyboardKey key = ConvertScancodeToKey(event.key.scancode);
#else
@ -1595,7 +1552,7 @@ void PollInputEvents(void)
case SDL_KEYUP:
{
#if defined(PLATFORM_DESKTOP_SDL3)
#if defined(USING_VERSION_SDL3)
KeyboardKey key = ConvertScancodeToKey(event.key.scancode);
#else
KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode);
@ -1611,7 +1568,7 @@ void PollInputEvents(void)
if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
{
// Add character (codepoint) to the queue
#if defined(PLATFORM_DESKTOP_SDL3)
#if defined(USING_VERSION_SDL3)
size_t textLen = strlen(event.text.text);
unsigned int codepoint = (unsigned int)SDL_StepUTF8(&event.text.text, &textLen);
#else
@ -1697,19 +1654,34 @@ void PollInputEvents(void)
{
int jid = event.jdevice.which; // Joystick device index
if (CORE.Input.Gamepad.ready[jid] && (jid < MAX_GAMEPADS))
// check if already added at InitPlatform
for (int i = 0; i < MAX_GAMEPADS; ++i)
{
platform.gamepad[jid] = SDL_GameControllerOpen(jid);
platform.gamepadId[jid] = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[jid]));
if (platform.gamepad[jid])
if (jid == platform.gamepadId[i])
{
CORE.Input.Gamepad.ready[jid] = true;
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;
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);
return;
}
}
int nextAvailableSlot = 0;
while (nextAvailableSlot < MAX_GAMEPADS && CORE.Input.Gamepad.ready[nextAvailableSlot])
{
++nextAvailableSlot;
}
if ((nextAvailableSlot < MAX_GAMEPADS) && !CORE.Input.Gamepad.ready[nextAvailableSlot])
{
platform.gamepad[nextAvailableSlot] = SDL_GameControllerOpen(jid);
platform.gamepadId[nextAvailableSlot] = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[nextAvailableSlot]));
if (platform.gamepad[nextAvailableSlot])
{
CORE.Input.Gamepad.ready[nextAvailableSlot] = true;
CORE.Input.Gamepad.axisCount[nextAvailableSlot] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[nextAvailableSlot]));
CORE.Input.Gamepad.axisState[nextAvailableSlot][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
CORE.Input.Gamepad.axisState[nextAvailableSlot][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
memset(CORE.Input.Gamepad.name[nextAvailableSlot], 0, MAX_GAMEPAD_NAME_LENGTH);
strncpy(CORE.Input.Gamepad.name[nextAvailableSlot], SDL_GameControllerNameForIndex(nextAvailableSlot), MAX_GAMEPAD_NAME_LENGTH - 1);
}
else
{
@ -1737,7 +1709,7 @@ void PollInputEvents(void)
{
int button = -1;
switch (event.jbutton.button)
switch (event.gbutton.button)
{
case SDL_CONTROLLER_BUTTON_Y: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break;
case SDL_CONTROLLER_BUTTON_B: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break;
@ -1765,7 +1737,7 @@ void PollInputEvents(void)
{
for (int i = 0; i < MAX_GAMEPADS; i++)
{
if (platform.gamepadId[i] == event.jbutton.which)
if (platform.gamepadId[i] == event.gbutton.which)
{
CORE.Input.Gamepad.currentButtonState[i][button] = 1;
CORE.Input.Gamepad.lastButtonPressed = button;
@ -1778,7 +1750,7 @@ void PollInputEvents(void)
{
int button = -1;
switch (event.jbutton.button)
switch (event.gbutton.button)
{
case SDL_CONTROLLER_BUTTON_Y: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break;
case SDL_CONTROLLER_BUTTON_B: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break;
@ -1806,7 +1778,7 @@ void PollInputEvents(void)
{
for (int i = 0; i < MAX_GAMEPADS; i++)
{
if (platform.gamepadId[i] == event.jbutton.which)
if (platform.gamepadId[i] == event.gbutton.which)
{
CORE.Input.Gamepad.currentButtonState[i][button] = 0;
if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
@ -1978,7 +1950,7 @@ int InitPlatform(void)
}
// Init window
#if defined(PLATFORM_DESKTOP_SDL3)
#if defined(USING_VERSION_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);
@ -2031,21 +2003,28 @@ int InitPlatform(void)
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]));
int numJoysticks = 0;
SDL_JoystickID *joysticks = SDL_GetJoysticks(&numJoysticks); // array of joystick IDs, they do not start from 0
if (platform.gamepad[i])
if (joysticks)
{
for (int i = 0; (i < numJoysticks) && (i < MAX_GAMEPADS); i++)
{
CORE.Input.Gamepad.ready[i] = true;
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), MAX_GAMEPAD_NAME_LENGTH - 1);
CORE.Input.Gamepad.name[i][MAX_GAMEPAD_NAME_LENGTH - 1] = '\0';
platform.gamepad[i] = SDL_GameControllerOpen(joysticks[i]);
platform.gamepadId[i] = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[i]));
if (platform.gamepad[i])
{
CORE.Input.Gamepad.ready[i] = true;
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), 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());
}
else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
SDL_free(joysticks);
}
// Disable mouse events being interpreted as touch events
@ -2072,7 +2051,7 @@ int InitPlatform(void)
CORE.Storage.basePath = SDL_GetBasePath(); // Alternative: GetWorkingDirectory();
//----------------------------------------------------------------------------
#if defined(PLATFORM_DESKTOP_SDL3)
#if defined(USING_VERSION_SDL3)
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL3): Initialized successfully");
#else
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL2): Initialized successfully");
@ -2139,3 +2118,39 @@ static int GetCodepointNextSDL(const char *text, int *codepointSize)
return codepoint;
}
// Update CORE input touch point info from SDL touch data
static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event)
{
#if defined(USING_VERSION_SDL3) // SDL3
int count = 0;
SDL_Finger **fingers = SDL_GetTouchFingers(event.touchID, &count);
CORE.Input.Touch.pointCount = count;
for (int i = 0; i < CORE.Input.Touch.pointCount; i++)
{
SDL_Finger *finger = fingers[i];
CORE.Input.Touch.pointId[i] = finger->id;
CORE.Input.Touch.position[i].x = finger->x*CORE.Window.screen.width;
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);
for (int i = 0; i < CORE.Input.Touch.pointCount; i++)
{
SDL_Finger *finger = SDL_GetTouchFinger(event.touchId, i);
CORE.Input.Touch.pointId[i] = finger->id;
CORE.Input.Touch.position[i].x = finger->x*CORE.Window.screen.width;
CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height;
CORE.Input.Touch.currentTouchState[i] = 1;
}
#endif
for (int i = CORE.Input.Touch.pointCount; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.currentTouchState[i] = 0;
}

File diff suppressed because it is too large Load diff

View file

@ -245,6 +245,7 @@ static void RestoreKeyboard(void); // Restore keyboard system
static void ProcessKeyboard(void); // Process keyboard events
#endif
// Input management functions
static void InitEvdevInput(void); // Initialize evdev inputs
static void ConfigureEvdevDevice(char *device); // Identifies a input device and configures it for use if appropriate
static void PollKeyboardEvents(void); // Process evdev keyboard events
@ -703,7 +704,7 @@ void SwapScreenBuffer()
if (!crtcSet || !platform.gbmSurface) return;
static int loopCnt = 0;
static int errCnt[5] = {0};
static int errCnt[5] = { 0 };
loopCnt++;
// Call this only, if pendingFlip is not set

View file

@ -1495,8 +1495,8 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
// WARNING: GLFW could return GLFW_REPEAT, we need to consider it as 1
// to work properly with our implementation (IsKeyDown/IsKeyUp checks)
if (action == GLFW_RELEASE) CORE.Input.Keyboard.currentKeyState[key] = 0;
else if(action == GLFW_PRESS) CORE.Input.Keyboard.currentKeyState[key] = 1;
else if(action == GLFW_REPEAT) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1;
else if (action == GLFW_PRESS) CORE.Input.Keyboard.currentKeyState[key] = 1;
else if (action == GLFW_REPEAT) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1;
// Check if there is space available in the key queue
if ((CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE) && (action == GLFW_PRESS))
@ -1722,8 +1722,7 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent
}
#if defined(SUPPORT_GESTURES_SYSTEM)
GestureEvent gestureEvent = {0};
GestureEvent gestureEvent = { 0 };
gestureEvent.pointCount = CORE.Input.Touch.pointCount;
// Register touch actions
@ -1852,7 +1851,7 @@ static EM_BOOL EmscriptenVisibilityChangeCallback(int eventType, const Emscripte
//-------------------------------------------------------------------------------------------------------
// JS: Get the canvas id provided by the module configuration
EM_JS(char*, GetCanvasIdJs, (), {
EM_JS(char *, GetCanvasIdJs, (), {
var canvasId = "#" + Module.canvas.id;
var lengthBytes = lengthBytesUTF8(canvasId) + 1;
var stringOnWasmHeap = _malloc(lengthBytes);

View file

@ -454,6 +454,7 @@ void UntrackAudioBuffer(AudioBuffer *buffer);
//----------------------------------------------------------------------------------
// Module Functions Definition - Audio Device initialization and Closing
//----------------------------------------------------------------------------------
// Initialize audio device
void InitAudioDevice(void)
{

View file

@ -1110,45 +1110,51 @@ RLAPI void MemFree(void *ptr); // Internal me
// Set custom callbacks
// WARNING: Callbacks setup is intended for advanced users
RLAPI void SetTraceLogCallback(TraceLogCallback callback); // Set custom trace log
RLAPI void SetLoadFileDataCallback(LoadFileDataCallback callback); // Set custom file binary data loader
RLAPI void SetSaveFileDataCallback(SaveFileDataCallback callback); // Set custom file binary data saver
RLAPI void SetLoadFileTextCallback(LoadFileTextCallback callback); // Set custom file text data loader
RLAPI void SetSaveFileTextCallback(SaveFileTextCallback callback); // Set custom file text data saver
RLAPI void SetTraceLogCallback(TraceLogCallback callback); // Set custom trace log
RLAPI void SetLoadFileDataCallback(LoadFileDataCallback callback); // Set custom file binary data loader
RLAPI void SetSaveFileDataCallback(SaveFileDataCallback callback); // Set custom file binary data saver
RLAPI void SetLoadFileTextCallback(LoadFileTextCallback callback); // Set custom file text data loader
RLAPI void SetSaveFileTextCallback(SaveFileTextCallback callback); // Set custom file text data saver
// Files management functions
RLAPI unsigned char *LoadFileData(const char *fileName, int *dataSize); // Load file data as byte array (read)
RLAPI void UnloadFileData(unsigned char *data); // Unload file data allocated by LoadFileData()
RLAPI void UnloadFileData(unsigned char *data); // Unload file data allocated by LoadFileData()
RLAPI bool SaveFileData(const char *fileName, void *data, int dataSize); // Save data to file from byte array (write), returns true on success
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, const char *text); // Save text data to file (write), string must be '\0' terminated, 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, const char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success
//------------------------------------------------------------------
// File system functions
RLAPI bool FileExists(const char *fileName); // Check if file exists
RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists
RLAPI bool IsFileExtension(const char *fileName, const char *ext); // Check file extension (recommended include point: .png, .wav)
RLAPI int GetFileLength(const char *fileName); // Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h)
RLAPI const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes dot: '.png')
RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string
RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string)
RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a given fileName with path (uses static string)
RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a given path (uses static string)
RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string)
RLAPI const char *GetApplicationDirectory(void); // Get the directory of the running application (uses static string)
RLAPI int MakeDirectory(const char *dirPath); // Create directories (including full path requested), returns 0 on success
RLAPI bool ChangeDirectory(const char *dir); // Change working directory, return true on success
RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory
RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS
RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths
RLAPI int FileRename(const char *fileName, const char *fileRename); // Rename file (if exists)
RLAPI int FileRemove(const char *fileName); // Remove file (if exists)
RLAPI int FileCopy(const char *srcPath, const char *dstPath); // Copy file from one path to another, dstPath created if it doesn't exist
RLAPI int FileMove(const char *srcPath, const char *dstPath); // Move file from one directory to another, dstPath created if it doesn't exist
RLAPI int FileTextReplace(const char *fileName, const char *search, const char *replacement); // Replace text in an existing file
RLAPI int FileTextFindIndex(const char *fileName, const char *search); // Find text in existing file
RLAPI bool FileExists(const char *fileName); // Check if file exists
RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists
RLAPI bool IsFileExtension(const char *fileName, const char *ext); // Check file extension (recommended include point: .png, .wav)
RLAPI int GetFileLength(const char *fileName); // Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h)
RLAPI long GetFileModTime(const char *fileName); // Get file modification time (last write time)
RLAPI const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes dot: '.png')
RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string
RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string)
RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a given fileName with path (uses static string)
RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a given path (uses static string)
RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string)
RLAPI const char *GetApplicationDirectory(void); // Get the directory of the running application (uses static string)
RLAPI int MakeDirectory(const char *dirPath); // Create directories (including full path requested), returns 0 on success
RLAPI bool ChangeDirectory(const char *dir); // Change working directory, return true on success
RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory
RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS
RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths
RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result
RLAPI void UnloadDirectoryFiles(FilePathList files); // Unload filepaths
RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window
RLAPI FilePathList LoadDroppedFiles(void); // Load dropped filepaths
RLAPI void UnloadDroppedFiles(FilePathList files); // Unload dropped filepaths
RLAPI long GetFileModTime(const char *fileName); // Get file modification time (last write time)
RLAPI void UnloadDirectoryFiles(FilePathList files); // Unload filepaths
RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window
RLAPI FilePathList LoadDroppedFiles(void); // Load dropped filepaths
RLAPI void UnloadDroppedFiles(FilePathList files); // Unload dropped filepaths
// Compression/Encoding functionality
RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize); // Compress data (DEFLATE algorithm), memory must be MemFree()
@ -1504,21 +1510,24 @@ RLAPI int GetCodepointPrevious(const char *text, int *codepointSize);
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)
// WARNING 1: Most of these functions use internal static buffers, it's recommended to store returned data on user-side for re-use
// 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 char **LoadTextLines(const char *text, int *count); // Load text as separate lines ('\n')
RLAPI void UnloadTextLines(char **text); // Unload text lines
RLAPI void UnloadTextLines(char **text, int lineCount); // Unload text lines
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
RLAPI const char *TextFormat(const char *text, ...); // Text formatting with variables (sprintf() style)
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 const char *TextRemoveSpaces(const char *text); // Remove text spaces, concat words
RLAPI char *GetTextBetween(const char *text, const char *begin, const char *end); // Get text between two strings
RLAPI char *TextReplace(const char *text, const char *search, const char *replacement); // Replace text string (WARNING: memory must be freed!)
RLAPI char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement); // Replace text between two specific strings (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 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, using MAX_TEXTSPLIT_COUNT static 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, -1 if not found
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 *search); // Find first text occurrence within a string, -1 if not found
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

View file

@ -2552,65 +2552,91 @@ RMAPI int QuaternionEquals(Quaternion p, Quaternion q)
return result;
}
// Decompose a transformation matrix into its rotational, translational and scaling components
// Decompose a transformation matrix into its rotational, translational and scaling components and remove shear
RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotation, Vector3 *scale)
{
// Extract translation.
float eps = (float)1e-9;
// Extract Translation
translation->x = mat.m12;
translation->y = mat.m13;
translation->z = mat.m14;
// Extract upper-left for determinant computation
const float a = mat.m0;
const float b = mat.m4;
const float c = mat.m8;
const float d = mat.m1;
const float e = mat.m5;
const float f = mat.m9;
const float g = mat.m2;
const float h = mat.m6;
const float i = mat.m10;
const float A = e*i - f*h;
const float B = f*g - d*i;
const float C = d*h - e*g;
// Matrix Columns - Rotation will be extracted into here.
Vector3 matColumns[3] = { { mat.m0, mat.m4, mat.m8 },
{ mat.m1, mat.m5, mat.m9 },
{ mat.m2, mat.m6, mat.m10 } };
// Extract scale
const float det = a*A + b*B + c*C;
Vector3 abc = { a, b, c };
Vector3 def = { d, e, f };
Vector3 ghi = { g, h, i };
// Shear Parameters XY, XZ, and YZ (extract and ignored)
float shear[3] = { 0 };
float scalex = Vector3Length(abc);
float scaley = Vector3Length(def);
float scalez = Vector3Length(ghi);
Vector3 s = { scalex, scaley, scalez };
// Normalized Scale Parameters
Vector3 scl = { 0 };
if (det < 0) s = Vector3Negate(s);
*scale = s;
// Remove scale from the matrix if it is not close to zero
Matrix clone = mat;
if (!FloatEquals(det, 0))
// Max-Normalizing helps numerical stability
float stabilizer = eps;
for (int i = 0; i < 3; i++)
{
clone.m0 /= s.x;
clone.m4 /= s.x;
clone.m8 /= s.x;
clone.m1 /= s.y;
clone.m5 /= s.y;
clone.m9 /= s.y;
clone.m2 /= s.z;
clone.m6 /= s.z;
clone.m10 /= s.z;
stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].x));
stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].y));
stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].z));
};
matColumns[0] = Vector3Scale(matColumns[0], 1.0f / stabilizer);
matColumns[1] = Vector3Scale(matColumns[1], 1.0f / stabilizer);
matColumns[2] = Vector3Scale(matColumns[2], 1.0f / stabilizer);
// Extract rotation
*rotation = QuaternionFromMatrix(clone);
}
else
// X Scale
scl.x = Vector3Length(matColumns[0]);
if (scl.x > eps)
{
// Set to identity if close to zero
*rotation = QuaternionIdentity();
matColumns[0] = Vector3Scale(matColumns[0], 1.0f / scl.x);
}
// Compute XY shear and make col2 orthogonal
shear[0] = Vector3DotProduct(matColumns[0], matColumns[1]);
matColumns[1] = Vector3Subtract(matColumns[1], Vector3Scale(matColumns[0], shear[0]));
// Y Scale
scl.y = Vector3Length(matColumns[1]);
if (scl.y > eps)
{
matColumns[1] = Vector3Scale(matColumns[1], 1.0f / scl.y);
shear[0] /= scl.y; // Correct XY shear
}
// Compute XZ and YZ shears and make col3 orthogonal
shear[1] = Vector3DotProduct(matColumns[0], matColumns[2]);
matColumns[2] = Vector3Subtract(matColumns[2], Vector3Scale(matColumns[0], shear[1]));
shear[2] = Vector3DotProduct(matColumns[1], matColumns[2]);
matColumns[2] = Vector3Subtract(matColumns[2], Vector3Scale(matColumns[1], shear[2]));
// Z Scale
scl.z = Vector3Length(matColumns[2]);
if (scl.z > eps)
{
matColumns[2] = Vector3Scale(matColumns[2], 1.0f / scl.z);
shear[1] /= scl.z; // Correct XZ shear
shear[2] /= scl.z; // Correct YZ shear
}
// matColumns are now orthonormal in O(3). Now ensure its in SO(3) by enforcing det = 1.
if (Vector3DotProduct(matColumns[0], Vector3CrossProduct(matColumns[1], matColumns[2])) < 0)
{
scl = Vector3Negate(scl);
matColumns[0] = Vector3Negate(matColumns[0]);
matColumns[1] = Vector3Negate(matColumns[1]);
matColumns[2] = Vector3Negate(matColumns[2]);
}
// Set Scale
*scale = Vector3Scale(scl, stabilizer);
// Extract Rotation
Matrix rotationMatrix = { matColumns[0].x, matColumns[0].y, matColumns[0].z, 0,
matColumns[1].x, matColumns[1].y, matColumns[1].z, 0,
matColumns[2].x, matColumns[2].y, matColumns[2].z, 0,
0, 0, 0, 1 };
*rotation = QuaternionFromMatrix(rotationMatrix);
}
#if defined(__cplusplus) && !defined(RAYMATH_DISABLE_CPP_OPERATORS)

View file

@ -1927,6 +1927,115 @@ void SetConfigFlags(unsigned int flags)
// Module Functions Definition: File system
//----------------------------------------------------------------------------------
// Rename file (if exists)
// NOTE: Only rename file name required, not full path
int FileRename(const char *fileName, const char *fileRename)
{
int result = 0;
if (FileExists(fileName))
{
result = rename(fileName, fileRename);
}
else result = -1;
return result;
}
// Remove file (if exists)
int FileRemove(const char *fileName)
{
int result = 0;
if (FileExists(fileName))
{
result = remove(fileName);
}
else result = -1;
return result;
}
// Copy file from one path to another
// NOTE: If destination path does not exist, it is created!
int FileCopy(const char *srcPath, const char *dstPath)
{
int result = 0;
int srcDataSize = 0;
unsigned char *srcFileData = LoadFileData(srcPath, &srcDataSize);
// Create required paths if they do not exist
if (!DirectoryExists(GetDirectoryPath(dstPath)))
result = MakeDirectory(GetDirectoryPath(dstPath));
if (result == 0) // Directory created successfully (or already exists)
{
if ((srcFileData != NULL) && (srcDataSize > 0))
result = SaveFileData(dstPath, srcFileData, srcDataSize);
}
UnloadFileData(srcFileData);
return result;
}
// Move file from one directory to another
// NOTE: If dst directories do not exists they are created
int FileMove(const char *srcPath, const char *dstPath)
{
int result = 0;
if (FileExists(srcPath))
{
FileCopy(srcPath, dstPath);
FileRemove(srcPath);
}
else result = -1;
return result;
}
// Replace text in an existing file
// WARNING: DEPENDENCY: [rtext] module
int FileTextReplace(const char *fileName, const char *search, const char *replacement)
{
int result = 0;
char *fileText = NULL;
char *fileTextUpdated = { 0 };
#if defined(SUPPORT_MODULE_RTEXT)
if (FileExists(fileName))
{
fileText = LoadFileText(fileName);
fileTextUpdated = TextReplace(fileText, search, replacement);
result = SaveFileText(fileName, fileTextUpdated);
MemFree(fileTextUpdated);
UnloadFileText(fileText);
}
#else
TRACELOG(LOG_WARNING, "FILE: File text replace requires [rtext] module");
#endif
return result;
}
// Find text index position in existing file
// WARNING: DEPENDENCY: [rtext] module
int FileTextFindIndex(const char *fileName, const char *search)
{
int result = -1;
if (FileExists(fileName))
{
char *fileText = LoadFileText(fileName);
char *ptr = strstr(fileText, search);
if (ptr != NULL) result = (int)(ptr - fileText);
UnloadFileText(fileText);
}
return result;
}
// Check if the file exists
bool FileExists(const char *fileName)
{
@ -2054,6 +2163,21 @@ int GetFileLength(const char *fileName)
return size;
}
// Get file modification time (last write time)
long GetFileModTime(const char *fileName)
{
struct stat result = { 0 };
long modTime = 0;
if (stat(fileName, &result) == 0)
{
time_t mod = result.st_mtime;
modTime = (long)mod;
}
return modTime;
}
// Get pointer to extension for a filename string (includes the dot: .png)
// WARNING: We just get the ptr but not the extension as a separate string
const char *GetFileExtension(const char *fileName)
@ -2318,8 +2442,8 @@ FilePathList LoadDirectoryFiles(const char *dirPath)
// Memory allocation for dirFileCount
files.capacity = fileCounter;
files.paths = (char **)RL_MALLOC(files.capacity*sizeof(char *));
for (unsigned int i = 0; i < files.capacity; i++) files.paths[i] = (char *)RL_MALLOC(MAX_FILEPATH_LENGTH*sizeof(char));
files.paths = (char **)RL_CALLOC(files.capacity, sizeof(char *));
for (unsigned int i = 0; i < files.capacity; i++) files.paths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
closedir(dir);
@ -2367,7 +2491,7 @@ void UnloadDirectoryFiles(FilePathList files)
// Create directories (including full path requested), returns 0 on success
int MakeDirectory(const char *dirPath)
{
if ((dirPath == NULL) || (dirPath[0] == '\0')) return 1; // Path is not valid
if ((dirPath == NULL) || (dirPath[0] == '\0')) return -1; // Path is not valid
if (DirectoryExists(dirPath)) return 0; // Path already exists (is valid)
// Copy path string to avoid modifying original
@ -2392,8 +2516,11 @@ int MakeDirectory(const char *dirPath)
// Create final directory
if (!DirectoryExists(pathcpy)) MKDIR(pathcpy);
RL_FREE(pathcpy);
// In case something failed and requested directory
// was not successfully created, return -1
if (!DirectoryExists(dirPath)) return -1;
return 0;
}
@ -2513,22 +2640,6 @@ void UnloadDroppedFiles(FilePathList files)
}
}
// Get file modification time (last write time)
long GetFileModTime(const char *fileName)
{
struct stat result = { 0 };
long modTime = 0;
if (stat(fileName, &result) == 0)
{
time_t mod = result.st_mtime;
modTime = (long)mod;
}
return modTime;
}
//----------------------------------------------------------------------------------
// Module Functions Definition: Compression and Encoding
//----------------------------------------------------------------------------------
@ -2563,19 +2674,19 @@ unsigned char *DecompressData(const unsigned char *compData, int compDataSize, i
#if defined(SUPPORT_COMPRESSION_API)
// Decompress data from a valid DEFLATE stream
unsigned char *data0 = (unsigned char *)RL_CALLOC(MAX_DECOMPRESSION_SIZE*1024*1024, 1);
int length = sinflate(data, MAX_DECOMPRESSION_SIZE*1024*1024, compData, compDataSize);
int size = sinflate(data0, MAX_DECOMPRESSION_SIZE*1024*1024, compData, compDataSize);
// WARNING: RL_REALLOC can make (and leave) data copies in memory,
// WARNING: RL_REALLOC can make (and leave) data copies in memory,
// that can be a security concern in case of compression of sensitive data
// So, we use a second buffer to copy data manually, wiping original buffer memory
data = (unsigned char *)RL_CALLOC(length, 1);
memcpy(data, data0, length);
data = (unsigned char *)RL_CALLOC(size, 1);
memcpy(data, data0, size);
memset(data0, 0, MAX_DECOMPRESSION_SIZE*1024*1024); // Wipe memory, is memset() safe?
RL_FREE(data0);
TRACELOG(LOG_INFO, "SYSTEM: Decompress data: Comp. size: %i -> Original size: %i", compDataSize, length);
*dataSize = length;
TRACELOG(LOG_INFO, "SYSTEM: Decompress data: Comp. size: %i -> Original size: %i", compDataSize, size);
*dataSize = size;
#endif
return data;
@ -2671,13 +2782,25 @@ unsigned char *DecodeDataBase64(const char *text, int *outputSize)
for (int i = 0; i < dataSize;)
{
// Every 4 sixtets must generate 3 octets
if ((i + 2) >= dataSize)
{
TRACELOG(LOG_WARNING, "BASE64: Decoding error: Input data size is not valid");
break;
}
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 sixtetC = (((i + 2) < dataSize) && (unsigned char)text[i + 2] != '=')? base64DecodeTable[(unsigned char)text[i + 2]] : 0;
unsigned int sixtetD = (((i + 3) < dataSize) && (unsigned char)text[i + 3] != '=')? base64DecodeTable[(unsigned char)text[i + 3]] : 0;
unsigned int octetPack = (sixtetA << 18) | (sixtetB << 12) | (sixtetC << 6) | sixtetD;
if ((outputCount + 3) > maxOutputSize)
{
TRACELOG(LOG_WARNING, "BASE64: Decoding error: Output data size is too small");
break;
}
decodedData[outputCount + 0] = (octetPack >> 16) & 0xff;
decodedData[outputCount + 1] = (octetPack >> 8) & 0xff;
decodedData[outputCount + 2] = octetPack & 0xff;
@ -2891,7 +3014,7 @@ unsigned int *ComputeSHA1(unsigned char *data, int dataSize)
for (int offset = 0; offset < newDataSize; offset += (512/8))
{
// Break chunk into sixteen 32-bit words w[j], 0 <= j <= 15
unsigned int w[80] = {0};
unsigned int w[80] = { 0 };
for (int i = 0; i < 16; i++)
{
w[i] = (msg[offset + (i*4) + 0] << 24) |
@ -3006,7 +3129,7 @@ AutomationEventList LoadAutomationEventList(const char *fileName)
char *result = fgets(buffer, 256, raeFile);
if (result != buffer) TRACELOG(LOG_WARNING, "AUTOMATION: [%s] Issue reading line to buffer", fileName);
while (!feof(raeFile))
{
switch (buffer[0])

View file

@ -870,6 +870,7 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
#elif defined(GRAPHICS_API_OPENGL_ES2)
// NOTE: OpenGL ES 2.0 can be enabled on Desktop platforms,
// in that case, functions are loaded from a custom glad for OpenGL ES 2.0
// TODO: OpenGL ES 2.0 support shouldn't be platform-dependant, neither require GLAD
#if defined(PLATFORM_DESKTOP_GLFW) || defined(PLATFORM_DESKTOP_SDL)
#define GLAD_GLES2_IMPLEMENTATION
#include "external/glad_gles2.h"
@ -889,7 +890,7 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
#endif
#endif
#include <stdlib.h> // Required for: malloc(), free()
#include <stdlib.h> // Required for: calloc(), free()
#include <string.h> // Required for: strcmp(), strlen() [Used in rlglInit(), on extensions loading]
#include <math.h> // Required for: sqrtf(), sinf(), cosf(), floor(), log()
@ -1066,6 +1067,7 @@ typedef struct rlglData {
Matrix stack[RL_MAX_MATRIX_STACK_SIZE];// Matrix stack for push/pop
int stackCounter; // Matrix stack counter
unsigned int currentTextureId; // Current texture id to be used on glBegin
unsigned int defaultTextureId; // Default texture used on shapes/poly drawing (required by shader)
unsigned int activeTextureId[RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS]; // Active texture ids to be enabled on batch drawing (0 active by default)
unsigned int defaultVShaderId; // Default vertex shader id (used by default shader program)
@ -1484,8 +1486,8 @@ void rlBegin(int mode)
if (RLGL.currentBatch->drawCounter >= RL_DEFAULT_BATCH_DRAWCALLS) rlDrawRenderBatch(RLGL.currentBatch);
RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode = mode;
RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount = 0;
RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId = RLGL.State.defaultTextureId;
RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId = RLGL.State.currentTextureId;
RLGL.State.currentTextureId = RLGL.State.defaultTextureId;
}
}
@ -1650,6 +1652,7 @@ void rlSetTexture(unsigned int id)
{
rlDrawRenderBatch(RLGL.currentBatch);
}
RLGL.State.currentTextureId = RLGL.State.defaultTextureId;
#endif
}
else
@ -1657,6 +1660,7 @@ void rlSetTexture(unsigned int id)
#if defined(GRAPHICS_API_OPENGL_11)
rlEnableTexture(id);
#else
RLGL.State.currentTextureId = id;
if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId != id)
{
if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount > 0)
@ -1675,6 +1679,9 @@ void rlSetTexture(unsigned int id)
RLGL.State.vertexCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment;
RLGL.currentBatch->drawCounter++;
RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode = RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 2].mode;
}
}
@ -2256,6 +2263,7 @@ void rlglInit(int width, int height)
// Init default white texture
unsigned char pixels[4] = { 255, 255, 255, 255 }; // 1 pixel RGBA (4 bytes)
RLGL.State.defaultTextureId = rlLoadTexture(pixels, 1, 1, RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1);
RLGL.State.currentTextureId = RLGL.State.defaultTextureId;
if (RLGL.State.defaultTextureId != 0) TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Default texture loaded successfully", RLGL.State.defaultTextureId);
else TRACELOG(RL_LOG_WARNING, "TEXTURE: Failed to load default texture");
@ -2429,7 +2437,7 @@ void rlLoadExtensions(void *loader)
// Get supported extensions list
GLint numExt = 0;
const char **extList = (const char **)RL_MALLOC(512*sizeof(const char *)); // Allocate 512 strings pointers (2 KB)
const char **extList = (const char **)RL_CALLOC(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
@ -2473,7 +2481,7 @@ void rlLoadExtensions(void *loader)
}
// Check instanced rendering support
if (strstr(extList[i], (const char*)"instanced_arrays") != NULL) // Broad check for instanced_arrays
if (strstr(extList[i], (const char *)"instanced_arrays") != NULL) // Broad check for instanced_arrays
{
// Specific check
if (strcmp(extList[i], (const char *)"GL_ANGLE_instanced_arrays") == 0) // ANGLE
@ -2506,7 +2514,7 @@ void rlLoadExtensions(void *loader)
glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedEXT");
glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedEXT");
}
else if (strcmp(extList[i], (const char*)"GL_NV_draw_instanced") == 0)
else if (strcmp(extList[i], (const char *)"GL_NV_draw_instanced") == 0)
{
glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedNV");
glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedNV");
@ -2741,21 +2749,21 @@ rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements)
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Initialize CPU (RAM) vertex buffers (position, texcoord, color data and indexes)
//--------------------------------------------------------------------------------------------
batch.vertexBuffer = (rlVertexBuffer *)RL_MALLOC(numBuffers*sizeof(rlVertexBuffer));
batch.vertexBuffer = (rlVertexBuffer *)RL_CALLOC(numBuffers, sizeof(rlVertexBuffer));
for (int i = 0; i < numBuffers; i++)
{
batch.vertexBuffer[i].elementCount = bufferElements;
batch.vertexBuffer[i].vertices = (float *)RL_MALLOC(bufferElements*3*4*sizeof(float)); // 3 float by vertex, 4 vertex by quad
batch.vertexBuffer[i].texcoords = (float *)RL_MALLOC(bufferElements*2*4*sizeof(float)); // 2 float by texcoord, 4 texcoord by quad
batch.vertexBuffer[i].normals = (float *)RL_MALLOC(bufferElements*3*4*sizeof(float)); // 3 float by vertex, 4 vertex by quad
batch.vertexBuffer[i].colors = (unsigned char *)RL_MALLOC(bufferElements*4*4*sizeof(unsigned char)); // 4 float by color, 4 colors by quad
batch.vertexBuffer[i].vertices = (float *)RL_CALLOC(bufferElements*3*4, sizeof(float)); // 3 float by vertex, 4 vertex by quad
batch.vertexBuffer[i].texcoords = (float *)RL_CALLOC(bufferElements*2*4, sizeof(float)); // 2 float by texcoord, 4 texcoord by quad
batch.vertexBuffer[i].normals = (float *)RL_CALLOC(bufferElements*3*4, sizeof(float)); // 3 float by vertex, 4 vertex by quad
batch.vertexBuffer[i].colors = (unsigned char *)RL_CALLOC(bufferElements*4*4, sizeof(unsigned char)); // 4 float by color, 4 colors by quad
#if defined(GRAPHICS_API_OPENGL_33)
batch.vertexBuffer[i].indices = (unsigned int *)RL_MALLOC(bufferElements*6*sizeof(unsigned int)); // 6 int by quad (indices)
batch.vertexBuffer[i].indices = (unsigned int *)RL_CALLOC(bufferElements*6, sizeof(unsigned int)); // 6 int by quad (indices)
#endif
#if defined(GRAPHICS_API_OPENGL_ES2)
batch.vertexBuffer[i].indices = (unsigned short *)RL_MALLOC(bufferElements*6*sizeof(unsigned short)); // 6 int by quad (indices)
batch.vertexBuffer[i].indices = (unsigned short *)RL_CALLOC(bufferElements*6, sizeof(unsigned short)); // 6 int by quad (indices)
#endif
for (int j = 0; j < (3*4*bufferElements); j++) batch.vertexBuffer[i].vertices[j] = 0.0f;
@ -2843,7 +2851,7 @@ rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements)
// Init draw calls tracking system
//--------------------------------------------------------------------------------------------
batch.draws = (rlDrawCall *)RL_MALLOC(RL_DEFAULT_BATCH_DRAWCALLS*sizeof(rlDrawCall));
batch.draws = (rlDrawCall *)RL_CALLOC(RL_DEFAULT_BATCH_DRAWCALLS, sizeof(rlDrawCall));
for (int i = 0; i < RL_DEFAULT_BATCH_DRAWCALLS; i++)
{
@ -3649,7 +3657,7 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format)
if ((glInternalFormat != 0) && (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB))
{
pixels = RL_MALLOC(size);
pixels = RL_CALLOC(size, 1);
glGetTexImage(GL_TEXTURE_2D, 0, glFormat, glType, pixels);
}
else TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] Data retrieval not suported for pixel format (%i)", id, format);
@ -3674,7 +3682,7 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, id, 0);
// We read data as RGBA because FBO texture is configured as RGBA, despite binding another texture format
pixels = (unsigned char *)RL_MALLOC(rlGetPixelDataSize(width, height, RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8));
pixels = RL_CALLOC(rlGetPixelDataSize(width, height, RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8), 1);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

View file

@ -1432,7 +1432,8 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
else rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices);
rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords);
if (mesh.normals) rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.animNormals);
if (mesh.animNormals) rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.animNormals);
else rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals);
rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors);
@ -3864,7 +3865,7 @@ void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float sca
{
Rectangle source = { 0.0f, 0.0f, (float)texture.width, (float)texture.height };
DrawBillboardRec(camera, texture, source, position, (Vector2) { scale*fabsf((float)source.width/source.height), scale }, tint);
DrawBillboardRec(camera, texture, source, position, (Vector2){ scale*fabsf((float)source.width/source.height), scale }, tint);
}
// Draw a billboard (part of a texture defined by a rectangle)
@ -4260,9 +4261,10 @@ static void BuildPoseFromParentJoints(BoneInfo *bones, int boneCount, Transform
continue;
}
transforms[i].rotation = QuaternionMultiply(transforms[bones[i].parent].rotation, transforms[i].rotation);
transforms[i].scale = Vector3Multiply(transforms[i].scale, transforms[bones[i].parent].scale);
transforms[i].translation = Vector3Multiply(transforms[i].translation, transforms[bones[i].parent].scale);
transforms[i].translation = Vector3RotateByQuaternion(transforms[i].translation, transforms[bones[i].parent].rotation);
transforms[i].translation = Vector3Add(transforms[i].translation, transforms[bones[i].parent].translation);
transforms[i].scale = Vector3Multiply(transforms[i].scale, transforms[bones[i].parent].scale);
}
}
}
@ -5535,7 +5537,7 @@ static Model LoadGLTF(const char *fileName)
cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
// WARNING: SPECS: POSITION accessor MUST have its min and max properties defined
if (model.meshes[meshIndex].vertices != NULL) TRACELOG(LOG_WARNING, "MODEL: [%s] Vertices attribute data already loaded", fileName);
else
{
@ -5881,7 +5883,7 @@ static Model LoadGLTF(const char *fileName)
};
MatrixDecompose(worldMatrix, &(model.bindPose[i].translation), &(model.bindPose[i].rotation), &(model.bindPose[i].scale));
}
if (data->skins_count > 1) TRACELOG(LOG_WARNING, "MODEL: [%s] can only load one skin (armature) per model, but gltf skins_count == %i", fileName, data->skins_count);
}
@ -6237,6 +6239,18 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
*animCount = (int)data->animations_count;
animations = (ModelAnimation *)RL_CALLOC(data->animations_count, sizeof(ModelAnimation));
Transform worldTransform = { 0 };
cgltf_float cgltf_worldTransform[16] = { 0 };
cgltf_node *node = skin.joints[0];
cgltf_node_transform_world(node->parent, cgltf_worldTransform);
Matrix worldMatrix = {
cgltf_worldTransform[0], cgltf_worldTransform[4], cgltf_worldTransform[8], cgltf_worldTransform[12],
cgltf_worldTransform[1], cgltf_worldTransform[5], cgltf_worldTransform[9], cgltf_worldTransform[13],
cgltf_worldTransform[2], cgltf_worldTransform[6], cgltf_worldTransform[10], cgltf_worldTransform[14],
cgltf_worldTransform[3], cgltf_worldTransform[7], cgltf_worldTransform[11], cgltf_worldTransform[15]
};
MatrixDecompose(worldMatrix, &worldTransform.translation, &worldTransform.rotation, &worldTransform.scale);
for (unsigned int i = 0; i < data->animations_count; i++)
{
animations[i].bones = LoadBoneInfoGLTF(skin, &animations[i].boneCount);
@ -6355,6 +6369,13 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
};
}
Transform* root = &animations[i].framePoses[j][0];
root->rotation = QuaternionMultiply(worldTransform.rotation, root->rotation);
root->scale = Vector3Multiply(root->scale, worldTransform.scale);
root->translation = Vector3Multiply(root->translation, worldTransform.scale);
root->translation = Vector3RotateByQuaternion(root->translation, worldTransform.rotation);
root->translation = Vector3Add(root->translation, worldTransform.translation);
BuildPoseFromParentJoints(animations[i].bones, animations[i].boneCount, animations[i].framePoses[j]);
}
@ -6577,7 +6598,7 @@ static Model LoadM3D(const char *fileName)
if (k + 1 >= model.meshCount)
{
model.meshCount++;
// Create a second buffer for mesh re-allocation
Mesh *tempMeshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
memcpy(tempMeshes, model.meshes, (model.meshCount - 1)*sizeof(Mesh));

View file

@ -760,7 +760,7 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
// NOTE: For optimum results, bitmap font should be generated at base pixel size
for (int p = 0; p < cpWidth*cpHeight; p++)
{
if (((unsigned char *)glyphs[k].image.data)[p] < FONT_BITMAP_ALPHA_THRESHOLD)
if (((unsigned char *)glyphs[k].image.data)[p] < FONT_BITMAP_ALPHA_THRESHOLD)
((unsigned char *)glyphs[k].image.data)[p] = 0;
else ((unsigned char *)glyphs[k].image.data)[p] = 255;
}
@ -774,7 +774,7 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
// WARNING: Glyph not found on font, optionally use a fallback glyph
}
}
if (glyphCounter < codepointCount) TRACELOG(LOG_WARNING, "FONT: Requested codepoints glyphs found: [%i/%i]", k, codepointCount);
}
else TRACELOG(LOG_WARNING, "FONT: Failed to process TTF font data");
@ -1448,36 +1448,39 @@ Rectangle GetGlyphAtlasRec(Font font, int codepoint)
// Text strings management functions
//----------------------------------------------------------------------------------
// Load text as separate lines ('\n')
// WARNING: There is a limit set for number of lines and line-size
// NOTE: Returned lines end with null terminator '\0'
char **LoadTextLines(const char *text, int *count)
{
#define MAX_TEXTLINES_COUNT 512
#define MAX_TEXTLINES_LINE_LEN 512
int lineCount = 1;
int textSize = strlen(text);
char **lines = (char **)RL_CALLOC(MAX_TEXTLINES_COUNT, sizeof(char *));
for (int i = 0; i < MAX_TEXTLINES_COUNT; i++) lines[i] = (char *)RL_CALLOC(MAX_TEXTLINES_LINE_LEN, 1);
int textSize = (int)strlen(text);
int k = 0;
for (int i = 0, len = 0; (i < textSize) && (k < MAX_TEXTLINES_COUNT); i++)
// Text pass to get required line count
for (int i = 0; i < textSize; i++)
{
if ((text[i] == '\n') || (len == (MAX_TEXTLINES_LINE_LEN - 1)))
{
strncpy(lines[k], &text[i - len], len);
len = 0;
k++;
}
else len++;
if (text[i] == '\n') lineCount++;
}
*count += k;
char **lines = (char **)RL_CALLOC(lineCount, sizeof(char *));
for (int i = 0, l = 0, lineLen = 0; i <= textSize; i++)
{
if ((text[i] == '\n') || (text[i] == '\0'))
{
lines[l] = (char *)RL_CALLOC(lineLen + 1, 1);
strncpy(lines[l], &text[i - lineLen], lineLen);
lineLen = 0;
l++;
}
else lineLen++;
}
*count = lineCount;
return lines;
}
// Unload text lines
void UnloadTextLines(char **lines)
void UnloadTextLines(char **lines, int lineCount)
{
for (int i = 0; i < MAX_TEXTLINES_COUNT; i++) RL_FREE(lines[i]);
for (int i = 0; i < lineCount; i++) RL_FREE(lines[i]);
RL_FREE(lines);
}
@ -1646,34 +1649,79 @@ const char *TextSubtext(const char *text, int position, int length)
return buffer;
}
// Remove text spaces, concat words
const char *TextRemoveSpaces(const char *text)
{
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
if (text != NULL)
{
// Avoid copying the ' ' characters
for (int i = 0, j = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); i++)
{
if (text[i] != ' ') { buffer[j] = text[i]; j++; }
}
}
return buffer;
}
// Get text between two strings
char *GetTextBetween(const char *text, const char *begin, const char *end)
{
#define MAX_TEXT_BETWEEN_SIZE 1024
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
int beginIndex = TextFindIndex(text, begin);
if (beginIndex > -1)
{
int beginLen = strlen(begin);
int endIndex = TextFindIndex(text + beginIndex + beginLen, end);
if (endIndex > -1)
{
endIndex += (beginIndex + beginLen);
int len = (endIndex - beginIndex - beginLen);
if (len < (MAX_TEXT_BETWEEN_SIZE - 1)) strncpy(buffer, text + beginIndex + beginLen, len);
else strncpy(buffer, text + beginIndex + beginLen, MAX_TEXT_BETWEEN_SIZE - 1);
}
}
return buffer;
}
// Replace text string
// REQUIRES: strstr(), strncpy(), strcpy()
// TODO: If (replacement == NULL) remove "search" text
// WARNING: Allocated memory must be manually freed
char *TextReplace(const char *text, const char *replace, const char *by)
char *TextReplace(const char *text, const char *search, const char *replacement)
{
// Sanity checks and initialization
if (!text || !replace || !by) return NULL;
char *result = NULL;
if (!text || !search) return NULL; // Sanity check
char *insertPoint = NULL; // Next insert point
char *temp = NULL; // Temp pointer
int replaceLen = 0; // Replace string length of (the string to remove)
int byLen = 0; // Replacement length (the string to replace by)
int lastReplacePos = 0; // Distance between replace and end of last replace
int searchLen = 0; // Search string length of (the string to remove)
int replaceLen = 0; // Replacement length (the string to replace by)
int lastReplacePos = 0; // Distance between next search and end of last replace
int count = 0; // Number of replacements
replaceLen = TextLength(replace);
if (replaceLen == 0) return NULL; // Empty replace causes infinite loop during count
searchLen = TextLength(search);
if (searchLen == 0) return NULL; // Empty search causes infinite loop during count
byLen = TextLength(by);
replaceLen = TextLength(replacement);
// Count the number of replacements needed
insertPoint = (char *)text;
for (count = 0; (temp = strstr(insertPoint, replace)); count++) insertPoint = temp + replaceLen;
for (count = 0; (temp = strstr(insertPoint, search)); count++) insertPoint = temp + searchLen;
// Allocate returning string and point temp to it
temp = result = (char *)RL_MALLOC(TextLength(text) + (byLen - replaceLen)*count + 1);
temp = result = (char *)RL_MALLOC(TextLength(text) + (replaceLen - searchLen)*count + 1);
if (!result) return NULL; // Memory could not be allocated
@ -1683,11 +1731,11 @@ char *TextReplace(const char *text, const char *replace, const char *by)
// - 'text' points to the remainder of text after "end of replace"
while (count--)
{
insertPoint = strstr(text, replace);
insertPoint = strstr(text, search);
lastReplacePos = (int)(insertPoint - text);
temp = strncpy(temp, text, lastReplacePos) + lastReplacePos;
temp = strcpy(temp, by) + byLen;
text += lastReplacePos + replaceLen; // Move to next "end of replace"
temp = strcpy(temp, replacement) + replaceLen;
text += lastReplacePos + searchLen; // Move to next "end of replace"
}
// Copy remaind text part after replacement to result (pointed by moving temp)
@ -1696,6 +1744,41 @@ char *TextReplace(const char *text, const char *replace, const char *by)
return result;
}
// Replace text between two specific strings
// REQUIRES: strlen(), strncpy()
// NOTE: If (replacement == NULL) remove "begin"[ ]"end" text
// WARNING: Returned string must be freed by user
char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement)
{
char *result = NULL;
if (!text || !begin || !end) return NULL; // Sanity check
int beginIndex = TextFindIndex(text, begin);
if (beginIndex > -1)
{
int beginLen = strlen(begin);
int endIndex = TextFindIndex(text + beginIndex + beginLen, end);
if (endIndex > -1)
{
endIndex += (beginIndex + beginLen);
int textLen = strlen(text);
int replaceLen = (replacement == NULL)? 0 : strlen(replacement);
int toreplaceLen = endIndex - beginIndex - beginLen;
result = (char *)RL_CALLOC(textLen + replaceLen - toreplaceLen + 1, sizeof(char));
strncpy(result, text, beginIndex + beginLen); // Copy first text part
if (replacement != NULL) strncpy(result + beginIndex + beginLen, replacement, replaceLen); // Copy replacement (if provided)
strncpy(result + beginIndex + beginLen + replaceLen, text + endIndex, textLen - endIndex); // Copy end text part
}
}
return result;
}
// Insert text in a specific position, moves all text forward
// WARNING: Allocated memory must be manually freed
char *TextInsert(const char *text, const char *insert, int position)
@ -1758,11 +1841,11 @@ 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 char *result[MAX_TEXTSPLIT_COUNT] = { NULL };
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
static char *buffers[MAX_TEXTSPLIT_COUNT] = { NULL }; // Pointers to buffer[] text data
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; // Text data with '\0' separators
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
result[0] = buffer;
buffers[0] = buffer;
int counter = 0;
if (text != NULL)
@ -1777,7 +1860,7 @@ char **TextSplit(const char *text, char delimiter, int *count)
else if (buffer[i] == delimiter)
{
buffer[i] = '\0'; // Set an end of string at this point
result[counter] = buffer + i + 1;
buffers[counter] = buffer + i + 1;
counter++;
if (counter == MAX_TEXTSPLIT_COUNT) break;
@ -1786,7 +1869,7 @@ char **TextSplit(const char *text, char delimiter, int *count)
}
*count = counter;
return result;
return buffers;
}
// Append text at specific position and move cursor
@ -1800,11 +1883,11 @@ void TextAppend(char *text, const char *append, int *position)
// Find first text occurrence within a string
// REQUIRES: strstr()
int TextFindIndex(const char *text, const char *find)
int TextFindIndex(const char *text, const char *search)
{
int position = -1;
char *ptr = strstr(text, find);
char *ptr = strstr(text, search);
if (ptr != NULL) position = (int)(ptr - text);
@ -1882,7 +1965,7 @@ char *TextToPascal(const char *text)
// WARNING: Limited functionality, only basic characters set
char *TextToSnake(const char *text)
{
static char buffer[MAX_TEXT_BUFFER_LENGTH] = {0};
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
if (text != NULL)
@ -1910,7 +1993,7 @@ char *TextToSnake(const char *text)
// WARNING: Limited functionality, only basic characters set
char *TextToCamel(const char *text)
{
static char buffer[MAX_TEXT_BUFFER_LENGTH] = {0};
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
if (text != NULL)

View file

@ -592,11 +592,10 @@ Image LoadImageFromTexture(Texture2D texture)
// Load image from screen buffer and (screenshot)
Image LoadImageFromScreen(void)
{
Vector2 scale = GetWindowScaleDPI();
Image image = { 0 };
image.width = (int)(GetScreenWidth()*scale.x);
image.height = (int)(GetScreenHeight()*scale.y);
image.width = (int)(GetRenderWidth());
image.height = (int)(GetRenderHeight());
image.mipmaps = 1;
image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
image.data = rlReadScreenPixels(image.width, image.height);
@ -702,7 +701,7 @@ bool ExportImage(Image image, const char *fileName)
result = SaveFileData(fileName, image.data, GetPixelDataSize(image.width, image.height, image.format));
}
else TRACELOG(LOG_WARNING, "IMAGE: Export image format requested not supported");
if (allocatedData) RL_FREE(imgData);
#endif // SUPPORT_IMAGE_EXPORT

View file

@ -34,7 +34,7 @@
<link rel="shortcut icon" href="https://www.raylib.com/favicon.ico">
<style>
body { font-family: arial; margin: 0; padding: none; }
body { font-family: arial; margin: 0; padding: unset; }
#header {
width: 100%;

View file

@ -203,7 +203,7 @@ unsigned char *LoadFileData(const char *fileName, int *dataSize)
if (size > 0)
{
data = (unsigned char *)RL_MALLOC(size*sizeof(unsigned char));
data = (unsigned char *)RL_CALLOC(size, sizeof(unsigned char));
if (data != NULL)
{
@ -366,7 +366,7 @@ char *LoadFileText(const char *fileName)
if (size > 0)
{
text = (char *)RL_MALLOC((size + 1)*sizeof(char));
text = (char *)RL_CALLOC(size + 1, sizeof(char));
if (text != NULL)
{