Merge branch 'master' into more-spline-functions

This commit is contained in:
Ray 2025-07-30 11:43:02 +02:00 • committed by GitHub
commit b80920b1ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 20425 additions and 18426 deletions

View file

@ -8,7 +8,7 @@ include(JoinPaths)
# Sets build type if not set by now
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
if(RAYLIB_IS_MAIN)
if(PROJECT_IS_TOP_LEVEL)
set(default_build_type Debug)
else()
message(WARNING "Default build type is not set (CMAKE_BUILD_TYPE)")

View file

@ -638,7 +638,7 @@ OBJS = rcore.o \
rshapes.o \
rtextures.o \
rtext.o \
utils.o
utils.o
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
ifeq ($(USE_EXTERNAL_GLFW),FALSE)
@ -868,7 +868,7 @@ clean: clean_shell_$(PLATFORM_SHELL)
@echo "removed all generated files!"
clean_shell_sh:
rm -fv *.o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).a $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).bc $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).so* raygui.c $(RAYLIB_RELEASE_PATH)/*-protocol.h $(RAYLIB_RELEASE_PATH)/*-protocol-code.h
rm -fv *.o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).a $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).web.a $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).so* raygui.c $(RAYLIB_RELEASE_PATH)/*-protocol.h $(RAYLIB_RELEASE_PATH)/*-protocol-code.h
ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
rm -fv $(NATIVE_APP_GLUE)/android_native_app_glue.o
endif
@ -879,6 +879,7 @@ clean_shell_cmd:
del *.o /s
cd $(RAYLIB_RELEASE_PATH) & \
del lib$(RAYLIB_LIB_NAME).a /s & \
del lib$(RAYLIB_LIB_NAME).web.a /s & \
del lib$(RAYLIB_LIB_NAME)dll.a /s & \
del $(RAYLIB_LIB_NAME).dll /s & \
del raygui.c /s & \

View file

@ -104,7 +104,7 @@
#define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported
#define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported
#define MAX_GAMEPADS 4 // Maximum number of gamepads supported
#define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad)
#define MAX_GAMEPAD_AXES 8 // Maximum number of axes supported (per gamepad)
#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
#define MAX_GAMEPAD_VIBRATION_TIME 2.0f // Maximum vibration time in seconds
#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
@ -136,8 +136,8 @@
#define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported
#define RL_CULL_DISTANCE_NEAR 0.01 // Default projection matrix near cull distance
#define RL_CULL_DISTANCE_FAR 1000.0 // Default projection matrix far cull distance
#define RL_CULL_DISTANCE_NEAR 0.001 // Default projection matrix near cull distance
#define RL_CULL_DISTANCE_FAR 10000.0 // Default projection matrix far cull distance
// Default shader vertex attribute locations
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0
@ -189,7 +189,7 @@
//------------------------------------------------------------------------------------
// Module: rtextures - Configuration Flags
//------------------------------------------------------------------------------------
// Selecte desired fileformats to be supported for image data loading
// Selected desired fileformats to be supported for image data loading
#define SUPPORT_FILEFORMAT_PNG 1
//#define SUPPORT_FILEFORMAT_BMP 1
//#define SUPPORT_FILEFORMAT_TGA 1

21452
src/external/RGFW.h vendored

File diff suppressed because it is too large Load diff

462
src/external/dr_flac.h vendored
View file

@ -1,121 +1,12 @@
/*
FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
dr_flac - v0.12.42 - 2023-11-02
dr_flac - v0.13.0 - TBD
David Reid - mackron@gmail.com
GitHub: https://github.com/mackron/dr_libs
*/
/*
RELEASE NOTES - v0.12.0
=======================
Version 0.12.0 has breaking API changes including changes to the existing API and the removal of deprecated APIs.
Improved Client-Defined Memory Allocation
-----------------------------------------
The main change with this release is the addition of a more flexible way of implementing custom memory allocation routines. The
existing system of DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE are still in place and will be used by default when no custom
allocation callbacks are specified.
To use the new system, you pass in a pointer to a drflac_allocation_callbacks object to drflac_open() and family, like this:
void* my_malloc(size_t sz, void* pUserData)
{
return malloc(sz);
}
void* my_realloc(void* p, size_t sz, void* pUserData)
{
return realloc(p, sz);
}
void my_free(void* p, void* pUserData)
{
free(p);
}
...
drflac_allocation_callbacks allocationCallbacks;
allocationCallbacks.pUserData = &myData;
allocationCallbacks.onMalloc = my_malloc;
allocationCallbacks.onRealloc = my_realloc;
allocationCallbacks.onFree = my_free;
drflac* pFlac = drflac_open_file("my_file.flac", &allocationCallbacks);
The advantage of this new system is that it allows you to specify user data which will be passed in to the allocation routines.
Passing in null for the allocation callbacks object will cause dr_flac to use defaults which is the same as DRFLAC_MALLOC,
DRFLAC_REALLOC and DRFLAC_FREE and the equivalent of how it worked in previous versions.
Every API that opens a drflac object now takes this extra parameter. These include the following:
drflac_open()
drflac_open_relaxed()
drflac_open_with_metadata()
drflac_open_with_metadata_relaxed()
drflac_open_file()
drflac_open_file_with_metadata()
drflac_open_memory()
drflac_open_memory_with_metadata()
drflac_open_and_read_pcm_frames_s32()
drflac_open_and_read_pcm_frames_s16()
drflac_open_and_read_pcm_frames_f32()
drflac_open_file_and_read_pcm_frames_s32()
drflac_open_file_and_read_pcm_frames_s16()
drflac_open_file_and_read_pcm_frames_f32()
drflac_open_memory_and_read_pcm_frames_s32()
drflac_open_memory_and_read_pcm_frames_s16()
drflac_open_memory_and_read_pcm_frames_f32()
Optimizations
-------------
Seeking performance has been greatly improved. A new binary search based seeking algorithm has been introduced which significantly
improves performance over the brute force method which was used when no seek table was present. Seek table based seeking also takes
advantage of the new binary search seeking system to further improve performance there as well. Note that this depends on CRC which
means it will be disabled when DR_FLAC_NO_CRC is used.
The SSE4.1 pipeline has been cleaned up and optimized. You should see some improvements with decoding speed of 24-bit files in
particular. 16-bit streams should also see some improvement.
drflac_read_pcm_frames_s16() has been optimized. Previously this sat on top of drflac_read_pcm_frames_s32() and performed it's s32
to s16 conversion in a second pass. This is now all done in a single pass. This includes SSE2 and ARM NEON optimized paths.
A minor optimization has been implemented for drflac_read_pcm_frames_s32(). This will now use an SSE2 optimized pipeline for stereo
channel reconstruction which is the last part of the decoding process.
The ARM build has seen a few improvements. The CLZ (count leading zeroes) and REV (byte swap) instructions are now used when
compiling with GCC and Clang which is achieved using inline assembly. The CLZ instruction requires ARM architecture version 5 at
compile time and the REV instruction requires ARM architecture version 6.
An ARM NEON optimized pipeline has been implemented. To enable this you'll need to add -mfpu=neon to the command line when compiling.
Removed APIs
------------
The following APIs were deprecated in version 0.11.0 and have been completely removed in version 0.12.0:
drflac_read_s32() -> drflac_read_pcm_frames_s32()
drflac_read_s16() -> drflac_read_pcm_frames_s16()
drflac_read_f32() -> drflac_read_pcm_frames_f32()
drflac_seek_to_sample() -> drflac_seek_to_pcm_frame()
drflac_open_and_decode_s32() -> drflac_open_and_read_pcm_frames_s32()
drflac_open_and_decode_s16() -> drflac_open_and_read_pcm_frames_s16()
drflac_open_and_decode_f32() -> drflac_open_and_read_pcm_frames_f32()
drflac_open_and_decode_file_s32() -> drflac_open_file_and_read_pcm_frames_s32()
drflac_open_and_decode_file_s16() -> drflac_open_file_and_read_pcm_frames_s16()
drflac_open_and_decode_file_f32() -> drflac_open_file_and_read_pcm_frames_f32()
drflac_open_and_decode_memory_s32() -> drflac_open_memory_and_read_pcm_frames_s32()
drflac_open_and_decode_memory_s16() -> drflac_open_memory_and_read_pcm_frames_s16()
drflac_open_and_decode_memory_f32() -> drflac_open_memroy_and_read_pcm_frames_f32()
Prior versions of dr_flac operated on a per-sample basis whereas now it operates on PCM frames. The removed APIs all relate
to the old per-sample APIs. You now need to use the "pcm_frame" versions.
*/
/*
Introduction
============
@ -179,7 +70,7 @@ reports metadata to the application through the use of a callback, and every met
The main opening APIs (`drflac_open()`, etc.) will fail if the header is not present. The presents a problem in certain scenarios such as broadcast style
streams or internet radio where the header may not be present because the user has started playback mid-stream. To handle this, use the relaxed APIs:
`drflac_open_relaxed()`
`drflac_open_with_metadata_relaxed()`
@ -234,8 +125,8 @@ extern "C" {
#define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x)
#define DRFLAC_VERSION_MAJOR 0
#define DRFLAC_VERSION_MINOR 12
#define DRFLAC_VERSION_REVISION 42
#define DRFLAC_VERSION_MINOR 13
#define DRFLAC_VERSION_REVISION 0
#define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION)
#include <stddef.h> /* For size_t. */
@ -348,11 +239,11 @@ but also more memory. In my testing there is diminishing returns after about 4KB
#define DRFLAC_64BIT
#endif
#if defined(__x86_64__) || defined(_M_X64)
#if defined(__x86_64__) || (defined(_M_X64) && !defined(_M_ARM64EC))
#define DRFLAC_X64
#elif defined(__i386) || defined(_M_IX86)
#define DRFLAC_X86
#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64)
#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
#define DRFLAC_ARM
#endif
/* End Architecture Detection */
@ -406,8 +297,9 @@ typedef enum
typedef enum
{
drflac_seek_origin_start,
drflac_seek_origin_current
DRFLAC_SEEK_SET,
DRFLAC_SEEK_CUR,
DRFLAC_SEEK_END
} drflac_seek_origin;
/* The order of members in this structure is important because we map this directly to the raw data within the SEEKTABLE metadata block. */
@ -547,7 +439,7 @@ offset (in)
The number of bytes to move, relative to the origin. Will never be negative.
origin (in)
The origin of the seek - the current position or the start of the stream.
The origin of the seek - the current position, the start of the stream, or the end of the stream.
Return Value
@ -557,14 +449,32 @@ Whether or not the seek was successful.
Remarks
-------
The offset will never be negative. Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which will be
either drflac_seek_origin_start or drflac_seek_origin_current.
Seeking relative to the start and the current position must always be supported. If seeking from the end of the stream is not supported, return DRFLAC_FALSE.
When seeking to a PCM frame using drflac_seek_to_pcm_frame(), dr_flac may call this with an offset beyond the end of the FLAC stream. This needs to be detected
and handled by returning DRFLAC_FALSE.
*/
typedef drflac_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin);
/*
Callback for when the current position in the stream needs to be retrieved.
Parameters
----------
pUserData (in)
The user data that was passed to drflac_open() and family.
pCursor (out)
A pointer to a variable to receive the current position in the stream.
Return Value
------------
Whether or not the operation was successful.
*/
typedef drflac_bool32 (* drflac_tell_proc)(void* pUserData, drflac_int64* pCursor);
/*
Callback for when a metadata block is read.
@ -603,6 +513,9 @@ typedef struct
/* The function to call when the current read position needs to be moved. */
drflac_seek_proc onSeek;
/* The function to call when the current read position needs to be retrieved. */
drflac_tell_proc onTell;
/* The user data to pass around to onRead and onSeek. */
void* pUserData;
@ -828,7 +741,7 @@ drflac_open_memory()
drflac_open_with_metadata()
drflac_close()
*/
DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
/*
Opens a FLAC stream with relaxed validation of the header block.
@ -869,7 +782,7 @@ force your `onRead` callback to return 0, which dr_flac will use as an indicator
Use `drflac_open_with_metadata_relaxed()` if you need access to metadata.
*/
DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
/*
Opens a FLAC decoder and notifies the caller of the metadata chunks (album art, etc.).
@ -926,7 +839,7 @@ drflac_open_memory_with_metadata()
drflac_open()
drflac_close()
*/
DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
/*
The same as drflac_open_with_metadata(), except attempts to open the stream even when a header block is not present.
@ -936,7 +849,7 @@ See Also
drflac_open_with_metadata()
drflac_open_relaxed()
*/
DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
/*
Closes the given FLAC decoder.
@ -1234,13 +1147,13 @@ read samples into a dynamically sized buffer on the heap until no samples are le
Do not call this function on a broadcast type of stream (like internet radio streams and whatnot).
*/
DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
/* Same as drflac_open_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */
DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
/* Same as drflac_open_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */
DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
#ifndef DR_FLAC_NO_STDIO
/* Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a file. */
@ -2960,25 +2873,25 @@ static drflac_bool32 drflac__seek_to_byte(drflac_bs* bs, drflac_uint64 offsetFro
*/
if (offsetFromStart > 0x7FFFFFFF) {
drflac_uint64 bytesRemaining = offsetFromStart;
if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) {
if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, DRFLAC_SEEK_SET)) {
return DRFLAC_FALSE;
}
bytesRemaining -= 0x7FFFFFFF;
while (bytesRemaining > 0x7FFFFFFF) {
if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) {
if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, DRFLAC_SEEK_CUR)) {
return DRFLAC_FALSE;
}
bytesRemaining -= 0x7FFFFFFF;
}
if (bytesRemaining > 0) {
if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, drflac_seek_origin_current)) {
if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, DRFLAC_SEEK_CUR)) {
return DRFLAC_FALSE;
}
}
} else {
if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, drflac_seek_origin_start)) {
if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, DRFLAC_SEEK_SET)) {
return DRFLAC_FALSE;
}
}
@ -5393,6 +5306,12 @@ static drflac_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe
return DRFLAC_FALSE;
}
/*
Default to 0 for the LPC order. It's important that we always set this to 0 for non LPC
and FIXED subframes because we'll be using it in a generic validation check later.
*/
pSubframe->lpcOrder = 0;
type = (header & 0x7E) >> 1;
if (type == 0) {
pSubframe->subframeType = DRFLAC_SUBFRAME_CONSTANT;
@ -5465,6 +5384,18 @@ static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame,
pSubframe->pSamplesS32 = pDecodedSamplesOut;
/*
pDecodedSamplesOut will be pointing to a buffer that was allocated with enough memory to store
maxBlockSizeInPCMFrames samples (as specified in the FLAC header). We need to guard against an
overflow here. At a higher level we are checking maxBlockSizeInPCMFrames from the header, but
here we need to do an additional check to ensure this frame's block size fully encompasses any
warmup samples which is determined by the LPC order. For non LPC and FIXED subframes, the LPC
order will be have been set to 0 in drflac__read_subframe_header().
*/
if (frame->header.blockSizeInPCMFrames < pSubframe->lpcOrder) {
return DRFLAC_FALSE;
}
switch (pSubframe->subframeType)
{
case DRFLAC_SUBFRAME_CONSTANT:
@ -6312,6 +6243,7 @@ typedef struct
{
drflac_read_proc onRead;
drflac_seek_proc onSeek;
drflac_tell_proc onTell;
drflac_meta_proc onMeta;
drflac_container container;
void* pUserData;
@ -6479,7 +6411,7 @@ static void drflac__free_from_callbacks(void* p, const drflac_allocation_callbac
}
static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_uint64* pFirstFramePos, drflac_uint64* pSeektablePos, drflac_uint32* pSeekpointCount, drflac_allocation_callbacks* pAllocationCallbacks)
static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_uint64* pFirstFramePos, drflac_uint64* pSeektablePos, drflac_uint32* pSeekpointCount, drflac_allocation_callbacks* pAllocationCallbacks)
{
/*
We want to keep track of the byte position in the stream of the seektable. At the time of calling this function we know that
@ -6489,6 +6421,8 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
drflac_uint64 seektablePos = 0;
drflac_uint32 seektableSize = 0;
(void)onTell;
for (;;) {
drflac_metadata metadata;
drflac_uint8 isLastBlock = 0;
@ -6702,10 +6636,10 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
/* Skip to the index point count */
pRunningData += 35;
indexCount = pRunningData[0];
pRunningData += 1;
bufferSize += indexCount * sizeof(drflac_cuesheet_track_index);
/* Quick validation check. */
@ -6840,7 +6774,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
metadata.data.padding.unused = 0;
/* Padding doesn't have anything meaningful in it, so just skip over it, but make sure the caller is aware of it by firing the callback. */
if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
if (!onSeek(pUserData, blockSize, DRFLAC_SEEK_CUR)) {
isLastBlock = DRFLAC_TRUE; /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */
} else {
onMeta(pUserDataMD, &metadata);
@ -6852,7 +6786,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
{
/* Invalid chunk. Just skip over this one. */
if (onMeta) {
if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
if (!onSeek(pUserData, blockSize, DRFLAC_SEEK_CUR)) {
isLastBlock = DRFLAC_TRUE; /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */
}
}
@ -6886,7 +6820,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
/* If we're not handling metadata, just skip over the block. If we are, it will have been handled earlier in the switch statement above. */
if (onMeta == NULL && blockSize > 0) {
if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
if (!onSeek(pUserData, blockSize, DRFLAC_SEEK_CUR)) {
isLastBlock = DRFLAC_TRUE;
}
}
@ -7220,6 +7154,7 @@ typedef struct
{
drflac_read_proc onRead; /* The original onRead callback from drflac_open() and family. */
drflac_seek_proc onSeek; /* The original onSeek callback from drflac_open() and family. */
drflac_tell_proc onTell; /* The original onTell callback from drflac_open() and family. */
void* pUserData; /* The user data passed on onRead and onSeek. This is the user data that was passed on drflac_open() and family. */
drflac_uint64 currentBytePos; /* The position of the byte we are sitting on in the physical byte stream. Used for efficient seeking. */
drflac_uint64 firstBytePos; /* The position of the first byte in the physical bitstream. Points to the start of the "OggS" identifier of the FLAC bos page. */
@ -7241,32 +7176,32 @@ static size_t drflac_oggbs__read_physical(drflac_oggbs* oggbs, void* bufferOut,
static drflac_bool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, drflac_uint64 offset, drflac_seek_origin origin)
{
if (origin == drflac_seek_origin_start) {
if (origin == DRFLAC_SEEK_SET) {
if (offset <= 0x7FFFFFFF) {
if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_start)) {
if (!oggbs->onSeek(oggbs->pUserData, (int)offset, DRFLAC_SEEK_SET)) {
return DRFLAC_FALSE;
}
oggbs->currentBytePos = offset;
return DRFLAC_TRUE;
} else {
if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) {
if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, DRFLAC_SEEK_SET)) {
return DRFLAC_FALSE;
}
oggbs->currentBytePos = offset;
return drflac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, drflac_seek_origin_current);
return drflac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, DRFLAC_SEEK_CUR);
}
} else {
while (offset > 0x7FFFFFFF) {
if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) {
if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, DRFLAC_SEEK_CUR)) {
return DRFLAC_FALSE;
}
oggbs->currentBytePos += 0x7FFFFFFF;
offset -= 0x7FFFFFFF;
}
if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_current)) { /* <-- Safe cast thanks to the loop above. */
if (!oggbs->onSeek(oggbs->pUserData, (int)offset, DRFLAC_SEEK_CUR)) { /* <-- Safe cast thanks to the loop above. */
return DRFLAC_FALSE;
}
oggbs->currentBytePos += offset;
@ -7298,7 +7233,7 @@ static drflac_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs, drflac_og
if (header.serialNumber != oggbs->serialNumber) {
/* It's not a FLAC page. Skip it. */
if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, drflac_seek_origin_current)) {
if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, DRFLAC_SEEK_CUR)) {
return DRFLAC_FALSE;
}
continue;
@ -7384,7 +7319,7 @@ static drflac_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs)
At this point we will have found either the packet or the end of the page. If were at the end of the page we'll
want to load the next page and keep searching for the end of the packet.
*/
drflac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, drflac_seek_origin_current);
drflac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, DRFLAC_SEEK_CUR);
oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage;
if (atEndOfPage) {
@ -7462,8 +7397,8 @@ static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_see
DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */
/* Seeking is always forward which makes things a lot simpler. */
if (origin == drflac_seek_origin_start) {
if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, drflac_seek_origin_start)) {
if (origin == DRFLAC_SEEK_SET) {
if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, DRFLAC_SEEK_SET)) {
return DRFLAC_FALSE;
}
@ -7471,38 +7406,50 @@ static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_see
return DRFLAC_FALSE;
}
return drflac__on_seek_ogg(pUserData, offset, drflac_seek_origin_current);
}
return drflac__on_seek_ogg(pUserData, offset, DRFLAC_SEEK_CUR);
} else if (origin == DRFLAC_SEEK_CUR) {
while (bytesSeeked < offset) {
int bytesRemainingToSeek = offset - bytesSeeked;
DRFLAC_ASSERT(bytesRemainingToSeek >= 0);
DRFLAC_ASSERT(origin == drflac_seek_origin_current);
if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) {
bytesSeeked += bytesRemainingToSeek;
(void)bytesSeeked; /* <-- Silence a dead store warning emitted by Clang Static Analyzer. */
oggbs->bytesRemainingInPage -= bytesRemainingToSeek;
break;
}
while (bytesSeeked < offset) {
int bytesRemainingToSeek = offset - bytesSeeked;
DRFLAC_ASSERT(bytesRemainingToSeek >= 0);
/* If we get here it means some of the requested data is contained in the next pages. */
if (oggbs->bytesRemainingInPage > 0) {
bytesSeeked += (int)oggbs->bytesRemainingInPage;
oggbs->bytesRemainingInPage = 0;
}
if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) {
bytesSeeked += bytesRemainingToSeek;
(void)bytesSeeked; /* <-- Silence a dead store warning emitted by Clang Static Analyzer. */
oggbs->bytesRemainingInPage -= bytesRemainingToSeek;
break;
}
/* If we get here it means some of the requested data is contained in the next pages. */
if (oggbs->bytesRemainingInPage > 0) {
bytesSeeked += (int)oggbs->bytesRemainingInPage;
oggbs->bytesRemainingInPage = 0;
}
DRFLAC_ASSERT(bytesRemainingToSeek > 0);
if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) {
/* Failed to go to the next page. We either hit the end of the stream or had a CRC mismatch. */
return DRFLAC_FALSE;
DRFLAC_ASSERT(bytesRemainingToSeek > 0);
if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) {
/* Failed to go to the next page. We either hit the end of the stream or had a CRC mismatch. */
return DRFLAC_FALSE;
}
}
} else if (origin == DRFLAC_SEEK_END) {
/* Seeking to the end is not supported. */
return DRFLAC_FALSE;
}
return DRFLAC_TRUE;
}
static drflac_bool32 drflac__on_tell_ogg(void* pUserData, drflac_int64* pCursor)
{
/*
Not implemented for Ogg containers because we don't currently track the byte position of the logical bitstream. To support this, we'll need
to track the position in drflac__on_read_ogg and drflac__on_seek_ogg.
*/
(void)pUserData;
(void)pCursor;
return DRFLAC_FALSE;
}
static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex)
{
@ -7525,7 +7472,7 @@ static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64
runningGranulePosition = 0;
for (;;) {
if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start);
drflac_oggbs__seek_physical(oggbs, originalBytePos, DRFLAC_SEEK_SET);
return DRFLAC_FALSE; /* Never did find that sample... */
}
@ -7559,7 +7506,7 @@ static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64
a new frame. This property means that after we've seeked to the page we can immediately start looping over frames until
we find the one containing the target sample.
*/
if (!drflac_oggbs__seek_physical(oggbs, runningFrameBytePos, drflac_seek_origin_start)) {
if (!drflac_oggbs__seek_physical(oggbs, runningFrameBytePos, DRFLAC_SEEK_SET)) {
return DRFLAC_FALSE;
}
if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
@ -7726,7 +7673,7 @@ static drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_r
The next 2 bytes are the non-audio packets, not including this one. We don't care about this because we're going to
be handling it in a generic way based on the serial number and packet types.
*/
if (!onSeek(pUserData, 2, drflac_seek_origin_current)) {
if (!onSeek(pUserData, 2, DRFLAC_SEEK_CUR)) {
return DRFLAC_FALSE;
}
@ -7783,18 +7730,18 @@ static drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_r
}
} else {
/* Not a FLAC header. Skip it. */
if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) {
if (!onSeek(pUserData, bytesRemainingInPage, DRFLAC_SEEK_CUR)) {
return DRFLAC_FALSE;
}
}
} else {
/* Not a FLAC header. Seek past the entire page and move on to the next. */
if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) {
if (!onSeek(pUserData, bytesRemainingInPage, DRFLAC_SEEK_CUR)) {
return DRFLAC_FALSE;
}
}
} else {
if (!onSeek(pUserData, pageBodySize, drflac_seek_origin_current)) {
if (!onSeek(pUserData, pageBodySize, DRFLAC_SEEK_CUR)) {
return DRFLAC_FALSE;
}
}
@ -7819,18 +7766,19 @@ static drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_r
}
#endif
static drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD)
static drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD)
{
drflac_bool32 relaxed;
drflac_uint8 id[4];
if (pInit == NULL || onRead == NULL || onSeek == NULL) {
if (pInit == NULL || onRead == NULL || onSeek == NULL) { /* <-- onTell is optional. */
return DRFLAC_FALSE;
}
DRFLAC_ZERO_MEMORY(pInit, sizeof(*pInit));
pInit->onRead = onRead;
pInit->onSeek = onSeek;
pInit->onTell = onTell;
pInit->onMeta = onMeta;
pInit->container = container;
pInit->pUserData = pUserData;
@ -7838,6 +7786,7 @@ static drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_p
pInit->bs.onRead = onRead;
pInit->bs.onSeek = onSeek;
pInit->bs.onTell = onTell;
pInit->bs.pUserData = pUserData;
drflac__reset_cache(&pInit->bs);
@ -7870,7 +7819,7 @@ static drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_p
headerSize += 10;
}
if (!onSeek(pUserData, headerSize, drflac_seek_origin_current)) {
if (!onSeek(pUserData, headerSize, DRFLAC_SEEK_CUR)) {
return DRFLAC_FALSE; /* Failed to seek past the tag. */
}
pInit->runningFilePos += headerSize;
@ -7922,7 +7871,7 @@ static void drflac__init_from_info(drflac* pFlac, const drflac_init_info* pInit)
}
static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD, const drflac_allocation_callbacks* pAllocationCallbacks)
static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac_init_info init;
drflac_uint32 allocationSize;
@ -7940,7 +7889,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
/* CPU support first. */
drflac__init_cpu_caps();
if (!drflac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) {
if (!drflac__init_private(&init, onRead, onSeek, onTell, onMeta, container, pUserData, pUserDataMD)) {
return NULL;
}
@ -7996,6 +7945,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
DRFLAC_ZERO_MEMORY(pOggbs, sizeof(*pOggbs));
pOggbs->onRead = onRead;
pOggbs->onSeek = onSeek;
pOggbs->onTell = onTell;
pOggbs->pUserData = pUserData;
pOggbs->currentBytePos = init.oggFirstBytePos;
pOggbs->firstBytePos = init.oggFirstBytePos;
@ -8016,17 +7966,19 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
if (init.hasMetadataBlocks) {
drflac_read_proc onReadOverride = onRead;
drflac_seek_proc onSeekOverride = onSeek;
drflac_tell_proc onTellOverride = onTell;
void* pUserDataOverride = pUserData;
#ifndef DR_FLAC_NO_OGG
if (init.container == drflac_container_ogg) {
onReadOverride = drflac__on_read_ogg;
onSeekOverride = drflac__on_seek_ogg;
onTellOverride = drflac__on_tell_ogg;
pUserDataOverride = (void*)pOggbs;
}
#endif
if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) {
if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onTellOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) {
#ifndef DR_FLAC_NO_OGG
drflac__free_from_callbacks(pOggbs, &allocationCallbacks);
#endif
@ -8061,6 +8013,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
/* The Ogg bistream needs to be layered on top of the original bitstream. */
pFlac->bs.onRead = drflac__on_read_ogg;
pFlac->bs.onSeek = drflac__on_seek_ogg;
pFlac->bs.onTell = drflac__on_tell_ogg;
pFlac->bs.pUserData = (void*)pInternalOggbs;
pFlac->_oggbs = (void*)pInternalOggbs;
}
@ -8087,7 +8040,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
DRFLAC_ASSERT(pFlac->bs.onRead != NULL);
/* Seek to the seektable, then just read directly into our seektable buffer. */
if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, drflac_seek_origin_start)) {
if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, DRFLAC_SEEK_SET)) {
drflac_uint32 iSeekpoint;
for (iSeekpoint = 0; iSeekpoint < seekpointCount; iSeekpoint += 1) {
@ -8105,7 +8058,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
}
/* We need to seek back to where we were. If this fails it's a critical error. */
if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, drflac_seek_origin_start)) {
if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, DRFLAC_SEEK_SET)) {
drflac__free_from_callbacks(pFlac, &allocationCallbacks);
return NULL;
}
@ -8276,7 +8229,7 @@ static drflac_result drflac_result_from_errno(int e)
#ifdef ENOSYS
case ENOSYS: return DRFLAC_NOT_IMPLEMENTED;
#endif
#ifdef ENOTEMPTY
#if defined(ENOTEMPTY) && ENOTEMPTY != EEXIST /* In AIX, ENOTEMPTY and EEXIST use the same value. */
case ENOTEMPTY: return DRFLAC_DIRECTORY_NOT_EMPTY;
#endif
#ifdef ELOOP
@ -8727,11 +8680,41 @@ static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t byt
static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
{
DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */
int whence = SEEK_SET;
if (origin == DRFLAC_SEEK_CUR) {
whence = SEEK_CUR;
} else if (origin == DRFLAC_SEEK_END) {
whence = SEEK_END;
}
return fseek((FILE*)pUserData, offset, (origin == drflac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
return fseek((FILE*)pUserData, offset, whence) == 0;
}
static drflac_bool32 drflac__on_tell_stdio(void* pUserData, drflac_int64* pCursor)
{
FILE* pFileStdio = (FILE*)pUserData;
drflac_int64 result;
/* These were all validated at a higher level. */
DRFLAC_ASSERT(pFileStdio != NULL);
DRFLAC_ASSERT(pCursor != NULL);
#if defined(_WIN32)
#if defined(_MSC_VER) && _MSC_VER > 1200
result = _ftelli64(pFileStdio);
#else
result = ftell(pFileStdio);
#endif
#else
result = ftell(pFileStdio);
#endif
*pCursor = result;
return DRFLAC_TRUE;
}
DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks)
{
@ -8742,7 +8725,7 @@ DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocati
return NULL;
}
pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, drflac__on_tell_stdio, (void*)pFile, pAllocationCallbacks);
if (pFlac == NULL) {
fclose(pFile);
return NULL;
@ -8761,7 +8744,7 @@ DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_all
return NULL;
}
pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, drflac__on_tell_stdio, (void*)pFile, pAllocationCallbacks);
if (pFlac == NULL) {
fclose(pFile);
return NULL;
@ -8780,7 +8763,7 @@ DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_
return NULL;
}
pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, drflac__on_tell_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
if (pFlac == NULL) {
fclose(pFile);
return pFlac;
@ -8799,7 +8782,7 @@ DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, dr
return NULL;
}
pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, drflac__on_tell_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
if (pFlac == NULL) {
fclose(pFile);
return pFlac;
@ -8834,28 +8817,45 @@ static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t by
static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin)
{
drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
drflac_int64 newCursor;
DRFLAC_ASSERT(memoryStream != NULL);
DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */
if (offset > (drflac_int64)memoryStream->dataSize) {
newCursor = memoryStream->currentReadPos;
if (origin == DRFLAC_SEEK_SET) {
newCursor = 0;
} else if (origin == DRFLAC_SEEK_CUR) {
newCursor = (drflac_int64)memoryStream->currentReadPos;
} else if (origin == DRFLAC_SEEK_END) {
newCursor = (drflac_int64)memoryStream->dataSize;
} else {
DRFLAC_ASSERT(!"Invalid seek origin");
return DRFLAC_FALSE;
}
if (origin == drflac_seek_origin_current) {
if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) {
memoryStream->currentReadPos += offset;
} else {
return DRFLAC_FALSE; /* Trying to seek too far forward. */
}
} else {
if ((drflac_uint32)offset <= memoryStream->dataSize) {
memoryStream->currentReadPos = offset;
} else {
return DRFLAC_FALSE; /* Trying to seek too far forward. */
}
newCursor += offset;
if (newCursor < 0) {
return DRFLAC_FALSE; /* Trying to seek prior to the start of the buffer. */
}
if ((size_t)newCursor > memoryStream->dataSize) {
return DRFLAC_FALSE; /* Trying to seek beyond the end of the buffer. */
}
memoryStream->currentReadPos = (size_t)newCursor;
return DRFLAC_TRUE;
}
static drflac_bool32 drflac__on_tell_memory(void* pUserData, drflac_int64* pCursor)
{
drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
DRFLAC_ASSERT(memoryStream != NULL);
DRFLAC_ASSERT(pCursor != NULL);
*pCursor = (drflac_int64)memoryStream->currentReadPos;
return DRFLAC_TRUE;
}
@ -8867,7 +8867,7 @@ DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const
memoryStream.data = (const drflac_uint8*)pData;
memoryStream.dataSize = dataSize;
memoryStream.currentReadPos = 0;
pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, &memoryStream, pAllocationCallbacks);
pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, drflac__on_tell_memory, &memoryStream, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
@ -8898,7 +8898,7 @@ DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t da
memoryStream.data = (const drflac_uint8*)pData;
memoryStream.dataSize = dataSize;
memoryStream.currentReadPos = 0;
pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, onMeta, drflac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks);
pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, drflac__on_tell_memory, onMeta, drflac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
@ -8923,22 +8923,22 @@ DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t da
DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
{
return drflac_open_with_metadata_private(onRead, onSeek, NULL, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
return drflac_open_with_metadata_private(onRead, onSeek, onTell, NULL, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
}
DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
{
return drflac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData, pAllocationCallbacks);
return drflac_open_with_metadata_private(onRead, onSeek, onTell, NULL, container, pUserData, pUserData, pAllocationCallbacks);
}
DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
{
return drflac_open_with_metadata_private(onRead, onSeek, onMeta, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
return drflac_open_with_metadata_private(onRead, onSeek, onTell, onMeta, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
}
DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
{
return drflac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData, pAllocationCallbacks);
return drflac_open_with_metadata_private(onRead, onSeek, onTell, onMeta, container, pUserData, pUserData, pAllocationCallbacks);
}
DRFLAC_API void drflac_close(drflac* pFlac)
@ -11770,7 +11770,7 @@ DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s32, drflac_int32)
DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s16, drflac_int16)
DRFLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float)
DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
@ -11784,7 +11784,7 @@ DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc on
*totalPCMFrameCountOut = 0;
}
pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
pFlac = drflac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
@ -11792,7 +11792,7 @@ DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc on
return drflac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
}
DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
@ -11806,7 +11806,7 @@ DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc on
*totalPCMFrameCountOut = 0;
}
pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
pFlac = drflac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
@ -11814,7 +11814,7 @@ DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc on
return drflac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
}
DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
@ -11828,7 +11828,7 @@ DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, d
*totalPCMFrameCountOut = 0;
}
pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
pFlac = drflac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
@ -12077,6 +12077,26 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
/*
REVISION HISTORY
================
v0.13.0 - TBD
- API CHANGE: Seek origin enums have been renamed to match the naming convention used by other dr_libs libraries:
- drflac_seek_origin_start -> DRFLAC_SEEK_SET
- drflac_seek_origin_current -> DRFLAC_SEEK_CUR
- DRFLAC_SEEK_END (new)
- API CHANGE: A new seek origin has been added to allow seeking from the end of the file. If you implement your own `onSeek` callback, you should now detect and handle `DRFLAC_SEEK_END`. If seeking to the end is not supported, return `DRFLAC_FALSE`. If you only use `*_open_file()` or `*_open_memory()`, you need not change anything.
- API CHANGE: An `onTell` callback has been added to the following functions:
- drflac_open()
- drflac_open_relaxed()
- drflac_open_with_metadata()
- drflac_open_with_metadata_relaxed()
- drflac_open_and_read_pcm_frames_s32()
- drflac_open_and_read_pcm_frames_s16()
- drflac_open_and_read_pcm_frames_f32()
- Fix compilation for AIX OS.
v0.12.43 - 2024-12-17
- Fix a possible buffer overflow during decoding.
- Improve detection of ARM64EC
v0.12.42 - 2023-11-02
- Fix build for ARMv6-M.
- Fix a compilation warning with GCC.

899
src/external/dr_mp3.h vendored

File diff suppressed because it is too large Load diff

492
src/external/dr_wav.h vendored

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -232,6 +232,13 @@ uint64_t jar_xm_get_remaining_samples(jar_xm_context_t* ctx);
#include <limits.h>
#include <string.h>
#ifdef DEBUG
// Undefine DEBUG to avoid external redefinition warnings/conflicts
// This is probably a common definition for
// many external build systems' debug configurations
#undef DEBUG
#endif
#if JAR_XM_DEBUG //JAR_XM_DEBUG defined as 0
#include <stdio.h>
#define DEBUG(fmt, ...) do { \

1813
src/external/miniaudio.h vendored

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

44
src/external/rprand.h vendored
View file

@ -15,15 +15,15 @@
* - Support 64 bits generation
*
* ADDITIONAL NOTES:
* This library implements two pseudo-random number generation algorithms:
* This library implements two pseudo-random number generation algorithms:
*
* - Xoshiro128** : https://prng.di.unimi.it/xoshiro128starstar.c
* - SplitMix64 : https://prng.di.unimi.it/splitmix64.c
*
* SplitMix64 is used to initialize the Xoshiro128** state, from a provided seed
*
* It's suggested to use SplitMix64 to initialize the state of the generators starting from
* a 64-bit seed, as research has shown that initialization must be performed with a generator
* It's suggested to use SplitMix64 to initialize the state of the generators starting from
* a 64-bit seed, as research has shown that initialization must be performed with a generator
* radically different in nature from the one initialized to avoid correlation on similar seeds.
*
* CONFIGURATION:
@ -31,7 +31,7 @@
* Generates the implementation of the library into the included file.
* If not defined, the library is in header only mode and can be included in other headers
* or source files without problems. But only ONE file should hold the implementation.
*
*
* DEPENDENCIES: none
*
* VERSIONS HISTORY:
@ -90,7 +90,7 @@
#define RPRAND_FREE(ptr) free(ptr)
#endif
// Simple log system to avoid RPNG_LOG() calls if required
// Simple log system to avoid log calls if required
// NOTE: Avoiding those calls, also avoids const strings memory usage
#define RPRAND_SHOW_LOG_INFO
#if defined(RPNG_SHOW_LOG_INFO)
@ -153,7 +153,7 @@ static uint32_t rprand_state[4] = { // Xoshiro128** state, initializ
0x218b21e5,
0xaa91febd,
0x976414d4
};
};
//----------------------------------------------------------------------------------
// Module internal functions declaration
@ -190,8 +190,8 @@ int rprand_get_value(int min, int max)
int *rprand_load_sequence(unsigned int count, int min, int max)
{
int *sequence = NULL;
if (count > (unsigned int)(abs(max - min) + 1))
if (count > (unsigned int)(abs(max - min) + 1))
{
RPRAND_LOG("WARNING: Sequence count required is greater than range provided\n");
//count = (max - min);
@ -244,26 +244,26 @@ static inline uint32_t rprand_rotate_left(const uint32_t x, int k)
}
// Xoshiro128** generator info:
//
//
// Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
//
//
// To the extent possible under law, the author has dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
//
// See <http://creativecommons.org/publicdomain/zero/1.0/>.
//
//
// This is xoshiro128** 1.1, one of our 32-bit all-purpose, rock-solid
// generators. It has excellent speed, a state size (128 bits) that is
// large enough for mild parallelism, and it passes all tests we are aware
// of.
//
//
// Note that version 1.0 had mistakenly s[0] instead of s[1] as state
// word passed to the scrambler.
//
//
// For generating just single-precision (i.e., 32-bit) floating-point
// numbers, xoshiro128+ is even faster.
//
//
// The state must be seeded so that it is not everywhere zero.
//
uint32_t rprand_xoshiro(void)
@ -275,29 +275,29 @@ uint32_t rprand_xoshiro(void)
rprand_state[3] ^= rprand_state[1];
rprand_state[1] ^= rprand_state[2];
rprand_state[0] ^= rprand_state[3];
rprand_state[2] ^= t;
rprand_state[3] = rprand_rotate_left(rprand_state[3], 11);
return result;
}
// SplitMix64 generator info:
//
//
// Written in 2015 by Sebastiano Vigna (vigna@acm.org)
//
//
// To the extent possible under law, the author has dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
//
// See <http://creativecommons.org/publicdomain/zero/1.0/>.
//
//
//
// This is a fixed-increment version of Java 8's SplittableRandom generator
// See http://dx.doi.org/10.1145/2714064.2660195 and
// http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html
//
//
// It is a very fast generator passing BigCrush, and it can be useful if
// for some reason you absolutely want 64 bits of state.
uint64_t rprand_splitmix64()

View file

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

View file

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

View file

@ -70,6 +70,16 @@ typedef struct {
EGLConfig config; // Graphic config
} PlatformData;
typedef struct {
// Store data for both Hover and Touch events
// Used to ignore Hover events which are interpreted as Touch events
int32_t pointCount; // Number of touch points active
int32_t pointId[MAX_TOUCH_POINTS]; // Point identifiers
Vector2 position[MAX_TOUCH_POINTS]; // Touch position on screen
int32_t hoverPoints[MAX_TOUCH_POINTS]; // Hover Points
} TouchRaw;
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
@ -246,6 +256,8 @@ static const KeyboardKey mapKeycode[KEYCODE_MAP_SIZE] = {
KEY_KP_EQUAL // AKEYCODE_NUMPAD_EQUALS
};
static TouchRaw touchRaw = { 0 };
//----------------------------------------------------------------------------------
// Module Internal Functions Declaration
//----------------------------------------------------------------------------------
@ -337,7 +349,7 @@ void MinimizeWindow(void)
TRACELOG(LOG_WARNING, "MinimizeWindow() not available on target platform");
}
// Set window state: not minimized/maximized
// Restore window from being minimized/maximized
void RestoreWindow(void)
{
TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform");
@ -431,7 +443,7 @@ int GetMonitorCount(void)
return 1;
}
// Get number of monitors
// Get current monitor where window is placed
int GetCurrentMonitor(void)
{
TRACELOG(LOG_WARNING, "GetCurrentMonitor() not implemented on target platform");
@ -801,6 +813,8 @@ int InitPlatform(void)
}
}
for (int i = 0; i < MAX_TOUCH_POINTS; i++) touchRaw.hoverPoints[i] = -1;
return 0;
}
@ -859,7 +873,7 @@ static int InitGraphicsDevice(void)
EGL_GREEN_SIZE, 8, // GREEN color bit depth (alternative: 6)
EGL_BLUE_SIZE, 8, // BLUE color bit depth (alternative: 5)
//EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI)
EGL_DEPTH_SIZE, 16, // Depth buffer size (Required to use Depth testing!)
EGL_DEPTH_SIZE, 24, // Depth buffer size (Required to use Depth testing!)
//EGL_STENCIL_SIZE, 8, // Stencil buffer size
EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA
EGL_SAMPLES, samples, // 4x Antialiasing if activated (Free on MALI GPUs)
@ -1269,25 +1283,85 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
}
// Register touch points count
CORE.Input.Touch.pointCount = AMotionEvent_getPointerCount(event);
touchRaw.pointCount = AMotionEvent_getPointerCount(event);
for (int i = 0; (i < CORE.Input.Touch.pointCount) && (i < MAX_TOUCH_POINTS); i++)
for (int i = 0; (i < touchRaw.pointCount) && (i < MAX_TOUCH_POINTS); i++)
{
// Register touch points id
CORE.Input.Touch.pointId[i] = AMotionEvent_getPointerId(event, i);
touchRaw.pointId[i] = AMotionEvent_getPointerId(event, i);
// Register touch points position
CORE.Input.Touch.position[i] = (Vector2){ AMotionEvent_getX(event, i), AMotionEvent_getY(event, i) };
touchRaw.position[i] = (Vector2){ AMotionEvent_getX(event, i), AMotionEvent_getY(event, i) };
// Normalize CORE.Input.Touch.position[i] for CORE.Window.screen.width and CORE.Window.screen.height
float widthRatio = (float)(CORE.Window.screen.width + CORE.Window.renderOffset.x)/(float)CORE.Window.display.width;
float heightRatio = (float)(CORE.Window.screen.height + CORE.Window.renderOffset.y)/(float)CORE.Window.display.height;
CORE.Input.Touch.position[i].x = CORE.Input.Touch.position[i].x*widthRatio - (float)CORE.Window.renderOffset.x/2;
CORE.Input.Touch.position[i].y = CORE.Input.Touch.position[i].y*heightRatio - (float)CORE.Window.renderOffset.y/2;
touchRaw.position[i].x = touchRaw.position[i].x*widthRatio - (float)CORE.Window.renderOffset.x/2;
touchRaw.position[i].y = touchRaw.position[i].y*heightRatio - (float)CORE.Window.renderOffset.y/2;
}
int32_t action = AMotionEvent_getAction(event);
unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
if (flags == AMOTION_EVENT_ACTION_HOVER_ENTER)
{
// The new pointer is hover
// So add it to hoverPoints
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
{
if (touchRaw.hoverPoints[i] == -1)
{
touchRaw.hoverPoints[i] = touchRaw.pointId[pointerIndex];
break;
}
}
}
if ((flags == AMOTION_EVENT_ACTION_POINTER_UP) || (flags == AMOTION_EVENT_ACTION_UP) || (flags == AMOTION_EVENT_ACTION_HOVER_EXIT))
{
// One of the touchpoints is released, remove it from touch point arrays
if (flags == AMOTION_EVENT_ACTION_HOVER_EXIT)
{
// If the touchPoint is hover, remove it from hoverPoints
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
{
if (touchRaw.hoverPoints[i] == touchRaw.pointId[pointerIndex])
{
touchRaw.hoverPoints[i] = -1;
break;
}
}
}
for (int i = pointerIndex; (i < touchRaw.pointCount - 1) && (i < MAX_TOUCH_POINTS - 1); i++)
{
touchRaw.pointId[i] = touchRaw.pointId[i+1];
touchRaw.position[i] = touchRaw.position[i+1];
}
touchRaw.pointCount--;
}
int pointCount = 0;
for (int i = 0; (i < touchRaw.pointCount) && (i < MAX_TOUCH_POINTS); i++)
{
// If the touchPoint is hover, Ignore it
bool hover = false;
for (int j = 0; j < MAX_TOUCH_POINTS; j++)
{
// Check if the touchPoint is in hoverPointers
if (touchRaw.hoverPoints[j] == touchRaw.pointId[i])
{
hover = true;
break;
}
}
if (hover) continue;
CORE.Input.Touch.pointId[pointCount] = touchRaw.pointId[i];
CORE.Input.Touch.position[pointCount] = touchRaw.position[i];
pointCount++;
}
CORE.Input.Touch.pointCount = pointCount;
#if defined(SUPPORT_GESTURES_SYSTEM)
GestureEvent gestureEvent = { 0 };
@ -1312,20 +1386,6 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
ProcessGestureEvent(gestureEvent);
#endif
int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
if (flags == AMOTION_EVENT_ACTION_POINTER_UP || flags == AMOTION_EVENT_ACTION_UP)
{
// One of the touchpoints is released, remove it from touch point arrays
for (int i = pointerIndex; (i < CORE.Input.Touch.pointCount - 1) && (i < MAX_TOUCH_POINTS); i++)
{
CORE.Input.Touch.pointId[i] = CORE.Input.Touch.pointId[i+1];
CORE.Input.Touch.position[i] = CORE.Input.Touch.position[i+1];
}
CORE.Input.Touch.pointCount--;
}
// When all touchpoints are tapped and released really quickly, this event is generated
if (flags == AMOTION_EVENT_ACTION_CANCEL) CORE.Input.Touch.pointCount = 0;

View file

@ -1,6 +1,6 @@
/**********************************************************************************************
*
* rcore_desktop - Functions to manage window, graphics device and inputs
* rcore_desktop_glfw - Functions to manage window, graphics device and inputs
*
* PLATFORM: DESKTOP: GLFW
* - Windows (Win32, Win64)
@ -74,9 +74,14 @@
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
#include <sys/time.h> // Required for: timespec, nanosleep(), select() - POSIX
//#define GLFW_EXPOSE_NATIVE_X11 // WARNING: Exposing Xlib.h > X.h results in dup symbols for Font type
//#define GLFW_EXPOSE_NATIVE_WAYLAND
#define GLFW_EXPOSE_NATIVE_X11
#define Font X11Font // Hack to fix 'Font' name collision
// The definition and references to the X11 Font type will be replaced by 'X11Font'
// Works as long as the current file consistently references any X11 Font as X11Font
// Since it is never referenced (as of writting), this does not pose an issue
#include "GLFW/glfw3native.h" // Required for: glfwGetX11Window()
#undef Font // Revert hack and allow normal raylib Font usage
#endif
#if defined(__APPLE__)
#include <unistd.h> // Required for: usleep()
@ -130,9 +135,9 @@ static void CursorEnterCallback(GLFWwindow *window, int enter);
static void JoystickCallback(int jid, int event); // GLFW3 Joystick Connected/Disconnected Callback
// Wrappers used by glfwInitAllocator
static void* AllocateWrapper(size_t size, void* user); // GLFW3 GLFWallocatefun, wrapps around RL_MALLOC macro
static void* ReallocateWrapper(void* block, size_t size, void* user); // GLFW3 GLFWreallocatefun, wrapps around RL_MALLOC macro
static void DeallocateWrapper(void* block, void* user); // GLFW3 GLFWdeallocatefun, wraps around RL_FREE macro
static void *AllocateWrapper(size_t size, void *user); // GLFW3 GLFWallocatefun, wrapps around RL_MALLOC macro
static void *ReallocateWrapper(void *block, size_t size, void *user); // GLFW3 GLFWreallocatefun, wrapps around RL_MALLOC macro
static void DeallocateWrapper(void *block, void *user); // GLFW3 GLFWdeallocatefun, wraps around RL_FREE macro
//----------------------------------------------------------------------------------
// Module Functions Declaration
@ -292,7 +297,7 @@ void MinimizeWindow(void)
glfwIconifyWindow(platform.handle);
}
// Set window state: not minimized/maximized
// Restore window from being minimized/maximized
void RestoreWindow(void)
{
if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE)
@ -307,6 +312,8 @@ void RestoreWindow(void)
// Set window configuration state using flags
void SetWindowState(unsigned int flags)
{
if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
// Check previous state and requested state to apply required changes
// NOTE: In most cases the functions already change the flags internally
@ -574,7 +581,7 @@ void SetWindowIcons(Image *images, int count)
else
{
int valid = 0;
GLFWimage *icons = RL_CALLOC(count, sizeof(GLFWimage));
GLFWimage *icons = (GLFWimage *)RL_CALLOC(count, sizeof(GLFWimage));
for (int i = 0; i < count; i++)
{
@ -703,6 +710,12 @@ void SetWindowFocused(void)
glfwFocusWindow(platform.handle);
}
#if defined(__linux__)
// 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
static XID X11WindowHandle;
#endif
// Get native window handle
void *GetWindowHandle(void)
{
@ -711,12 +724,10 @@ void *GetWindowHandle(void)
return glfwGetWin32Window(platform.handle);
#endif
#if defined(__linux__)
// NOTE: Returned handle is: unsigned long Window (X.h)
// typedef unsigned long XID;
// typedef XID Window;
//unsigned long id = (unsigned long)glfwGetX11Window(platform.handle);
//return NULL; // TODO: Find a way to return value... cast to void *?
return (void *)platform.handle;
// Store the window handle localy and return a pointer to the variable instead.
// Reasoning detailed in the declaration of X11WindowHandle
X11WindowHandle = glfwGetX11Window(platform.handle);
return &X11WindowHandle;
#endif
#if defined(__APPLE__)
// NOTE: Returned handle is: (objc_object *)
@ -736,7 +747,7 @@ int GetMonitorCount(void)
return monitorCount;
}
// Get number of monitors
// Get current monitor where window is placed
int GetCurrentMonitor(void)
{
int index = 0;
@ -1236,7 +1247,7 @@ void PollInputEvents(void)
}
}
// Get current axis state
// Get current state of axes
const float *axes = state.axes;
for (int k = 0; (axes != NULL) && (k < GLFW_GAMEPAD_AXIS_LAST + 1); k++)
@ -1244,7 +1255,7 @@ void PollInputEvents(void)
CORE.Input.Gamepad.axisState[i][k] = axes[k];
}
// Register buttons for 2nd triggers (because GLFW doesn't count these as buttons but rather axis)
// Register buttons for 2nd triggers (because GLFW doesn't count these as buttons but rather as axes)
if (CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] > 0.1f)
{
CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_LEFT_TRIGGER_2] = 1;
@ -1298,17 +1309,17 @@ static void SetDimensionsFromMonitor(GLFWmonitor *monitor)
// We need to provide these because GLFWallocator expects function pointers with specific signatures.
// Similar wrappers exist in utils.c but we cannot reuse them here due to declaration mismatch.
// https://www.glfw.org/docs/latest/intro_guide.html#init_allocator
static void* AllocateWrapper(size_t size, void* user)
static void *AllocateWrapper(size_t size, void *user)
{
(void)user;
return RL_MALLOC(size);
}
static void* ReallocateWrapper(void* block, size_t size, void* user)
static void *ReallocateWrapper(void *block, size_t size, void *user)
{
(void)user;
return RL_REALLOC(block, size);
}
static void DeallocateWrapper(void* block, void* user)
static void DeallocateWrapper(void *block, void *user)
{
(void)user;
RL_FREE(block);
@ -1325,6 +1336,7 @@ int InitPlatform(void)
.reallocate = ReallocateWrapper,
.user = NULL, // RL_*ALLOC macros are not capable of handling user-provided data
};
glfwInitAllocator(&allocator);
#if defined(__APPLE__)
@ -1379,6 +1391,12 @@ int InitPlatform(void)
if ((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); // Transparent framebuffer
else glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_FALSE); // Opaque framebuffer
// HACK: Most of this was written before GLFW_SCALE_FRAMEBUFFER existed and
// was enabled by default. Disabling it gets back the old behavior. A
// complete fix will require removing a lot of CORE.Window.render
// manipulation code.
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
{
// Resize window content area based on the monitor content scale.
@ -1386,7 +1404,7 @@ int InitPlatform(void)
// On platforms like macOS the resolution of the framebuffer is changed independently of the window size.
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // Scale content area based on the monitor content scale where window is placed on
#if defined(__APPLE__)
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE);
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
#endif
}
else glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE);
@ -1600,7 +1618,7 @@ int InitPlatform(void)
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
{
// NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling.
// Framebuffer scaling should be activated with: glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE);
// Framebuffer scaling should be activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
#if !defined(__APPLE__)
glfwGetFramebufferSize(platform.handle, &fbWidth, &fbHeight);
@ -1688,6 +1706,8 @@ int InitPlatform(void)
// Retrieve gamepad names
for (int i = 0; i < MAX_GAMEPADS; i++)
{
// WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
// we can get a not-NULL terminated string, so, we only copy up to (MAX_GAMEPAD_NAME_LENGTH - 1)
if (glfwJoystickPresent(i)) strncpy(CORE.Input.Gamepad.name[i], glfwGetJoystickName(i), MAX_GAMEPAD_NAME_LENGTH - 1);
}
//----------------------------------------------------------------------------
@ -1741,9 +1761,13 @@ static void ErrorCallback(int error, const char *description)
}
// GLFW3 WindowSize Callback, runs when window is resizedLastFrame
// NOTE: Window resizing not allowed by default
// NOTE: Window resizing not enabled by default, use SetConfigFlags()
static void WindowSizeCallback(GLFWwindow *window, int width, int height)
{
// WARNING: On window minimization, callback is called,
// but we don't want to change internal screen values, it breaks things
if ((width == 0) || (height == 0)) return;
// Reset viewport and projection matrix for new size
SetupViewport(width, height);
@ -1753,12 +1777,22 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height)
if (IsWindowFullscreen()) return;
// Set current screen size
// if we are doing automatic DPI scaling, then the "screen" size is divided by the window scale
if (IsWindowState(FLAG_WINDOW_HIGHDPI))
{
width = (int)(width/GetWindowScaleDPI().x);
height = (int)(height/GetWindowScaleDPI().y);
}
// Set render size
CORE.Window.render.width = width;
CORE.Window.render.height = height;
// Set current screen size
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
// NOTE: Postprocessing texture is not scaled to new size
// WARNING: If using a render texture, it is not scaled to new size
}
static void WindowPosCallback(GLFWwindow* window, int x, int y)
{
@ -1828,8 +1862,8 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
// WARNING: GLFW could return GLFW_REPEAT, we need to consider it as 1
// to work properly with our implementation (IsKeyDown/IsKeyUp checks)
if (action == GLFW_RELEASE) CORE.Input.Keyboard.currentKeyState[key] = 0;
else if(action == GLFW_PRESS) CORE.Input.Keyboard.currentKeyState[key] = 1;
else if(action == GLFW_REPEAT) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1;
else if (action == GLFW_PRESS) CORE.Input.Keyboard.currentKeyState[key] = 1;
else if (action == GLFW_REPEAT) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1;
// WARNING: Check if CAPS/NUM key modifiers are enabled and force down state for those keys
if (((key == KEY_CAPS_LOCK) && ((mods & GLFW_MOD_CAPS_LOCK) > 0)) ||
@ -1951,6 +1985,9 @@ static void JoystickCallback(int jid, int event)
{
if (event == GLFW_CONNECTED)
{
// WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
// we can get a not-NULL terminated string, so, we clean destination and only copy up to -1
memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH);
strncpy(CORE.Input.Gamepad.name[jid], glfwGetJoystickName(jid), MAX_GAMEPAD_NAME_LENGTH - 1);
}
else if (event == GLFW_DISCONNECTED)

View file

@ -54,7 +54,7 @@
#endif
#if defined(PLATFORM_WEB_RGFW)
#define RGFW_NO_GL_HEADER
#define RGFW_NO_GL_HEADER
#endif
#if defined(GRAPHICS_API_OPENGL_ES2) && !defined(PLATFORM_WEB_RGFW)
@ -76,14 +76,14 @@ void CloseWindow(void);
#if defined(_WIN32) || defined(_WIN64)
#define WIN32_LEAN_AND_MEAN
#define Rectangle rectangle_win32
#define Rectangle rectangle_win32
#define CloseWindow CloseWindow_win32
#define ShowCursor __imp_ShowCursor
#define _APISETSTRING_
#undef MAX_PATH
#define _APISETSTRING_
#undef MAX_PATH
__declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar);
__declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar);
#endif
#if defined(__APPLE__)
@ -103,8 +103,8 @@ void CloseWindow(void);
#undef CloseWindow
#undef Rectangle
#undef MAX_PATH
#define MAX_PATH 1025
#undef MAX_PATH
#define MAX_PATH 1025
#endif
#if defined(__APPLE__)
@ -128,7 +128,7 @@ typedef struct {
//----------------------------------------------------------------------------------
extern CoreData CORE; // Global CORE state context
static PlatformData platform = { NULL }; // Platform specific
static PlatformData platform = { 0 }; // Platform specific
static bool RGFW_disableCursor = false;
@ -175,7 +175,9 @@ static const unsigned short keyMappingRGFW[] = {
[RGFW_superL] = KEY_LEFT_SUPER,
#ifndef RGFW_MACOS
[RGFW_shiftR] = KEY_RIGHT_SHIFT,
[RGFW_controlR] = KEY_RIGHT_CONTROL,
[RGFW_altR] = KEY_RIGHT_ALT,
[RGFW_superR] = KEY_RIGHT_SUPER,
#endif
[RGFW_space] = KEY_SPACE,
@ -264,11 +266,12 @@ bool WindowShouldClose(void)
// Toggle fullscreen mode
void ToggleFullscreen(void)
{
{
if (!CORE.Window.fullscreen)
{
// Store previous window position (in case we exit fullscreen)
CORE.Window.previousPosition = CORE.Window.position;
CORE.Window.previousScreen = CORE.Window.screen;
platform.mon = RGFW_window_getMonitor(platform.window);
CORE.Window.fullscreen = true;
@ -281,18 +284,20 @@ void ToggleFullscreen(void)
{
CORE.Window.fullscreen = false;
CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
if (platform.mon.mode.area.w)
if (platform.mon.mode.area.w)
{
RGFW_monitor monitor = RGFW_window_getMonitor(platform.window);
RGFW_monitor_requestMode(monitor, platform.mon.mode, RGFW_monitorScale);
platform.mon.mode.area.w = 0;
}
// we update the window position right away
CORE.Window.position = CORE.Window.previousPosition;
RGFW_window_setFullscreen(platform.window, 0);
RGFW_window_move(platform.window, RGFW_POINT(CORE.Window.position.x, CORE.Window.position.y));
RGFW_window_resize(platform.window, RGFW_AREA(CORE.Window.previousScreen.width, CORE.Window.previousScreen.height));
}
// Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)
@ -303,10 +308,7 @@ void ToggleFullscreen(void)
// Toggle borderless windowed mode
void ToggleBorderlessWindowed(void)
{
if (platform.window == NULL)
return;
if (CORE.Window.fullscreen)
if (CORE.Window.fullscreen)
{
CORE.Window.previousPosition = CORE.Window.position;
CORE.Window.previousScreen = CORE.Window.screen;
@ -315,7 +317,9 @@ void ToggleBorderlessWindowed(void)
RGFW_monitor mon = RGFW_window_getMonitor(platform.window);
RGFW_window_resize(platform.window, mon.mode.area);
} else {
}
else
{
RGFW_window_setBorder(platform.window, 1);
CORE.Window.position = CORE.Window.previousPosition;
@ -337,11 +341,10 @@ void MinimizeWindow(void)
RGFW_window_minimize(platform.window);
}
// Set window state: not minimized/maximized
// Restore window from being minimized/maximized
void RestoreWindow(void)
{
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED))
RGFW_window_focus(platform.window);
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
RGFW_window_restore(platform.window);
}
@ -349,6 +352,8 @@ void RestoreWindow(void)
// Set window configuration state using flags
void SetWindowState(unsigned int flags)
{
if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
CORE.Window.flags |= flags;
if (flags & FLAG_VSYNC_HINT)
@ -357,8 +362,7 @@ void SetWindowState(unsigned int flags)
}
if (flags & FLAG_FULLSCREEN_MODE)
{
if (!CORE.Window.fullscreen)
ToggleFullscreen();
if (!CORE.Window.fullscreen) ToggleFullscreen();
}
if (flags & FLAG_WINDOW_RESIZABLE)
{
@ -384,6 +388,8 @@ void SetWindowState(unsigned int flags)
if (flags & FLAG_WINDOW_UNFOCUSED)
{
CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED;
platform.window->_flags &= ~RGFW_windowFocusOnShow;
RGFW_window_setFlags(platform.window, platform.window->_flags);
}
if (flags & FLAG_WINDOW_TOPMOST)
{
@ -430,8 +436,7 @@ void ClearWindowState(unsigned int flags)
}
if (flags & FLAG_FULLSCREEN_MODE)
{
if (CORE.Window.fullscreen)
ToggleFullscreen();
if (CORE.Window.fullscreen) ToggleFullscreen();
}
if (flags & FLAG_WINDOW_RESIZABLE)
{
@ -444,25 +449,25 @@ void ClearWindowState(unsigned int flags)
}
if (flags & FLAG_WINDOW_HIDDEN)
{
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED))
RGFW_window_focus(platform.window);
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
RGFW_window_show(platform.window);
}
if (flags & FLAG_WINDOW_MINIMIZED)
{
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED))
RGFW_window_focus(platform.window);
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
RGFW_window_restore(platform.window);
}
if (flags & FLAG_WINDOW_MAXIMIZED)
{
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED))
RGFW_window_focus(platform.window);
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
RGFW_window_restore(platform.window);
}
if (flags & FLAG_WINDOW_UNFOCUSED)
{
RGFW_window_setFlags(platform.window, platform.window->_flags | RGFW_windowFocusOnShow);
CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED;
}
if (flags & FLAG_WINDOW_TOPMOST)
@ -487,8 +492,7 @@ void ClearWindowState(unsigned int flags)
}
if (flags & FLAG_BORDERLESS_WINDOWED_MODE)
{
if (CORE.Window.fullscreen)
ToggleBorderlessWindowed();
if (CORE.Window.fullscreen) ToggleBorderlessWindowed();
}
if (flags & FLAG_MSAA_4X_HINT)
{
@ -502,7 +506,8 @@ void ClearWindowState(unsigned int flags)
int RGFW_formatToChannels(int format)
{
switch (format) {
switch (format)
{
case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
case PIXELFORMAT_UNCOMPRESSED_R16: // 16 bpp (1 channel - half float)
case PIXELFORMAT_UNCOMPRESSED_R32: // 32 bpp (1 channel - float)
@ -547,21 +552,20 @@ void SetWindowIcons(Image *images, int count)
if ((images == NULL) || (count <= 0))
{
RGFW_window_setIcon(platform.window, NULL, RGFW_AREA(0, 0), 0);
} {
Image* bigIcon = NULL;
Image* smallIcon = NULL;
}
else
{
Image *bigIcon = NULL;
Image *smallIcon = NULL;
for (size_t i = 0; i < count; i++) {
if (bigIcon == NULL || (images[i].width > bigIcon->width && images[i].height > bigIcon->height))
bigIcon = &images[i];
if (smallIcon == NULL || (images[i].width < smallIcon->width && images[i].height > smallIcon->height))
smallIcon = &images[i];
for (int i = 0; i < count; i++)
{
if ((bigIcon == NULL) || ((images[i].width > bigIcon->width) && (images[i].height > bigIcon->height))) bigIcon = &images[i];
if ((smallIcon == NULL) || ((images[i].width < smallIcon->width) && (images[i].height > smallIcon->height))) smallIcon = &images[i];
}
if (smallIcon != NULL)
RGFW_window_setIconEx(platform.window, smallIcon->data, RGFW_AREA(smallIcon->width, smallIcon->height), RGFW_formatToChannels(smallIcon->format), RGFW_iconWindow);
if (bigIcon != NULL)
RGFW_window_setIconEx(platform.window, bigIcon->data, RGFW_AREA(bigIcon->width, bigIcon->height), RGFW_formatToChannels(bigIcon->format), RGFW_iconTaskbar);
if (smallIcon != NULL) RGFW_window_setIconEx(platform.window, smallIcon->data, RGFW_AREA(smallIcon->width, smallIcon->height), RGFW_formatToChannels(smallIcon->format), RGFW_iconWindow);
if (bigIcon != NULL) RGFW_window_setIconEx(platform.window, bigIcon->data, RGFW_AREA(bigIcon->width, bigIcon->height), RGFW_formatToChannels(bigIcon->format), RGFW_iconTaskbar);
}
}
@ -581,7 +585,7 @@ void SetWindowPosition(int x, int y)
// Set monitor for the current window
void SetWindowMonitor(int monitor)
{
RGFW_window_moveToMonitor(platform.window, RGFW_getMonitors()[monitor]);
RGFW_window_moveToMonitor(platform.window, RGFW_getMonitors(NULL)[monitor]);
}
// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
@ -624,7 +628,8 @@ void SetWindowFocused(void)
// Get native window handle
void *GetWindowHandle(void)
{
#ifdef RGFW_WEBASM
if (platform.window == NULL) return NULL;
#ifdef RGFW_WASM
return (void *)platform.window->src.ctx;
#else
return (void *)platform.window->src.window;
@ -637,7 +642,7 @@ int GetMonitorCount(void)
#define MAX_MONITORS_SUPPORTED 6
int count = MAX_MONITORS_SUPPORTED;
RGFW_monitor *mons = RGFW_getMonitors();
RGFW_monitor *mons = RGFW_getMonitors(NULL);
for (int i = 0; i < 6; i++)
{
@ -651,11 +656,14 @@ int GetMonitorCount(void)
return count;
}
// Get number of monitors
// Get current monitor where window is placed
int GetCurrentMonitor(void)
{
RGFW_monitor *mons = RGFW_getMonitors();
RGFW_monitor mon = RGFW_window_getMonitor(platform.window);
RGFW_monitor *mons = RGFW_getMonitors(NULL);
RGFW_monitor mon = { 0 };
if (platform.window) mon = RGFW_window_getMonitor(platform.window);
else mon = RGFW_getPrimaryMonitor();
for (int i = 0; i < 6; i++)
{
@ -668,7 +676,7 @@ int GetCurrentMonitor(void)
// Get selected monitor position
Vector2 GetMonitorPosition(int monitor)
{
RGFW_monitor *mons = RGFW_getMonitors();
RGFW_monitor *mons = RGFW_getMonitors(NULL);
return (Vector2){ (float)mons[monitor].x, (float)mons[monitor].y };
}
@ -676,7 +684,7 @@ Vector2 GetMonitorPosition(int monitor)
// Get selected monitor width (currently used by monitor)
int GetMonitorWidth(int monitor)
{
RGFW_monitor *mons = RGFW_getMonitors();
RGFW_monitor *mons = RGFW_getMonitors(NULL);
return mons[monitor].mode.area.w;
}
@ -684,7 +692,7 @@ int GetMonitorWidth(int monitor)
// Get selected monitor height (currently used by monitor)
int GetMonitorHeight(int monitor)
{
RGFW_monitor *mons = RGFW_getMonitors();
RGFW_monitor *mons = RGFW_getMonitors(NULL);
return mons[monitor].mode.area.h;
}
@ -692,7 +700,7 @@ int GetMonitorHeight(int monitor)
// Get selected monitor physical width in millimetres
int GetMonitorPhysicalWidth(int monitor)
{
RGFW_monitor *mons = RGFW_getMonitors();
RGFW_monitor *mons = RGFW_getMonitors(NULL);
return mons[monitor].physW;
}
@ -700,7 +708,7 @@ int GetMonitorPhysicalWidth(int monitor)
// Get selected monitor physical height in millimetres
int GetMonitorPhysicalHeight(int monitor)
{
RGFW_monitor *mons = RGFW_getMonitors();
RGFW_monitor *mons = RGFW_getMonitors(NULL);
return (int)mons[monitor].physH;
}
@ -708,7 +716,7 @@ int GetMonitorPhysicalHeight(int monitor)
// Get selected monitor refresh rate
int GetMonitorRefreshRate(int monitor)
{
RGFW_monitor *mons = RGFW_getMonitors();
RGFW_monitor *mons = RGFW_getMonitors(NULL);
return (int)mons[monitor].mode.refreshRate;
}
@ -716,7 +724,7 @@ int GetMonitorRefreshRate(int monitor)
// Get the human-readable, UTF-8 encoded name of the selected monitor
const char *GetMonitorName(int monitor)
{
RGFW_monitor *mons = RGFW_getMonitors();
RGFW_monitor *mons = RGFW_getMonitors(NULL);
return mons[monitor].name;
}
@ -724,15 +732,19 @@ const char *GetMonitorName(int monitor)
// Get window position XY on monitor
Vector2 GetWindowPosition(void)
{
if (platform.window == NULL) return (Vector2){ 0.0f, 0.0f };
return (Vector2){ (float)platform.window->r.x, (float)platform.window->r.y };
}
// Get window scale DPI factor for current monitor
Vector2 GetWindowScaleDPI(void)
{
RGFW_monitor monitor = RGFW_window_getMonitor(platform.window);
RGFW_monitor monitor = { 0 };
return (Vector2){monitor.scaleX, monitor.scaleX};
if (platform.window) monitor = RGFW_window_getMonitor(platform.window);
else monitor = RGFW_getPrimaryMonitor();
return (Vector2){ monitor.scaleX, monitor.scaleX };
}
// Set clipboard text content
@ -748,7 +760,6 @@ const char *GetClipboardText(void)
return RGFW_readClipboard(NULL);
}
#if defined(SUPPORT_CLIPBOARD_IMAGE)
#if defined(_WIN32)
#define WIN32_CLIPBOARD_IMPLEMENTATION
@ -771,7 +782,7 @@ Image GetClipboardImage(void)
int width = 0;
int height = 0;
fileData = (void *)Win32GetClipboardImageData(&width, &height, &dataSize);
if (fileData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data");
else image = LoadImageFromMemory(".bmp", fileData, dataSize);
#else
@ -829,11 +840,7 @@ void SwapScreenBuffer(void)
// Get elapsed time measure in seconds since InitTimer()
double GetTime(void)
{
double time = 0.0;
unsigned long long int nanoSeconds = RGFW_getTimeNS();
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
return time;
return RGFW_getTime();
}
// Open URL with default system browser (if available)
@ -886,29 +893,30 @@ void SetMouseCursor(int cursor)
const char *GetKeyName(int key)
{
TRACELOG(LOG_WARNING, "GetKeyName() unsupported on target platform");
return "";
}
static KeyboardKey ConvertScancodeToKey(u32 keycode);
int RGFW_gpConvTable[18] = {
[RGFW_gamepadY] = GAMEPAD_BUTTON_RIGHT_FACE_UP,
[RGFW_gamepadB] = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT,
[RGFW_gamepadA] = GAMEPAD_BUTTON_RIGHT_FACE_DOWN,
[RGFW_gamepadX] = GAMEPAD_BUTTON_RIGHT_FACE_LEFT,
[RGFW_gamepadL1] = GAMEPAD_BUTTON_LEFT_TRIGGER_1,
[RGFW_gamepadR1] = GAMEPAD_BUTTON_RIGHT_TRIGGER_1,
[RGFW_gamepadL2] = GAMEPAD_BUTTON_LEFT_TRIGGER_2,
[RGFW_gamepadR2] = GAMEPAD_BUTTON_RIGHT_TRIGGER_2,
[RGFW_gamepadSelect] = GAMEPAD_BUTTON_MIDDLE_LEFT,
[RGFW_gamepadHome] = GAMEPAD_BUTTON_MIDDLE,
[RGFW_gamepadStart] = GAMEPAD_BUTTON_MIDDLE_RIGHT,
[RGFW_gamepadUp] = GAMEPAD_BUTTON_LEFT_FACE_UP,
[RGFW_gamepadRight] = GAMEPAD_BUTTON_LEFT_FACE_RIGHT,
[RGFW_gamepadDown] = GAMEPAD_BUTTON_LEFT_FACE_DOWN,
[RGFW_gamepadLeft] = GAMEPAD_BUTTON_LEFT_FACE_LEFT,
[RGFW_gamepadL3] = GAMEPAD_BUTTON_LEFT_THUMB,
[RGFW_gamepadR3] = GAMEPAD_BUTTON_RIGHT_THUMB,
[RGFW_gamepadY] = GAMEPAD_BUTTON_RIGHT_FACE_UP,
[RGFW_gamepadB] = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT,
[RGFW_gamepadA] = GAMEPAD_BUTTON_RIGHT_FACE_DOWN,
[RGFW_gamepadX] = GAMEPAD_BUTTON_RIGHT_FACE_LEFT,
[RGFW_gamepadL1] = GAMEPAD_BUTTON_LEFT_TRIGGER_1,
[RGFW_gamepadR1] = GAMEPAD_BUTTON_RIGHT_TRIGGER_1,
[RGFW_gamepadL2] = GAMEPAD_BUTTON_LEFT_TRIGGER_2,
[RGFW_gamepadR2] = GAMEPAD_BUTTON_RIGHT_TRIGGER_2,
[RGFW_gamepadSelect] = GAMEPAD_BUTTON_MIDDLE_LEFT,
[RGFW_gamepadHome] = GAMEPAD_BUTTON_MIDDLE,
[RGFW_gamepadStart] = GAMEPAD_BUTTON_MIDDLE_RIGHT,
[RGFW_gamepadUp] = GAMEPAD_BUTTON_LEFT_FACE_UP,
[RGFW_gamepadRight] = GAMEPAD_BUTTON_LEFT_FACE_RIGHT,
[RGFW_gamepadDown] = GAMEPAD_BUTTON_LEFT_FACE_DOWN,
[RGFW_gamepadLeft] = GAMEPAD_BUTTON_LEFT_FACE_LEFT,
[RGFW_gamepadL3] = GAMEPAD_BUTTON_LEFT_THUMB,
[RGFW_gamepadR3] = GAMEPAD_BUTTON_RIGHT_THUMB,
};
// Register all input events
@ -919,7 +927,7 @@ void PollInputEvents(void)
// because ProcessGestureEvent() is just called on an event, not every frame
UpdateGestures();
#endif
// Reset keys/chars pressed registered
CORE.Input.Keyboard.keyPressedQueueCount = 0;
CORE.Input.Keyboard.charPressedQueueCount = 0;
@ -979,19 +987,25 @@ void PollInputEvents(void)
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
}
if ((CORE.Window.eventWaiting) || (IsWindowState(FLAG_WINDOW_MINIMIZED) && !IsWindowState(FLAG_WINDOW_ALWAYS_RUN)))
{
RGFW_window_eventWait(platform.window, -1); // Wait for input events: keyboard/mouse/window events (callbacks) -> Update keys state
CORE.Time.previous = GetTime();
}
while (RGFW_window_checkEvent(platform.window))
{
RGFW_event *event = &platform.window->event;
// All input events can be processed after polling
switch (event->type)
switch (event->type)
{
case RGFW_quit:
if (CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN)
event->type = 0;
else
CORE.Window.shouldClose = true;
break;
case RGFW_mouseEnter: CORE.Input.Mouse.cursorOnScreen = true; break;
case RGFW_mouseLeave: CORE.Input.Mouse.cursorOnScreen = false; break;
case RGFW_quit:
event->type = 0;
CORE.Window.shouldClose = true;
return;
case RGFW_DND: // Dropped file
{
for (int i = 0; i < event->droppedFilesCount; i++)
@ -1005,7 +1019,7 @@ void PollInputEvents(void)
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event->droppedFiles[i]);
CORE.Window.dropFileCount++;
}
else if (CORE.Window.dropFileCount < 1024)
@ -1023,12 +1037,38 @@ void PollInputEvents(void)
case RGFW_windowResized:
{
SetupViewport(platform.window->r.w, platform.window->r.h);
CORE.Window.screen.width = platform.window->r.w;
CORE.Window.screen.height = platform.window->r.h;
// if we are doing automatic DPI scaling, then the "screen" size is divided by the window scale
if (IsWindowState(FLAG_WINDOW_HIGHDPI))
{
CORE.Window.screen.width = (int)(platform.window->r.w / GetWindowScaleDPI().x);
CORE.Window.screen.height = (int)(platform.window->r.h / GetWindowScaleDPI().y);
}
else
{
CORE.Window.screen.width = platform.window->r.w;
CORE.Window.screen.height = platform.window->r.h;
}
CORE.Window.currentFbo.width = platform.window->r.w;
CORE.Window.currentFbo.height = platform.window->r.h;
CORE.Window.resizedLastFrame = true;
} break;
case RGFW_windowMaximized:
{
CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // The window was maximized
} break;
case RGFW_windowMinimized:
{
CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; // The window was iconified
} break;
case RGFW_windowRestored:
{
if (RGFW_window_isMaximized(platform.window))
CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED; // The window was restored
if (RGFW_window_isMinimized(platform.window))
CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored
} break;
case RGFW_windowMoved:
{
CORE.Window.position.x = platform.window->r.x;
@ -1079,12 +1119,13 @@ void PollInputEvents(void)
{
CORE.Input.Mouse.currentWheelMove.y = event->scroll;
break;
} else CORE.Input.Mouse.currentWheelMove.y = 0;
}
else CORE.Input.Mouse.currentWheelMove.y = 0;
int btn = event->button;
if (btn == RGFW_mouseLeft) btn = 1;
else if (btn == RGFW_mouseRight) btn = 2;
else if (btn == RGFW_mouseMiddle) btn = 3;
else if (btn == RGFW_mouseMiddle) btn = 3;
CORE.Input.Mouse.currentButtonState[btn - 1] = 1;
CORE.Input.Touch.currentTouchState[btn - 1] = 1;
@ -1097,7 +1138,8 @@ void PollInputEvents(void)
{
CORE.Input.Mouse.currentWheelMove.y = event->scroll;
break;
} else CORE.Input.Mouse.currentWheelMove.y = 0;
}
else CORE.Input.Mouse.currentWheelMove.y = 0;
int btn = event->button;
if (btn == RGFW_mouseLeft) btn = 1;
@ -1127,19 +1169,21 @@ void PollInputEvents(void)
touchAction = 2;
} break;
case RGFW_gamepadConnected:
{
CORE.Input.Gamepad.ready[platform.window->event.gamepad] = true;
CORE.Input.Gamepad.axisCount[platform.window->event.gamepad] = platform.window->event.axisesCount;
CORE.Input.Gamepad.axisState[platform.window->event.gamepad][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
CORE.Input.Gamepad.axisState[platform.window->event.gamepad][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
strcpy(CORE.Input.Gamepad.name[platform.window->event.gamepad], RGFW_getGamepadName(platform.window, platform.window->event.gamepad));
break;
} break;
case RGFW_gamepadDisconnected:
{
CORE.Input.Gamepad.ready[platform.window->event.gamepad] = false;
break;
} break;
case RGFW_gamepadButtonPressed:
{
int button = RGFW_gpConvTable[event->button];
int button = RGFW_gpConvTable[event->button];
if (button >= 0)
{
@ -1149,7 +1193,7 @@ void PollInputEvents(void)
} break;
case RGFW_gamepadButtonReleased:
{
int button = RGFW_gpConvTable[event->button];
int button = RGFW_gpConvTable[event->button];
CORE.Input.Gamepad.currentButtonState[event->gamepad][button] = 0;
if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
@ -1157,33 +1201,34 @@ void PollInputEvents(void)
case RGFW_gamepadAxisMove:
{
int axis = -1;
float value = 0;
float value = 0;
switch(event->whichAxis)
switch(event->whichAxis)
{
case 0:
{
CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_LEFT_X] = event->axis[0].x / 100.0f;
CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_LEFT_Y] = event->axis[0].y / 100.0f;
} break;
case 1:
{
CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_RIGHT_X] = event->axis[1].x / 100.0f;
CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_RIGHT_Y] = event->axis[1].y / 100.0f;
} break;
case 2: axis = GAMEPAD_AXIS_LEFT_TRIGGER;
case 3:
{
case 0:
{
CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_LEFT_X] = event->axis[0].x / 100.0f;
CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_LEFT_Y] = event->axis[0].y / 100.0f;
} break;
case 1:
{
CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_RIGHT_X] = event->axis[1].x / 100.0f;
CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_RIGHT_Y] = event->axis[1].y / 100.0f;
} break;
case 2: axis = GAMEPAD_AXIS_LEFT_TRIGGER;
case 3:
{
if (axis == -1) axis = GAMEPAD_AXIS_RIGHT_TRIGGER;
int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER)? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2;
int pressed = (value > 0.1f);
CORE.Input.Gamepad.currentButtonState[event->gamepad][button] = pressed;
if (pressed) CORE.Input.Gamepad.lastButtonPressed = button;
else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
}
default: break;
}
int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER)? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2;
int pressed = (value > 0.1f);
CORE.Input.Gamepad.currentButtonState[event->gamepad][button] = pressed;
if (pressed) CORE.Input.Gamepad.lastButtonPressed = button;
else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
}
default: break;
}
} break;
default: break;
}
@ -1239,7 +1284,7 @@ int InitPlatform(void)
}
if ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0)
{
{
CORE.Window.fullscreen = true;
flags |= RGFW_windowedFullscreen;
}
@ -1251,44 +1296,51 @@ int InitPlatform(void)
if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) flags |= RGFW_windowHide;
if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) flags |= RGFW_windowMaximize;
// NOTE: Some OpenGL context attributes must be set before window creation
// Check selection OpenGL version
if (rlGetVersion() == RL_OPENGL_21)
{
if (rlGetVersion() == RL_OPENGL_21)
{
RGFW_setGLHint(RGFW_glMajor, 2);
RGFW_setGLHint(RGFW_glMinor, 1);
}
else if (rlGetVersion() == RL_OPENGL_33)
{
RGFW_setGLHint(RGFW_glCore, 3);
}
else if (rlGetVersion() == RL_OPENGL_33)
{
RGFW_setGLHint(RGFW_glMajor, 3);
RGFW_setGLHint(RGFW_glMinor, 3);
}
else if (rlGetVersion() == RL_OPENGL_43)
{
RGFW_setGLHint(RGFW_glCore, 3);
}
else if (rlGetVersion() == RL_OPENGL_43)
{
RGFW_setGLHint(RGFW_glMajor, 4);
RGFW_setGLHint(RGFW_glMinor, 3);
}
if (CORE.Window.flags & FLAG_MSAA_4X_HINT) RGFW_setGLHint(RGFW_glSamples, 4);
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) flags |= RGFW_windowFocusOnShow | RGFW_windowFocus;
platform.window = RGFW_createWindow(CORE.Window.title, RGFW_RECT(0, 0, CORE.Window.screen.width, CORE.Window.screen.height), flags);
platform.mon.mode.area.w = 0;
if (platform.window != NULL)
{
// NOTE: RGFW's exit key is distinct from raylib's exit key (which can
// be set with SetExitKey()) and defaults to Escape
platform.window->exitKey = RGFW_keyNULL;
}
#ifndef PLATFORM_WEB_RGFW
RGFW_area screenSize = RGFW_getScreenSize();
CORE.Window.display.width = screenSize.w;
CORE.Window.display.height = screenSize.h;
#else
CORE.Window.display.width = CORE.Window.screen.width;
CORE.Window.display.width = CORE.Window.screen.width;
CORE.Window.display.height = CORE.Window.screen.height;
#endif
// TODO: Is this needed by raylib now?
// TODO: Is this needed by raylib now?
// If so, rcore_desktop_sdl should be updated too
//SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
if (CORE.Window.flags & FLAG_VSYNC_HINT) RGFW_window_swapInterval(platform.window, 1);
//SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
if (CORE.Window.flags & FLAG_VSYNC_HINT) RGFW_window_swapInterval(platform.window, 1);
RGFW_window_makeCurrent(platform.window);
// Check surface and context activation
@ -1338,14 +1390,23 @@ int InitPlatform(void)
CORE.Storage.basePath = GetWorkingDirectory();
//----------------------------------------------------------------------------
#ifdef RGFW_X11
for (int i = 0; (i < 4) && (i < MAX_GAMEPADS); i++)
{
RGFW_registerGamepad(platform.window, i);
}
#if defined(RGFW_WAYLAND)
if (RGFW_useWaylandBool) TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Wayland): Initialized successfully");
else TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11 (fallback)): Initialized successfully");
#elif defined(RGFW_X11)
#if defined(__APPLE__)
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11 (MacOS)): Initialized successfully");
#else
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11): Initialized successfully");
#endif
#elif defined (RGFW_WINDOWS)
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Win32): Initialized successfully");
#elif defined(RGFW_WASM)
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - WASMs): Initialized successfully");
#elif defined(RGFW_MACOS)
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - MacOS): Initialized successfully");
#endif
TRACELOG(LOG_INFO, "PLATFORM: CUSTOM: Initialized successfully");
return 0;
}
@ -1359,6 +1420,6 @@ void ClosePlatform(void)
static KeyboardKey ConvertScancodeToKey(u32 keycode)
{
if (keycode > sizeof(keyMappingRGFW)/sizeof(unsigned short)) return 0;
return keyMappingRGFW[keycode];
return keyMappingRGFW[keycode];
}

View file

@ -52,13 +52,27 @@
#ifndef SDL_ENABLE_OLD_NAMES
#define SDL_ENABLE_OLD_NAMES // Just in case we're on SDL3, we need some in-between compatibily
#endif
#include "SDL.h" // SDL base library (window/rendered, input, timing... functionality)
// SDL base library (window/rendered, input, timing... functionality)
#ifdef USING_SDL3_PROJECT
#include "SDL3/SDL.h"
#elif USING_SDL2_PROJECT
#include "SDL2/SDL.h"
#else
#include "SDL.h"
#endif
#if defined(GRAPHICS_API_OPENGL_ES2)
// It seems it does not need to be included to work
//#include "SDL_opengles2.h"
#else
#include "SDL_opengl.h" // SDL OpenGL functionality (if required, instead of internal renderer)
// SDL OpenGL functionality (if required, instead of internal renderer)
#ifdef USING_SDL3_PROJECT
#include "SDL3/SDL_opengl.h"
#elif USING_SDL2_PROJECT
#include "SDL2/SDL_opengl.h"
#else
#include "SDL_opengl.h"
#endif
#endif
//----------------------------------------------------------------------------------
@ -238,8 +252,7 @@ static const int CursorsLUT[] = {
//SDL_SYSTEM_CURSOR_WAITARROW, // No equivalent implemented on MouseCursor enum on raylib.h
};
// SDL3 Migration Layer made to avoid `ifdefs` inside functions when we can.
// SDL3 Migration Layer made to avoid 'ifdefs' inside functions when we can.
#if defined(PLATFORM_DESKTOP_SDL3)
// SDL3 Migration:
@ -290,13 +303,13 @@ int SDL_GetNumVideoDisplays(void)
int monitorCount = 0;
SDL_DisplayID *displays = SDL_GetDisplays(&monitorCount);
// Safe because If `mem` is NULL, SDL_free does nothing
// Safe because If 'mem' is NULL, SDL_free does nothing
SDL_free(displays);
return monitorCount;
}
// SLD3 Migration: To emulate SDL2 this function should return `SDL_DISABLE` or `SDL_ENABLE`
// SLD3 Migration: To emulate SDL2 this function should return 'SDL_DISABLE' or 'SDL_ENABLE'
// representing the *processing state* of the event before this function makes any changes to it
Uint8 SDL_EventState(Uint32 type, int state)
{
@ -424,6 +437,8 @@ void ClosePlatform(void); // Close platform
static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode); // Help convert SDL scancodes to raylib key
static int GetCodepointNextSDL(const char *text, int *codepointSize); // Get next codepoint in a byte sequence and bytes processed
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
@ -508,7 +523,7 @@ void MinimizeWindow(void)
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) == 0) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED;
}
// Set window state: not minimized/maximized
// Restore window from being minimized/maximized
void RestoreWindow(void)
{
SDL_RestoreWindow(platform.window);
@ -518,6 +533,8 @@ void RestoreWindow(void)
// Set window configuration state using flags
void SetWindowState(unsigned int flags)
{
if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
CORE.Window.flags |= flags;
if (flags & FLAG_VSYNC_HINT)
@ -563,7 +580,7 @@ void SetWindowState(unsigned int flags)
if (flags & FLAG_WINDOW_UNFOCUSED)
{
// NOTE: To be able to implement this part it seems that we should
// do it ourselves, via `Windows.h`, `X11/Xlib.h` or even `Cocoa.h`
// do it ourselves, via 'windows.h', 'X11/Xlib.h' or even 'Cocoa.h'
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_UNFOCUSED is not supported on PLATFORM_DESKTOP_SDL");
}
if (flags & FLAG_WINDOW_TOPMOST)
@ -702,70 +719,84 @@ void SetWindowIcon(Image image)
switch (image.format)
{
case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
{
rmask = 0xFF, gmask = 0;
bmask = 0, amask = 0;
depth = 8, pitch = image.width;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
{
rmask = 0xFF, gmask = 0xFF00;
bmask = 0, amask = 0;
depth = 16, pitch = image.width*2;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
{
rmask = 0xF800, gmask = 0x07E0;
bmask = 0x001F, amask = 0;
depth = 16, pitch = image.width*2;
break;
case PIXELFORMAT_UNCOMPRESSED_R8G8B8: // Uses BGR for 24-bit
rmask = 0x0000FF, gmask = 0x00FF00;
bmask = 0xFF0000, amask = 0;
} break;
case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
{
// WARNING: SDL2 could be using BGR but SDL3 RGB
rmask = 0xFF0000, gmask = 0x00FF00;
bmask = 0x0000FF, amask = 0;
depth = 24, pitch = image.width*3;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
{
rmask = 0xF800, gmask = 0x07C0;
bmask = 0x003E, amask = 0x0001;
depth = 16, pitch = image.width*2;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
{
rmask = 0xF000, gmask = 0x0F00;
bmask = 0x00F0, amask = 0x000F;
depth = 16, pitch = image.width*2;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
{
rmask = 0xFF000000, gmask = 0x00FF0000;
bmask = 0x0000FF00, amask = 0x000000FF;
depth = 32, pitch = image.width*4;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R32:
{
rmask = 0xFFFFFFFF, gmask = 0;
bmask = 0, amask = 0;
depth = 32, pitch = image.width*4;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
{
rmask = 0xFFFFFFFF, gmask = 0xFFFFFFFF;
bmask = 0xFFFFFFFF, amask = 0;
depth = 96, pitch = image.width*12;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
{
rmask = 0xFFFFFFFF, gmask = 0xFFFFFFFF;
bmask = 0xFFFFFFFF, amask = 0xFFFFFFFF;
depth = 128, pitch = image.width*16;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R16:
{
rmask = 0xFFFF, gmask = 0;
bmask = 0, amask = 0;
depth = 16, pitch = image.width*2;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
{
rmask = 0xFFFF, gmask = 0xFFFF;
bmask = 0xFFFF, amask = 0;
depth = 48, pitch = image.width*6;
break;
} break;
case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
{
rmask = 0xFFFF, gmask = 0xFFFF;
bmask = 0xFFFF, amask = 0xFFFF;
depth = 64, pitch = image.width*8;
break;
} break;
default: return; // Compressed formats are not supported
}
@ -914,7 +945,7 @@ int GetMonitorCount(void)
return monitorCount;
}
// Get number of monitors
// Get current monitor where window is placed
int GetCurrentMonitor(void)
{
int currentMonitor = 0;
@ -1137,13 +1168,13 @@ Image GetClipboardImage(void)
image = LoadImageFromMemory(imageExtensions[i], fileData, dataSize);
if (IsImageValid(image))
{
TRACELOG(LOG_INFO, "Clipboard image: Got image from clipboard as a `%s` successfully", imageExtensions[i]);
TRACELOG(LOG_INFO, "Clipboard: Got image from clipboard successfully: %s", imageExtensions[i]);
return image;
}
}
}
if (!IsImageValid(image)) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data. Error: %s", SDL_GetError());
if (!IsImageValid(image)) TRACELOG(LOG_WARNING, "Clipboard: Couldn't get clipboard data. ERROR: %s", SDL_GetError());
#endif
return image;
@ -1349,7 +1380,7 @@ void PollInputEvents(void)
for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i];
// Map touch position to mouse position for convenience
CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
if (CORE.Input.Touch.pointCount == 0) CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
int touchAction = -1; // 0-TOUCH_ACTION_UP, 1-TOUCH_ACTION_DOWN, 2-TOUCH_ACTION_MOVE
bool realTouch = false; // Flag to differentiate real touch gestures from mouse ones
@ -1451,8 +1482,17 @@ void PollInputEvents(void)
const int width = event.window.data1;
const int height = event.window.data2;
SetupViewport(width, height);
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
// if we are doing automatic DPI scaling, then the "screen" size is divided by the window scale
if (IsWindowState(FLAG_WINDOW_HIGHDPI))
{
CORE.Window.screen.width = (int)(width / GetWindowScaleDPI().x);
CORE.Window.screen.height = (int)(height / GetWindowScaleDPI().y);
}
else
{
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
}
CORE.Window.currentFbo.width = width;
CORE.Window.currentFbo.height = height;
CORE.Window.resizedLastFrame = true;
@ -1576,13 +1616,18 @@ void PollInputEvents(void)
{
// NOTE: event.text.text data comes an UTF-8 text sequence but we register codepoints (int)
int codepointSize = 0;
// Check if there is space available in the queue
if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
{
// Add character (codepoint) to the queue
CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = GetCodepointNext(event.text.text, &codepointSize);
#if defined(PLATFORM_DESKTOP_SDL3)
unsigned int textLen = strlen(event.text.text);
unsigned int codepoint = (unsigned int)SDL_StepUTF8(&event.text.text, textLen);
#else
int codepointSize = 0;
int codepoint = GetCodepointNextSDL(event.text.text, &codepointSize);
#endif
CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = codepoint;
CORE.Input.Keyboard.charPressedQueueCount++;
}
} break;
@ -1661,7 +1706,7 @@ void PollInputEvents(void)
{
int jid = event.jdevice.which; // Joystick device index
if (!CORE.Input.Gamepad.ready[jid] && (jid < MAX_GAMEPADS))
if (CORE.Input.Gamepad.ready[jid] && (jid < MAX_GAMEPADS))
{
platform.gamepad[jid] = SDL_GameControllerOpen(jid);
platform.gamepadId[jid] = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[jid]));
@ -1672,8 +1717,8 @@ void PollInputEvents(void)
CORE.Input.Gamepad.axisCount[jid] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[jid]));
CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH);
strncpy(CORE.Input.Gamepad.name[jid], SDL_GameControllerNameForIndex(jid), MAX_GAMEPAD_NAME_LENGTH - 1);
CORE.Input.Gamepad.name[jid][MAX_GAMEPAD_NAME_LENGTH - 1] = '\0';
}
else
{
@ -1800,7 +1845,7 @@ void PollInputEvents(void)
{
if (platform.gamepadId[i] == event.jaxis.which)
{
// SDL axis value range is -32768 to 32767, we normalize it to RayLib's -1.0 to 1.0f range
// SDL axis value range is -32768 to 32767, we normalize it to raylib's -1.0 to 1.0f range
float value = event.jaxis.value/(float)32767;
CORE.Input.Gamepad.axisState[i][axis] = value;
@ -2068,4 +2113,42 @@ static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode)
return KEY_NULL; // No equivalent key in Raylib
}
// EOF
// Get next codepoint in a byte sequence and bytes processed
static int GetCodepointNextSDL(const char *text, int *codepointSize)
{
const char *ptr = text;
int codepoint = 0x3f; // Codepoint (defaults to '?')
*codepointSize = 1;
// Get current codepoint and bytes processed
if (0xf0 == (0xf8 & ptr[0]))
{
// 4 byte UTF-8 codepoint
if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80) || ((ptr[3] & 0xC0) ^ 0x80)) { return codepoint; } // 10xxxxxx checks
codepoint = ((0x07 & ptr[0]) << 18) | ((0x3f & ptr[1]) << 12) | ((0x3f & ptr[2]) << 6) | (0x3f & ptr[3]);
*codepointSize = 4;
}
else if (0xe0 == (0xf0 & ptr[0]))
{
// 3 byte UTF-8 codepoint */
if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } // 10xxxxxx checks
codepoint = ((0x0f & ptr[0]) << 12) | ((0x3f & ptr[1]) << 6) | (0x3f & ptr[2]);
*codepointSize = 3;
}
else if (0xc0 == (0xe0 & ptr[0]))
{
// 2 byte UTF-8 codepoint
if ((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } // 10xxxxxx checks
codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]);
*codepointSize = 2;
}
else if (0x00 == (0x80 & ptr[0]))
{
// 1 byte UTF-8 codepoint
codepoint = ptr[0];
*codepointSize = 1;
}
return codepoint;
}

View file

@ -48,11 +48,11 @@
*
**********************************************************************************************/
#include <fcntl.h> // POSIX file control definitions - open(), creat(), fcntl()
#include <unistd.h> // POSIX standard function definitions - read(), close(), STDIN_FILENO
#include <termios.h> // POSIX terminal control definitions - tcgetattr(), tcsetattr()
#include <pthread.h> // POSIX threads management (inputs reading)
#include <dirent.h> // POSIX directory browsing
#include <fcntl.h> // POSIX file control definitions - open(), creat(), fcntl()
#include <unistd.h> // POSIX standard function definitions - read(), close(), STDIN_FILENO
#include <termios.h> // POSIX terminal control definitions - tcgetattr(), tcsetattr()
#include <pthread.h> // POSIX threads management (inputs reading)
#include <dirent.h> // POSIX directory browsing
#include <sys/ioctl.h> // Required for: ioctl() - UNIX System call for device-specific input/output operations
#include <linux/kd.h> // Linux: KDSKBMODE, K_MEDIUMRAM constants definition
@ -71,6 +71,14 @@
#include "EGL/egl.h" // Native platform windowing system interface
#include "EGL/eglext.h" // EGL extensions
// NOTE: DRM cache enables triple buffered DRM caching
#if defined(SUPPORT_DRM_CACHE)
#include <poll.h> // Required for: drmHandleEvent() poll
#include <errno.h> // Required for: EBUSY, EAGAIN
#define MAX_DRM_CACHED_BUFFERS 3
#endif // SUPPORT_DRM_CACHE
#ifndef EGL_OPENGL_ES3_BIT
#define EGL_OPENGL_ES3_BIT 0x40
#endif
@ -78,18 +86,16 @@
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define USE_LAST_TOUCH_DEVICE // When multiple touchscreens are connected, only use the one with the highest event<N> number
#define USE_LAST_TOUCH_DEVICE // When multiple touchscreens are connected, only use the one with the highest event<N> number
#define DEFAULT_EVDEV_PATH "/dev/input/" // Path to the linux input events
#define DEFAULT_EVDEV_PATH "/dev/input/" // Path to the linux input events
// So actually the biggest key is KEY_CNT but we only really map the keys up to
// KEY_ALS_TOGGLE
// Actually biggest key is KEY_CNT but we only really map the keys up to KEY_ALS_TOGGLE
#define KEYMAP_SIZE KEY_ALS_TOGGLE
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
typedef struct {
// Display data
int fd; // File descriptor for /dev/dri/...
@ -124,11 +130,23 @@ typedef struct {
// Gamepad data
int gamepadStreamFd[MAX_GAMEPADS]; // Gamepad device file descriptor
int gamepadAbsAxisRange[MAX_GAMEPADS][MAX_GAMEPAD_AXIS][2]; // [0] = min, [1] = range value of the axis
int gamepadAbsAxisRange[MAX_GAMEPADS][MAX_GAMEPAD_AXES][2]; // [0] = min, [1] = range value of the axes
int gamepadAbsAxisMap[MAX_GAMEPADS][ABS_CNT]; // Maps the axes gamepads from the evdev api to a sequential one
int gamepadCount; // The number of gamepads registered
} PlatformData;
#if defined(SUPPORT_DRM_CACHE)
typedef struct {
struct gbm_bo *bo; // Graphics buffer object
uint32_t fbId; // DRM framebuffer ID
} FramebufferCache;
static FramebufferCache fbCache[MAX_DRM_CACHED_BUFFERS] = { 0 };
static volatile int fbCacheCount = 0;
static volatile bool pendingFlip = false;
static bool crtcSet = false;
#endif // SUPPORT_DRM_CACHE
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
@ -277,7 +295,7 @@ void MinimizeWindow(void)
TRACELOG(LOG_WARNING, "MinimizeWindow() not available on target platform");
}
// Set window state: not minimized/maximized
// Restore window from being minimized/maximized
void RestoreWindow(void)
{
TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform");
@ -371,7 +389,7 @@ int GetMonitorCount(void)
return 1;
}
// Get number of monitors
// Get current monitor where window is placed
int GetCurrentMonitor(void)
{
TRACELOG(LOG_WARNING, "GetCurrentMonitor() not implemented on target platform");
@ -551,6 +569,212 @@ void DisableCursor(void)
CORE.Input.Mouse.cursorHidden = true;
}
#if defined(SUPPORT_DRM_CACHE)
// Destroy cached framebuffer callback, set by gbm_bo_set_user_data()
static void DestroyFrameBufferCallback(struct gbm_bo *bo, void *data)
{
uint32_t fbId = (uintptr_t)data;
// Remove from cache
for (int i = 0; i < fbCacheCount; i++)
{
if (fbCache[i].bo == bo)
{
TRACELOG(LOG_INFO, "DISPLAY: DRM: Framebuffer removed [%u]", (uintptr_t)fbId);
drmModeRmFB(platform.fd, fbCache[i].fbId); // Release DRM FB
// Shift remaining entries
for (int j = i; j < fbCacheCount - 1; j++) fbCache[j] = fbCache[j + 1];
fbCacheCount--;
break;
}
}
}
// Create or retrieve cached DRM FB for BO
static uint32_t GetOrCreateFbForBo(struct gbm_bo *bo)
{
// Try to find existing cache entry
for (int i = 0; i < fbCacheCount; i++)
{
if (fbCache[i].bo == bo) return fbCache[i].fbId;
}
// Create new entry if cache not full
if (fbCacheCount >= MAX_DRM_CACHED_BUFFERS) return 0; // FB cache full
uint32_t handle = gbm_bo_get_handle(bo).u32;
uint32_t stride = gbm_bo_get_stride(bo);
uint32_t width = gbm_bo_get_width(bo);
uint32_t height = gbm_bo_get_height(bo);
uint32_t fbId = 0;
if (drmModeAddFB(platform.fd, width, height, 24, 32, stride, handle, &fbId)) return 0;
// Store in cache
fbCache[fbCacheCount] = (FramebufferCache){ .bo = bo, .fbId = fbId };
fbCacheCount++;
// Set destroy callback to auto-cleanup
gbm_bo_set_user_data(bo, (void *)(uintptr_t)fbId, DestroyFrameBufferCallback);
TRACELOG(LOG_INFO, "DISPLAY: DRM: Added new buffer object [%u]" , (uintptr_t)fbId);
return fbId;
}
// Renders a blank frame to allocate initial buffers
// TODO: WARNING: Platform layers do not include OpenGL code!
void RenderBlankFrame()
{
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(platform.device, platform.surface);
glFinish(); // Ensure the buffer is processed
}
// Initialize with first buffer only
int InitSwapScreenBuffer()
{
if (!platform.gbmSurface || (platform.fd < 0))
{
TRACELOG(LOG_ERROR, "DISPLAY: DRM: Swap buffers can not be initialized");
return -1;
}
// Render a blank frame to allocate buffers
RenderBlankFrame();
// Get first buffer
struct gbm_bo *bo = gbm_surface_lock_front_buffer(platform.gbmSurface);
if (!bo)
{
TRACELOG(LOG_ERROR, "DISPLAY: DRM: Failed to lock initial swap buffer");
return -1;
}
// Create FB for first buffer
uint32_t fbId = GetOrCreateFbForBo(bo);
if (!fbId)
{
gbm_surface_release_buffer(platform.gbmSurface, bo);
return -1;
}
// Initial CRTC setup
if (drmModeSetCrtc(platform.fd, platform.crtc->crtc_id, fbId, 0, 0, &platform.connector->connector_id, 1, &platform.connector->modes[platform.modeIndex]))
{
TRACELOG(LOG_ERROR, "DISPLAY: DRM: Failed to initialize CRTC setup. ERROR: %s", strerror(errno));
gbm_surface_release_buffer(platform.gbmSurface, bo);
return -1;
}
// Keep first buffer locked until flipped
platform.prevBO = bo;
crtcSet = true;
return 0;
}
// Static page flip handler
// NOTE: Called once the drmModePageFlip() finished from the drmHandleEvent() context
static void PageFlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data)
{
// Unused inputs
(void)fd;
(void)frame;
(void)sec;
(void)usec;
pendingFlip = false;
struct gbm_bo *boToRelease = (struct gbm_bo *)data;
// Buffers are released after the flip completes (via page_flip_handler), ensuring they're no longer in use
// Prevents the GPU from writing to a buffer being scanned out
if (boToRelease) gbm_surface_release_buffer(platform.gbmSurface, boToRelease);
}
// Swap implementation with proper caching
void SwapScreenBuffer()
{
if (!crtcSet || !platform.gbmSurface) return;
static int loopCnt = 0;
static int errCnt[5] = {0};
loopCnt++;
// Call this only, if pendingFlip is not set
eglSwapBuffers(platform.device, platform.surface);
// Process pending events non-blocking
drmEventContext evctx = {
.version = DRM_EVENT_CONTEXT_VERSION,
.page_flip_handler = PageFlipHandler
};
struct pollfd pfd = { .fd = platform.fd, .events = POLLIN };
// Polling for event for 0ms
while (poll(&pfd, 1, 0) > 0) drmHandleEvent(platform.fd, &evctx);
// Skip if previous flip pending
if (pendingFlip)
{
errCnt[0]++; // Skip frame: flip pending
return;
}
// Get new front buffer
struct gbm_bo *nextBO = gbm_surface_lock_front_buffer(platform.gbmSurface);
if (!nextBO) // Failed to lock front buffer
{
errCnt[1]++;
return;
}
// Get FB ID (creates new one if needed)
uint32_t fbId = GetOrCreateFbForBo(nextBO);
if (!fbId)
{
gbm_surface_release_buffer(platform.gbmSurface, nextBO);
errCnt[2]++;
return;
}
// Attempt page flip
// NOTE: rmModePageFlip() schedules a buffer-flip for the next vblank and then notifies us about it.
// It takes a CRTC-id, fb-id and an arbitrary data-pointer and then schedules the page-flip.
// This is fully asynchronous and when the page-flip happens, the DRM-fd will become readable and we can call drmHandleEvent().
// This will read all vblank/page-flip events and call our modeset_page_flip_event() callback with the data-pointer that we passed to drmModePageFlip().
// We simply call modeset_draw_dev() then so the next frame is rendered... returns immediately.
if (drmModePageFlip(platform.fd, platform.crtc->crtc_id, fbId, DRM_MODE_PAGE_FLIP_EVENT, platform.prevBO))
{
if (errno == EBUSY) errCnt[3]++; // Display busy - skip flip
else errCnt[4]++; // Page flip failed
gbm_surface_release_buffer(platform.gbmSurface, nextBO);
return;
}
// Success: update state
pendingFlip = true;
platform.prevBO = nextBO;
/*
// Some benchmarking code
if (loopCnt >= 600)
{
TRACELOG(LOG_INFO, "DRM: Error counters: %d, %d, %d, %d, %d, %d", errCnt[0], errCnt[1], errCnt[2], errCnt[3], errCnt[4], loopCnt);
for (int i = 0; i < 5; i++) errCnt[i] = 0;
loopCnt = 0;
}
*/
}
#else // !SUPPORT_DRM_CACHE
// Swap back buffer with front buffer (screen drawing)
void SwapScreenBuffer(void)
{
@ -580,6 +804,7 @@ void SwapScreenBuffer(void)
platform.prevBO = bo;
}
#endif // SUPPORT_DRM_CACHE
//----------------------------------------------------------------------------------
// Module Functions Definition: Misc
@ -735,20 +960,24 @@ int InitPlatform(void)
#if defined(DEFAULT_GRAPHIC_DEVICE_DRM)
platform.fd = open(DEFAULT_GRAPHIC_DEVICE_DRM, O_RDWR);
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: Default graphic device DRM opened successfully");
#else
TRACELOG(LOG_INFO, "DISPLAY: No graphic card set, trying platform-gpu-card");
TRACELOG(LOG_WARNING, "DISPLAY: No graphic card set, trying platform-gpu-card");
platform.fd = open("/dev/dri/by-path/platform-gpu-card", O_RDWR); // VideoCore VI (Raspberry Pi 4)
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: platform-gpu-card opened successfully");
if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
{
TRACELOG(LOG_INFO, "DISPLAY: Failed to open platform-gpu-card, trying card1");
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open platform-gpu-card, trying card1");
platform.fd = open("/dev/dri/card1", O_RDWR); // Other Embedded
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card1 opened successfully");
}
if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
{
TRACELOG(LOG_INFO, "DISPLAY: Failed to open graphic card1, trying card0");
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card1, trying card0");
platform.fd = open("/dev/dri/card0", O_RDWR); // VideoCore IV (Raspberry Pi 1-3)
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card0 opened successfully");
}
#endif
@ -906,7 +1135,7 @@ int InitPlatform(void)
EGL_BLUE_SIZE, 8, // BLUE color bit depth (alternative: 5)
EGL_ALPHA_SIZE, 8, // ALPHA bit depth (required for transparent framebuffer)
//EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI)
EGL_DEPTH_SIZE, 16, // Depth buffer size (Required to use Depth testing!)
EGL_DEPTH_SIZE, 24, // Depth buffer size (Required to use Depth testing!)
//EGL_STENCIL_SIZE, 8, // Stencil buffer size
EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA
EGL_SAMPLES, samples, // 4x Antialiasing if activated (Free on MALI GPUs)
@ -944,7 +1173,7 @@ int InitPlatform(void)
TRACELOG(LOG_TRACE, "DISPLAY: EGL configs available: %d", numConfigs);
EGLConfig *configs = RL_CALLOC(numConfigs, sizeof(*configs));
EGLConfig *configs = (EGLConfig *)RL_CALLOC(numConfigs, sizeof(*configs));
if (!configs)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get memory for EGL configs");
@ -1079,9 +1308,21 @@ int InitPlatform(void)
CORE.Storage.basePath = GetWorkingDirectory();
//----------------------------------------------------------------------------
#if defined(SUPPORT_DRM_CACHE)
if (InitSwapScreenBuffer() == 0)
{
TRACELOG(LOG_INFO, "PLATFORM: DRM: Initialized successfully");
return 0;
}
else
{
TRACELOG(LOG_INFO, "PLATFORM: DRM: Initialized failed");
return -1;
}
#else // !SUPPORT_DRM_CACHE
TRACELOG(LOG_INFO, "PLATFORM: DRM: Initialized successfully");
return 0;
#endif
}
// Close platform
@ -1370,7 +1611,7 @@ static void InitEvdevInput(void)
if ((strncmp("event", entity->d_name, strlen("event")) == 0) || // Search for devices named "event*"
(strncmp("mouse", entity->d_name, strlen("mouse")) == 0)) // Search for devices named "mouse*"
{
sprintf(path, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name);
snprintf(path, MAX_FILEPATH_LENGTH, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name);
ConfigureEvdevDevice(path); // Configure the device if appropriate
}
}
@ -1399,7 +1640,7 @@ static void ConfigureEvdevDevice(char *device)
int fd = open(device, O_RDONLY | O_NONBLOCK);
if (fd < 0)
{
TRACELOG(LOG_WARNING, "DRM: Failed to open input device: %s", device);
TRACELOG(LOG_WARNING, "SYSTEM: Failed to open input device: %s", device);
return;
}
@ -1456,7 +1697,7 @@ static void ConfigureEvdevDevice(char *device)
// matter if we support them
else if (hasAbsXY && TEST_BIT(keyBits, BTN_MOUSE)) isMouse = true;
// If any of the common joystick axis is present, we assume it's a gamepad
// If any of the common joystick axes are present, we assume it's a gamepad
else
{
for (int axis = (hasAbsXY? ABS_Z : ABS_X); axis < ABS_PRESSURE; axis++)
@ -1542,7 +1783,7 @@ static void ConfigureEvdevDevice(char *device)
if (absAxisCount > 0)
{
// TODO / NOTE
// So gamepad axis (as in the actual linux joydev.c) are just simply enumerated
// So gamepad axes (as in the actual linux joydev.c) are just simply enumerated
// and (at least for some input drivers like xpat) it's convention to use
// ABS_X, ABX_Y for one joystick ABS_RX, ABS_RY for the other and the Z axes for the
// shoulder buttons
@ -1677,7 +1918,7 @@ static void PollGamepadEvents(void)
TRACELOG(LOG_DEBUG, "INPUT: Gamepad %2i: Axis: %2i Value: %i", i, axisRaylib, event.value);
if (axisRaylib < MAX_GAMEPAD_AXIS)
if (axisRaylib < MAX_GAMEPAD_AXES)
{
int min = platform.gamepadAbsAxisRange[i][event.code][0];
int range = platform.gamepadAbsAxisRange[i][event.code][1];

View file

@ -114,7 +114,7 @@ void MinimizeWindow(void)
TRACELOG(LOG_WARNING, "MinimizeWindow() not available on target platform");
}
// Set window state: not minimized/maximized
// Restore window from being minimized/maximized
void RestoreWindow(void)
{
TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform");
@ -208,7 +208,7 @@ int GetMonitorCount(void)
return 1;
}
// Get number of monitors
// Get current monitor where window is placed
int GetCurrentMonitor(void)
{
TRACELOG(LOG_WARNING, "GetCurrentMonitor() not implemented on target platform");

Some files were not shown because too many files have changed in this diff Show more