Merge branch 'master' into flag-macros
This commit is contained in:
commit
bcde2885d1
18 changed files with 19685 additions and 17673 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -454,6 +454,7 @@ void UntrackAudioBuffer(AudioBuffer *buffer);
|
|||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition - Audio Device initialization and Closing
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Initialize audio device
|
||||
void InitAudioDevice(void)
|
||||
{
|
||||
|
|
|
|||
79
src/raylib.h
79
src/raylib.h
|
|
@ -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
|
||||
|
|
|
|||
118
src/raymath.h
118
src/raymath.h
|
|
@ -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)
|
||||
|
|
|
|||
185
src/rcore.c
185
src/rcore.c
|
|
@ -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])
|
||||
|
|
|
|||
40
src/rlgl.h
40
src/rlgl.h
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
175
src/rtext.c
175
src/rtext.c
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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%;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue