mirror of
https://github.com/raysan5/raylib.git
synced 2025-12-17 20:05:35 +00:00
Merge branch 'master' into master
This commit is contained in:
@@ -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 & \
|
||||
|
||||
14
src/config.h
14
src/config.h
@@ -95,7 +95,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// rcore: Configuration values
|
||||
//------------------------------------------------------------------------------------
|
||||
#define MAX_FILEPATH_CAPACITY 8192 // Maximum file paths capacity
|
||||
@@ -104,7 +103,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 +135,8 @@
|
||||
|
||||
#define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported
|
||||
|
||||
#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
|
||||
#define RL_CULL_DISTANCE_NEAR 0.05 // Default projection matrix near cull distance
|
||||
#define RL_CULL_DISTANCE_FAR 4000.0 // Default projection matrix far cull distance
|
||||
|
||||
// Default shader vertex attribute locations
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0
|
||||
@@ -153,7 +152,6 @@
|
||||
#endif
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX 9
|
||||
|
||||
|
||||
// Default shader vertex attribute names to set location points
|
||||
// NOTE: When a new shader is loaded, the following locations are tried to be set for convenience
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION
|
||||
@@ -173,7 +171,6 @@
|
||||
#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1)
|
||||
#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2)
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module: rshapes - Configuration Flags
|
||||
//------------------------------------------------------------------------------------
|
||||
@@ -185,11 +182,10 @@
|
||||
//------------------------------------------------------------------------------------
|
||||
#define SPLINE_SEGMENT_DIVISIONS 24 // Spline segments subdivisions
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// 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
|
||||
@@ -213,7 +209,6 @@
|
||||
// If not defined, still some functions are supported: ImageFormat(), ImageCrop(), ImageToPOT()
|
||||
#define SUPPORT_IMAGE_MANIPULATION 1
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module: rtext - Configuration Flags
|
||||
//------------------------------------------------------------------------------------
|
||||
@@ -240,7 +235,6 @@
|
||||
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit()
|
||||
#define MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit()
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module: rmodels - Configuration Flags
|
||||
//------------------------------------------------------------------------------------
|
||||
|
||||
21393
src/external/RGFW.h
vendored
21393
src/external/RGFW.h
vendored
File diff suppressed because it is too large
Load Diff
462
src/external/dr_flac.h
vendored
462
src/external/dr_flac.h
vendored
@@ -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
899
src/external/dr_mp3.h
vendored
File diff suppressed because it is too large
Load Diff
492
src/external/dr_wav.h
vendored
492
src/external/dr_wav.h
vendored
File diff suppressed because it is too large
Load Diff
2115
src/external/glfw/src/mappings.h
vendored
2115
src/external/glfw/src/mappings.h
vendored
File diff suppressed because it is too large
Load Diff
4
src/external/jar_mod.h
vendored
4
src/external/jar_mod.h
vendored
@@ -1130,7 +1130,7 @@ static bool jar_mod_load( jar_mod_context_t * modctx, void * mod_data, int mod_d
|
||||
{
|
||||
if( modctx )
|
||||
{
|
||||
memcopy(&(modctx->song.title),modmemory,1084);
|
||||
memcopy(&(modctx->song), modmemory, 1084);
|
||||
|
||||
i = 0;
|
||||
modctx->number_of_channels = 0;
|
||||
@@ -1593,4 +1593,4 @@ void jar_mod_seek_start(jar_mod_context_t * ctx)
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#endif //end of header file
|
||||
#endif //end of header file
|
||||
|
||||
1813
src/external/miniaudio.h
vendored
1813
src/external/miniaudio.h
vendored
File diff suppressed because it is too large
Load Diff
46
src/external/qoaplay.c
vendored
46
src/external/qoaplay.c
vendored
@@ -46,7 +46,6 @@ typedef struct {
|
||||
unsigned int sample_position; // Current streaming sample position
|
||||
|
||||
unsigned char *buffer; // Buffer used to read samples from file/memory (used on decoding)
|
||||
unsigned int buffer_len; // Buffer length to read samples for streaming
|
||||
|
||||
short *sample_data; // Sample data decoded
|
||||
unsigned int sample_data_len; // Sample data decoded length
|
||||
@@ -111,7 +110,7 @@ qoaplay_desc *qoaplay_open(const char *path)
|
||||
qoa_ctx->file = file;
|
||||
qoa_ctx->file_data = NULL;
|
||||
qoa_ctx->file_data_size = 0;
|
||||
qoa_ctx->file_data_offset = 0;
|
||||
qoa_ctx->file_data_offset = first_frame_pos;
|
||||
qoa_ctx->first_frame_pos = first_frame_pos;
|
||||
|
||||
// Setup data pointers to previously allocated data
|
||||
@@ -128,34 +127,30 @@ qoaplay_desc *qoaplay_open(const char *path)
|
||||
// Open QOA file from memory, no FILE pointer required
|
||||
qoaplay_desc *qoaplay_open_memory(const unsigned char *data, int data_size)
|
||||
{
|
||||
// Read and decode the file header
|
||||
unsigned char header[QOA_MIN_FILESIZE];
|
||||
memcpy(header, data, QOA_MIN_FILESIZE);
|
||||
|
||||
qoa_desc qoa;
|
||||
unsigned int first_frame_pos = qoa_decode_header(header, QOA_MIN_FILESIZE, &qoa);
|
||||
if (data_size < QOA_MIN_FILESIZE) return NULL;
|
||||
unsigned int first_frame_pos = qoa_decode_header(data, QOA_MIN_FILESIZE, &qoa);
|
||||
if (!first_frame_pos) return NULL;
|
||||
|
||||
// Allocate one chunk of memory for the qoaplay_desc struct
|
||||
// + the sample data for one frame
|
||||
// + a buffer to hold one frame of encoded data
|
||||
unsigned int buffer_size = qoa_max_frame_size(&qoa);
|
||||
unsigned int sample_data_size = qoa.channels*QOA_FRAME_LEN*sizeof(short)*2;
|
||||
qoaplay_desc *qoa_ctx = QOA_MALLOC(sizeof(qoaplay_desc) + buffer_size + sample_data_size);
|
||||
qoaplay_desc *qoa_ctx = QOA_MALLOC(sizeof(qoaplay_desc) + sample_data_size + data_size);
|
||||
memset(qoa_ctx, 0, sizeof(qoaplay_desc));
|
||||
|
||||
qoa_ctx->file = NULL;
|
||||
|
||||
// Keep a copy of file data provided to be managed internally
|
||||
qoa_ctx->file_data = (unsigned char *)QOA_MALLOC(data_size);
|
||||
qoa_ctx->file_data = (((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc) + sample_data_size);
|
||||
memcpy(qoa_ctx->file_data, data, data_size);
|
||||
qoa_ctx->file_data_size = data_size;
|
||||
qoa_ctx->file_data_offset = 0;
|
||||
qoa_ctx->file_data_offset = first_frame_pos;
|
||||
qoa_ctx->first_frame_pos = first_frame_pos;
|
||||
|
||||
// Setup data pointers to previously allocated data
|
||||
qoa_ctx->buffer = ((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc);
|
||||
qoa_ctx->sample_data = (short *)(((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc) + buffer_size);
|
||||
qoa_ctx->buffer = NULL;
|
||||
qoa_ctx->sample_data = (short *)(((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc));
|
||||
|
||||
qoa_ctx->info.channels = qoa.channels;
|
||||
qoa_ctx->info.samplerate = qoa.samplerate;
|
||||
@@ -169,11 +164,7 @@ void qoaplay_close(qoaplay_desc *qoa_ctx)
|
||||
{
|
||||
if (qoa_ctx->file) fclose(qoa_ctx->file);
|
||||
|
||||
if ((qoa_ctx->file_data) && (qoa_ctx->file_data_size > 0))
|
||||
{
|
||||
QOA_FREE(qoa_ctx->file_data);
|
||||
qoa_ctx->file_data_size = 0;
|
||||
}
|
||||
qoa_ctx->file_data_size = 0;
|
||||
|
||||
QOA_FREE(qoa_ctx);
|
||||
}
|
||||
@@ -181,16 +172,23 @@ void qoaplay_close(qoaplay_desc *qoa_ctx)
|
||||
// Decode one frame from QOA data
|
||||
unsigned int qoaplay_decode_frame(qoaplay_desc *qoa_ctx)
|
||||
{
|
||||
if (qoa_ctx->file) qoa_ctx->buffer_len = fread(qoa_ctx->buffer, 1, qoa_max_frame_size(&qoa_ctx->info), qoa_ctx->file);
|
||||
unsigned char *buffer;
|
||||
unsigned int buffer_len;
|
||||
|
||||
if (qoa_ctx->file)
|
||||
{
|
||||
buffer = qoa_ctx->buffer;
|
||||
buffer_len = fread(buffer, 1, qoa_max_frame_size(&qoa_ctx->info), qoa_ctx->file);
|
||||
}
|
||||
else
|
||||
{
|
||||
qoa_ctx->buffer_len = qoa_max_frame_size(&qoa_ctx->info);
|
||||
memcpy(qoa_ctx->buffer, qoa_ctx->file_data + qoa_ctx->file_data_offset, qoa_ctx->buffer_len);
|
||||
qoa_ctx->file_data_offset += qoa_ctx->buffer_len;
|
||||
buffer = qoa_ctx->file_data + qoa_ctx->file_data_offset;
|
||||
buffer_len = qoa_max_frame_size(&qoa_ctx->info);
|
||||
qoa_ctx->file_data_offset += buffer_len;
|
||||
}
|
||||
|
||||
unsigned int frame_len;
|
||||
qoa_decode_frame(qoa_ctx->buffer, qoa_ctx->buffer_len, &qoa_ctx->info, qoa_ctx->sample_data, &frame_len);
|
||||
qoa_decode_frame(buffer, buffer_len, &qoa_ctx->info, qoa_ctx->sample_data, &frame_len);
|
||||
qoa_ctx->sample_data_pos = 0;
|
||||
qoa_ctx->sample_data_len = frame_len;
|
||||
|
||||
@@ -201,7 +199,7 @@ unsigned int qoaplay_decode_frame(qoaplay_desc *qoa_ctx)
|
||||
void qoaplay_rewind(qoaplay_desc *qoa_ctx)
|
||||
{
|
||||
if (qoa_ctx->file) fseek(qoa_ctx->file, qoa_ctx->first_frame_pos, SEEK_SET);
|
||||
else qoa_ctx->file_data_offset = 0;
|
||||
else qoa_ctx->file_data_offset = qoa_ctx->first_frame_pos;
|
||||
|
||||
qoa_ctx->sample_position = 0;
|
||||
qoa_ctx->sample_data_len = 0;
|
||||
|
||||
994
src/external/rl_gputex.h
vendored
994
src/external/rl_gputex.h
vendored
File diff suppressed because it is too large
Load Diff
42
src/external/rprand.h
vendored
42
src/external/rprand.h
vendored
@@ -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:
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
//----------------------------------------------------------------------------------
|
||||
@@ -801,6 +813,8 @@ int InitPlatform(void)
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_TOUCH_POINTS; i++) touchRaw.hoverPoints[i] = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1269,25 +1283,85 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
||||
}
|
||||
|
||||
// Register touch points count
|
||||
CORE.Input.Touch.pointCount = AMotionEvent_getPointerCount(event);
|
||||
touchRaw.pointCount = AMotionEvent_getPointerCount(event);
|
||||
|
||||
for (int i = 0; (i < CORE.Input.Touch.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
||||
for (int i = 0; (i < touchRaw.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
||||
{
|
||||
// Register touch points id
|
||||
CORE.Input.Touch.pointId[i] = AMotionEvent_getPointerId(event, i);
|
||||
touchRaw.pointId[i] = AMotionEvent_getPointerId(event, i);
|
||||
|
||||
// Register touch points position
|
||||
CORE.Input.Touch.position[i] = (Vector2){ AMotionEvent_getX(event, i), AMotionEvent_getY(event, i) };
|
||||
touchRaw.position[i] = (Vector2){ AMotionEvent_getX(event, i), AMotionEvent_getY(event, i) };
|
||||
|
||||
// Normalize CORE.Input.Touch.position[i] for CORE.Window.screen.width and CORE.Window.screen.height
|
||||
float widthRatio = (float)(CORE.Window.screen.width + CORE.Window.renderOffset.x)/(float)CORE.Window.display.width;
|
||||
float heightRatio = (float)(CORE.Window.screen.height + CORE.Window.renderOffset.y)/(float)CORE.Window.display.height;
|
||||
CORE.Input.Touch.position[i].x = CORE.Input.Touch.position[i].x*widthRatio - (float)CORE.Window.renderOffset.x/2;
|
||||
CORE.Input.Touch.position[i].y = CORE.Input.Touch.position[i].y*heightRatio - (float)CORE.Window.renderOffset.y/2;
|
||||
touchRaw.position[i].x = touchRaw.position[i].x*widthRatio - (float)CORE.Window.renderOffset.x/2;
|
||||
touchRaw.position[i].y = touchRaw.position[i].y*heightRatio - (float)CORE.Window.renderOffset.y/2;
|
||||
}
|
||||
|
||||
int32_t action = AMotionEvent_getAction(event);
|
||||
unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
|
||||
int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
||||
|
||||
if (flags == AMOTION_EVENT_ACTION_HOVER_ENTER)
|
||||
{
|
||||
// The new pointer is hover
|
||||
// So add it to hoverPoints
|
||||
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
||||
{
|
||||
if (touchRaw.hoverPoints[i] == -1)
|
||||
{
|
||||
touchRaw.hoverPoints[i] = touchRaw.pointId[pointerIndex];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags == AMOTION_EVENT_ACTION_POINTER_UP) || (flags == AMOTION_EVENT_ACTION_UP) || (flags == AMOTION_EVENT_ACTION_HOVER_EXIT))
|
||||
{
|
||||
// One of the touchpoints is released, remove it from touch point arrays
|
||||
if (flags == AMOTION_EVENT_ACTION_HOVER_EXIT)
|
||||
{
|
||||
// If the touchPoint is hover, remove it from hoverPoints
|
||||
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
||||
{
|
||||
if (touchRaw.hoverPoints[i] == touchRaw.pointId[pointerIndex])
|
||||
{
|
||||
touchRaw.hoverPoints[i] = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = pointerIndex; (i < touchRaw.pointCount - 1) && (i < MAX_TOUCH_POINTS - 1); i++)
|
||||
{
|
||||
touchRaw.pointId[i] = touchRaw.pointId[i+1];
|
||||
touchRaw.position[i] = touchRaw.position[i+1];
|
||||
}
|
||||
touchRaw.pointCount--;
|
||||
}
|
||||
|
||||
int pointCount = 0;
|
||||
for (int i = 0; (i < touchRaw.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
||||
{
|
||||
// If the touchPoint is hover, Ignore it
|
||||
bool hover = false;
|
||||
for (int j = 0; j < MAX_TOUCH_POINTS; j++)
|
||||
{
|
||||
// Check if the touchPoint is in hoverPointers
|
||||
if (touchRaw.hoverPoints[j] == touchRaw.pointId[i])
|
||||
{
|
||||
hover = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hover) continue;
|
||||
|
||||
CORE.Input.Touch.pointId[pointCount] = touchRaw.pointId[i];
|
||||
CORE.Input.Touch.position[pointCount] = touchRaw.position[i];
|
||||
pointCount++;
|
||||
}
|
||||
CORE.Input.Touch.pointCount = pointCount;
|
||||
|
||||
#if defined(SUPPORT_GESTURES_SYSTEM)
|
||||
GestureEvent gestureEvent = { 0 };
|
||||
@@ -1312,20 +1386,6 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
||||
ProcessGestureEvent(gestureEvent);
|
||||
#endif
|
||||
|
||||
int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
||||
|
||||
if (flags == AMOTION_EVENT_ACTION_POINTER_UP || flags == AMOTION_EVENT_ACTION_UP)
|
||||
{
|
||||
// One of the touchpoints is released, remove it from touch point arrays
|
||||
for (int i = pointerIndex; (i < CORE.Input.Touch.pointCount - 1) && (i < MAX_TOUCH_POINTS); i++)
|
||||
{
|
||||
CORE.Input.Touch.pointId[i] = CORE.Input.Touch.pointId[i+1];
|
||||
CORE.Input.Touch.position[i] = CORE.Input.Touch.position[i+1];
|
||||
}
|
||||
|
||||
CORE.Input.Touch.pointCount--;
|
||||
}
|
||||
|
||||
// When all touchpoints are tapped and released really quickly, this event is generated
|
||||
if (flags == AMOTION_EVENT_ACTION_CANCEL) CORE.Input.Touch.pointCount = 0;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**********************************************************************************************
|
||||
*
|
||||
* rcore_desktop - Functions to manage window, graphics device and inputs
|
||||
* rcore_desktop_glfw - Functions to manage window, graphics device and inputs
|
||||
*
|
||||
* PLATFORM: DESKTOP: GLFW
|
||||
* - Windows (Win32, Win64)
|
||||
@@ -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
|
||||
@@ -576,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++)
|
||||
{
|
||||
@@ -705,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)
|
||||
{
|
||||
@@ -713,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 *)
|
||||
@@ -1057,9 +1066,9 @@ double GetTime(void)
|
||||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
// NOTE: This function is only safe to use if you control the URL given.
|
||||
// A user could craft a malicious string performing another action.
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself.
|
||||
// NOTE: This function is only safe to use if you control the URL given
|
||||
// A user could craft a malicious string performing another action
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself
|
||||
// Ref: https://github.com/raysan5/raylib/issues/686
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
@@ -1121,7 +1130,7 @@ void SetMouseCursor(int cursor)
|
||||
}
|
||||
}
|
||||
|
||||
// Get physical key name.
|
||||
// Get physical key name
|
||||
const char *GetKeyName(int key)
|
||||
{
|
||||
return glfwGetKeyName(key, glfwGetKeyScancode(key));
|
||||
@@ -1238,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++)
|
||||
@@ -1246,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;
|
||||
@@ -1297,20 +1306,20 @@ static void SetDimensionsFromMonitor(GLFWmonitor *monitor)
|
||||
}
|
||||
|
||||
// Function wrappers around RL_*alloc macros, used by glfwInitAllocator() inside of InitPlatform()
|
||||
// We need to provide these because GLFWallocator expects function pointers with specific signatures.
|
||||
// Similar wrappers exist in utils.c but we cannot reuse them here due to declaration mismatch.
|
||||
// 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);
|
||||
@@ -1327,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__)
|
||||
@@ -1384,15 +1394,15 @@ int InitPlatform(void)
|
||||
// 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.
|
||||
// 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.
|
||||
// NOTE: This hint only has an effect on platforms where screen coordinates and pixels always map 1:1 such as Windows and X11.
|
||||
// On platforms like macOS the resolution of the framebuffer is changed independently of the window size.
|
||||
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // Scale content area based on the monitor content scale where window is placed on
|
||||
// Resize window content area based on the monitor content scale
|
||||
// NOTE: This hint only has an effect on platforms where screen coordinates and pixels always map 1:1 such as Windows and X11
|
||||
// On platforms like macOS the resolution of the framebuffer is changed independently of the window size
|
||||
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_SCALE_FRAMEBUFFER, GLFW_TRUE);
|
||||
#endif
|
||||
@@ -1411,8 +1421,8 @@ int InitPlatform(void)
|
||||
}
|
||||
|
||||
// NOTE: When asking for an OpenGL context version, most drivers provide the highest supported version
|
||||
// with backward compatibility to older OpenGL versions.
|
||||
// For example, if using OpenGL 1.1, driver can provide a 4.3 backwards compatible context.
|
||||
// with backward compatibility to older OpenGL versions
|
||||
// For example, if using OpenGL 1.1, driver can provide a 4.3 backwards compatible context
|
||||
|
||||
// Check selection OpenGL version
|
||||
if (rlGetVersion() == RL_OPENGL_21)
|
||||
@@ -1458,9 +1468,9 @@ int InitPlatform(void)
|
||||
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
|
||||
}
|
||||
|
||||
// NOTE: GLFW 3.4+ defers initialization of the Joystick subsystem on the first call to any Joystick related functions.
|
||||
// Forcing this initialization here avoids doing it on PollInputEvents() called by EndDrawing() after first frame has been just drawn.
|
||||
// The initialization will still happen and possible delays still occur, but before the window is shown, which is a nicer experience.
|
||||
// NOTE: GLFW 3.4+ defers initialization of the Joystick subsystem on the first call to any Joystick related functions
|
||||
// Forcing this initialization here avoids doing it on PollInputEvents() called by EndDrawing() after first frame has been just drawn
|
||||
// The initialization will still happen and possible delays still occur, but before the window is shown, which is a nicer experience
|
||||
// REF: https://github.com/raysan5/raylib/issues/1554
|
||||
glfwSetJoystickCallback(NULL);
|
||||
|
||||
@@ -1468,7 +1478,7 @@ int InitPlatform(void)
|
||||
if (CORE.Window.fullscreen)
|
||||
{
|
||||
// According to glfwCreateWindow(), if the user does not have a choice, fullscreen applications
|
||||
// should default to the primary monitor.
|
||||
// should default to the primary monitor
|
||||
|
||||
monitor = glfwGetPrimaryMonitor();
|
||||
if (!monitor)
|
||||
@@ -1482,8 +1492,8 @@ int InitPlatform(void)
|
||||
// Remember center for switching from fullscreen to window
|
||||
if ((CORE.Window.screen.height == CORE.Window.display.height) && (CORE.Window.screen.width == CORE.Window.display.width))
|
||||
{
|
||||
// If screen width/height equal to the display, we can't calculate the window pos for toggling full-screened/windowed.
|
||||
// Toggling full-screened/windowed with pos(0, 0) can cause problems in some platforms, such as X11.
|
||||
// If screen width/height equal to the display, we can't calculate the window pos for toggling full-screened/windowed
|
||||
// Toggling full-screened/windowed with pos(0, 0) can cause problems in some platforms, such as X11
|
||||
CORE.Window.position.x = CORE.Window.display.width/4;
|
||||
CORE.Window.position.y = CORE.Window.display.height/4;
|
||||
}
|
||||
@@ -1544,7 +1554,7 @@ int InitPlatform(void)
|
||||
// No-fullscreen window creation
|
||||
bool requestWindowedFullscreen = (CORE.Window.screen.height == 0) && (CORE.Window.screen.width == 0);
|
||||
|
||||
// Default to at least one pixel in size, as creation with a zero dimension is not allowed.
|
||||
// Default to at least one pixel in size, as creation with a zero dimension is not allowed
|
||||
int creationWidth = CORE.Window.screen.width != 0 ? CORE.Window.screen.width : 1;
|
||||
int creationHeight = CORE.Window.screen.height != 0 ? CORE.Window.screen.height : 1;
|
||||
|
||||
@@ -1556,8 +1566,8 @@ int InitPlatform(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// After the window was created, determine the monitor that the window manager assigned.
|
||||
// Derive display sizes, and, if possible, window size in case it was zero at beginning.
|
||||
// After the window was created, determine the monitor that the window manager assigned
|
||||
// Derive display sizes, and, if possible, window size in case it was zero at beginning
|
||||
|
||||
int monitorCount = 0;
|
||||
int monitorIndex = GetCurrentMonitor();
|
||||
@@ -1572,7 +1582,7 @@ int InitPlatform(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
// The monitor for the window-manager-created window can not be determined, so it can not be centered.
|
||||
// The monitor for the window-manager-created window can not be determined, so it can not be centered
|
||||
glfwTerminate();
|
||||
TRACELOG(LOG_WARNING, "GLFW: Failed to determine Monitor to center Window");
|
||||
return -1;
|
||||
@@ -1594,7 +1604,7 @@ int InitPlatform(void)
|
||||
|
||||
// Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)
|
||||
// NOTE: V-Sync can be enabled by graphic driver configuration, it doesn't need
|
||||
// to be activated on web platforms since VSync is enforced there.
|
||||
// to be activated on web platforms since VSync is enforced there
|
||||
if (CORE.Window.flags & FLAG_VSYNC_HINT)
|
||||
{
|
||||
// WARNING: It seems to hit a critical render path in Intel HD Graphics
|
||||
@@ -1607,7 +1617,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.
|
||||
// NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling
|
||||
// Framebuffer scaling should be activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
|
||||
#if !defined(__APPLE__)
|
||||
glfwGetFramebufferSize(platform.handle, &fbWidth, &fbHeight);
|
||||
@@ -1650,7 +1660,8 @@ int InitPlatform(void)
|
||||
int monitorHeight = 0;
|
||||
glfwGetMonitorWorkarea(monitor, &monitorX, &monitorY, &monitorWidth, &monitorHeight);
|
||||
|
||||
// Here CORE.Window.render.width/height should be used instead of CORE.Window.screen.width/height to center the window correctly when the high dpi flag is enabled.
|
||||
// Here CORE.Window.render.width/height should be used instead of
|
||||
// CORE.Window.screen.width/height to center the window correctly when the high dpi flag is enabled
|
||||
int posX = monitorX + (monitorWidth - (int)CORE.Window.render.width)/2;
|
||||
int posY = monitorY + (monitorHeight - (int)CORE.Window.render.height)/2;
|
||||
if (posX < monitorX) posX = monitorX;
|
||||
@@ -1696,6 +1707,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);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -1753,7 +1766,7 @@ static void ErrorCallback(int error, const char *description)
|
||||
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
|
||||
// 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
|
||||
@@ -1850,8 +1863,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)) ||
|
||||
@@ -1973,6 +1986,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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -583,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)
|
||||
@@ -640,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++)
|
||||
{
|
||||
@@ -657,7 +659,7 @@ int GetMonitorCount(void)
|
||||
// Get current monitor where window is placed
|
||||
int GetCurrentMonitor(void)
|
||||
{
|
||||
RGFW_monitor *mons = RGFW_getMonitors();
|
||||
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||
RGFW_monitor mon = { 0 };
|
||||
|
||||
if (platform.window) mon = RGFW_window_getMonitor(platform.window);
|
||||
@@ -674,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 };
|
||||
}
|
||||
@@ -682,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;
|
||||
}
|
||||
@@ -690,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;
|
||||
}
|
||||
@@ -698,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;
|
||||
}
|
||||
@@ -706,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;
|
||||
}
|
||||
@@ -714,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;
|
||||
}
|
||||
@@ -722,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;
|
||||
}
|
||||
@@ -987,7 +989,7 @@ void PollInputEvents(void)
|
||||
|
||||
if ((CORE.Window.eventWaiting) || (IsWindowState(FLAG_WINDOW_MINIMIZED) && !IsWindowState(FLAG_WINDOW_ALWAYS_RUN)))
|
||||
{
|
||||
RGFW_window_eventWait(platform.window, 0); // Wait for input events: keyboard/mouse/window events (callbacks) -> Update keys state
|
||||
RGFW_window_eventWait(platform.window, -1); // Wait for input events: keyboard/mouse/window events (callbacks) -> Update keys state
|
||||
CORE.Time.previous = GetTime();
|
||||
}
|
||||
|
||||
@@ -1319,6 +1321,13 @@ int InitPlatform(void)
|
||||
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;
|
||||
|
||||
@@ -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:
|
||||
@@ -256,7 +269,7 @@ static const int CursorsLUT[] = {
|
||||
// SDL3 Migration: SDL_INIT_TIMER - no longer needed before calling SDL_AddTimer()
|
||||
#define SDL_INIT_TIMER 0x0 // It's a flag, so no problem in setting it to zero if we use in a bitor (|)
|
||||
|
||||
// SDL3 Migration: The SDL_WINDOW_SHOWN flag has been removed. Windows are shown by default and can be created hidden by using the SDL_WINDOW_HIDDEN flag.
|
||||
// SDL3 Migration: The SDL_WINDOW_SHOWN flag has been removed. Windows are shown by default and can be created hidden by using the SDL_WINDOW_HIDDEN flag
|
||||
#define SDL_WINDOW_SHOWN 0x0 // It's a flag, so no problem in setting it to zero if we use in a bitor (|)
|
||||
|
||||
// SDL3 Migration: Renamed
|
||||
@@ -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)
|
||||
{
|
||||
@@ -331,7 +344,7 @@ SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth
|
||||
// SDL3 Migration:
|
||||
// SDL_GetDisplayDPI() -
|
||||
// not reliable across platforms, approximately replaced by multiplying
|
||||
// SDL_GetWindowDisplayScale() times 160 on iPhone and Android, and 96 on other platforms.
|
||||
// SDL_GetWindowDisplayScale() times 160 on iPhone and Android, and 96 on other platforms
|
||||
// returns 0 on success or a negative error code on failure
|
||||
int SDL_GetDisplayDPI(int displayIndex, float *ddpi, float *hdpi, float *vdpi)
|
||||
{
|
||||
@@ -369,7 +382,7 @@ int SDL_NumJoysticks(void)
|
||||
|
||||
// SDL_SetRelativeMouseMode
|
||||
// returns 0 on success or a negative error code on failure
|
||||
// If relative mode is not supported, this returns -1.
|
||||
// If relative mode is not supported, this returns -1
|
||||
int SDL_SetRelativeMouseMode_Adapter(SDL_bool enabled)
|
||||
{
|
||||
// SDL_SetWindowRelativeMouseMode(SDL_Window *window, bool enabled)
|
||||
@@ -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
|
||||
//----------------------------------------------------------------------------------
|
||||
@@ -565,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)
|
||||
@@ -721,7 +736,7 @@ void SetWindowIcon(Image image)
|
||||
bmask = 0x001F, amask = 0;
|
||||
depth = 16, pitch = image.width*2;
|
||||
} break;
|
||||
case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
|
||||
case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
|
||||
{
|
||||
// WARNING: SDL2 could be using BGR but SDL3 RGB
|
||||
rmask = 0xFF0000, gmask = 0x00FF00;
|
||||
@@ -826,7 +841,7 @@ void SetWindowMonitor(int monitor)
|
||||
// NOTE:
|
||||
// 1. SDL started supporting moving exclusive fullscreen windows between displays on SDL3,
|
||||
// see commit https://github.com/libsdl-org/SDL/commit/3f5ef7dd422057edbcf3e736107e34be4b75d9ba
|
||||
// 2. A workaround for SDL2 is leaving fullscreen, moving the window, then entering full screen again.
|
||||
// 2. A workaround for SDL2 is leaving fullscreen, moving the window, then entering full screen again
|
||||
const bool wasFullscreen = ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)? true : false;
|
||||
|
||||
const int screenWidth = CORE.Window.screen.width;
|
||||
@@ -839,7 +854,7 @@ void SetWindowMonitor(int monitor)
|
||||
if (SDL_GetDisplayUsableBounds(monitor, &usableBounds) == 0)
|
||||
#endif
|
||||
{
|
||||
if (wasFullscreen == 1) ToggleFullscreen(); // Leave fullscreen.
|
||||
if (wasFullscreen == 1) ToggleFullscreen(); // Leave fullscreen
|
||||
|
||||
// If the screen size is larger than the monitor usable area, anchor it on the top left corner, otherwise, center it
|
||||
if ((screenWidth >= usableBounds.w) || (screenHeight >= usableBounds.h))
|
||||
@@ -847,11 +862,11 @@ void SetWindowMonitor(int monitor)
|
||||
// NOTE:
|
||||
// 1. There's a known issue where if the window larger than the target display bounds,
|
||||
// when moving the windows to that display, the window could be clipped back
|
||||
// ending up positioned partly outside the target display.
|
||||
// ending up positioned partly outside the target display
|
||||
// 2. The workaround for that is, previously to moving the window,
|
||||
// setting the window size to the target display size, so they match.
|
||||
// setting the window size to the target display size, so they match
|
||||
// 3. It wasn't done here because we can't assume changing the window size automatically
|
||||
// is acceptable behavior by the user.
|
||||
// is acceptable behavior by the user
|
||||
SDL_SetWindowPosition(platform.window, usableBounds.x, usableBounds.y);
|
||||
CORE.Window.position.x = usableBounds.x;
|
||||
CORE.Window.position.y = usableBounds.y;
|
||||
@@ -1084,12 +1099,11 @@ Vector2 GetWindowScaleDPI(void)
|
||||
#ifndef PLATFORM_DESKTOP_SDL3
|
||||
// NOTE: SDL_GetWindowDisplayScale was only added on SDL3
|
||||
// see https://wiki.libsdl.org/SDL3/SDL_GetWindowDisplayScale
|
||||
// TODO: Implement the window scale factor calculation manually.
|
||||
// TODO: Implement the window scale factor calculation manually
|
||||
TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform");
|
||||
#else
|
||||
scale.x = SDL_GetWindowDisplayScale(platform.window);
|
||||
scale.y = scale.x;
|
||||
TRACELOG(LOG_INFO, "WindowScaleDPI is %f", scale.x);
|
||||
scale.y = scale.x;
|
||||
#endif
|
||||
|
||||
return scale;
|
||||
@@ -1153,13 +1167,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;
|
||||
@@ -1231,9 +1245,9 @@ double GetTime(void)
|
||||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
// NOTE: This function is only safe to use if you control the URL given.
|
||||
// A user could craft a malicious string performing another action.
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself.
|
||||
// NOTE: This function is only safe to use if you control the URL given
|
||||
// A user could craft a malicious string performing another action
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself
|
||||
// Ref: https://github.com/raysan5/raylib/issues/686
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
@@ -1285,7 +1299,7 @@ void SetMouseCursor(int cursor)
|
||||
CORE.Input.Mouse.cursor = cursor;
|
||||
}
|
||||
|
||||
// Get physical key name.
|
||||
// Get physical key name
|
||||
const char *GetKeyName(int key)
|
||||
{
|
||||
return SDL_GetKeyName(key);
|
||||
@@ -1452,10 +1466,9 @@ void PollInputEvents(void)
|
||||
|
||||
#ifndef PLATFORM_DESKTOP_SDL3
|
||||
// SDL3 states:
|
||||
// The SDL_WINDOWEVENT_* events have been moved to top level events,
|
||||
// and SDL_WINDOWEVENT has been removed.
|
||||
// In general, handling this change just means checking for the individual events instead of first checking for SDL_WINDOWEVENT
|
||||
// and then checking for window events. You can compare the event >= SDL_EVENT_WINDOW_FIRST and <= SDL_EVENT_WINDOW_LAST if you need to see whether it's a window event.
|
||||
// The SDL_WINDOWEVENT_* events have been moved to top level events, and SDL_WINDOWEVENT has been removed
|
||||
// In general, handling this change just means checking for the individual events instead of first checking for SDL_WINDOWEVENT
|
||||
// and then checking for window events. You can compare the event >= SDL_EVENT_WINDOW_FIRST and <= SDL_EVENT_WINDOW_LAST if you need to see whether it's a window event.
|
||||
case SDL_WINDOWEVENT:
|
||||
{
|
||||
switch (event.window.event)
|
||||
@@ -1601,13 +1614,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;
|
||||
@@ -1697,8 +1715,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
|
||||
{
|
||||
@@ -1825,7 +1843,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;
|
||||
|
||||
@@ -2093,4 +2111,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;
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
*
|
||||
* CONFIGURATION:
|
||||
* #define SUPPORT_SSH_KEYBOARD_RPI (Raspberry Pi only)
|
||||
* Reconfigure standard input to receive key inputs, works with SSH connection.
|
||||
* Reconfigure standard input to receive key inputs, works with SSH connection
|
||||
* WARNING: Reconfiguring standard input could lead to undesired effects, like breaking other
|
||||
* running processes orblocking the device if not restored properly. Use with care.
|
||||
* running processes orblocking the device if not restored properly. Use with care
|
||||
*
|
||||
* DEPENDENCIES:
|
||||
* - DRM and GLM: System libraries for display initialization and configuration
|
||||
@@ -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
|
||||
//----------------------------------------------------------------------------------
|
||||
@@ -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
|
||||
@@ -599,9 +824,9 @@ double GetTime(void)
|
||||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
// NOTE: This function is only safe to use if you control the URL given.
|
||||
// A user could craft a malicious string performing another action.
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself.
|
||||
// NOTE: This function is only safe to use if you control the URL given
|
||||
// A user could craft a malicious string performing another action
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself
|
||||
// Ref: https://github.com/raysan5/raylib/issues/686
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
@@ -638,7 +863,7 @@ void SetMouseCursor(int cursor)
|
||||
TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform");
|
||||
}
|
||||
|
||||
// Get physical key name.
|
||||
// Get physical key name
|
||||
const char *GetKeyName(int key)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform");
|
||||
@@ -672,7 +897,7 @@ void PollInputEvents(void)
|
||||
PollKeyboardEvents();
|
||||
|
||||
#if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
||||
// NOTE: Keyboard reading could be done using input_event(s) or just read from stdin, both methods are used here.
|
||||
// NOTE: Keyboard reading could be done using input_event(s) or just read from stdin, both methods are used here
|
||||
// stdin reading is still used for legacy purposes, it allows keyboard input trough SSH console
|
||||
if (!platform.eventKeyboardMode) ProcessKeyboard();
|
||||
#endif
|
||||
@@ -778,8 +1003,8 @@ int InitPlatform(void)
|
||||
drmModeConnector *con = drmModeGetConnector(platform.fd, res->connectors[i]);
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: Connector modes detected: %i", con->count_modes);
|
||||
|
||||
// In certain cases the status of the conneciton is reported as UKNOWN, but it is still connected.
|
||||
// This might be a hardware or software limitation like on Raspberry Pi Zero with composite output.
|
||||
// In certain cases the status of the conneciton is reported as UKNOWN, but it is still connected
|
||||
// This might be a hardware or software limitation like on Raspberry Pi Zero with composite output
|
||||
if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->encoder_id))
|
||||
{
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected");
|
||||
@@ -935,7 +1160,7 @@ int InitPlatform(void)
|
||||
// Initialize the EGL device connection
|
||||
if (eglInitialize(platform.device, NULL, NULL) == EGL_FALSE)
|
||||
{
|
||||
// If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred.
|
||||
// If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device");
|
||||
return -1;
|
||||
}
|
||||
@@ -948,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");
|
||||
@@ -1083,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
|
||||
@@ -1319,7 +1556,7 @@ static void ProcessKeyboard(void)
|
||||
{
|
||||
CORE.Input.Keyboard.currentKeyState[259] = 1;
|
||||
|
||||
CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = 257; // Add keys pressed into queue
|
||||
CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = 259; // Add keys pressed into queue
|
||||
CORE.Input.Keyboard.keyPressedQueueCount++;
|
||||
}
|
||||
else
|
||||
@@ -1374,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
|
||||
}
|
||||
}
|
||||
@@ -1407,7 +1644,7 @@ static void ConfigureEvdevDevice(char *device)
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point we have a connection to the device, but we don't yet know what the device is.
|
||||
// At this point we have a connection to the device, but we don't yet know what the device is
|
||||
// It could be many things, even as simple as a power button...
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -1460,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++)
|
||||
@@ -1546,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
|
||||
@@ -1681,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];
|
||||
|
||||
@@ -111,23 +111,23 @@ int InitPlatform(void); // Initialize platform (graphics, inputs and mo
|
||||
void ClosePlatform(void); // Close platform
|
||||
|
||||
// Error callback event
|
||||
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
|
||||
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
|
||||
|
||||
// Window callbacks events
|
||||
static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized
|
||||
static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored
|
||||
static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 Window Size Callback, runs when window is resized
|
||||
static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 Window Iconify Callback, runs when window is minimized/restored
|
||||
//static void WindowMaximizeCallback(GLFWwindow *window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized
|
||||
static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus
|
||||
static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 Window Focus Callback, runs when window get/lose focus
|
||||
static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window
|
||||
static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley); // GLFW3 Window Content Scale Callback, runs when window changes scale
|
||||
|
||||
// Input callbacks events
|
||||
static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed
|
||||
static void CharCallback(GLFWwindow *window, unsigned int key); // GLFW3 Char Key Callback, runs on key pressed (get char value)
|
||||
static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods); // GLFW3 Mouse Button Callback, runs on mouse button pressed
|
||||
static void MouseCursorPosCallback(GLFWwindow *window, double x, double y); // GLFW3 Cursor Position Callback, runs on mouse move
|
||||
static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Srolling Callback, runs on mouse wheel
|
||||
static void CursorEnterCallback(GLFWwindow *window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area
|
||||
static void CharCallback(GLFWwindow *window, unsigned int key); // GLFW3 Char Key Callback, runs on key pressed (get char value)
|
||||
static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods); // GLFW3 Mouse Button Callback, runs on mouse button pressed
|
||||
static void MouseMoveCallback(GLFWwindow *window, double x, double y); // GLFW3 Mouse Move Callback, runs on mouse move
|
||||
static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Mouse Scrolling Callback, runs on mouse wheel
|
||||
static void MouseEnterCallback(GLFWwindow *window, int enter); // GLFW3 Mouse Enter Callback, cursor enters client area
|
||||
|
||||
// Emscripten window callback events
|
||||
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData);
|
||||
@@ -137,6 +137,7 @@ static EM_BOOL EmscriptenFocusCallback(int eventType, const EmscriptenFocusEvent
|
||||
static EM_BOOL EmscriptenVisibilityChangeCallback(int eventType, const EmscriptenVisibilityChangeEvent *visibilityChangeEvent, void *userData);
|
||||
|
||||
// Emscripten input callback events
|
||||
//static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyboardEvent, void *userData);
|
||||
static EM_BOOL EmscriptenMouseMoveCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
|
||||
static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
|
||||
static EM_BOOL EmscriptenPointerlockCallback(int eventType, const EmscriptenPointerlockChangeEvent *pointerlockChangeEvent, void *userData);
|
||||
@@ -163,13 +164,13 @@ bool WindowShouldClose(void)
|
||||
// REF: https://emscripten.org/docs/porting/asyncify.html
|
||||
|
||||
// WindowShouldClose() is not called on a web-ready raylib application if using emscripten_set_main_loop()
|
||||
// and encapsulating one frame execution on a UpdateDrawFrame() function,
|
||||
// and encapsulating one frame execution on a UpdateDrawFrame() function,
|
||||
// allowing the browser to manage execution asynchronously
|
||||
|
||||
// Optionally we can manage the time we give-control-back-to-browser if required,
|
||||
// but it seems below line could generate stuttering on some browsers
|
||||
emscripten_sleep(12);
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1081,7 +1082,7 @@ void PollInputEvents(void)
|
||||
}
|
||||
|
||||
// Register axis data for every connected gamepad
|
||||
for (int j = 0; (j < gamepadState.numAxes) && (j < MAX_GAMEPAD_AXIS); j++)
|
||||
for (int j = 0; (j < gamepadState.numAxes) && (j < MAX_GAMEPAD_AXES); j++)
|
||||
{
|
||||
CORE.Input.Gamepad.axisState[i][j] = gamepadState.axis[j];
|
||||
}
|
||||
@@ -1300,23 +1301,24 @@ int InitPlatform(void)
|
||||
emscripten_set_window_title((CORE.Window.title != 0)? CORE.Window.title : " ");
|
||||
|
||||
// Set window callback events
|
||||
glfwSetWindowSizeCallback(platform.handle, WindowSizeCallback); // NOTE: Resizing not allowed by default!
|
||||
glfwSetWindowSizeCallback(platform.handle, WindowSizeCallback);
|
||||
glfwSetWindowIconifyCallback(platform.handle, WindowIconifyCallback);
|
||||
glfwSetWindowFocusCallback(platform.handle, WindowFocusCallback);
|
||||
glfwSetDropCallback(platform.handle, WindowDropCallback);
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
{
|
||||
glfwSetWindowContentScaleCallback(platform.handle, WindowContentScaleCallback);
|
||||
// Window content (framebuffer) scale callback
|
||||
glfwSetWindowContentScaleCallback(platform.handle, WindowContentScaleCallback);
|
||||
}
|
||||
|
||||
// Set input callback events
|
||||
glfwSetKeyCallback(platform.handle, KeyCallback);
|
||||
glfwSetCharCallback(platform.handle, CharCallback);
|
||||
glfwSetMouseButtonCallback(platform.handle, MouseButtonCallback);
|
||||
glfwSetCursorPosCallback(platform.handle, MouseCursorPosCallback); // Track mouse position changes
|
||||
glfwSetCursorPosCallback(platform.handle, MouseMoveCallback);
|
||||
glfwSetScrollCallback(platform.handle, MouseScrollCallback);
|
||||
glfwSetCursorEnterCallback(platform.handle, CursorEnterCallback);
|
||||
glfwSetCursorEnterCallback(platform.handle, MouseEnterCallback);
|
||||
|
||||
glfwMakeContextCurrent(platform.handle);
|
||||
result = true; // TODO: WARNING: glfwGetError(NULL); symbol can not be found in Web
|
||||
@@ -1356,48 +1358,36 @@ int InitPlatform(void)
|
||||
rlLoadExtensions(glfwGetProcAddress);
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Initialize input events callbacks
|
||||
// Initialize events callbacks
|
||||
//----------------------------------------------------------------------------
|
||||
// Setup callback functions for the DOM events
|
||||
// Setup window events callbacks
|
||||
emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenFullscreenChangeCallback);
|
||||
|
||||
emscripten_set_blur_callback(GetCanvasId(), platform.handle, 1, EmscriptenFocusCallback);
|
||||
emscripten_set_focus_callback(GetCanvasId(), platform.handle, 1, EmscriptenFocusCallback);
|
||||
emscripten_set_visibilitychange_callback(NULL, 1, EmscriptenVisibilityChangeCallback);
|
||||
|
||||
// WARNING: Below resize code was breaking fullscreen mode for sample games and examples, it needs review
|
||||
// Check fullscreen change events(note this is done on the window since most browsers don't support this on #canvas)
|
||||
// emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
|
||||
// Check Resize event (note this is done on the window since most browsers don't support this on #canvas)
|
||||
emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
|
||||
|
||||
// Trigger this once to get initial window sizing
|
||||
// Trigger resize callback to force initial size
|
||||
EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
|
||||
|
||||
// Support keyboard events -> Not used, GLFW.JS takes care of that
|
||||
// emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
|
||||
// emscripten_set_keydown_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
|
||||
|
||||
// Support mouse events
|
||||
// Setup input events
|
||||
// NOTE: Keyboard callbacks only used to consume some events, libglfw.js takes care of the actual input
|
||||
//emscripten_set_keypress_callback(GetCanvasId(), NULL, 1, EmscriptenKeyboardCallback); // WRNING: Breaks input
|
||||
//emscripten_set_keydown_callback(GetCanvasId(), NULL, 1, EmscriptenKeyboardCallback);
|
||||
emscripten_set_click_callback(GetCanvasId(), NULL, 1, EmscriptenMouseCallback);
|
||||
emscripten_set_pointerlockchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenPointerlockCallback);
|
||||
|
||||
// Following the mouse delta when the mouse is locked
|
||||
emscripten_set_mousemove_callback(GetCanvasId(), NULL, 1, EmscriptenMouseMoveCallback);
|
||||
|
||||
// Support touch events
|
||||
emscripten_set_touchstart_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback);
|
||||
emscripten_set_touchend_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback);
|
||||
emscripten_set_touchmove_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback);
|
||||
emscripten_set_touchcancel_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback);
|
||||
|
||||
// Support gamepad events (not provided by GLFW3 on emscripten)
|
||||
emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenGamepadCallback);
|
||||
emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback);
|
||||
|
||||
// Support focus events
|
||||
emscripten_set_blur_callback(GetCanvasId(), platform.handle, 1, EmscriptenFocusCallback);
|
||||
emscripten_set_focus_callback(GetCanvasId(), platform.handle, 1, EmscriptenFocusCallback);
|
||||
|
||||
// Support visibility events
|
||||
emscripten_set_visibilitychange_callback(NULL, 1, EmscriptenVisibilityChangeCallback);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Initialize timing system
|
||||
@@ -1422,14 +1412,15 @@ void ClosePlatform(void)
|
||||
glfwTerminate();
|
||||
}
|
||||
|
||||
// GLFW3 Error Callback, runs on GLFW3 error
|
||||
// GLFW3 callback functions, called on GLFW registered events
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
// GLFW3: Called on errors
|
||||
static void ErrorCallback(int error, const char *description)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GLFW: Error: %i Description: %s", error, description);
|
||||
}
|
||||
|
||||
// GLFW3 WindowSize Callback, runs when window is resizedLastFrame
|
||||
// NOTE: Window resizing not allowed by default
|
||||
// GLFW3: Called on window resizing, runs when window is resizedLastFrame
|
||||
static void WindowSizeCallback(GLFWwindow *window, int width, int height)
|
||||
{
|
||||
// Reset viewport and projection matrix for new size
|
||||
@@ -1458,34 +1449,27 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height)
|
||||
// NOTE: Postprocessing texture is not scaled to new size
|
||||
}
|
||||
|
||||
// GLFW3: Called on window content (framebuffer) scaled
|
||||
static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley)
|
||||
{
|
||||
CORE.Window.screenScale = MatrixScale(scalex, scaley, 1.0f);
|
||||
}
|
||||
|
||||
// GLFW3 WindowIconify Callback, runs when window is minimized/restored
|
||||
// GLFW3: Called on windows minimized/restored
|
||||
static void WindowIconifyCallback(GLFWwindow *window, int iconified)
|
||||
{
|
||||
if (iconified) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; // The window was iconified
|
||||
else CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored
|
||||
}
|
||||
|
||||
/*
|
||||
// GLFW3 Window Maximize Callback, runs when window is maximized
|
||||
static void WindowMaximizeCallback(GLFWwindow *window, int maximized)
|
||||
{
|
||||
// TODO.
|
||||
}
|
||||
*/
|
||||
|
||||
// GLFW3 WindowFocus Callback, runs when window get/lose focus
|
||||
// GLFW3: Called on windows get/lose focus
|
||||
static void WindowFocusCallback(GLFWwindow *window, int focused)
|
||||
{
|
||||
if (focused) CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // The window was focused
|
||||
else CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED; // The window lost focus
|
||||
}
|
||||
|
||||
// GLFW3 Window Drop Callback, runs when drop files into window
|
||||
// GLFW3: Called on file-drop over the window
|
||||
static void WindowDropCallback(GLFWwindow *window, int count, const char **paths)
|
||||
{
|
||||
if (count > 0)
|
||||
@@ -1513,7 +1497,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths
|
||||
}
|
||||
}
|
||||
|
||||
// GLFW3 Keyboard Callback, runs on key pressed
|
||||
// GLFW3: Called on keyboard interaction
|
||||
static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
if (key < 0) return; // Security check, macOS fn key generates -1
|
||||
@@ -1536,7 +1520,7 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
|
||||
if ((key == CORE.Input.Keyboard.exitKey) && (action == GLFW_PRESS)) glfwSetWindowShouldClose(platform.handle, GLFW_TRUE);
|
||||
}
|
||||
|
||||
// GLFW3 Char Key Callback, runs on key down (gets equivalent unicode char value)
|
||||
// GLFW3: Called on key down interaction, gets equivalent unicode char value for the key
|
||||
static void CharCallback(GLFWwindow *window, unsigned int key)
|
||||
{
|
||||
//TRACELOG(LOG_DEBUG, "Char Callback: KEY:%i(%c)", key, key);
|
||||
@@ -1555,7 +1539,7 @@ static void CharCallback(GLFWwindow *window, unsigned int key)
|
||||
}
|
||||
}
|
||||
|
||||
// GLFW3 Mouse Button Callback, runs on mouse button pressed
|
||||
// GLFW3: Called on mouse button interaction
|
||||
static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods)
|
||||
{
|
||||
// WARNING: GLFW could only return GLFW_PRESS (1) or GLFW_RELEASE (0) for now,
|
||||
@@ -1571,7 +1555,7 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int
|
||||
if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) gestureEvent.touchAction = TOUCH_ACTION_DOWN;
|
||||
else if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) gestureEvent.touchAction = TOUCH_ACTION_UP;
|
||||
|
||||
// NOTE: TOUCH_ACTION_MOVE event is registered in MouseCursorPosCallback()
|
||||
// NOTE: TOUCH_ACTION_MOVE event is registered in MouseMoveCallback()
|
||||
|
||||
// Assign a pointer ID
|
||||
gestureEvent.pointId[0] = 0;
|
||||
@@ -1593,8 +1577,8 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int
|
||||
#endif
|
||||
}
|
||||
|
||||
// GLFW3 Cursor Position Callback, runs on mouse move
|
||||
static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
|
||||
// GLFW3: Called on mouse move
|
||||
static void MouseMoveCallback(GLFWwindow *window, double x, double y)
|
||||
{
|
||||
// If the pointer is not locked, follow the position
|
||||
if (!CORE.Input.Mouse.cursorHidden)
|
||||
@@ -1628,34 +1612,28 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
|
||||
#endif
|
||||
}
|
||||
|
||||
static EM_BOOL EmscriptenMouseMoveCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
|
||||
{
|
||||
// To emulate the GLFW_RAW_MOUSE_MOTION property.
|
||||
if (CORE.Input.Mouse.cursorHidden)
|
||||
{
|
||||
CORE.Input.Mouse.previousPosition.x = lockedMousePos.x - mouseEvent->movementX;
|
||||
CORE.Input.Mouse.previousPosition.y = lockedMousePos.y - mouseEvent->movementY;
|
||||
}
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// GLFW3 Scrolling Callback, runs on mouse wheel
|
||||
// GLFW3: Called on mouse wheel scrolling
|
||||
static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset)
|
||||
{
|
||||
CORE.Input.Mouse.currentWheelMove = (Vector2){ (float)xoffset, (float)yoffset };
|
||||
}
|
||||
|
||||
// GLFW3 CursorEnter Callback, when cursor enters the window
|
||||
static void CursorEnterCallback(GLFWwindow *window, int enter)
|
||||
// GLFW3: Called on mouse entering the window
|
||||
static void MouseEnterCallback(GLFWwindow *window, int enter)
|
||||
{
|
||||
if (enter) CORE.Input.Mouse.cursorOnScreen = true;
|
||||
else CORE.Input.Mouse.cursorOnScreen = false;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Register fullscreen change events
|
||||
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData)
|
||||
// Emscripten callback functions, called on specific browser events
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
// Emscripten: Called on key events
|
||||
static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyboardEvent, void *userData)
|
||||
{
|
||||
// WARNING: Keyboard inputs already processed through GLFW callback
|
||||
|
||||
// NOTE: 1. Reset the fullscreen flags if the user left fullscreen manually by pressing the Escape key
|
||||
// 2. Which is a necessary safeguard because that case will bypass the toggles CORE.Window.flags resets
|
||||
if (platform.ourFullscreen) platform.ourFullscreen = false;
|
||||
@@ -1670,23 +1648,21 @@ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const Emscripte
|
||||
}
|
||||
}
|
||||
|
||||
// trigger resize event after a brief pause to ensure the canvas exists to resize
|
||||
// Trigger resize event after a brief pause to ensure the canvas exists to resize
|
||||
EM_ASM({ setTimeout(function() { window.dispatchEvent(new Event("resize")); }, 50); });
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
*/
|
||||
|
||||
// Register window resize event
|
||||
// static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData)
|
||||
// {
|
||||
// // TODO: Implement EmscriptenWindowResizedCallback()?
|
||||
|
||||
// return 1; // The event was consumed by the callback handler
|
||||
// }
|
||||
|
||||
// Register DOM element resize event
|
||||
static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData)
|
||||
// Emscripten: Called on mouse input events
|
||||
static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
|
||||
{
|
||||
// NOTE: Current code solves mouse position problems with the 3 possible approaches to canvas scaling
|
||||
// 1. Canvas not scaled, framebuffer size is fixed
|
||||
// 2. Canvas is scaled to 100% browser size, framebuffer size is fixed
|
||||
// 3. Canvas is resized to browser size, framebuffer is resized
|
||||
|
||||
// Don't resize non-resizeable windows
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) == 0) return 1;
|
||||
|
||||
@@ -1703,7 +1679,7 @@ static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *
|
||||
|
||||
emscripten_set_canvas_element_size(GetCanvasId(), width, height);
|
||||
|
||||
glfwSetWindowSize(platform.handle, width, height); // inform glfw of the new size
|
||||
glfwSetWindowSize(platform.handle, width, height); // Inform glfw of the new size
|
||||
|
||||
SetupViewport(width, height); // Reset viewport and projection matrix for new size
|
||||
|
||||
@@ -1717,20 +1693,25 @@ static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *
|
||||
CORE.Window.screen.width = width;
|
||||
CORE.Window.screen.height = height;
|
||||
|
||||
// NOTE: Postprocessing texture is not scaled to new size
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Register mouse input events
|
||||
static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
|
||||
{
|
||||
// This is only for registering mouse click events with emscripten and doesn't need to do anything
|
||||
// WARNING: RenderTextures are not scaled to new size
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// Register pointer lock events
|
||||
// Emscripten: Called on mouse move events
|
||||
static EM_BOOL EmscriptenMouseMoveCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
|
||||
{
|
||||
// To emulate the GLFW_RAW_MOUSE_MOTION property.
|
||||
if (CORE.Input.Mouse.cursorHidden)
|
||||
{
|
||||
CORE.Input.Mouse.previousPosition.x = lockedMousePos.x - mouseEvent->movementX;
|
||||
CORE.Input.Mouse.previousPosition.y = lockedMousePos.y - mouseEvent->movementY;
|
||||
}
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// Emscripten: Called on pointer lock events
|
||||
static EM_BOOL EmscriptenPointerlockCallback(int eventType, const EmscriptenPointerlockChangeEvent *pointerlockChangeEvent, void *userData)
|
||||
{
|
||||
CORE.Input.Mouse.cursorHidden = EM_ASM_INT( { if (document.pointerLockElement) return 1; }, 0);
|
||||
@@ -1744,7 +1725,7 @@ static EM_BOOL EmscriptenPointerlockCallback(int eventType, const EmscriptenPoin
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// Register connected/disconnected gamepads events
|
||||
// Emscripten: Called on connect/disconnect gamepads events
|
||||
static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
|
||||
{
|
||||
/*
|
||||
@@ -1759,33 +1740,14 @@ static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadE
|
||||
if (gamepadEvent->connected && (gamepadEvent->index < MAX_GAMEPADS))
|
||||
{
|
||||
CORE.Input.Gamepad.ready[gamepadEvent->index] = true;
|
||||
sprintf(CORE.Input.Gamepad.name[gamepadEvent->index], "%s", gamepadEvent->id);
|
||||
snprintf(CORE.Input.Gamepad.name[gamepadEvent->index], MAX_GAMEPAD_NAME_LENGTH, "%s", gamepadEvent->id);
|
||||
}
|
||||
else CORE.Input.Gamepad.ready[gamepadEvent->index] = false;
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
static EM_BOOL EmscriptenFocusCallback(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)
|
||||
{
|
||||
EM_BOOL consumed = 1;
|
||||
switch (eventType)
|
||||
{
|
||||
case EMSCRIPTEN_EVENT_BLUR: WindowFocusCallback(userData, 0); break;
|
||||
case EMSCRIPTEN_EVENT_FOCUS: WindowFocusCallback(userData, 1); break;
|
||||
default: consumed = 0; break;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
static EM_BOOL EmscriptenVisibilityChangeCallback(int eventType, const EmscriptenVisibilityChangeEvent *visibilityChangeEvent, void *userData)
|
||||
{
|
||||
if (visibilityChangeEvent->hidden) CORE.Window.flags |= FLAG_WINDOW_HIDDEN; // The window was hidden
|
||||
else CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; // The window was restored
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// Register touch input events
|
||||
// Emscripten: Called on touch input events
|
||||
static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
|
||||
{
|
||||
// Register touch points count
|
||||
@@ -1871,7 +1833,85 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// obtaining the canvas id provided by the module configuration
|
||||
// Emscripten: Called on fullscreen change events
|
||||
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData)
|
||||
{
|
||||
// NOTE: 1. Reset the fullscreen flags if the user left fullscreen manually by pressing the Escape key
|
||||
// 2. Which is a necessary safeguard because that case will bypass the toggles CORE.Window.flags resets
|
||||
if (platform.ourFullscreen) platform.ourFullscreen = false;
|
||||
else
|
||||
{
|
||||
const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
|
||||
if (!wasFullscreen)
|
||||
{
|
||||
CORE.Window.fullscreen = false;
|
||||
CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
|
||||
CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
|
||||
}
|
||||
}
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// Emscripten: Called on resize event
|
||||
static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData)
|
||||
{
|
||||
// Don't resize non-resizeable windows
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) == 0) return 1;
|
||||
|
||||
// This event is called whenever the window changes sizes,
|
||||
// so the size of the canvas object is explicitly retrieved below
|
||||
int width = EM_ASM_INT( return window.innerWidth; );
|
||||
int height = EM_ASM_INT( return window.innerHeight; );
|
||||
|
||||
if (width < (int)CORE.Window.screenMin.width) width = CORE.Window.screenMin.width;
|
||||
else if ((width > (int)CORE.Window.screenMax.width) && (CORE.Window.screenMax.width > 0)) width = CORE.Window.screenMax.width;
|
||||
|
||||
if (height < (int)CORE.Window.screenMin.height) height = CORE.Window.screenMin.height;
|
||||
else if ((height > (int)CORE.Window.screenMax.height) && (CORE.Window.screenMax.height > 0)) height = CORE.Window.screenMax.height;
|
||||
|
||||
emscripten_set_canvas_element_size(GetCanvasId(), width, height);
|
||||
|
||||
SetupViewport(width, height); // Reset viewport and projection matrix for new size
|
||||
|
||||
CORE.Window.currentFbo.width = width;
|
||||
CORE.Window.currentFbo.height = height;
|
||||
CORE.Window.resizedLastFrame = true;
|
||||
|
||||
if (IsWindowFullscreen()) return 1;
|
||||
|
||||
// Set current screen size
|
||||
CORE.Window.screen.width = width;
|
||||
CORE.Window.screen.height = height;
|
||||
|
||||
// NOTE: Postprocessing texture is not scaled to new size
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Emscripten: Called on windows focus change events
|
||||
static EM_BOOL EmscriptenFocusCallback(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)
|
||||
{
|
||||
EM_BOOL consumed = 1;
|
||||
switch (eventType)
|
||||
{
|
||||
case EMSCRIPTEN_EVENT_BLUR: WindowFocusCallback(userData, 0); break;
|
||||
case EMSCRIPTEN_EVENT_FOCUS: WindowFocusCallback(userData, 1); break;
|
||||
default: consumed = 0; break;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
// Emscripten: Called on visibility change events
|
||||
static EM_BOOL EmscriptenVisibilityChangeCallback(int eventType, const EmscriptenVisibilityChangeEvent *visibilityChangeEvent, void *userData)
|
||||
{
|
||||
if (visibilityChangeEvent->hidden) CORE.Window.flags |= FLAG_WINDOW_HIDDEN; // The window was hidden
|
||||
else CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; // The window was restored
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
|
||||
// JS: Get the canvas id provided by the module configuration
|
||||
EM_JS(char*, GetCanvasIdJs, (), {
|
||||
var canvasId = "#" + Module.canvas.id;
|
||||
var lengthBytes = lengthBytesUTF8(canvasId) + 1;
|
||||
@@ -1880,6 +1920,7 @@ EM_JS(char*, GetCanvasIdJs, (), {
|
||||
return stringOnWasmHeap;
|
||||
});
|
||||
|
||||
// Get canvas id (using embedded JS function)
|
||||
static const char *GetCanvasId(void)
|
||||
{
|
||||
static char *canvasId = NULL;
|
||||
|
||||
75
src/raudio.c
75
src/raudio.c
@@ -15,8 +15,8 @@
|
||||
* raudio module is included in the build
|
||||
*
|
||||
* #define RAUDIO_STANDALONE
|
||||
* Define to use the module as standalone library (independently of raylib).
|
||||
* Required types and functions are defined in the same module.
|
||||
* Define to use the module as standalone library (independently of raylib)
|
||||
* Required types and functions are defined in the same module
|
||||
*
|
||||
* #define SUPPORT_FILEFORMAT_WAV
|
||||
* #define SUPPORT_FILEFORMAT_OGG
|
||||
@@ -81,7 +81,7 @@
|
||||
#include "utils.h" // Required for: fopen() Android mapping
|
||||
#endif
|
||||
|
||||
#if defined(SUPPORT_MODULE_RAUDIO)
|
||||
#if defined(SUPPORT_MODULE_RAUDIO) || defined(RAUDIO_STANDALONE)
|
||||
|
||||
#if defined(_WIN32)
|
||||
// To avoid conflicting windows.h symbols with raylib, some flags are defined
|
||||
@@ -89,7 +89,7 @@
|
||||
// by user at some point and won't be included...
|
||||
//-------------------------------------------------------------------------------------
|
||||
|
||||
// If defined, the following flags inhibit definition of the indicated items.
|
||||
// If defined, the following flags inhibit definition of the indicated items
|
||||
#define NOGDICAPMASKS // CC_*, LC_*, PC_*, CP_*, TC_*, RC_
|
||||
#define NOVIRTUALKEYCODES // VK_*
|
||||
#define NOWINMESSAGES // WM_*, EM_*, LB_*, CB_*
|
||||
@@ -124,9 +124,9 @@
|
||||
#define NOWH // SetWindowsHook and WH_*
|
||||
#define NOWINOFFSETS // GWL_*, GCL_*, associated routines
|
||||
#define NOCOMM // COMM driver routines
|
||||
#define NOKANJI // Kanji support stuff.
|
||||
#define NOHELP // Help engine interface.
|
||||
#define NOPROFILER // Profiler interface.
|
||||
#define NOKANJI // Kanji support stuff
|
||||
#define NOHELP // Help engine interface
|
||||
#define NOPROFILER // Profiler interface
|
||||
#define NODEFERWINDOWPOS // DeferWindowPos routines
|
||||
#define NOMCX // Modem Configuration Extensions
|
||||
|
||||
@@ -451,7 +451,6 @@ void SetAudioBufferPan(AudioBuffer *buffer, float pan);
|
||||
void TrackAudioBuffer(AudioBuffer *buffer);
|
||||
void UntrackAudioBuffer(AudioBuffer *buffer);
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition - Audio Device initialization and Closing
|
||||
//----------------------------------------------------------------------------------
|
||||
@@ -996,7 +995,6 @@ Sound LoadSoundAlias(Sound source)
|
||||
return sound;
|
||||
}
|
||||
|
||||
|
||||
// Checks if a sound is valid (data loaded and buffers initialized)
|
||||
bool IsSoundValid(Sound sound)
|
||||
{
|
||||
@@ -1037,6 +1035,8 @@ void UnloadSoundAlias(Sound alias)
|
||||
}
|
||||
|
||||
// Update sound buffer with new data
|
||||
// NOTE 1: data format must match sound.stream.sampleSize
|
||||
// NOTE 2: frameCount must not exceed sound.frameCount
|
||||
void UpdateSound(Sound sound, const void *data, int frameCount)
|
||||
{
|
||||
if (sound.stream.buffer != NULL)
|
||||
@@ -1118,7 +1118,7 @@ bool ExportWaveAsCode(Wave wave, const char *fileName)
|
||||
|
||||
// NOTE: Text data buffer size is estimated considering wave data size in bytes
|
||||
// and requiring 12 char bytes for every byte; the actual size varies, but
|
||||
// the longest possible char being appended is "%.4ff,\n ", which is 12 bytes.
|
||||
// the longest possible char being appended is "%.4ff,\n ", which is 12 bytes
|
||||
char *txtData = (char *)RL_CALLOC(waveDataSize*12 + 2000, sizeof(char));
|
||||
|
||||
int byteCount = 0;
|
||||
@@ -1337,7 +1337,7 @@ Music LoadMusicStream(const char *fileName)
|
||||
#if defined(SUPPORT_FILEFORMAT_WAV)
|
||||
else if (IsFileExtension(fileName, ".wav"))
|
||||
{
|
||||
drwav *ctxWav = RL_CALLOC(1, sizeof(drwav));
|
||||
drwav *ctxWav = (drwav *)RL_CALLOC(1, sizeof(drwav));
|
||||
bool success = drwav_init_file(ctxWav, fileName, NULL);
|
||||
|
||||
if (success)
|
||||
@@ -1387,7 +1387,7 @@ Music LoadMusicStream(const char *fileName)
|
||||
#if defined(SUPPORT_FILEFORMAT_MP3)
|
||||
else if (IsFileExtension(fileName, ".mp3"))
|
||||
{
|
||||
drmp3 *ctxMp3 = RL_CALLOC(1, sizeof(drmp3));
|
||||
drmp3 *ctxMp3 = (drmp3 *)RL_CALLOC(1, sizeof(drmp3));
|
||||
int result = drmp3_init_file(ctxMp3, fileName, NULL);
|
||||
|
||||
if (result > 0)
|
||||
@@ -1478,7 +1478,7 @@ Music LoadMusicStream(const char *fileName)
|
||||
#if defined(SUPPORT_FILEFORMAT_MOD)
|
||||
else if (IsFileExtension(fileName, ".mod"))
|
||||
{
|
||||
jar_mod_context_t *ctxMod = RL_CALLOC(1, sizeof(jar_mod_context_t));
|
||||
jar_mod_context_t *ctxMod = (jar_mod_context_t *)RL_CALLOC(1, sizeof(jar_mod_context_t));
|
||||
jar_mod_init(ctxMod);
|
||||
int result = jar_mod_load_file(ctxMod, fileName);
|
||||
|
||||
@@ -1529,7 +1529,7 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data,
|
||||
#if defined(SUPPORT_FILEFORMAT_WAV)
|
||||
else if ((strcmp(fileType, ".wav") == 0) || (strcmp(fileType, ".WAV") == 0))
|
||||
{
|
||||
drwav *ctxWav = RL_CALLOC(1, sizeof(drwav));
|
||||
drwav *ctxWav = (drwav *)RL_CALLOC(1, sizeof(drwav));
|
||||
|
||||
bool success = drwav_init_memory(ctxWav, (const void *)data, dataSize, NULL);
|
||||
|
||||
@@ -1545,7 +1545,8 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data,
|
||||
music.looping = true; // Looping enabled by default
|
||||
musicLoaded = true;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
drwav_uninit(ctxWav);
|
||||
RL_FREE(ctxWav);
|
||||
}
|
||||
@@ -1580,7 +1581,7 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data,
|
||||
#if defined(SUPPORT_FILEFORMAT_MP3)
|
||||
else if ((strcmp(fileType, ".mp3") == 0) || (strcmp(fileType, ".MP3") == 0))
|
||||
{
|
||||
drmp3 *ctxMp3 = RL_CALLOC(1, sizeof(drmp3));
|
||||
drmp3 *ctxMp3 = (drmp3 *)RL_CALLOC(1, sizeof(drmp3));
|
||||
int success = drmp3_init_memory(ctxMp3, (const void*)data, dataSize, NULL);
|
||||
|
||||
if (success)
|
||||
@@ -1869,6 +1870,7 @@ void SeekMusicStream(Music music, float position)
|
||||
void UpdateMusicStream(Music music)
|
||||
{
|
||||
if (music.stream.buffer == NULL) return;
|
||||
if (!music.stream.buffer->playing) return;
|
||||
|
||||
ma_mutex_lock(&AUDIO.System.lock);
|
||||
|
||||
@@ -1888,14 +1890,28 @@ void UpdateMusicStream(Music music)
|
||||
// Check both sub-buffers to check if they require refilling
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (!music.stream.buffer->isSubBufferProcessed[i]) continue; // No refilling required, move to next sub-buffer
|
||||
|
||||
unsigned int framesLeft = music.frameCount - music.stream.buffer->framesProcessed; // Frames left to be processed
|
||||
unsigned int framesToStream = 0; // Total frames to be streamed
|
||||
|
||||
if ((framesLeft >= subBufferSizeInFrames) || music.looping) framesToStream = subBufferSizeInFrames;
|
||||
else framesToStream = framesLeft;
|
||||
|
||||
if (framesToStream == 0)
|
||||
{
|
||||
// Check if both buffers have been processed
|
||||
if (music.stream.buffer->isSubBufferProcessed[0] && music.stream.buffer->isSubBufferProcessed[1])
|
||||
{
|
||||
ma_mutex_unlock(&AUDIO.System.lock);
|
||||
StopMusicStream(music);
|
||||
return;
|
||||
}
|
||||
|
||||
ma_mutex_unlock(&AUDIO.System.lock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!music.stream.buffer->isSubBufferProcessed[i]) continue; // No refilling required, move to next sub-buffer
|
||||
|
||||
int frameCountStillNeeded = framesToStream;
|
||||
int frameCountReadTotal = 0;
|
||||
|
||||
@@ -2008,19 +2024,6 @@ void UpdateMusicStream(Music music)
|
||||
}
|
||||
|
||||
UpdateAudioStreamInLockedState(music.stream, AUDIO.System.pcmBuffer, framesToStream);
|
||||
|
||||
music.stream.buffer->framesProcessed = music.stream.buffer->framesProcessed%music.frameCount;
|
||||
|
||||
if (framesLeft <= subBufferSizeInFrames)
|
||||
{
|
||||
if (!music.looping)
|
||||
{
|
||||
ma_mutex_unlock(&AUDIO.System.lock);
|
||||
// Streaming is ending, we filled latest frames from input
|
||||
StopMusicStream(music);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ma_mutex_unlock(&AUDIO.System.lock);
|
||||
@@ -2083,8 +2086,12 @@ float GetMusicTimePlayed(Music music)
|
||||
int subBufferSize = (int)music.stream.buffer->sizeInFrames/2;
|
||||
int framesInFirstBuffer = music.stream.buffer->isSubBufferProcessed[0]? 0 : subBufferSize;
|
||||
int framesInSecondBuffer = music.stream.buffer->isSubBufferProcessed[1]? 0 : subBufferSize;
|
||||
int framesInBuffers = framesInFirstBuffer + framesInSecondBuffer;
|
||||
if ((unsigned int)framesInBuffers > music.frameCount) {
|
||||
if (!music.looping) framesInBuffers = music.frameCount;
|
||||
}
|
||||
int framesSentToMix = music.stream.buffer->frameCursorPos%subBufferSize;
|
||||
int framesPlayed = (framesProcessed - framesInFirstBuffer - framesInSecondBuffer + framesSentToMix)%(int)music.frameCount;
|
||||
int framesPlayed = (framesProcessed - framesInBuffers + framesSentToMix)%(int)music.frameCount;
|
||||
if (framesPlayed < 0) framesPlayed += music.frameCount;
|
||||
secondsPlayed = (float)framesPlayed/music.stream.sampleRate;
|
||||
ma_mutex_unlock(&AUDIO.System.lock);
|
||||
@@ -2340,7 +2347,6 @@ void DetachAudioMixedProcessor(AudioCallback process)
|
||||
ma_mutex_unlock(&AUDIO.System.lock);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module specific Functions Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
@@ -2681,8 +2687,7 @@ static void UpdateAudioStreamInLockedState(AudioStream stream, const void *data,
|
||||
ma_uint32 subBufferSizeInFrames = stream.buffer->sizeInFrames/2;
|
||||
unsigned char *subBuffer = stream.buffer->data + ((subBufferSizeInFrames*stream.channels*(stream.sampleSize/8))*subBufferToUpdate);
|
||||
|
||||
// Total frames processed in buffer is always the complete size, filled with 0 if required
|
||||
stream.buffer->framesProcessed += subBufferSizeInFrames;
|
||||
stream.buffer->framesProcessed += frameCount;
|
||||
|
||||
// Does this API expect a whole buffer to be updated in one go?
|
||||
// Assuming so, but if not will need to change this logic
|
||||
|
||||
34
src/raylib.h
34
src/raylib.h
@@ -5,7 +5,7 @@
|
||||
* FEATURES:
|
||||
* - NO external dependencies, all required libraries included with raylib
|
||||
* - Multiplatform: Windows, Linux, FreeBSD, OpenBSD, NetBSD, DragonFly,
|
||||
* MacOS, Haiku, Android, Raspberry Pi, DRM native, HTML5.
|
||||
* MacOS, Haiku, Android, Raspberry Pi, DRM native, HTML5
|
||||
* - Written in plain C code (C99) in PascalCase/camelCase notation
|
||||
* - Hardware accelerated with OpenGL (1.1, 2.1, 3.3, 4.3, ES2, ES3 - choose at compile)
|
||||
* - Unique OpenGL abstraction layer (usable as standalone module): [rlgl]
|
||||
@@ -36,7 +36,7 @@
|
||||
* [rcore] msf_gif (Miles Fogle) for GIF recording
|
||||
* [rcore] sinfl (Micha Mettke) for DEFLATE decompression algorithm
|
||||
* [rcore] sdefl (Micha Mettke) for DEFLATE compression algorithm
|
||||
* [rcore] rprand (Ramon Snatamaria) for pseudo-random numbers generation
|
||||
* [rcore] rprand (Ramon Santamaria) for pseudo-random numbers generation
|
||||
* [rtextures] qoi (Dominic Szablewski - https://phoboslab.org) for QOI image manage
|
||||
* [rtextures] stb_image (Sean Barret) for images loading (BMP, TGA, PNG, JPEG, HDR...)
|
||||
* [rtextures] stb_image_write (Sean Barret) for image writing (BMP, TGA, PNG, JPG)
|
||||
@@ -743,7 +743,7 @@ typedef enum {
|
||||
GAMEPAD_BUTTON_RIGHT_THUMB // Gamepad joystick pressed button right
|
||||
} GamepadButton;
|
||||
|
||||
// Gamepad axis
|
||||
// Gamepad axes
|
||||
typedef enum {
|
||||
GAMEPAD_AXIS_LEFT_X = 0, // Gamepad left stick X axis
|
||||
GAMEPAD_AXIS_LEFT_Y = 1, // Gamepad left stick Y axis
|
||||
@@ -1129,7 +1129,7 @@ RLAPI bool SaveFileText(const char *fileName, const char *text); // Save text d
|
||||
// File system functions
|
||||
RLAPI bool FileExists(const char *fileName); // Check if file exists
|
||||
RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists
|
||||
RLAPI bool IsFileExtension(const char *fileName, const char *ext); // Check file extension (including point: .png, .wav)
|
||||
RLAPI bool IsFileExtension(const char *fileName, const char *ext); // Check file extension (recommended include point: .png, .wav)
|
||||
RLAPI int GetFileLength(const char *fileName); // Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h)
|
||||
RLAPI const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes dot: '.png')
|
||||
RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string
|
||||
@@ -1153,8 +1153,8 @@ RLAPI long GetFileModTime(const char *fileName); // Get file mo
|
||||
// Compression/Encoding functionality
|
||||
RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize); // Compress data (DEFLATE algorithm), memory must be MemFree()
|
||||
RLAPI unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // Decompress data (DEFLATE algorithm), memory must be MemFree()
|
||||
RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string, memory must be MemFree()
|
||||
RLAPI unsigned char *DecodeDataBase64(const char *data, int *outputSize); // Decode Base64 string data, memory must be MemFree()
|
||||
RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string (includes NULL terminator), memory must be MemFree()
|
||||
RLAPI unsigned char *DecodeDataBase64(const char *text, int *outputSize); // Decode Base64 string (expected NULL terminated), memory must be MemFree()
|
||||
RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize); // Compute CRC32 hash code
|
||||
RLAPI unsigned int *ComputeMD5(unsigned char *data, int dataSize); // Compute MD5 hash code, returns static int[4] (16 bytes)
|
||||
RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes)
|
||||
@@ -1192,8 +1192,8 @@ RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Check if a game
|
||||
RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Check if a gamepad button has been released once
|
||||
RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Check if a gamepad button is NOT being pressed
|
||||
RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed
|
||||
RLAPI int GetGamepadAxisCount(int gamepad); // Get gamepad axis count for a gamepad
|
||||
RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Get axis movement value for a gamepad axis
|
||||
RLAPI int GetGamepadAxisCount(int gamepad); // Get axis count for a gamepad
|
||||
RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Get movement value for a gamepad axis
|
||||
RLAPI int SetGamepadMappings(const char *mappings); // Set internal gamepad mappings (SDL_GameControllerDB)
|
||||
RLAPI void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration); // Set gamepad vibration for both motors (duration in seconds)
|
||||
|
||||
@@ -1264,7 +1264,9 @@ RLAPI void DrawCircleV(Vector2 center, float radius, Color color);
|
||||
RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline
|
||||
RLAPI void DrawCircleLinesV(Vector2 center, float radius, Color color); // Draw circle outline (Vector version)
|
||||
RLAPI void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse
|
||||
RLAPI void DrawEllipseV(Vector2 center, float radiusH, float radiusV, Color color); // Draw ellipse (Vector version)
|
||||
RLAPI void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse outline
|
||||
RLAPI void DrawEllipseLinesV(Vector2 center, float radiusH, float radiusV, Color color); // Draw ellipse outline (Vector version)
|
||||
RLAPI void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring
|
||||
RLAPI void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring outline
|
||||
RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle
|
||||
@@ -1273,7 +1275,7 @@ RLAPI void DrawRectangleRec(Rectangle rec, Color color);
|
||||
RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters
|
||||
RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color top, Color bottom); // Draw a vertical-gradient-filled rectangle
|
||||
RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color left, Color right); // Draw a horizontal-gradient-filled rectangle
|
||||
RLAPI void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color topRight, Color bottomRight); // Draw a gradient-filled rectangle with custom vertex colors
|
||||
RLAPI void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color bottomRight, Color topRight); // Draw a gradient-filled rectangle with custom vertex colors
|
||||
RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline
|
||||
RLAPI void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color); // Draw rectangle outline with extended parameters
|
||||
RLAPI void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color); // Draw rectangle with rounded edges
|
||||
@@ -1406,8 +1408,8 @@ RLAPI void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color c
|
||||
RLAPI void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle within an image
|
||||
RLAPI void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3); // Draw triangle with interpolated colors within an image
|
||||
RLAPI void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline within an image
|
||||
RLAPI void ImageDrawTriangleFan(Image *dst, Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points within an image (first vertex is the center)
|
||||
RLAPI void ImageDrawTriangleStrip(Image *dst, Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points within an image
|
||||
RLAPI void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points within an image (first vertex is the center)
|
||||
RLAPI void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points within an image
|
||||
RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source)
|
||||
RLAPI void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination)
|
||||
RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination)
|
||||
@@ -1422,8 +1424,8 @@ RLAPI bool IsTextureValid(Texture2D texture);
|
||||
RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM)
|
||||
RLAPI bool IsRenderTextureValid(RenderTexture2D target); // Check if a render texture is valid (loaded in GPU)
|
||||
RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM)
|
||||
RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data
|
||||
RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels); // Update GPU texture rectangle with new data
|
||||
RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data (pixels should be able to fill texture)
|
||||
RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels); // Update GPU texture rectangle with new data (pixels and rec should fit in texture)
|
||||
|
||||
// Texture configuration functions
|
||||
RLAPI void GenTextureMipmaps(Texture2D *texture); // Generate GPU mipmaps for a texture
|
||||
@@ -1512,9 +1514,9 @@ RLAPI const char *TextSubtext(const char *text, int position, int length);
|
||||
RLAPI char *TextReplace(const char *text, const char *replace, const char *by); // Replace text string (WARNING: memory must be freed!)
|
||||
RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a position (WARNING: memory must be freed!)
|
||||
RLAPI char *TextJoin(char **textList, int count, const char *delimiter); // Join text strings with delimiter
|
||||
RLAPI char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings
|
||||
RLAPI char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings
|
||||
RLAPI void TextAppend(char *text, const char *append, int *position); // Append text at specific position and move cursor!
|
||||
RLAPI int TextFindIndex(const char *text, const char *find); // Find first text occurrence within a string
|
||||
RLAPI int TextFindIndex(const char *text, const char *find); // Find first text occurrence within a string, -1 if not found
|
||||
RLAPI char *TextToUpper(const char *text); // Get upper case version of provided string
|
||||
RLAPI char *TextToLower(const char *text); // Get lower case version of provided string
|
||||
RLAPI char *TextToPascal(const char *text); // Get Pascal case notation version of provided string
|
||||
@@ -1644,7 +1646,7 @@ RLAPI Sound LoadSound(const char *fileName); // Load so
|
||||
RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data
|
||||
RLAPI Sound LoadSoundAlias(Sound source); // Create a new sound that shares the same sample data as the source sound, does not own the sound data
|
||||
RLAPI bool IsSoundValid(Sound sound); // Checks if a sound is valid (data loaded and buffers initialized)
|
||||
RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data
|
||||
RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data (data and frame count should fit in sound)
|
||||
RLAPI void UnloadWave(Wave wave); // Unload wave data
|
||||
RLAPI void UnloadSound(Sound sound); // Unload sound
|
||||
RLAPI void UnloadSoundAlias(Sound alias); // Unload a sound alias (does not deallocate sample data)
|
||||
|
||||
@@ -329,7 +329,7 @@ RMAPI float Vector2DistanceSqr(Vector2 v1, Vector2 v2)
|
||||
}
|
||||
|
||||
// Calculate the signed angle from v1 to v2, relative to the origin (0, 0)
|
||||
// NOTE: Coordinate system convention: positive X right, positive Y down,
|
||||
// NOTE: Coordinate system convention: positive X right, positive Y down
|
||||
// positive angles appear clockwise, and negative angles appear counterclockwise
|
||||
RMAPI float Vector2Angle(Vector2 v1, Vector2 v2)
|
||||
{
|
||||
|
||||
@@ -65,8 +65,8 @@
|
||||
#endif
|
||||
|
||||
#if defined(RCAMERA_STANDALONE)
|
||||
#define CAMERA_CULL_DISTANCE_NEAR 0.01
|
||||
#define CAMERA_CULL_DISTANCE_FAR 1000.0
|
||||
#define CAMERA_CULL_DISTANCE_NEAR 0.05
|
||||
#define CAMERA_CULL_DISTANCE_FAR 4000.0
|
||||
#else
|
||||
#define CAMERA_CULL_DISTANCE_NEAR RL_CULL_DISTANCE_NEAR
|
||||
#define CAMERA_CULL_DISTANCE_FAR RL_CULL_DISTANCE_FAR
|
||||
|
||||
308
src/rcore.c
308
src/rcore.c
@@ -113,7 +113,7 @@
|
||||
|
||||
#include <stdlib.h> // Required for: srand(), rand(), atexit()
|
||||
#include <stdio.h> // Required for: sprintf() [Used in OpenURL()]
|
||||
#include <string.h> // Required for: strrchr(), strcmp(), strlen(), memset()
|
||||
#include <string.h> // Required for: strlen(), strcpy(), strcmp(), strrchr(), memset()
|
||||
#include <time.h> // Required for: time() [Used in InitTimer()]
|
||||
#include <math.h> // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()]
|
||||
|
||||
@@ -235,10 +235,10 @@ __declspec(dllimport) unsigned int __stdcall timeEndPeriod(unsigned int uPeriod)
|
||||
#define MAX_GAMEPADS 4 // Maximum number of gamepads supported
|
||||
#endif
|
||||
#ifndef MAX_GAMEPAD_NAME_LENGTH
|
||||
#define MAX_GAMEPAD_NAME_LENGTH 128 // Maximum number of characters of gamepad name (byte size)
|
||||
#define MAX_GAMEPAD_NAME_LENGTH 128 // Maximum number of characters in a gamepad name (byte size)
|
||||
#endif
|
||||
#ifndef MAX_GAMEPAD_AXIS
|
||||
#define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad)
|
||||
#ifndef MAX_GAMEPAD_AXES
|
||||
#define MAX_GAMEPAD_AXES 8 // Maximum number of axes supported (per gamepad)
|
||||
#endif
|
||||
#ifndef MAX_GAMEPAD_BUTTONS
|
||||
#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
|
||||
@@ -354,12 +354,12 @@ typedef struct CoreData {
|
||||
} Touch;
|
||||
struct {
|
||||
int lastButtonPressed; // Register last gamepad button pressed
|
||||
int axisCount[MAX_GAMEPADS]; // Register number of available gamepad axis
|
||||
int axisCount[MAX_GAMEPADS]; // Register number of available gamepad axes
|
||||
bool ready[MAX_GAMEPADS]; // Flag to know if gamepad is ready
|
||||
char name[MAX_GAMEPADS][MAX_GAMEPAD_NAME_LENGTH]; // Gamepad name holder
|
||||
char currentButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Current gamepad buttons state
|
||||
char previousButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Previous gamepad buttons state
|
||||
float axisState[MAX_GAMEPADS][MAX_GAMEPAD_AXIS]; // Gamepad axis state
|
||||
float axisState[MAX_GAMEPADS][MAX_GAMEPAD_AXES]; // Gamepad axes state
|
||||
|
||||
} Gamepad;
|
||||
} Input;
|
||||
@@ -539,7 +539,7 @@ const char *TextFormat(const char *text, ...); // Formatting of tex
|
||||
#pragma message ("WARNING: Getting image from the clipboard might not work without SUPPORT_FILEFORMAT_PNG or SUPPORT_FILEFORMAT_JPG")
|
||||
#endif
|
||||
|
||||
// Not needed because `rtexture.c` will automatically defined STBI_REQUIRED when any SUPPORT_FILEFORMAT_* is defined
|
||||
// Not needed because 'rtexture.c' will automatically defined STBI_REQUIRED when any SUPPORT_FILEFORMAT_* is defined
|
||||
// #if !defined(STBI_REQUIRED)
|
||||
// #pragma message ("WARNING: "STBI_REQUIRED is not defined, that means we can't load images from clipbard"
|
||||
// #endif
|
||||
@@ -827,6 +827,8 @@ int GetScreenHeight(void)
|
||||
// Get current render width which is equal to screen width*dpi scale
|
||||
int GetRenderWidth(void)
|
||||
{
|
||||
if (CORE.Window.usingFbo) return CORE.Window.currentFbo.width;
|
||||
|
||||
int width = 0;
|
||||
#if defined(__APPLE__)
|
||||
Vector2 scale = GetWindowScaleDPI();
|
||||
@@ -840,6 +842,8 @@ int GetRenderWidth(void)
|
||||
// Get current screen height which is equal to screen height*dpi scale
|
||||
int GetRenderHeight(void)
|
||||
{
|
||||
if (CORE.Window.usingFbo) return CORE.Window.currentFbo.height;
|
||||
|
||||
int height = 0;
|
||||
#if defined(__APPLE__)
|
||||
Vector2 scale = GetWindowScaleDPI();
|
||||
@@ -1526,7 +1530,7 @@ Ray GetScreenToWorldRayEx(Vector2 position, Camera camera, int width, int height
|
||||
double right = top*aspect;
|
||||
|
||||
// Calculate projection matrix from orthographic
|
||||
matProj = MatrixOrtho(-right, right, -top, top, 0.01, 1000.0);
|
||||
matProj = MatrixOrtho(-right, right, -top, top, rlGetCullDistanceNear(), rlGetCullDistanceFar());
|
||||
}
|
||||
|
||||
// Unproject far/near points
|
||||
@@ -1889,7 +1893,7 @@ void TakeScreenshot(const char *fileName)
|
||||
char path[512] = { 0 };
|
||||
strcpy(path, TextFormat("%s/%s", CORE.Storage.basePath, fileName));
|
||||
|
||||
ExportImage(image, path); // WARNING: Module required: rtextures
|
||||
ExportImage(image, path); // WARNING: Module required: rtextures
|
||||
RL_FREE(imgData);
|
||||
|
||||
if (FileExists(path)) TRACELOG(LOG_INFO, "SYSTEM: [%s] Screenshot taken successfully", path);
|
||||
@@ -1936,34 +1940,61 @@ bool FileExists(const char *fileName)
|
||||
}
|
||||
|
||||
// Check file extension
|
||||
// NOTE: Extensions checking is not case-sensitive
|
||||
bool IsFileExtension(const char *fileName, const char *ext)
|
||||
{
|
||||
#define MAX_FILE_EXTENSION_LENGTH 16
|
||||
#define MAX_FILE_EXTENSIONS 32
|
||||
|
||||
bool result = false;
|
||||
const char *fileExt = GetFileExtension(fileName);
|
||||
|
||||
if (fileExt != NULL)
|
||||
{
|
||||
#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_TEXT_MANIPULATION)
|
||||
int extCount = 0;
|
||||
char **checkExts = TextSplit(ext, ';', &extCount); // WARNING: Module required: rtext
|
||||
|
||||
char fileExtLower[MAX_FILE_EXTENSION_LENGTH + 1] = { 0 };
|
||||
strncpy(fileExtLower, TextToLower(fileExt), MAX_FILE_EXTENSION_LENGTH); // WARNING: Module required: rtext
|
||||
int fileExtLen = strlen(fileExt);
|
||||
char fileExtLower[8] = { 0 };
|
||||
char *fileExtLowerPtr = fileExtLower;
|
||||
for (int i = 0; i < fileExtLen; i++)
|
||||
{
|
||||
// Copy and convert to lower-case
|
||||
if ((fileExt[i] >= 'A') && (fileExt[i] <= 'Z')) fileExtLower[i] = fileExt[i] + 32;
|
||||
else fileExtLower[i] = fileExt[i];
|
||||
}
|
||||
|
||||
int extCount = 1;
|
||||
int extLen = strlen(ext);
|
||||
char *extList = (char *)RL_CALLOC(extLen + 1, 1);
|
||||
char *extListPtrs[MAX_FILE_EXTENSIONS] = { 0 };
|
||||
strcpy(extList, ext);
|
||||
extListPtrs[0] = extList;
|
||||
|
||||
for (int i = 0; i < extLen; i++)
|
||||
{
|
||||
// Convert to lower-case if extension is upper-case
|
||||
if ((extList[i] >= 'A') && (extList[i] <= 'Z')) extList[i] += 32;
|
||||
|
||||
// Get pointer to next extension and add null-terminator
|
||||
if ((extList[i] == ';') && (extCount < (MAX_FILE_EXTENSIONS - 1)))
|
||||
{
|
||||
extList[i] = '\0';
|
||||
extListPtrs[extCount] = extList + i + 1;
|
||||
extCount++;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < extCount; i++)
|
||||
{
|
||||
if (strcmp(fileExtLower, TextToLower(checkExts[i])) == 0)
|
||||
// Consider the case where extension provided
|
||||
// does not start with the '.'
|
||||
fileExtLowerPtr = fileExtLower;
|
||||
if (extListPtrs[i][0] != '.') fileExtLowerPtr++;
|
||||
|
||||
if (strcmp(fileExtLowerPtr, extListPtrs[i]) == 0)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (strcmp(fileExt, ext) == 0) result = true;
|
||||
#endif
|
||||
|
||||
RL_FREE(extList);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -2500,7 +2531,7 @@ unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDa
|
||||
|
||||
#if defined(SUPPORT_COMPRESSION_API)
|
||||
// Compress data and generate a valid DEFLATE stream
|
||||
struct sdefl *sdefl = RL_CALLOC(1, sizeof(struct sdefl)); // WARNING: Possible stack overflow, struct sdefl is almost 1MB
|
||||
struct sdefl *sdefl = (struct sdefl *)RL_CALLOC(1, sizeof(struct sdefl)); // WARNING: Possible stack overflow, struct sdefl is almost 1MB
|
||||
int bounds = sdefl_bound(dataSize);
|
||||
compData = (unsigned char *)RL_CALLOC(bounds, 1);
|
||||
|
||||
@@ -2539,96 +2570,112 @@ unsigned char *DecompressData(const unsigned char *compData, int compDataSize, i
|
||||
}
|
||||
|
||||
// Encode data to Base64 string
|
||||
// NOTE: Returned string includes NULL terminator, considered on outputSize
|
||||
char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize)
|
||||
{
|
||||
static const unsigned char base64encodeTable[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
|
||||
};
|
||||
// Base64 conversion table from RFC 4648 [0..63]
|
||||
// NOTE: They represent 64 values (6 bits), to encode 3 bytes of data into 4 "sixtets" (6bit characters)
|
||||
static const char base64EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
static const int modTable[] = { 0, 2, 1 };
|
||||
// Compute expected size and padding
|
||||
int paddedSize = dataSize;
|
||||
while (paddedSize%3 != 0) paddedSize++; // Padding bytes to round 4*(dataSize/3) to 4 bytes
|
||||
int estimatedOutputSize = 4*(paddedSize/3);
|
||||
int padding = paddedSize - dataSize;
|
||||
|
||||
*outputSize = 4*((dataSize + 2)/3);
|
||||
// Adding null terminator to string
|
||||
estimatedOutputSize += 1;
|
||||
|
||||
char *encodedData = (char *)RL_MALLOC(*outputSize);
|
||||
// Load some memory to store encoded string
|
||||
char *encodedData = (char *)RL_CALLOC(estimatedOutputSize, 1);
|
||||
if (encodedData == NULL) return NULL;
|
||||
|
||||
if (encodedData == NULL) return NULL; // Security check
|
||||
|
||||
for (int i = 0, j = 0; i < dataSize;)
|
||||
int outputCount = 0;
|
||||
for (int i = 0; i < dataSize;)
|
||||
{
|
||||
unsigned int octetA = (i < dataSize)? (unsigned char)data[i++] : 0;
|
||||
unsigned int octetB = (i < dataSize)? (unsigned char)data[i++] : 0;
|
||||
unsigned int octetC = (i < dataSize)? (unsigned char)data[i++] : 0;
|
||||
unsigned int octetA = 0;
|
||||
unsigned int octetB = 0;
|
||||
unsigned int octetC = 0;
|
||||
unsigned int octetPack = 0;
|
||||
|
||||
unsigned int triple = (octetA << 0x10) + (octetB << 0x08) + octetC;
|
||||
octetA = data[i]; // Generates 2 sextets
|
||||
octetB = ((i + 1) < dataSize)? data[i + 1] : 0; // Generates 3 sextets
|
||||
octetC = ((i + 2) < dataSize)? data[i + 2] : 0; // Generates 4 sextets
|
||||
|
||||
encodedData[j++] = base64encodeTable[(triple >> 3*6) & 0x3F];
|
||||
encodedData[j++] = base64encodeTable[(triple >> 2*6) & 0x3F];
|
||||
encodedData[j++] = base64encodeTable[(triple >> 1*6) & 0x3F];
|
||||
encodedData[j++] = base64encodeTable[(triple >> 0*6) & 0x3F];
|
||||
octetPack = (octetA << 16) | (octetB << 8) | octetC;
|
||||
|
||||
encodedData[outputCount + 0] = (unsigned char)(base64EncodeTable[(octetPack >> 18) & 0x3f]);
|
||||
encodedData[outputCount + 1] = (unsigned char)(base64EncodeTable[(octetPack >> 12) & 0x3f]);
|
||||
encodedData[outputCount + 2] = (unsigned char)(base64EncodeTable[(octetPack >> 6) & 0x3f]);
|
||||
encodedData[outputCount + 3] = (unsigned char)(base64EncodeTable[octetPack & 0x3f]);
|
||||
outputCount += 4;
|
||||
i += 3;
|
||||
}
|
||||
|
||||
for (int i = 0; i < modTable[dataSize%3]; i++) encodedData[*outputSize - 1 - i] = '='; // Padding character
|
||||
// Add required padding bytes
|
||||
for (int p = 0; p < padding; p++) encodedData[outputCount - p - 1] = '=';
|
||||
|
||||
// Add null terminator to string
|
||||
encodedData[outputCount] = '\0';
|
||||
outputCount++;
|
||||
|
||||
if (outputCount != estimatedOutputSize) TRACELOG(LOG_WARNING, "BASE64: Output size differs from estimation");
|
||||
|
||||
*outputSize = estimatedOutputSize;
|
||||
return encodedData;
|
||||
}
|
||||
|
||||
// Decode Base64 string data
|
||||
unsigned char *DecodeDataBase64(const char *data, int *outputSize)
|
||||
// Decode Base64 string (expected NULL terminated)
|
||||
unsigned char *DecodeDataBase64(const char *text, int *outputSize)
|
||||
{
|
||||
static const unsigned char base64decodeTable[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
|
||||
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
|
||||
// Base64 decode table
|
||||
// NOTE: Following ASCII order [0..255] assigning the expected sixtet value to
|
||||
// every character in the corresponding ASCII position
|
||||
static const unsigned char base64DecodeTable[256] = {
|
||||
['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4, ['F'] = 5, ['G'] = 6, ['H'] = 7,
|
||||
['I'] = 8, ['J'] = 9, ['K'] = 10, ['L'] = 11, ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15,
|
||||
['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19, ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24, ['Z'] = 25,
|
||||
['a'] = 26, ['b'] = 27, ['c'] = 28, ['d'] = 29, ['e'] = 30, ['f'] = 31, ['g'] = 32, ['h'] = 33,
|
||||
['i'] = 34, ['j'] = 35, ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39, ['o'] = 40, ['p'] = 41,
|
||||
['q'] = 42, ['r'] = 43, ['s'] = 44, ['t'] = 45, ['u'] = 46, ['v'] = 47, ['w'] = 48, ['x'] = 49, ['y'] = 50, ['z'] = 51,
|
||||
['0'] = 52, ['1'] = 53, ['2'] = 54, ['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59,
|
||||
['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63
|
||||
};
|
||||
|
||||
// Get output size of Base64 input data
|
||||
int outSize = 0;
|
||||
for (int i = 0; data[4*i] != 0; i++)
|
||||
// Compute expected size and padding
|
||||
int dataSize = (int)strlen(text); // WARNING: Expecting NULL terminated strings!
|
||||
int ending = dataSize - 1;
|
||||
int padding = 0;
|
||||
while (text[ending] == '=') { padding++; ending--; }
|
||||
int estimatedOutputSize = 3*(dataSize/4) - padding;
|
||||
int maxOutputSize = 3*(dataSize/4);
|
||||
|
||||
// Load some memory to store decoded data
|
||||
// NOTE: Allocated enough size to include padding
|
||||
unsigned char *decodedData = (unsigned char *)RL_CALLOC(maxOutputSize, 1);
|
||||
if (decodedData == NULL) return NULL;
|
||||
|
||||
int outputCount = 0;
|
||||
for (int i = 0; i < dataSize;)
|
||||
{
|
||||
if (data[4*i + 3] == '=')
|
||||
{
|
||||
if (data[4*i + 2] == '=') outSize += 1;
|
||||
else outSize += 2;
|
||||
}
|
||||
else outSize += 3;
|
||||
// Every 4 sixtets must generate 3 octets
|
||||
unsigned int sixtetA = base64DecodeTable[(unsigned char)text[i]];
|
||||
unsigned int sixtetB = base64DecodeTable[(unsigned char)text[i + 1]];
|
||||
unsigned int sixtetC = ((unsigned char)text[i + 2] != '=')? base64DecodeTable[(unsigned char)text[i + 2]] : 0;
|
||||
unsigned int sixtetD = ((unsigned char)text[i + 3] != '=')? base64DecodeTable[(unsigned char)text[i + 3]] : 0;
|
||||
|
||||
unsigned int octetPack = (sixtetA << 18) | (sixtetB << 12) | (sixtetC << 6) | sixtetD;
|
||||
|
||||
decodedData[outputCount + 0] = (octetPack >> 16) & 0xff;
|
||||
decodedData[outputCount + 1] = (octetPack >> 8) & 0xff;
|
||||
decodedData[outputCount + 2] = octetPack & 0xff;
|
||||
outputCount += 3;
|
||||
i += 4;
|
||||
}
|
||||
|
||||
// Allocate memory to store decoded Base64 data
|
||||
unsigned char *decodedData = (unsigned char *)RL_MALLOC(outSize);
|
||||
if (estimatedOutputSize != (outputCount - padding)) TRACELOG(LOG_WARNING, "BASE64: Decoded size differs from estimation");
|
||||
|
||||
for (int i = 0; i < outSize/3; i++)
|
||||
{
|
||||
unsigned char a = base64decodeTable[(int)data[4*i]];
|
||||
unsigned char b = base64decodeTable[(int)data[4*i + 1]];
|
||||
unsigned char c = base64decodeTable[(int)data[4*i + 2]];
|
||||
unsigned char d = base64decodeTable[(int)data[4*i + 3]];
|
||||
|
||||
decodedData[3*i] = (a << 2) | (b >> 4);
|
||||
decodedData[3*i + 1] = (b << 4) | (c >> 2);
|
||||
decodedData[3*i + 2] = (c << 6) | d;
|
||||
}
|
||||
|
||||
if (outSize%3 == 1)
|
||||
{
|
||||
int n = outSize/3;
|
||||
unsigned char a = base64decodeTable[(int)data[4*n]];
|
||||
unsigned char b = base64decodeTable[(int)data[4*n + 1]];
|
||||
decodedData[outSize - 1] = (a << 2) | (b >> 4);
|
||||
}
|
||||
else if (outSize%3 == 2)
|
||||
{
|
||||
int n = outSize/3;
|
||||
unsigned char a = base64decodeTable[(int)data[4*n]];
|
||||
unsigned char b = base64decodeTable[(int)data[4*n + 1]];
|
||||
unsigned char c = base64decodeTable[(int)data[4*n + 2]];
|
||||
decodedData[outSize - 2] = (a << 2) | (b >> 4);
|
||||
decodedData[outSize - 1] = (b << 4) | (c >> 2);
|
||||
}
|
||||
|
||||
*outputSize = outSize;
|
||||
*outputSize = estimatedOutputSize;
|
||||
return decodedData;
|
||||
}
|
||||
|
||||
@@ -2636,38 +2683,38 @@ unsigned char *DecodeDataBase64(const char *data, int *outputSize)
|
||||
unsigned int ComputeCRC32(unsigned char *data, int dataSize)
|
||||
{
|
||||
static unsigned int crcTable[256] = {
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||
0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
||||
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
||||
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
||||
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
||||
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
||||
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
||||
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
||||
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
||||
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
||||
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
||||
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
||||
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
||||
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
||||
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
||||
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
||||
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
||||
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
||||
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
||||
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
||||
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
||||
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
unsigned int crc = ~0u;
|
||||
@@ -2731,7 +2778,7 @@ unsigned int *ComputeMD5(unsigned char *data, int dataSize)
|
||||
|
||||
int newDataSize = ((((dataSize + 8)/64) + 1)*64) - 8;
|
||||
|
||||
unsigned char *msg = RL_CALLOC(newDataSize + 64, 1); // Initialize with '0' bits, allocating 64 extra bytes
|
||||
unsigned char *msg = (unsigned char *)RL_CALLOC(newDataSize + 64, 1); // Initialize with '0' bits, allocating 64 extra bytes
|
||||
memcpy(msg, data, dataSize);
|
||||
msg[dataSize] = 128; // Write the '1' bit
|
||||
|
||||
@@ -2821,7 +2868,7 @@ unsigned int *ComputeSHA1(unsigned char *data, int dataSize)
|
||||
|
||||
int newDataSize = ((((dataSize + 8)/64) + 1)*64);
|
||||
|
||||
unsigned char *msg = RL_CALLOC(newDataSize, 1); // Initialize with '0' bits
|
||||
unsigned char *msg = (unsigned char *)RL_CALLOC(newDataSize, 1); // Initialize with '0' bits
|
||||
memcpy(msg, data, dataSize);
|
||||
msg[dataSize] = 128; // Write the '1' bit
|
||||
|
||||
@@ -3352,11 +3399,11 @@ int GetGamepadAxisCount(int gamepad)
|
||||
// Get axis movement vector for a gamepad
|
||||
float GetGamepadAxisMovement(int gamepad, int axis)
|
||||
{
|
||||
float value = (axis == GAMEPAD_AXIS_LEFT_TRIGGER || axis == GAMEPAD_AXIS_RIGHT_TRIGGER)? -1.0f : 0.0f;
|
||||
float value = ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))? -1.0f : 0.0f;
|
||||
|
||||
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXIS))
|
||||
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXES))
|
||||
{
|
||||
float movement = value < 0.0f ? CORE.Input.Gamepad.axisState[gamepad][axis] : fabsf(CORE.Input.Gamepad.axisState[gamepad][axis]);
|
||||
float movement = (value < 0.0f)? CORE.Input.Gamepad.axisState[gamepad][axis] : fabsf(CORE.Input.Gamepad.axisState[gamepad][axis]);
|
||||
|
||||
if (movement > value) value = CORE.Input.Gamepad.axisState[gamepad][axis];
|
||||
}
|
||||
@@ -3741,7 +3788,8 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const
|
||||
// Scan all files and directories recursively from a base path
|
||||
static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *files, const char *filter)
|
||||
{
|
||||
static char path[MAX_FILEPATH_LENGTH] = { 0 };
|
||||
// WARNING: Path can not be static or it will be reused between recursive function calls!
|
||||
char path[MAX_FILEPATH_LENGTH] = { 0 };
|
||||
memset(path, 0, MAX_FILEPATH_LENGTH);
|
||||
|
||||
struct dirent *dp = NULL;
|
||||
@@ -4034,10 +4082,10 @@ static void RecordAutomationEvent(void)
|
||||
if (currentEventList->count == currentEventList->capacity) return; // Security check
|
||||
}
|
||||
|
||||
for (int axis = 0; axis < MAX_GAMEPAD_AXIS; axis++)
|
||||
for (int axis = 0; axis < MAX_GAMEPAD_AXES; axis++)
|
||||
{
|
||||
// Event type: INPUT_GAMEPAD_AXIS_MOTION
|
||||
float defaultMovement = (axis == GAMEPAD_AXIS_LEFT_TRIGGER || axis == GAMEPAD_AXIS_RIGHT_TRIGGER)? -1.0f : 0.0f;
|
||||
float defaultMovement = ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))? -1.0f : 0.0f;
|
||||
if (GetGamepadAxisMovement(gamepad, axis) != defaultMovement)
|
||||
{
|
||||
currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
|
||||
|
||||
79
src/rlgl.h
79
src/rlgl.h
@@ -710,6 +710,7 @@ RLAPI void rlSetBlendFactorsSeparate(int glSrcRGB, int glDstRGB, int glSrcAlpha,
|
||||
RLAPI void rlglInit(int width, int height); // Initialize rlgl (buffers, shaders, textures, states)
|
||||
RLAPI void rlglClose(void); // De-initialize rlgl (buffers, shaders, textures)
|
||||
RLAPI void rlLoadExtensions(void *loader); // Load OpenGL extensions (loader function required)
|
||||
RLAPI void *rlGetProcAddress(const char *procName); // Get OpenGL procedure address
|
||||
RLAPI int rlGetVersion(void); // Get current OpenGL version
|
||||
RLAPI void rlSetFramebufferWidth(int width); // Set current framebuffer width
|
||||
RLAPI int rlGetFramebufferWidth(void); // Get default framebuffer width
|
||||
@@ -1041,10 +1042,15 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
|
||||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
|
||||
typedef void *(*rlglLoadProc)(const char *name); // OpenGL extension functions loader signature (same as GLADloadproc)
|
||||
|
||||
typedef struct rlglData {
|
||||
rlRenderBatch *currentBatch; // Current render batch
|
||||
rlRenderBatch defaultBatch; // Default internal render batch
|
||||
|
||||
rlglLoadProc loader; // OpenGL function loader
|
||||
|
||||
struct {
|
||||
int vertexCounter; // Current active render batch vertex counter (generic, used for all batches)
|
||||
float texcoordx, texcoordy; // Current active texture coordinate (added on glVertex*())
|
||||
@@ -1114,8 +1120,6 @@ typedef struct rlglData {
|
||||
} ExtSupported; // Extensions supported flags
|
||||
} rlglData;
|
||||
|
||||
typedef void *(*rlglLoadProc)(const char *name); // OpenGL extension functions loader signature (same as GLADloadproc)
|
||||
|
||||
#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
@@ -1153,16 +1157,16 @@ static const char *rlGetCompressedFormatName(int format); // Get compressed form
|
||||
|
||||
static int rlGetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture)
|
||||
|
||||
static Matrix rlMatrixIdentity(void); // Get identity matrix
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
// Auxiliar matrix math functions
|
||||
typedef struct rl_float16 {
|
||||
float v[16];
|
||||
} rl_float16;
|
||||
typedef struct rl_float16 { float v[16]; } rl_float16;
|
||||
static rl_float16 rlMatrixToFloatV(Matrix mat); // Get float array of matrix data
|
||||
#define rlMatrixToFloat(mat) (rlMatrixToFloatV(mat).v) // Get float vector for Matrix
|
||||
static Matrix rlMatrixIdentity(void); // Get identity matrix
|
||||
static Matrix rlMatrixMultiply(Matrix left, Matrix right); // Multiply two matrices
|
||||
static Matrix rlMatrixTranspose(Matrix mat); // Transposes provided matrix
|
||||
static Matrix rlMatrixInvert(Matrix mat); // Invert provided matrix
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition - Matrix operations
|
||||
@@ -1748,7 +1752,6 @@ void rlTextureParameters(unsigned int id, int param, int value)
|
||||
#endif
|
||||
}
|
||||
else glTexParameteri(GL_TEXTURE_2D, param, value);
|
||||
|
||||
} break;
|
||||
case RL_TEXTURE_MAG_FILTER:
|
||||
case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_2D, param, value); break;
|
||||
@@ -1793,7 +1796,6 @@ void rlCubemapParameters(unsigned int id, int param, int value)
|
||||
else TRACELOG(RL_LOG_WARNING, "GL: Clamp mirror wrap mode not supported (GL_MIRROR_CLAMP_EXT)");
|
||||
}
|
||||
else glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value);
|
||||
|
||||
} break;
|
||||
case RL_TEXTURE_MAG_FILTER:
|
||||
case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value); break;
|
||||
@@ -1887,7 +1889,7 @@ void rlActiveDrawBuffers(int count)
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
if (count > 8) TRACELOG(LOG_WARNING, "GL: Max color buffers limited to 8");
|
||||
if (count > 8) TRACELOG(RL_LOG_WARNING, "GL: Max color buffers limited to 8");
|
||||
else
|
||||
{
|
||||
unsigned int buffers[8] = {
|
||||
@@ -1904,7 +1906,7 @@ void rlActiveDrawBuffers(int count)
|
||||
glDrawBuffers(count, buffers);
|
||||
}
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "GL: One color buffer active by default");
|
||||
else TRACELOG(RL_LOG_WARNING, "GL: One color buffer active by default");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2112,14 +2114,12 @@ void rlSetBlendMode(int mode)
|
||||
{
|
||||
// NOTE: Using GL blend src/dst factors and GL equation configured with rlSetBlendFactors()
|
||||
glBlendFunc(RLGL.State.glBlendSrcFactor, RLGL.State.glBlendDstFactor); glBlendEquation(RLGL.State.glBlendEquation);
|
||||
|
||||
} break;
|
||||
case RL_BLEND_CUSTOM_SEPARATE:
|
||||
{
|
||||
// NOTE: Using GL blend src/dst factors and GL equation configured with rlSetBlendFactorsSeparate()
|
||||
glBlendFuncSeparate(RLGL.State.glBlendSrcFactorRGB, RLGL.State.glBlendDestFactorRGB, RLGL.State.glBlendSrcFactorAlpha, RLGL.State.glBlendDestFactorAlpha);
|
||||
glBlendEquationSeparate(RLGL.State.glBlendEquationRGB, RLGL.State.glBlendEquationAlpha);
|
||||
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
@@ -2223,10 +2223,10 @@ static void GLAPIENTRY rlDebugMessageCallback(GLenum source, GLenum type, GLuint
|
||||
default: break;
|
||||
}
|
||||
|
||||
TRACELOG(LOG_WARNING, "GL: OpenGL debug message: %s", message);
|
||||
TRACELOG(LOG_WARNING, " > Type: %s", msgType);
|
||||
TRACELOG(LOG_WARNING, " > Source = %s", msgSource);
|
||||
TRACELOG(LOG_WARNING, " > Severity = %s", msgSeverity);
|
||||
TRACELOG(RL_LOG_WARNING, "GL: OpenGL debug message: %s", message);
|
||||
TRACELOG(RL_LOG_WARNING, " > Type: %s", msgType);
|
||||
TRACELOG(RL_LOG_WARNING, " > Source = %s", msgSource);
|
||||
TRACELOG(RL_LOG_WARNING, " > Severity = %s", msgSeverity);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2429,7 +2429,7 @@ void rlLoadExtensions(void *loader)
|
||||
|
||||
// Get supported extensions list
|
||||
GLint numExt = 0;
|
||||
const char **extList = RL_MALLOC(512*sizeof(const char *)); // Allocate 512 strings pointers (2 KB)
|
||||
const char **extList = (const char **)RL_MALLOC(512*sizeof(const char *)); // Allocate 512 strings pointers (2 KB)
|
||||
const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string
|
||||
|
||||
// NOTE: We have to duplicate string because glGetString() returns a const string
|
||||
@@ -2572,6 +2572,8 @@ void rlLoadExtensions(void *loader)
|
||||
TRACELOG(RL_LOG_INFO, " > GLSL: %s", glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
RLGL.loader = (rlglLoadProc)loader;
|
||||
|
||||
// NOTE: Anisotropy levels capability is an extension
|
||||
#ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
|
||||
#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
|
||||
@@ -2629,6 +2631,16 @@ void rlLoadExtensions(void *loader)
|
||||
#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
|
||||
}
|
||||
|
||||
// Get OpenGL procedure address
|
||||
void *rlGetProcAddress(const char *procName)
|
||||
{
|
||||
void *func = NULL;
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
func = RLGL.loader(procName);
|
||||
#endif
|
||||
return func;
|
||||
}
|
||||
|
||||
// Get current OpenGL version
|
||||
int rlGetVersion(void)
|
||||
{
|
||||
@@ -3747,19 +3759,16 @@ void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType,
|
||||
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_2D, texId, mipLevel);
|
||||
else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_RENDERBUFFER, texId);
|
||||
else if (texType >= RL_ATTACHMENT_CUBEMAP_POSITIVE_X) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_CUBE_MAP_POSITIVE_X + texType, texId, mipLevel);
|
||||
|
||||
} break;
|
||||
case RL_ATTACHMENT_DEPTH:
|
||||
{
|
||||
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texId, mipLevel);
|
||||
else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, texId);
|
||||
|
||||
} break;
|
||||
case RL_ATTACHMENT_STENCIL:
|
||||
{
|
||||
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texId, mipLevel);
|
||||
else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, texId);
|
||||
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
@@ -4185,6 +4194,9 @@ unsigned int rlCompileShader(const char *shaderCode, int type)
|
||||
RL_FREE(log);
|
||||
}
|
||||
|
||||
// Unload object allocated by glCreateShader(),
|
||||
// despite failing in the compilation process
|
||||
glDeleteShader(shader);
|
||||
shader = 0;
|
||||
}
|
||||
else
|
||||
@@ -5133,7 +5145,20 @@ static int rlGetPixelDataSize(int width, int height, int format)
|
||||
}
|
||||
|
||||
// Auxiliar math functions
|
||||
//-------------------------------------------------------------------------------
|
||||
// Get identity matrix
|
||||
static Matrix rlMatrixIdentity(void)
|
||||
{
|
||||
Matrix result = {
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
// Get float array of matrix data
|
||||
static rl_float16 rlMatrixToFloatV(Matrix mat)
|
||||
{
|
||||
@@ -5159,19 +5184,6 @@ static rl_float16 rlMatrixToFloatV(Matrix mat)
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get identity matrix
|
||||
static Matrix rlMatrixIdentity(void)
|
||||
{
|
||||
Matrix result = {
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get two matrix multiplication
|
||||
// NOTE: When multiplying matrices... the order matters!
|
||||
static Matrix rlMatrixMultiply(Matrix left, Matrix right)
|
||||
@@ -5269,5 +5281,6 @@ static Matrix rlMatrixInvert(Matrix mat)
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // RLGL_IMPLEMENTATION
|
||||
|
||||
245
src/rmodels.c
245
src/rmodels.c
@@ -12,7 +12,7 @@
|
||||
* #define SUPPORT_FILEFORMAT_GLTF
|
||||
* #define SUPPORT_FILEFORMAT_VOX
|
||||
* #define SUPPORT_FILEFORMAT_M3D
|
||||
* Selected desired fileformats to be supported for model data loading.
|
||||
* Selected desired fileformats to be supported for model data loading
|
||||
*
|
||||
* #define SUPPORT_MESH_GENERATION
|
||||
* Support procedural mesh generation functions, uses external par_shapes.h library
|
||||
@@ -1433,7 +1433,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
|
||||
else rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices);
|
||||
|
||||
rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords);
|
||||
if (mesh.normals) rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.animNormalss);
|
||||
if (mesh.normals) rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.animNormals);
|
||||
else rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals);
|
||||
|
||||
rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors);
|
||||
@@ -2174,7 +2174,7 @@ Material *LoadMaterials(const char *fileName, int *materialCount)
|
||||
int result = tinyobj_parse_mtl_file(&mats, &count, fileName);
|
||||
if (result != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to parse materials file", fileName);
|
||||
|
||||
materials = RL_MALLOC(count*sizeof(Material));
|
||||
materials = (Material *)RL_MALLOC(count*sizeof(Material));
|
||||
ProcessMaterialsOBJ(materials, mats, count);
|
||||
|
||||
tinyobj_materials_free(mats, count);
|
||||
@@ -2298,7 +2298,7 @@ void UpdateModelAnimationBones(Model model, ModelAnimation anim, int frame)
|
||||
|
||||
if (firstMeshWithBones != -1)
|
||||
{
|
||||
// Update all bones and boneMatrices of first mesh with bones.
|
||||
// Update all bones and boneMatrices of first mesh with bones
|
||||
for (int boneId = 0; boneId < anim.boneCount; boneId++)
|
||||
{
|
||||
Transform *bindTransform = &model.bindPose[boneId];
|
||||
@@ -3713,7 +3713,7 @@ void GenMeshTangents(Mesh *mesh)
|
||||
// Create a tangent perpendicular to the normal
|
||||
if (fabsf(normal.z) > 0.707f) tangent = (Vector3){ 1.0f, 0.0f, 0.0f };
|
||||
else tangent = Vector3Normalize((Vector3){ -normal.y, normal.x, 0.0f });
|
||||
|
||||
|
||||
mesh->tangents[i*4 + 0] = tangent.x;
|
||||
mesh->tangents[i*4 + 1] = tangent.y;
|
||||
mesh->tangents[i*4 + 2] = tangent.z;
|
||||
@@ -3724,7 +3724,7 @@ void GenMeshTangents(Mesh *mesh)
|
||||
// Gram-Schmidt orthogonalization to make tangent orthogonal to normal
|
||||
// T_prime = T - N * dot(N, T)
|
||||
Vector3 orthogonalized = Vector3Subtract(tangent, Vector3Scale(normal, Vector3DotProduct(normal, tangent)));
|
||||
|
||||
|
||||
// Handle cases where orthogonalized vector is too small
|
||||
if (Vector3Length(orthogonalized) < 0.0001f)
|
||||
{
|
||||
@@ -3742,7 +3742,7 @@ void GenMeshTangents(Mesh *mesh)
|
||||
mesh->tangents[i*4 + 0] = orthogonalized.x;
|
||||
mesh->tangents[i*4 + 1] = orthogonalized.y;
|
||||
mesh->tangents[i*4 + 2] = orthogonalized.z;
|
||||
|
||||
|
||||
// Calculate the handedness (w component)
|
||||
mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, orthogonalized), tan2[i]) < 0.0f)? -1.0f : 1.0f;
|
||||
}
|
||||
@@ -4292,7 +4292,7 @@ static Model LoadOBJ(const char *fileName)
|
||||
|
||||
if (fileText == NULL)
|
||||
{
|
||||
TRACELOG(LOG_ERROR, "MODEL: [%s] Unable to read obj file", fileName);
|
||||
TRACELOG(LOG_WARNING, "MODEL: [%s] Unable to read obj file", fileName);
|
||||
return model;
|
||||
}
|
||||
|
||||
@@ -4308,7 +4308,7 @@ static Model LoadOBJ(const char *fileName)
|
||||
|
||||
if (ret != TINYOBJ_SUCCESS)
|
||||
{
|
||||
TRACELOG(LOG_ERROR, "MODEL: Unable to read obj data %s", fileName);
|
||||
TRACELOG(LOG_WARNING, "MODEL: Unable to read obj data %s", fileName);
|
||||
return model;
|
||||
}
|
||||
|
||||
@@ -4473,9 +4473,17 @@ static Model LoadOBJ(const char *fileName)
|
||||
|
||||
for (int i = 0; i < 3; i++) model.meshes[meshIndex].vertices[localMeshVertexCount*3 + i] = objAttributes.vertices[vertIndex*3 + i];
|
||||
|
||||
for (int i = 0; i < 3; i++) model.meshes[meshIndex].normals[localMeshVertexCount*3 + i] = objAttributes.normals[normalIndex*3 + i];
|
||||
|
||||
for (int i = 0; i < 2; i++) model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + i] = objAttributes.texcoords[texcordIndex*2 + i];
|
||||
if (objAttributes.normals != NULL && normalIndex != TINYOBJ_INVALID_INDEX && normalIndex >= 0)
|
||||
{
|
||||
for (int i = 0; i < 3; i++) model.meshes[meshIndex].normals[localMeshVertexCount*3 + i] = objAttributes.normals[normalIndex*3 + i];
|
||||
}
|
||||
else
|
||||
{
|
||||
model.meshes[meshIndex].normals[localMeshVertexCount*3 + 0] = 0.0f;
|
||||
model.meshes[meshIndex].normals[localMeshVertexCount*3 + 1] = 1.0f;
|
||||
model.meshes[meshIndex].normals[localMeshVertexCount*3 + 2] = 0.0f;
|
||||
}
|
||||
|
||||
model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1] = 1.0f - model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1];
|
||||
|
||||
@@ -4493,8 +4501,6 @@ static Model LoadOBJ(const char *fileName)
|
||||
tinyobj_shapes_free(objShapes, objShapeCount);
|
||||
tinyobj_materials_free(objMaterials, objMaterialCount);
|
||||
|
||||
for (int i = 0; i < model.meshCount; i++) UploadMesh(model.meshes + i, true);
|
||||
|
||||
// Restore current working directory
|
||||
if (CHDIR(currentDir) != 0)
|
||||
{
|
||||
@@ -4642,13 +4648,13 @@ static Model LoadIQM(const char *fileName)
|
||||
//fileDataPtr += sizeof(IQMHeader); // Move file data pointer
|
||||
|
||||
// Meshes data processing
|
||||
imesh = RL_MALLOC(iqmHeader->num_meshes*sizeof(IQMMesh));
|
||||
imesh = (IQMMesh *)RL_MALLOC(iqmHeader->num_meshes*sizeof(IQMMesh));
|
||||
//fseek(iqmFile, iqmHeader->ofs_meshes, SEEK_SET);
|
||||
//fread(imesh, sizeof(IQMMesh)*iqmHeader->num_meshes, 1, iqmFile);
|
||||
memcpy(imesh, fileDataPtr + iqmHeader->ofs_meshes, iqmHeader->num_meshes*sizeof(IQMMesh));
|
||||
|
||||
model.meshCount = iqmHeader->num_meshes;
|
||||
model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh));
|
||||
model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
|
||||
|
||||
model.materialCount = model.meshCount;
|
||||
model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
|
||||
@@ -4676,24 +4682,24 @@ static Model LoadIQM(const char *fileName)
|
||||
|
||||
model.meshes[i].vertexCount = imesh[i].num_vertexes;
|
||||
|
||||
model.meshes[i].vertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex positions
|
||||
model.meshes[i].normals = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex normals
|
||||
model.meshes[i].texcoords = RL_CALLOC(model.meshes[i].vertexCount*2, sizeof(float)); // Default vertex texcoords
|
||||
model.meshes[i].vertices = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex positions
|
||||
model.meshes[i].normals = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex normals
|
||||
model.meshes[i].texcoords = (float *)RL_CALLOC(model.meshes[i].vertexCount*2, sizeof(float)); // Default vertex texcoords
|
||||
|
||||
model.meshes[i].boneIds = RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(unsigned char)); // Up-to 4 bones supported!
|
||||
model.meshes[i].boneWeights = RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(float)); // Up-to 4 bones supported!
|
||||
model.meshes[i].boneIds = (unsigned char *)RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(unsigned char)); // Up-to 4 bones supported!
|
||||
model.meshes[i].boneWeights = (float *)RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(float)); // Up-to 4 bones supported!
|
||||
|
||||
model.meshes[i].triangleCount = imesh[i].num_triangles;
|
||||
model.meshes[i].indices = RL_CALLOC(model.meshes[i].triangleCount*3, sizeof(unsigned short));
|
||||
model.meshes[i].indices = (unsigned short *)RL_CALLOC(model.meshes[i].triangleCount*3, sizeof(unsigned short));
|
||||
|
||||
// Animated vertex data, what we actually process for rendering
|
||||
// NOTE: Animated vertex should be re-uploaded to GPU (if not using GPU skinning)
|
||||
model.meshes[i].animVertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
|
||||
model.meshes[i].animNormals = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
|
||||
model.meshes[i].animVertices = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
|
||||
model.meshes[i].animNormals = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
|
||||
}
|
||||
|
||||
// Triangles data processing
|
||||
tri = RL_MALLOC(iqmHeader->num_triangles*sizeof(IQMTriangle));
|
||||
tri = (IQMTriangle *)RL_MALLOC(iqmHeader->num_triangles*sizeof(IQMTriangle));
|
||||
//fseek(iqmFile, iqmHeader->ofs_triangles, SEEK_SET);
|
||||
//fread(tri, sizeof(IQMTriangle), iqmHeader->num_triangles, iqmFile);
|
||||
memcpy(tri, fileDataPtr + iqmHeader->ofs_triangles, iqmHeader->num_triangles*sizeof(IQMTriangle));
|
||||
@@ -4715,7 +4721,7 @@ static Model LoadIQM(const char *fileName)
|
||||
}
|
||||
|
||||
// Vertex arrays data processing
|
||||
va = RL_MALLOC(iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
|
||||
va = (IQMVertexArray *)RL_MALLOC(iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
|
||||
//fseek(iqmFile, iqmHeader->ofs_vertexarrays, SEEK_SET);
|
||||
//fread(va, sizeof(IQMVertexArray), iqmHeader->num_vertexarrays, iqmFile);
|
||||
memcpy(va, fileDataPtr + iqmHeader->ofs_vertexarrays, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
|
||||
@@ -4726,7 +4732,7 @@ static Model LoadIQM(const char *fileName)
|
||||
{
|
||||
case IQM_POSITION:
|
||||
{
|
||||
vertex = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
|
||||
vertex = (float *)RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
|
||||
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||
//fread(vertex, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
|
||||
memcpy(vertex, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
|
||||
@@ -4744,7 +4750,7 @@ static Model LoadIQM(const char *fileName)
|
||||
} break;
|
||||
case IQM_NORMAL:
|
||||
{
|
||||
normal = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
|
||||
normal = (float *)RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
|
||||
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||
//fread(normal, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
|
||||
memcpy(normal, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
|
||||
@@ -4762,7 +4768,7 @@ static Model LoadIQM(const char *fileName)
|
||||
} break;
|
||||
case IQM_TEXCOORD:
|
||||
{
|
||||
text = RL_MALLOC(iqmHeader->num_vertexes*2*sizeof(float));
|
||||
text = (float *)RL_MALLOC(iqmHeader->num_vertexes*2*sizeof(float));
|
||||
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||
//fread(text, iqmHeader->num_vertexes*2*sizeof(float), 1, iqmFile);
|
||||
memcpy(text, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*2*sizeof(float));
|
||||
@@ -4779,7 +4785,7 @@ static Model LoadIQM(const char *fileName)
|
||||
} break;
|
||||
case IQM_BLENDINDEXES:
|
||||
{
|
||||
blendi = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(char));
|
||||
blendi = (char *)RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(char));
|
||||
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||
//fread(blendi, iqmHeader->num_vertexes*4*sizeof(char), 1, iqmFile);
|
||||
memcpy(blendi, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(char));
|
||||
@@ -4796,7 +4802,7 @@ static Model LoadIQM(const char *fileName)
|
||||
} break;
|
||||
case IQM_BLENDWEIGHTS:
|
||||
{
|
||||
blendw = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||
blendw = (unsigned char *)RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||
//fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
|
||||
memcpy(blendw, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||
@@ -4813,14 +4819,14 @@ static Model LoadIQM(const char *fileName)
|
||||
} break;
|
||||
case IQM_COLOR:
|
||||
{
|
||||
color = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||
color = (unsigned char *)RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||
//fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
|
||||
memcpy(color, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||
|
||||
for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
|
||||
{
|
||||
model.meshes[m].colors = RL_CALLOC(model.meshes[m].vertexCount*4, sizeof(unsigned char));
|
||||
model.meshes[m].colors = (unsigned char *)RL_CALLOC(model.meshes[m].vertexCount*4, sizeof(unsigned char));
|
||||
|
||||
int vCounter = 0;
|
||||
for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
|
||||
@@ -4834,14 +4840,14 @@ static Model LoadIQM(const char *fileName)
|
||||
}
|
||||
|
||||
// Bones (joints) data processing
|
||||
ijoint = RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
|
||||
ijoint = (IQMJoint *)RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
|
||||
//fseek(iqmFile, iqmHeader->ofs_joints, SEEK_SET);
|
||||
//fread(ijoint, sizeof(IQMJoint), iqmHeader->num_joints, iqmFile);
|
||||
memcpy(ijoint, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint));
|
||||
|
||||
model.boneCount = iqmHeader->num_joints;
|
||||
model.bones = RL_MALLOC(iqmHeader->num_joints*sizeof(BoneInfo));
|
||||
model.bindPose = RL_MALLOC(iqmHeader->num_joints*sizeof(Transform));
|
||||
model.bones = (BoneInfo *)RL_MALLOC(iqmHeader->num_joints*sizeof(BoneInfo));
|
||||
model.bindPose = (Transform *)RL_MALLOC(iqmHeader->num_joints*sizeof(Transform));
|
||||
|
||||
for (unsigned int i = 0; i < iqmHeader->num_joints; i++)
|
||||
{
|
||||
@@ -4871,7 +4877,7 @@ static Model LoadIQM(const char *fileName)
|
||||
for (int i = 0; i < model.meshCount; i++)
|
||||
{
|
||||
model.meshes[i].boneCount = model.boneCount;
|
||||
model.meshes[i].boneMatrices = RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
|
||||
model.meshes[i].boneMatrices = (Matrix *)RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
|
||||
|
||||
for (int j = 0; j < model.meshes[i].boneCount; j++)
|
||||
{
|
||||
@@ -4963,36 +4969,36 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCou
|
||||
}
|
||||
|
||||
// Get bones data
|
||||
IQMPose *poses = RL_MALLOC(iqmHeader->num_poses*sizeof(IQMPose));
|
||||
IQMPose *poses = (IQMPose *)RL_MALLOC(iqmHeader->num_poses*sizeof(IQMPose));
|
||||
//fseek(iqmFile, iqmHeader->ofs_poses, SEEK_SET);
|
||||
//fread(poses, sizeof(IQMPose), iqmHeader->num_poses, iqmFile);
|
||||
memcpy(poses, fileDataPtr + iqmHeader->ofs_poses, iqmHeader->num_poses*sizeof(IQMPose));
|
||||
|
||||
// Get animations data
|
||||
*animCount = iqmHeader->num_anims;
|
||||
IQMAnim *anim = RL_MALLOC(iqmHeader->num_anims*sizeof(IQMAnim));
|
||||
IQMAnim *anim = (IQMAnim *)RL_MALLOC(iqmHeader->num_anims*sizeof(IQMAnim));
|
||||
//fseek(iqmFile, iqmHeader->ofs_anims, SEEK_SET);
|
||||
//fread(anim, sizeof(IQMAnim), iqmHeader->num_anims, iqmFile);
|
||||
memcpy(anim, fileDataPtr + iqmHeader->ofs_anims, iqmHeader->num_anims*sizeof(IQMAnim));
|
||||
|
||||
ModelAnimation *animations = RL_MALLOC(iqmHeader->num_anims*sizeof(ModelAnimation));
|
||||
ModelAnimation *animations = (ModelAnimation *)RL_MALLOC(iqmHeader->num_anims*sizeof(ModelAnimation));
|
||||
|
||||
// frameposes
|
||||
unsigned short *framedata = RL_MALLOC(iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
|
||||
unsigned short *framedata = (unsigned short *)RL_MALLOC(iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
|
||||
//fseek(iqmFile, iqmHeader->ofs_frames, SEEK_SET);
|
||||
//fread(framedata, sizeof(unsigned short), iqmHeader->num_frames*iqmHeader->num_framechannels, iqmFile);
|
||||
memcpy(framedata, fileDataPtr + iqmHeader->ofs_frames, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
|
||||
|
||||
// joints
|
||||
IQMJoint *joints = RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
|
||||
IQMJoint *joints = (IQMJoint *)RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
|
||||
memcpy(joints, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint));
|
||||
|
||||
for (unsigned int a = 0; a < iqmHeader->num_anims; a++)
|
||||
{
|
||||
animations[a].frameCount = anim[a].num_frames;
|
||||
animations[a].boneCount = iqmHeader->num_poses;
|
||||
animations[a].bones = RL_MALLOC(iqmHeader->num_poses*sizeof(BoneInfo));
|
||||
animations[a].framePoses = RL_MALLOC(anim[a].num_frames*sizeof(Transform *));
|
||||
animations[a].bones = (BoneInfo *)RL_MALLOC(iqmHeader->num_poses*sizeof(BoneInfo));
|
||||
animations[a].framePoses = (Transform **)RL_MALLOC(anim[a].num_frames*sizeof(Transform *));
|
||||
memcpy(animations[a].name, fileDataPtr + iqmHeader->ofs_text + anim[a].name, 32); // I don't like this 32 here
|
||||
TraceLog(LOG_INFO, "IQM Anim %s", animations[a].name);
|
||||
// animations[a].framerate = anim.framerate; // TODO: Use animation framerate data?
|
||||
@@ -5007,7 +5013,7 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCou
|
||||
animations[a].bones[j].parent = poses[j].parent;
|
||||
}
|
||||
|
||||
for (unsigned int j = 0; j < anim[a].num_frames; j++) animations[a].framePoses[j] = RL_MALLOC(iqmHeader->num_poses*sizeof(Transform));
|
||||
for (unsigned int j = 0; j < anim[a].num_frames; j++) animations[a].framePoses[j] = (Transform *)RL_MALLOC(iqmHeader->num_poses*sizeof(Transform));
|
||||
|
||||
int dcounter = anim[a].first_frame*iqmHeader->num_framechannels;
|
||||
|
||||
@@ -5198,7 +5204,7 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat
|
||||
}
|
||||
else if ((cgltfImage->buffer_view != NULL) && (cgltfImage->buffer_view->buffer->data != NULL)) // Check if image is provided as data buffer
|
||||
{
|
||||
unsigned char *data = RL_MALLOC(cgltfImage->buffer_view->size);
|
||||
unsigned char *data = (unsigned char *)RL_MALLOC(cgltfImage->buffer_view->size);
|
||||
int offset = (int)cgltfImage->buffer_view->offset;
|
||||
int stride = (int)cgltfImage->buffer_view->stride? (int)cgltfImage->buffer_view->stride : 1;
|
||||
|
||||
@@ -5231,16 +5237,12 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat
|
||||
static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, int *boneCount)
|
||||
{
|
||||
*boneCount = (int)skin.joints_count;
|
||||
BoneInfo *bones = RL_MALLOC(skin.joints_count*sizeof(BoneInfo));
|
||||
BoneInfo *bones = (BoneInfo *)RL_CALLOC(skin.joints_count, sizeof(BoneInfo));
|
||||
|
||||
for (unsigned int i = 0; i < skin.joints_count; i++)
|
||||
{
|
||||
cgltf_node node = *skin.joints[i];
|
||||
if (node.name != NULL)
|
||||
{
|
||||
strncpy(bones[i].name, node.name, sizeof(bones[i].name));
|
||||
bones[i].name[sizeof(bones[i].name) - 1] = '\0';
|
||||
}
|
||||
if (node.name != NULL) strncpy(bones[i].name, node.name, sizeof(bones[i].name) - 1);
|
||||
|
||||
// Find parent bone index
|
||||
int parentIndex = -1;
|
||||
@@ -5289,8 +5291,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
> Texcoords: vec2: float
|
||||
> Colors: vec4: u8, u16, f32 (normalized)
|
||||
> Indices: u16, u32 (truncated to u16)
|
||||
- Scenes defined in the glTF file are ignored. All nodes in the file
|
||||
are used.
|
||||
- Scenes defined in the glTF file are ignored. All nodes in the file are used
|
||||
|
||||
***********************************************************************************************/
|
||||
|
||||
@@ -5345,8 +5346,8 @@ static Model LoadGLTF(const char *fileName)
|
||||
|
||||
int primitivesCount = 0;
|
||||
|
||||
// NOTE: We will load every primitive in the glTF as a separate raylib Mesh.
|
||||
// Determine total number of meshes needed from the node hierarchy.
|
||||
// NOTE: We will load every primitive in the glTF as a separate raylib Mesh
|
||||
// Determine total number of meshes needed from the node hierarchy
|
||||
for (unsigned int i = 0; i < data->nodes_count; i++)
|
||||
{
|
||||
cgltf_node *node = &(data->nodes[i]);
|
||||
@@ -5362,15 +5363,15 @@ static Model LoadGLTF(const char *fileName)
|
||||
|
||||
// Load our model data: meshes and materials
|
||||
model.meshCount = primitivesCount;
|
||||
model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh));
|
||||
model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
|
||||
|
||||
// NOTE: We keep an extra slot for default material, in case some mesh requires it
|
||||
model.materialCount = (int)data->materials_count + 1;
|
||||
model.materials = RL_CALLOC(model.materialCount, sizeof(Material));
|
||||
model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
|
||||
model.materials[0] = LoadMaterialDefault(); // Load default material (index: 0)
|
||||
|
||||
// Load mesh-material indices, by default all meshes are mapped to material index: 0
|
||||
model.meshMaterial = RL_CALLOC(model.meshCount, sizeof(int));
|
||||
model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
|
||||
|
||||
// Load materials data
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
@@ -5488,14 +5489,13 @@ static Model LoadGLTF(const char *fileName)
|
||||
// has_clearcoat, has_transmission, has_volume, has_ior, has specular, has_sheen
|
||||
}
|
||||
|
||||
// Visit each node in the hierarchy and process any mesh linked from it.
|
||||
// Each primitive within a glTF node becomes a Raylib Mesh.
|
||||
// Visit each node in the hierarchy and process any mesh linked from it
|
||||
// Each primitive within a glTF node becomes a Raylib Mesh
|
||||
// The local-to-world transform of each node is used to transform the
|
||||
// points/normals/tangents of the created Mesh(es).
|
||||
// points/normals/tangents of the created Mesh(es)
|
||||
// Any glTF mesh linked from more than one Node (i.e. instancing)
|
||||
// is turned into multiple Mesh's, as each Node will have its own
|
||||
// transform applied.
|
||||
// NOTE: The code below disregards the scenes defined in the file, all nodes are used.
|
||||
// is turned into multiple Mesh's, as each Node will have its own transform applied
|
||||
// NOTE: The code below disregards the scenes defined in the file, all nodes are used
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
int meshIndex = 0;
|
||||
for (unsigned int i = 0; i < data->nodes_count; i++)
|
||||
@@ -5540,7 +5540,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
{
|
||||
// Init raylib mesh vertices to copy glTF attribute data
|
||||
model.meshes[meshIndex].vertexCount = (int)attribute->count;
|
||||
model.meshes[meshIndex].vertices = RL_MALLOC(attribute->count*3*sizeof(float));
|
||||
model.meshes[meshIndex].vertices = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
|
||||
|
||||
// Load 3 components of float data type into mesh.vertices
|
||||
LOAD_ATTRIBUTE(attribute, 3, float, model.meshes[meshIndex].vertices)
|
||||
@@ -5564,7 +5564,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_32f))
|
||||
{
|
||||
// Init raylib mesh normals to copy glTF attribute data
|
||||
model.meshes[meshIndex].normals = RL_MALLOC(attribute->count*3*sizeof(float));
|
||||
model.meshes[meshIndex].normals = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
|
||||
|
||||
// Load 3 components of float data type into mesh.normals
|
||||
LOAD_ATTRIBUTE(attribute, 3, float, model.meshes[meshIndex].normals)
|
||||
@@ -5581,14 +5581,14 @@ static Model LoadGLTF(const char *fileName)
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "MODEL: [%s] Normal attribute data format not supported, use vec3 float", fileName);
|
||||
}
|
||||
else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_tangent) // TANGENT, vec3, float
|
||||
else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_tangent) // TANGENT, vec4, float, w is tangent basis sign
|
||||
{
|
||||
cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
|
||||
|
||||
if ((attribute->type == cgltf_type_vec4) && (attribute->component_type == cgltf_component_type_r_32f))
|
||||
{
|
||||
// Init raylib mesh tangent to copy glTF attribute data
|
||||
model.meshes[meshIndex].tangents = RL_MALLOC(attribute->count*4*sizeof(float));
|
||||
model.meshes[meshIndex].tangents = (float *)RL_MALLOC(attribute->count*4*sizeof(float));
|
||||
|
||||
// Load 4 components of float data type into mesh.tangents
|
||||
LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].tangents)
|
||||
@@ -5597,10 +5597,10 @@ static Model LoadGLTF(const char *fileName)
|
||||
float *tangents = model.meshes[meshIndex].tangents;
|
||||
for (unsigned int k = 0; k < attribute->count; k++)
|
||||
{
|
||||
Vector3 tt = Vector3Transform((Vector3){ tangents[3*k], tangents[3*k+1], tangents[3*k+2] }, worldMatrix);
|
||||
tangents[3*k] = tt.x;
|
||||
tangents[3*k+1] = tt.y;
|
||||
tangents[3*k+2] = tt.z;
|
||||
Vector3 tt = Vector3Transform((Vector3){ tangents[4*k], tangents[4*k+1], tangents[4*k+2] }, worldMatrix);
|
||||
tangents[4*k] = tt.x;
|
||||
tangents[4*k+1] = tt.y;
|
||||
tangents[4*k+2] = tt.z;
|
||||
}
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "MODEL: [%s] Tangent attribute data format not supported, use vec4 float", fileName);
|
||||
@@ -5674,10 +5674,10 @@ static Model LoadGLTF(const char *fileName)
|
||||
if (attribute->component_type == cgltf_component_type_r_8u)
|
||||
{
|
||||
// Init raylib mesh color to copy glTF attribute data
|
||||
model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
|
||||
// Load data into a temp buffer to be converted to raylib data type
|
||||
unsigned char *temp = RL_MALLOC(attribute->count*3*sizeof(unsigned char));
|
||||
unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*3*sizeof(unsigned char));
|
||||
LOAD_ATTRIBUTE(attribute, 3, unsigned char, temp);
|
||||
|
||||
// Convert data to raylib color data type (4 bytes)
|
||||
@@ -5694,10 +5694,10 @@ static Model LoadGLTF(const char *fileName)
|
||||
else if (attribute->component_type == cgltf_component_type_r_16u)
|
||||
{
|
||||
// Init raylib mesh color to copy glTF attribute data
|
||||
model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
|
||||
// Load data into a temp buffer to be converted to raylib data type
|
||||
unsigned short *temp = RL_MALLOC(attribute->count*3*sizeof(unsigned short));
|
||||
unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*3*sizeof(unsigned short));
|
||||
LOAD_ATTRIBUTE(attribute, 3, unsigned short, temp);
|
||||
|
||||
// Convert data to raylib color data type (4 bytes)
|
||||
@@ -5714,10 +5714,10 @@ static Model LoadGLTF(const char *fileName)
|
||||
else if (attribute->component_type == cgltf_component_type_r_32f)
|
||||
{
|
||||
// Init raylib mesh color to copy glTF attribute data
|
||||
model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
|
||||
// Load data into a temp buffer to be converted to raylib data type
|
||||
float *temp = RL_MALLOC(attribute->count*3*sizeof(float));
|
||||
float *temp = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
|
||||
LOAD_ATTRIBUTE(attribute, 3, float, temp);
|
||||
|
||||
// Convert data to raylib color data type (4 bytes)
|
||||
@@ -5738,7 +5738,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
if (attribute->component_type == cgltf_component_type_r_8u)
|
||||
{
|
||||
// Init raylib mesh color to copy glTF attribute data
|
||||
model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
|
||||
// Load 4 components of unsigned char data type into mesh.colors
|
||||
LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].colors)
|
||||
@@ -5746,10 +5746,10 @@ static Model LoadGLTF(const char *fileName)
|
||||
else if (attribute->component_type == cgltf_component_type_r_16u)
|
||||
{
|
||||
// Init raylib mesh color to copy glTF attribute data
|
||||
model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
|
||||
// Load data into a temp buffer to be converted to raylib data type
|
||||
unsigned short *temp = RL_MALLOC(attribute->count*4*sizeof(unsigned short));
|
||||
unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*4*sizeof(unsigned short));
|
||||
LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
|
||||
|
||||
// Convert data to raylib color data type (4 bytes)
|
||||
@@ -5760,10 +5760,10 @@ static Model LoadGLTF(const char *fileName)
|
||||
else if (attribute->component_type == cgltf_component_type_r_32f)
|
||||
{
|
||||
// Init raylib mesh color to copy glTF attribute data
|
||||
model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
|
||||
// Load data into a temp buffer to be converted to raylib data type
|
||||
float *temp = RL_MALLOC(attribute->count*4*sizeof(float));
|
||||
float *temp = (float *)RL_MALLOC(attribute->count*4*sizeof(float));
|
||||
LOAD_ATTRIBUTE(attribute, 4, float, temp);
|
||||
|
||||
// Convert data to raylib color data type (4 bytes), we expect the color data normalized
|
||||
@@ -5789,7 +5789,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
if (attribute->component_type == cgltf_component_type_r_16u)
|
||||
{
|
||||
// Init raylib mesh indices to copy glTF attribute data
|
||||
model.meshes[meshIndex].indices = RL_MALLOC(attribute->count*sizeof(unsigned short));
|
||||
model.meshes[meshIndex].indices = (unsigned short *)RL_MALLOC(attribute->count*sizeof(unsigned short));
|
||||
|
||||
// Load unsigned short data type into mesh.indices
|
||||
LOAD_ATTRIBUTE(attribute, 1, unsigned short, model.meshes[meshIndex].indices)
|
||||
@@ -5797,14 +5797,14 @@ static Model LoadGLTF(const char *fileName)
|
||||
else if (attribute->component_type == cgltf_component_type_r_8u)
|
||||
{
|
||||
// Init raylib mesh indices to copy glTF attribute data
|
||||
model.meshes[meshIndex].indices = RL_MALLOC(attribute->count*sizeof(unsigned short));
|
||||
model.meshes[meshIndex].indices = (unsigned short *)RL_MALLOC(attribute->count*sizeof(unsigned short));
|
||||
LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned char, model.meshes[meshIndex].indices, unsigned short)
|
||||
|
||||
}
|
||||
else if (attribute->component_type == cgltf_component_type_r_32u)
|
||||
{
|
||||
// Init raylib mesh indices to copy glTF attribute data
|
||||
model.meshes[meshIndex].indices = RL_MALLOC(attribute->count*sizeof(unsigned short));
|
||||
model.meshes[meshIndex].indices = (unsigned short *)RL_MALLOC(attribute->count*sizeof(unsigned short));
|
||||
LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned int, model.meshes[meshIndex].indices, unsigned short);
|
||||
|
||||
TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data converted from u32 to u16, possible loss of data", fileName);
|
||||
@@ -5848,7 +5848,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
{
|
||||
cgltf_skin skin = data->skins[0];
|
||||
model.bones = LoadBoneInfoGLTF(skin, &model.boneCount);
|
||||
model.bindPose = RL_MALLOC(model.boneCount*sizeof(Transform));
|
||||
model.bindPose = (Transform *)RL_MALLOC(model.boneCount*sizeof(Transform));
|
||||
|
||||
for (int i = 0; i < model.boneCount; i++)
|
||||
{
|
||||
@@ -5905,7 +5905,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
if (attribute->component_type == cgltf_component_type_r_8u)
|
||||
{
|
||||
// Init raylib mesh boneIds to copy glTF attribute data
|
||||
model.meshes[meshIndex].boneIds = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
||||
model.meshes[meshIndex].boneIds = (unsigned char *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
||||
|
||||
// Load attribute: vec4, u8 (unsigned char)
|
||||
LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].boneIds)
|
||||
@@ -5913,10 +5913,10 @@ static Model LoadGLTF(const char *fileName)
|
||||
else if (attribute->component_type == cgltf_component_type_r_16u)
|
||||
{
|
||||
// Init raylib mesh boneIds to copy glTF attribute data
|
||||
model.meshes[meshIndex].boneIds = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
||||
model.meshes[meshIndex].boneIds = (unsigned char *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
||||
|
||||
// Load data into a temp buffer to be converted to raylib data type
|
||||
unsigned short *temp = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned short));
|
||||
unsigned short *temp = (unsigned short *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned short));
|
||||
LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
|
||||
|
||||
// Convert data to raylib color data type (4 bytes)
|
||||
@@ -5948,10 +5948,10 @@ static Model LoadGLTF(const char *fileName)
|
||||
if (attribute->component_type == cgltf_component_type_r_8u)
|
||||
{
|
||||
// Init raylib mesh bone weight to copy glTF attribute data
|
||||
model.meshes[meshIndex].boneWeights = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||
model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||
|
||||
// Load data into a temp buffer to be converted to raylib data type
|
||||
unsigned char *temp = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||
LOAD_ATTRIBUTE(attribute, 4, unsigned char, temp);
|
||||
|
||||
// Convert data to raylib bone weight data type (4 bytes)
|
||||
@@ -5962,10 +5962,10 @@ static Model LoadGLTF(const char *fileName)
|
||||
else if (attribute->component_type == cgltf_component_type_r_16u)
|
||||
{
|
||||
// Init raylib mesh bone weight to copy glTF attribute data
|
||||
model.meshes[meshIndex].boneWeights = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||
model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||
|
||||
// Load data into a temp buffer to be converted to raylib data type
|
||||
unsigned short *temp = RL_MALLOC(attribute->count*4*sizeof(unsigned short));
|
||||
unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*4*sizeof(unsigned short));
|
||||
LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
|
||||
|
||||
// Convert data to raylib bone weight data type
|
||||
@@ -5976,7 +5976,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
else if (attribute->component_type == cgltf_component_type_r_32f)
|
||||
{
|
||||
// Init raylib mesh bone weight to copy glTF attribute data
|
||||
model.meshes[meshIndex].boneWeights = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||
model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||
|
||||
// Load 4 components of float data type into mesh.boneWeights
|
||||
// for cgltf_attribute_type_weights we have:
|
||||
@@ -6007,8 +6007,8 @@ static Model LoadGLTF(const char *fileName)
|
||||
|
||||
if (parentBoneId >= 0)
|
||||
{
|
||||
model.meshes[meshIndex].boneIds = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
||||
model.meshes[meshIndex].boneWeights = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||
model.meshes[meshIndex].boneIds = (unsigned char *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
||||
model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||
|
||||
for (int vertexIndex = 0; vertexIndex < model.meshes[meshIndex].vertexCount*4; vertexIndex += 4)
|
||||
{
|
||||
@@ -6019,9 +6019,9 @@ static Model LoadGLTF(const char *fileName)
|
||||
}
|
||||
|
||||
// Animated vertex data
|
||||
model.meshes[meshIndex].animVertices = RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
|
||||
model.meshes[meshIndex].animVertices = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
|
||||
memcpy(model.meshes[meshIndex].animVertices, model.meshes[meshIndex].vertices, model.meshes[meshIndex].vertexCount*3*sizeof(float));
|
||||
model.meshes[meshIndex].animNormals = RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
|
||||
model.meshes[meshIndex].animNormals = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
|
||||
if (model.meshes[meshIndex].normals != NULL)
|
||||
{
|
||||
memcpy(model.meshes[meshIndex].animNormals, model.meshes[meshIndex].normals, model.meshes[meshIndex].vertexCount*3*sizeof(float));
|
||||
@@ -6029,7 +6029,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
|
||||
// Bone Transform Matrices
|
||||
model.meshes[meshIndex].boneCount = model.boneCount;
|
||||
model.meshes[meshIndex].boneMatrices = RL_CALLOC(model.meshes[meshIndex].boneCount, sizeof(Matrix));
|
||||
model.meshes[meshIndex].boneMatrices = (Matrix *)RL_CALLOC(model.meshes[meshIndex].boneCount, sizeof(Matrix));
|
||||
|
||||
for (int j = 0; j < model.meshes[meshIndex].boneCount; j++)
|
||||
{
|
||||
@@ -6219,7 +6219,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
|
||||
{
|
||||
cgltf_skin skin = data->skins[0];
|
||||
*animCount = (int)data->animations_count;
|
||||
animations = RL_MALLOC(data->animations_count*sizeof(ModelAnimation));
|
||||
animations = (ModelAnimation *)RL_CALLOC(data->animations_count, sizeof(ModelAnimation));
|
||||
|
||||
for (unsigned int i = 0; i < data->animations_count; i++)
|
||||
{
|
||||
@@ -6234,7 +6234,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
|
||||
cgltf_interpolation_type interpolationType;
|
||||
};
|
||||
|
||||
struct Channels *boneChannels = RL_CALLOC(animations[i].boneCount, sizeof(struct Channels));
|
||||
struct Channels *boneChannels = (struct Channels *)RL_CALLOC(animations[i].boneCount, sizeof(struct Channels));
|
||||
float animDuration = 0.0f;
|
||||
|
||||
for (unsigned int j = 0; j < animData.channels_count; j++)
|
||||
@@ -6292,18 +6292,14 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
|
||||
animDuration = (t > animDuration)? t : animDuration;
|
||||
}
|
||||
|
||||
if (animData.name != NULL)
|
||||
{
|
||||
strncpy(animations[i].name, animData.name, sizeof(animations[i].name));
|
||||
animations[i].name[sizeof(animations[i].name) - 1] = '\0';
|
||||
}
|
||||
if (animData.name != NULL) strncpy(animations[i].name, animData.name, sizeof(animations[i].name) - 1);
|
||||
|
||||
animations[i].frameCount = (int)(animDuration*1000.0f/GLTF_ANIMDELAY) + 1;
|
||||
animations[i].framePoses = RL_MALLOC(animations[i].frameCount*sizeof(Transform *));
|
||||
animations[i].framePoses = (Transform **)RL_MALLOC(animations[i].frameCount*sizeof(Transform *));
|
||||
|
||||
for (int j = 0; j < animations[i].frameCount; j++)
|
||||
{
|
||||
animations[i].framePoses[j] = RL_MALLOC(animations[i].boneCount*sizeof(Transform));
|
||||
animations[i].framePoses[j] = (Transform *)RL_MALLOC(animations[i].boneCount*sizeof(Transform));
|
||||
float time = ((float) j*GLTF_ANIMDELAY)/1000.0f;
|
||||
|
||||
for (int k = 0; k < animations[i].boneCount; k++)
|
||||
@@ -6453,7 +6449,7 @@ static Model LoadVOX(const char *fileName)
|
||||
|
||||
// Copy colors
|
||||
size = pmesh->vertexCount*sizeof(Color);
|
||||
pmesh->colors = RL_MALLOC(size);
|
||||
pmesh->colors = (unsigned char *)RL_MALLOC(size);
|
||||
memcpy(pmesh->colors, pcolors, size);
|
||||
|
||||
// First material index
|
||||
@@ -6589,7 +6585,7 @@ static Model LoadM3D(const char *fileName)
|
||||
|
||||
// If no map is provided, or we have colors defined, we allocate storage for vertex colors
|
||||
// M3D specs only consider vertex colors if no material is provided, however raylib uses both and mixes the colors
|
||||
if ((mi == M3D_UNDEF) || vcolor) model.meshes[k].colors = RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char));
|
||||
if ((mi == M3D_UNDEF) || vcolor) model.meshes[k].colors = (unsigned char *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char));
|
||||
|
||||
// If no map is provided and we allocated vertex colors, set them to white
|
||||
if ((mi == M3D_UNDEF) && (model.meshes[k].colors != NULL))
|
||||
@@ -6623,11 +6619,11 @@ static Model LoadM3D(const char *fileName)
|
||||
// Without vertex color (full transparency), we use the default color
|
||||
if (model.meshes[k].colors != NULL)
|
||||
{
|
||||
if (m3d->vertex[m3d->face[i].vertex[0]].color & 0xFF000000)
|
||||
if (m3d->vertex[m3d->face[i].vertex[0]].color & 0xff000000)
|
||||
memcpy(&model.meshes[k].colors[l*12 + 0], &m3d->vertex[m3d->face[i].vertex[0]].color, 4);
|
||||
if (m3d->vertex[m3d->face[i].vertex[1]].color & 0xFF000000)
|
||||
if (m3d->vertex[m3d->face[i].vertex[1]].color & 0xff000000)
|
||||
memcpy(&model.meshes[k].colors[l*12 + 4], &m3d->vertex[m3d->face[i].vertex[1]].color, 4);
|
||||
if (m3d->vertex[m3d->face[i].vertex[2]].color & 0xFF000000)
|
||||
if (m3d->vertex[m3d->face[i].vertex[2]].color & 0xff000000)
|
||||
memcpy(&model.meshes[k].colors[l*12 + 8], &m3d->vertex[m3d->face[i].vertex[2]].color, 4);
|
||||
}
|
||||
|
||||
@@ -6756,13 +6752,13 @@ static Model LoadM3D(const char *fileName)
|
||||
if (m3d->numbone)
|
||||
{
|
||||
model.boneCount = m3d->numbone + 1;
|
||||
model.bones = RL_CALLOC(model.boneCount, sizeof(BoneInfo));
|
||||
model.bindPose = RL_CALLOC(model.boneCount, sizeof(Transform));
|
||||
model.bones = (BoneInfo *)RL_CALLOC(model.boneCount, sizeof(BoneInfo));
|
||||
model.bindPose = (Transform *)RL_CALLOC(model.boneCount, sizeof(Transform));
|
||||
|
||||
for (i = 0; i < (int)m3d->numbone; i++)
|
||||
{
|
||||
model.bones[i].parent = m3d->bone[i].parent;
|
||||
strncpy(model.bones[i].name, m3d->bone[i].name, sizeof(model.bones[i].name));
|
||||
strncpy(model.bones[i].name, m3d->bone[i].name, sizeof(model.bones[i].name) - 1);
|
||||
model.bindPose[i].translation.x = m3d->vertex[m3d->bone[i].pos].x*m3d->scale;
|
||||
model.bindPose[i].translation.y = m3d->vertex[m3d->bone[i].pos].y*m3d->scale;
|
||||
model.bindPose[i].translation.z = m3d->vertex[m3d->bone[i].pos].z*m3d->scale;
|
||||
@@ -6808,7 +6804,7 @@ static Model LoadM3D(const char *fileName)
|
||||
memcpy(model.meshes[i].animNormals, model.meshes[i].normals, model.meshes[i].vertexCount*3*sizeof(float));
|
||||
|
||||
model.meshes[i].boneCount = model.boneCount;
|
||||
model.meshes[i].boneMatrices = RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
|
||||
model.meshes[i].boneMatrices = (Matrix *)RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
|
||||
for (j = 0; j < model.meshes[i].boneCount; j++)
|
||||
{
|
||||
model.meshes[i].boneMatrices[j] = MatrixIdentity();
|
||||
@@ -6858,24 +6854,23 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCou
|
||||
return NULL;
|
||||
}
|
||||
|
||||
animations = RL_MALLOC(m3d->numaction*sizeof(ModelAnimation));
|
||||
animations = (ModelAnimation *)RL_CALLOC(m3d->numaction, sizeof(ModelAnimation));
|
||||
*animCount = m3d->numaction;
|
||||
|
||||
for (unsigned int a = 0; a < m3d->numaction; a++)
|
||||
{
|
||||
animations[a].frameCount = m3d->action[a].durationmsec/M3D_ANIMDELAY;
|
||||
animations[a].boneCount = m3d->numbone + 1;
|
||||
animations[a].bones = RL_MALLOC((m3d->numbone + 1)*sizeof(BoneInfo));
|
||||
animations[a].framePoses = RL_MALLOC(animations[a].frameCount*sizeof(Transform *));
|
||||
strncpy(animations[a].name, m3d->action[a].name, sizeof(animations[a].name));
|
||||
animations[a].name[sizeof(animations[a].name) - 1] = '\0';
|
||||
animations[a].bones = (BoneInfo *)RL_MALLOC((m3d->numbone + 1)*sizeof(BoneInfo));
|
||||
animations[a].framePoses = (Transform **)RL_MALLOC(animations[a].frameCount*sizeof(Transform *));
|
||||
strncpy(animations[a].name, m3d->action[a].name, sizeof(animations[a].name) - 1);
|
||||
|
||||
TRACELOG(LOG_INFO, "MODEL: [%s] animation #%i: %i msec, %i frames", fileName, a, m3d->action[a].durationmsec, animations[a].frameCount);
|
||||
|
||||
for (i = 0; i < (int)m3d->numbone; i++)
|
||||
{
|
||||
animations[a].bones[i].parent = m3d->bone[i].parent;
|
||||
strncpy(animations[a].bones[i].name, m3d->bone[i].name, sizeof(animations[a].bones[i].name));
|
||||
strncpy(animations[a].bones[i].name, m3d->bone[i].name, sizeof(animations[a].bones[i].name) - 1);
|
||||
}
|
||||
|
||||
// A special, never transformed "no bone" bone, used for boneless vertices
|
||||
@@ -6886,7 +6881,7 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCou
|
||||
// regular intervals, so let the M3D SDK do the heavy lifting and calculate interpolated bones
|
||||
for (i = 0; i < animations[a].frameCount; i++)
|
||||
{
|
||||
animations[a].framePoses[i] = RL_MALLOC((m3d->numbone + 1)*sizeof(Transform));
|
||||
animations[a].framePoses[i] = (Transform *)RL_MALLOC((m3d->numbone + 1)*sizeof(Transform));
|
||||
|
||||
m3db_t *pose = m3d_pose(m3d, a, i*M3D_ANIMDELAY);
|
||||
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
* rshapes - Basic functions to draw 2d shapes and check collisions
|
||||
*
|
||||
* ADDITIONAL NOTES:
|
||||
* Shapes can be draw using 3 types of primitives: LINES, TRIANGLES and QUADS.
|
||||
* Shapes can be draw using 3 types of primitives: LINES, TRIANGLES and QUADS
|
||||
* Some functions implement two drawing options: TRIANGLES and QUADS, by default TRIANGLES
|
||||
* are used but QUADS implementation can be selected with SUPPORT_QUADS_DRAW_MODE define
|
||||
*
|
||||
* Some functions define texture coordinates (rlTexCoord2f()) for the shapes and use a
|
||||
* user-provided texture with SetShapesTexture(), the pourpouse of this implementation
|
||||
* is allowing to reduce draw calls when combined with a texture-atlas.
|
||||
* is allowing to reduce draw calls when combined with a texture-atlas
|
||||
*
|
||||
* By default, raylib sets the default texture and rectangle at InitWindow()[rcore] to one
|
||||
* white character of default font [rtext], this way, raylib text and shapes can be draw with
|
||||
* a single draw call and it also allows users to configure it the same way with their own fonts.
|
||||
* a single draw call and it also allows users to configure it the same way with their own fonts
|
||||
*
|
||||
* CONFIGURATION:
|
||||
* #define SUPPORT_MODULE_RSHAPES
|
||||
@@ -470,27 +470,39 @@ void DrawCircleLinesV(Vector2 center, float radius, Color color)
|
||||
|
||||
// Draw ellipse
|
||||
void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color)
|
||||
{
|
||||
DrawEllipseV((Vector2){ (float)centerX, (float)centerY }, radiusH, radiusV, color);
|
||||
}
|
||||
|
||||
// Draw ellipse (Vector version)
|
||||
void DrawEllipseV(Vector2 center, float radiusH, float radiusV, Color color)
|
||||
{
|
||||
rlBegin(RL_TRIANGLES);
|
||||
for (int i = 0; i < 360; i += 10)
|
||||
{
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlVertex2f((float)centerX, (float)centerY);
|
||||
rlVertex2f((float)centerX + cosf(DEG2RAD*(i + 10))*radiusH, (float)centerY + sinf(DEG2RAD*(i + 10))*radiusV);
|
||||
rlVertex2f((float)centerX + cosf(DEG2RAD*i)*radiusH, (float)centerY + sinf(DEG2RAD*i)*radiusV);
|
||||
rlVertex2f(center.x, center.y);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radiusH, center.y + sinf(DEG2RAD*(i + 10))*radiusV);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*i)*radiusH, center.y + sinf(DEG2RAD*i)*radiusV);
|
||||
}
|
||||
rlEnd();
|
||||
}
|
||||
|
||||
// Draw ellipse outline
|
||||
void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color)
|
||||
{
|
||||
DrawEllipseLinesV((Vector2){ (float)centerX, (float)centerY }, radiusH, radiusV, color);
|
||||
}
|
||||
|
||||
// Draw ellipse outline
|
||||
void DrawEllipseLinesV(Vector2 center, float radiusH, float radiusV, Color color)
|
||||
{
|
||||
rlBegin(RL_LINES);
|
||||
for (int i = 0; i < 360; i += 10)
|
||||
{
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlVertex2f(centerX + cosf(DEG2RAD*(i + 10))*radiusH, centerY + sinf(DEG2RAD*(i + 10))*radiusV);
|
||||
rlVertex2f(centerX + cosf(DEG2RAD*i)*radiusH, centerY + sinf(DEG2RAD*i)*radiusV);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radiusH, center.y + sinf(DEG2RAD*(i + 10))*radiusV);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*i)*radiusH, center.y + sinf(DEG2RAD*i)*radiusV);
|
||||
}
|
||||
rlEnd();
|
||||
}
|
||||
@@ -774,7 +786,7 @@ void DrawRectangleGradientH(int posX, int posY, int width, int height, Color lef
|
||||
}
|
||||
|
||||
// Draw a gradient-filled rectangle
|
||||
void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color topRight, Color bottomRight)
|
||||
void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color bottomRight, Color topRight)
|
||||
{
|
||||
rlSetTexture(GetShapesTexture().id);
|
||||
Rectangle shapeRect = GetShapesTextureRectangle();
|
||||
@@ -791,11 +803,11 @@ void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Col
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(rec.x, rec.y + rec.height);
|
||||
|
||||
rlColor4ub(topRight.r, topRight.g, topRight.b, topRight.a);
|
||||
rlColor4ub(bottomRight.r, bottomRight.g, bottomRight.b, bottomRight.a);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(rec.x + rec.width, rec.y + rec.height);
|
||||
|
||||
rlColor4ub(bottomRight.r, bottomRight.g, bottomRight.b, bottomRight.a);
|
||||
rlColor4ub(topRight.r, topRight.g, topRight.b, topRight.a);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(rec.x + rec.width, rec.y);
|
||||
rlEnd();
|
||||
|
||||
18
src/rtext.c
18
src/rtext.c
@@ -7,8 +7,8 @@
|
||||
* rtext module is included in the build
|
||||
*
|
||||
* #define SUPPORT_DEFAULT_FONT
|
||||
* Load default raylib font on initialization to be used by DrawText() and MeasureText().
|
||||
* If no default font loaded, DrawTextEx() and MeasureTextEx() are required.
|
||||
* Load default raylib font on initialization to be used by DrawText() and MeasureText()
|
||||
* If no default font loaded, DrawTextEx() and MeasureTextEx() are required
|
||||
*
|
||||
* #define SUPPORT_FILEFORMAT_FNT
|
||||
* #define SUPPORT_FILEFORMAT_TTF
|
||||
@@ -19,7 +19,7 @@
|
||||
* #define SUPPORT_FONT_ATLAS_WHITE_REC
|
||||
* On font atlas image generation [GenImageFontAtlas()], add a 3x3 pixels white rectangle
|
||||
* at the bottom-right corner of the atlas. It can be useful to for shapes drawing, to allow
|
||||
* drawing text and shapes with a single draw call [SetShapesTexture()].
|
||||
* drawing text and shapes with a single draw call [SetShapesTexture()]
|
||||
*
|
||||
* #define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
|
||||
* TextSplit() function static buffer max size
|
||||
@@ -130,6 +130,7 @@ extern bool isGpuReady;
|
||||
// NOTE: Default font is loaded on InitWindow() and disposed on CloseWindow() [module: core]
|
||||
static Font defaultFont = { 0 };
|
||||
#endif
|
||||
static int textLineSpacing = 2; // Text vertical line spacing in pixels (between lines)
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Other Modules Functions Declaration (required by text)
|
||||
@@ -145,7 +146,6 @@ static Font LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode
|
||||
#if defined(SUPPORT_FILEFORMAT_BDF)
|
||||
static GlyphInfo *LoadFontDataBDF(const unsigned char *fileData, int dataSize, int *codepoints, int codepointCount, int *outFontSize);
|
||||
#endif
|
||||
static int textLineSpacing = 2; // Text vertical line spacing in pixels (between lines)
|
||||
|
||||
#if defined(SUPPORT_DEFAULT_FONT)
|
||||
extern void LoadFontDefault(void);
|
||||
@@ -162,7 +162,7 @@ extern void LoadFontDefault(void)
|
||||
#define BIT_CHECK(a,b) ((a) & (1u << (b)))
|
||||
|
||||
// check to see if we have allready allocated the font for an image, and if we don't need to upload, then just return
|
||||
if (defaultFont.glyphs != NULL && !isGpuReady)
|
||||
if (defaultFont.glyphs != NULL && !isGpuReady)
|
||||
return;
|
||||
|
||||
// NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement
|
||||
@@ -253,18 +253,18 @@ extern void LoadFontDefault(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
((unsigned char *)imFont.data)[(i + j)*sizeof(short)] = 0xFF;
|
||||
((unsigned char *)imFont.data)[(i + j)*sizeof(short)] = 0xff;
|
||||
((unsigned char *)imFont.data)[(i + j)*sizeof(short) + 1] = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
counter++;
|
||||
}
|
||||
|
||||
|
||||
if (isGpuReady)
|
||||
{
|
||||
defaultFont.texture = LoadTextureFromImage(imFont);
|
||||
|
||||
|
||||
// we have already loaded the font glyph data an image, and the GPU is ready, we are done
|
||||
// if we don't do this, we will leak memory by reallocating the glyphs and rects
|
||||
if (defaultFont.glyphs != NULL)
|
||||
@@ -391,7 +391,7 @@ Font LoadFont(const char *fileName)
|
||||
else
|
||||
{
|
||||
SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance)
|
||||
TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", FONT_TTF_DEFAULT_SIZE, FONT_TTF_DEFAULT_NUMCHARS);
|
||||
TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
108
src/rtextures.c
108
src/rtextures.c
@@ -36,7 +36,7 @@
|
||||
*
|
||||
* DEPENDENCIES:
|
||||
* stb_image - Multiple image formats loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC)
|
||||
* NOTE: stb_image has been slightly modified to support Android platform.
|
||||
* NOTE: stb_image has been slightly modified to support Android platform
|
||||
* stb_image_resize - Multiple image resize algorithms
|
||||
*
|
||||
*
|
||||
@@ -169,10 +169,13 @@
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
|
||||
#define RL_GPUTEX_MALLOC RL_MALLOC
|
||||
#define RL_GPUTEX_FREE RL_FREE
|
||||
#define RL_GPUTEX_LOG(...) TRACELOG(LOG_WARNING, "IMAGE: " __VA_ARGS__)
|
||||
#define RL_GPUTEX_SHOW_LOG_INFO
|
||||
#define RL_GPUTEX_IMPLEMENTATION
|
||||
#include "external/rl_gputex.h" // Required for: rl_load_xxx_from_memory()
|
||||
// NOTE: Used to read compressed textures data (multiple formats support)
|
||||
|
||||
#if defined(__GNUC__) // GCC and Clang
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
@@ -2102,8 +2105,8 @@ void ImageBlurGaussian(Image *image, int blurSize)
|
||||
Color *pixels = LoadImageColors(*image);
|
||||
|
||||
// Loop switches between pixelsCopy1 and pixelsCopy2
|
||||
Vector4 *pixelsCopy1 = RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
||||
Vector4 *pixelsCopy2 = RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
||||
Vector4 *pixelsCopy1 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
||||
Vector4 *pixelsCopy2 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
||||
|
||||
for (int i = 0; i < (image->height*image->width); i++)
|
||||
{
|
||||
@@ -2217,9 +2220,9 @@ void ImageBlurGaussian(Image *image, int blurSize)
|
||||
else if (pixelsCopy1[i].w <= 255.0f)
|
||||
{
|
||||
float alpha = (float)pixelsCopy1[i].w/255.0f;
|
||||
pixels[i].r = (unsigned char)((float)pixelsCopy1[i].x/alpha);
|
||||
pixels[i].g = (unsigned char)((float)pixelsCopy1[i].y/alpha);
|
||||
pixels[i].b = (unsigned char)((float)pixelsCopy1[i].z/alpha);
|
||||
pixels[i].r = (unsigned char)fminf((float)pixelsCopy1[i].x/alpha, 255.0);
|
||||
pixels[i].g = (unsigned char)fminf((float)pixelsCopy1[i].y/alpha, 255.0);
|
||||
pixels[i].b = (unsigned char)fminf((float)pixelsCopy1[i].z/alpha, 255.0);
|
||||
pixels[i].a = (unsigned char) pixelsCopy1[i].w;
|
||||
}
|
||||
}
|
||||
@@ -2251,8 +2254,8 @@ void ImageKernelConvolution(Image *image, const float *kernel, int kernelSize)
|
||||
|
||||
Color *pixels = LoadImageColors(*image);
|
||||
|
||||
Vector4 *imageCopy2 = RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
||||
Vector4 *temp = RL_MALLOC(kernelSize*sizeof(Vector4));
|
||||
Vector4 *imageCopy2 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
||||
Vector4 *temp = (Vector4 *)RL_MALLOC(kernelSize*sizeof(Vector4));
|
||||
|
||||
for (int i = 0; i < kernelSize; i++)
|
||||
{
|
||||
@@ -2927,7 +2930,16 @@ void ImageColorReplace(Image *image, Color color, Color replace)
|
||||
image->data = pixels;
|
||||
image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
|
||||
|
||||
ImageFormat(image, format);
|
||||
// Only convert back to original format if it supported alpha
|
||||
if ((format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) ||
|
||||
(format == PIXELFORMAT_UNCOMPRESSED_R5G6B5) ||
|
||||
(format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) ||
|
||||
(format == PIXELFORMAT_UNCOMPRESSED_R32G32B32) ||
|
||||
(format == PIXELFORMAT_UNCOMPRESSED_R16G16B16) ||
|
||||
(format == PIXELFORMAT_COMPRESSED_DXT1_RGB) ||
|
||||
(format == PIXELFORMAT_COMPRESSED_ETC1_RGB) ||
|
||||
(format == PIXELFORMAT_COMPRESSED_ETC2_RGB) ||
|
||||
(format == PIXELFORMAT_COMPRESSED_PVRT_RGB)) ImageFormat(image, format);
|
||||
}
|
||||
#endif // SUPPORT_IMAGE_MANIPULATION
|
||||
|
||||
@@ -3565,34 +3577,43 @@ void ImageDrawLineEx(Image *dst, Vector2 start, Vector2 end, int thick, Color co
|
||||
int dx = x2 - x1;
|
||||
int dy = y2 - y1;
|
||||
|
||||
// Draw the main line between (x1, y1) and (x2, y2)
|
||||
ImageDrawLine(dst, x1, y1, x2, y2, color);
|
||||
|
||||
// Determine if the line is more horizontal or vertical
|
||||
if ((dx != 0) && (abs(dy/dx) < 1))
|
||||
{
|
||||
// Line is more horizontal
|
||||
// Calculate half the width of the line
|
||||
int wy = (thick - 1)*(int)sqrtf((float)(dx*dx + dy*dy))/(2*abs(dx));
|
||||
|
||||
// Draw additional lines above and below the main line
|
||||
for (int i = 1; i <= wy; i++)
|
||||
// How many additional lines to draw
|
||||
int wy = thick - 1;
|
||||
|
||||
// Draw the main line and lower half
|
||||
for (int i = 0; i <= ((wy+1)/2); i++)
|
||||
{
|
||||
ImageDrawLine(dst, x1, y1 - i, x2, y2 - i, color); // Draw above the main line
|
||||
ImageDrawLine(dst, x1, y1 + i, x2, y2 + i, color); // Draw below the main line
|
||||
ImageDrawLine(dst, x1, y1 + i, x2, y2 + i, color);
|
||||
}
|
||||
|
||||
// Draw the upper half
|
||||
for (int i = 1; i <= (wy/2); i++)
|
||||
{
|
||||
ImageDrawLine(dst, x1, y1 - i, x2, y2 - i, color);
|
||||
}
|
||||
}
|
||||
else if (dy != 0)
|
||||
{
|
||||
// Line is more vertical or perfectly horizontal
|
||||
// Calculate half the width of the line
|
||||
int wx = (thick - 1)*(int)sqrtf((float)(dx*dx + dy*dy))/(2*abs(dy));
|
||||
|
||||
// Draw additional lines to the left and right of the main line
|
||||
for (int i = 1; i <= wx; i++)
|
||||
// How many additional lines to draw
|
||||
int wx = thick - 1;
|
||||
|
||||
//Draw the main line and right half
|
||||
for (int i = 0; i <= ((wx+1)/2); i++)
|
||||
{
|
||||
ImageDrawLine(dst, x1 - i, y1, x2 - i, y2, color); // Draw left of the main line
|
||||
ImageDrawLine(dst, x1 + i, y1, x2 + i, y2, color); // Draw right of the main line
|
||||
ImageDrawLine(dst, x1 + i, y1, x2 + i, y2, color);
|
||||
}
|
||||
|
||||
// Draw the left half
|
||||
for (int i = 1; i <= (wx/2); i++)
|
||||
{
|
||||
ImageDrawLine(dst, x1 - i, y1, x2 - i, y2, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3891,7 +3912,7 @@ void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Colo
|
||||
}
|
||||
|
||||
// Draw a triangle fan defined by points within an image (first vertex is the center)
|
||||
void ImageDrawTriangleFan(Image *dst, Vector2 *points, int pointCount, Color color)
|
||||
void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color)
|
||||
{
|
||||
if (pointCount >= 3)
|
||||
{
|
||||
@@ -3903,7 +3924,7 @@ void ImageDrawTriangleFan(Image *dst, Vector2 *points, int pointCount, Color col
|
||||
}
|
||||
|
||||
// Draw a triangle strip defined by points within an image
|
||||
void ImageDrawTriangleStrip(Image *dst, Vector2 *points, int pointCount, Color color)
|
||||
void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color)
|
||||
{
|
||||
if (pointCount >= 3)
|
||||
{
|
||||
@@ -4338,14 +4359,17 @@ void UnloadRenderTexture(RenderTexture2D target)
|
||||
}
|
||||
|
||||
// Update GPU texture with new data
|
||||
// NOTE: pixels data must match texture.format
|
||||
// NOTE 1: pixels data must match texture.format
|
||||
// NOTE 2: pixels data must contain at least as many pixels as texture
|
||||
void UpdateTexture(Texture2D texture, const void *pixels)
|
||||
{
|
||||
rlUpdateTexture(texture.id, 0, 0, texture.width, texture.height, texture.format, pixels);
|
||||
}
|
||||
|
||||
// Update GPU texture rectangle with new data
|
||||
// NOTE: pixels data must match texture.format
|
||||
// NOTE 1: pixels data must match texture.format
|
||||
// NOTE 2: pixels data must contain as many pixels as rec contains
|
||||
// NOTE 3: rec must fit completely within texture's width and height
|
||||
void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels)
|
||||
{
|
||||
rlUpdateTexture(texture.id, (int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, texture.format, pixels);
|
||||
@@ -5148,10 +5172,10 @@ Color GetColor(unsigned int hexValue)
|
||||
{
|
||||
Color color;
|
||||
|
||||
color.r = (unsigned char)(hexValue >> 24) & 0xFF;
|
||||
color.g = (unsigned char)(hexValue >> 16) & 0xFF;
|
||||
color.b = (unsigned char)(hexValue >> 8) & 0xFF;
|
||||
color.a = (unsigned char)hexValue & 0xFF;
|
||||
color.r = (unsigned char)(hexValue >> 24) & 0xff;
|
||||
color.g = (unsigned char)(hexValue >> 16) & 0xff;
|
||||
color.b = (unsigned char)(hexValue >> 8) & 0xff;
|
||||
color.a = (unsigned char)hexValue & 0xff;
|
||||
|
||||
return color;
|
||||
}
|
||||
@@ -5391,17 +5415,16 @@ static float HalfToFloat(unsigned short x)
|
||||
{
|
||||
float result = 0.0f;
|
||||
|
||||
union
|
||||
{
|
||||
union {
|
||||
float fm;
|
||||
unsigned int ui;
|
||||
} uni;
|
||||
|
||||
const unsigned int e = (x & 0x7C00) >> 10; // Exponent
|
||||
const unsigned int m = (x & 0x03FF) << 13; // Mantissa
|
||||
const unsigned int e = (x & 0x7c00) >> 10; // Exponent
|
||||
const unsigned int m = (x & 0x03ff) << 13; // Mantissa
|
||||
uni.fm = (float)m;
|
||||
const unsigned int v = uni.ui >> 23; // Evil log2 bit hack to count leading zeros in denormalized format
|
||||
uni.ui = (x & 0x8000) << 16 | (e != 0)*((e + 112) << 23 | m) | ((e == 0)&(m != 0))*((v - 37) << 23 | ((m << (150 - v)) & 0x007FE000)); // sign : normalized : denormalized
|
||||
uni.ui = (x & 0x8000) << 16 | (e != 0)*((e + 112) << 23 | m) | ((e == 0)&(m != 0))*((v - 37) << 23 | ((m << (150 - v)) & 0x007fe000)); // sign : normalized : denormalized
|
||||
|
||||
result = uni.fm;
|
||||
|
||||
@@ -5413,18 +5436,17 @@ static unsigned short FloatToHalf(float x)
|
||||
{
|
||||
unsigned short result = 0;
|
||||
|
||||
union
|
||||
{
|
||||
union {
|
||||
float fm;
|
||||
unsigned int ui;
|
||||
} uni;
|
||||
uni.fm = x;
|
||||
|
||||
const unsigned int b = uni.ui + 0x00001000; // Round-to-nearest-even: add last bit after truncated mantissa
|
||||
const unsigned int e = (b & 0x7F800000) >> 23; // Exponent
|
||||
const unsigned int m = b & 0x007FFFFF; // Mantissa; in line below: 0x007FF000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding
|
||||
const unsigned int e = (b & 0x7f800000) >> 23; // Exponent
|
||||
const unsigned int m = b & 0x007fffff; // Mantissa; in line below: 0x007ff000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding
|
||||
|
||||
result = (b & 0x80000000) >> 16 | (e > 112)*((((e - 112) << 10) & 0x7C00) | m >> 13) | ((e < 113) & (e > 101))*((((0x007FF000 + m) >> (125 - e)) + 1) >> 1) | (e > 143)*0x7FFF; // sign : normalized : denormalized : saturate
|
||||
result = (b & 0x80000000) >> 16 | (e > 112)*((((e - 112) << 10) & 0x7c00) | m >> 13) | ((e < 113) & (e > 101))*((((0x007ff000 + m) >> (125 - e)) + 1) >> 1) | (e > 143)*0x7fff; // sign : normalized : denormalized : saturate
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user