mirror of
https://github.com/raysan5/raylib.git
synced 2025-12-25 10:22:33 -05:00
Merge branch 'raysan5:master' into safety-comments
This commit is contained in:
@ -8,7 +8,7 @@ include(JoinPaths)
|
||||
|
||||
# Sets build type if not set by now
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
if(RAYLIB_IS_MAIN)
|
||||
if(PROJECT_IS_TOP_LEVEL)
|
||||
set(default_build_type Debug)
|
||||
else()
|
||||
message(WARNING "Default build type is not set (CMAKE_BUILD_TYPE)")
|
||||
|
||||
@ -638,7 +638,7 @@ OBJS = rcore.o \
|
||||
rshapes.o \
|
||||
rtextures.o \
|
||||
rtext.o \
|
||||
utils.o
|
||||
utils.o
|
||||
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
|
||||
ifeq ($(USE_EXTERNAL_GLFW),FALSE)
|
||||
|
||||
@ -104,7 +104,7 @@
|
||||
#define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported
|
||||
#define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported
|
||||
#define MAX_GAMEPADS 4 // Maximum number of gamepads supported
|
||||
#define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad)
|
||||
#define MAX_GAMEPAD_AXES 8 // Maximum number of axes supported (per gamepad)
|
||||
#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
|
||||
#define MAX_GAMEPAD_VIBRATION_TIME 2.0f // Maximum vibration time in seconds
|
||||
#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
|
||||
@ -136,8 +136,8 @@
|
||||
|
||||
#define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported
|
||||
|
||||
#define RL_CULL_DISTANCE_NEAR 0.01 // Default projection matrix near cull distance
|
||||
#define RL_CULL_DISTANCE_FAR 1000.0 // Default projection matrix far cull distance
|
||||
#define RL_CULL_DISTANCE_NEAR 0.001 // Default projection matrix near cull distance
|
||||
#define RL_CULL_DISTANCE_FAR 10000.0 // Default projection matrix far cull distance
|
||||
|
||||
// Default shader vertex attribute locations
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0
|
||||
@ -189,7 +189,7 @@
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module: rtextures - Configuration Flags
|
||||
//------------------------------------------------------------------------------------
|
||||
// Selecte desired fileformats to be supported for image data loading
|
||||
// Selected desired fileformats to be supported for image data loading
|
||||
#define SUPPORT_FILEFORMAT_PNG 1
|
||||
//#define SUPPORT_FILEFORMAT_BMP 1
|
||||
//#define SUPPORT_FILEFORMAT_TGA 1
|
||||
|
||||
21452
src/external/RGFW.h
vendored
21452
src/external/RGFW.h
vendored
File diff suppressed because it is too large
Load Diff
7
src/external/jar_xm.h
vendored
7
src/external/jar_xm.h
vendored
@ -232,6 +232,13 @@ uint64_t jar_xm_get_remaining_samples(jar_xm_context_t* ctx);
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
// Undefine DEBUG to avoid external redefinition warnings/conflicts
|
||||
// This is probably a common definition for
|
||||
// many external build systems' debug configurations
|
||||
#undef DEBUG
|
||||
#endif
|
||||
|
||||
#if JAR_XM_DEBUG //JAR_XM_DEBUG defined as 0
|
||||
#include <stdio.h>
|
||||
#define DEBUG(fmt, ...) do { \
|
||||
|
||||
1813
src/external/miniaudio.h
vendored
1813
src/external/miniaudio.h
vendored
File diff suppressed because it is too large
Load Diff
2
src/external/rprand.h
vendored
2
src/external/rprand.h
vendored
@ -90,7 +90,7 @@
|
||||
#define RPRAND_FREE(ptr) free(ptr)
|
||||
#endif
|
||||
|
||||
// Simple log system to avoid RPNG_LOG() calls if required
|
||||
// Simple log system to avoid log calls if required
|
||||
// NOTE: Avoiding those calls, also avoids const strings memory usage
|
||||
#define RPRAND_SHOW_LOG_INFO
|
||||
#if defined(RPNG_SHOW_LOG_INFO)
|
||||
|
||||
9
src/external/sinfl.h
vendored
9
src/external/sinfl.h
vendored
@ -171,10 +171,11 @@ extern int zsinflate(void *out, int cap, const void *in, int size);
|
||||
|
||||
static int
|
||||
sinfl_bsr(unsigned n) {
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
_BitScanReverse(&n, n);
|
||||
return n;
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#ifdef _MSC_VER
|
||||
unsigned long uln = 0;
|
||||
_BitScanReverse(&uln, n);
|
||||
return (int)(uln);
|
||||
#else // defined(__GNUC__) || defined(__clang__) || defined(__TINYC__)
|
||||
return 31 - __builtin_clz(n);
|
||||
#endif
|
||||
}
|
||||
|
||||
8
src/external/stb_truetype.h
vendored
8
src/external/stb_truetype.h
vendored
@ -1863,11 +1863,11 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
|
||||
stbtt_vertex* v = &comp_verts[i];
|
||||
stbtt_vertex_type x,y;
|
||||
x=v->x; y=v->y;
|
||||
v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
|
||||
v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
|
||||
v->x = (stbtt_vertex_type)(mtx[0]*x + mtx[2]*y + mtx[4]*m);
|
||||
v->y = (stbtt_vertex_type)(mtx[1]*x + mtx[3]*y + mtx[5]*n);
|
||||
x=v->cx; y=v->cy;
|
||||
v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
|
||||
v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
|
||||
v->cx = (stbtt_vertex_type)(mtx[0]*x + mtx[2]*y + mtx[4]*m);
|
||||
v->cy = (stbtt_vertex_type)(mtx[1]*x + mtx[3]*y + mtx[5]*n);
|
||||
}
|
||||
// Append vertices.
|
||||
tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata);
|
||||
|
||||
@ -70,6 +70,16 @@ typedef struct {
|
||||
EGLConfig config; // Graphic config
|
||||
} PlatformData;
|
||||
|
||||
typedef struct {
|
||||
// Store data for both Hover and Touch events
|
||||
// Used to ignore Hover events which are interpreted as Touch events
|
||||
int32_t pointCount; // Number of touch points active
|
||||
int32_t pointId[MAX_TOUCH_POINTS]; // Point identifiers
|
||||
Vector2 position[MAX_TOUCH_POINTS]; // Touch position on screen
|
||||
|
||||
int32_t hoverPoints[MAX_TOUCH_POINTS]; // Hover Points
|
||||
} TouchRaw;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Global Variables Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
@ -246,6 +256,8 @@ static const KeyboardKey mapKeycode[KEYCODE_MAP_SIZE] = {
|
||||
KEY_KP_EQUAL // AKEYCODE_NUMPAD_EQUALS
|
||||
};
|
||||
|
||||
static TouchRaw touchRaw = { 0 };
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Internal Functions Declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
@ -337,7 +349,7 @@ void MinimizeWindow(void)
|
||||
TRACELOG(LOG_WARNING, "MinimizeWindow() not available on target platform");
|
||||
}
|
||||
|
||||
// Set window state: not minimized/maximized
|
||||
// Restore window from being minimized/maximized
|
||||
void RestoreWindow(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform");
|
||||
@ -431,7 +443,7 @@ int GetMonitorCount(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get number of monitors
|
||||
// Get current monitor where window is placed
|
||||
int GetCurrentMonitor(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetCurrentMonitor() not implemented on target platform");
|
||||
@ -801,6 +813,8 @@ int InitPlatform(void)
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_TOUCH_POINTS; i++) touchRaw.hoverPoints[i] = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -859,7 +873,7 @@ static int InitGraphicsDevice(void)
|
||||
EGL_GREEN_SIZE, 8, // GREEN color bit depth (alternative: 6)
|
||||
EGL_BLUE_SIZE, 8, // BLUE color bit depth (alternative: 5)
|
||||
//EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI)
|
||||
EGL_DEPTH_SIZE, 16, // Depth buffer size (Required to use Depth testing!)
|
||||
EGL_DEPTH_SIZE, 24, // Depth buffer size (Required to use Depth testing!)
|
||||
//EGL_STENCIL_SIZE, 8, // Stencil buffer size
|
||||
EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA
|
||||
EGL_SAMPLES, samples, // 4x Antialiasing if activated (Free on MALI GPUs)
|
||||
@ -1269,25 +1283,85 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
||||
}
|
||||
|
||||
// Register touch points count
|
||||
CORE.Input.Touch.pointCount = AMotionEvent_getPointerCount(event);
|
||||
touchRaw.pointCount = AMotionEvent_getPointerCount(event);
|
||||
|
||||
for (int i = 0; (i < CORE.Input.Touch.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
||||
for (int i = 0; (i < touchRaw.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
||||
{
|
||||
// Register touch points id
|
||||
CORE.Input.Touch.pointId[i] = AMotionEvent_getPointerId(event, i);
|
||||
touchRaw.pointId[i] = AMotionEvent_getPointerId(event, i);
|
||||
|
||||
// Register touch points position
|
||||
CORE.Input.Touch.position[i] = (Vector2){ AMotionEvent_getX(event, i), AMotionEvent_getY(event, i) };
|
||||
touchRaw.position[i] = (Vector2){ AMotionEvent_getX(event, i), AMotionEvent_getY(event, i) };
|
||||
|
||||
// Normalize CORE.Input.Touch.position[i] for CORE.Window.screen.width and CORE.Window.screen.height
|
||||
float widthRatio = (float)(CORE.Window.screen.width + CORE.Window.renderOffset.x)/(float)CORE.Window.display.width;
|
||||
float heightRatio = (float)(CORE.Window.screen.height + CORE.Window.renderOffset.y)/(float)CORE.Window.display.height;
|
||||
CORE.Input.Touch.position[i].x = CORE.Input.Touch.position[i].x*widthRatio - (float)CORE.Window.renderOffset.x/2;
|
||||
CORE.Input.Touch.position[i].y = CORE.Input.Touch.position[i].y*heightRatio - (float)CORE.Window.renderOffset.y/2;
|
||||
touchRaw.position[i].x = touchRaw.position[i].x*widthRatio - (float)CORE.Window.renderOffset.x/2;
|
||||
touchRaw.position[i].y = touchRaw.position[i].y*heightRatio - (float)CORE.Window.renderOffset.y/2;
|
||||
}
|
||||
|
||||
int32_t action = AMotionEvent_getAction(event);
|
||||
unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
|
||||
int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
||||
|
||||
if (flags == AMOTION_EVENT_ACTION_HOVER_ENTER)
|
||||
{
|
||||
// The new pointer is hover
|
||||
// So add it to hoverPoints
|
||||
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
||||
{
|
||||
if (touchRaw.hoverPoints[i] == -1)
|
||||
{
|
||||
touchRaw.hoverPoints[i] = touchRaw.pointId[pointerIndex];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags == AMOTION_EVENT_ACTION_POINTER_UP) || (flags == AMOTION_EVENT_ACTION_UP) || (flags == AMOTION_EVENT_ACTION_HOVER_EXIT))
|
||||
{
|
||||
// One of the touchpoints is released, remove it from touch point arrays
|
||||
if (flags == AMOTION_EVENT_ACTION_HOVER_EXIT)
|
||||
{
|
||||
// If the touchPoint is hover, remove it from hoverPoints
|
||||
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
||||
{
|
||||
if (touchRaw.hoverPoints[i] == touchRaw.pointId[pointerIndex])
|
||||
{
|
||||
touchRaw.hoverPoints[i] = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = pointerIndex; (i < touchRaw.pointCount - 1) && (i < MAX_TOUCH_POINTS - 1); i++)
|
||||
{
|
||||
touchRaw.pointId[i] = touchRaw.pointId[i+1];
|
||||
touchRaw.position[i] = touchRaw.position[i+1];
|
||||
}
|
||||
touchRaw.pointCount--;
|
||||
}
|
||||
|
||||
int pointCount = 0;
|
||||
for (int i = 0; (i < touchRaw.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
||||
{
|
||||
// If the touchPoint is hover, Ignore it
|
||||
bool hover = false;
|
||||
for (int j = 0; j < MAX_TOUCH_POINTS; j++)
|
||||
{
|
||||
// Check if the touchPoint is in hoverPointers
|
||||
if (touchRaw.hoverPoints[j] == touchRaw.pointId[i])
|
||||
{
|
||||
hover = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hover) continue;
|
||||
|
||||
CORE.Input.Touch.pointId[pointCount] = touchRaw.pointId[i];
|
||||
CORE.Input.Touch.position[pointCount] = touchRaw.position[i];
|
||||
pointCount++;
|
||||
}
|
||||
CORE.Input.Touch.pointCount = pointCount;
|
||||
|
||||
#if defined(SUPPORT_GESTURES_SYSTEM)
|
||||
GestureEvent gestureEvent = { 0 };
|
||||
@ -1312,20 +1386,6 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
||||
ProcessGestureEvent(gestureEvent);
|
||||
#endif
|
||||
|
||||
int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
||||
|
||||
if (flags == AMOTION_EVENT_ACTION_POINTER_UP || flags == AMOTION_EVENT_ACTION_UP)
|
||||
{
|
||||
// One of the touchpoints is released, remove it from touch point arrays
|
||||
for (int i = pointerIndex; (i < CORE.Input.Touch.pointCount - 1) && (i < MAX_TOUCH_POINTS); i++)
|
||||
{
|
||||
CORE.Input.Touch.pointId[i] = CORE.Input.Touch.pointId[i+1];
|
||||
CORE.Input.Touch.position[i] = CORE.Input.Touch.position[i+1];
|
||||
}
|
||||
|
||||
CORE.Input.Touch.pointCount--;
|
||||
}
|
||||
|
||||
// When all touchpoints are tapped and released really quickly, this event is generated
|
||||
if (flags == AMOTION_EVENT_ACTION_CANCEL) CORE.Input.Touch.pointCount = 0;
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/**********************************************************************************************
|
||||
*
|
||||
* rcore_desktop - Functions to manage window, graphics device and inputs
|
||||
* rcore_desktop_glfw - Functions to manage window, graphics device and inputs
|
||||
*
|
||||
* PLATFORM: DESKTOP: GLFW
|
||||
* - Windows (Win32, Win64)
|
||||
@ -130,9 +130,9 @@ static void CursorEnterCallback(GLFWwindow *window, int enter);
|
||||
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
|
||||
static void *AllocateWrapper(size_t size, void *user); // GLFW3 GLFWallocatefun, wrapps around RL_MALLOC macro
|
||||
static void *ReallocateWrapper(void *block, size_t size, void *user); // GLFW3 GLFWreallocatefun, wrapps around RL_MALLOC macro
|
||||
static void DeallocateWrapper(void *block, void *user); // GLFW3 GLFWdeallocatefun, wraps around RL_FREE macro
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Declaration
|
||||
@ -292,7 +292,7 @@ void MinimizeWindow(void)
|
||||
glfwIconifyWindow(platform.handle);
|
||||
}
|
||||
|
||||
// Set window state: not minimized/maximized
|
||||
// Restore window from being minimized/maximized
|
||||
void RestoreWindow(void)
|
||||
{
|
||||
if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE)
|
||||
@ -307,6 +307,8 @@ void RestoreWindow(void)
|
||||
// Set window configuration state using flags
|
||||
void SetWindowState(unsigned int flags)
|
||||
{
|
||||
if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
|
||||
|
||||
// Check previous state and requested state to apply required changes
|
||||
// NOTE: In most cases the functions already change the flags internally
|
||||
|
||||
@ -574,7 +576,7 @@ void SetWindowIcons(Image *images, int count)
|
||||
else
|
||||
{
|
||||
int valid = 0;
|
||||
GLFWimage *icons = RL_CALLOC(count, sizeof(GLFWimage));
|
||||
GLFWimage *icons = (GLFWimage *)RL_CALLOC(count, sizeof(GLFWimage));
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
@ -736,7 +738,7 @@ int GetMonitorCount(void)
|
||||
return monitorCount;
|
||||
}
|
||||
|
||||
// Get number of monitors
|
||||
// Get current monitor where window is placed
|
||||
int GetCurrentMonitor(void)
|
||||
{
|
||||
int index = 0;
|
||||
@ -1236,7 +1238,7 @@ void PollInputEvents(void)
|
||||
}
|
||||
}
|
||||
|
||||
// Get current axis state
|
||||
// Get current state of axes
|
||||
const float *axes = state.axes;
|
||||
|
||||
for (int k = 0; (axes != NULL) && (k < GLFW_GAMEPAD_AXIS_LAST + 1); k++)
|
||||
@ -1244,7 +1246,7 @@ void PollInputEvents(void)
|
||||
CORE.Input.Gamepad.axisState[i][k] = axes[k];
|
||||
}
|
||||
|
||||
// Register buttons for 2nd triggers (because GLFW doesn't count these as buttons but rather axis)
|
||||
// Register buttons for 2nd triggers (because GLFW doesn't count these as buttons but rather as axes)
|
||||
if (CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] > 0.1f)
|
||||
{
|
||||
CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_LEFT_TRIGGER_2] = 1;
|
||||
@ -1298,17 +1300,17 @@ static void SetDimensionsFromMonitor(GLFWmonitor *monitor)
|
||||
// We need to provide these because GLFWallocator expects function pointers with specific signatures.
|
||||
// Similar wrappers exist in utils.c but we cannot reuse them here due to declaration mismatch.
|
||||
// https://www.glfw.org/docs/latest/intro_guide.html#init_allocator
|
||||
static void* AllocateWrapper(size_t size, void* user)
|
||||
static void *AllocateWrapper(size_t size, void *user)
|
||||
{
|
||||
(void)user;
|
||||
return RL_MALLOC(size);
|
||||
}
|
||||
static void* ReallocateWrapper(void* block, size_t size, void* user)
|
||||
static void *ReallocateWrapper(void *block, size_t size, void *user)
|
||||
{
|
||||
(void)user;
|
||||
return RL_REALLOC(block, size);
|
||||
}
|
||||
static void DeallocateWrapper(void* block, void* user)
|
||||
static void DeallocateWrapper(void *block, void *user)
|
||||
{
|
||||
(void)user;
|
||||
RL_FREE(block);
|
||||
@ -1325,6 +1327,7 @@ int InitPlatform(void)
|
||||
.reallocate = ReallocateWrapper,
|
||||
.user = NULL, // RL_*ALLOC macros are not capable of handling user-provided data
|
||||
};
|
||||
|
||||
glfwInitAllocator(&allocator);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
@ -1379,6 +1382,12 @@ int InitPlatform(void)
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); // Transparent framebuffer
|
||||
else glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_FALSE); // Opaque framebuffer
|
||||
|
||||
// HACK: Most of this was written before GLFW_SCALE_FRAMEBUFFER existed and
|
||||
// was enabled by default. Disabling it gets back the old behavior. A
|
||||
// complete fix will require removing a lot of CORE.Window.render
|
||||
// manipulation code.
|
||||
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
{
|
||||
// Resize window content area based on the monitor content scale.
|
||||
@ -1386,7 +1395,7 @@ int InitPlatform(void)
|
||||
// On platforms like macOS the resolution of the framebuffer is changed independently of the window size.
|
||||
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // Scale content area based on the monitor content scale where window is placed on
|
||||
#if defined(__APPLE__)
|
||||
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE);
|
||||
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
|
||||
#endif
|
||||
}
|
||||
else glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE);
|
||||
@ -1600,7 +1609,7 @@ int InitPlatform(void)
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
{
|
||||
// NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling.
|
||||
// Framebuffer scaling should be activated with: glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE);
|
||||
// Framebuffer scaling should be activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
|
||||
#if !defined(__APPLE__)
|
||||
glfwGetFramebufferSize(platform.handle, &fbWidth, &fbHeight);
|
||||
|
||||
@ -1688,6 +1697,8 @@ int InitPlatform(void)
|
||||
// Retrieve gamepad names
|
||||
for (int i = 0; i < MAX_GAMEPADS; i++)
|
||||
{
|
||||
// WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
|
||||
// we can get a not-NULL terminated string, so, we only copy up to (MAX_GAMEPAD_NAME_LENGTH - 1)
|
||||
if (glfwJoystickPresent(i)) strncpy(CORE.Input.Gamepad.name[i], glfwGetJoystickName(i), MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
@ -1741,9 +1752,13 @@ static void ErrorCallback(int error, const char *description)
|
||||
}
|
||||
|
||||
// GLFW3 WindowSize Callback, runs when window is resizedLastFrame
|
||||
// NOTE: Window resizing not allowed by default
|
||||
// NOTE: Window resizing not enabled by default, use SetConfigFlags()
|
||||
static void WindowSizeCallback(GLFWwindow *window, int width, int height)
|
||||
{
|
||||
// WARNING: On window minimization, callback is called,
|
||||
// but we don't want to change internal screen values, it breaks things
|
||||
if ((width == 0) || (height == 0)) return;
|
||||
|
||||
// Reset viewport and projection matrix for new size
|
||||
SetupViewport(width, height);
|
||||
|
||||
@ -1753,12 +1768,22 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height)
|
||||
|
||||
if (IsWindowFullscreen()) return;
|
||||
|
||||
// Set current screen size
|
||||
// if we are doing automatic DPI scaling, then the "screen" size is divided by the window scale
|
||||
if (IsWindowState(FLAG_WINDOW_HIGHDPI))
|
||||
{
|
||||
width = (int)(width/GetWindowScaleDPI().x);
|
||||
height = (int)(height/GetWindowScaleDPI().y);
|
||||
}
|
||||
|
||||
// Set render size
|
||||
CORE.Window.render.width = width;
|
||||
CORE.Window.render.height = height;
|
||||
|
||||
// Set current screen size
|
||||
CORE.Window.screen.width = width;
|
||||
CORE.Window.screen.height = height;
|
||||
|
||||
// NOTE: Postprocessing texture is not scaled to new size
|
||||
// WARNING: If using a render texture, it is not scaled to new size
|
||||
}
|
||||
static void WindowPosCallback(GLFWwindow* window, int x, int y)
|
||||
{
|
||||
@ -1951,6 +1976,9 @@ static void JoystickCallback(int jid, int event)
|
||||
{
|
||||
if (event == GLFW_CONNECTED)
|
||||
{
|
||||
// WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
|
||||
// we can get a not-NULL terminated string, so, we clean destination and only copy up to -1
|
||||
memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH);
|
||||
strncpy(CORE.Input.Gamepad.name[jid], glfwGetJoystickName(jid), MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||
}
|
||||
else if (event == GLFW_DISCONNECTED)
|
||||
|
||||
@ -54,7 +54,7 @@
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_WEB_RGFW)
|
||||
#define RGFW_NO_GL_HEADER
|
||||
#define RGFW_NO_GL_HEADER
|
||||
#endif
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_ES2) && !defined(PLATFORM_WEB_RGFW)
|
||||
@ -76,14 +76,14 @@ void CloseWindow(void);
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define Rectangle rectangle_win32
|
||||
#define Rectangle rectangle_win32
|
||||
#define CloseWindow CloseWindow_win32
|
||||
#define ShowCursor __imp_ShowCursor
|
||||
#define _APISETSTRING_
|
||||
|
||||
#undef MAX_PATH
|
||||
#define _APISETSTRING_
|
||||
|
||||
#undef MAX_PATH
|
||||
|
||||
__declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar);
|
||||
__declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar);
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
@ -103,8 +103,8 @@ void CloseWindow(void);
|
||||
#undef CloseWindow
|
||||
#undef Rectangle
|
||||
|
||||
#undef MAX_PATH
|
||||
#define MAX_PATH 1025
|
||||
#undef MAX_PATH
|
||||
#define MAX_PATH 1025
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
@ -128,7 +128,7 @@ typedef struct {
|
||||
//----------------------------------------------------------------------------------
|
||||
extern CoreData CORE; // Global CORE state context
|
||||
|
||||
static PlatformData platform = { NULL }; // Platform specific
|
||||
static PlatformData platform = { 0 }; // Platform specific
|
||||
|
||||
static bool RGFW_disableCursor = false;
|
||||
|
||||
@ -175,7 +175,9 @@ static const unsigned short keyMappingRGFW[] = {
|
||||
[RGFW_superL] = KEY_LEFT_SUPER,
|
||||
#ifndef RGFW_MACOS
|
||||
[RGFW_shiftR] = KEY_RIGHT_SHIFT,
|
||||
[RGFW_controlR] = KEY_RIGHT_CONTROL,
|
||||
[RGFW_altR] = KEY_RIGHT_ALT,
|
||||
[RGFW_superR] = KEY_RIGHT_SUPER,
|
||||
#endif
|
||||
[RGFW_space] = KEY_SPACE,
|
||||
|
||||
@ -264,11 +266,12 @@ bool WindowShouldClose(void)
|
||||
|
||||
// Toggle fullscreen mode
|
||||
void ToggleFullscreen(void)
|
||||
{
|
||||
{
|
||||
if (!CORE.Window.fullscreen)
|
||||
{
|
||||
// Store previous window position (in case we exit fullscreen)
|
||||
CORE.Window.previousPosition = CORE.Window.position;
|
||||
CORE.Window.previousScreen = CORE.Window.screen;
|
||||
|
||||
platform.mon = RGFW_window_getMonitor(platform.window);
|
||||
CORE.Window.fullscreen = true;
|
||||
@ -281,18 +284,20 @@ void ToggleFullscreen(void)
|
||||
{
|
||||
CORE.Window.fullscreen = false;
|
||||
CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
|
||||
|
||||
if (platform.mon.mode.area.w)
|
||||
|
||||
if (platform.mon.mode.area.w)
|
||||
{
|
||||
RGFW_monitor monitor = RGFW_window_getMonitor(platform.window);
|
||||
RGFW_monitor_requestMode(monitor, platform.mon.mode, RGFW_monitorScale);
|
||||
|
||||
|
||||
platform.mon.mode.area.w = 0;
|
||||
}
|
||||
|
||||
// we update the window position right away
|
||||
CORE.Window.position = CORE.Window.previousPosition;
|
||||
RGFW_window_setFullscreen(platform.window, 0);
|
||||
RGFW_window_move(platform.window, RGFW_POINT(CORE.Window.position.x, CORE.Window.position.y));
|
||||
RGFW_window_resize(platform.window, RGFW_AREA(CORE.Window.previousScreen.width, CORE.Window.previousScreen.height));
|
||||
}
|
||||
|
||||
// Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)
|
||||
@ -303,10 +308,7 @@ void ToggleFullscreen(void)
|
||||
// Toggle borderless windowed mode
|
||||
void ToggleBorderlessWindowed(void)
|
||||
{
|
||||
if (platform.window == NULL)
|
||||
return;
|
||||
|
||||
if (CORE.Window.fullscreen)
|
||||
if (CORE.Window.fullscreen)
|
||||
{
|
||||
CORE.Window.previousPosition = CORE.Window.position;
|
||||
CORE.Window.previousScreen = CORE.Window.screen;
|
||||
@ -315,7 +317,9 @@ void ToggleBorderlessWindowed(void)
|
||||
|
||||
RGFW_monitor mon = RGFW_window_getMonitor(platform.window);
|
||||
RGFW_window_resize(platform.window, mon.mode.area);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
RGFW_window_setBorder(platform.window, 1);
|
||||
|
||||
CORE.Window.position = CORE.Window.previousPosition;
|
||||
@ -337,11 +341,10 @@ void MinimizeWindow(void)
|
||||
RGFW_window_minimize(platform.window);
|
||||
}
|
||||
|
||||
// Set window state: not minimized/maximized
|
||||
// Restore window from being minimized/maximized
|
||||
void RestoreWindow(void)
|
||||
{
|
||||
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED))
|
||||
RGFW_window_focus(platform.window);
|
||||
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
|
||||
|
||||
RGFW_window_restore(platform.window);
|
||||
}
|
||||
@ -349,6 +352,8 @@ void RestoreWindow(void)
|
||||
// Set window configuration state using flags
|
||||
void SetWindowState(unsigned int flags)
|
||||
{
|
||||
if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
|
||||
|
||||
CORE.Window.flags |= flags;
|
||||
|
||||
if (flags & FLAG_VSYNC_HINT)
|
||||
@ -357,8 +362,7 @@ void SetWindowState(unsigned int flags)
|
||||
}
|
||||
if (flags & FLAG_FULLSCREEN_MODE)
|
||||
{
|
||||
if (!CORE.Window.fullscreen)
|
||||
ToggleFullscreen();
|
||||
if (!CORE.Window.fullscreen) ToggleFullscreen();
|
||||
}
|
||||
if (flags & FLAG_WINDOW_RESIZABLE)
|
||||
{
|
||||
@ -384,6 +388,8 @@ void SetWindowState(unsigned int flags)
|
||||
if (flags & FLAG_WINDOW_UNFOCUSED)
|
||||
{
|
||||
CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED;
|
||||
platform.window->_flags &= ~RGFW_windowFocusOnShow;
|
||||
RGFW_window_setFlags(platform.window, platform.window->_flags);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_TOPMOST)
|
||||
{
|
||||
@ -430,8 +436,7 @@ void ClearWindowState(unsigned int flags)
|
||||
}
|
||||
if (flags & FLAG_FULLSCREEN_MODE)
|
||||
{
|
||||
if (CORE.Window.fullscreen)
|
||||
ToggleFullscreen();
|
||||
if (CORE.Window.fullscreen) ToggleFullscreen();
|
||||
}
|
||||
if (flags & FLAG_WINDOW_RESIZABLE)
|
||||
{
|
||||
@ -444,25 +449,25 @@ void ClearWindowState(unsigned int flags)
|
||||
}
|
||||
if (flags & FLAG_WINDOW_HIDDEN)
|
||||
{
|
||||
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED))
|
||||
RGFW_window_focus(platform.window);
|
||||
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
|
||||
|
||||
RGFW_window_show(platform.window);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_MINIMIZED)
|
||||
{
|
||||
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED))
|
||||
RGFW_window_focus(platform.window);
|
||||
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
|
||||
|
||||
RGFW_window_restore(platform.window);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_MAXIMIZED)
|
||||
{
|
||||
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED))
|
||||
RGFW_window_focus(platform.window);
|
||||
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
|
||||
|
||||
RGFW_window_restore(platform.window);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_UNFOCUSED)
|
||||
{
|
||||
RGFW_window_setFlags(platform.window, platform.window->_flags | RGFW_windowFocusOnShow);
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED;
|
||||
}
|
||||
if (flags & FLAG_WINDOW_TOPMOST)
|
||||
@ -487,8 +492,7 @@ void ClearWindowState(unsigned int flags)
|
||||
}
|
||||
if (flags & FLAG_BORDERLESS_WINDOWED_MODE)
|
||||
{
|
||||
if (CORE.Window.fullscreen)
|
||||
ToggleBorderlessWindowed();
|
||||
if (CORE.Window.fullscreen) ToggleBorderlessWindowed();
|
||||
}
|
||||
if (flags & FLAG_MSAA_4X_HINT)
|
||||
{
|
||||
@ -502,7 +506,8 @@ void ClearWindowState(unsigned int flags)
|
||||
|
||||
int RGFW_formatToChannels(int format)
|
||||
{
|
||||
switch (format) {
|
||||
switch (format)
|
||||
{
|
||||
case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
|
||||
case PIXELFORMAT_UNCOMPRESSED_R16: // 16 bpp (1 channel - half float)
|
||||
case PIXELFORMAT_UNCOMPRESSED_R32: // 32 bpp (1 channel - float)
|
||||
@ -547,21 +552,20 @@ void SetWindowIcons(Image *images, int count)
|
||||
if ((images == NULL) || (count <= 0))
|
||||
{
|
||||
RGFW_window_setIcon(platform.window, NULL, RGFW_AREA(0, 0), 0);
|
||||
} {
|
||||
Image* bigIcon = NULL;
|
||||
Image* smallIcon = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
Image *bigIcon = NULL;
|
||||
Image *smallIcon = NULL;
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
if (bigIcon == NULL || (images[i].width > bigIcon->width && images[i].height > bigIcon->height))
|
||||
bigIcon = &images[i];
|
||||
if (smallIcon == NULL || (images[i].width < smallIcon->width && images[i].height > smallIcon->height))
|
||||
smallIcon = &images[i];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if ((bigIcon == NULL) || ((images[i].width > bigIcon->width) && (images[i].height > bigIcon->height))) bigIcon = &images[i];
|
||||
if ((smallIcon == NULL) || ((images[i].width < smallIcon->width) && (images[i].height > smallIcon->height))) smallIcon = &images[i];
|
||||
}
|
||||
|
||||
if (smallIcon != NULL)
|
||||
RGFW_window_setIconEx(platform.window, smallIcon->data, RGFW_AREA(smallIcon->width, smallIcon->height), RGFW_formatToChannels(smallIcon->format), RGFW_iconWindow);
|
||||
if (bigIcon != NULL)
|
||||
RGFW_window_setIconEx(platform.window, bigIcon->data, RGFW_AREA(bigIcon->width, bigIcon->height), RGFW_formatToChannels(bigIcon->format), RGFW_iconTaskbar);
|
||||
|
||||
if (smallIcon != NULL) RGFW_window_setIconEx(platform.window, smallIcon->data, RGFW_AREA(smallIcon->width, smallIcon->height), RGFW_formatToChannels(smallIcon->format), RGFW_iconWindow);
|
||||
if (bigIcon != NULL) RGFW_window_setIconEx(platform.window, bigIcon->data, RGFW_AREA(bigIcon->width, bigIcon->height), RGFW_formatToChannels(bigIcon->format), RGFW_iconTaskbar);
|
||||
}
|
||||
}
|
||||
|
||||
@ -581,7 +585,7 @@ void SetWindowPosition(int x, int y)
|
||||
// Set monitor for the current window
|
||||
void SetWindowMonitor(int monitor)
|
||||
{
|
||||
RGFW_window_moveToMonitor(platform.window, RGFW_getMonitors()[monitor]);
|
||||
RGFW_window_moveToMonitor(platform.window, RGFW_getMonitors(NULL)[monitor]);
|
||||
}
|
||||
|
||||
// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
|
||||
@ -624,7 +628,8 @@ void SetWindowFocused(void)
|
||||
// Get native window handle
|
||||
void *GetWindowHandle(void)
|
||||
{
|
||||
#ifdef RGFW_WEBASM
|
||||
if (platform.window == NULL) return NULL;
|
||||
#ifdef RGFW_WASM
|
||||
return (void *)platform.window->src.ctx;
|
||||
#else
|
||||
return (void *)platform.window->src.window;
|
||||
@ -637,7 +642,7 @@ int GetMonitorCount(void)
|
||||
#define MAX_MONITORS_SUPPORTED 6
|
||||
|
||||
int count = MAX_MONITORS_SUPPORTED;
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
@ -651,11 +656,14 @@ int GetMonitorCount(void)
|
||||
return count;
|
||||
}
|
||||
|
||||
// Get number of monitors
|
||||
// Get current monitor where window is placed
|
||||
int GetCurrentMonitor(void)
|
||||
{
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor mon = RGFW_window_getMonitor(platform.window);
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
RGFW_monitor mon = { 0 };
|
||||
|
||||
if (platform.window) mon = RGFW_window_getMonitor(platform.window);
|
||||
else mon = RGFW_getPrimaryMonitor();
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
@ -668,7 +676,7 @@ int GetCurrentMonitor(void)
|
||||
// Get selected monitor position
|
||||
Vector2 GetMonitorPosition(int monitor)
|
||||
{
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
|
||||
return (Vector2){ (float)mons[monitor].x, (float)mons[monitor].y };
|
||||
}
|
||||
@ -676,7 +684,7 @@ Vector2 GetMonitorPosition(int monitor)
|
||||
// Get selected monitor width (currently used by monitor)
|
||||
int GetMonitorWidth(int monitor)
|
||||
{
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
|
||||
return mons[monitor].mode.area.w;
|
||||
}
|
||||
@ -684,7 +692,7 @@ int GetMonitorWidth(int monitor)
|
||||
// Get selected monitor height (currently used by monitor)
|
||||
int GetMonitorHeight(int monitor)
|
||||
{
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
|
||||
return mons[monitor].mode.area.h;
|
||||
}
|
||||
@ -692,7 +700,7 @@ int GetMonitorHeight(int monitor)
|
||||
// Get selected monitor physical width in millimetres
|
||||
int GetMonitorPhysicalWidth(int monitor)
|
||||
{
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
|
||||
return mons[monitor].physW;
|
||||
}
|
||||
@ -700,7 +708,7 @@ int GetMonitorPhysicalWidth(int monitor)
|
||||
// Get selected monitor physical height in millimetres
|
||||
int GetMonitorPhysicalHeight(int monitor)
|
||||
{
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
|
||||
return (int)mons[monitor].physH;
|
||||
}
|
||||
@ -708,7 +716,7 @@ int GetMonitorPhysicalHeight(int monitor)
|
||||
// Get selected monitor refresh rate
|
||||
int GetMonitorRefreshRate(int monitor)
|
||||
{
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
|
||||
return (int)mons[monitor].mode.refreshRate;
|
||||
}
|
||||
@ -716,7 +724,7 @@ int GetMonitorRefreshRate(int monitor)
|
||||
// Get the human-readable, UTF-8 encoded name of the selected monitor
|
||||
const char *GetMonitorName(int monitor)
|
||||
{
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
|
||||
return mons[monitor].name;
|
||||
}
|
||||
@ -724,15 +732,19 @@ const char *GetMonitorName(int monitor)
|
||||
// Get window position XY on monitor
|
||||
Vector2 GetWindowPosition(void)
|
||||
{
|
||||
if (platform.window == NULL) return (Vector2){ 0.0f, 0.0f };
|
||||
return (Vector2){ (float)platform.window->r.x, (float)platform.window->r.y };
|
||||
}
|
||||
|
||||
// Get window scale DPI factor for current monitor
|
||||
Vector2 GetWindowScaleDPI(void)
|
||||
{
|
||||
RGFW_monitor monitor = RGFW_window_getMonitor(platform.window);
|
||||
RGFW_monitor monitor = { 0 };
|
||||
|
||||
return (Vector2){monitor.scaleX, monitor.scaleX};
|
||||
if (platform.window) monitor = RGFW_window_getMonitor(platform.window);
|
||||
else monitor = RGFW_getPrimaryMonitor();
|
||||
|
||||
return (Vector2){ monitor.scaleX, monitor.scaleX };
|
||||
}
|
||||
|
||||
// Set clipboard text content
|
||||
@ -748,7 +760,6 @@ const char *GetClipboardText(void)
|
||||
return RGFW_readClipboard(NULL);
|
||||
}
|
||||
|
||||
|
||||
#if defined(SUPPORT_CLIPBOARD_IMAGE)
|
||||
#if defined(_WIN32)
|
||||
#define WIN32_CLIPBOARD_IMPLEMENTATION
|
||||
@ -771,7 +782,7 @@ Image GetClipboardImage(void)
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
fileData = (void *)Win32GetClipboardImageData(&width, &height, &dataSize);
|
||||
|
||||
|
||||
if (fileData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data");
|
||||
else image = LoadImageFromMemory(".bmp", fileData, dataSize);
|
||||
#else
|
||||
@ -829,11 +840,7 @@ void SwapScreenBuffer(void)
|
||||
// Get elapsed time measure in seconds since InitTimer()
|
||||
double GetTime(void)
|
||||
{
|
||||
double time = 0.0;
|
||||
unsigned long long int nanoSeconds = RGFW_getTimeNS();
|
||||
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
|
||||
|
||||
return time;
|
||||
return RGFW_getTime();
|
||||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
@ -886,29 +893,30 @@ void SetMouseCursor(int cursor)
|
||||
const char *GetKeyName(int key)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetKeyName() unsupported on target platform");
|
||||
|
||||
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,
|
||||
[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
|
||||
@ -919,7 +927,7 @@ void PollInputEvents(void)
|
||||
// because ProcessGestureEvent() is just called on an event, not every frame
|
||||
UpdateGestures();
|
||||
#endif
|
||||
|
||||
|
||||
// Reset keys/chars pressed registered
|
||||
CORE.Input.Keyboard.keyPressedQueueCount = 0;
|
||||
CORE.Input.Keyboard.charPressedQueueCount = 0;
|
||||
@ -979,19 +987,25 @@ void PollInputEvents(void)
|
||||
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
||||
}
|
||||
|
||||
if ((CORE.Window.eventWaiting) || (IsWindowState(FLAG_WINDOW_MINIMIZED) && !IsWindowState(FLAG_WINDOW_ALWAYS_RUN)))
|
||||
{
|
||||
RGFW_window_eventWait(platform.window, -1); // Wait for input events: keyboard/mouse/window events (callbacks) -> Update keys state
|
||||
CORE.Time.previous = GetTime();
|
||||
}
|
||||
|
||||
while (RGFW_window_checkEvent(platform.window))
|
||||
{
|
||||
RGFW_event *event = &platform.window->event;
|
||||
// All input events can be processed after polling
|
||||
|
||||
switch (event->type)
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case RGFW_quit:
|
||||
if (CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN)
|
||||
event->type = 0;
|
||||
else
|
||||
CORE.Window.shouldClose = true;
|
||||
break;
|
||||
case RGFW_mouseEnter: CORE.Input.Mouse.cursorOnScreen = true; break;
|
||||
case RGFW_mouseLeave: CORE.Input.Mouse.cursorOnScreen = false; break;
|
||||
case RGFW_quit:
|
||||
event->type = 0;
|
||||
CORE.Window.shouldClose = true;
|
||||
return;
|
||||
case RGFW_DND: // Dropped file
|
||||
{
|
||||
for (int i = 0; i < event->droppedFilesCount; i++)
|
||||
@ -1005,7 +1019,7 @@ void PollInputEvents(void)
|
||||
|
||||
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
|
||||
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event->droppedFiles[i]);
|
||||
|
||||
|
||||
CORE.Window.dropFileCount++;
|
||||
}
|
||||
else if (CORE.Window.dropFileCount < 1024)
|
||||
@ -1023,12 +1037,38 @@ void PollInputEvents(void)
|
||||
case RGFW_windowResized:
|
||||
{
|
||||
SetupViewport(platform.window->r.w, platform.window->r.h);
|
||||
CORE.Window.screen.width = platform.window->r.w;
|
||||
CORE.Window.screen.height = platform.window->r.h;
|
||||
|
||||
// if we are doing automatic DPI scaling, then the "screen" size is divided by the window scale
|
||||
if (IsWindowState(FLAG_WINDOW_HIGHDPI))
|
||||
{
|
||||
CORE.Window.screen.width = (int)(platform.window->r.w / GetWindowScaleDPI().x);
|
||||
CORE.Window.screen.height = (int)(platform.window->r.h / GetWindowScaleDPI().y);
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE.Window.screen.width = platform.window->r.w;
|
||||
CORE.Window.screen.height = platform.window->r.h;
|
||||
}
|
||||
|
||||
CORE.Window.currentFbo.width = platform.window->r.w;
|
||||
CORE.Window.currentFbo.height = platform.window->r.h;
|
||||
CORE.Window.resizedLastFrame = true;
|
||||
} break;
|
||||
case RGFW_windowMaximized:
|
||||
{
|
||||
CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // The window was maximized
|
||||
} break;
|
||||
case RGFW_windowMinimized:
|
||||
{
|
||||
CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; // The window was iconified
|
||||
} break;
|
||||
case RGFW_windowRestored:
|
||||
{
|
||||
if (RGFW_window_isMaximized(platform.window))
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED; // The window was restored
|
||||
if (RGFW_window_isMinimized(platform.window))
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored
|
||||
} break;
|
||||
case RGFW_windowMoved:
|
||||
{
|
||||
CORE.Window.position.x = platform.window->r.x;
|
||||
@ -1079,12 +1119,13 @@ void PollInputEvents(void)
|
||||
{
|
||||
CORE.Input.Mouse.currentWheelMove.y = event->scroll;
|
||||
break;
|
||||
} else CORE.Input.Mouse.currentWheelMove.y = 0;
|
||||
}
|
||||
else CORE.Input.Mouse.currentWheelMove.y = 0;
|
||||
|
||||
int btn = event->button;
|
||||
if (btn == RGFW_mouseLeft) btn = 1;
|
||||
else if (btn == RGFW_mouseRight) btn = 2;
|
||||
else if (btn == RGFW_mouseMiddle) btn = 3;
|
||||
else if (btn == RGFW_mouseMiddle) btn = 3;
|
||||
|
||||
CORE.Input.Mouse.currentButtonState[btn - 1] = 1;
|
||||
CORE.Input.Touch.currentTouchState[btn - 1] = 1;
|
||||
@ -1097,7 +1138,8 @@ void PollInputEvents(void)
|
||||
{
|
||||
CORE.Input.Mouse.currentWheelMove.y = event->scroll;
|
||||
break;
|
||||
} else CORE.Input.Mouse.currentWheelMove.y = 0;
|
||||
}
|
||||
else CORE.Input.Mouse.currentWheelMove.y = 0;
|
||||
|
||||
int btn = event->button;
|
||||
if (btn == RGFW_mouseLeft) btn = 1;
|
||||
@ -1127,19 +1169,21 @@ void PollInputEvents(void)
|
||||
touchAction = 2;
|
||||
} break;
|
||||
case RGFW_gamepadConnected:
|
||||
{
|
||||
CORE.Input.Gamepad.ready[platform.window->event.gamepad] = true;
|
||||
CORE.Input.Gamepad.axisCount[platform.window->event.gamepad] = platform.window->event.axisesCount;
|
||||
CORE.Input.Gamepad.axisState[platform.window->event.gamepad][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
|
||||
CORE.Input.Gamepad.axisState[platform.window->event.gamepad][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
|
||||
|
||||
strcpy(CORE.Input.Gamepad.name[platform.window->event.gamepad], RGFW_getGamepadName(platform.window, platform.window->event.gamepad));
|
||||
break;
|
||||
} break;
|
||||
case RGFW_gamepadDisconnected:
|
||||
{
|
||||
CORE.Input.Gamepad.ready[platform.window->event.gamepad] = false;
|
||||
break;
|
||||
} break;
|
||||
case RGFW_gamepadButtonPressed:
|
||||
{
|
||||
int button = RGFW_gpConvTable[event->button];
|
||||
int button = RGFW_gpConvTable[event->button];
|
||||
|
||||
if (button >= 0)
|
||||
{
|
||||
@ -1149,7 +1193,7 @@ void PollInputEvents(void)
|
||||
} break;
|
||||
case RGFW_gamepadButtonReleased:
|
||||
{
|
||||
int button = RGFW_gpConvTable[event->button];
|
||||
int button = RGFW_gpConvTable[event->button];
|
||||
|
||||
CORE.Input.Gamepad.currentButtonState[event->gamepad][button] = 0;
|
||||
if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
|
||||
@ -1157,33 +1201,34 @@ void PollInputEvents(void)
|
||||
case RGFW_gamepadAxisMove:
|
||||
{
|
||||
int axis = -1;
|
||||
float value = 0;
|
||||
|
||||
float value = 0;
|
||||
switch(event->whichAxis)
|
||||
switch(event->whichAxis)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_LEFT_X] = event->axis[0].x / 100.0f;
|
||||
CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_LEFT_Y] = event->axis[0].y / 100.0f;
|
||||
} break;
|
||||
case 1:
|
||||
{
|
||||
CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_RIGHT_X] = event->axis[1].x / 100.0f;
|
||||
CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_RIGHT_Y] = event->axis[1].y / 100.0f;
|
||||
} break;
|
||||
case 2: axis = GAMEPAD_AXIS_LEFT_TRIGGER;
|
||||
case 3:
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_LEFT_X] = event->axis[0].x / 100.0f;
|
||||
CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_LEFT_Y] = event->axis[0].y / 100.0f;
|
||||
} break;
|
||||
case 1:
|
||||
{
|
||||
CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_RIGHT_X] = event->axis[1].x / 100.0f;
|
||||
CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_RIGHT_Y] = event->axis[1].y / 100.0f;
|
||||
} break;
|
||||
case 2: axis = GAMEPAD_AXIS_LEFT_TRIGGER;
|
||||
case 3:
|
||||
{
|
||||
if (axis == -1) axis = GAMEPAD_AXIS_RIGHT_TRIGGER;
|
||||
int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER)? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2;
|
||||
int pressed = (value > 0.1f);
|
||||
CORE.Input.Gamepad.currentButtonState[event->gamepad][button] = pressed;
|
||||
|
||||
if (pressed) CORE.Input.Gamepad.lastButtonPressed = button;
|
||||
else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER)? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2;
|
||||
int pressed = (value > 0.1f);
|
||||
CORE.Input.Gamepad.currentButtonState[event->gamepad][button] = pressed;
|
||||
|
||||
if (pressed) CORE.Input.Gamepad.lastButtonPressed = button;
|
||||
else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
@ -1239,7 +1284,7 @@ int InitPlatform(void)
|
||||
}
|
||||
|
||||
if ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0)
|
||||
{
|
||||
{
|
||||
CORE.Window.fullscreen = true;
|
||||
flags |= RGFW_windowedFullscreen;
|
||||
}
|
||||
@ -1251,44 +1296,51 @@ int InitPlatform(void)
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) flags |= RGFW_windowHide;
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) flags |= RGFW_windowMaximize;
|
||||
|
||||
|
||||
// NOTE: Some OpenGL context attributes must be set before window creation
|
||||
|
||||
// Check selection OpenGL version
|
||||
if (rlGetVersion() == RL_OPENGL_21)
|
||||
{
|
||||
if (rlGetVersion() == RL_OPENGL_21)
|
||||
{
|
||||
RGFW_setGLHint(RGFW_glMajor, 2);
|
||||
RGFW_setGLHint(RGFW_glMinor, 1);
|
||||
}
|
||||
else if (rlGetVersion() == RL_OPENGL_33)
|
||||
{
|
||||
RGFW_setGLHint(RGFW_glCore, 3);
|
||||
}
|
||||
else if (rlGetVersion() == RL_OPENGL_33)
|
||||
{
|
||||
RGFW_setGLHint(RGFW_glMajor, 3);
|
||||
RGFW_setGLHint(RGFW_glMinor, 3);
|
||||
}
|
||||
else if (rlGetVersion() == RL_OPENGL_43)
|
||||
{
|
||||
RGFW_setGLHint(RGFW_glCore, 3);
|
||||
}
|
||||
else if (rlGetVersion() == RL_OPENGL_43)
|
||||
{
|
||||
RGFW_setGLHint(RGFW_glMajor, 4);
|
||||
RGFW_setGLHint(RGFW_glMinor, 3);
|
||||
}
|
||||
|
||||
if (CORE.Window.flags & FLAG_MSAA_4X_HINT) RGFW_setGLHint(RGFW_glSamples, 4);
|
||||
|
||||
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) flags |= RGFW_windowFocusOnShow | RGFW_windowFocus;
|
||||
|
||||
platform.window = RGFW_createWindow(CORE.Window.title, RGFW_RECT(0, 0, CORE.Window.screen.width, CORE.Window.screen.height), flags);
|
||||
platform.mon.mode.area.w = 0;
|
||||
|
||||
if (platform.window != NULL)
|
||||
{
|
||||
// NOTE: RGFW's exit key is distinct from raylib's exit key (which can
|
||||
// be set with SetExitKey()) and defaults to Escape
|
||||
platform.window->exitKey = RGFW_keyNULL;
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_WEB_RGFW
|
||||
RGFW_area screenSize = RGFW_getScreenSize();
|
||||
CORE.Window.display.width = screenSize.w;
|
||||
CORE.Window.display.height = screenSize.h;
|
||||
#else
|
||||
CORE.Window.display.width = CORE.Window.screen.width;
|
||||
CORE.Window.display.width = CORE.Window.screen.width;
|
||||
CORE.Window.display.height = CORE.Window.screen.height;
|
||||
#endif
|
||||
// TODO: Is this needed by raylib now?
|
||||
// TODO: Is this needed by raylib now?
|
||||
// If so, rcore_desktop_sdl should be updated too
|
||||
//SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
|
||||
|
||||
if (CORE.Window.flags & FLAG_VSYNC_HINT) RGFW_window_swapInterval(platform.window, 1);
|
||||
//SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
|
||||
|
||||
if (CORE.Window.flags & FLAG_VSYNC_HINT) RGFW_window_swapInterval(platform.window, 1);
|
||||
RGFW_window_makeCurrent(platform.window);
|
||||
|
||||
// Check surface and context activation
|
||||
@ -1338,14 +1390,23 @@ int InitPlatform(void)
|
||||
CORE.Storage.basePath = GetWorkingDirectory();
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifdef RGFW_X11
|
||||
for (int i = 0; (i < 4) && (i < MAX_GAMEPADS); i++)
|
||||
{
|
||||
RGFW_registerGamepad(platform.window, i);
|
||||
}
|
||||
#if defined(RGFW_WAYLAND)
|
||||
if (RGFW_useWaylandBool) TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Wayland): Initialized successfully");
|
||||
else TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11 (fallback)): Initialized successfully");
|
||||
#elif defined(RGFW_X11)
|
||||
#if defined(__APPLE__)
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11 (MacOS)): Initialized successfully");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11): Initialized successfully");
|
||||
#endif
|
||||
#elif defined (RGFW_WINDOWS)
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Win32): Initialized successfully");
|
||||
#elif defined(RGFW_WASM)
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - WASMs): Initialized successfully");
|
||||
#elif defined(RGFW_MACOS)
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - MacOS): Initialized successfully");
|
||||
#endif
|
||||
|
||||
TRACELOG(LOG_INFO, "PLATFORM: CUSTOM: Initialized successfully");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1359,6 +1420,6 @@ void ClosePlatform(void)
|
||||
static KeyboardKey ConvertScancodeToKey(u32 keycode)
|
||||
{
|
||||
if (keycode > sizeof(keyMappingRGFW)/sizeof(unsigned short)) return 0;
|
||||
|
||||
return keyMappingRGFW[keycode];
|
||||
|
||||
return keyMappingRGFW[keycode];
|
||||
}
|
||||
|
||||
@ -424,6 +424,8 @@ 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
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
@ -508,7 +510,7 @@ void MinimizeWindow(void)
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) == 0) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED;
|
||||
}
|
||||
|
||||
// Set window state: not minimized/maximized
|
||||
// Restore window from being minimized/maximized
|
||||
void RestoreWindow(void)
|
||||
{
|
||||
SDL_RestoreWindow(platform.window);
|
||||
@ -518,6 +520,8 @@ void RestoreWindow(void)
|
||||
// Set window configuration state using flags
|
||||
void SetWindowState(unsigned int flags)
|
||||
{
|
||||
if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
|
||||
|
||||
CORE.Window.flags |= flags;
|
||||
|
||||
if (flags & FLAG_VSYNC_HINT)
|
||||
@ -702,70 +706,84 @@ void SetWindowIcon(Image image)
|
||||
switch (image.format)
|
||||
{
|
||||
case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
|
||||
{
|
||||
rmask = 0xFF, gmask = 0;
|
||||
bmask = 0, amask = 0;
|
||||
depth = 8, pitch = image.width;
|
||||
break;
|
||||
} break;
|
||||
case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
|
||||
{
|
||||
rmask = 0xFF, gmask = 0xFF00;
|
||||
bmask = 0, amask = 0;
|
||||
depth = 16, pitch = image.width*2;
|
||||
break;
|
||||
} break;
|
||||
case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
|
||||
{
|
||||
rmask = 0xF800, gmask = 0x07E0;
|
||||
bmask = 0x001F, amask = 0;
|
||||
depth = 16, pitch = image.width*2;
|
||||
break;
|
||||
case PIXELFORMAT_UNCOMPRESSED_R8G8B8: // Uses BGR for 24-bit
|
||||
rmask = 0x0000FF, gmask = 0x00FF00;
|
||||
bmask = 0xFF0000, amask = 0;
|
||||
} break;
|
||||
case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
|
||||
{
|
||||
// WARNING: SDL2 could be using BGR but SDL3 RGB
|
||||
rmask = 0xFF0000, gmask = 0x00FF00;
|
||||
bmask = 0x0000FF, amask = 0;
|
||||
depth = 24, pitch = image.width*3;
|
||||
break;
|
||||
} break;
|
||||
case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
|
||||
{
|
||||
rmask = 0xF800, gmask = 0x07C0;
|
||||
bmask = 0x003E, amask = 0x0001;
|
||||
depth = 16, pitch = image.width*2;
|
||||
break;
|
||||
} break;
|
||||
case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
|
||||
{
|
||||
rmask = 0xF000, gmask = 0x0F00;
|
||||
bmask = 0x00F0, amask = 0x000F;
|
||||
depth = 16, pitch = image.width*2;
|
||||
break;
|
||||
} break;
|
||||
case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
|
||||
{
|
||||
rmask = 0xFF000000, gmask = 0x00FF0000;
|
||||
bmask = 0x0000FF00, amask = 0x000000FF;
|
||||
depth = 32, pitch = image.width*4;
|
||||
break;
|
||||
} break;
|
||||
case PIXELFORMAT_UNCOMPRESSED_R32:
|
||||
{
|
||||
rmask = 0xFFFFFFFF, gmask = 0;
|
||||
bmask = 0, amask = 0;
|
||||
depth = 32, pitch = image.width*4;
|
||||
break;
|
||||
} break;
|
||||
case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
|
||||
{
|
||||
rmask = 0xFFFFFFFF, gmask = 0xFFFFFFFF;
|
||||
bmask = 0xFFFFFFFF, amask = 0;
|
||||
depth = 96, pitch = image.width*12;
|
||||
break;
|
||||
} break;
|
||||
case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
|
||||
{
|
||||
rmask = 0xFFFFFFFF, gmask = 0xFFFFFFFF;
|
||||
bmask = 0xFFFFFFFF, amask = 0xFFFFFFFF;
|
||||
depth = 128, pitch = image.width*16;
|
||||
break;
|
||||
} break;
|
||||
case PIXELFORMAT_UNCOMPRESSED_R16:
|
||||
{
|
||||
rmask = 0xFFFF, gmask = 0;
|
||||
bmask = 0, amask = 0;
|
||||
depth = 16, pitch = image.width*2;
|
||||
break;
|
||||
} break;
|
||||
case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
|
||||
{
|
||||
rmask = 0xFFFF, gmask = 0xFFFF;
|
||||
bmask = 0xFFFF, amask = 0;
|
||||
depth = 48, pitch = image.width*6;
|
||||
break;
|
||||
} break;
|
||||
case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
|
||||
{
|
||||
rmask = 0xFFFF, gmask = 0xFFFF;
|
||||
bmask = 0xFFFF, amask = 0xFFFF;
|
||||
depth = 64, pitch = image.width*8;
|
||||
break;
|
||||
} break;
|
||||
default: return; // Compressed formats are not supported
|
||||
}
|
||||
|
||||
@ -914,7 +932,7 @@ int GetMonitorCount(void)
|
||||
return monitorCount;
|
||||
}
|
||||
|
||||
// Get number of monitors
|
||||
// Get current monitor where window is placed
|
||||
int GetCurrentMonitor(void)
|
||||
{
|
||||
int currentMonitor = 0;
|
||||
@ -1349,7 +1367,7 @@ void PollInputEvents(void)
|
||||
for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i];
|
||||
|
||||
// Map touch position to mouse position for convenience
|
||||
CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
|
||||
if (CORE.Input.Touch.pointCount == 0) CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
|
||||
|
||||
int touchAction = -1; // 0-TOUCH_ACTION_UP, 1-TOUCH_ACTION_DOWN, 2-TOUCH_ACTION_MOVE
|
||||
bool realTouch = false; // Flag to differentiate real touch gestures from mouse ones
|
||||
@ -1451,8 +1469,17 @@ void PollInputEvents(void)
|
||||
const int width = event.window.data1;
|
||||
const int height = event.window.data2;
|
||||
SetupViewport(width, height);
|
||||
CORE.Window.screen.width = width;
|
||||
CORE.Window.screen.height = height;
|
||||
// if we are doing automatic DPI scaling, then the "screen" size is divided by the window scale
|
||||
if (IsWindowState(FLAG_WINDOW_HIGHDPI))
|
||||
{
|
||||
CORE.Window.screen.width = (int)(width / GetWindowScaleDPI().x);
|
||||
CORE.Window.screen.height = (int)(height / GetWindowScaleDPI().y);
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE.Window.screen.width = width;
|
||||
CORE.Window.screen.height = height;
|
||||
}
|
||||
CORE.Window.currentFbo.width = width;
|
||||
CORE.Window.currentFbo.height = height;
|
||||
CORE.Window.resizedLastFrame = true;
|
||||
@ -1576,13 +1603,18 @@ void PollInputEvents(void)
|
||||
{
|
||||
// NOTE: event.text.text data comes an UTF-8 text sequence but we register codepoints (int)
|
||||
|
||||
int codepointSize = 0;
|
||||
|
||||
// Check if there is space available in the queue
|
||||
if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
|
||||
{
|
||||
// Add character (codepoint) to the queue
|
||||
CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = GetCodepointNext(event.text.text, &codepointSize);
|
||||
#if defined(PLATFORM_DESKTOP_SDL3)
|
||||
unsigned int textLen = strlen(event.text.text);
|
||||
unsigned int codepoint = (unsigned int)SDL_StepUTF8(&event.text.text, textLen);
|
||||
#else
|
||||
int codepointSize = 0;
|
||||
codepoint = GetCodepointNextSDL(event.text.text, &codepointSize);
|
||||
#endif
|
||||
CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = codepoint;
|
||||
CORE.Input.Keyboard.charPressedQueueCount++;
|
||||
}
|
||||
} break;
|
||||
@ -1661,7 +1693,7 @@ void PollInputEvents(void)
|
||||
{
|
||||
int jid = event.jdevice.which; // Joystick device index
|
||||
|
||||
if (!CORE.Input.Gamepad.ready[jid] && (jid < MAX_GAMEPADS))
|
||||
if (CORE.Input.Gamepad.ready[jid] && (jid < MAX_GAMEPADS))
|
||||
{
|
||||
platform.gamepad[jid] = SDL_GameControllerOpen(jid);
|
||||
platform.gamepadId[jid] = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[jid]));
|
||||
@ -1672,8 +1704,8 @@ void PollInputEvents(void)
|
||||
CORE.Input.Gamepad.axisCount[jid] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[jid]));
|
||||
CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
|
||||
CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
|
||||
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);
|
||||
CORE.Input.Gamepad.name[jid][MAX_GAMEPAD_NAME_LENGTH - 1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1800,7 +1832,7 @@ void PollInputEvents(void)
|
||||
{
|
||||
if (platform.gamepadId[i] == event.jaxis.which)
|
||||
{
|
||||
// SDL axis value range is -32768 to 32767, we normalize it to RayLib's -1.0 to 1.0f range
|
||||
// SDL axis value range is -32768 to 32767, we normalize it to raylib's -1.0 to 1.0f range
|
||||
float value = event.jaxis.value/(float)32767;
|
||||
CORE.Input.Gamepad.axisState[i][axis] = value;
|
||||
|
||||
@ -2068,4 +2100,42 @@ static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode)
|
||||
|
||||
return KEY_NULL; // No equivalent key in Raylib
|
||||
}
|
||||
// EOF
|
||||
|
||||
// Get next codepoint in a byte sequence and bytes processed
|
||||
static int GetCodepointNextSDL(const char *text, int *codepointSize)
|
||||
{
|
||||
const char *ptr = text;
|
||||
int codepoint = 0x3f; // Codepoint (defaults to '?')
|
||||
*codepointSize = 1;
|
||||
|
||||
// Get current codepoint and bytes processed
|
||||
if (0xf0 == (0xf8 & ptr[0]))
|
||||
{
|
||||
// 4 byte UTF-8 codepoint
|
||||
if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80) || ((ptr[3] & 0xC0) ^ 0x80)) { return codepoint; } // 10xxxxxx checks
|
||||
codepoint = ((0x07 & ptr[0]) << 18) | ((0x3f & ptr[1]) << 12) | ((0x3f & ptr[2]) << 6) | (0x3f & ptr[3]);
|
||||
*codepointSize = 4;
|
||||
}
|
||||
else if (0xe0 == (0xf0 & ptr[0]))
|
||||
{
|
||||
// 3 byte UTF-8 codepoint */
|
||||
if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } // 10xxxxxx checks
|
||||
codepoint = ((0x0f & ptr[0]) << 12) | ((0x3f & ptr[1]) << 6) | (0x3f & ptr[2]);
|
||||
*codepointSize = 3;
|
||||
}
|
||||
else if (0xc0 == (0xe0 & ptr[0]))
|
||||
{
|
||||
// 2 byte UTF-8 codepoint
|
||||
if ((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } // 10xxxxxx checks
|
||||
codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]);
|
||||
*codepointSize = 2;
|
||||
}
|
||||
else if (0x00 == (0x80 & ptr[0]))
|
||||
{
|
||||
// 1 byte UTF-8 codepoint
|
||||
codepoint = ptr[0];
|
||||
*codepointSize = 1;
|
||||
}
|
||||
|
||||
return codepoint;
|
||||
}
|
||||
|
||||
@ -124,7 +124,7 @@ typedef struct {
|
||||
|
||||
// Gamepad data
|
||||
int gamepadStreamFd[MAX_GAMEPADS]; // Gamepad device file descriptor
|
||||
int gamepadAbsAxisRange[MAX_GAMEPADS][MAX_GAMEPAD_AXIS][2]; // [0] = min, [1] = range value of the axis
|
||||
int gamepadAbsAxisRange[MAX_GAMEPADS][MAX_GAMEPAD_AXES][2]; // [0] = min, [1] = range value of the axes
|
||||
int gamepadAbsAxisMap[MAX_GAMEPADS][ABS_CNT]; // Maps the axes gamepads from the evdev api to a sequential one
|
||||
int gamepadCount; // The number of gamepads registered
|
||||
} PlatformData;
|
||||
@ -277,7 +277,7 @@ void MinimizeWindow(void)
|
||||
TRACELOG(LOG_WARNING, "MinimizeWindow() not available on target platform");
|
||||
}
|
||||
|
||||
// Set window state: not minimized/maximized
|
||||
// Restore window from being minimized/maximized
|
||||
void RestoreWindow(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform");
|
||||
@ -371,7 +371,7 @@ int GetMonitorCount(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get number of monitors
|
||||
// Get current monitor where window is placed
|
||||
int GetCurrentMonitor(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetCurrentMonitor() not implemented on target platform");
|
||||
@ -735,20 +735,24 @@ int InitPlatform(void)
|
||||
|
||||
#if defined(DEFAULT_GRAPHIC_DEVICE_DRM)
|
||||
platform.fd = open(DEFAULT_GRAPHIC_DEVICE_DRM, O_RDWR);
|
||||
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: Default graphic device DRM opened successfully");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, "DISPLAY: No graphic card set, trying platform-gpu-card");
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: No graphic card set, trying platform-gpu-card");
|
||||
platform.fd = open("/dev/dri/by-path/platform-gpu-card", O_RDWR); // VideoCore VI (Raspberry Pi 4)
|
||||
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: platform-gpu-card opened successfully");
|
||||
|
||||
if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
|
||||
{
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Failed to open platform-gpu-card, trying card1");
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open platform-gpu-card, trying card1");
|
||||
platform.fd = open("/dev/dri/card1", O_RDWR); // Other Embedded
|
||||
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card1 opened successfully");
|
||||
}
|
||||
|
||||
if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
|
||||
{
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Failed to open graphic card1, trying card0");
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card1, trying card0");
|
||||
platform.fd = open("/dev/dri/card0", O_RDWR); // VideoCore IV (Raspberry Pi 1-3)
|
||||
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card0 opened successfully");
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -906,7 +910,7 @@ int InitPlatform(void)
|
||||
EGL_BLUE_SIZE, 8, // BLUE color bit depth (alternative: 5)
|
||||
EGL_ALPHA_SIZE, 8, // ALPHA bit depth (required for transparent framebuffer)
|
||||
//EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI)
|
||||
EGL_DEPTH_SIZE, 16, // Depth buffer size (Required to use Depth testing!)
|
||||
EGL_DEPTH_SIZE, 24, // Depth buffer size (Required to use Depth testing!)
|
||||
//EGL_STENCIL_SIZE, 8, // Stencil buffer size
|
||||
EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA
|
||||
EGL_SAMPLES, samples, // 4x Antialiasing if activated (Free on MALI GPUs)
|
||||
@ -944,7 +948,7 @@ int InitPlatform(void)
|
||||
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: EGL configs available: %d", numConfigs);
|
||||
|
||||
EGLConfig *configs = RL_CALLOC(numConfigs, sizeof(*configs));
|
||||
EGLConfig *configs = (EGLConfig *)RL_CALLOC(numConfigs, sizeof(*configs));
|
||||
if (!configs)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get memory for EGL configs");
|
||||
@ -1370,7 +1374,7 @@ static void InitEvdevInput(void)
|
||||
if ((strncmp("event", entity->d_name, strlen("event")) == 0) || // Search for devices named "event*"
|
||||
(strncmp("mouse", entity->d_name, strlen("mouse")) == 0)) // Search for devices named "mouse*"
|
||||
{
|
||||
sprintf(path, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name);
|
||||
snprintf(path, MAX_FILEPATH_LENGTH, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name);
|
||||
ConfigureEvdevDevice(path); // Configure the device if appropriate
|
||||
}
|
||||
}
|
||||
@ -1399,7 +1403,7 @@ static void ConfigureEvdevDevice(char *device)
|
||||
int fd = open(device, O_RDONLY | O_NONBLOCK);
|
||||
if (fd < 0)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "DRM: Failed to open input device: %s", device);
|
||||
TRACELOG(LOG_WARNING, "SYSTEM: Failed to open input device: %s", device);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1456,7 +1460,7 @@ static void ConfigureEvdevDevice(char *device)
|
||||
// matter if we support them
|
||||
else if (hasAbsXY && TEST_BIT(keyBits, BTN_MOUSE)) isMouse = true;
|
||||
|
||||
// If any of the common joystick axis is present, we assume it's a gamepad
|
||||
// If any of the common joystick axes are present, we assume it's a gamepad
|
||||
else
|
||||
{
|
||||
for (int axis = (hasAbsXY? ABS_Z : ABS_X); axis < ABS_PRESSURE; axis++)
|
||||
@ -1542,7 +1546,7 @@ static void ConfigureEvdevDevice(char *device)
|
||||
if (absAxisCount > 0)
|
||||
{
|
||||
// TODO / NOTE
|
||||
// So gamepad axis (as in the actual linux joydev.c) are just simply enumerated
|
||||
// So gamepad axes (as in the actual linux joydev.c) are just simply enumerated
|
||||
// and (at least for some input drivers like xpat) it's convention to use
|
||||
// ABS_X, ABX_Y for one joystick ABS_RX, ABS_RY for the other and the Z axes for the
|
||||
// shoulder buttons
|
||||
@ -1677,7 +1681,7 @@ static void PollGamepadEvents(void)
|
||||
|
||||
TRACELOG(LOG_DEBUG, "INPUT: Gamepad %2i: Axis: %2i Value: %i", i, axisRaylib, event.value);
|
||||
|
||||
if (axisRaylib < MAX_GAMEPAD_AXIS)
|
||||
if (axisRaylib < MAX_GAMEPAD_AXES)
|
||||
{
|
||||
int min = platform.gamepadAbsAxisRange[i][event.code][0];
|
||||
int range = platform.gamepadAbsAxisRange[i][event.code][1];
|
||||
|
||||
@ -114,7 +114,7 @@ void MinimizeWindow(void)
|
||||
TRACELOG(LOG_WARNING, "MinimizeWindow() not available on target platform");
|
||||
}
|
||||
|
||||
// Set window state: not minimized/maximized
|
||||
// Restore window from being minimized/maximized
|
||||
void RestoreWindow(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform");
|
||||
@ -208,7 +208,7 @@ int GetMonitorCount(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get number of monitors
|
||||
// Get current monitor where window is placed
|
||||
int GetCurrentMonitor(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetCurrentMonitor() not implemented on target platform");
|
||||
|
||||
@ -163,13 +163,13 @@ bool WindowShouldClose(void)
|
||||
// REF: https://emscripten.org/docs/porting/asyncify.html
|
||||
|
||||
// WindowShouldClose() is not called on a web-ready raylib application if using emscripten_set_main_loop()
|
||||
// and encapsulating one frame execution on a UpdateDrawFrame() function,
|
||||
// and encapsulating one frame execution on a UpdateDrawFrame() function,
|
||||
// allowing the browser to manage execution asynchronously
|
||||
|
||||
// Optionally we can manage the time we give-control-back-to-browser if required,
|
||||
// but it seems below line could generate stuttering on some browsers
|
||||
emscripten_sleep(12);
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -350,7 +350,7 @@ void MinimizeWindow(void)
|
||||
TRACELOG(LOG_WARNING, "MinimizeWindow() not available on target platform");
|
||||
}
|
||||
|
||||
// Set window state: not minimized/maximized
|
||||
// Restore window from being minimized/maximized
|
||||
void RestoreWindow(void)
|
||||
{
|
||||
if ((glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) && (CORE.Window.flags & FLAG_WINDOW_MAXIMIZED))
|
||||
@ -364,6 +364,8 @@ void RestoreWindow(void)
|
||||
// Set window configuration state using flags
|
||||
void SetWindowState(unsigned int flags)
|
||||
{
|
||||
if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
|
||||
|
||||
// Check previous state and requested state to apply required changes
|
||||
// NOTE: In most cases the functions already change the flags internally
|
||||
|
||||
@ -709,7 +711,7 @@ int GetMonitorCount(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get number of monitors
|
||||
// Get current monitor where window is placed
|
||||
int GetCurrentMonitor(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetCurrentMonitor() not implemented on target platform");
|
||||
@ -1079,7 +1081,7 @@ void PollInputEvents(void)
|
||||
}
|
||||
|
||||
// Register axis data for every connected gamepad
|
||||
for (int j = 0; (j < gamepadState.numAxes) && (j < MAX_GAMEPAD_AXIS); j++)
|
||||
for (int j = 0; (j < gamepadState.numAxes) && (j < MAX_GAMEPAD_AXES); j++)
|
||||
{
|
||||
CORE.Input.Gamepad.axisState[i][j] = gamepadState.axis[j];
|
||||
}
|
||||
@ -1744,7 +1746,7 @@ static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadE
|
||||
if (gamepadEvent->connected && (gamepadEvent->index < MAX_GAMEPADS))
|
||||
{
|
||||
CORE.Input.Gamepad.ready[gamepadEvent->index] = true;
|
||||
sprintf(CORE.Input.Gamepad.name[gamepadEvent->index], "%s", gamepadEvent->id);
|
||||
snprintf(CORE.Input.Gamepad.name[gamepadEvent->index], MAX_GAMEPAD_NAME_LENGTH, "%s", gamepadEvent->id);
|
||||
}
|
||||
else CORE.Input.Gamepad.ready[gamepadEvent->index] = false;
|
||||
|
||||
|
||||
22
src/raudio.c
22
src/raudio.c
@ -604,6 +604,7 @@ AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam
|
||||
|
||||
audioBuffer->usage = usage;
|
||||
audioBuffer->frameCursorPos = 0;
|
||||
audioBuffer->framesProcessed = 0;
|
||||
audioBuffer->sizeInFrames = sizeInFrames;
|
||||
|
||||
// Buffers should be marked as processed by default so that a call to
|
||||
@ -650,6 +651,9 @@ void PlayAudioBuffer(AudioBuffer *buffer)
|
||||
buffer->playing = true;
|
||||
buffer->paused = false;
|
||||
buffer->frameCursorPos = 0;
|
||||
buffer->framesProcessed = 0;
|
||||
buffer->isSubBufferProcessed[0] = true;
|
||||
buffer->isSubBufferProcessed[1] = true;
|
||||
ma_mutex_unlock(&AUDIO.System.lock);
|
||||
}
|
||||
}
|
||||
@ -1335,7 +1339,7 @@ Music LoadMusicStream(const char *fileName)
|
||||
#if defined(SUPPORT_FILEFORMAT_WAV)
|
||||
else if (IsFileExtension(fileName, ".wav"))
|
||||
{
|
||||
drwav *ctxWav = RL_CALLOC(1, sizeof(drwav));
|
||||
drwav *ctxWav = (drwav *)RL_CALLOC(1, sizeof(drwav));
|
||||
bool success = drwav_init_file(ctxWav, fileName, NULL);
|
||||
|
||||
if (success)
|
||||
@ -1385,7 +1389,7 @@ Music LoadMusicStream(const char *fileName)
|
||||
#if defined(SUPPORT_FILEFORMAT_MP3)
|
||||
else if (IsFileExtension(fileName, ".mp3"))
|
||||
{
|
||||
drmp3 *ctxMp3 = RL_CALLOC(1, sizeof(drmp3));
|
||||
drmp3 *ctxMp3 = (drmp3 *)RL_CALLOC(1, sizeof(drmp3));
|
||||
int result = drmp3_init_file(ctxMp3, fileName, NULL);
|
||||
|
||||
if (result > 0)
|
||||
@ -1476,7 +1480,7 @@ Music LoadMusicStream(const char *fileName)
|
||||
#if defined(SUPPORT_FILEFORMAT_MOD)
|
||||
else if (IsFileExtension(fileName, ".mod"))
|
||||
{
|
||||
jar_mod_context_t *ctxMod = RL_CALLOC(1, sizeof(jar_mod_context_t));
|
||||
jar_mod_context_t *ctxMod = (jar_mod_context_t *)RL_CALLOC(1, sizeof(jar_mod_context_t));
|
||||
jar_mod_init(ctxMod);
|
||||
int result = jar_mod_load_file(ctxMod, fileName);
|
||||
|
||||
@ -1527,7 +1531,7 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data,
|
||||
#if defined(SUPPORT_FILEFORMAT_WAV)
|
||||
else if ((strcmp(fileType, ".wav") == 0) || (strcmp(fileType, ".WAV") == 0))
|
||||
{
|
||||
drwav *ctxWav = RL_CALLOC(1, sizeof(drwav));
|
||||
drwav *ctxWav = (drwav *)RL_CALLOC(1, sizeof(drwav));
|
||||
|
||||
bool success = drwav_init_memory(ctxWav, (const void *)data, dataSize, NULL);
|
||||
|
||||
@ -1578,7 +1582,7 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data,
|
||||
#if defined(SUPPORT_FILEFORMAT_MP3)
|
||||
else if ((strcmp(fileType, ".mp3") == 0) || (strcmp(fileType, ".MP3") == 0))
|
||||
{
|
||||
drmp3 *ctxMp3 = RL_CALLOC(1, sizeof(drmp3));
|
||||
drmp3 *ctxMp3 = (drmp3 *)RL_CALLOC(1, sizeof(drmp3));
|
||||
int success = drmp3_init_memory(ctxMp3, (const void*)data, dataSize, NULL);
|
||||
|
||||
if (success)
|
||||
@ -2106,8 +2110,12 @@ AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
|
||||
// The size of a streaming buffer must be at least double the size of a period
|
||||
unsigned int periodSize = AUDIO.System.device.playback.internalPeriodSizeInFrames;
|
||||
|
||||
// If the buffer is not set, compute one that would give us a buffer good enough for a decent frame rate
|
||||
unsigned int subBufferSize = (AUDIO.Buffer.defaultSize == 0)? AUDIO.System.device.sampleRate/30 : AUDIO.Buffer.defaultSize;
|
||||
// If the buffer is not set, compute one that would give us a buffer good enough for a decent frame rate at the device bit size/rate
|
||||
int deviceBitsPerSample = AUDIO.System.device.playback.format;
|
||||
if (deviceBitsPerSample > 4) deviceBitsPerSample = 4;
|
||||
deviceBitsPerSample *= AUDIO.System.device.playback.channels;
|
||||
|
||||
unsigned int subBufferSize = (AUDIO.Buffer.defaultSize == 0) ? (AUDIO.System.device.sampleRate/30*deviceBitsPerSample) : AUDIO.Buffer.defaultSize;
|
||||
|
||||
if (subBufferSize < periodSize) subBufferSize = periodSize;
|
||||
|
||||
|
||||
24
src/raylib.h
24
src/raylib.h
@ -743,7 +743,7 @@ typedef enum {
|
||||
GAMEPAD_BUTTON_RIGHT_THUMB // Gamepad joystick pressed button right
|
||||
} GamepadButton;
|
||||
|
||||
// Gamepad axis
|
||||
// Gamepad axes
|
||||
typedef enum {
|
||||
GAMEPAD_AXIS_LEFT_X = 0, // Gamepad left stick X axis
|
||||
GAMEPAD_AXIS_LEFT_Y = 1, // Gamepad left stick Y axis
|
||||
@ -954,7 +954,7 @@ typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args);
|
||||
typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, int *dataSize); // FileIO: Load binary data
|
||||
typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, int dataSize); // FileIO: Save binary data
|
||||
typedef char *(*LoadFileTextCallback)(const char *fileName); // FileIO: Load text data
|
||||
typedef bool (*SaveFileTextCallback)(const char *fileName, char *text); // FileIO: Save text data
|
||||
typedef bool (*SaveFileTextCallback)(const char *fileName, const char *text); // FileIO: Save text data
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Global Variables Definition
|
||||
@ -987,7 +987,7 @@ RLAPI void ToggleFullscreen(void); // Toggle wind
|
||||
RLAPI void ToggleBorderlessWindowed(void); // Toggle window state: borderless windowed, resizes window to match monitor resolution
|
||||
RLAPI void MaximizeWindow(void); // Set window state: maximized, if resizable
|
||||
RLAPI void MinimizeWindow(void); // Set window state: minimized, if resizable
|
||||
RLAPI void RestoreWindow(void); // Set window state: not minimized/maximized
|
||||
RLAPI void RestoreWindow(void); // Restore window from being minimized/maximized
|
||||
RLAPI void SetWindowIcon(Image image); // Set icon for window (single image, RGBA 32bit)
|
||||
RLAPI void SetWindowIcons(Image *images, int count); // Set icon for window (multiple images, RGBA 32bit)
|
||||
RLAPI void SetWindowTitle(const char *title); // Set title for window
|
||||
@ -1123,7 +1123,7 @@ RLAPI bool SaveFileData(const char *fileName, void *data, int dataSize); // Save
|
||||
RLAPI bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName); // Export data to code (.h), returns true on success
|
||||
RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string
|
||||
RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText()
|
||||
RLAPI bool SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success
|
||||
RLAPI bool SaveFileText(const char *fileName, const char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success
|
||||
//------------------------------------------------------------------
|
||||
|
||||
// File system functions
|
||||
@ -1153,8 +1153,8 @@ RLAPI long GetFileModTime(const char *fileName); // Get file mo
|
||||
// Compression/Encoding functionality
|
||||
RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize); // Compress data (DEFLATE algorithm), memory must be MemFree()
|
||||
RLAPI unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // Decompress data (DEFLATE algorithm), memory must be MemFree()
|
||||
RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string, memory must be MemFree()
|
||||
RLAPI unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize); // Decode Base64 string data, memory must be MemFree()
|
||||
RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string (includes NULL terminator), memory must be MemFree()
|
||||
RLAPI unsigned char *DecodeDataBase64(const char *text, int *outputSize); // Decode Base64 string (expected NULL terminated), memory must be MemFree()
|
||||
RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize); // Compute CRC32 hash code
|
||||
RLAPI unsigned int *ComputeMD5(unsigned char *data, int dataSize); // Compute MD5 hash code, returns static int[4] (16 bytes)
|
||||
RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes)
|
||||
@ -1192,8 +1192,8 @@ RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Check if a game
|
||||
RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Check if a gamepad button has been released once
|
||||
RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Check if a gamepad button is NOT being pressed
|
||||
RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed
|
||||
RLAPI int GetGamepadAxisCount(int gamepad); // Get gamepad axis count for a gamepad
|
||||
RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Get axis movement value for a gamepad axis
|
||||
RLAPI int GetGamepadAxisCount(int gamepad); // Get axis count for a gamepad
|
||||
RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Get movement value for a gamepad axis
|
||||
RLAPI int SetGamepadMappings(const char *mappings); // Set internal gamepad mappings (SDL_GameControllerDB)
|
||||
RLAPI void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration); // Set gamepad vibration for both motors (duration in seconds)
|
||||
|
||||
@ -1264,7 +1264,9 @@ RLAPI void DrawCircleV(Vector2 center, float radius, Color color);
|
||||
RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline
|
||||
RLAPI void DrawCircleLinesV(Vector2 center, float radius, Color color); // Draw circle outline (Vector version)
|
||||
RLAPI void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse
|
||||
RLAPI void DrawEllipseV(Vector2 center, float radiusH, float radiusV, Color color); // Draw ellipse (Vector version)
|
||||
RLAPI void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse outline
|
||||
RLAPI void DrawEllipseLinesV(Vector2 center, float radiusH, float radiusV, Color color); // Draw ellipse outline (Vector version)
|
||||
RLAPI void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring
|
||||
RLAPI void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring outline
|
||||
RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle
|
||||
@ -1273,7 +1275,7 @@ RLAPI void DrawRectangleRec(Rectangle rec, Color color);
|
||||
RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters
|
||||
RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color top, Color bottom); // Draw a vertical-gradient-filled rectangle
|
||||
RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color left, Color right); // Draw a horizontal-gradient-filled rectangle
|
||||
RLAPI void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color topRight, Color bottomRight); // Draw a gradient-filled rectangle with custom vertex colors
|
||||
RLAPI void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color bottomRight, Color topRight); // Draw a gradient-filled rectangle with custom vertex colors
|
||||
RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline
|
||||
RLAPI void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color); // Draw rectangle outline with extended parameters
|
||||
RLAPI void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color); // Draw rectangle with rounded edges
|
||||
@ -1406,8 +1408,8 @@ RLAPI void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color c
|
||||
RLAPI void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle within an image
|
||||
RLAPI void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3); // Draw triangle with interpolated colors within an image
|
||||
RLAPI void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline within an image
|
||||
RLAPI void ImageDrawTriangleFan(Image *dst, Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points within an image (first vertex is the center)
|
||||
RLAPI void ImageDrawTriangleStrip(Image *dst, Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points within an image
|
||||
RLAPI void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points within an image (first vertex is the center)
|
||||
RLAPI void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points within an image
|
||||
RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source)
|
||||
RLAPI void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination)
|
||||
RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination)
|
||||
|
||||
298
src/rcore.c
298
src/rcore.c
@ -235,10 +235,10 @@ __declspec(dllimport) unsigned int __stdcall timeEndPeriod(unsigned int uPeriod)
|
||||
#define MAX_GAMEPADS 4 // Maximum number of gamepads supported
|
||||
#endif
|
||||
#ifndef MAX_GAMEPAD_NAME_LENGTH
|
||||
#define MAX_GAMEPAD_NAME_LENGTH 128 // Maximum number of characters of gamepad name (byte size)
|
||||
#define MAX_GAMEPAD_NAME_LENGTH 128 // Maximum number of characters in a gamepad name (byte size)
|
||||
#endif
|
||||
#ifndef MAX_GAMEPAD_AXIS
|
||||
#define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad)
|
||||
#ifndef MAX_GAMEPAD_AXES
|
||||
#define MAX_GAMEPAD_AXES 8 // Maximum number of axes supported (per gamepad)
|
||||
#endif
|
||||
#ifndef MAX_GAMEPAD_BUTTONS
|
||||
#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
|
||||
@ -354,12 +354,12 @@ typedef struct CoreData {
|
||||
} Touch;
|
||||
struct {
|
||||
int lastButtonPressed; // Register last gamepad button pressed
|
||||
int axisCount[MAX_GAMEPADS]; // Register number of available gamepad axis
|
||||
int axisCount[MAX_GAMEPADS]; // Register number of available gamepad axes
|
||||
bool ready[MAX_GAMEPADS]; // Flag to know if gamepad is ready
|
||||
char name[MAX_GAMEPADS][MAX_GAMEPAD_NAME_LENGTH]; // Gamepad name holder
|
||||
char currentButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Current gamepad buttons state
|
||||
char previousButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Previous gamepad buttons state
|
||||
float axisState[MAX_GAMEPADS][MAX_GAMEPAD_AXIS]; // Gamepad axis state
|
||||
float axisState[MAX_GAMEPADS][MAX_GAMEPAD_AXES]; // Gamepad axes state
|
||||
|
||||
} Gamepad;
|
||||
} Input;
|
||||
@ -523,25 +523,25 @@ const char *TextFormat(const char *text, ...); // Formatting of tex
|
||||
#define PLATFORM_DESKTOP_GLFW
|
||||
#endif
|
||||
|
||||
// We're using `#pragma message` because `#warning` is not adopted by MSVC.
|
||||
// We're using '#pragma message' because '#warning' is not adopted by MSVC
|
||||
#if defined(SUPPORT_CLIPBOARD_IMAGE)
|
||||
#if !defined(SUPPORT_MODULE_RTEXTURES)
|
||||
#pragma message ("Warning: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly")
|
||||
#pragma message ("WARNING: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly")
|
||||
#endif
|
||||
|
||||
// It's nice to have support Bitmap on Linux as well, but not as necessary as Windows
|
||||
#if !defined(SUPPORT_FILEFORMAT_BMP) && defined(_WIN32)
|
||||
#pragma message ("Warning: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_FILEFORMAT_BMP, specially on Windows")
|
||||
#pragma message ("WARNING: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_FILEFORMAT_BMP, specially on Windows")
|
||||
#endif
|
||||
|
||||
// From what I've tested applications on Wayland saves images on clipboard as PNG.
|
||||
// From what I've tested applications on Wayland saves images on clipboard as PNG
|
||||
#if (!defined(SUPPORT_FILEFORMAT_PNG) || !defined(SUPPORT_FILEFORMAT_JPG)) && !defined(_WIN32)
|
||||
#pragma message ("Warning: Getting image from the clipboard might not work without SUPPORT_FILEFORMAT_PNG or SUPPORT_FILEFORMAT_JPG")
|
||||
#pragma message ("WARNING: Getting image from the clipboard might not work without SUPPORT_FILEFORMAT_PNG or SUPPORT_FILEFORMAT_JPG")
|
||||
#endif
|
||||
|
||||
// Not needed because `rtexture.c` will automatically defined STBI_REQUIRED when any SUPPORT_FILEFORMAT_* is defined.
|
||||
// Not needed because `rtexture.c` will automatically defined STBI_REQUIRED when any SUPPORT_FILEFORMAT_* is defined
|
||||
// #if !defined(STBI_REQUIRED)
|
||||
// #pragma message ("Warning: "STBI_REQUIRED is not defined, that means we can't load images from clipbard"
|
||||
// #pragma message ("WARNING: "STBI_REQUIRED is not defined, that means we can't load images from clipbard"
|
||||
// #endif
|
||||
|
||||
#endif // SUPPORT_CLIPBOARD_IMAGE
|
||||
@ -1119,7 +1119,7 @@ void BeginTextureMode(RenderTexture2D target)
|
||||
//rlScalef(0.0f, -1.0f, 0.0f); // Flip Y-drawing (?)
|
||||
|
||||
// Setup current width/height for proper aspect ratio
|
||||
// calculation when using BeginMode3D()
|
||||
// calculation when using BeginTextureMode()
|
||||
CORE.Window.currentFbo.width = target.texture.width;
|
||||
CORE.Window.currentFbo.height = target.texture.height;
|
||||
CORE.Window.usingFbo = true;
|
||||
@ -1322,7 +1322,7 @@ Shader LoadShader(const char *vsFileName, const char *fsFileName)
|
||||
if (fsFileName != NULL) fShaderStr = LoadFileText(fsFileName);
|
||||
|
||||
if ((vShaderStr == NULL) && (fShaderStr == NULL)) TraceLog(LOG_WARNING, "SHADER: Shader files provided are not valid, using default shader");
|
||||
|
||||
|
||||
shader = LoadShaderFromMemory(vShaderStr, fShaderStr);
|
||||
|
||||
UnloadFileText(vShaderStr);
|
||||
@ -1879,12 +1879,15 @@ void TakeScreenshot(const char *fileName)
|
||||
// Security check to (partially) avoid malicious code
|
||||
if (strchr(fileName, '\'') != NULL) { TRACELOG(LOG_WARNING, "SYSTEM: Provided fileName could be potentially malicious, avoid [\'] character"); return; }
|
||||
|
||||
Vector2 scale = GetWindowScaleDPI();
|
||||
// Apply a scale if we are doing HIGHDPI auto-scaling
|
||||
Vector2 scale = { 1.0f, 1.0f };
|
||||
if (IsWindowState(FLAG_WINDOW_HIGHDPI)) scale = GetWindowScaleDPI();
|
||||
|
||||
unsigned char *imgData = rlReadScreenPixels((int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y));
|
||||
Image image = { imgData, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y), 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
|
||||
|
||||
char path[512] = { 0 };
|
||||
strcpy(path, TextFormat("%s/%s", CORE.Storage.basePath, GetFileName(fileName)));
|
||||
strcpy(path, TextFormat("%s/%s", CORE.Storage.basePath, fileName));
|
||||
|
||||
ExportImage(image, path); // WARNING: Module required: rtextures
|
||||
RL_FREE(imgData);
|
||||
@ -1902,6 +1905,8 @@ void TakeScreenshot(const char *fileName)
|
||||
// To configure window states after creation, just use SetWindowState()
|
||||
void SetConfigFlags(unsigned int flags)
|
||||
{
|
||||
if (CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetConfigFlags called after window initialization, Use \"SetWindowState\" to set flags instead");
|
||||
|
||||
// Selected flags are set but not evaluated at this point,
|
||||
// flag evaluation happens at InitWindow() or SetWindowState()
|
||||
CORE.Window.flags |= flags;
|
||||
@ -2309,9 +2314,12 @@ FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool
|
||||
// WARNING: files.count is not reseted to 0 after unloading
|
||||
void UnloadDirectoryFiles(FilePathList files)
|
||||
{
|
||||
for (unsigned int i = 0; i < files.capacity; i++) RL_FREE(files.paths[i]);
|
||||
if (files.paths != NULL)
|
||||
{
|
||||
for (unsigned int i = 0; i < files.capacity; i++) RL_FREE(files.paths[i]);
|
||||
|
||||
RL_FREE(files.paths);
|
||||
RL_FREE(files.paths);
|
||||
}
|
||||
}
|
||||
|
||||
// Create directories (including full path requested), returns 0 on success
|
||||
@ -2354,6 +2362,7 @@ bool ChangeDirectory(const char *dir)
|
||||
bool result = CHDIR(dir);
|
||||
|
||||
if (result != 0) TRACELOG(LOG_WARNING, "SYSTEM: Failed to change to directory: %s", dir);
|
||||
else TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", dir);
|
||||
|
||||
return (result == 0);
|
||||
}
|
||||
@ -2491,7 +2500,7 @@ unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDa
|
||||
|
||||
#if defined(SUPPORT_COMPRESSION_API)
|
||||
// Compress data and generate a valid DEFLATE stream
|
||||
struct sdefl *sdefl = RL_CALLOC(1, sizeof(struct sdefl)); // WARNING: Possible stack overflow, struct sdefl is almost 1MB
|
||||
struct sdefl *sdefl = (struct sdefl *)RL_CALLOC(1, sizeof(struct sdefl)); // WARNING: Possible stack overflow, struct sdefl is almost 1MB
|
||||
int bounds = sdefl_bound(dataSize);
|
||||
compData = (unsigned char *)RL_CALLOC(bounds, 1);
|
||||
|
||||
@ -2530,96 +2539,112 @@ unsigned char *DecompressData(const unsigned char *compData, int compDataSize, i
|
||||
}
|
||||
|
||||
// Encode data to Base64 string
|
||||
// NOTE: Returned string includes NULL terminator, considered on outputSize
|
||||
char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize)
|
||||
{
|
||||
static const unsigned char base64encodeTable[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
|
||||
};
|
||||
// Base64 conversion table from RFC 4648 [0..63]
|
||||
// NOTE: They represent 64 values (6 bits), to encode 3 bytes of data into 4 "sixtets" (6bit characters)
|
||||
static const char base64EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
static const int modTable[] = { 0, 2, 1 };
|
||||
// Compute expected size and padding
|
||||
int paddedSize = dataSize;
|
||||
while (paddedSize%3 != 0) paddedSize++; // Padding bytes to round 4*(dataSize/3) to 4 bytes
|
||||
int estimatedOutputSize = 4*(paddedSize/3);
|
||||
int padding = paddedSize - dataSize;
|
||||
|
||||
*outputSize = 4*((dataSize + 2)/3);
|
||||
// Adding null terminator to string
|
||||
estimatedOutputSize += 1;
|
||||
|
||||
char *encodedData = (char *)RL_MALLOC(*outputSize);
|
||||
// Load some memory to store encoded string
|
||||
char *encodedData = (char *)RL_CALLOC(estimatedOutputSize, 1);
|
||||
if (encodedData == NULL) return NULL;
|
||||
|
||||
if (encodedData == NULL) return NULL; // Security check
|
||||
|
||||
for (int i = 0, j = 0; i < dataSize;)
|
||||
int outputCount = 0;
|
||||
for (int i = 0; i < dataSize;)
|
||||
{
|
||||
unsigned int octetA = (i < dataSize)? (unsigned char)data[i++] : 0;
|
||||
unsigned int octetB = (i < dataSize)? (unsigned char)data[i++] : 0;
|
||||
unsigned int octetC = (i < dataSize)? (unsigned char)data[i++] : 0;
|
||||
unsigned int octetA = 0;
|
||||
unsigned int octetB = 0;
|
||||
unsigned int octetC = 0;
|
||||
unsigned int octetPack = 0;
|
||||
|
||||
unsigned int triple = (octetA << 0x10) + (octetB << 0x08) + octetC;
|
||||
octetA = data[i]; // Generates 2 sextets
|
||||
octetB = ((i + 1) < dataSize)? data[i + 1] : 0; // Generates 3 sextets
|
||||
octetC = ((i + 2) < dataSize)? data[i + 2] : 0; // Generates 4 sextets
|
||||
|
||||
encodedData[j++] = base64encodeTable[(triple >> 3*6) & 0x3F];
|
||||
encodedData[j++] = base64encodeTable[(triple >> 2*6) & 0x3F];
|
||||
encodedData[j++] = base64encodeTable[(triple >> 1*6) & 0x3F];
|
||||
encodedData[j++] = base64encodeTable[(triple >> 0*6) & 0x3F];
|
||||
octetPack = (octetA << 16) | (octetB << 8) | octetC;
|
||||
|
||||
encodedData[outputCount + 0] = (unsigned char)(base64EncodeTable[(octetPack >> 18) & 0x3f]);
|
||||
encodedData[outputCount + 1] = (unsigned char)(base64EncodeTable[(octetPack >> 12) & 0x3f]);
|
||||
encodedData[outputCount + 2] = (unsigned char)(base64EncodeTable[(octetPack >> 6) & 0x3f]);
|
||||
encodedData[outputCount + 3] = (unsigned char)(base64EncodeTable[octetPack & 0x3f]);
|
||||
outputCount += 4;
|
||||
i += 3;
|
||||
}
|
||||
|
||||
for (int i = 0; i < modTable[dataSize%3]; i++) encodedData[*outputSize - 1 - i] = '='; // Padding character
|
||||
// Add required padding bytes
|
||||
for (int p = 0; p < padding; p++) encodedData[outputCount - p - 1] = '=';
|
||||
|
||||
// Add null terminator to string
|
||||
encodedData[outputCount] = '\0';
|
||||
outputCount++;
|
||||
|
||||
if (outputCount != estimatedOutputSize) TRACELOG(LOG_WARNING, "BASE64: Output size differs from estimation");
|
||||
|
||||
*outputSize = estimatedOutputSize;
|
||||
return encodedData;
|
||||
}
|
||||
|
||||
// Decode Base64 string data
|
||||
unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize)
|
||||
// Decode Base64 string (expected NULL terminated)
|
||||
unsigned char *DecodeDataBase64(const char *text, int *outputSize)
|
||||
{
|
||||
static const unsigned char base64decodeTable[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
|
||||
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
|
||||
// Base64 decode table
|
||||
// NOTE: Following ASCII order [0..255] assigning the expected sixtet value to
|
||||
// every character in the corresponding ASCII position
|
||||
static const unsigned char base64DecodeTable[256] = {
|
||||
['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4, ['F'] = 5, ['G'] = 6, ['H'] = 7,
|
||||
['I'] = 8, ['J'] = 9, ['K'] = 10, ['L'] = 11, ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15,
|
||||
['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19, ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24, ['Z'] = 25,
|
||||
['a'] = 26, ['b'] = 27, ['c'] = 28, ['d'] = 29, ['e'] = 30, ['f'] = 31, ['g'] = 32, ['h'] = 33,
|
||||
['i'] = 34, ['j'] = 35, ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39, ['o'] = 40, ['p'] = 41,
|
||||
['q'] = 42, ['r'] = 43, ['s'] = 44, ['t'] = 45, ['u'] = 46, ['v'] = 47, ['w'] = 48, ['x'] = 49, ['y'] = 50, ['z'] = 51,
|
||||
['0'] = 52, ['1'] = 53, ['2'] = 54, ['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59,
|
||||
['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63
|
||||
};
|
||||
|
||||
// Get output size of Base64 input data
|
||||
int outSize = 0;
|
||||
for (int i = 0; data[4*i] != 0; i++)
|
||||
// Compute expected size and padding
|
||||
int dataSize = (int)strlen(text); // WARNING: Expecting NULL terminated strings!
|
||||
int ending = dataSize - 1;
|
||||
int padding = 0;
|
||||
while (text[ending] == '=') { padding++; ending--; }
|
||||
int estimatedOutputSize = 3*(dataSize/4) - padding;
|
||||
int maxOutputSize = 3*(dataSize/4);
|
||||
|
||||
// Load some memory to store decoded data
|
||||
// NOTE: Allocated enough size to include padding
|
||||
unsigned char *decodedData = (unsigned char *)RL_CALLOC(maxOutputSize, 1);
|
||||
if (decodedData == NULL) return NULL;
|
||||
|
||||
int outputCount = 0;
|
||||
for (int i = 0; i < dataSize;)
|
||||
{
|
||||
if (data[4*i + 3] == '=')
|
||||
{
|
||||
if (data[4*i + 2] == '=') outSize += 1;
|
||||
else outSize += 2;
|
||||
}
|
||||
else outSize += 3;
|
||||
// Every 4 sixtets must generate 3 octets
|
||||
unsigned int sixtetA = base64DecodeTable[(unsigned char)text[i]];
|
||||
unsigned int sixtetB = base64DecodeTable[(unsigned char)text[i + 1]];
|
||||
unsigned int sixtetC = ((unsigned char)text[i + 2] != '=')? base64DecodeTable[(unsigned char)text[i + 2]] : 0;
|
||||
unsigned int sixtetD = ((unsigned char)text[i + 3] != '=')? base64DecodeTable[(unsigned char)text[i + 3]] : 0;
|
||||
|
||||
unsigned int octetPack = (sixtetA << 18) | (sixtetB << 12) | (sixtetC << 6) | sixtetD;
|
||||
|
||||
decodedData[outputCount + 0] = (octetPack >> 16) & 0xff;
|
||||
decodedData[outputCount + 1] = (octetPack >> 8) & 0xff;
|
||||
decodedData[outputCount + 2] = octetPack & 0xff;
|
||||
outputCount += 3;
|
||||
i += 4;
|
||||
}
|
||||
|
||||
// Allocate memory to store decoded Base64 data
|
||||
unsigned char *decodedData = (unsigned char *)RL_MALLOC(outSize);
|
||||
if (estimatedOutputSize != (outputCount - padding)) TRACELOG(LOG_WARNING, "BASE64: Decoded size differs from estimation");
|
||||
|
||||
for (int i = 0; i < outSize/3; i++)
|
||||
{
|
||||
unsigned char a = base64decodeTable[(int)data[4*i]];
|
||||
unsigned char b = base64decodeTable[(int)data[4*i + 1]];
|
||||
unsigned char c = base64decodeTable[(int)data[4*i + 2]];
|
||||
unsigned char d = base64decodeTable[(int)data[4*i + 3]];
|
||||
|
||||
decodedData[3*i] = (a << 2) | (b >> 4);
|
||||
decodedData[3*i + 1] = (b << 4) | (c >> 2);
|
||||
decodedData[3*i + 2] = (c << 6) | d;
|
||||
}
|
||||
|
||||
if (outSize%3 == 1)
|
||||
{
|
||||
int n = outSize/3;
|
||||
unsigned char a = base64decodeTable[(int)data[4*n]];
|
||||
unsigned char b = base64decodeTable[(int)data[4*n + 1]];
|
||||
decodedData[outSize - 1] = (a << 2) | (b >> 4);
|
||||
}
|
||||
else if (outSize%3 == 2)
|
||||
{
|
||||
int n = outSize/3;
|
||||
unsigned char a = base64decodeTable[(int)data[4*n]];
|
||||
unsigned char b = base64decodeTable[(int)data[4*n + 1]];
|
||||
unsigned char c = base64decodeTable[(int)data[4*n + 2]];
|
||||
decodedData[outSize - 2] = (a << 2) | (b >> 4);
|
||||
decodedData[outSize - 1] = (b << 4) | (c >> 2);
|
||||
}
|
||||
|
||||
*outputSize = outSize;
|
||||
*outputSize = estimatedOutputSize;
|
||||
return decodedData;
|
||||
}
|
||||
|
||||
@ -2627,38 +2652,38 @@ unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize)
|
||||
unsigned int ComputeCRC32(unsigned char *data, int dataSize)
|
||||
{
|
||||
static unsigned int crcTable[256] = {
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||
0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
||||
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
||||
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
||||
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
||||
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
||||
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
||||
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
||||
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
||||
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
||||
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
||||
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
||||
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
||||
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
||||
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
||||
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
||||
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
||||
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
||||
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
||||
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
||||
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
||||
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
unsigned int crc = ~0u;
|
||||
@ -2722,7 +2747,7 @@ unsigned int *ComputeMD5(unsigned char *data, int dataSize)
|
||||
|
||||
int newDataSize = ((((dataSize + 8)/64) + 1)*64) - 8;
|
||||
|
||||
unsigned char *msg = RL_CALLOC(newDataSize + 64, 1); // Initialize with '0' bits, allocating 64 extra bytes
|
||||
unsigned char *msg = (unsigned char *)RL_CALLOC(newDataSize + 64, 1); // Initialize with '0' bits, allocating 64 extra bytes
|
||||
memcpy(msg, data, dataSize);
|
||||
msg[dataSize] = 128; // Write the '1' bit
|
||||
|
||||
@ -2812,7 +2837,7 @@ unsigned int *ComputeSHA1(unsigned char *data, int dataSize)
|
||||
|
||||
int newDataSize = ((((dataSize + 8)/64) + 1)*64);
|
||||
|
||||
unsigned char *msg = RL_CALLOC(newDataSize, 1); // Initialize with '0' bits
|
||||
unsigned char *msg = (unsigned char *)RL_CALLOC(newDataSize, 1); // Initialize with '0' bits
|
||||
memcpy(msg, data, dataSize);
|
||||
msg[dataSize] = 128; // Write the '1' bit
|
||||
|
||||
@ -3343,11 +3368,11 @@ int GetGamepadAxisCount(int gamepad)
|
||||
// Get axis movement vector for a gamepad
|
||||
float GetGamepadAxisMovement(int gamepad, int axis)
|
||||
{
|
||||
float value = (axis == GAMEPAD_AXIS_LEFT_TRIGGER || axis == GAMEPAD_AXIS_RIGHT_TRIGGER)? -1.0f : 0.0f;
|
||||
float value = ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))? -1.0f : 0.0f;
|
||||
|
||||
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXIS))
|
||||
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXES))
|
||||
{
|
||||
float movement = value < 0.0f ? CORE.Input.Gamepad.axisState[gamepad][axis] : fabsf(CORE.Input.Gamepad.axisState[gamepad][axis]);
|
||||
float movement = (value < 0.0f)? CORE.Input.Gamepad.axisState[gamepad][axis] : fabsf(CORE.Input.Gamepad.axisState[gamepad][axis]);
|
||||
|
||||
if (movement > value) value = CORE.Input.Gamepad.axisState[gamepad][axis];
|
||||
}
|
||||
@ -3688,12 +3713,16 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const
|
||||
(strcmp(dp->d_name, "..") != 0))
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
sprintf(path, "%s\\%s", basePath, dp->d_name);
|
||||
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s\\%s", basePath, dp->d_name);
|
||||
#else
|
||||
sprintf(path, "%s/%s", basePath, dp->d_name);
|
||||
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s/%s", basePath, dp->d_name);
|
||||
#endif
|
||||
|
||||
if (filter != NULL)
|
||||
if ((pathLength < 0) || (pathLength >= MAX_FILEPATH_LENGTH))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "FILEIO: Path longer than %d characters (%s...)", MAX_FILEPATH_LENGTH, basePath);
|
||||
}
|
||||
else if (filter != NULL)
|
||||
{
|
||||
if (IsPathFile(path))
|
||||
{
|
||||
@ -3728,6 +3757,7 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const
|
||||
// Scan all files and directories recursively from a base path
|
||||
static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *files, const char *filter)
|
||||
{
|
||||
// WARNING: Path can not be static or it will be reused between recursive function calls!
|
||||
char path[MAX_FILEPATH_LENGTH] = { 0 };
|
||||
memset(path, 0, MAX_FILEPATH_LENGTH);
|
||||
|
||||
@ -3742,12 +3772,16 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi
|
||||
{
|
||||
// Construct new path from our base path
|
||||
#if defined(_WIN32)
|
||||
sprintf(path, "%s\\%s", basePath, dp->d_name);
|
||||
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s\\%s", basePath, dp->d_name);
|
||||
#else
|
||||
sprintf(path, "%s/%s", basePath, dp->d_name);
|
||||
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s/%s", basePath, dp->d_name);
|
||||
#endif
|
||||
|
||||
if (IsPathFile(path))
|
||||
if ((pathLength < 0) || (pathLength >= MAX_FILEPATH_LENGTH))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "FILEIO: Path longer than %d characters (%s...)", MAX_FILEPATH_LENGTH, basePath);
|
||||
}
|
||||
else if (IsPathFile(path))
|
||||
{
|
||||
if (filter != NULL)
|
||||
{
|
||||
@ -4017,10 +4051,10 @@ static void RecordAutomationEvent(void)
|
||||
if (currentEventList->count == currentEventList->capacity) return; // Security check
|
||||
}
|
||||
|
||||
for (int axis = 0; axis < MAX_GAMEPAD_AXIS; axis++)
|
||||
for (int axis = 0; axis < MAX_GAMEPAD_AXES; axis++)
|
||||
{
|
||||
// Event type: INPUT_GAMEPAD_AXIS_MOTION
|
||||
float defaultMovement = (axis == GAMEPAD_AXIS_LEFT_TRIGGER || axis == GAMEPAD_AXIS_RIGHT_TRIGGER)? -1.0f : 0.0f;
|
||||
float defaultMovement = ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))? -1.0f : 0.0f;
|
||||
if (GetGamepadAxisMovement(gamepad, axis) != defaultMovement)
|
||||
{
|
||||
currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
|
||||
|
||||
36
src/rlgl.h
36
src/rlgl.h
@ -56,8 +56,8 @@
|
||||
*
|
||||
* #define RL_MAX_MATRIX_STACK_SIZE 32 // Maximum size of internal Matrix stack
|
||||
* #define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported
|
||||
* #define RL_CULL_DISTANCE_NEAR 0.01 // Default projection matrix near cull distance
|
||||
* #define RL_CULL_DISTANCE_FAR 1000.0 // Default projection matrix far cull distance
|
||||
* #define RL_CULL_DISTANCE_NEAR 0.05 // Default projection matrix near cull distance
|
||||
* #define RL_CULL_DISTANCE_FAR 4000.0 // Default projection matrix far cull distance
|
||||
*
|
||||
* When loading a shader, the following vertex attributes and uniform
|
||||
* location names are tried to be set automatically:
|
||||
@ -234,10 +234,10 @@
|
||||
|
||||
// Projection matrix culling
|
||||
#ifndef RL_CULL_DISTANCE_NEAR
|
||||
#define RL_CULL_DISTANCE_NEAR 0.01 // Default near cull distance
|
||||
#define RL_CULL_DISTANCE_NEAR 0.05 // Default near cull distance
|
||||
#endif
|
||||
#ifndef RL_CULL_DISTANCE_FAR
|
||||
#define RL_CULL_DISTANCE_FAR 1000.0 // Default far cull distance
|
||||
#define RL_CULL_DISTANCE_FAR 4000.0 // Default far cull distance
|
||||
#endif
|
||||
|
||||
// Texture parameters (equivalent to OpenGL defines)
|
||||
@ -1459,9 +1459,6 @@ void rlBegin(int mode)
|
||||
// NOTE: In all three cases, vertex are accumulated over default internal vertex buffer
|
||||
if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode != mode)
|
||||
{
|
||||
// Get current binded texture to preserve it between draw modes change (QUADS <--> TRIANGLES)
|
||||
int currentTexture = RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId;
|
||||
|
||||
if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount > 0)
|
||||
{
|
||||
// Make sure current RLGL.currentBatch->draws[i].vertexCount is aligned a multiple of 4,
|
||||
@ -1484,16 +1481,13 @@ void rlBegin(int mode)
|
||||
|
||||
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 = currentTexture; // Preserve active texture
|
||||
RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId = RLGL.State.defaultTextureId;
|
||||
}
|
||||
}
|
||||
|
||||
// Finish vertex providing
|
||||
void rlEnd(void)
|
||||
{
|
||||
// Reset texture to default
|
||||
rlSetTexture(RLGL.State.defaultTextureId);
|
||||
|
||||
// NOTE: Depth increment is dependant on rlOrtho(): z-near and z-far values,
|
||||
// as well as depth buffer bit-depth (16bit or 24bit or 32bit)
|
||||
// Correct increment formula would be: depthInc = (zfar - znear)/pow(2, bits)
|
||||
@ -1754,7 +1748,6 @@ void rlTextureParameters(unsigned int id, int param, int value)
|
||||
#endif
|
||||
}
|
||||
else glTexParameteri(GL_TEXTURE_2D, param, value);
|
||||
|
||||
} break;
|
||||
case RL_TEXTURE_MAG_FILTER:
|
||||
case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_2D, param, value); break;
|
||||
@ -1799,7 +1792,6 @@ void rlCubemapParameters(unsigned int id, int param, int value)
|
||||
else TRACELOG(RL_LOG_WARNING, "GL: Clamp mirror wrap mode not supported (GL_MIRROR_CLAMP_EXT)");
|
||||
}
|
||||
else glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value);
|
||||
|
||||
} break;
|
||||
case RL_TEXTURE_MAG_FILTER:
|
||||
case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value); break;
|
||||
@ -2118,14 +2110,12 @@ void rlSetBlendMode(int mode)
|
||||
{
|
||||
// NOTE: Using GL blend src/dst factors and GL equation configured with rlSetBlendFactors()
|
||||
glBlendFunc(RLGL.State.glBlendSrcFactor, RLGL.State.glBlendDstFactor); glBlendEquation(RLGL.State.glBlendEquation);
|
||||
|
||||
} break;
|
||||
case RL_BLEND_CUSTOM_SEPARATE:
|
||||
{
|
||||
// NOTE: Using GL blend src/dst factors and GL equation configured with rlSetBlendFactorsSeparate()
|
||||
glBlendFuncSeparate(RLGL.State.glBlendSrcFactorRGB, RLGL.State.glBlendDestFactorRGB, RLGL.State.glBlendSrcFactorAlpha, RLGL.State.glBlendDestFactorAlpha);
|
||||
glBlendEquationSeparate(RLGL.State.glBlendEquationRGB, RLGL.State.glBlendEquationAlpha);
|
||||
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
@ -2435,7 +2425,7 @@ void rlLoadExtensions(void *loader)
|
||||
|
||||
// Get supported extensions list
|
||||
GLint numExt = 0;
|
||||
const char **extList = RL_MALLOC(512*sizeof(const char *)); // Allocate 512 strings pointers (2 KB)
|
||||
const char **extList = (const char **)RL_MALLOC(512*sizeof(const char *)); // Allocate 512 strings pointers (2 KB)
|
||||
const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string
|
||||
|
||||
// NOTE: We have to duplicate string because glGetString() returns a const string
|
||||
@ -3317,7 +3307,7 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format,
|
||||
// Activate Trilinear filtering if mipmaps are available
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmapCount); // user defined mip count would break without this.
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmapCount); // Required for user-defined mip count
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -3690,12 +3680,12 @@ unsigned char *rlReadScreenPixels(int width, int height)
|
||||
|
||||
// Flip image vertically!
|
||||
// NOTE: Alpha value has already been applied to RGB in framebuffer, we don't need it!
|
||||
for (int y = height - 1; y >= height / 2; y--)
|
||||
for (int y = height - 1; y >= height/2; y--)
|
||||
{
|
||||
for (int x = 0; x < (width*4); x += 4)
|
||||
{
|
||||
size_t s = ((height - 1) - y)*width*4 + x;
|
||||
size_t e = y*width*4 + x;
|
||||
unsigned int s = ((height - 1) - y)*width*4 + x;
|
||||
unsigned int e = y*width*4 + x;
|
||||
|
||||
unsigned char r = imgData[s];
|
||||
unsigned char g = imgData[s+1];
|
||||
@ -3753,19 +3743,16 @@ void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType,
|
||||
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_2D, texId, mipLevel);
|
||||
else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_RENDERBUFFER, texId);
|
||||
else if (texType >= RL_ATTACHMENT_CUBEMAP_POSITIVE_X) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_CUBE_MAP_POSITIVE_X + texType, texId, mipLevel);
|
||||
|
||||
} break;
|
||||
case RL_ATTACHMENT_DEPTH:
|
||||
{
|
||||
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texId, mipLevel);
|
||||
else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, texId);
|
||||
|
||||
} break;
|
||||
case RL_ATTACHMENT_STENCIL:
|
||||
{
|
||||
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texId, mipLevel);
|
||||
else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, texId);
|
||||
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
@ -4191,6 +4178,9 @@ unsigned int rlCompileShader(const char *shaderCode, int type)
|
||||
RL_FREE(log);
|
||||
}
|
||||
|
||||
// Unload object allocated by glCreateShader(),
|
||||
// despite failing in the compilation process
|
||||
glDeleteShader(shader);
|
||||
shader = 0;
|
||||
}
|
||||
else
|
||||
|
||||
446
src/rmodels.c
446
src/rmodels.c
@ -496,12 +496,18 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color
|
||||
vertices[2] = (Vector3){ cosslice*vertices[2].x - sinslice*vertices[2].z, vertices[2].y, sinslice*vertices[2].x + cosslice*vertices[2].z }; // Rotation matrix around y axis
|
||||
vertices[3] = (Vector3){ cosslice*vertices[3].x - sinslice*vertices[3].z, vertices[3].y, sinslice*vertices[3].x + cosslice*vertices[3].z };
|
||||
|
||||
rlNormal3f(vertices[0].x, vertices[0].y, vertices[0].z);
|
||||
rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
|
||||
rlNormal3f(vertices[3].x, vertices[3].y, vertices[3].z);
|
||||
rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z);
|
||||
rlNormal3f(vertices[1].x, vertices[1].y, vertices[1].z);
|
||||
rlVertex3f(vertices[1].x, vertices[1].y, vertices[1].z);
|
||||
|
||||
rlNormal3f(vertices[0].x, vertices[0].y, vertices[0].z);
|
||||
rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
|
||||
rlNormal3f(vertices[2].x, vertices[2].y, vertices[2].z);
|
||||
rlVertex3f(vertices[2].x, vertices[2].y, vertices[2].z);
|
||||
rlNormal3f(vertices[3].x, vertices[3].y, vertices[3].z);
|
||||
rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z);
|
||||
}
|
||||
|
||||
@ -1423,9 +1429,13 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
|
||||
|
||||
rlEnableTexture(material.maps[MATERIAL_MAP_DIFFUSE].texture.id);
|
||||
|
||||
rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices);
|
||||
if (mesh.animVertices) rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.animVertices);
|
||||
else rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices);
|
||||
|
||||
rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords);
|
||||
rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals);
|
||||
if (mesh.normals) rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.animNormals);
|
||||
else rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals);
|
||||
|
||||
rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors);
|
||||
|
||||
rlPushMatrix();
|
||||
@ -2164,7 +2174,7 @@ Material *LoadMaterials(const char *fileName, int *materialCount)
|
||||
int result = tinyobj_parse_mtl_file(&mats, &count, fileName);
|
||||
if (result != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to parse materials file", fileName);
|
||||
|
||||
materials = RL_MALLOC(count*sizeof(Material));
|
||||
materials = (Material *)RL_MALLOC(count*sizeof(Material));
|
||||
ProcessMaterialsOBJ(materials, mats, count);
|
||||
|
||||
tinyobj_materials_free(mats, count);
|
||||
@ -2286,38 +2296,28 @@ void UpdateModelAnimationBones(Model model, ModelAnimation anim, int frame)
|
||||
}
|
||||
}
|
||||
|
||||
// Update all bones and boneMatrices of first mesh with bones.
|
||||
for (int boneId = 0; boneId < anim.boneCount; boneId++)
|
||||
{
|
||||
Vector3 inTranslation = model.bindPose[boneId].translation;
|
||||
Quaternion inRotation = model.bindPose[boneId].rotation;
|
||||
Vector3 inScale = model.bindPose[boneId].scale;
|
||||
|
||||
Vector3 outTranslation = anim.framePoses[frame][boneId].translation;
|
||||
Quaternion outRotation = anim.framePoses[frame][boneId].rotation;
|
||||
Vector3 outScale = anim.framePoses[frame][boneId].scale;
|
||||
|
||||
Quaternion invRotation = QuaternionInvert(inRotation);
|
||||
Vector3 invTranslation = Vector3RotateByQuaternion(Vector3Negate(inTranslation), invRotation);
|
||||
Vector3 invScale = Vector3Divide((Vector3){ 1.0f, 1.0f, 1.0f }, inScale);
|
||||
|
||||
Vector3 boneTranslation = Vector3Add(Vector3RotateByQuaternion(
|
||||
Vector3Multiply(outScale, invTranslation), outRotation), outTranslation);
|
||||
Quaternion boneRotation = QuaternionMultiply(outRotation, invRotation);
|
||||
Vector3 boneScale = Vector3Multiply(outScale, invScale);
|
||||
|
||||
Matrix boneMatrix = MatrixMultiply(MatrixMultiply(
|
||||
QuaternionToMatrix(boneRotation),
|
||||
MatrixTranslate(boneTranslation.x, boneTranslation.y, boneTranslation.z)),
|
||||
MatrixScale(boneScale.x, boneScale.y, boneScale.z));
|
||||
|
||||
model.meshes[firstMeshWithBones].boneMatrices[boneId] = boneMatrix;
|
||||
}
|
||||
|
||||
// Update remaining meshes with bones
|
||||
// NOTE: Using deep copy because shallow copy results in double free with 'UnloadModel()'
|
||||
if (firstMeshWithBones != -1)
|
||||
{
|
||||
// Update all bones and boneMatrices of first mesh with bones.
|
||||
for (int boneId = 0; boneId < anim.boneCount; boneId++)
|
||||
{
|
||||
Transform *bindTransform = &model.bindPose[boneId];
|
||||
Matrix bindMatrix = MatrixMultiply(MatrixMultiply(
|
||||
MatrixScale(bindTransform->scale.x, bindTransform->scale.y, bindTransform->scale.z),
|
||||
QuaternionToMatrix(bindTransform->rotation)),
|
||||
MatrixTranslate(bindTransform->translation.x, bindTransform->translation.y, bindTransform->translation.z));
|
||||
|
||||
Transform *targetTransform = &anim.framePoses[frame][boneId];
|
||||
Matrix targetMatrix = MatrixMultiply(MatrixMultiply(
|
||||
MatrixScale(targetTransform->scale.x, targetTransform->scale.y, targetTransform->scale.z),
|
||||
QuaternionToMatrix(targetTransform->rotation)),
|
||||
MatrixTranslate(targetTransform->translation.x, targetTransform->translation.y, targetTransform->translation.z));
|
||||
|
||||
model.meshes[firstMeshWithBones].boneMatrices[boneId] = MatrixMultiply(MatrixInvert(bindMatrix), targetMatrix);
|
||||
}
|
||||
|
||||
// Update remaining meshes with bones
|
||||
// NOTE: Using deep copy because shallow copy results in double free with 'UnloadModel()'
|
||||
for (int i = firstMeshWithBones + 1; i < model.meshCount; i++)
|
||||
{
|
||||
if (model.meshes[i].boneMatrices)
|
||||
@ -3608,16 +3608,16 @@ BoundingBox GetMeshBoundingBox(Mesh mesh)
|
||||
}
|
||||
|
||||
// Compute mesh tangents
|
||||
// NOTE: To calculate mesh tangents and binormals we need mesh vertex positions and texture coordinates
|
||||
// Implementation based on: https://answers.unity.com/questions/7789/calculating-tangents-vector4.html
|
||||
void GenMeshTangents(Mesh *mesh)
|
||||
{
|
||||
if ((mesh->vertices == NULL) || (mesh->texcoords == NULL))
|
||||
// Check if input mesh data is useful
|
||||
if ((mesh == NULL) || (mesh->vertices == NULL) || (mesh->texcoords == NULL) || (mesh->normals == NULL))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "MESH: Tangents generation requires texcoord vertex attribute data");
|
||||
TRACELOG(LOG_WARNING, "MESH: Tangents generation requires vertices, texcoords and normals vertex attribute data");
|
||||
return;
|
||||
}
|
||||
|
||||
// Allocate or reallocate tangents data
|
||||
if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
|
||||
else
|
||||
{
|
||||
@ -3625,26 +3625,51 @@ void GenMeshTangents(Mesh *mesh)
|
||||
mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
|
||||
}
|
||||
|
||||
Vector3 *tan1 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3));
|
||||
Vector3 *tan2 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3));
|
||||
// Allocate temporary arrays for tangents calculation
|
||||
Vector3 *tan1 = (Vector3 *)RL_CALLOC(mesh->vertexCount, sizeof(Vector3));
|
||||
Vector3 *tan2 = (Vector3 *)RL_CALLOC(mesh->vertexCount, sizeof(Vector3));
|
||||
|
||||
if (mesh->vertexCount % 3 != 0)
|
||||
if (tan1 == NULL || tan2 == NULL)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "MESH: vertexCount expected to be a multiple of 3. Expect uninitialized values.");
|
||||
TRACELOG(LOG_WARNING, "MESH: Failed to allocate temporary memory for tangent calculation");
|
||||
if (tan1) RL_FREE(tan1);
|
||||
if (tan2) RL_FREE(tan2);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i <= mesh->vertexCount - 3; i += 3)
|
||||
// Process all triangles of the mesh
|
||||
// 'triangleCount' must be always valid
|
||||
for (int t = 0; t < mesh->triangleCount; t++)
|
||||
{
|
||||
// Get triangle vertices
|
||||
Vector3 v1 = { mesh->vertices[(i + 0)*3 + 0], mesh->vertices[(i + 0)*3 + 1], mesh->vertices[(i + 0)*3 + 2] };
|
||||
Vector3 v2 = { mesh->vertices[(i + 1)*3 + 0], mesh->vertices[(i + 1)*3 + 1], mesh->vertices[(i + 1)*3 + 2] };
|
||||
Vector3 v3 = { mesh->vertices[(i + 2)*3 + 0], mesh->vertices[(i + 2)*3 + 1], mesh->vertices[(i + 2)*3 + 2] };
|
||||
// Get triangle vertex indices
|
||||
int i0, i1, i2;
|
||||
|
||||
if (mesh->indices != NULL)
|
||||
{
|
||||
// Use indices if available
|
||||
i0 = mesh->indices[t*3 + 0];
|
||||
i1 = mesh->indices[t*3 + 1];
|
||||
i2 = mesh->indices[t*3 + 2];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sequential access for non-indexed mesh
|
||||
i0 = t*3 + 0;
|
||||
i1 = t*3 + 1;
|
||||
i2 = t*3 + 2;
|
||||
}
|
||||
|
||||
// Get triangle vertices position
|
||||
Vector3 v1 = { mesh->vertices[i0*3 + 0], mesh->vertices[i0*3 + 1], mesh->vertices[i0*3 + 2] };
|
||||
Vector3 v2 = { mesh->vertices[i1*3 + 0], mesh->vertices[i1*3 + 1], mesh->vertices[i1*3 + 2] };
|
||||
Vector3 v3 = { mesh->vertices[i2*3 + 0], mesh->vertices[i2*3 + 1], mesh->vertices[i2*3 + 2] };
|
||||
|
||||
// Get triangle texcoords
|
||||
Vector2 uv1 = { mesh->texcoords[(i + 0)*2 + 0], mesh->texcoords[(i + 0)*2 + 1] };
|
||||
Vector2 uv2 = { mesh->texcoords[(i + 1)*2 + 0], mesh->texcoords[(i + 1)*2 + 1] };
|
||||
Vector2 uv3 = { mesh->texcoords[(i + 2)*2 + 0], mesh->texcoords[(i + 2)*2 + 1] };
|
||||
Vector2 uv1 = { mesh->texcoords[i0*2 + 0], mesh->texcoords[i0*2 + 1] };
|
||||
Vector2 uv2 = { mesh->texcoords[i1*2 + 0], mesh->texcoords[i1*2 + 1] };
|
||||
Vector2 uv3 = { mesh->texcoords[i2*2 + 0], mesh->texcoords[i2*2 + 1] };
|
||||
|
||||
// Calculate triangle edges
|
||||
float x1 = v2.x - v1.x;
|
||||
float y1 = v2.y - v1.y;
|
||||
float z1 = v2.z - v1.z;
|
||||
@ -3652,65 +3677,95 @@ void GenMeshTangents(Mesh *mesh)
|
||||
float y2 = v3.y - v1.y;
|
||||
float z2 = v3.z - v1.z;
|
||||
|
||||
// Calculate texture coordinate differences
|
||||
float s1 = uv2.x - uv1.x;
|
||||
float t1 = uv2.y - uv1.y;
|
||||
float s2 = uv3.x - uv1.x;
|
||||
float t2 = uv3.y - uv1.y;
|
||||
|
||||
// Calculate denominator and check for degenerate UV
|
||||
float div = s1*t2 - s2*t1;
|
||||
float r = (div == 0.0f)? 0.0f : 1.0f/div;
|
||||
float r = (fabsf(div) < 0.0001f)? 0.0f : 1.0f/div;
|
||||
|
||||
// Calculate tangent and bitangent directions
|
||||
Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r };
|
||||
Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r };
|
||||
|
||||
tan1[i + 0] = sdir;
|
||||
tan1[i + 1] = sdir;
|
||||
tan1[i + 2] = sdir;
|
||||
// Accumulate tangents and bitangents for each vertex of the triangle
|
||||
tan1[i0] = Vector3Add(tan1[i0], sdir);
|
||||
tan1[i1] = Vector3Add(tan1[i1], sdir);
|
||||
tan1[i2] = Vector3Add(tan1[i2], sdir);
|
||||
|
||||
tan2[i + 0] = tdir;
|
||||
tan2[i + 1] = tdir;
|
||||
tan2[i + 2] = tdir;
|
||||
tan2[i0] = Vector3Add(tan2[i0], tdir);
|
||||
tan2[i1] = Vector3Add(tan2[i1], tdir);
|
||||
tan2[i2] = Vector3Add(tan2[i2], tdir);
|
||||
}
|
||||
|
||||
// Compute tangents considering normals
|
||||
// Calculate final tangents for each vertex
|
||||
for (int i = 0; i < mesh->vertexCount; i++)
|
||||
{
|
||||
Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
|
||||
Vector3 tangent = tan1[i];
|
||||
|
||||
// TODO: Review, not sure if tangent computation is right, just used reference proposed maths...
|
||||
#if defined(COMPUTE_TANGENTS_METHOD_01)
|
||||
Vector3 tmp = Vector3Subtract(tangent, Vector3Scale(normal, Vector3DotProduct(normal, tangent)));
|
||||
tmp = Vector3Normalize(tmp);
|
||||
mesh->tangents[i*4 + 0] = tmp.x;
|
||||
mesh->tangents[i*4 + 1] = tmp.y;
|
||||
mesh->tangents[i*4 + 2] = tmp.z;
|
||||
mesh->tangents[i*4 + 3] = 1.0f;
|
||||
#else
|
||||
Vector3OrthoNormalize(&normal, &tangent);
|
||||
mesh->tangents[i*4 + 0] = tangent.x;
|
||||
mesh->tangents[i*4 + 1] = tangent.y;
|
||||
mesh->tangents[i*4 + 2] = tangent.z;
|
||||
mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f)? -1.0f : 1.0f;
|
||||
#endif
|
||||
// Handle zero tangent (can happen with degenerate UVs)
|
||||
if (Vector3Length(tangent) < 0.0001f)
|
||||
{
|
||||
// Create a tangent perpendicular to the normal
|
||||
if (fabsf(normal.z) > 0.707f) tangent = (Vector3){ 1.0f, 0.0f, 0.0f };
|
||||
else tangent = Vector3Normalize((Vector3){ -normal.y, normal.x, 0.0f });
|
||||
|
||||
mesh->tangents[i*4 + 0] = tangent.x;
|
||||
mesh->tangents[i*4 + 1] = tangent.y;
|
||||
mesh->tangents[i*4 + 2] = tangent.z;
|
||||
mesh->tangents[i*4 + 3] = 1.0f;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Gram-Schmidt orthogonalization to make tangent orthogonal to normal
|
||||
// T_prime = T - N * dot(N, T)
|
||||
Vector3 orthogonalized = Vector3Subtract(tangent, Vector3Scale(normal, Vector3DotProduct(normal, tangent)));
|
||||
|
||||
// Handle cases where orthogonalized vector is too small
|
||||
if (Vector3Length(orthogonalized) < 0.0001f)
|
||||
{
|
||||
// Create a tangent perpendicular to the normal
|
||||
if (fabsf(normal.z) > 0.707f) orthogonalized = (Vector3){ 1.0f, 0.0f, 0.0f };
|
||||
else orthogonalized = Vector3Normalize((Vector3){ -normal.y, normal.x, 0.0f });
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normalize the orthogonalized tangent
|
||||
orthogonalized = Vector3Normalize(orthogonalized);
|
||||
}
|
||||
|
||||
// Store the calculated tangent
|
||||
mesh->tangents[i*4 + 0] = orthogonalized.x;
|
||||
mesh->tangents[i*4 + 1] = orthogonalized.y;
|
||||
mesh->tangents[i*4 + 2] = orthogonalized.z;
|
||||
|
||||
// Calculate the handedness (w component)
|
||||
mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, orthogonalized), tan2[i]) < 0.0f)? -1.0f : 1.0f;
|
||||
}
|
||||
|
||||
// Free temporary arrays
|
||||
RL_FREE(tan1);
|
||||
RL_FREE(tan2);
|
||||
|
||||
// Update vertex buffers if available
|
||||
if (mesh->vboId != NULL)
|
||||
{
|
||||
if (mesh->vboId[SHADER_LOC_VERTEX_TANGENT] != 0)
|
||||
{
|
||||
// Update existing vertex buffer
|
||||
// Update existing tangent vertex buffer
|
||||
rlUpdateVertexBuffer(mesh->vboId[SHADER_LOC_VERTEX_TANGENT], mesh->tangents, mesh->vertexCount*4*sizeof(float), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load a new tangent attributes buffer
|
||||
// Create new tangent vertex buffer
|
||||
mesh->vboId[SHADER_LOC_VERTEX_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), false);
|
||||
}
|
||||
|
||||
// Set up vertex attributes for shader
|
||||
rlEnableVertexArray(mesh->vaoId);
|
||||
rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, 4, RL_FLOAT, 0, 0, 0);
|
||||
rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT);
|
||||
@ -4587,13 +4642,13 @@ static Model LoadIQM(const char *fileName)
|
||||
//fileDataPtr += sizeof(IQMHeader); // Move file data pointer
|
||||
|
||||
// Meshes data processing
|
||||
imesh = RL_MALLOC(iqmHeader->num_meshes*sizeof(IQMMesh));
|
||||
imesh = (IQMMesh *)RL_MALLOC(iqmHeader->num_meshes*sizeof(IQMMesh));
|
||||
//fseek(iqmFile, iqmHeader->ofs_meshes, SEEK_SET);
|
||||
//fread(imesh, sizeof(IQMMesh)*iqmHeader->num_meshes, 1, iqmFile);
|
||||
memcpy(imesh, fileDataPtr + iqmHeader->ofs_meshes, iqmHeader->num_meshes*sizeof(IQMMesh));
|
||||
|
||||
model.meshCount = iqmHeader->num_meshes;
|
||||
model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh));
|
||||
model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
|
||||
|
||||
model.materialCount = model.meshCount;
|
||||
model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
|
||||
@ -4621,24 +4676,24 @@ static Model LoadIQM(const char *fileName)
|
||||
|
||||
model.meshes[i].vertexCount = imesh[i].num_vertexes;
|
||||
|
||||
model.meshes[i].vertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex positions
|
||||
model.meshes[i].normals = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex normals
|
||||
model.meshes[i].texcoords = RL_CALLOC(model.meshes[i].vertexCount*2, sizeof(float)); // Default vertex texcoords
|
||||
model.meshes[i].vertices = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex positions
|
||||
model.meshes[i].normals = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex normals
|
||||
model.meshes[i].texcoords = (float *)RL_CALLOC(model.meshes[i].vertexCount*2, sizeof(float)); // Default vertex texcoords
|
||||
|
||||
model.meshes[i].boneIds = RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(unsigned char)); // Up-to 4 bones supported!
|
||||
model.meshes[i].boneWeights = RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(float)); // Up-to 4 bones supported!
|
||||
model.meshes[i].boneIds = (unsigned char *)RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(unsigned char)); // Up-to 4 bones supported!
|
||||
model.meshes[i].boneWeights = (float *)RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(float)); // Up-to 4 bones supported!
|
||||
|
||||
model.meshes[i].triangleCount = imesh[i].num_triangles;
|
||||
model.meshes[i].indices = RL_CALLOC(model.meshes[i].triangleCount*3, sizeof(unsigned short));
|
||||
model.meshes[i].indices = (unsigned short *)RL_CALLOC(model.meshes[i].triangleCount*3, sizeof(unsigned short));
|
||||
|
||||
// Animated vertex data, what we actually process for rendering
|
||||
// NOTE: Animated vertex should be re-uploaded to GPU (if not using GPU skinning)
|
||||
model.meshes[i].animVertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
|
||||
model.meshes[i].animNormals = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
|
||||
model.meshes[i].animVertices = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
|
||||
model.meshes[i].animNormals = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
|
||||
}
|
||||
|
||||
// Triangles data processing
|
||||
tri = RL_MALLOC(iqmHeader->num_triangles*sizeof(IQMTriangle));
|
||||
tri = (IQMTriangle *)RL_MALLOC(iqmHeader->num_triangles*sizeof(IQMTriangle));
|
||||
//fseek(iqmFile, iqmHeader->ofs_triangles, SEEK_SET);
|
||||
//fread(tri, sizeof(IQMTriangle), iqmHeader->num_triangles, iqmFile);
|
||||
memcpy(tri, fileDataPtr + iqmHeader->ofs_triangles, iqmHeader->num_triangles*sizeof(IQMTriangle));
|
||||
@ -4660,7 +4715,7 @@ static Model LoadIQM(const char *fileName)
|
||||
}
|
||||
|
||||
// Vertex arrays data processing
|
||||
va = RL_MALLOC(iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
|
||||
va = (IQMVertexArray *)RL_MALLOC(iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
|
||||
//fseek(iqmFile, iqmHeader->ofs_vertexarrays, SEEK_SET);
|
||||
//fread(va, sizeof(IQMVertexArray), iqmHeader->num_vertexarrays, iqmFile);
|
||||
memcpy(va, fileDataPtr + iqmHeader->ofs_vertexarrays, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
|
||||
@ -4671,7 +4726,7 @@ static Model LoadIQM(const char *fileName)
|
||||
{
|
||||
case IQM_POSITION:
|
||||
{
|
||||
vertex = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
|
||||
vertex = (float *)RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
|
||||
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||
//fread(vertex, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
|
||||
memcpy(vertex, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
|
||||
@ -4689,7 +4744,7 @@ static Model LoadIQM(const char *fileName)
|
||||
} break;
|
||||
case IQM_NORMAL:
|
||||
{
|
||||
normal = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
|
||||
normal = (float *)RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
|
||||
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||
//fread(normal, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
|
||||
memcpy(normal, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
|
||||
@ -4707,7 +4762,7 @@ static Model LoadIQM(const char *fileName)
|
||||
} break;
|
||||
case IQM_TEXCOORD:
|
||||
{
|
||||
text = RL_MALLOC(iqmHeader->num_vertexes*2*sizeof(float));
|
||||
text = (float *)RL_MALLOC(iqmHeader->num_vertexes*2*sizeof(float));
|
||||
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||
//fread(text, iqmHeader->num_vertexes*2*sizeof(float), 1, iqmFile);
|
||||
memcpy(text, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*2*sizeof(float));
|
||||
@ -4724,7 +4779,7 @@ static Model LoadIQM(const char *fileName)
|
||||
} break;
|
||||
case IQM_BLENDINDEXES:
|
||||
{
|
||||
blendi = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(char));
|
||||
blendi = (char *)RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(char));
|
||||
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||
//fread(blendi, iqmHeader->num_vertexes*4*sizeof(char), 1, iqmFile);
|
||||
memcpy(blendi, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(char));
|
||||
@ -4741,7 +4796,7 @@ static Model LoadIQM(const char *fileName)
|
||||
} break;
|
||||
case IQM_BLENDWEIGHTS:
|
||||
{
|
||||
blendw = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||
blendw = (unsigned char *)RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||
//fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
|
||||
memcpy(blendw, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||
@ -4758,14 +4813,14 @@ static Model LoadIQM(const char *fileName)
|
||||
} break;
|
||||
case IQM_COLOR:
|
||||
{
|
||||
color = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||
color = (unsigned char *)RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||
//fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
|
||||
memcpy(color, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||
|
||||
for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
|
||||
{
|
||||
model.meshes[m].colors = RL_CALLOC(model.meshes[m].vertexCount*4, sizeof(unsigned char));
|
||||
model.meshes[m].colors = (unsigned char *)RL_CALLOC(model.meshes[m].vertexCount*4, sizeof(unsigned char));
|
||||
|
||||
int vCounter = 0;
|
||||
for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
|
||||
@ -4779,14 +4834,14 @@ static Model LoadIQM(const char *fileName)
|
||||
}
|
||||
|
||||
// Bones (joints) data processing
|
||||
ijoint = RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
|
||||
ijoint = (IQMJoint *)RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
|
||||
//fseek(iqmFile, iqmHeader->ofs_joints, SEEK_SET);
|
||||
//fread(ijoint, sizeof(IQMJoint), iqmHeader->num_joints, iqmFile);
|
||||
memcpy(ijoint, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint));
|
||||
|
||||
model.boneCount = iqmHeader->num_joints;
|
||||
model.bones = RL_MALLOC(iqmHeader->num_joints*sizeof(BoneInfo));
|
||||
model.bindPose = RL_MALLOC(iqmHeader->num_joints*sizeof(Transform));
|
||||
model.bones = (BoneInfo *)RL_MALLOC(iqmHeader->num_joints*sizeof(BoneInfo));
|
||||
model.bindPose = (Transform *)RL_MALLOC(iqmHeader->num_joints*sizeof(Transform));
|
||||
|
||||
for (unsigned int i = 0; i < iqmHeader->num_joints; i++)
|
||||
{
|
||||
@ -4816,7 +4871,7 @@ static Model LoadIQM(const char *fileName)
|
||||
for (int i = 0; i < model.meshCount; i++)
|
||||
{
|
||||
model.meshes[i].boneCount = model.boneCount;
|
||||
model.meshes[i].boneMatrices = RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
|
||||
model.meshes[i].boneMatrices = (Matrix *)RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
|
||||
|
||||
for (int j = 0; j < model.meshes[i].boneCount; j++)
|
||||
{
|
||||
@ -4908,36 +4963,36 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCou
|
||||
}
|
||||
|
||||
// Get bones data
|
||||
IQMPose *poses = RL_MALLOC(iqmHeader->num_poses*sizeof(IQMPose));
|
||||
IQMPose *poses = (IQMPose *)RL_MALLOC(iqmHeader->num_poses*sizeof(IQMPose));
|
||||
//fseek(iqmFile, iqmHeader->ofs_poses, SEEK_SET);
|
||||
//fread(poses, sizeof(IQMPose), iqmHeader->num_poses, iqmFile);
|
||||
memcpy(poses, fileDataPtr + iqmHeader->ofs_poses, iqmHeader->num_poses*sizeof(IQMPose));
|
||||
|
||||
// Get animations data
|
||||
*animCount = iqmHeader->num_anims;
|
||||
IQMAnim *anim = RL_MALLOC(iqmHeader->num_anims*sizeof(IQMAnim));
|
||||
IQMAnim *anim = (IQMAnim *)RL_MALLOC(iqmHeader->num_anims*sizeof(IQMAnim));
|
||||
//fseek(iqmFile, iqmHeader->ofs_anims, SEEK_SET);
|
||||
//fread(anim, sizeof(IQMAnim), iqmHeader->num_anims, iqmFile);
|
||||
memcpy(anim, fileDataPtr + iqmHeader->ofs_anims, iqmHeader->num_anims*sizeof(IQMAnim));
|
||||
|
||||
ModelAnimation *animations = RL_MALLOC(iqmHeader->num_anims*sizeof(ModelAnimation));
|
||||
ModelAnimation *animations = (ModelAnimation *)RL_MALLOC(iqmHeader->num_anims*sizeof(ModelAnimation));
|
||||
|
||||
// frameposes
|
||||
unsigned short *framedata = RL_MALLOC(iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
|
||||
unsigned short *framedata = (unsigned short *)RL_MALLOC(iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
|
||||
//fseek(iqmFile, iqmHeader->ofs_frames, SEEK_SET);
|
||||
//fread(framedata, sizeof(unsigned short), iqmHeader->num_frames*iqmHeader->num_framechannels, iqmFile);
|
||||
memcpy(framedata, fileDataPtr + iqmHeader->ofs_frames, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
|
||||
|
||||
// joints
|
||||
IQMJoint *joints = RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
|
||||
IQMJoint *joints = (IQMJoint *)RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
|
||||
memcpy(joints, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint));
|
||||
|
||||
for (unsigned int a = 0; a < iqmHeader->num_anims; a++)
|
||||
{
|
||||
animations[a].frameCount = anim[a].num_frames;
|
||||
animations[a].boneCount = iqmHeader->num_poses;
|
||||
animations[a].bones = RL_MALLOC(iqmHeader->num_poses*sizeof(BoneInfo));
|
||||
animations[a].framePoses = RL_MALLOC(anim[a].num_frames*sizeof(Transform *));
|
||||
animations[a].bones = (BoneInfo *)RL_MALLOC(iqmHeader->num_poses*sizeof(BoneInfo));
|
||||
animations[a].framePoses = (Transform **)RL_MALLOC(anim[a].num_frames*sizeof(Transform *));
|
||||
memcpy(animations[a].name, fileDataPtr + iqmHeader->ofs_text + anim[a].name, 32); // I don't like this 32 here
|
||||
TraceLog(LOG_INFO, "IQM Anim %s", animations[a].name);
|
||||
// animations[a].framerate = anim.framerate; // TODO: Use animation framerate data?
|
||||
@ -4952,7 +5007,7 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCou
|
||||
animations[a].bones[j].parent = poses[j].parent;
|
||||
}
|
||||
|
||||
for (unsigned int j = 0; j < anim[a].num_frames; j++) animations[a].framePoses[j] = RL_MALLOC(iqmHeader->num_poses*sizeof(Transform));
|
||||
for (unsigned int j = 0; j < anim[a].num_frames; j++) animations[a].framePoses[j] = (Transform *)RL_MALLOC(iqmHeader->num_poses*sizeof(Transform));
|
||||
|
||||
int dcounter = anim[a].first_frame*iqmHeader->num_framechannels;
|
||||
|
||||
@ -5143,7 +5198,7 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat
|
||||
}
|
||||
else if ((cgltfImage->buffer_view != NULL) && (cgltfImage->buffer_view->buffer->data != NULL)) // Check if image is provided as data buffer
|
||||
{
|
||||
unsigned char *data = RL_MALLOC(cgltfImage->buffer_view->size);
|
||||
unsigned char *data = (unsigned char *)RL_MALLOC(cgltfImage->buffer_view->size);
|
||||
int offset = (int)cgltfImage->buffer_view->offset;
|
||||
int stride = (int)cgltfImage->buffer_view->stride? (int)cgltfImage->buffer_view->stride : 1;
|
||||
|
||||
@ -5156,11 +5211,11 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat
|
||||
|
||||
// Check mime_type for image: (cgltfImage->mime_type == "image/png")
|
||||
// NOTE: Detected that some models define mime_type as "image\\/png"
|
||||
if ((strcmp(cgltfImage->mime_type, "image\\/png") == 0) || (strcmp(cgltfImage->mime_type, "image/png") == 0))
|
||||
if ((strcmp(cgltfImage->mime_type, "image\\/png") == 0) || (strcmp(cgltfImage->mime_type, "image/png") == 0))
|
||||
{
|
||||
image = LoadImageFromMemory(".png", data, (int)cgltfImage->buffer_view->size);
|
||||
}
|
||||
else if ((strcmp(cgltfImage->mime_type, "image\\/jpeg") == 0) || (strcmp(cgltfImage->mime_type, "image/jpeg") == 0))
|
||||
else if ((strcmp(cgltfImage->mime_type, "image\\/jpeg") == 0) || (strcmp(cgltfImage->mime_type, "image/jpeg") == 0))
|
||||
{
|
||||
image = LoadImageFromMemory(".jpg", data, (int)cgltfImage->buffer_view->size);
|
||||
}
|
||||
@ -5176,16 +5231,12 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat
|
||||
static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, int *boneCount)
|
||||
{
|
||||
*boneCount = (int)skin.joints_count;
|
||||
BoneInfo *bones = RL_MALLOC(skin.joints_count*sizeof(BoneInfo));
|
||||
BoneInfo *bones = (BoneInfo *)RL_CALLOC(skin.joints_count, sizeof(BoneInfo));
|
||||
|
||||
for (unsigned int i = 0; i < skin.joints_count; i++)
|
||||
{
|
||||
cgltf_node node = *skin.joints[i];
|
||||
if (node.name != NULL)
|
||||
{
|
||||
strncpy(bones[i].name, node.name, sizeof(bones[i].name));
|
||||
bones[i].name[sizeof(bones[i].name) - 1] = '\0';
|
||||
}
|
||||
if (node.name != NULL) strncpy(bones[i].name, node.name, sizeof(bones[i].name) - 1);
|
||||
|
||||
// Find parent bone index
|
||||
int parentIndex = -1;
|
||||
@ -5211,7 +5262,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
/*********************************************************************************************
|
||||
|
||||
Function implemented by Wilhem Barbier(@wbrbr), with modifications by Tyler Bezera(@gamerfiend)
|
||||
Transform handling implemented by Paul Melis (@paulmelis).
|
||||
Transform handling implemented by Paul Melis (@paulmelis)
|
||||
Reviewed by Ramon Santamaria (@raysan5)
|
||||
|
||||
FEATURES:
|
||||
@ -5221,10 +5272,10 @@ static Model LoadGLTF(const char *fileName)
|
||||
PBR specular/glossiness flow and extended texture flows not supported
|
||||
- Supports multiple meshes per model (every primitives is loaded as a separate mesh)
|
||||
- Supports basic animations
|
||||
- Transforms, including parent-child relations, are applied on the mesh data, but the
|
||||
hierarchy is not kept (as it can't be represented).
|
||||
- Transforms, including parent-child relations, are applied on the mesh data,
|
||||
but the hierarchy is not kept (as it can't be represented)
|
||||
- Mesh instances in the glTF file (i.e. same mesh linked from multiple nodes)
|
||||
are turned into separate raylib Meshes.
|
||||
are turned into separate raylib Meshes
|
||||
|
||||
RESTRICTIONS:
|
||||
- Only triangle meshes supported
|
||||
@ -5307,15 +5358,15 @@ static Model LoadGLTF(const char *fileName)
|
||||
|
||||
// Load our model data: meshes and materials
|
||||
model.meshCount = primitivesCount;
|
||||
model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh));
|
||||
model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
|
||||
|
||||
// NOTE: We keep an extra slot for default material, in case some mesh requires it
|
||||
model.materialCount = (int)data->materials_count + 1;
|
||||
model.materials = RL_CALLOC(model.materialCount, sizeof(Material));
|
||||
model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
|
||||
model.materials[0] = LoadMaterialDefault(); // Load default material (index: 0)
|
||||
|
||||
// Load mesh-material indices, by default all meshes are mapped to material index: 0
|
||||
model.meshMaterial = RL_CALLOC(model.meshCount, sizeof(int));
|
||||
model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
|
||||
|
||||
// Load materials data
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
@ -5372,7 +5423,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
((unsigned char *)imMetallic.data)[y*imMetallic.width + x] = color.b; // Metallic color channel
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
model.materials[j].maps[MATERIAL_MAP_ROUGHNESS].texture = LoadTextureFromImage(imRoughness);
|
||||
model.materials[j].maps[MATERIAL_MAP_METALNESS].texture = LoadTextureFromImage(imMetallic);
|
||||
|
||||
@ -5440,7 +5491,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
// Any glTF mesh linked from more than one Node (i.e. instancing)
|
||||
// is turned into multiple Mesh's, as each Node will have its own
|
||||
// transform applied.
|
||||
// Note: the code below disregards the scenes defined in the file, all nodes are used.
|
||||
// NOTE: The code below disregards the scenes defined in the file, all nodes are used.
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
int meshIndex = 0;
|
||||
for (unsigned int i = 0; i < data->nodes_count; i++)
|
||||
@ -5485,7 +5536,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
{
|
||||
// Init raylib mesh vertices to copy glTF attribute data
|
||||
model.meshes[meshIndex].vertexCount = (int)attribute->count;
|
||||
model.meshes[meshIndex].vertices = RL_MALLOC(attribute->count*3*sizeof(float));
|
||||
model.meshes[meshIndex].vertices = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
|
||||
|
||||
// Load 3 components of float data type into mesh.vertices
|
||||
LOAD_ATTRIBUTE(attribute, 3, float, model.meshes[meshIndex].vertices)
|
||||
@ -5509,7 +5560,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_32f))
|
||||
{
|
||||
// Init raylib mesh normals to copy glTF attribute data
|
||||
model.meshes[meshIndex].normals = RL_MALLOC(attribute->count*3*sizeof(float));
|
||||
model.meshes[meshIndex].normals = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
|
||||
|
||||
// Load 3 components of float data type into mesh.normals
|
||||
LOAD_ATTRIBUTE(attribute, 3, float, model.meshes[meshIndex].normals)
|
||||
@ -5526,14 +5577,14 @@ static Model LoadGLTF(const char *fileName)
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "MODEL: [%s] Normal attribute data format not supported, use vec3 float", fileName);
|
||||
}
|
||||
else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_tangent) // TANGENT, vec3, float
|
||||
else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_tangent) // TANGENT, vec4, float, w is tangent basis sign
|
||||
{
|
||||
cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
|
||||
|
||||
if ((attribute->type == cgltf_type_vec4) && (attribute->component_type == cgltf_component_type_r_32f))
|
||||
{
|
||||
// Init raylib mesh tangent to copy glTF attribute data
|
||||
model.meshes[meshIndex].tangents = RL_MALLOC(attribute->count*4*sizeof(float));
|
||||
model.meshes[meshIndex].tangents = (float *)RL_MALLOC(attribute->count*4*sizeof(float));
|
||||
|
||||
// Load 4 components of float data type into mesh.tangents
|
||||
LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].tangents)
|
||||
@ -5542,10 +5593,10 @@ static Model LoadGLTF(const char *fileName)
|
||||
float *tangents = model.meshes[meshIndex].tangents;
|
||||
for (unsigned int k = 0; k < attribute->count; k++)
|
||||
{
|
||||
Vector3 tt = Vector3Transform((Vector3){ tangents[3*k], tangents[3*k+1], tangents[3*k+2] }, worldMatrix);
|
||||
tangents[3*k] = tt.x;
|
||||
tangents[3*k+1] = tt.y;
|
||||
tangents[3*k+2] = tt.z;
|
||||
Vector3 tt = Vector3Transform((Vector3){ tangents[4*k], tangents[4*k+1], tangents[4*k+2] }, worldMatrix);
|
||||
tangents[4*k] = tt.x;
|
||||
tangents[4*k+1] = tt.y;
|
||||
tangents[4*k+2] = tt.z;
|
||||
}
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "MODEL: [%s] Tangent attribute data format not supported, use vec4 float", fileName);
|
||||
@ -5619,10 +5670,10 @@ static Model LoadGLTF(const char *fileName)
|
||||
if (attribute->component_type == cgltf_component_type_r_8u)
|
||||
{
|
||||
// Init raylib mesh color to copy glTF attribute data
|
||||
model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
|
||||
// Load data into a temp buffer to be converted to raylib data type
|
||||
unsigned char *temp = RL_MALLOC(attribute->count*3*sizeof(unsigned char));
|
||||
unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*3*sizeof(unsigned char));
|
||||
LOAD_ATTRIBUTE(attribute, 3, unsigned char, temp);
|
||||
|
||||
// Convert data to raylib color data type (4 bytes)
|
||||
@ -5639,10 +5690,10 @@ static Model LoadGLTF(const char *fileName)
|
||||
else if (attribute->component_type == cgltf_component_type_r_16u)
|
||||
{
|
||||
// Init raylib mesh color to copy glTF attribute data
|
||||
model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
|
||||
// Load data into a temp buffer to be converted to raylib data type
|
||||
unsigned short *temp = RL_MALLOC(attribute->count*3*sizeof(unsigned short));
|
||||
unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*3*sizeof(unsigned short));
|
||||
LOAD_ATTRIBUTE(attribute, 3, unsigned short, temp);
|
||||
|
||||
// Convert data to raylib color data type (4 bytes)
|
||||
@ -5659,10 +5710,10 @@ static Model LoadGLTF(const char *fileName)
|
||||
else if (attribute->component_type == cgltf_component_type_r_32f)
|
||||
{
|
||||
// Init raylib mesh color to copy glTF attribute data
|
||||
model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
|
||||
// Load data into a temp buffer to be converted to raylib data type
|
||||
float *temp = RL_MALLOC(attribute->count*3*sizeof(float));
|
||||
float *temp = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
|
||||
LOAD_ATTRIBUTE(attribute, 3, float, temp);
|
||||
|
||||
// Convert data to raylib color data type (4 bytes)
|
||||
@ -5683,7 +5734,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
if (attribute->component_type == cgltf_component_type_r_8u)
|
||||
{
|
||||
// Init raylib mesh color to copy glTF attribute data
|
||||
model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
|
||||
// Load 4 components of unsigned char data type into mesh.colors
|
||||
LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].colors)
|
||||
@ -5691,10 +5742,10 @@ static Model LoadGLTF(const char *fileName)
|
||||
else if (attribute->component_type == cgltf_component_type_r_16u)
|
||||
{
|
||||
// Init raylib mesh color to copy glTF attribute data
|
||||
model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
|
||||
// Load data into a temp buffer to be converted to raylib data type
|
||||
unsigned short *temp = RL_MALLOC(attribute->count*4*sizeof(unsigned short));
|
||||
unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*4*sizeof(unsigned short));
|
||||
LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
|
||||
|
||||
// Convert data to raylib color data type (4 bytes)
|
||||
@ -5705,10 +5756,10 @@ static Model LoadGLTF(const char *fileName)
|
||||
else if (attribute->component_type == cgltf_component_type_r_32f)
|
||||
{
|
||||
// Init raylib mesh color to copy glTF attribute data
|
||||
model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
|
||||
// Load data into a temp buffer to be converted to raylib data type
|
||||
float *temp = RL_MALLOC(attribute->count*4*sizeof(float));
|
||||
float *temp = (float *)RL_MALLOC(attribute->count*4*sizeof(float));
|
||||
LOAD_ATTRIBUTE(attribute, 4, float, temp);
|
||||
|
||||
// Convert data to raylib color data type (4 bytes), we expect the color data normalized
|
||||
@ -5734,7 +5785,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
if (attribute->component_type == cgltf_component_type_r_16u)
|
||||
{
|
||||
// Init raylib mesh indices to copy glTF attribute data
|
||||
model.meshes[meshIndex].indices = RL_MALLOC(attribute->count*sizeof(unsigned short));
|
||||
model.meshes[meshIndex].indices = (unsigned short *)RL_MALLOC(attribute->count*sizeof(unsigned short));
|
||||
|
||||
// Load unsigned short data type into mesh.indices
|
||||
LOAD_ATTRIBUTE(attribute, 1, unsigned short, model.meshes[meshIndex].indices)
|
||||
@ -5742,14 +5793,14 @@ static Model LoadGLTF(const char *fileName)
|
||||
else if (attribute->component_type == cgltf_component_type_r_8u)
|
||||
{
|
||||
// Init raylib mesh indices to copy glTF attribute data
|
||||
model.meshes[meshIndex].indices = RL_MALLOC(attribute->count*sizeof(unsigned short));
|
||||
model.meshes[meshIndex].indices = (unsigned short *)RL_MALLOC(attribute->count*sizeof(unsigned short));
|
||||
LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned char, model.meshes[meshIndex].indices, unsigned short)
|
||||
|
||||
}
|
||||
else if (attribute->component_type == cgltf_component_type_r_32u)
|
||||
{
|
||||
// Init raylib mesh indices to copy glTF attribute data
|
||||
model.meshes[meshIndex].indices = RL_MALLOC(attribute->count*sizeof(unsigned short));
|
||||
model.meshes[meshIndex].indices = (unsigned short *)RL_MALLOC(attribute->count*sizeof(unsigned short));
|
||||
LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned int, model.meshes[meshIndex].indices, unsigned short);
|
||||
|
||||
TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data converted from u32 to u16, possible loss of data", fileName);
|
||||
@ -5793,7 +5844,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
{
|
||||
cgltf_skin skin = data->skins[0];
|
||||
model.bones = LoadBoneInfoGLTF(skin, &model.boneCount);
|
||||
model.bindPose = RL_MALLOC(model.boneCount*sizeof(Transform));
|
||||
model.bindPose = (Transform *)RL_MALLOC(model.boneCount*sizeof(Transform));
|
||||
|
||||
for (int i = 0; i < model.boneCount; i++)
|
||||
{
|
||||
@ -5825,15 +5876,17 @@ static Model LoadGLTF(const char *fileName)
|
||||
|
||||
for (unsigned int p = 0; p < mesh->primitives_count; p++)
|
||||
{
|
||||
bool hasJoints = false;
|
||||
|
||||
// NOTE: We only support primitives defined by triangles
|
||||
if (mesh->primitives[p].type != cgltf_primitive_type_triangles) continue;
|
||||
|
||||
for (unsigned int j = 0; j < mesh->primitives[p].attributes_count; j++)
|
||||
{
|
||||
// NOTE: JOINTS_1 + WEIGHT_1 will be used for +4 joints influencing a vertex -> Not supported by raylib
|
||||
|
||||
if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_joints) // JOINTS_n (vec4: 4 bones max per vertex / u8, u16)
|
||||
{
|
||||
hasJoints = true;
|
||||
cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
|
||||
|
||||
// NOTE: JOINTS_n can only be vec4 and u8/u16
|
||||
@ -5848,7 +5901,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
if (attribute->component_type == cgltf_component_type_r_8u)
|
||||
{
|
||||
// Init raylib mesh boneIds to copy glTF attribute data
|
||||
model.meshes[meshIndex].boneIds = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
||||
model.meshes[meshIndex].boneIds = (unsigned char *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
||||
|
||||
// Load attribute: vec4, u8 (unsigned char)
|
||||
LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].boneIds)
|
||||
@ -5856,10 +5909,10 @@ static Model LoadGLTF(const char *fileName)
|
||||
else if (attribute->component_type == cgltf_component_type_r_16u)
|
||||
{
|
||||
// Init raylib mesh boneIds to copy glTF attribute data
|
||||
model.meshes[meshIndex].boneIds = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
||||
model.meshes[meshIndex].boneIds = (unsigned char *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
||||
|
||||
// Load data into a temp buffer to be converted to raylib data type
|
||||
unsigned short *temp = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned short));
|
||||
unsigned short *temp = (unsigned short *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned short));
|
||||
LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
|
||||
|
||||
// Convert data to raylib color data type (4 bytes)
|
||||
@ -5888,14 +5941,13 @@ static Model LoadGLTF(const char *fileName)
|
||||
|
||||
if (attribute->type == cgltf_type_vec4)
|
||||
{
|
||||
// TODO: Support component types: u8, u16?
|
||||
if (attribute->component_type == cgltf_component_type_r_8u)
|
||||
{
|
||||
// Init raylib mesh bone weight to copy glTF attribute data
|
||||
model.meshes[meshIndex].boneWeights = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||
model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||
|
||||
// Load data into a temp buffer to be converted to raylib data type
|
||||
unsigned char *temp = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
LOAD_ATTRIBUTE(attribute, 4, unsigned char, temp);
|
||||
|
||||
// Convert data to raylib bone weight data type (4 bytes)
|
||||
@ -5906,10 +5958,10 @@ static Model LoadGLTF(const char *fileName)
|
||||
else if (attribute->component_type == cgltf_component_type_r_16u)
|
||||
{
|
||||
// Init raylib mesh bone weight to copy glTF attribute data
|
||||
model.meshes[meshIndex].boneWeights = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||
model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||
|
||||
// Load data into a temp buffer to be converted to raylib data type
|
||||
unsigned short *temp = RL_MALLOC(attribute->count*4*sizeof(unsigned short));
|
||||
unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*4*sizeof(unsigned short));
|
||||
LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
|
||||
|
||||
// Convert data to raylib bone weight data type
|
||||
@ -5920,10 +5972,11 @@ static Model LoadGLTF(const char *fileName)
|
||||
else if (attribute->component_type == cgltf_component_type_r_32f)
|
||||
{
|
||||
// Init raylib mesh bone weight to copy glTF attribute data
|
||||
model.meshes[meshIndex].boneWeights = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||
model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||
|
||||
// Load 4 components of float data type into mesh.boneWeights
|
||||
// for cgltf_attribute_type_weights we have:
|
||||
|
||||
// - data.meshes[0] (256 vertices)
|
||||
// - 256 values, provided as cgltf_type_vec4 of float (4 byte per joint, stride 16)
|
||||
LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].boneWeights)
|
||||
@ -5934,10 +5987,37 @@ static Model LoadGLTF(const char *fileName)
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we are animated, and the mesh was not given any bone assignments, but is the child of a bone node
|
||||
// in this case we need to fully attach all the verts to the parent bone so it will animate with the bone
|
||||
if (data->skins_count > 0 && !hasJoints && node->parent != NULL && node->parent->mesh == NULL)
|
||||
{
|
||||
int parentBoneId = -1;
|
||||
for (int joint = 0; joint < model.boneCount; joint++)
|
||||
{
|
||||
if (data->skins[0].joints[joint] == node->parent)
|
||||
{
|
||||
parentBoneId = joint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (parentBoneId >= 0)
|
||||
{
|
||||
model.meshes[meshIndex].boneIds = (unsigned char *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
||||
model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||
|
||||
for (int vertexIndex = 0; vertexIndex < model.meshes[meshIndex].vertexCount*4; vertexIndex += 4)
|
||||
{
|
||||
model.meshes[meshIndex].boneIds[vertexIndex] = (unsigned char)parentBoneId;
|
||||
model.meshes[meshIndex].boneWeights[vertexIndex] = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Animated vertex data
|
||||
model.meshes[meshIndex].animVertices = RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
|
||||
model.meshes[meshIndex].animVertices = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
|
||||
memcpy(model.meshes[meshIndex].animVertices, model.meshes[meshIndex].vertices, model.meshes[meshIndex].vertexCount*3*sizeof(float));
|
||||
model.meshes[meshIndex].animNormals = RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
|
||||
model.meshes[meshIndex].animNormals = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
|
||||
if (model.meshes[meshIndex].normals != NULL)
|
||||
{
|
||||
memcpy(model.meshes[meshIndex].animNormals, model.meshes[meshIndex].normals, model.meshes[meshIndex].vertexCount*3*sizeof(float));
|
||||
@ -5945,16 +6025,15 @@ static Model LoadGLTF(const char *fileName)
|
||||
|
||||
// Bone Transform Matrices
|
||||
model.meshes[meshIndex].boneCount = model.boneCount;
|
||||
model.meshes[meshIndex].boneMatrices = RL_CALLOC(model.meshes[meshIndex].boneCount, sizeof(Matrix));
|
||||
model.meshes[meshIndex].boneMatrices = (Matrix *)RL_CALLOC(model.meshes[meshIndex].boneCount, sizeof(Matrix));
|
||||
|
||||
for (int j = 0; j < model.meshes[meshIndex].boneCount; j++)
|
||||
{
|
||||
model.meshes[meshIndex].boneMatrices[j] = MatrixIdentity();
|
||||
}
|
||||
|
||||
meshIndex++; // Move to next mesh
|
||||
meshIndex++; // Move to next mesh
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Free all cgltf loaded data
|
||||
@ -6136,7 +6215,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
|
||||
{
|
||||
cgltf_skin skin = data->skins[0];
|
||||
*animCount = (int)data->animations_count;
|
||||
animations = RL_MALLOC(data->animations_count*sizeof(ModelAnimation));
|
||||
animations = (ModelAnimation *)RL_CALLOC(data->animations_count, sizeof(ModelAnimation));
|
||||
|
||||
for (unsigned int i = 0; i < data->animations_count; i++)
|
||||
{
|
||||
@ -6151,7 +6230,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
|
||||
cgltf_interpolation_type interpolationType;
|
||||
};
|
||||
|
||||
struct Channels *boneChannels = RL_CALLOC(animations[i].boneCount, sizeof(struct Channels));
|
||||
struct Channels *boneChannels = (struct Channels *)RL_CALLOC(animations[i].boneCount, sizeof(struct Channels));
|
||||
float animDuration = 0.0f;
|
||||
|
||||
for (unsigned int j = 0; j < animData.channels_count; j++)
|
||||
@ -6209,18 +6288,14 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
|
||||
animDuration = (t > animDuration)? t : animDuration;
|
||||
}
|
||||
|
||||
if (animData.name != NULL)
|
||||
{
|
||||
strncpy(animations[i].name, animData.name, sizeof(animations[i].name));
|
||||
animations[i].name[sizeof(animations[i].name) - 1] = '\0';
|
||||
}
|
||||
if (animData.name != NULL) strncpy(animations[i].name, animData.name, sizeof(animations[i].name) - 1);
|
||||
|
||||
animations[i].frameCount = (int)(animDuration*1000.0f/GLTF_ANIMDELAY) + 1;
|
||||
animations[i].framePoses = RL_MALLOC(animations[i].frameCount*sizeof(Transform *));
|
||||
animations[i].framePoses = (Transform **)RL_MALLOC(animations[i].frameCount*sizeof(Transform *));
|
||||
|
||||
for (int j = 0; j < animations[i].frameCount; j++)
|
||||
{
|
||||
animations[i].framePoses[j] = RL_MALLOC(animations[i].boneCount*sizeof(Transform));
|
||||
animations[i].framePoses[j] = (Transform *)RL_MALLOC(animations[i].boneCount*sizeof(Transform));
|
||||
float time = ((float) j*GLTF_ANIMDELAY)/1000.0f;
|
||||
|
||||
for (int k = 0; k < animations[i].boneCount; k++)
|
||||
@ -6370,7 +6445,7 @@ static Model LoadVOX(const char *fileName)
|
||||
|
||||
// Copy colors
|
||||
size = pmesh->vertexCount*sizeof(Color);
|
||||
pmesh->colors = RL_MALLOC(size);
|
||||
pmesh->colors = (unsigned char *)RL_MALLOC(size);
|
||||
memcpy(pmesh->colors, pcolors, size);
|
||||
|
||||
// First material index
|
||||
@ -6506,7 +6581,7 @@ static Model LoadM3D(const char *fileName)
|
||||
|
||||
// If no map is provided, or we have colors defined, we allocate storage for vertex colors
|
||||
// M3D specs only consider vertex colors if no material is provided, however raylib uses both and mixes the colors
|
||||
if ((mi == M3D_UNDEF) || vcolor) model.meshes[k].colors = RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char));
|
||||
if ((mi == M3D_UNDEF) || vcolor) model.meshes[k].colors = (unsigned char *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char));
|
||||
|
||||
// If no map is provided and we allocated vertex colors, set them to white
|
||||
if ((mi == M3D_UNDEF) && (model.meshes[k].colors != NULL))
|
||||
@ -6540,11 +6615,11 @@ static Model LoadM3D(const char *fileName)
|
||||
// Without vertex color (full transparency), we use the default color
|
||||
if (model.meshes[k].colors != NULL)
|
||||
{
|
||||
if (m3d->vertex[m3d->face[i].vertex[0]].color & 0xFF000000)
|
||||
if (m3d->vertex[m3d->face[i].vertex[0]].color & 0xff000000)
|
||||
memcpy(&model.meshes[k].colors[l*12 + 0], &m3d->vertex[m3d->face[i].vertex[0]].color, 4);
|
||||
if (m3d->vertex[m3d->face[i].vertex[1]].color & 0xFF000000)
|
||||
if (m3d->vertex[m3d->face[i].vertex[1]].color & 0xff000000)
|
||||
memcpy(&model.meshes[k].colors[l*12 + 4], &m3d->vertex[m3d->face[i].vertex[1]].color, 4);
|
||||
if (m3d->vertex[m3d->face[i].vertex[2]].color & 0xFF000000)
|
||||
if (m3d->vertex[m3d->face[i].vertex[2]].color & 0xff000000)
|
||||
memcpy(&model.meshes[k].colors[l*12 + 8], &m3d->vertex[m3d->face[i].vertex[2]].color, 4);
|
||||
}
|
||||
|
||||
@ -6673,13 +6748,13 @@ static Model LoadM3D(const char *fileName)
|
||||
if (m3d->numbone)
|
||||
{
|
||||
model.boneCount = m3d->numbone + 1;
|
||||
model.bones = RL_CALLOC(model.boneCount, sizeof(BoneInfo));
|
||||
model.bindPose = RL_CALLOC(model.boneCount, sizeof(Transform));
|
||||
model.bones = (BoneInfo *)RL_CALLOC(model.boneCount, sizeof(BoneInfo));
|
||||
model.bindPose = (Transform *)RL_CALLOC(model.boneCount, sizeof(Transform));
|
||||
|
||||
for (i = 0; i < (int)m3d->numbone; i++)
|
||||
{
|
||||
model.bones[i].parent = m3d->bone[i].parent;
|
||||
strncpy(model.bones[i].name, m3d->bone[i].name, sizeof(model.bones[i].name));
|
||||
strncpy(model.bones[i].name, m3d->bone[i].name, sizeof(model.bones[i].name) - 1);
|
||||
model.bindPose[i].translation.x = m3d->vertex[m3d->bone[i].pos].x*m3d->scale;
|
||||
model.bindPose[i].translation.y = m3d->vertex[m3d->bone[i].pos].y*m3d->scale;
|
||||
model.bindPose[i].translation.z = m3d->vertex[m3d->bone[i].pos].z*m3d->scale;
|
||||
@ -6725,7 +6800,7 @@ static Model LoadM3D(const char *fileName)
|
||||
memcpy(model.meshes[i].animNormals, model.meshes[i].normals, model.meshes[i].vertexCount*3*sizeof(float));
|
||||
|
||||
model.meshes[i].boneCount = model.boneCount;
|
||||
model.meshes[i].boneMatrices = RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
|
||||
model.meshes[i].boneMatrices = (Matrix *)RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
|
||||
for (j = 0; j < model.meshes[i].boneCount; j++)
|
||||
{
|
||||
model.meshes[i].boneMatrices[j] = MatrixIdentity();
|
||||
@ -6775,24 +6850,23 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCou
|
||||
return NULL;
|
||||
}
|
||||
|
||||
animations = RL_MALLOC(m3d->numaction*sizeof(ModelAnimation));
|
||||
animations = (ModelAnimation *)RL_CALLOC(m3d->numaction, sizeof(ModelAnimation));
|
||||
*animCount = m3d->numaction;
|
||||
|
||||
for (unsigned int a = 0; a < m3d->numaction; a++)
|
||||
{
|
||||
animations[a].frameCount = m3d->action[a].durationmsec/M3D_ANIMDELAY;
|
||||
animations[a].boneCount = m3d->numbone + 1;
|
||||
animations[a].bones = RL_MALLOC((m3d->numbone + 1)*sizeof(BoneInfo));
|
||||
animations[a].framePoses = RL_MALLOC(animations[a].frameCount*sizeof(Transform *));
|
||||
strncpy(animations[a].name, m3d->action[a].name, sizeof(animations[a].name));
|
||||
animations[a].name[sizeof(animations[a].name) - 1] = '\0';
|
||||
animations[a].bones = (BoneInfo *)RL_MALLOC((m3d->numbone + 1)*sizeof(BoneInfo));
|
||||
animations[a].framePoses = (Transform **)RL_MALLOC(animations[a].frameCount*sizeof(Transform *));
|
||||
strncpy(animations[a].name, m3d->action[a].name, sizeof(animations[a].name) - 1);
|
||||
|
||||
TRACELOG(LOG_INFO, "MODEL: [%s] animation #%i: %i msec, %i frames", fileName, a, m3d->action[a].durationmsec, animations[a].frameCount);
|
||||
|
||||
for (i = 0; i < (int)m3d->numbone; i++)
|
||||
{
|
||||
animations[a].bones[i].parent = m3d->bone[i].parent;
|
||||
strncpy(animations[a].bones[i].name, m3d->bone[i].name, sizeof(animations[a].bones[i].name));
|
||||
strncpy(animations[a].bones[i].name, m3d->bone[i].name, sizeof(animations[a].bones[i].name) - 1);
|
||||
}
|
||||
|
||||
// A special, never transformed "no bone" bone, used for boneless vertices
|
||||
@ -6803,7 +6877,7 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCou
|
||||
// regular intervals, so let the M3D SDK do the heavy lifting and calculate interpolated bones
|
||||
for (i = 0; i < animations[a].frameCount; i++)
|
||||
{
|
||||
animations[a].framePoses[i] = RL_MALLOC((m3d->numbone + 1)*sizeof(Transform));
|
||||
animations[a].framePoses[i] = (Transform *)RL_MALLOC((m3d->numbone + 1)*sizeof(Transform));
|
||||
|
||||
m3db_t *pose = m3d_pose(m3d, a, i*M3D_ANIMDELAY);
|
||||
|
||||
|
||||
@ -285,6 +285,7 @@ void DrawCircleV(Vector2 center, float radius, Color color)
|
||||
// Draw a piece of a circle
|
||||
void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color)
|
||||
{
|
||||
if (startAngle == endAngle) return;
|
||||
if (radius <= 0.0f) radius = 0.1f; // Avoid div by zero
|
||||
|
||||
// Function expects (endAngle > startAngle)
|
||||
@ -376,6 +377,7 @@ void DrawCircleSector(Vector2 center, float radius, float startAngle, float endA
|
||||
// Draw a piece of a circle outlines
|
||||
void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color)
|
||||
{
|
||||
if (startAngle == endAngle) return;
|
||||
if (radius <= 0.0f) radius = 0.1f; // Avoid div by zero issue
|
||||
|
||||
// Function expects (endAngle > startAngle)
|
||||
@ -468,27 +470,39 @@ void DrawCircleLinesV(Vector2 center, float radius, Color color)
|
||||
|
||||
// Draw ellipse
|
||||
void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color)
|
||||
{
|
||||
DrawEllipseV((Vector2){ (float)centerX, (float)centerY }, radiusH, radiusV, color);
|
||||
}
|
||||
|
||||
// Draw ellipse (Vector version)
|
||||
void DrawEllipseV(Vector2 center, float radiusH, float radiusV, Color color)
|
||||
{
|
||||
rlBegin(RL_TRIANGLES);
|
||||
for (int i = 0; i < 360; i += 10)
|
||||
{
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlVertex2f((float)centerX, (float)centerY);
|
||||
rlVertex2f((float)centerX + cosf(DEG2RAD*(i + 10))*radiusH, (float)centerY + sinf(DEG2RAD*(i + 10))*radiusV);
|
||||
rlVertex2f((float)centerX + cosf(DEG2RAD*i)*radiusH, (float)centerY + sinf(DEG2RAD*i)*radiusV);
|
||||
rlVertex2f(center.x, center.y);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radiusH, center.y + sinf(DEG2RAD*(i + 10))*radiusV);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*i)*radiusH, center.y + sinf(DEG2RAD*i)*radiusV);
|
||||
}
|
||||
rlEnd();
|
||||
}
|
||||
|
||||
// Draw ellipse outline
|
||||
void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color)
|
||||
{
|
||||
DrawEllipseLinesV((Vector2){ (float)centerX, (float)centerY }, radiusH, radiusV, color);
|
||||
}
|
||||
|
||||
// Draw ellipse outline
|
||||
void DrawEllipseLinesV(Vector2 center, float radiusH, float radiusV, Color color)
|
||||
{
|
||||
rlBegin(RL_LINES);
|
||||
for (int i = 0; i < 360; i += 10)
|
||||
{
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlVertex2f(centerX + cosf(DEG2RAD*(i + 10))*radiusH, centerY + sinf(DEG2RAD*(i + 10))*radiusV);
|
||||
rlVertex2f(centerX + cosf(DEG2RAD*i)*radiusH, centerY + sinf(DEG2RAD*i)*radiusV);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radiusH, center.y + sinf(DEG2RAD*(i + 10))*radiusV);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*i)*radiusH, center.y + sinf(DEG2RAD*i)*radiusV);
|
||||
}
|
||||
rlEnd();
|
||||
}
|
||||
@ -772,7 +786,7 @@ void DrawRectangleGradientH(int posX, int posY, int width, int height, Color lef
|
||||
}
|
||||
|
||||
// Draw a gradient-filled rectangle
|
||||
void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color topRight, Color bottomRight)
|
||||
void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color bottomRight, Color topRight)
|
||||
{
|
||||
rlSetTexture(GetShapesTexture().id);
|
||||
Rectangle shapeRect = GetShapesTextureRectangle();
|
||||
@ -789,11 +803,11 @@ void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Col
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(rec.x, rec.y + rec.height);
|
||||
|
||||
rlColor4ub(topRight.r, topRight.g, topRight.b, topRight.a);
|
||||
rlColor4ub(bottomRight.r, bottomRight.g, bottomRight.b, bottomRight.a);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(rec.x + rec.width, rec.y + rec.height);
|
||||
|
||||
rlColor4ub(bottomRight.r, bottomRight.g, bottomRight.b, bottomRight.a);
|
||||
rlColor4ub(topRight.r, topRight.g, topRight.b, topRight.a);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(rec.x + rec.width, rec.y);
|
||||
rlEnd();
|
||||
@ -2237,7 +2251,7 @@ bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2
|
||||
// NOTE: Based on http://jeffreythompson.org/collision-detection/poly-point.php
|
||||
bool CheckCollisionPointPoly(Vector2 point, const Vector2 *points, int pointCount)
|
||||
{
|
||||
bool inside = false;
|
||||
bool collision = false;
|
||||
|
||||
if (pointCount > 2)
|
||||
{
|
||||
@ -2246,12 +2260,12 @@ bool CheckCollisionPointPoly(Vector2 point, const Vector2 *points, int pointCoun
|
||||
if ((points[i].y > point.y) != (points[j].y > point.y) &&
|
||||
(point.x < (points[j].x - points[i].x)*(point.y - points[i].y)/(points[j].y - points[i].y) + points[i].x))
|
||||
{
|
||||
inside = !inside;
|
||||
collision = !collision;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inside;
|
||||
return collision;
|
||||
}
|
||||
|
||||
// Check collision between two rectangles
|
||||
|
||||
28
src/rtext.c
28
src/rtext.c
@ -161,6 +161,10 @@ extern void LoadFontDefault(void)
|
||||
{
|
||||
#define BIT_CHECK(a,b) ((a) & (1u << (b)))
|
||||
|
||||
// check to see if we have allready allocated the font for an image, and if we don't need to upload, then just return
|
||||
if (defaultFont.glyphs != NULL && !isGpuReady)
|
||||
return;
|
||||
|
||||
// NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement
|
||||
// Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl
|
||||
|
||||
@ -249,7 +253,7 @@ extern void LoadFontDefault(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
((unsigned char *)imFont.data)[(i + j)*sizeof(short)] = 0xFF;
|
||||
((unsigned char *)imFont.data)[(i + j)*sizeof(short)] = 0xff;
|
||||
((unsigned char *)imFont.data)[(i + j)*sizeof(short) + 1] = 0x00;
|
||||
}
|
||||
}
|
||||
@ -257,7 +261,18 @@ extern void LoadFontDefault(void)
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (isGpuReady) defaultFont.texture = LoadTextureFromImage(imFont);
|
||||
if (isGpuReady)
|
||||
{
|
||||
defaultFont.texture = LoadTextureFromImage(imFont);
|
||||
|
||||
// we have already loaded the font glyph data an image, and the GPU is ready, we are done
|
||||
// if we don't do this, we will leak memory by reallocating the glyphs and rects
|
||||
if (defaultFont.glyphs != NULL)
|
||||
{
|
||||
UnloadImage(imFont);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount
|
||||
//------------------------------------------------------------------------------
|
||||
@ -282,7 +297,7 @@ extern void LoadFontDefault(void)
|
||||
|
||||
testPosX += (int)(defaultFont.recs[i].width + (float)charsDivisor);
|
||||
|
||||
if (testPosX >= defaultFont.texture.width)
|
||||
if (testPosX >= imFont.width)
|
||||
{
|
||||
currentLine++;
|
||||
currentPosX = 2*charsDivisor + charsWidth[i];
|
||||
@ -316,6 +331,9 @@ extern void UnloadFontDefault(void)
|
||||
if (isGpuReady) UnloadTexture(defaultFont.texture);
|
||||
RL_FREE(defaultFont.glyphs);
|
||||
RL_FREE(defaultFont.recs);
|
||||
defaultFont.glyphCount = 0;
|
||||
defaultFont.glyphs = NULL;
|
||||
defaultFont.recs = NULL;
|
||||
}
|
||||
#endif // SUPPORT_DEFAULT_FONT
|
||||
|
||||
@ -1075,7 +1093,7 @@ bool ExportFontAsCode(Font font, const char *fileName)
|
||||
byteCount += sprintf(txtData + byteCount, " Image imFont = { fontImageData_%s, %i, %i, 1, %i };\n\n", styleName, image.width, image.height, image.format);
|
||||
#endif
|
||||
byteCount += sprintf(txtData + byteCount, " // Load texture from image\n");
|
||||
byteCount += sprintf(txtData + byteCount, " if (isGpuReady) font.texture = LoadTextureFromImage(imFont);\n");
|
||||
byteCount += sprintf(txtData + byteCount, " font.texture = LoadTextureFromImage(imFont);\n");
|
||||
#if defined(SUPPORT_COMPRESSED_FONT_ATLAS)
|
||||
byteCount += sprintf(txtData + byteCount, " UnloadImage(imFont); // Uncompressed data can be unloaded from memory\n\n");
|
||||
#endif
|
||||
@ -1560,7 +1578,7 @@ const char *TextSubtext(const char *text, int position, int length)
|
||||
}
|
||||
|
||||
// Replace text string
|
||||
// REQUIRES: strlen(), strstr(), strncpy(), strcpy()
|
||||
// REQUIRES: strstr(), strncpy(), strcpy()
|
||||
// WARNING: Allocated memory must be manually freed
|
||||
char *TextReplace(const char *text, const char *replace, const char *by)
|
||||
{
|
||||
|
||||
@ -832,10 +832,11 @@ Image GenImageGradientLinear(int width, int height, int direction, Color start,
|
||||
|
||||
// Calculate how far the top-left pixel is along the gradient direction from the center of said gradient
|
||||
float startingPos = 0.5f - (cosDir*width/2) - (sinDir*height/2);
|
||||
|
||||
// With directions that lie in the first or third quadrant (i.e. from top-left to
|
||||
// bottom-right or vice-versa), pixel (0, 0) is the farthest point on the gradient
|
||||
// (i.e. the pixel which should become one of the gradient's ends color); while for
|
||||
// directions that lie in the second or fourth quadrant, that point is pixel (width, 0).
|
||||
// directions that lie in the second or fourth quadrant, that point is pixel (width, 0)
|
||||
float maxPosValue = ((signbit(sinDir) != 0) == (signbit(cosDir) != 0))? fabsf(startingPos) : fabsf(startingPos + width*cosDir);
|
||||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
@ -2101,8 +2102,8 @@ void ImageBlurGaussian(Image *image, int blurSize)
|
||||
Color *pixels = LoadImageColors(*image);
|
||||
|
||||
// Loop switches between pixelsCopy1 and pixelsCopy2
|
||||
Vector4 *pixelsCopy1 = RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
||||
Vector4 *pixelsCopy2 = RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
||||
Vector4 *pixelsCopy1 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
||||
Vector4 *pixelsCopy2 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
||||
|
||||
for (int i = 0; i < (image->height*image->width); i++)
|
||||
{
|
||||
@ -2250,8 +2251,8 @@ void ImageKernelConvolution(Image *image, const float *kernel, int kernelSize)
|
||||
|
||||
Color *pixels = LoadImageColors(*image);
|
||||
|
||||
Vector4 *imageCopy2 = RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
||||
Vector4 *temp = RL_MALLOC(kernelSize*sizeof(Vector4));
|
||||
Vector4 *imageCopy2 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
||||
Vector4 *temp = (Vector4 *)RL_MALLOC(kernelSize*sizeof(Vector4));
|
||||
|
||||
for (int i = 0; i < kernelSize; i++)
|
||||
{
|
||||
@ -3835,7 +3836,7 @@ void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c
|
||||
|
||||
// Calculate the inverse of the sum of the barycentric coordinates for normalization
|
||||
// NOTE 1: Here, we act as if we multiply by 255 the reciprocal, which avoids additional
|
||||
// calculations in the loop. This is acceptable because we are only interpolating colors.
|
||||
// calculations in the loop. This is acceptable because we are only interpolating colors
|
||||
// NOTE 2: This sum remains constant throughout the triangle
|
||||
float wInvSum = 255.0f/(w1Row + w2Row + w3Row);
|
||||
|
||||
@ -3890,7 +3891,7 @@ void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Colo
|
||||
}
|
||||
|
||||
// Draw a triangle fan defined by points within an image (first vertex is the center)
|
||||
void ImageDrawTriangleFan(Image *dst, Vector2 *points, int pointCount, Color color)
|
||||
void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color)
|
||||
{
|
||||
if (pointCount >= 3)
|
||||
{
|
||||
@ -3902,7 +3903,7 @@ void ImageDrawTriangleFan(Image *dst, Vector2 *points, int pointCount, Color col
|
||||
}
|
||||
|
||||
// Draw a triangle strip defined by points within an image
|
||||
void ImageDrawTriangleStrip(Image *dst, Vector2 *points, int pointCount, Color color)
|
||||
void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color)
|
||||
{
|
||||
if (pointCount >= 3)
|
||||
{
|
||||
@ -5150,10 +5151,10 @@ Color GetColor(unsigned int hexValue)
|
||||
{
|
||||
Color color;
|
||||
|
||||
color.r = (unsigned char)(hexValue >> 24) & 0xFF;
|
||||
color.g = (unsigned char)(hexValue >> 16) & 0xFF;
|
||||
color.b = (unsigned char)(hexValue >> 8) & 0xFF;
|
||||
color.a = (unsigned char)hexValue & 0xFF;
|
||||
color.r = (unsigned char)(hexValue >> 24) & 0xff;
|
||||
color.g = (unsigned char)(hexValue >> 16) & 0xff;
|
||||
color.b = (unsigned char)(hexValue >> 8) & 0xff;
|
||||
color.a = (unsigned char)hexValue & 0xff;
|
||||
|
||||
return color;
|
||||
}
|
||||
@ -5393,17 +5394,16 @@ static float HalfToFloat(unsigned short x)
|
||||
{
|
||||
float result = 0.0f;
|
||||
|
||||
union
|
||||
{
|
||||
union {
|
||||
float fm;
|
||||
unsigned int ui;
|
||||
} uni;
|
||||
|
||||
const unsigned int e = (x & 0x7C00) >> 10; // Exponent
|
||||
const unsigned int m = (x & 0x03FF) << 13; // Mantissa
|
||||
const unsigned int e = (x & 0x7c00) >> 10; // Exponent
|
||||
const unsigned int m = (x & 0x03cc) << 13; // Mantissa
|
||||
uni.fm = (float)m;
|
||||
const unsigned int v = uni.ui >> 23; // Evil log2 bit hack to count leading zeros in denormalized format
|
||||
uni.ui = (x & 0x8000) << 16 | (e != 0)*((e + 112) << 23 | m) | ((e == 0)&(m != 0))*((v - 37) << 23 | ((m << (150 - v)) & 0x007FE000)); // sign : normalized : denormalized
|
||||
uni.ui = (x & 0x8000) << 16 | (e != 0)*((e + 112) << 23 | m) | ((e == 0)&(m != 0))*((v - 37) << 23 | ((m << (150 - v)) & 0x007fe000)); // sign : normalized : denormalized
|
||||
|
||||
result = uni.fm;
|
||||
|
||||
@ -5415,18 +5415,17 @@ static unsigned short FloatToHalf(float x)
|
||||
{
|
||||
unsigned short result = 0;
|
||||
|
||||
union
|
||||
{
|
||||
union {
|
||||
float fm;
|
||||
unsigned int ui;
|
||||
} uni;
|
||||
uni.fm = x;
|
||||
|
||||
const unsigned int b = uni.ui + 0x00001000; // Round-to-nearest-even: add last bit after truncated mantissa
|
||||
const unsigned int e = (b & 0x7F800000) >> 23; // Exponent
|
||||
const unsigned int m = b & 0x007FFFFF; // Mantissa; in line below: 0x007FF000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding
|
||||
const unsigned int e = (b & 0x7f800000) >> 23; // Exponent
|
||||
const unsigned int m = b & 0x007fffff; // Mantissa; in line below: 0x007ff000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding
|
||||
|
||||
result = (b & 0x80000000) >> 16 | (e > 112)*((((e - 112) << 10) & 0x7C00) | m >> 13) | ((e < 113) & (e > 101))*((((0x007FF000 + m) >> (125 - e)) + 1) >> 1) | (e > 143)*0x7FFF; // sign : normalized : denormalized : saturate
|
||||
result = (b & 0x80000000) >> 16 | (e > 112)*((((e - 112) << 10) & 0x7c00) | m >> 13) | ((e < 113) & (e > 101))*((((0x007ff000 + m) >> (125 - e)) + 1) >> 1) | (e > 143)*0x7fff; // sign : normalized : denormalized : saturate
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -405,7 +405,7 @@ void UnloadFileText(char *text)
|
||||
}
|
||||
|
||||
// Save text data to file (write), string must be '\0' terminated
|
||||
bool SaveFileText(const char *fileName, char *text)
|
||||
bool SaveFileText(const char *fileName, const char *text)
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user