Merge branch 'raysan5:master' into Add-RL_POINTS

This commit is contained in:
Maicon Santana 2026-06-04 10:05:15 +01:00 • committed by GitHub
commit 4b28f75aeb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 858 additions and 650 deletions

View file

@ -30,14 +30,22 @@ set(raylib_public_headers
# Sources to be compiled
set(raylib_sources
raudio.c
rcore.c
rmodels.c
rshapes.c
rtext.c
rtextures.c
)
# Only build raudio if it's enabled
if (NOT DEFINED SUPPORT_MODULE_RAUDIO OR SUPPORT_MODULE_RAUDIO)
list(APPEND raylib_sources raudio.c)
endif()
# Only build rmodels if it's enabled
if (NOT DEFINED SUPPORT_MODULE_RMODELS OR SUPPORT_MODULE_RMODELS)
list(APPEND raylib_sources rmodels.c)
endif()
# <root>/cmake/GlfwImport.cmake handles the details around the inclusion of glfw
if (NOT ${PLATFORM} MATCHES "Web")
include(GlfwImport)
@ -48,10 +56,10 @@ endif ()
# Produces a variable LIBS_PRIVATE that will be used later
include(LibraryConfigurations)
if (SUPPORT_MODULE_RAUDIO)
MESSAGE(STATUS "Audio Backend: miniaudio")
else ()
if (DEFINED SUPPORT_MODULE_RAUDIO AND NOT SUPPORT_MODULE_RAUDIO)
MESSAGE(STATUS "Audio Backend: None (-DCUSTOMIZE_BUILD=ON -DSUPPORT_MODULE_RAUDIO=OFF)")
else ()
MESSAGE(STATUS "Audio Backend: miniaudio")
endif ()
add_library(raylib ${raylib_sources} ${raylib_public_headers})

View file

@ -240,6 +240,9 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
ifeq ($(ANDROID_ARCH),x86_64)
ANDROID_COMPILER_ARCH = x86_64
endif
ifndef ANDROID_COMPILER_ARCH
$(error ANDROID_COMPILER_ARCH: Unknown ANDROID_ARCH=$(ANDROID_ARCH))
endif
endif
# Define raylib graphics api depending on selected platform

View file

@ -41495,11 +41495,11 @@ Web Audio Backend
#ifdef MA_HAS_WEBAUDIO
#include <emscripten/emscripten.h>
#if (__EMSCRIPTEN_major__ > 3) || (__EMSCRIPTEN_major__ == 3 && (__EMSCRIPTEN_minor__ > 1 || (__EMSCRIPTEN_minor__ == 1 && __EMSCRIPTEN_tiny__ >= 32)))
#if (__EMSCRIPTEN_MAJOR__ > 3) || (__EMSCRIPTEN_MAJOR__ == 3 && (__EMSCRIPTEN_MINOR__ > 1 || (__EMSCRIPTEN_MINOR__ == 1 && __EMSCRIPTEN_TINY__ >= 32)))
#include <emscripten/webaudio.h>
#define MA_SUPPORT_AUDIO_WORKLETS
#if (__EMSCRIPTEN_major__ > 3) || (__EMSCRIPTEN_major__ == 3 && (__EMSCRIPTEN_minor__ > 1 || (__EMSCRIPTEN_minor__ == 1 && __EMSCRIPTEN_tiny__ >= 70)))
#if (__EMSCRIPTEN_MAJOR__ > 3) || (__EMSCRIPTEN_MAJOR__ == 3 && (__EMSCRIPTEN_MINOR__ > 1 || (__EMSCRIPTEN_MINOR__ == 1 && __EMSCRIPTEN_TINY__ >= 70)))
#define MA_SUPPORT_AUDIO_WORKLETS_VARIABLE_BUFFER_SIZE
#endif
#endif

291
src/external/rlsw.h vendored
View file

@ -164,18 +164,10 @@
#endif
#endif
// Fast power-of-two texture wrap (SW_REPEAT mode only)
// When defined, textures whose width/height are powers of two use a bitmask
// wrap (`x & (size-1)`) instead of `floorf`-based fractional wrap or the
// signed `%` chain in the linear sampler. Saves a software divide on Xtensa
// and a few instructions everywhere. NPOT textures keep using the original
// path via a runtime `(size & (size-1)) == 0` check, so SW_REPEAT remains
// correct for them. The only observable behavior change is for POT textures
// sampled with negative UV coordinates: bitmask wrap (two's complement) can
// differ from `sw_fract` by one texel. Off by default to keep bit-for-bit
// behavior; opt in if you control your asset UVs.
//
// #define SW_TEXTURE_REPEAT_POT_FAST
// Full NPOT texture support (enabled by default)
// When disabled, SW_REPEAT requires POT on its axis (fast bitmask wrap)
// SW_CLAMP remains supported for any dimension, per-axis
#define SW_SUPPORT_NPOT_TEXTURE true
//----------------------------------------------------------------------------------
// OpenGL Compatibility Types
@ -860,11 +852,9 @@ SWAPI void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWatta
#endif
// ESP-DSP acceleration: ESP-IDF ships an optimized math library that includes
// `dspm_mult_4x4x4_f32` (4x4 matrix multiply) and `dspm_mult_4x4x1_f32`
// (matrix * vector). These are S3-tuned hand-vectorized kernels that beat the
// scalar versions for both throughput and code-size. Detection is opt-in to
// keep the dependency optional: define SW_USE_ESP_DSP from your build system
// (or rely on the `idf_component.yml` example shown in the rlsw docs).
// `dspm_mult_4x4x4_f32` (4x4 matrix multiply) and `dspm_mult_4x4x1_f32` (matrix * vector)
// These are S3-tuned hand-vectorized kernels that beat the scalar versions for both throughput and code-size
// Detection is opt-in to keep the dependency optional: define SW_USE_ESP_DSP from your build system
#if defined(ESP_PLATFORM) && defined(SW_USE_ESP_DSP)
#define SW_HAS_ESP_DSP
#include "dspm_mult.h"
@ -884,41 +874,41 @@ SWAPI void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWatta
#define SW_DEG2RAD (SW_PI/180.0f)
#define SW_RAD2DEG (180.0f/SW_PI)
// When clipping a convex polygon against a plane, at most one vertex is added.
// When clipping a convex polygon against a plane, at most one vertex is added
// Starting from a quadrilateral (4 vertices), clipped sequentially against
// the frustum (6 planes) then the scissor rectangle (4 planes):
// 4 + 6 + 4 = 14 vertices maximum.
#define SW_MAX_CLIPPED_POLYGON_VERTICES 14
#define SW_CLIP_EPSILON 1e-4f
// 4 + 6 + 4 = 14 vertices maximum
#define SW_MAX_CLIPPED_POLYGON_VERTICES 14
#define SW_CLIP_EPSILON 1e-4f
#define SW_HANDLE_NULL 0u
#define SW_POOL_SLOT_LIVE 0x80u // bit7 of the generation byte
#define SW_POOL_SLOT_VER_MASK 0x7Fu // bits6:0 = anti-ABA counter
#define SW_HANDLE_NULL 0u
#define SW_POOL_SLOT_LIVE 0x80u // bit7 of the generation byte
#define SW_POOL_SLOT_VER_MASK 0x7Fu // bits6:0 = anti-ABA counter
#define SW_CONCAT(a, b) a##b
#define SW_CONCATX(a, b) SW_CONCAT(a, b)
#define SW_CONCAT(a, b) a##b
#define SW_CONCATX(a, b) SW_CONCAT(a, b)
#define SW_FRAMEBUFFER_COLOR8_GET(c,p,o) SW_CONCATX(sw_pixel_read_color8_, SW_FRAMEBUFFER_COLOR_TYPE)((c),(p),(o))
#define SW_FRAMEBUFFER_COLOR_GET(c,p,o) SW_CONCATX(sw_pixel_read_color_, SW_FRAMEBUFFER_COLOR_TYPE)((c),(p),(o))
#define SW_FRAMEBUFFER_COLOR_SET(p,c,o) SW_CONCATX(sw_pixel_write_color_, SW_FRAMEBUFFER_COLOR_TYPE)((p),(c),(o))
#define SW_FRAMEBUFFER_COLOR8_GET(c,p,o) SW_CONCATX(sw_pixel_read_color8_, SW_FRAMEBUFFER_COLOR_TYPE)((c),(p),(o))
#define SW_FRAMEBUFFER_COLOR_GET(c,p,o) SW_CONCATX(sw_pixel_read_color_, SW_FRAMEBUFFER_COLOR_TYPE)((c),(p),(o))
#define SW_FRAMEBUFFER_COLOR_SET(p,c,o) SW_CONCATX(sw_pixel_write_color_, SW_FRAMEBUFFER_COLOR_TYPE)((p),(c),(o))
#define SW_FRAMEBUFFER_DEPTH_GET(p,o) SW_CONCATX(sw_pixel_read_depth_, SW_FRAMEBUFFER_DEPTH_TYPE)((p),(o))
#define SW_FRAMEBUFFER_DEPTH_SET(p,d,o) SW_CONCATX(sw_pixel_write_depth_, SW_FRAMEBUFFER_DEPTH_TYPE)((p),(d),(o))
#define SW_FRAMEBUFFER_DEPTH_GET(p,o) SW_CONCATX(sw_pixel_read_depth_, SW_FRAMEBUFFER_DEPTH_TYPE)((p),(o))
#define SW_FRAMEBUFFER_DEPTH_SET(p,d,o) SW_CONCATX(sw_pixel_write_depth_, SW_FRAMEBUFFER_DEPTH_TYPE)((p),(d),(o))
#define SW_FRAMEBUFFER_COLOR_FORMAT SW_CONCATX(SW_PIXELFORMAT_COLOR_, SW_FRAMEBUFFER_COLOR_TYPE)
#define SW_FRAMEBUFFER_DEPTH_FORMAT SW_CONCATX(SW_PIXELFORMAT_DEPTH_, SW_FRAMEBUFFER_DEPTH_TYPE)
#define SW_FRAMEBUFFER_COLOR_FORMAT SW_CONCATX(SW_PIXELFORMAT_COLOR_, SW_FRAMEBUFFER_COLOR_TYPE)
#define SW_FRAMEBUFFER_DEPTH_FORMAT SW_CONCATX(SW_PIXELFORMAT_DEPTH_, SW_FRAMEBUFFER_DEPTH_TYPE)
#define SW_FRAMEBUFFER_COLOR_SIZE SW_PIXELFORMAT_SIZE[SW_FRAMEBUFFER_COLOR_FORMAT]
#define SW_FRAMEBUFFER_DEPTH_SIZE SW_PIXELFORMAT_SIZE[SW_FRAMEBUFFER_DEPTH_FORMAT]
#define SW_FRAMEBUFFER_COLOR_SIZE SW_PIXELFORMAT_SIZE[SW_FRAMEBUFFER_COLOR_FORMAT]
#define SW_FRAMEBUFFER_DEPTH_SIZE SW_PIXELFORMAT_SIZE[SW_FRAMEBUFFER_DEPTH_FORMAT]
#define SW_STATE_SCISSOR_TEST (1 << 0)
#define SW_STATE_TEXTURE_2D (1 << 1)
#define SW_STATE_DEPTH_TEST (1 << 2)
#define SW_STATE_CULL_FACE (1 << 3)
#define SW_STATE_BLEND (1 << 4)
#define SW_STATE_SCISSOR_TEST (1 << 0)
#define SW_STATE_TEXTURE_2D (1 << 1)
#define SW_STATE_DEPTH_TEST (1 << 2)
#define SW_STATE_CULL_FACE (1 << 3)
#define SW_STATE_BLEND (1 << 4)
#define SW_BLEND_FLAG_NOOP (1 << 0)
#define SW_BLEND_FLAG_NEEDS_ALPHA (1 << 1)
#define SW_BLEND_FLAG_NOOP (1 << 0)
#define SW_BLEND_FLAG_NEEDS_ALPHA (1 << 1)
//----------------------------------------------------------------------------------
// Module Types and Structures Definition
@ -1175,7 +1165,7 @@ static inline void sw_matrix_mul_rst(float *SW_RESTRICT dst, const float *SW_RES
// column-major, so passing them flat is equivalent to passing transposes:
// dspm_mult(L^T, R^T) computes (L^T)*(R^T) = (R*L)^T, written back into a
// flat array gives the same bit pattern as the column-major product (R*L)
// -- exactly the semantic the scalar fallback below has.
// -- exactly the semantic the scalar fallback below has
dspm_mult_4x4x4_f32(left, right, dst);
#else
float l00 = left[0], l01 = left[1], l02 = left[2], l03 = left[3];
@ -1248,12 +1238,12 @@ static inline float sw_fract(float x)
return (x - floorf(x));
}
// Fast reciprocal: 1-ULP accurate in ~7 instructions on Xtensa using the
// hardware `recip0.s` seed + two Newton-Raphson refinement steps. All work
// stays in FPU registers — no `__divsf3` software call. Hot-path divisions
// in the rasterizer (span/triangle setup, perspective divide, etc.) call
// this. On non-Xtensa targets it transparently expands to `1.0f / x`, so
// generated code is identical to before.
// Xtensa architecture optimization
// Fast reciprocal: 1-ULP accurate in ~7 instructions using the
// hardware `recip0.s` seed + two Newton-Raphson refinement steps
// All work stays in FPU registers — no `__divsf3` software call
// Hot-path divisions in the rasterizer (span/triangle setup, perspective divide, etc.) call this
// On non-Xtensa targets it transparently expands to `1.0f / x`, so generated code is identical to before
#if defined(__XTENSA__)
__attribute__((always_inline))
static inline float sw_rcp(float x)
@ -2409,6 +2399,14 @@ static inline bool sw_texture_alloc(sw_texture_t *texture, const void *data, int
int bpp = SW_PIXELFORMAT_SIZE[format];
int newSize = w*h*bpp;
if (texture->pixels == NULL)
{
texture->minFilter = SW_NEAREST;
texture->magFilter = SW_NEAREST;
texture->sWrap = SW_CLAMP;
texture->tWrap = SW_CLAMP;
}
if (newSize > texture->allocSz)
{
void *ptr = SW_REALLOC(texture->pixels, newSize);
@ -2473,38 +2471,25 @@ static inline void sw_texture_sample_nearest(float *SW_RESTRICT color, const sw_
{
int x, y;
#ifdef SW_TEXTURE_REPEAT_POT_FAST
if ((tex->sWrap == SW_REPEAT) && ((tex->width & tex->wMinus1) == 0))
{
x = (int)(u*tex->width) & tex->wMinus1;
}
else
#endif
{
u = (tex->sWrap == SW_REPEAT)? sw_fract(u) : sw_saturate(u);
x = (int)(u*tex->width);
}
#if SW_SUPPORT_NPOT_TEXTURE
if (tex->sWrap == SW_REPEAT) x = (int)(sw_fract(u)*tex->width);
else x = (int)(sw_saturate(u)*tex->width);
#ifdef SW_TEXTURE_REPEAT_POT_FAST
if ((tex->tWrap == SW_REPEAT) && ((tex->height & tex->hMinus1) == 0))
{
y = (int)(v*tex->height) & tex->hMinus1;
}
else
if (tex->tWrap == SW_REPEAT) y = (int)(sw_fract(v)*tex->height);
else y = (int)(sw_saturate(v)*tex->height);
#else
if (tex->sWrap == SW_REPEAT) x = (int)(u*tex->width) & tex->wMinus1;
else x = (int)(sw_saturate(u)*tex->width);
if (tex->tWrap == SW_REPEAT) y = (int)(v*tex->height) & tex->hMinus1;
else y = (int)(sw_saturate(v)*tex->height);
#endif
{
v = (tex->tWrap == SW_REPEAT)? sw_fract(v) : sw_saturate(v);
y = (int)(v*tex->height);
}
tex->readColor(color, tex->pixels, y*tex->width + x);
}
static inline void sw_texture_sample_linear(float *SW_RESTRICT color, const sw_texture_t *SW_RESTRICT tex, float u, float v)
{
// TODO: With a bit more cleverness the number of operations can
// be clearly reduced, but for now it works fine
float xf = (u*tex->width) - 0.5f;
float yf = (v*tex->height) - 0.5f;
@ -2517,41 +2502,36 @@ static inline void sw_texture_sample_linear(float *SW_RESTRICT color, const sw_t
int x1 = x0 + 1;
int y1 = y0 + 1;
if (tex->sWrap == SW_CLAMP)
{
x0 = (x0 > tex->wMinus1)? tex->wMinus1 : x0;
x1 = (x1 > tex->wMinus1)? tex->wMinus1 : x1;
}
#ifdef SW_TEXTURE_REPEAT_POT_FAST
else if ((tex->width & tex->wMinus1) == 0)
{
// POT fast path: bitmask wrap covers negative ints via two's complement
x0 = x0 & tex->wMinus1;
x1 = x1 & tex->wMinus1;
}
#endif
else
if (tex->sWrap == SW_REPEAT)
{
#if SW_SUPPORT_NPOT_TEXTURE
x0 = (x0%tex->width + tex->width)%tex->width;
x1 = (x1%tex->width + tex->width)%tex->width;
#else
x0 = x0 & tex->wMinus1;
x1 = x1 & tex->wMinus1;
#endif
}
if (tex->tWrap == SW_CLAMP)
{
y0 = (y0 > tex->hMinus1)? tex->hMinus1 : y0;
y1 = (y1 > tex->hMinus1)? tex->hMinus1 : y1;
}
#ifdef SW_TEXTURE_REPEAT_POT_FAST
else if ((tex->height & tex->hMinus1) == 0)
{
y0 = y0 & tex->hMinus1;
y1 = y1 & tex->hMinus1;
}
#endif
else
{
x0 = sw_clamp_int(x0, 0, tex->wMinus1);
x1 = sw_clamp_int(x1, 0, tex->wMinus1);
}
if (tex->tWrap == SW_REPEAT)
{
#if SW_SUPPORT_NPOT_TEXTURE
y0 = (y0%tex->height + tex->height)%tex->height;
y1 = (y1%tex->height + tex->height)%tex->height;
#else
y0 = y0 & tex->hMinus1;
y1 = y1 & tex->hMinus1;
#endif
}
else
{
y0 = sw_clamp_int(y0, 0, tex->hMinus1);
y1 = sw_clamp_int(y1, 0, tex->hMinus1);
}
float c00[4], c10[4], c01[4], c11[4];
@ -3558,8 +3538,8 @@ static inline bool sw_quad_face_culling(void)
// winding in the projected space when all w > 0
// A value of 0 for sgnArea means P0, P1, P2 are collinear in (x, y, w)
// space, which corresponds to a degenerate triangle projection
// Such quads might also be degenerate or non-planar. They are typically
// not culled by this test (0 < 0 is false, 0 > 0 is false)
// Such quads might also be degenerate or non-planar
// They are typically not culled by this test (0 < 0 is false, 0 > 0 is false)
// and should be handled by the clipper if necessary
return (RLSW.cullFace == SW_FRONT)? (sgnArea < 0.0f) : (sgnArea > 0.0f); // Cull if winding is "clockwise" : "counter-clockwise"
@ -3879,8 +3859,7 @@ static inline void sw_poly_fill_render(uint32_t state)
//-------------------------------------------------------------------------------------------
static void sw_immediate_begin(SWdraw mode)
{
// NOTE: Any checks to ensure command recording can start
// must be performed before calling this function.
// NOTE: Any checks to ensure command recording can start must be performed before calling this function
// Recalculate the MVP if this is needed
if (RLSW.isDirtyMVP)
@ -3891,8 +3870,8 @@ static void sw_immediate_begin(SWdraw mode)
#ifdef SW_HAS_ESP_DSP
// Pre-transpose to row-major so dspm_mult_4x4x1_f32(matMVP_rm, v, out)
// computes M*v directly in the per-vertex hot path. 16 scalar copies
// per MVP update vs. saving ~20 cycles per vertex transform.
// computes M*v directly in the per-vertex hot path; 16 scalar copies
// per MVP update vs saving ~20 cycles per vertex transform
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
@ -3955,7 +3934,7 @@ static void sw_immediate_push_vertex(const float position[4])
// Calculate clip coordinates
#ifdef SW_HAS_ESP_DSP
// dspm_mult_4x4x1_f32 declares its inputs non-const; rlsw treats them as
// read-only and the cast is safe (the kernel only loads from B).
// read-only and the cast is safe (the kernel only loads from B)
dspm_mult_4x4x1_f32(RLSW.matMVP_rm, (float *)position, vertex->position);
#else
const float *m = RLSW.matMVP;
@ -5191,11 +5170,25 @@ void swTexParameteri(int param, int value)
case SW_TEXTURE_WRAP_S:
{
if (!sw_is_texture_wrap_valid(value)) { RLSW.errCode = SW_INVALID_ENUM; return; }
#if !SW_SUPPORT_NPOT_TEXTURE
if (value == SW_REPEAT && (RLSW.boundTexture->width & RLSW.boundTexture->wMinus1) != 0)
{
RLSW.errCode = SW_INVALID_OPERATION;
return;
}
#endif
RLSW.boundTexture->sWrap = (SWwrap)value;
} break;
case SW_TEXTURE_WRAP_T:
{
if (!sw_is_texture_wrap_valid(value)) { RLSW.errCode = SW_INVALID_ENUM; return; }
#if !SW_SUPPORT_NPOT_TEXTURE
if (value == SW_REPEAT && (RLSW.boundTexture->height & RLSW.boundTexture->hMinus1) != 0)
{
RLSW.errCode = SW_INVALID_OPERATION;
return;
}
#endif
RLSW.boundTexture->tWrap = (SWwrap)value;
} break;
default: RLSW.errCode = SW_INVALID_ENUM; break;
@ -5389,6 +5382,16 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t
int xEnd = (int)end->position[0];
if (xStart == xEnd) return;
// Intercept the span bounds to ensure to not write before the framebuffer
int xLoopStart = (xStart >= 0)? xStart : 0;
int xLoopEnd = (xEnd <= RLSW.colorBuffer->width)? xEnd : RLSW.colorBuffer->width;
if (xLoopStart >= xLoopEnd) return; // Nothing to draw
// Get the current row and skip if outside the framebuffer
// Maybe this check is better suited elsewhere?
int y = (int)start->position[1];
if (y < 0 || y >= RLSW.colorBuffer->height) return;
// Compute the inverse horizontal distance along the X axis
float dxRcp = sw_rcp(end->position[0] - start->position[0]);
@ -5409,27 +5412,29 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t
#endif
// Compute the subpixel distance to traverse before the first pixel
// Also step further into them to move away from the colorbuffer edge
float xSubstep = 1.0f - sw_fract(start->position[0]);
float dxStart = (float)(xLoopStart - xStart);
float xOffset = xSubstep + dxStart;
// Initializing the interpolation starting values
float w = start->position[3] + dWdx*xSubstep;
float w = start->position[3] + dWdx*xOffset;
float color[4] = {
start->color[0] + dCdx[0]*xSubstep,
start->color[1] + dCdx[1]*xSubstep,
start->color[2] + dCdx[2]*xSubstep,
start->color[3] + dCdx[3]*xSubstep
start->color[0] + dCdx[0]*xOffset,
start->color[1] + dCdx[1]*xOffset,
start->color[2] + dCdx[2]*xOffset,
start->color[3] + dCdx[3]*xOffset
};
#ifdef SW_ENABLE_DEPTH_TEST
float z = start->position[2] + dZdx*xSubstep;
float z = start->position[2] + dZdx*xOffset;
#endif
#ifdef SW_ENABLE_TEXTURE
float u = start->texcoord[0] + dUdx*xSubstep;
float v = start->texcoord[1] + dVdx*xSubstep;
float u = start->texcoord[0] + dUdx*xOffset;
float v = start->texcoord[1] + dVdx*xOffset;
#endif
// Pre-calculate the starting pointers for the framebuffer row
int y = (int)start->position[1];
int baseOffset = y*RLSW.colorBuffer->width + xStart;
int baseOffset = y*RLSW.colorBuffer->width + xLoopStart;
uint8_t *cPtr = (uint8_t *)(RLSW.colorBuffer->pixels) + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE;
#ifdef SW_ENABLE_DEPTH_TEST
uint8_t *dPtr = (uint8_t *)(RLSW.depthBuffer->pixels) + baseOffset*SW_FRAMEBUFFER_DEPTH_SIZE;
@ -5437,12 +5442,12 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t
#define SW_AFFINE_BLOCK 16
int x = xStart;
while (x < xEnd)
int x = xLoopStart;
while (x < xLoopEnd)
{
// Clamp last block to remaining pixels
int blockEnd = x + SW_AFFINE_BLOCK;
if (blockEnd > xEnd) blockEnd = xEnd;
if (blockEnd > xLoopEnd) blockEnd = xLoopEnd;
float blockLenF = (float)(blockEnd - x);
float blockLenRcp = sw_rcp(blockLenF);
@ -5566,8 +5571,7 @@ static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, con
if (v1->position[1] > v2->position[1]) { const sw_vertex_t *tmp = v1; v1 = v2; v2 = tmp; }
if (v0->position[1] > v1->position[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; }
// Extracting coordinates from the sorted vertices
// Put x away for safe keeping. Only y is used right now. Silences warnings.
// Extracting Y coordinates from the sorted vertices
float y0 = v0->position[1];
float y1 = v1->position[1];
float y2 = v2->position[1];
@ -5677,6 +5681,14 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
int xMax = (int)br->position[0];
int yMax = (int)br->position[1];
// Exit early if no pixels to draw. Use these later for loop boundaries
int yLoopMin = (yMin >= 0)? yMin : 0;
int xLoopMin = (xMin >= 0)? xMin : 0;
int yLoopMax = (yMax <= RLSW.colorBuffer->height)? yMax : RLSW.colorBuffer->height;
int xLoopMax = (xMax <= RLSW.colorBuffer->width)? xMax : RLSW.colorBuffer->width;
if (yLoopMin >= yLoopMax || xLoopMin >= xLoopMax) return;
float w = (float)(xMax - xMin);
float h = (float)(yMax - yMin);
if ((w <= 0) || (h <= 0)) return;
@ -5730,21 +5742,44 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
uint8_t *dPixels = RLSW.depthBuffer->pixels;
#endif
for (int y = yMin; y < yMax; y++)
// Calculate the distance the in-bounds boundary is from the quad's edges, only on the left and top
float dxMin = (float)(xLoopMin - xMin);
float dyMin = (float)(yLoopMin - yMin);
// Correct our start by how far it's clipped outside the framebuffer
cRow[0] += dCdx[0]*dxMin + dCdy[0]*dyMin;
cRow[1] += dCdx[1]*dxMin + dCdy[1]*dyMin;
cRow[2] += dCdx[2]*dxMin + dCdy[2]*dyMin;
cRow[3] += dCdx[3]*dxMin + dCdy[3]*dyMin;
#ifdef SW_ENABLE_DEPTH_TEST
zRow += dZdy*dyMin + dZdx*dxMin;
#endif
#ifdef SW_ENABLE_TEXTURE
uRow += dUdy*dyMin + dUdx*dxMin;
vRow += dVdy*dyMin + dVdx*dxMin;
#endif
for (int y = yLoopMin; y < yLoopMax; y++)
{
int baseOffset = y*stride + xMin;
int baseOffset = y*stride + xLoopMin;
uint8_t *cPtr = cPixels + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE;
#ifdef SW_ENABLE_DEPTH_TEST
uint8_t *dPtr = dPixels + baseOffset*SW_FRAMEBUFFER_DEPTH_SIZE;
// Copy the cursors without destroying the offset maths
float z = zRow;
#endif
#ifdef SW_ENABLE_TEXTURE
float u = uRow;
float v = vRow;
#endif
float color[4] = { cRow[0], cRow[1], cRow[2], cRow[3] };
float color[4] = {
cRow[0],
cRow[1],
cRow[2],
cRow[3]
};
for (int x = xMin; x < xMax; x++)
for (int x = xLoopMin; x < xLoopMax; x++)
{
float srcColor[4] = { color[0], color[1], color[2], color[3] };
@ -5783,6 +5818,7 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
#ifdef SW_ENABLE_DEPTH_TEST
discard:
#endif
// Move one pixel over without touching the original "start offset"
color[0] += dCdx[0];
color[1] += dCdx[1];
color[2] += dCdx[2];
@ -5805,6 +5841,9 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
cPtr += SW_FRAMEBUFFER_COLOR_SIZE;
}
// The for loop is clamped to the right side of the screen
// However, these cursor start vars are still on the left
// That's fine, advancing to the next row
cRow[0] += dCdy[0];
cRow[1] += dCdy[1];
cRow[2] += dCdy[2];

10
src/external/rprand.h vendored
View file

@ -1,6 +1,6 @@
/**********************************************************************************************
*
* rprand v1.0 - A simple and easy-to-use pseudo-random numbers generator (PRNG)
* rprand v1.1 - A simple and easy-to-use pseudo-random numbers generator (PRNG)
*
* FEATURES:
* - Pseudo-random values generation, 32 bits: [0..4294967295]
@ -118,6 +118,7 @@ extern "C" { // Prevents name mangling of functions
//----------------------------------------------------------------------------------
RPRANDAPI void rprand_set_seed(unsigned long long seed); // Set rprand_state for Xoshiro128**, seed is 64bit
RPRANDAPI int rprand_get_value(int min, int max); // Get random value within a range, min and max included
RPRANDAPI int rprand_get_value_raw(void); // Get random value, Xoshiro128** generator (uses global rprand_state)
RPRANDAPI int *rprand_load_sequence(unsigned int count, int min, int max); // Load pseudo-random numbers sequence with no duplicates
RPRANDAPI void rprand_unload_sequence(int *sequence); // Unload pseudo-random numbers sequence
@ -186,6 +187,13 @@ int rprand_get_value(int min, int max)
return value;
}
int rprand_get_value_raw(void)
{
int value = rprand_xoshiro();
return value;
}
// Load pseudo-random numbers sequence with no duplicates, min and max included
int *rprand_load_sequence(unsigned int count, int min, int max)
{

View file

@ -473,8 +473,7 @@ void SetWindowFocused(void)
// Get native window handle
void *GetWindowHandle(void)
{
TRACELOG(LOG_WARNING, "GetWindowHandle() not implemented on target platform");
return NULL;
return (void *)platform.app->window; // Type: ANativeWindow*
}
// Get number of monitors

View file

@ -115,7 +115,7 @@ typedef struct {
// Local storage for the window handle returned by glfwGetX11Window
// This is needed as X11 handles are integers and may not fit inside a pointer depending on platform
// Storing the handle locally and returning a pointer in GetWindowHandle allows the code to work regardless of pointer width
XID windowHandleX11;
Window windowHandleX11; // Underlying type: unsigned long (XID, Window)
#endif
} PlatformData;
@ -764,9 +764,10 @@ void SetWindowFocused(void)
// Get native window handle
void *GetWindowHandle(void)
{
void *handle = NULL;
#if defined(_WIN32)
// NOTE: Returned handle is: void *HWND (windows.h)
return glfwGetWin32Window(platform.handle);
handle = glfwGetWin32Window(platform.handle); // Type: HWND
#endif
#if defined(__linux__)
#if defined(_GLFW_WAYLAND)
@ -774,28 +775,27 @@ void *GetWindowHandle(void)
int platformID = glfwGetPlatform();
if (platformID == GLFW_PLATFORM_WAYLAND)
{
return glfwGetWaylandWindow(platform.handle);
handle = (void *)glfwGetWaylandWindow(platform.handle); // Type: struct wl_surface*
}
else
{
platform.windowHandleX11 = glfwGetX11Window(platform.handle);
return &platform.windowHandleX11;
platform.windowHandleX11 = glfwGetX11Window(platform.handle); // Type: Window (unsigned long)
handle = &platform.windowHandleX11;
}
#else
return glfwGetWaylandWindow(platform.handle);
handle = (void *)glfwGetWaylandWindow(platform.handle);
#endif
#elif defined(_GLFW_X11)
// Store the window handle localy and return a pointer to the variable instead
// Store the window handle locally and return a pointer to the variable instead
platform.windowHandleX11 = glfwGetX11Window(platform.handle);
return &platform.windowHandleX11;
handle = &platform.windowHandleX11;
#endif
#endif
#if defined(__APPLE__)
// NOTE: Returned handle is: (objc_object *)
return (void *)glfwGetCocoaWindow(platform.handle);
handle = (void *)glfwGetCocoaWindow(platform.handle); // Type: NSWindow*
#endif
return NULL;
return handle;
}
// Get number of monitors
@ -839,7 +839,7 @@ int GetCurrentMonitor(void)
// this is probably an overengineered solution for a side case
// trying to match SDL behaviour
int closestDist = 0x7FFFFFFF;
unsigned int closestDist = 0xFFFFFFFFu;
// Window center position
int wcx = 0;
@ -883,7 +883,14 @@ int GetCurrentMonitor(void)
int dx = wcx - xclosest;
int dy = wcy - yclosest;
int dist = (dx*dx) + (dy*dy);
// Unsigned to dodge signed overflow UB; (-x)^2 == x^2 mod 2^32 so sign drops out.
// If |dx| or |dy| >= 65536, dist wraps and the wrong monitor may win.
// Not a concern for realistic monitor layouts.
unsigned int ux = (unsigned int)dx;
unsigned int uy = (unsigned int)dy;
unsigned int dist = ux*ux + uy*uy;
if (dist < closestDist)
{
index = i;
@ -1042,11 +1049,6 @@ const char *GetClipboardText(void)
return glfwGetClipboardString(platform.handle);
}
#if SUPPORT_CLIPBOARD_IMAGE && defined(__linux__) && defined(_GLFW_X11)
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#endif
// Get clipboard image
Image GetClipboardImage(void)
{
@ -1066,32 +1068,30 @@ Image GetClipboardImage(void)
else image = LoadImageFromMemory(".bmp", (const unsigned char *)bmpData, (int)dataSize);
#elif defined(__linux__) && defined(_GLFW_X11)
// REF: https://github.com/ColleagueRiley/Clipboard-Copy-Paste/blob/main/x11.c
Display *dpy = XOpenDisplay(NULL);
if (!dpy) return image;
Window root = DefaultRootWindow(dpy);
Window win = XCreateSimpleWindow(
dpy, // The connection to the X Server
root, // The 'Parent' window (usually the desktop/root)
0, 0, // X and Y position on the screen
1, 1, // Width and Height (1x1 pixel)
0, // Border width
0, // Border color
0 // Background color
);
static Atom clipboard = 0;
static Atom targetType = 0;
static Atom property = 0;
Atom clipboard = XInternAtom(dpy, "CLIPBOARD", False);
Atom targetType = XInternAtom(dpy, "image/png", False); // Ask for PNG
Atom property = XInternAtom(dpy, "RAYLIB_CLIPBOARD_MANAGER", False);
Display *display = glfwGetX11Display();
XID window = glfwGetX11Window(platform.handle);
// Request the data: "Convert whatever is in CLIPBOARD to image/png and put it in RAYLIB_CLIPBOARD_MANAGER"
XConvertSelection(dpy, clipboard, targetType, property, win, CurrentTime);
// Lazy-load X11 atoms
if(clipboard == 0)
{
clipboard = XInternAtom(display, "CLIPBOARD", False);
targetType = XInternAtom(display, "image/png", False);
property = XInternAtom(display, "RAYLIB_CLIPBOARD_MANAGER", False);
}
XConvertSelection(display, clipboard, targetType, property, window, CurrentTime);
XSync(display, 0);
// Wait for the SelectionNotify event
XEvent ev = { 0 };
XNextEvent(dpy, &ev);
// Keep calling until we get SelectionNotify
while (XCheckTypedEvent(display, SelectionNotify, &ev) == False);
Atom actualType = { 0 };
int actualFormat = 0;
@ -1099,9 +1099,8 @@ Image GetClipboardImage(void)
unsigned long bytesAfter = 0;
unsigned char *data = NULL;
// Read the data from our ghost window's property
XGetWindowProperty(dpy, win, property, 0, ~0L, False, AnyPropertyType,
&actualType, &actualFormat, &nitems, &bytesAfter, &data);
XGetWindowProperty(display, window, property, 0, ~0L, False, AnyPropertyType,
&actualType, &actualFormat, &nitems, &bytesAfter, &data);
if (data != NULL)
{
@ -1109,8 +1108,6 @@ Image GetClipboardImage(void)
XFree(data);
}
XDestroyWindow(dpy, win);
XCloseDisplay(dpy);
#else
TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform");
#endif // _WIN32

View file

@ -184,6 +184,9 @@ typedef struct {
i32 surfaceWidth;
i32 surfaceHeight;
#endif
#if defined(__linux__) && defined(RGFW_X11)
Window windowHandleX11; // Underlying type: unsigned long
#endif
} PlatformData;
//----------------------------------------------------------------------------------
@ -810,8 +813,8 @@ void SetWindowSize(int width, int height)
RGFW_monitor* currentMonitor = RGFW_window_getMonitor(platform.window);
CORE.Window.screenScale = MatrixScale(currentMonitor->pixelRatio, currentMonitor->pixelRatio, 1.0f);
CORE.Window.render.width = CORE.Window.screen.width * currentMonitor->pixelRatio;
CORE.Window.render.height = CORE.Window.screen.height * currentMonitor->pixelRatio;
CORE.Window.render.width = CORE.Window.screen.width*currentMonitor->pixelRatio;
CORE.Window.render.height = CORE.Window.screen.height*currentMonitor->pixelRatio;
CORE.Window.currentFbo.width = CORE.Window.render.width;
CORE.Window.currentFbo.height = CORE.Window.render.height;
#else
@ -851,15 +854,25 @@ void SetWindowFocused(void)
// Get native window handle
void *GetWindowHandle(void)
{
if (platform.window == NULL) return NULL;
void *handle = NULL;
#if defined(RGFW_WASM)
return (void *)&platform.window->src.ctx;
#elif defined(RGFW_WAYLAND)
return (void *)platform.window->src.surface;
#else
return (void *)platform.window->src.window;
if (platform.window != NULL)
{
#if defined(_WIN32)
handle = (void *)platform.window->src.window; // Type: HWND
#elif defined(__linux__)
#if defined(RGFW_X11)
platform.windowHandleX11 = platform.window->src.window; // Type: Window (unsigned long)
handle = &platform.window->src.window;
#elif defined(RGFW_WAYLAND)
handle = (void *)platform.window->src.surface; // Type: struct wl_surface*
#endif
#elif defined(__APPLE__)
handle = (void *)platform.window->src.window; // Type: id, NSWindow*
#endif
}
return handle;
}
// Get number of monitors
@ -1132,16 +1145,16 @@ void SwapScreenBuffer(void)
{
if (platform.surface)
{
// copy rlsw pixel data to the surface framebuffer
swReadPixels(0, 0, platform.surfaceWidth, platform.surfaceHeight, SW_RGBA, SW_UNSIGNED_BYTE, platform.surfacePixels);
// Copy rlsw pixel data to the surface framebuffer
rlCopyFramebuffer(0, 0, platform.surfaceWidth, platform.surfaceHeight, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, platform.surfacePixels);
// Mac wants a different pixel order. I cant seem to get this to work any other way
#if defined(__APPLE__)
unsigned char temp = 0;
unsigned char *p = NULL;
for (int i = 0; i < (platform.surfaceWidth * platform.surfaceHeight); i += 1)
for (int i = 0; i < (platform.surfaceWidth*platform.surfaceHeight); i += 1)
{
p = platform.surfacePixels + (i * 4);
p = platform.surfacePixels + (i*4);
temp = p[0];
p[0] = p[2];
p[2] = temp;
@ -1357,13 +1370,13 @@ void PollInputEvents(void)
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
{
RGFW_monitor* currentMonitor = RGFW_window_getMonitor(platform.window);
SetupViewport(platform.window->w * currentMonitor->pixelRatio, platform.window->h * currentMonitor->pixelRatio);
SetupViewport(platform.window->w*currentMonitor->pixelRatio, platform.window->h*currentMonitor->pixelRatio);
CORE.Window.screenScale = MatrixScale(currentMonitor->pixelRatio, currentMonitor->pixelRatio, 1.0f);
CORE.Window.screen.width = platform.window->w;
CORE.Window.screen.height = platform.window->h;
CORE.Window.render.width = CORE.Window.screen.width * currentMonitor->pixelRatio;
CORE.Window.render.height = CORE.Window.screen.height * currentMonitor->pixelRatio;
CORE.Window.render.width = CORE.Window.screen.width*currentMonitor->pixelRatio;
CORE.Window.render.height = CORE.Window.screen.height*currentMonitor->pixelRatio;
}
else
{
@ -1406,10 +1419,10 @@ void PollInputEvents(void)
#if defined(__APPLE__)
RGFW_monitor* currentMonitor = RGFW_window_getMonitor(platform.window);
CORE.Window.screenScale = MatrixScale(currentMonitor->pixelRatio, currentMonitor->pixelRatio, 1.0f);
SetupViewport(platform.window->w * currentMonitor->pixelRatio, platform.window->h * currentMonitor->pixelRatio);
SetupViewport(platform.window->w*currentMonitor->pixelRatio, platform.window->h*currentMonitor->pixelRatio);
CORE.Window.render.width = CORE.Window.screen.width * currentMonitor->pixelRatio;
CORE.Window.render.height = CORE.Window.screen.height * currentMonitor->pixelRatio;
CORE.Window.render.width = CORE.Window.screen.width*currentMonitor->pixelRatio;
CORE.Window.render.height = CORE.Window.screen.height*currentMonitor->pixelRatio;
CORE.Window.currentFbo.width = CORE.Window.render.width;
CORE.Window.currentFbo.height = CORE.Window.render.height;
#endif
@ -1427,7 +1440,7 @@ void PollInputEvents(void)
if (platform.surfacePixels != NULL)
{
RL_FREE(platform.surfacePixels);
platform.surfacePixels = RL_MALLOC(platform.surfaceWidth * platform.surfaceHeight * 4);
platform.surfacePixels = RL_MALLOC(platform.surfaceWidth*platform.surfaceHeight*4);
}
if (platform.surface != NULL)
@ -1743,8 +1756,8 @@ int InitPlatform(void)
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
{
#if !defined(__APPLE__)
CORE.Window.screen.width = CORE.Window.screen.width * GetWindowScaleDPI().x;
CORE.Window.screen.height = CORE.Window.screen.height * GetWindowScaleDPI().y;
CORE.Window.screen.width = CORE.Window.screen.width*GetWindowScaleDPI().x;
CORE.Window.screen.height = CORE.Window.screen.height*GetWindowScaleDPI().y;
#endif
}
@ -1828,8 +1841,8 @@ int InitPlatform(void)
RGFW_monitor* currentMonitor = RGFW_window_getMonitor(platform.window);
CORE.Window.screenScale = MatrixScale(currentMonitor->pixelRatio, currentMonitor->pixelRatio, 1.0f);
CORE.Window.render.width = CORE.Window.screen.width * currentMonitor->pixelRatio;
CORE.Window.render.height = CORE.Window.screen.height * currentMonitor->pixelRatio;
CORE.Window.render.width = CORE.Window.screen.width*currentMonitor->pixelRatio;
CORE.Window.render.height = CORE.Window.screen.height*currentMonitor->pixelRatio;
CORE.Window.currentFbo.width = CORE.Window.render.width;
CORE.Window.currentFbo.height = CORE.Window.render.height;
#else
@ -1846,8 +1859,8 @@ int InitPlatform(void)
RGFW_monitor* currentMonitor = RGFW_window_getMonitor(platform.window);
CORE.Window.screenScale = MatrixScale(currentMonitor->pixelRatio, currentMonitor->pixelRatio, 1.0f);
CORE.Window.render.width = CORE.Window.screen.width * currentMonitor->pixelRatio;
CORE.Window.render.height = CORE.Window.screen.height * currentMonitor->pixelRatio;
CORE.Window.render.width = CORE.Window.screen.width*currentMonitor->pixelRatio;
CORE.Window.render.height = CORE.Window.screen.height*currentMonitor->pixelRatio;
CORE.Window.currentFbo.width = CORE.Window.render.width;
CORE.Window.currentFbo.height = CORE.Window.render.height;
#endif
@ -1855,7 +1868,7 @@ int InitPlatform(void)
platform.surfaceWidth = CORE.Window.currentFbo.width;
platform.surfaceHeight = CORE.Window.currentFbo.height;
platform.surfacePixels = RL_MALLOC(platform.surfaceWidth * platform.surfaceHeight * 4);
platform.surfacePixels = RL_MALLOC(platform.surfaceWidth*platform.surfaceHeight*4);
if (platform.surfacePixels == NULL)
{
TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize software pixel buffer");

View file

@ -56,6 +56,7 @@
#include "SDL3/SDL.h"
#elif defined(USING_SDL2_PROJECT)
#include "SDL2/SDL.h"
#include "SDL2/SDL_syswm.h" // Required to get window handlers
#else
#include "SDL.h"
#endif
@ -101,6 +102,13 @@ typedef struct {
SDL_GameController *gamepad[MAX_GAMEPADS];
SDL_JoystickID gamepadId[MAX_GAMEPADS]; // Joystick instance ids, they do not start from 0
SDL_Cursor *cursor;
#if defined(__linux__)
// Local storage for the window handle (X11)
// NOTE: On SDL is not possible to know windowing backend at compile time, so,
// just in case, avoiding X11 specific types here
unsigned long windowHandleX11; // Underlying type for: XID, Window
#endif
} PlatformData;
//----------------------------------------------------------------------------------
@ -920,9 +928,60 @@ void SetWindowFocused(void)
}
// Get native window handle
// NOTE: Handle type depends on OS and windowing system
void *GetWindowHandle(void)
{
return (void *)platform.window;
void *handle = NULL;
#if defined(USING_SDL3_PROJECT)
// REF: https://github.com/libsdl-org/SDL/blob/main/include/SDL3/SDL_video.h#L1590
SDL_PropertiesID props = SDL_GetWindowProperties(platform.window);
#if defined(_WIN32)
handle = (void *)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); // Type: HWND
#elif defined(__linux__)
unsigned long windowId = (unsigned long)SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0); // Type: unsigned long (XID, Window)
if (windowId != 0)
{
// X11 window ID
platform.windowHandleX11 = windowId;
handle = &platform.windowHandleX11;
}
else
{
// Wayland, get display surface pointer
// NOTE: Alternative SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER
handle = (void *)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, NULL); // Type: struct wl_surface*
}
#elif defined(__APPLE__)
handle = (void *)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, NULL); // Type: NSWindow*
#endif
#elif defined(USING_SDL2_PROJECT)
SDL_SysWMinfo wmInfo = { 0 };
SDL_VERSION(&wmInfo.version);
if (SDL_GetWindowWMInfo(platform.window, &wmInfo))
{
#if defined(_WIN32)
handle = (void *)wmInfo.info.win.window; // Type: HWND
#elif defined(__linux__)
if (wmInfo.subsystem == SDL_SYSWM_X11)
{
// X11, get window ID (unsigned long)
platform.windowHandleX11 = (unsigned long)wmInfo.info.x11.window;
handle = &platform.windowHandleX11;
}
else if (wmInfo.subsystem == SDL_SYSWM_WAYLAND)
{
// Wayland, get display surface pointer
// NOTE: Alternative: wmInfo.info.wl.display
handle = (void *)wmInfo.info.wl.surface; // Type: struct wl_surface*
}
#elif defined(__APPLE__)
handle = (void *)wmInfo.info.cocoa.window; // Type: NSWindow*
#endif
}
#endif
return handle;
}
// Get number of monitors

View file

@ -1023,7 +1023,7 @@ void SetWindowFocused(void)
// Get native window handle
void *GetWindowHandle(void)
{
return platform.hwnd;
return (void *)platform.hwnd;
}
int GetMonitorCount(void)
@ -1257,8 +1257,9 @@ void OpenURL(const char *url)
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
else
{
char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char));
sprintf(cmd, "explorer \"%s\"", url);
int len = strlen(url) + 32;
char *cmd = (char *)RL_CALLOC(len, sizeof(char));
snprintf(cmd, len, "explorer \"%s\"", url);
int result = system(cmd);
if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created");
RL_FREE(cmd);
@ -2052,8 +2053,11 @@ static void HandleMouseButton(int button, char state)
static void HandleRawInput(LPARAM lparam)
{
RAWINPUT input = { 0 };
UINT inputSize = 0;
if (GetRawInputData((HRAWINPUT)lparam, RID_INPUT, NULL, &inputSize, sizeof(RAWINPUTHEADER)) != 0) return;
if (inputSize > sizeof(input)) return;
UINT inputSize = sizeof(input);
UINT size = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &input, &inputSize, sizeof(RAWINPUTHEADER));
if (size == (UINT)-1) TRACELOG(LOG_ERROR, "WIN32: Failed to get raw input data [ERROR: %lu]", GetLastError());

View file

@ -91,7 +91,7 @@ bool InitGraphicsDevice(void); // Initialize graphics device
// Module Internal Functions Declaration
//----------------------------------------------------------------------------------
#if !defined(_WIN32)
static int kbhit(void); // Check if a key has been pressed
static int kbhit(void); // Check if key has been pressed
static char getch(void) { return getchar(); } // Get pressed character
#endif
@ -374,6 +374,8 @@ double GetTime(void)
unsigned long long nanoSeconds = (unsigned long long)ts.tv_sec*1000000000LLU + (unsigned long long)ts.tv_nsec;
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
#elif defined(PICO_RP2350)
time = (double)to_ms_since_boot(get_absolute_time())/1000.0;
#endif
return time;
}
@ -560,7 +562,7 @@ void ClosePlatform(void)
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
#if !defined(_WIN32)
// Check if a key has been pressed
// Check if key has been pressed
static int kbhit(void)
{
struct termios oldt = { 0 };

View file

@ -1013,7 +1013,7 @@ Sound LoadSoundAlias(Sound source)
return sound;
}
// Check if a sound is valid (data loaded and buffers initialized)
// Check if sound is valid (data loaded and buffers initialized)
bool IsSoundValid(Sound sound)
{
bool result = false;
@ -1215,7 +1215,7 @@ void StopSound(Sound sound)
StopAudioBuffer(sound.stream.buffer);
}
// Check if a sound is playing
// Check if sound is playing
bool IsSoundPlaying(Sound sound)
{
bool result = false;
@ -1751,7 +1751,7 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data,
return music;
}
// Check if a music stream is valid (context and buffers initialized)
// Check if music stream is valid (context and buffers initialized)
bool IsMusicValid(Music music)
{
return ((music.ctxData != NULL) && // Validate context loaded

View file

@ -1070,7 +1070,7 @@ RLAPI void UnloadVrStereoConfig(VrStereoConfig config); // Unload VR s
// NOTE: Shader functionality is not available on OpenGL 1.1
RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations
RLAPI Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations
RLAPI bool IsShaderValid(Shader shader); // Check if a shader is valid (loaded on GPU)
RLAPI bool IsShaderValid(Shader shader); // Check if shader is valid (loaded on GPU)
RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location
RLAPI int GetShaderLocationAttrib(Shader shader, const char *attribName); // Get shader attribute location
RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType); // Set shader uniform value
@ -1141,14 +1141,14 @@ RLAPI void SetSaveFileDataCallback(SaveFileDataCallback callback); // Set custo
RLAPI void SetLoadFileTextCallback(LoadFileTextCallback callback); // Set custom file text data loader
RLAPI void SetSaveFileTextCallback(SaveFileTextCallback callback); // Set custom file text data saver
RLAPI int FileRename(const char *fileName, const char *fileRename); // Rename file (if exists)
RLAPI int FileRemove(const char *fileName); // Remove file (if exists)
RLAPI int FileCopy(const char *srcPath, const char *dstPath); // Copy file from one path to another, dstPath created if it doesn't exist
RLAPI int FileMove(const char *srcPath, const char *dstPath); // Move file from one directory to another, dstPath created if it doesn't exist
RLAPI int FileTextReplace(const char *fileName, const char *search, const char *replacement); // Replace text in an existing file
RLAPI int FileTextFindIndex(const char *fileName, const char *search); // Find text in existing file
RLAPI int FileRename(const char *fileName, const char *fileRename); // Rename file (if exists), returns 0 on success
RLAPI int FileRemove(const char *fileName); // Remove file (if exists), returns 0 on success
RLAPI int FileCopy(const char *srcPath, const char *dstPath); // Copy file from one path to another, dstPath created if it doesn't exist, returns 0 on success
RLAPI int FileMove(const char *srcPath, const char *dstPath); // Move file from one directory to another, dstPath created if it doesn't exist, returns 0 on success
RLAPI int FileTextReplace(const char *fileName, const char *search, const char *replacement); // Replace text in an existing file, returns 0 on success
RLAPI int FileTextFindIndex(const char *fileName, const char *search); // Find text in existing file, returns -1 if index not found or index otherwise
RLAPI bool FileExists(const char *fileName); // Check if file exists
RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists
RLAPI bool DirectoryExists(const char *dirPath); // Check if directory path exists
RLAPI bool IsFileExtension(const char *fileName, const char *ext); // Check file extension (recommended include point: .png, .wav)
RLAPI int GetFileLength(const char *fileName); // Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h)
RLAPI long GetFileModTime(const char *fileName); // Get file modification time (last write time)
@ -1160,13 +1160,13 @@ RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previ
RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string)
RLAPI const char *GetApplicationDirectory(void); // Get the directory of the running application (uses static string)
RLAPI int MakeDirectory(const char *dirPath); // Create directories (including full path requested), returns 0 on success
RLAPI bool ChangeDirectory(const char *dirPath); // Change working directory, return true on success
RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory
RLAPI int ChangeDirectory(const char *dirPath); // Change working directory, returns 0 on success
RLAPI bool IsPathFile(const char *path); // Check if given path is a file or a directory
RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS
RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths, files and directories, no subdirs scan
RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and subdir scan; some filters available: `*.*`,`FILES*`,`DIRS*`
RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and subdir scan; some filters available: '*.*','FILES*','DIRS*'
RLAPI void UnloadDirectoryFiles(FilePathList files); // Unload filepaths
RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window
RLAPI bool IsFileDropped(void); // Check if file has been dropped into window
RLAPI FilePathList LoadDroppedFiles(void); // Load dropped filepaths
RLAPI void UnloadDroppedFiles(FilePathList files); // Unload dropped filepaths
RLAPI unsigned int GetDirectoryFileCount(const char *dirPath); // Get the file count in a directory
@ -1197,23 +1197,23 @@ RLAPI void PlayAutomationEvent(AutomationEvent event); // Play a reco
//------------------------------------------------------------------------------------
// Input-related functions: keyboard
RLAPI bool IsKeyPressed(int key); // Check if a key has been pressed once
RLAPI bool IsKeyPressedRepeat(int key); // Check if a key has been pressed again
RLAPI bool IsKeyDown(int key); // Check if a key is being pressed
RLAPI bool IsKeyReleased(int key); // Check if a key has been released once
RLAPI bool IsKeyUp(int key); // Check if a key is NOT being pressed
RLAPI bool IsKeyPressed(int key); // Check if key has been pressed once
RLAPI bool IsKeyPressedRepeat(int key); // Check if key has been pressed again
RLAPI bool IsKeyDown(int key); // Check if key is being pressed
RLAPI bool IsKeyReleased(int key); // Check if key has been released once
RLAPI bool IsKeyUp(int key); // Check if key is NOT being pressed
RLAPI int GetKeyPressed(void); // Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty
RLAPI int GetCharPressed(void); // Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty
RLAPI const char *GetKeyName(int key); // Get name of a QWERTY key on the current keyboard layout (eg returns string 'q' for KEY_A on an AZERTY keyboard)
RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC)
// Input-related functions: gamepads
RLAPI bool IsGamepadAvailable(int gamepad); // Check if a gamepad is available
RLAPI bool IsGamepadAvailable(int gamepad); // Check if gamepad is available
RLAPI const char *GetGamepadName(int gamepad); // Get gamepad internal name id
RLAPI bool IsGamepadButtonPressed(int gamepad, int button); // Check if a gamepad button has been pressed once
RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Check if a gamepad button is being pressed
RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Check if a gamepad button has been released once
RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Check if a gamepad button is NOT being pressed
RLAPI bool IsGamepadButtonPressed(int gamepad, int button); // Check if gamepad button has been pressed once
RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Check if gamepad button is being pressed
RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Check if gamepad button has been released once
RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Check if gamepad button is NOT being pressed
RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed
RLAPI int GetGamepadAxisCount(int gamepad); // Get axis count for a gamepad
RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Get movement value for a gamepad axis
@ -1221,10 +1221,10 @@ RLAPI int SetGamepadMappings(const char *mappings); // Set internal ga
RLAPI void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration); // Set gamepad vibration for both motors (duration in seconds)
// Input-related functions: mouse
RLAPI bool IsMouseButtonPressed(int button); // Check if a mouse button has been pressed once
RLAPI bool IsMouseButtonDown(int button); // Check if a mouse button is being pressed
RLAPI bool IsMouseButtonReleased(int button); // Check if a mouse button has been released once
RLAPI bool IsMouseButtonUp(int button); // Check if a mouse button is NOT being pressed
RLAPI bool IsMouseButtonPressed(int button); // Check if mouse button has been pressed once
RLAPI bool IsMouseButtonDown(int button); // Check if mouse button is being pressed
RLAPI bool IsMouseButtonReleased(int button); // Check if mouse button has been released once
RLAPI bool IsMouseButtonUp(int button); // Check if mouse button is NOT being pressed
RLAPI int GetMouseX(void); // Get mouse position X
RLAPI int GetMouseY(void); // Get mouse position Y
RLAPI Vector2 GetMousePosition(void); // Get mouse position XY
@ -1247,7 +1247,7 @@ RLAPI int GetTouchPointCount(void); // Get number of t
// Gestures and Touch Handling Functions (Module: rgestures)
//------------------------------------------------------------------------------------
RLAPI void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags
RLAPI bool IsGestureDetected(unsigned int gesture); // Check if a gesture has been detected
RLAPI bool IsGestureDetected(unsigned int gesture); // Check if gesture has been detected
RLAPI int GetGestureDetected(void); // Get latest detected gesture
RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in seconds
RLAPI Vector2 GetGestureDragVector(void); // Get gesture drag vector
@ -1267,7 +1267,7 @@ RLAPI void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, f
// Set texture and rectangle to be used on shapes drawing
// NOTE: It can be useful when using basic shapes and one single font,
// defining a font char white rectangle would allow drawing everything in a single draw call
RLAPI void SetShapesTexture(Texture2D texture, Rectangle source); // Set texture and rectangle to be used on shapes drawing
RLAPI void SetShapesTexture(Texture2D texture, Rectangle rec); // Set texture and rectangle to be used on shapes drawing
RLAPI Texture2D GetShapesTexture(void); // Get texture that is used for shapes drawing
RLAPI Rectangle GetShapesTextureRectangle(void); // Get texture source rectangle that is used for shapes drawing
@ -1446,9 +1446,9 @@ RLAPI Texture2D LoadTexture(const char *fileName);
RLAPI Texture2D LoadTextureFromImage(Image image); // Load texture from image data
RLAPI TextureCubemap LoadTextureCubemap(Image image, int layout); // Load cubemap from image, multiple image cubemap layouts supported
RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer)
RLAPI bool IsTextureValid(Texture2D texture); // Check if a texture is valid (loaded in GPU)
RLAPI bool IsTextureValid(Texture2D texture); // Check if texture is valid (loaded in GPU)
RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM)
RLAPI bool IsRenderTextureValid(RenderTexture2D target); // Check if a render texture is valid (loaded in GPU)
RLAPI bool IsRenderTextureValid(RenderTexture2D target); // Check if render texture is valid (loaded in GPU)
RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM)
RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data (pixels should be able to fill texture)
RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels); // Update GPU texture rectangle with new data (pixels and rec should fit in texture)
@ -1462,9 +1462,9 @@ RLAPI void SetTextureWrap(Texture2D texture, int wrap);
RLAPI void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D
RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2
RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters
RLAPI void DrawTextureRec(Texture2D texture, Rectangle source, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle
RLAPI void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters
RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draw a texture (or part of it) that stretches or shrinks nicely
RLAPI void DrawTextureRec(Texture2D texture, Rectangle rec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle
RLAPI void DrawTexturePro(Texture2D texture, Rectangle srcrec, Rectangle dstrec, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a source rectangle to destination rectangle, with scaling and rotation
RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dstrec, Vector2 origin, float rotation, Color tint); // Draw a texture (or part of it) that stretches or shrinks nicely
// Color/pixel related functions
RLAPI bool ColorIsEqual(Color col1, Color col2); // Check if two colors are equal
@ -1481,7 +1481,7 @@ RLAPI Color ColorAlpha(Color color, float alpha); // G
RLAPI Color ColorAlphaBlend(Color dst, Color src, Color tint); // Get src alpha-blended into dst color with tint
RLAPI Color ColorLerp(Color color1, Color color2, float factor); // Get color lerp interpolation between two colors, factor [0.0f..1.0f]
RLAPI Color GetColor(unsigned int hexValue); // Get Color structure from hexadecimal value
RLAPI Color GetPixelColor(void *srcPtr, int format); // Get Color from a source pixel pointer of certain format
RLAPI Color GetPixelColor(const void *srcPtr, int format); // Get Color from a source pixel pointer of certain format
RLAPI void SetPixelColor(void *dstPtr, Color color, int format); // Set color formatted into destination pixel pointer
RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes for certain format
@ -1495,7 +1495,7 @@ RLAPI Font LoadFont(const char *fileName);
RLAPI Font LoadFontEx(const char *fileName, int fontSize, const int *codepoints, int codepointCount); // Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height
RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style)
RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, const int *codepoints, int codepointCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf'
RLAPI bool IsFontValid(Font font); // Check if a font is valid (font data loaded, WARNING: GPU texture not checked)
RLAPI bool IsFontValid(Font font); // Check if font is valid (font data loaded, WARNING: GPU texture not checked)
RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, const int *codepoints, int codepointCount, int type, int *glyphCount); // Load font data for further use
RLAPI Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info
RLAPI void UnloadFontData(GlyphInfo *glyphs, int glyphCount); // Unload font chars info data (RAM)
@ -1577,10 +1577,10 @@ RLAPI void DrawCubeWiresV(Vector3 position, Vector3 size, Color color);
RLAPI void DrawSphere(Vector3 centerPos, float radius, Color color); // Draw sphere
RLAPI void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere with extended parameters
RLAPI void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere wires
RLAPI void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone
RLAPI void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color); // Draw a cylinder/cone
RLAPI void DrawCylinderEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color); // Draw a cylinder with base at startPos and top at endPos
RLAPI void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone wires
RLAPI void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int slices, Color color); // Draw a cylinder wires with base at startPos and top at endPos
RLAPI void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color); // Draw a cylinder/cone wires
RLAPI void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color); // Draw a cylinder wires with base at startPos and top at endPos
RLAPI void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int rings, int slices, Color color); // Draw a capsule with the center of its sphere caps at startPos and endPos
RLAPI void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int rings, int slices, Color color); // Draw capsule wireframe with the center of its sphere caps at startPos and endPos
RLAPI void DrawPlane(Vector3 centerPos, Vector2 size, Color color); // Draw a plane XZ
@ -1594,7 +1594,7 @@ RLAPI void DrawGrid(int slices, float spacing);
// Model management functions
RLAPI Model LoadModel(const char *fileName); // Load model from files (meshes and materials)
RLAPI Model LoadModelFromMesh(Mesh mesh); // Load model from generated mesh (default material)
RLAPI bool IsModelValid(Model model); // Check if a model is valid (loaded in GPU, VAO/VBOs)
RLAPI bool IsModelValid(Model model); // Check if model is valid (loaded in GPU, VAO/VBOs)
RLAPI void UnloadModel(Model model); // Unload model (including meshes) from memory (RAM and/or VRAM)
RLAPI BoundingBox GetModelBoundingBox(Model model); // Compute model bounding box limits (considers all meshes)
@ -1605,8 +1605,8 @@ RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint
RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters
RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires)
RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint); // Draw a billboard texture
RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint); // Draw a billboard texture defined by source
RLAPI void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint); // Draw a billboard texture defined by source and rotation
RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle rec, Vector3 position, Vector2 size, Color tint); // Draw a billboard texture defined by rectangle
RLAPI void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle rec, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint); // Draw a billboard texture defined by source rectangle with scaling and rotation
// Mesh management functions
RLAPI void UploadMesh(Mesh *mesh, bool dynamic); // Upload mesh vertex data in GPU and provide VAO/VBO ids
@ -1635,7 +1635,7 @@ RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize);
// Material loading/unloading functions
RLAPI Material *LoadMaterials(const char *fileName, int *materialCount); // Load materials from model file
RLAPI Material LoadMaterialDefault(void); // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)
RLAPI bool IsMaterialValid(Material material); // Check if a material is valid (shader assigned, map textures loaded in GPU)
RLAPI bool IsMaterialValid(Material material); // Check if material is valid (shader assigned, map textures loaded in GPU)
RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM)
RLAPI void SetMaterialTexture(Material *material, int mapType, Texture2D texture); // Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...)
RLAPI void SetModelMeshMaterial(Model *model, int meshId, int materialId); // Set material for a mesh
@ -1676,7 +1676,7 @@ RLAPI bool IsWaveValid(Wave wave); // Check i
RLAPI Sound LoadSound(const char *fileName); // Load sound from file
RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data
RLAPI Sound LoadSoundAlias(Sound source); // Load sound alias, new sound that shares the same sample data as the source sound, does not own the sound data
RLAPI bool IsSoundValid(Sound sound); // Check if a sound is valid (data loaded and buffers initialized)
RLAPI bool IsSoundValid(Sound sound); // Check if sound is valid (data loaded and buffers initialized)
RLAPI void UpdateSound(Sound sound, const void *data, int frameCount); // Update sound buffer with new data (default data format: 32 bit float, stereo)
RLAPI void UnloadWave(Wave wave); // Unload wave data
RLAPI void UnloadSound(Sound sound); // Unload sound
@ -1689,7 +1689,7 @@ RLAPI void PlaySound(Sound sound); // Play a
RLAPI void StopSound(Sound sound); // Stop playing a sound
RLAPI void PauseSound(Sound sound); // Pause a sound
RLAPI void ResumeSound(Sound sound); // Resume a paused sound
RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing
RLAPI bool IsSoundPlaying(Sound sound); // Check if sound is currently playing
RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level)
RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level)
RLAPI void SetSoundPan(Sound sound, float pan); // Set pan for a sound (-1.0 left, 0.0 center, 1.0 right)
@ -1702,7 +1702,7 @@ RLAPI void UnloadWaveSamples(float *samples); // Unload
// Music management functions
RLAPI Music LoadMusicStream(const char *fileName); // Load music stream from file
RLAPI Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, int dataSize); // Load music stream from data
RLAPI bool IsMusicValid(Music music); // Check if a music stream is valid (context and buffers initialized)
RLAPI bool IsMusicValid(Music music); // Check if music stream is valid (context and buffers initialized)
RLAPI void UnloadMusicStream(Music music); // Unload music stream
RLAPI void PlayMusicStream(Music music); // Start music playing
RLAPI bool IsMusicStreamPlaying(Music music); // Check if music is playing

View file

@ -506,11 +506,11 @@ __declspec(dllimport) void __stdcall Sleep(unsigned long msTimeout); // Required
const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed'
#endif
// NOTE: PLATFORM_DESKTOP defaults to GLFW backend
#if defined(PLATFORM_DESKTOP)
#define PLATFORM_DESKTOP_GLFW
#endif
// Include platform-specific submodules
#if defined(PLATFORM_DESKTOP_GLFW)
#include "platforms/rcore_desktop_glfw.c"
@ -1293,7 +1293,7 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
return shader;
}
// Check if a shader is valid (loaded on GPU)
// Check if shader is valid (loaded on GPU)
bool IsShaderValid(Shader shader)
{
return ((shader.id > 0) && // Validate shader id (GPU loaded successfully)
@ -2205,13 +2205,12 @@ void SetSaveFileTextCallback(SaveFileTextCallback callback)
// NOTE: Only rename file name required, not full path
int FileRename(const char *fileName, const char *fileRename)
{
int result = 0;
int result = -1;
if (FileExists(fileName))
{
result = rename(fileName, fileRename);
}
else result = -1;
return result;
}
@ -2219,13 +2218,12 @@ int FileRename(const char *fileName, const char *fileRename)
// Remove file (if exists)
int FileRemove(const char *fileName)
{
int result = 0;
int result = -1;
if (FileExists(fileName))
{
result = remove(fileName);
}
else result = -1;
return result;
}
@ -2234,7 +2232,7 @@ int FileRemove(const char *fileName)
// NOTE: If destination path does not exist, it is created!
int FileCopy(const char *srcPath, const char *dstPath)
{
int result = 0;
int result = -1;
int srcDataSize = 0;
unsigned char *srcFileData = LoadFileData(srcPath, &srcDataSize);
@ -2245,7 +2243,10 @@ int FileCopy(const char *srcPath, const char *dstPath)
if (result == 0) // Directory created successfully (or already exists)
{
if ((srcFileData != NULL) && (srcDataSize > 0))
result = SaveFileData(dstPath, srcFileData, srcDataSize);
{
bool saved = SaveFileData(dstPath, srcFileData, srcDataSize);
if (saved) result = 0;
}
}
UnloadFileData(srcFileData);
@ -2261,11 +2262,18 @@ int FileMove(const char *srcPath, const char *dstPath)
if (FileExists(srcPath))
{
FileCopy(srcPath, dstPath);
// Make sure file has been correctly copied before removing
if (FileExists(dstPath) && (GetFileLength(srcPath) == GetFileLength(dstPath))) result = FileRemove(srcPath);
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to copy file to [%s]", srcPath, dstPath);
result = FileCopy(srcPath, dstPath);
if (result == 0)
{
// Make sure file has been correctly copied before removing
if (FileExists(dstPath) && (GetFileLength(srcPath) == GetFileLength(dstPath)))
{
result = FileRemove(srcPath);
if (result != 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to remove source file after copy", srcPath);
}
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to copy file to [%s]", srcPath, dstPath);
}
}
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Source file does not exist", srcPath);
@ -2276,16 +2284,18 @@ int FileMove(const char *srcPath, const char *dstPath)
// WARNING: DEPENDENCY: [rtext] module
int FileTextReplace(const char *fileName, const char *search, const char *replacement)
{
int result = 0;
int result = -1;
#if SUPPORT_MODULE_RTEXT
char *fileText = NULL;
char *fileTextUpdated = { 0 };
#if SUPPORT_MODULE_RTEXT
if (FileExists(fileName))
{
fileText = LoadFileText(fileName);
fileTextUpdated = TextReplaceAlloc(fileText, search, replacement);
result = SaveFileText(fileName, fileTextUpdated);
bool saved = SaveFileText(fileName, fileTextUpdated);
if (saved) result = 0;
MemFree(fileTextUpdated);
UnloadFileText(fileText);
}
@ -2318,7 +2328,7 @@ bool FileExists(const char *fileName)
{
bool result = false;
if (ACCESS(fileName) != -1) result = true;
if ((fileName != NULL) && (ACCESS(fileName) != -1)) result = true;
// NOTE: Alternatively, stat() can be used instead of access()
//#include <sys/stat.h>
@ -2395,7 +2405,7 @@ bool IsFileExtension(const char *fileName, const char *ext)
return result;
}
// Check if a directory path exists
// Check if directory path exists
bool DirectoryExists(const char *dirPath)
{
bool result = false;
@ -2800,17 +2810,19 @@ int MakeDirectory(const char *dirPath)
}
// Change working directory, returns true on success
bool ChangeDirectory(const char *dirPath)
int ChangeDirectory(const char *dirPath)
{
bool result = CHDIR(dirPath);
// NOTE: On success, CHDIR() return 0; on error, returns -1 and errno is set to indicate the error,
// depending on the filesystem, other errors can be returned
int result = CHDIR(dirPath);
if (result != 0) TRACELOG(LOG_WARNING, "SYSTEM: Failed to change to directory: %s", dirPath);
else TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", dirPath);
return (result == 0);
return result;
}
// Check if a given path point to a file
// Check if given path point to a file
bool IsPathFile(const char *path)
{
struct stat result = { 0 };
@ -2875,7 +2887,7 @@ bool IsFileNameValid(const char *fileName)
return valid;
}
// Check if a file has been dropped into window
// Check if file has been dropped into window
bool IsFileDropped(void)
{
bool result = false;
@ -3786,7 +3798,7 @@ void PlayAutomationEvent(AutomationEvent event)
// Module Functions Definition: Input Handling: Keyboard
//----------------------------------------------------------------------------------
// Check if a key has been pressed once
// Check if key has been pressed once
bool IsKeyPressed(int key)
{
bool pressed = false;
@ -3799,7 +3811,7 @@ bool IsKeyPressed(int key)
return pressed;
}
// Check if a key has been pressed again
// Check if key has been pressed again
bool IsKeyPressedRepeat(int key)
{
bool repeat = false;
@ -3812,7 +3824,7 @@ bool IsKeyPressedRepeat(int key)
return repeat;
}
// Check if a key is being pressed (key held down)
// Check if key is being pressed (key held down)
bool IsKeyDown(int key)
{
bool down = false;
@ -3825,7 +3837,7 @@ bool IsKeyDown(int key)
return down;
}
// Check if a key has been released once
// Check if key has been released once
bool IsKeyReleased(int key)
{
bool released = false;
@ -3838,7 +3850,7 @@ bool IsKeyReleased(int key)
return released;
}
// Check if a key is NOT being pressed (key not held down)
// Check if key is NOT being pressed (key not held down)
bool IsKeyUp(int key)
{
bool up = false;
@ -3909,7 +3921,7 @@ void SetExitKey(int key)
// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
//int SetGamepadMappings(const char *mappings)
// Check if a gamepad is available
// Check if gamepad is available
bool IsGamepadAvailable(int gamepad)
{
bool result = false;
@ -3925,7 +3937,7 @@ const char *GetGamepadName(int gamepad)
return CORE.Input.Gamepad.name[gamepad];
}
// Check if a gamepad button has been pressed once
// Check if gamepad button has been pressed once
bool IsGamepadButtonPressed(int gamepad, int button)
{
bool pressed = false;
@ -3938,7 +3950,7 @@ bool IsGamepadButtonPressed(int gamepad, int button)
return pressed;
}
// Check if a gamepad button is being pressed
// Check if gamepad button is being pressed
bool IsGamepadButtonDown(int gamepad, int button)
{
bool down = false;
@ -3951,7 +3963,7 @@ bool IsGamepadButtonDown(int gamepad, int button)
return down;
}
// Check if a gamepad button has NOT been pressed once
// Check if gamepad button has NOT been pressed once
bool IsGamepadButtonReleased(int gamepad, int button)
{
bool released = false;
@ -3964,7 +3976,7 @@ bool IsGamepadButtonReleased(int gamepad, int button)
return released;
}
// Check if a gamepad button is NOT being pressed
// Check if gamepad button is NOT being pressed
bool IsGamepadButtonUp(int gamepad, int button)
{
bool up = false;
@ -4013,7 +4025,7 @@ float GetGamepadAxisMovement(int gamepad, int axis)
//void SetMousePosition(int x, int y)
//void SetMouseCursor(int cursor)
// Check if a mouse button has been pressed once
// Check if mouse button has been pressed once
bool IsMouseButtonPressed(int button)
{
bool pressed = false;
@ -4029,7 +4041,7 @@ bool IsMouseButtonPressed(int button)
return pressed;
}
// Check if a mouse button is being pressed
// Check if mouse button is being pressed
bool IsMouseButtonDown(int button)
{
bool down = false;
@ -4045,7 +4057,7 @@ bool IsMouseButtonDown(int button)
return down;
}
// Check if a mouse button has been released once
// Check if mouse button has been released once
bool IsMouseButtonReleased(int button)
{
bool released = false;
@ -4061,7 +4073,7 @@ bool IsMouseButtonReleased(int button)
return released;
}
// Check if a mouse button is NOT being pressed
// Check if mouse button is NOT being pressed
bool IsMouseButtonUp(int button)
{
bool up = false;

View file

@ -127,7 +127,7 @@ void UpdateGestures(void); // Update gestures detec
#if defined(RGESTURES_STANDALONE)
void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags
bool IsGestureDetected(int gesture); // Check if a gesture has been detected
bool IsGestureDetected(int gesture); // Check if gesture has been detected
int GetGestureDetected(void); // Get latest detected gesture
float GetGestureHoldDuration(void); // Get gesture hold time in seconds
@ -257,7 +257,7 @@ void SetGesturesEnabled(unsigned int flags)
GESTURES.enabledFlags = flags;
}
// Check if a gesture have been detected
// Check if gesture have been detected
bool IsGestureDetected(unsigned int gesture)
{
if ((GESTURES.enabledFlags & GESTURES.current) == gesture) return true;

View file

@ -897,7 +897,7 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
// It seems OpenGL ES 2.0 instancing entry points are not defined on Raspberry Pi
// provided headers (despite being defined in official Khronos GLES2 headers)
// TODO: Avoid raylib platform-dependent code on rlgl, it should be a completely portable library
#if defined(PLATFORM_DRM)
#if defined(PLATFORM_DRM) // Use CONFIG_DRM?
typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount);
typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISOREXTPROC) (GLuint index, GLuint divisor);

View file

@ -1162,7 +1162,7 @@ Model LoadModelFromMesh(Mesh mesh)
return model;
}
// Check if a model is valid (loaded in GPU, VAO/VBOs)
// Check if model is valid (loaded in GPU, VAO/VBOs)
bool IsModelValid(Model model)
{
bool result = false;
@ -2223,7 +2223,7 @@ Material LoadMaterialDefault(void)
return material;
}
// Check if a material is valid (map textures loaded in GPU)
// Check if material is valid (map textures loaded in GPU)
bool IsMaterialValid(Material material)
{
bool result = false;
@ -3978,22 +3978,22 @@ void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float
// Draw a billboard
void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint)
{
Rectangle source = { 0.0f, 0.0f, (float)texture.width, (float)texture.height };
Rectangle rec = { 0.0f, 0.0f, (float)texture.width, (float)texture.height };
DrawBillboardRec(camera, texture, source, position, (Vector2){ scale*fabsf((float)source.width/source.height), scale }, tint);
DrawBillboardRec(camera, texture, rec, position, (Vector2){ scale*fabsf((float)rec.width/rec.height), scale }, tint);
}
// Draw a billboard (part of a texture defined by a rectangle)
void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint)
void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle rec, Vector3 position, Vector2 size, Color tint)
{
// NOTE: Billboard locked on axis-Y
Vector3 up = { 0.0f, 1.0f, 0.0f };
DrawBillboardPro(camera, texture, source, position, up, size, Vector2Scale(size, 0.5), 0.0f, tint);
DrawBillboardPro(camera, texture, rec, position, up, size, Vector2Scale(size, 0.5), 0.0f, tint);
}
// Draw a billboard with additional parameters
void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint)
// Draw a billboard texture defined by source rectangle with scaling and rotation
void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle rec, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint)
{
// Compute the up vector and the right vector
Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
@ -4004,20 +4004,20 @@ void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector
// Flip the content of the billboard while maintaining the counterclockwise edge rendering order
if (size.x < 0.0f)
{
source.x -= size.x;
source.width *= -1.0;
rec.x -= size.x;
rec.width *= -1.0;
right = Vector3Negate(right);
origin.x *= -1.0f;
}
if (size.y < 0.0f)
{
source.y -= size.y;
source.height *= -1.0;
rec.y -= size.y;
rec.height *= -1.0;
up = Vector3Negate(up);
origin.y *= -1.0f;
}
// Draw the texture region described by source on the following rectangle in 3D space:
// Draw the texture region described by rec on the following rectangle in 3D space:
//
// size.x <--.
// 3 ^---------------------------+ 2 \ rotation
@ -4049,10 +4049,10 @@ void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector
}
Vector2 texcoords[4];
texcoords[0] = (Vector2){ (float)source.x/texture.width, (float)(source.y + source.height)/texture.height };
texcoords[1] = (Vector2){ (float)(source.x + source.width)/texture.width, (float)(source.y + source.height)/texture.height };
texcoords[2] = (Vector2){ (float)(source.x + source.width)/texture.width, (float)source.y/texture.height };
texcoords[3] = (Vector2){ (float)source.x/texture.width, (float)source.y/texture.height };
texcoords[0] = (Vector2){ (float)rec.x/texture.width, (float)(rec.y + rec.height)/texture.height };
texcoords[1] = (Vector2){ (float)(rec.x + rec.width)/texture.width, (float)(rec.y + rec.height)/texture.height };
texcoords[2] = (Vector2){ (float)(rec.x + rec.width)/texture.width, (float)rec.y/texture.height };
texcoords[3] = (Vector2){ (float)rec.x/texture.width, (float)rec.y/texture.height };
rlSetTexture(texture.id);
rlBegin(RL_QUADS);
@ -5370,16 +5370,18 @@ static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, int *boneCount)
cgltf_node node = *skin.joints[i];
if (node.name != NULL) strncpy(bones[i].name, node.name, sizeof(bones[i].name) - 1);
// Find parent bone index
// Find parent bone index by walking up the node tree past any
// non-joint ancestors (intermediate transform nodes used by some
// DCC exporters), until we hit a node that is also in skin.joints.
int parentIndex = -1;
for (unsigned int j = 0; j < skin.joints_count; j++)
cgltf_node *ancestor = node.parent;
while (ancestor != NULL && parentIndex == -1)
{
if (skin.joints[j] == node.parent)
for (unsigned int j = 0; j < skin.joints_count; j++)
{
parentIndex = (int)j;
break;
if (skin.joints[j] == ancestor) { parentIndex = (int)j; break; }
}
if (parentIndex == -1) ancestor = ancestor->parent;
}
bones[i].parent = parentIndex;
@ -6510,20 +6512,58 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
if (data->skins_count > 0)
{
cgltf_skin skin = data->skins[0];
// Precompute, per joint, the static transform contributed by any
// intermediate non-joint nodes between the joint and its nearest
// joint ancestor. This handles exporters (e.g. wow.export) that
// store bone offsets on dummy parent nodes rather than on the
// joints themselves. Depends only on the skin, not the animation.
int jointCount = (int)skin.joints_count;
Matrix *extOffset = (Matrix *)RL_MALLOC(jointCount*sizeof(Matrix));
if (extOffset == NULL)
{
// Allocation failed: abort animation loading at the source rather than
// propagating a NULL pointer into the per-frame transform loop below
TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to allocate joint offset buffer", fileName);
cgltf_free(data);
UnloadFileData(fileData);
*animCount = 0;
return NULL;
}
*animCount = (int)data->animations_count;
animations = (ModelAnimation *)RL_CALLOC(data->animations_count, sizeof(ModelAnimation));
Transform worldTransform = { 0 };
cgltf_float cgltf_worldTransform[16] = { 0 };
cgltf_node *node = skin.joints[0];
cgltf_node_transform_world(node->parent, cgltf_worldTransform);
Matrix worldMatrix = {
cgltf_worldTransform[0], cgltf_worldTransform[4], cgltf_worldTransform[8], cgltf_worldTransform[12],
cgltf_worldTransform[1], cgltf_worldTransform[5], cgltf_worldTransform[9], cgltf_worldTransform[13],
cgltf_worldTransform[2], cgltf_worldTransform[6], cgltf_worldTransform[10], cgltf_worldTransform[14],
cgltf_worldTransform[3], cgltf_worldTransform[7], cgltf_worldTransform[11], cgltf_worldTransform[15]
};
MatrixDecompose(worldMatrix, &worldTransform.translation, &worldTransform.rotation, &worldTransform.scale);
for (int k = 0; k < jointCount; k++)
{
extOffset[k] = MatrixIdentity();
cgltf_node *n = skin.joints[k]->parent;
while (n != NULL)
{
bool isJoint = false;
for (int jj = 0; jj < jointCount; jj++)
{
if (skin.joints[jj] == n)
{
isJoint = true;
break;
}
}
if (isJoint) break;
// Compose the intermediate node's local TRS (scale, then rotation, then translation)
Matrix nodeScale = MatrixScale(n->scale[0], n->scale[1], n->scale[2]);
Matrix nodeRotation = QuaternionToMatrix((Quaternion){ n->rotation[0], n->rotation[1], n->rotation[2], n->rotation[3] });
Matrix nodeTranslation = MatrixTranslate(n->translation[0], n->translation[1], n->translation[2]);
Matrix nodeTransform = MatrixMultiply(MatrixMultiply(nodeScale, nodeRotation), nodeTranslation);
extOffset[k] = MatrixMultiply(extOffset[k], nodeTransform);
n = n->parent;
}
}
for (unsigned int a = 0; a < data->animations_count; a++)
{
@ -6632,19 +6672,19 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
}
}
animations[a].keyframePoses[j][k] = (Transform){
.translation = translation,
.rotation = rotation,
.scale = scale
};
}
// Compose joint local TRS, then prepend the static
// intermediate non-joint offsets so the final TRS is
// expressed relative to the joint's skeleton parent.
Matrix S = MatrixScale(scale.x, scale.y, scale.z);
Matrix R = QuaternionToMatrix(rotation);
Matrix T = MatrixTranslate(translation.x, translation.y, translation.z);
Matrix jointLocal = MatrixMultiply(MatrixMultiply(S, R), T);
Matrix combined = MatrixMultiply(jointLocal, extOffset[k]);
Transform *root = &animations[a].keyframePoses[j][0];
root->rotation = QuaternionMultiply(worldTransform.rotation, root->rotation);
root->scale = Vector3Multiply(root->scale, worldTransform.scale);
root->translation = Vector3Multiply(root->translation, worldTransform.scale);
root->translation = Vector3RotateByQuaternion(root->translation, worldTransform.rotation);
root->translation = Vector3Add(root->translation, worldTransform.translation);
Transform tr;
MatrixDecompose(combined, &tr.translation, &tr.rotation, &tr.scale);
animations[a].keyframePoses[j][k] = tr;
}
BuildPoseFromParentJoints(bones, animations[a].boneCount, animations[a].keyframePoses[j]);
}
@ -6653,6 +6693,8 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
RL_FREE(boneChannels);
RL_FREE(bones);
}
RL_FREE(extOffset);
}
if (data->skins_count > 1)

View file

@ -90,12 +90,12 @@ static float EaseCubicInOut(float t, float b, float c, float d); // Cubic eas
// Set texture and rectangle to be used on shapes drawing
// NOTE: It can be useful when using basic shapes and one single font,
// defining a font char white rectangle would allow drawing everything in a single draw call
void SetShapesTexture(Texture2D texture, Rectangle source)
void SetShapesTexture(Texture2D texture, Rectangle rec)
{
// Reset texture to default pixel if required
// WARNING: Shapes texture should be probably better validated,
// it can break the rendering of all shapes if misused
if ((texture.id == 0) || (source.width == 0) || (source.height == 0))
if ((texture.id == 0) || (rec.width == 0) || (rec.height == 0))
{
texShapes = (Texture2D){ 1, 1, 1, 1, 7 };
texShapesRec = (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f };
@ -103,7 +103,7 @@ void SetShapesTexture(Texture2D texture, Rectangle source)
else
{
texShapes = texture;
texShapesRec = source;
texShapesRec = rec;
}
}
@ -326,7 +326,7 @@ void DrawCircleSector(Vector2 center, float radius, float startAngle, float endA
{
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
segments = (int)ceilf((endAngle - startAngle)*(2*PI/th)/360.0f);
if (segments <= 0) segments = minSegments;
}
@ -418,7 +418,7 @@ void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float
{
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
segments = (int)ceilf((endAngle - startAngle)*(2*PI/th)/360.0f);
if (segments <= 0) segments = minSegments;
}
@ -544,7 +544,7 @@ void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startA
{
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
segments = (int)ceilf((endAngle - startAngle)*(2*PI/th)/360.0f);
if (segments <= 0) segments = minSegments;
}
@ -635,7 +635,7 @@ void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float s
{
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
segments = (int)ceilf((endAngle - startAngle)*(2*PI/th)/360.0f);
if (segments <= 0) segments = minSegments;
}
@ -925,7 +925,7 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
{
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
segments = (int)(ceilf(2*PI/th)/4.0f);
segments = (int)ceilf((2*PI/th)/4.0f);
if (segments <= 0) segments = 4;
}
@ -1160,7 +1160,7 @@ void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, f
{
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
segments = (int)(ceilf(2*PI/th)/2.0f);
segments = (int)ceilf((2*PI/th)/4.0f);
if (segments <= 0) segments = 4;
}

View file

@ -580,15 +580,20 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int
TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount);
}
else font = GetFontDefault();
else
{
TRACELOG(LOG_WARNING, "FONT: Font is not supported by LoadFontEx/LoadFontFromMemory or no glyphs found, reverted to default font");
font = GetFontDefault();
}
#else
TRACELOG(LOG_WARNING, "FONT: Font is not supported by LoadFontEx/LoadFontFromMemory or no glyphs found, reverted to default font");
font = GetFontDefault();
#endif
return font;
}
// Check if a font is valid (font data loaded)
// Check if font is valid (font data loaded)
// WARNING: GPU texture not checked
bool IsFontValid(Font font)
{
@ -678,7 +683,7 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be
// stbtt_MakeCodepointBitmap() -- renders into a provided bitmap
// Check if a glyph is available in the font
// Check if glyph is available in the font
// WARNING: if (index == 0), glyph not found, it could fallback to default .notdef glyph (if defined in font)
int index = stbtt_FindGlyphIndex(&fontInfo, cp);
@ -2667,8 +2672,8 @@ static Font LoadBMFont(const char *fileName)
for (int i = 1; i < pageCount; i++)
{
Rectangle srcRec = { 0.0f, 0.0f, (float)imWidth, (float)imHeight };
Rectangle destRec = { 0.0f, (float)imHeight*(float)i, (float)imWidth, (float)imHeight };
ImageDraw(&fullFont, imFonts[i], srcRec, destRec, WHITE);
Rectangle dstRec = { 0.0f, (float)imHeight*(float)i, (float)imWidth, (float)imHeight };
ImageDraw(&fullFont, imFonts[i], srcRec, dstRec, WHITE);
}
}

View file

@ -1744,7 +1744,7 @@ void ImageResize(Image *image, int newWidth, int newHeight)
// Security check to avoid program crash
if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
// Check if a fast path can be used on image scaling
// Check if fast path can be used on image scaling
// It can be for 8 bit per channel images with 1 to 4 channels per pixel
if ((image->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) ||
(image->format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) ||
@ -3506,7 +3506,7 @@ void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int en
}
// Initialize variables for drawing loop
int endVal = longLen;
int endVal = longLen + 1;
int sgnInc = 1;
// Adjust direction increment based on longLen sign
@ -3514,6 +3514,7 @@ void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int en
{
longLen = -longLen;
sgnInc = -1;
endVal -= 2;
}
// Calculate fixed-point increment for shorter length
@ -3523,7 +3524,8 @@ void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int en
if (yLonger)
{
// If line is more vertical, iterate over y-axis
for (int i = 0, j = 0; i != endVal; i += sgnInc, j += decInc)
// Init j with 0.5 in 16-bit fixed point (1 << 15) for better rounding.
for (int i = 0, j = (1 << 15); i != endVal; i += sgnInc, j += decInc)
{
// Calculate pixel position and draw it
ImageDrawPixel(dst, startPosX + (j >> 16), startPosY + i, color);
@ -3532,7 +3534,7 @@ void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int en
else
{
// If line is more horizontal, iterate over x-axis
for (int i = 0, j = 0; i != endVal; i += sgnInc, j += decInc)
for (int i = 0, j = (1 << 15); i != endVal; i += sgnInc, j += decInc)
{
// Calculate pixel position and draw it
ImageDrawPixel(dst, startPosX + i, startPosY + (j >> 16), color);
@ -4293,7 +4295,7 @@ RenderTexture2D LoadRenderTexture(int width, int height)
return target;
}
// Check if a texture is valid (loaded in GPU)
// Check if texture is valid (loaded in GPU)
bool IsTextureValid(Texture2D texture)
{
bool result = false;
@ -4318,7 +4320,7 @@ void UnloadTexture(Texture2D texture)
}
}
// Check if a render texture is valid (loaded in GPU)
// Check if render texture is valid (loaded in GPU)
bool IsRenderTextureValid(RenderTexture2D target)
{
bool result = false;
@ -4489,25 +4491,25 @@ void DrawTextureV(Texture2D texture, Vector2 position, Color tint)
// Draw a texture with extended parameters
void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint)
{
Rectangle source = { 0.0f, 0.0f, (float)texture.width, (float)texture.height };
Rectangle dest = { position.x, position.y, (float)texture.width*scale, (float)texture.height*scale };
Rectangle srcrec = { 0.0f, 0.0f, (float)texture.width, (float)texture.height };
Rectangle dstrec = { position.x, position.y, (float)texture.width*scale, (float)texture.height*scale };
Vector2 origin = { 0.0f, 0.0f };
DrawTexturePro(texture, source, dest, origin, rotation, tint);
DrawTexturePro(texture, srcrec, dstrec, origin, rotation, tint);
}
// Draw a part of a texture (defined by a rectangle)
void DrawTextureRec(Texture2D texture, Rectangle source, Vector2 position, Color tint)
void DrawTextureRec(Texture2D texture, Rectangle rec, Vector2 position, Color tint)
{
Rectangle dest = { position.x, position.y, fabsf(source.width), fabsf(source.height) };
Rectangle dstrec = { position.x, position.y, fabsf(rec.width), fabsf(rec.height) };
Vector2 origin = { 0.0f, 0.0f };
DrawTexturePro(texture, source, dest, origin, 0.0f, tint);
DrawTexturePro(texture, rec, dstrec, origin, 0.0f, tint);
}
// Draw a part of a texture (defined by a rectangle) with 'pro' parameters
// NOTE: origin is relative to destination rectangle size
void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint)
void DrawTexturePro(Texture2D texture, Rectangle srcrec, Rectangle dstrec, Vector2 origin, float rotation, Color tint)
{
// Check if texture is valid
if (texture.id > 0)
@ -4517,11 +4519,11 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2
bool flipX = false;
if (source.width < 0) { flipX = true; source.width *= -1; }
if (source.height < 0) source.y -= source.height;
if (srcrec.width < 0) { flipX = true; srcrec.width *= -1; }
if (srcrec.height < 0) srcrec.y -= srcrec.height;
if (dest.width < 0) dest.width *= -1;
if (dest.height < 0) dest.height *= -1;
if (dstrec.width < 0) dstrec.width *= -1;
if (dstrec.height < 0) dstrec.height *= -1;
Vector2 topLeft = { 0 };
Vector2 topRight = { 0 };
@ -4531,33 +4533,33 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2
// Only calculate rotation if needed
if (rotation == 0.0f)
{
float x = dest.x - origin.x;
float y = dest.y - origin.y;
float x = dstrec.x - origin.x;
float y = dstrec.y - origin.y;
topLeft = (Vector2){ x, y };
topRight = (Vector2){ x + dest.width, y };
bottomLeft = (Vector2){ x, y + dest.height };
bottomRight = (Vector2){ x + dest.width, y + dest.height };
topRight = (Vector2){ x + dstrec.width, y };
bottomLeft = (Vector2){ x, y + dstrec.height };
bottomRight = (Vector2){ x + dstrec.width, y + dstrec.height };
}
else
{
float sinRotation = sinf(rotation*DEG2RAD);
float cosRotation = cosf(rotation*DEG2RAD);
float x = dest.x;
float y = dest.y;
float x = dstrec.x;
float y = dstrec.y;
float dx = -origin.x;
float dy = -origin.y;
topLeft.x = x + dx*cosRotation - dy*sinRotation;
topLeft.y = y + dx*sinRotation + dy*cosRotation;
topRight.x = x + (dx + dest.width)*cosRotation - dy*sinRotation;
topRight.y = y + (dx + dest.width)*sinRotation + dy*cosRotation;
topRight.x = x + (dx + dstrec.width)*cosRotation - dy*sinRotation;
topRight.y = y + (dx + dstrec.width)*sinRotation + dy*cosRotation;
bottomLeft.x = x + dx*cosRotation - (dy + dest.height)*sinRotation;
bottomLeft.y = y + dx*sinRotation + (dy + dest.height)*cosRotation;
bottomLeft.x = x + dx*cosRotation - (dy + dstrec.height)*sinRotation;
bottomLeft.y = y + dx*sinRotation + (dy + dstrec.height)*cosRotation;
bottomRight.x = x + (dx + dest.width)*cosRotation - (dy + dest.height)*sinRotation;
bottomRight.y = y + (dx + dest.width)*sinRotation + (dy + dest.height)*cosRotation;
bottomRight.x = x + (dx + dstrec.width)*cosRotation - (dy + dstrec.height)*sinRotation;
bottomRight.y = y + (dx + dstrec.width)*sinRotation + (dy + dstrec.height)*cosRotation;
}
rlSetTexture(texture.id);
@ -4567,23 +4569,23 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer
// Top-left corner for texture and quad
if (flipX) rlTexCoord2f((source.x + source.width)/width, source.y/height);
else rlTexCoord2f(source.x/width, source.y/height);
if (flipX) rlTexCoord2f((srcrec.x + srcrec.width)/width, srcrec.y/height);
else rlTexCoord2f(srcrec.x/width, srcrec.y/height);
rlVertex2f(topLeft.x, topLeft.y);
// Bottom-left corner for texture and quad
if (flipX) rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height);
else rlTexCoord2f(source.x/width, (source.y + source.height)/height);
if (flipX) rlTexCoord2f((srcrec.x + srcrec.width)/width, (srcrec.y + srcrec.height)/height);
else rlTexCoord2f(srcrec.x/width, (srcrec.y + srcrec.height)/height);
rlVertex2f(bottomLeft.x, bottomLeft.y);
// Bottom-right corner for texture and quad
if (flipX) rlTexCoord2f(source.x/width, (source.y + source.height)/height);
else rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height);
if (flipX) rlTexCoord2f(srcrec.x/width, (srcrec.y + srcrec.height)/height);
else rlTexCoord2f((srcrec.x + srcrec.width)/width, (srcrec.y + srcrec.height)/height);
rlVertex2f(bottomRight.x, bottomRight.y);
// Top-right corner for texture and quad
if (flipX) rlTexCoord2f(source.x/width, source.y/height);
else rlTexCoord2f((source.x + source.width)/width, source.y/height);
if (flipX) rlTexCoord2f(srcrec.x/width, srcrec.y/height);
else rlTexCoord2f((srcrec.x + srcrec.width)/width, srcrec.y/height);
rlVertex2f(topRight.x, topRight.y);
rlEnd();
@ -4597,7 +4599,7 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2
/*
rlSetTexture(texture.id);
rlPushMatrix();
rlTranslatef(dest.x, dest.y, 0.0f);
rlTranslatef(dstrec.x, dstrec.y, 0.0f);
if (rotation != 0.0f) rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
rlTranslatef(-origin.x, -origin.y, 0.0f);
@ -4606,24 +4608,24 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer
// Bottom-left corner for texture and quad
if (flipX) rlTexCoord2f((source.x + source.width)/width, source.y/height);
else rlTexCoord2f(source.x/width, source.y/height);
if (flipX) rlTexCoord2f((srcrec.x + srcrec.width)/width, srcrec.y/height);
else rlTexCoord2f(srcrec.x/width, srcrec.y/height);
rlVertex2f(0.0f, 0.0f);
// Bottom-right corner for texture and quad
if (flipX) rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height);
else rlTexCoord2f(source.x/width, (source.y + source.height)/height);
rlVertex2f(0.0f, dest.height);
if (flipX) rlTexCoord2f((srcrec.x + srcrec.width)/width, (srcrec.y + srcrec.height)/height);
else rlTexCoord2f(srcrec.x/width, (srcrec.y + srcrec.height)/height);
rlVertex2f(0.0f, dstrec.height);
// Top-right corner for texture and quad
if (flipX) rlTexCoord2f(source.x/width, (source.y + source.height)/height);
else rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height);
rlVertex2f(dest.width, dest.height);
if (flipX) rlTexCoord2f(srcrec.x/width, (srcrec.y + srcrec.height)/height);
else rlTexCoord2f((srcrec.x + srcrec.width)/width, (srcrec.y + srcrec.height)/height);
rlVertex2f(dstrec.width, dstrec.height);
// Top-left corner for texture and quad
if (flipX) rlTexCoord2f(source.x/width, source.y/height);
else rlTexCoord2f((source.x + source.width)/width, source.y/height);
rlVertex2f(dest.width, 0.0f);
if (flipX) rlTexCoord2f(srcrec.x/width, srcrec.y/height);
else rlTexCoord2f((srcrec.x + srcrec.width)/width, srcrec.y/height);
rlVertex2f(dstrec.width, 0.0f);
rlEnd();
rlPopMatrix();
rlSetTexture(0);
@ -4632,15 +4634,15 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2
}
// Draw a texture (or part of it) that stretches or shrinks nicely using n-patch info
void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint)
void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dstrec, Vector2 origin, float rotation, Color tint)
{
if (texture.id > 0)
{
float width = (float)texture.width;
float height = (float)texture.height;
float patchWidth = ((int)dest.width <= 0)? 0.0f : dest.width;
float patchHeight = ((int)dest.height <= 0)? 0.0f : dest.height;
float patchWidth = ((int)dstrec.width <= 0)? 0.0f : dstrec.width;
float patchHeight = ((int)dstrec.height <= 0)? 0.0f : dstrec.height;
if (nPatchInfo.source.width < 0) nPatchInfo.source.x -= nPatchInfo.source.width;
if (nPatchInfo.source.height < 0) nPatchInfo.source.y -= nPatchInfo.source.height;
@ -4699,7 +4701,7 @@ void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest,
rlSetTexture(texture.id);
rlPushMatrix();
rlTranslatef(dest.x, dest.y, 0.0f);
rlTranslatef(dstrec.x, dstrec.y, 0.0f);
rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
rlTranslatef(-origin.x, -origin.y, 0.0f);
@ -5178,7 +5180,7 @@ Color GetColor(unsigned int hexValue)
}
// Get color from a pixel from certain format
Color GetPixelColor(void *srcPtr, int format)
Color GetPixelColor(const void *srcPtr, int format)
{
Color color = { 0 };