Merge branch 'raysan5:master' into Add-RL_POINTS
This commit is contained in:
commit
fb853ea03c
172 changed files with 15080 additions and 4022 deletions
56
src/Makefile
56
src/Makefile
|
|
@ -275,15 +275,28 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
|
|||
GRAPHICS ?= GRAPHICS_API_OPENGL_ES2
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_SOFTWARE # Uncomment to use software rendering
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_RGFW))
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_WEB)
|
||||
# On HTML5 OpenGL ES 2.0 is used, emscripten translates it to WebGL 1.0
|
||||
GRAPHICS ?= GRAPHICS_API_OPENGL_ES2
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_ES3
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_WEB_RGFW)
|
||||
# On HTML5 OpenGL ES 2.0 is used, emscripten translates it to WebGL 1.0
|
||||
GRAPHICS ?= GRAPHICS_API_OPENGL_ES2
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_ES3
|
||||
|
||||
ifeq ($(GRAPHICS),GRAPHICS_API_OPENGL_SOFTWARE)
|
||||
$(error WEB_RGFW: Software rendering not supported!)
|
||||
endif
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
|
||||
# By default use OpenGL ES 2.0 on Android
|
||||
GRAPHICS ?= GRAPHICS_API_OPENGL_ES2
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_MEMORY)
|
||||
# By default use OpenGL Software
|
||||
GRAPHICS = GRAPHICS_API_OPENGL_SOFTWARE
|
||||
endif
|
||||
|
||||
# Define default C compiler and archiver to pack library: CC, AR
|
||||
#------------------------------------------------------------------------------------------------
|
||||
|
|
@ -320,7 +333,12 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
|
|||
AR = $(RPI_TOOLCHAIN)/bin/$(RPI_TOOLCHAIN_NAME)-ar
|
||||
endif
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_RGFW))
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_WEB)
|
||||
# HTML5 emscripten compiler
|
||||
CC = emcc
|
||||
AR = emar
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_WEB_RGFW)
|
||||
# HTML5 emscripten compiler
|
||||
CC = emcc
|
||||
AR = emar
|
||||
|
|
@ -364,7 +382,6 @@ ifneq ($(RAYLIB_CONFIG_FLAGS), NONE)
|
|||
endif
|
||||
|
||||
ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_RGFW))
|
||||
# NOTE: When using multi-threading in the user code, it requires -pthread enabled
|
||||
CFLAGS += -std=gnu99
|
||||
else
|
||||
CFLAGS += -std=c99
|
||||
|
|
@ -383,12 +400,15 @@ ifeq ($(RAYLIB_BUILD_MODE),DEBUG)
|
|||
endif
|
||||
|
||||
ifeq ($(RAYLIB_BUILD_MODE),RELEASE)
|
||||
ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_RGFW))
|
||||
CFLAGS += -Os
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
|
||||
CFLAGS += -O1
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_WEB)
|
||||
CFLAGS += -Os
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_WEB_RGFW)
|
||||
CFLAGS += -Os
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
|
||||
CFLAGS += -O2
|
||||
endif
|
||||
|
|
@ -402,23 +422,12 @@ endif
|
|||
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
|
||||
CFLAGS += -Werror=implicit-function-declaration
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_RGFW))
|
||||
# -Os # size optimization
|
||||
# -O2 # optimization level 2, if used, also set --memory-init-file 0
|
||||
# -sUSE_GLFW=3 # Use glfw3 library (context/input management)
|
||||
# -sALLOW_MEMORY_GROWTH=1 # to allow memory resizing -> WARNING: Audio buffers could FAIL!
|
||||
# -sTOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) (67108864 = 64MB)
|
||||
# -sUSE_PTHREADS=1 # multithreading support
|
||||
# -sWASM=0 # disable Web Assembly, emitted by default
|
||||
# -sASYNCIFY # lets synchronous C/C++ code interact with asynchronous JS
|
||||
# -sFORCE_FILESYSTEM=1 # force filesystem to load/save files data
|
||||
# -sASSERTIONS=1 # enable runtime checks for common memory allocation errors (-O1 and above turn it off)
|
||||
# -sMINIFY_HTML=0 # minify generated html from shell.html
|
||||
# --profiling # include information for code profiling
|
||||
# --memory-init-file 0 # to avoid an external memory initialization code file (.mem)
|
||||
# --preload-file resources # specify a resources folder for data compilation
|
||||
# --source-map-base # allow debugging in browser with source map
|
||||
# --shell-file shell.html # define a custom shell .html and output extension
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_WEB)
|
||||
ifeq ($(RAYLIB_BUILD_MODE),DEBUG)
|
||||
CFLAGS += --profiling
|
||||
endif
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_WEB_RGFW)
|
||||
ifeq ($(RAYLIB_BUILD_MODE),DEBUG)
|
||||
CFLAGS += --profiling
|
||||
endif
|
||||
|
|
@ -768,7 +777,6 @@ all: raylib
|
|||
raylib: $(OBJS)
|
||||
ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_RGFW))
|
||||
# Compile raylib libray for web
|
||||
#$(CC) $(OBJS) -r -o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).bc
|
||||
ifeq ($(RAYLIB_LIBTYPE),SHARED)
|
||||
@echo "WARNING: $(TARGET_PLATFORM) does not support SHARED libraries. Generating STATIC library."
|
||||
endif
|
||||
|
|
|
|||
11
src/config.h
11
src/config.h
|
|
@ -73,7 +73,7 @@
|
|||
#define SUPPORT_RPRAND_GENERATOR 1
|
||||
#endif
|
||||
#ifndef SUPPORT_MOUSE_GESTURES
|
||||
// Mouse gestures are directly mapped like touches and processed by gestures system
|
||||
// Mouse gestures are directly mapped like touches and processed by the gestures system
|
||||
#define SUPPORT_MOUSE_GESTURES 1
|
||||
#endif
|
||||
#ifndef SUPPORT_SSH_KEYBOARD_RPI
|
||||
|
|
@ -125,7 +125,7 @@
|
|||
#endif
|
||||
|
||||
// rcore: Configuration values
|
||||
// NOTE: Below values are alread defined inside [rcore.c] so there is no need to be
|
||||
// NOTE: Below values are already defined inside [rcore.c] so there is no need to be
|
||||
// redefined here, in case it must be done, uncomment the required line and update
|
||||
// the value; it can also be done on compilation with -DVALUE_TO_REDEFINE=128
|
||||
//------------------------------------------------------------------------------------
|
||||
|
|
@ -159,7 +159,7 @@
|
|||
#endif
|
||||
|
||||
// rlgl: Configuration values
|
||||
// NOTE: Below values are alread defined inside [rlgl.h] so there is no need to be
|
||||
// NOTE: Below values are already defined inside [rlgl.h] so there is no need to be
|
||||
// redefined here, in case it must be done, uncomment the required line and update
|
||||
// the value; it can also be done on compilation with -DVALUE_TO_REDEFINE=128
|
||||
//------------------------------------------------------------------------------------
|
||||
|
|
@ -252,6 +252,9 @@
|
|||
#ifndef SUPPORT_FILEFORMAT_PIC
|
||||
#define SUPPORT_FILEFORMAT_PIC 0 // Disabled by default
|
||||
#endif
|
||||
#ifndef SUPPORT_FILEFORMAT_PNM
|
||||
#define SUPPORT_FILEFORMAT_PNM 0 // Disabled by default
|
||||
#endif
|
||||
#ifndef SUPPORT_FILEFORMAT_KTX
|
||||
#define SUPPORT_FILEFORMAT_KTX 0 // Disabled by default
|
||||
#endif
|
||||
|
|
@ -349,7 +352,7 @@
|
|||
#endif
|
||||
|
||||
// raudio: Configuration values
|
||||
// NOTE: Below values are alread defined inside [rlgl.h] so there is no need to be
|
||||
// NOTE: Below values are already defined inside [rlgl.h] so there is no need to be
|
||||
// redefined here, in case it must be done, uncomment the required line and update
|
||||
// the value; it can also be done on compilation with -DVALUE_TO_REDEFINE=128
|
||||
//------------------------------------------------------------------------------------
|
||||
|
|
|
|||
211
src/external/cgltf.h
vendored
211
src/external/cgltf.h
vendored
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* cgltf - a single-file glTF 2.0 parser written in C99.
|
||||
*
|
||||
* Version: 1.14
|
||||
* Version: 1.15
|
||||
*
|
||||
* Website: https://github.com/jkuhlmann/cgltf
|
||||
*
|
||||
|
|
@ -141,7 +141,7 @@ typedef struct cgltf_memory_options
|
|||
typedef struct cgltf_file_options
|
||||
{
|
||||
cgltf_result(*read)(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, const char* path, cgltf_size* size, void** data);
|
||||
void (*release)(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, void* data);
|
||||
void (*release)(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, void* data, cgltf_size size);
|
||||
void* user_data;
|
||||
} cgltf_file_options;
|
||||
|
||||
|
|
@ -296,6 +296,7 @@ typedef enum cgltf_meshopt_compression_filter {
|
|||
cgltf_meshopt_compression_filter_octahedral,
|
||||
cgltf_meshopt_compression_filter_quaternion,
|
||||
cgltf_meshopt_compression_filter_exponential,
|
||||
cgltf_meshopt_compression_filter_color,
|
||||
cgltf_meshopt_compression_filter_max_enum
|
||||
} cgltf_meshopt_compression_filter;
|
||||
|
||||
|
|
@ -308,6 +309,7 @@ typedef struct cgltf_meshopt_compression
|
|||
cgltf_size count;
|
||||
cgltf_meshopt_compression_mode mode;
|
||||
cgltf_meshopt_compression_filter filter;
|
||||
cgltf_bool is_khr;
|
||||
} cgltf_meshopt_compression;
|
||||
|
||||
typedef struct cgltf_buffer_view
|
||||
|
|
@ -376,13 +378,29 @@ typedef struct cgltf_image
|
|||
cgltf_extension* extensions;
|
||||
} cgltf_image;
|
||||
|
||||
typedef enum cgltf_filter_type {
|
||||
cgltf_filter_type_undefined = 0,
|
||||
cgltf_filter_type_nearest = 9728,
|
||||
cgltf_filter_type_linear = 9729,
|
||||
cgltf_filter_type_nearest_mipmap_nearest = 9984,
|
||||
cgltf_filter_type_linear_mipmap_nearest = 9985,
|
||||
cgltf_filter_type_nearest_mipmap_linear = 9986,
|
||||
cgltf_filter_type_linear_mipmap_linear = 9987
|
||||
} cgltf_filter_type;
|
||||
|
||||
typedef enum cgltf_wrap_mode {
|
||||
cgltf_wrap_mode_clamp_to_edge = 33071,
|
||||
cgltf_wrap_mode_mirrored_repeat = 33648,
|
||||
cgltf_wrap_mode_repeat = 10497
|
||||
} cgltf_wrap_mode;
|
||||
|
||||
typedef struct cgltf_sampler
|
||||
{
|
||||
char* name;
|
||||
cgltf_int mag_filter;
|
||||
cgltf_int min_filter;
|
||||
cgltf_int wrap_s;
|
||||
cgltf_int wrap_t;
|
||||
cgltf_filter_type mag_filter;
|
||||
cgltf_filter_type min_filter;
|
||||
cgltf_wrap_mode wrap_s;
|
||||
cgltf_wrap_mode wrap_t;
|
||||
cgltf_extras extras;
|
||||
cgltf_size extensions_count;
|
||||
cgltf_extension* extensions;
|
||||
|
|
@ -500,6 +518,14 @@ typedef struct cgltf_iridescence
|
|||
cgltf_texture_view iridescence_thickness_texture;
|
||||
} cgltf_iridescence;
|
||||
|
||||
typedef struct cgltf_diffuse_transmission
|
||||
{
|
||||
cgltf_texture_view diffuse_transmission_texture;
|
||||
cgltf_float diffuse_transmission_factor;
|
||||
cgltf_float diffuse_transmission_color_factor[3];
|
||||
cgltf_texture_view diffuse_transmission_color_texture;
|
||||
} cgltf_diffuse_transmission;
|
||||
|
||||
typedef struct cgltf_anisotropy
|
||||
{
|
||||
cgltf_float anisotropy_strength;
|
||||
|
|
@ -525,6 +551,7 @@ typedef struct cgltf_material
|
|||
cgltf_bool has_sheen;
|
||||
cgltf_bool has_emissive_strength;
|
||||
cgltf_bool has_iridescence;
|
||||
cgltf_bool has_diffuse_transmission;
|
||||
cgltf_bool has_anisotropy;
|
||||
cgltf_bool has_dispersion;
|
||||
cgltf_pbr_metallic_roughness pbr_metallic_roughness;
|
||||
|
|
@ -537,6 +564,7 @@ typedef struct cgltf_material
|
|||
cgltf_volume volume;
|
||||
cgltf_emissive_strength emissive_strength;
|
||||
cgltf_iridescence iridescence;
|
||||
cgltf_diffuse_transmission diffuse_transmission;
|
||||
cgltf_anisotropy anisotropy;
|
||||
cgltf_dispersion dispersion;
|
||||
cgltf_texture_view normal_texture;
|
||||
|
|
@ -743,6 +771,7 @@ typedef struct cgltf_data
|
|||
{
|
||||
cgltf_file_type file_type;
|
||||
void* file_data;
|
||||
cgltf_size file_size;
|
||||
|
||||
cgltf_asset asset;
|
||||
|
||||
|
|
@ -844,6 +873,8 @@ void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix)
|
|||
|
||||
const uint8_t* cgltf_buffer_view_data(const cgltf_buffer_view* view);
|
||||
|
||||
const cgltf_accessor* cgltf_find_accessor(const cgltf_primitive* prim, cgltf_attribute_type type, cgltf_int index);
|
||||
|
||||
cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size);
|
||||
cgltf_bool cgltf_accessor_read_uint(const cgltf_accessor* accessor, cgltf_size index, cgltf_uint* out, cgltf_size element_size);
|
||||
cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index);
|
||||
|
|
@ -1071,9 +1102,10 @@ static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* m
|
|||
return cgltf_result_success;
|
||||
}
|
||||
|
||||
static void cgltf_default_file_release(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, void* data)
|
||||
static void cgltf_default_file_release(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, void* data, cgltf_size size)
|
||||
{
|
||||
(void)file_options;
|
||||
(void)size;
|
||||
void (*memfree)(void*, void*) = memory_options->free_func ? memory_options->free_func : &cgltf_default_free;
|
||||
memfree(memory_options->user_data, data);
|
||||
}
|
||||
|
|
@ -1220,7 +1252,7 @@ cgltf_result cgltf_parse_file(const cgltf_options* options, const char* path, cg
|
|||
}
|
||||
|
||||
cgltf_result (*file_read)(const struct cgltf_memory_options*, const struct cgltf_file_options*, const char*, cgltf_size*, void**) = options->file.read ? options->file.read : &cgltf_default_file_read;
|
||||
void (*file_release)(const struct cgltf_memory_options*, const struct cgltf_file_options*, void* data) = options->file.release ? options->file.release : cgltf_default_file_release;
|
||||
void (*file_release)(const struct cgltf_memory_options*, const struct cgltf_file_options*, void* data, cgltf_size size) = options->file.release ? options->file.release : cgltf_default_file_release;
|
||||
|
||||
void* file_data = NULL;
|
||||
cgltf_size file_size = 0;
|
||||
|
|
@ -1234,11 +1266,12 @@ cgltf_result cgltf_parse_file(const cgltf_options* options, const char* path, cg
|
|||
|
||||
if (result != cgltf_result_success)
|
||||
{
|
||||
file_release(&options->memory, &options->file, file_data);
|
||||
file_release(&options->memory, &options->file, file_data, file_size);
|
||||
return result;
|
||||
}
|
||||
|
||||
(*out_data)->file_data = file_data;
|
||||
(*out_data)->file_size = file_size;
|
||||
|
||||
return cgltf_result_success;
|
||||
}
|
||||
|
|
@ -1630,8 +1663,8 @@ cgltf_result cgltf_validate(cgltf_data* data)
|
|||
CGLTF_ASSERT_IF((mc->mode == cgltf_meshopt_compression_mode_triangles || mc->mode == cgltf_meshopt_compression_mode_indices) && mc->filter != cgltf_meshopt_compression_filter_none, cgltf_result_invalid_gltf);
|
||||
|
||||
CGLTF_ASSERT_IF(mc->filter == cgltf_meshopt_compression_filter_octahedral && mc->stride != 4 && mc->stride != 8, cgltf_result_invalid_gltf);
|
||||
|
||||
CGLTF_ASSERT_IF(mc->filter == cgltf_meshopt_compression_filter_quaternion && mc->stride != 8, cgltf_result_invalid_gltf);
|
||||
CGLTF_ASSERT_IF(mc->filter == cgltf_meshopt_compression_filter_color && mc->stride != 4 && mc->stride != 8, cgltf_result_invalid_gltf);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1822,7 +1855,7 @@ void cgltf_free(cgltf_data* data)
|
|||
return;
|
||||
}
|
||||
|
||||
void (*file_release)(const struct cgltf_memory_options*, const struct cgltf_file_options*, void* data) = data->file.release ? data->file.release : cgltf_default_file_release;
|
||||
void (*file_release)(const struct cgltf_memory_options*, const struct cgltf_file_options*, void* data, cgltf_size size) = data->file.release ? data->file.release : cgltf_default_file_release;
|
||||
|
||||
data->memory.free_func(data->memory.user_data, data->asset.copyright);
|
||||
data->memory.free_func(data->memory.user_data, data->asset.generator);
|
||||
|
|
@ -1857,7 +1890,7 @@ void cgltf_free(cgltf_data* data)
|
|||
|
||||
if (data->buffers[i].data_free_method == cgltf_data_free_method_file_release)
|
||||
{
|
||||
file_release(&data->memory, &data->file, data->buffers[i].data);
|
||||
file_release(&data->memory, &data->file, data->buffers[i].data, data->buffers[i].size);
|
||||
}
|
||||
else if (data->buffers[i].data_free_method == cgltf_data_free_method_memory_free)
|
||||
{
|
||||
|
|
@ -2096,7 +2129,7 @@ void cgltf_free(cgltf_data* data)
|
|||
|
||||
data->memory.free_func(data->memory.user_data, data->extensions_required);
|
||||
|
||||
file_release(&data->memory, &data->file, data->file_data);
|
||||
file_release(&data->memory, &data->file, data->file_data, data->file_size);
|
||||
|
||||
data->memory.free_func(data->memory.user_data, data);
|
||||
}
|
||||
|
|
@ -2312,11 +2345,58 @@ const uint8_t* cgltf_buffer_view_data(const cgltf_buffer_view* view)
|
|||
return result;
|
||||
}
|
||||
|
||||
const cgltf_accessor* cgltf_find_accessor(const cgltf_primitive* prim, cgltf_attribute_type type, cgltf_int index)
|
||||
{
|
||||
for (cgltf_size i = 0; i < prim->attributes_count; ++i)
|
||||
{
|
||||
const cgltf_attribute* attr = &prim->attributes[i];
|
||||
if (attr->type == type && attr->index == index)
|
||||
return attr->data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const uint8_t* cgltf_find_sparse_index(const cgltf_accessor* accessor, cgltf_size needle)
|
||||
{
|
||||
const cgltf_accessor_sparse* sparse = &accessor->sparse;
|
||||
const uint8_t* index_data = cgltf_buffer_view_data(sparse->indices_buffer_view);
|
||||
const uint8_t* value_data = cgltf_buffer_view_data(sparse->values_buffer_view);
|
||||
|
||||
if (index_data == NULL || value_data == NULL)
|
||||
return NULL;
|
||||
|
||||
index_data += sparse->indices_byte_offset;
|
||||
value_data += sparse->values_byte_offset;
|
||||
|
||||
cgltf_size index_stride = cgltf_component_size(sparse->indices_component_type);
|
||||
|
||||
cgltf_size offset = 0;
|
||||
cgltf_size length = sparse->count;
|
||||
|
||||
while (length)
|
||||
{
|
||||
cgltf_size rem = length % 2;
|
||||
length /= 2;
|
||||
|
||||
cgltf_size index = cgltf_component_read_index(index_data + (offset + length) * index_stride, sparse->indices_component_type);
|
||||
offset += index < needle ? length + rem : 0;
|
||||
}
|
||||
|
||||
if (offset == sparse->count)
|
||||
return NULL;
|
||||
|
||||
cgltf_size index = cgltf_component_read_index(index_data + offset * index_stride, sparse->indices_component_type);
|
||||
return index == needle ? value_data + offset * accessor->stride : NULL;
|
||||
}
|
||||
|
||||
cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size)
|
||||
{
|
||||
if (accessor->is_sparse)
|
||||
{
|
||||
return 0;
|
||||
const uint8_t* element = cgltf_find_sparse_index(accessor, index);
|
||||
if (element)
|
||||
return cgltf_element_read_float(element, accessor->type, accessor->component_type, accessor->normalized, out, element_size);
|
||||
}
|
||||
if (accessor->buffer_view == NULL)
|
||||
{
|
||||
|
|
@ -2460,11 +2540,13 @@ cgltf_bool cgltf_accessor_read_uint(const cgltf_accessor* accessor, cgltf_size i
|
|||
{
|
||||
if (accessor->is_sparse)
|
||||
{
|
||||
return 0;
|
||||
const uint8_t* element = cgltf_find_sparse_index(accessor, index);
|
||||
if (element)
|
||||
return cgltf_element_read_uint(element, accessor->type, accessor->component_type, out, element_size);
|
||||
}
|
||||
if (accessor->buffer_view == NULL)
|
||||
{
|
||||
memset(out, 0, element_size * sizeof( cgltf_uint ));
|
||||
memset(out, 0, element_size * sizeof(cgltf_uint));
|
||||
return 1;
|
||||
}
|
||||
const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view);
|
||||
|
|
@ -2480,7 +2562,9 @@ cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size
|
|||
{
|
||||
if (accessor->is_sparse)
|
||||
{
|
||||
return 0; // This is an error case, but we can't communicate the error with existing interface.
|
||||
const uint8_t* element = cgltf_find_sparse_index(accessor, index);
|
||||
if (element)
|
||||
return cgltf_component_read_index(element, accessor->component_type);
|
||||
}
|
||||
if (accessor->buffer_view == NULL)
|
||||
{
|
||||
|
|
@ -2598,7 +2682,10 @@ cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, void* o
|
|||
return accessor->count;
|
||||
}
|
||||
|
||||
index_count = accessor->count < index_count ? accessor->count : index_count;
|
||||
cgltf_size numbers_per_element = cgltf_num_components(accessor->type);
|
||||
cgltf_size available_numbers = accessor->count * numbers_per_element;
|
||||
|
||||
index_count = available_numbers < index_count ? available_numbers : index_count;
|
||||
cgltf_size index_component_size = cgltf_component_size(accessor->component_type);
|
||||
|
||||
if (accessor->is_sparse)
|
||||
|
|
@ -2620,15 +2707,23 @@ cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, void* o
|
|||
}
|
||||
element += accessor->offset;
|
||||
|
||||
if (index_component_size == out_component_size && accessor->stride == out_component_size)
|
||||
if (index_component_size == out_component_size && accessor->stride == out_component_size * numbers_per_element)
|
||||
{
|
||||
memcpy(out, element, index_count * index_component_size);
|
||||
return index_count;
|
||||
}
|
||||
|
||||
// Data couldn't be copied with memcpy due to stride being larger than the component size.
|
||||
// OR
|
||||
// The component size of the output array is larger than the component size of the index data, so index data will be padded.
|
||||
switch (out_component_size)
|
||||
{
|
||||
case 1:
|
||||
for (cgltf_size index = 0; index < index_count; index++, element += accessor->stride)
|
||||
{
|
||||
((uint8_t*)out)[index] = (uint8_t)cgltf_component_read_index(element, accessor->component_type);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (cgltf_size index = 0; index < index_count; index++, element += accessor->stride)
|
||||
{
|
||||
|
|
@ -2642,7 +2737,7 @@ cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, void* o
|
|||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return index_count;
|
||||
|
|
@ -4278,6 +4373,52 @@ static int cgltf_parse_json_iridescence(cgltf_options* options, jsmntok_t const*
|
|||
return i;
|
||||
}
|
||||
|
||||
static int cgltf_parse_json_diffuse_transmission(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_diffuse_transmission* out_diff_transmission)
|
||||
{
|
||||
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
int size = tokens[i].size;
|
||||
++i;
|
||||
|
||||
// Defaults
|
||||
cgltf_fill_float_array(out_diff_transmission->diffuse_transmission_color_factor, 3, 1.0f);
|
||||
out_diff_transmission->diffuse_transmission_factor = 0.f;
|
||||
|
||||
for (int j = 0; j < size; ++j)
|
||||
{
|
||||
CGLTF_CHECK_KEY(tokens[i]);
|
||||
|
||||
if (cgltf_json_strcmp(tokens + i, json_chunk, "diffuseTransmissionFactor") == 0)
|
||||
{
|
||||
++i;
|
||||
out_diff_transmission->diffuse_transmission_factor = cgltf_json_to_float(tokens + i, json_chunk);
|
||||
++i;
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "diffuseTransmissionTexture") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_diff_transmission->diffuse_transmission_texture);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "diffuseTransmissionColorFactor") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_diff_transmission->diffuse_transmission_color_factor, 3);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "diffuseTransmissionColorTexture") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_diff_transmission->diffuse_transmission_color_texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
i = cgltf_skip_json(tokens, i + 1);
|
||||
}
|
||||
|
||||
if (i < 0)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int cgltf_parse_json_anisotropy(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_anisotropy* out_anisotropy)
|
||||
{
|
||||
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
|
|
@ -4406,8 +4547,8 @@ static int cgltf_parse_json_sampler(cgltf_options* options, jsmntok_t const* tok
|
|||
(void)options;
|
||||
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
|
||||
out_sampler->wrap_s = 10497;
|
||||
out_sampler->wrap_t = 10497;
|
||||
out_sampler->wrap_s = cgltf_wrap_mode_repeat;
|
||||
out_sampler->wrap_t = cgltf_wrap_mode_repeat;
|
||||
|
||||
int size = tokens[i].size;
|
||||
++i;
|
||||
|
|
@ -4424,28 +4565,28 @@ static int cgltf_parse_json_sampler(cgltf_options* options, jsmntok_t const* tok
|
|||
{
|
||||
++i;
|
||||
out_sampler->mag_filter
|
||||
= cgltf_json_to_int(tokens + i, json_chunk);
|
||||
= (cgltf_filter_type)cgltf_json_to_int(tokens + i, json_chunk);
|
||||
++i;
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "minFilter") == 0)
|
||||
{
|
||||
++i;
|
||||
out_sampler->min_filter
|
||||
= cgltf_json_to_int(tokens + i, json_chunk);
|
||||
= (cgltf_filter_type)cgltf_json_to_int(tokens + i, json_chunk);
|
||||
++i;
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapS") == 0)
|
||||
{
|
||||
++i;
|
||||
out_sampler->wrap_s
|
||||
= cgltf_json_to_int(tokens + i, json_chunk);
|
||||
= (cgltf_wrap_mode)cgltf_json_to_int(tokens + i, json_chunk);
|
||||
++i;
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapT") == 0)
|
||||
{
|
||||
++i;
|
||||
out_sampler->wrap_t
|
||||
= cgltf_json_to_int(tokens + i, json_chunk);
|
||||
= (cgltf_wrap_mode)cgltf_json_to_int(tokens + i, json_chunk);
|
||||
++i;
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
|
|
@ -4766,6 +4907,11 @@ static int cgltf_parse_json_material(cgltf_options* options, jsmntok_t const* to
|
|||
out_material->has_iridescence = 1;
|
||||
i = cgltf_parse_json_iridescence(options, tokens, i + 1, json_chunk, &out_material->iridescence);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_diffuse_transmission") == 0)
|
||||
{
|
||||
out_material->has_diffuse_transmission = 1;
|
||||
i = cgltf_parse_json_diffuse_transmission(options, tokens, i + 1, json_chunk, &out_material->diffuse_transmission);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_anisotropy") == 0)
|
||||
{
|
||||
out_material->has_anisotropy = 1;
|
||||
|
|
@ -4974,6 +5120,10 @@ static int cgltf_parse_json_meshopt_compression(cgltf_options* options, jsmntok_
|
|||
{
|
||||
out_meshopt_compression->filter = cgltf_meshopt_compression_filter_exponential;
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens+i, json_chunk, "COLOR") == 0)
|
||||
{
|
||||
out_meshopt_compression->filter = cgltf_meshopt_compression_filter_color;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
else
|
||||
|
|
@ -5084,6 +5234,12 @@ static int cgltf_parse_json_buffer_view(cgltf_options* options, jsmntok_t const*
|
|||
out_buffer_view->has_meshopt_compression = 1;
|
||||
i = cgltf_parse_json_meshopt_compression(options, tokens, i + 1, json_chunk, &out_buffer_view->meshopt_compression);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_meshopt_compression") == 0)
|
||||
{
|
||||
out_buffer_view->has_meshopt_compression = 1;
|
||||
out_buffer_view->meshopt_compression.is_khr = 1;
|
||||
i = cgltf_parse_json_meshopt_compression(options, tokens, i + 1, json_chunk, &out_buffer_view->meshopt_compression);
|
||||
}
|
||||
else
|
||||
{
|
||||
i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_buffer_view->extensions[out_buffer_view->extensions_count++]));
|
||||
|
|
@ -6629,6 +6785,9 @@ static int cgltf_fixup_pointers(cgltf_data* data)
|
|||
CGLTF_PTRFIXUP(data->materials[i].iridescence.iridescence_texture.texture, data->textures, data->textures_count);
|
||||
CGLTF_PTRFIXUP(data->materials[i].iridescence.iridescence_thickness_texture.texture, data->textures, data->textures_count);
|
||||
|
||||
CGLTF_PTRFIXUP(data->materials[i].diffuse_transmission.diffuse_transmission_texture.texture, data->textures, data->textures_count);
|
||||
CGLTF_PTRFIXUP(data->materials[i].diffuse_transmission.diffuse_transmission_color_texture.texture, data->textures, data->textures_count);
|
||||
|
||||
CGLTF_PTRFIXUP(data->materials[i].anisotropy.anisotropy_texture.texture, data->textures, data->textures_count);
|
||||
}
|
||||
|
||||
|
|
|
|||
1565
src/external/cgltf_write.h
vendored
Normal file
1565
src/external/cgltf_write.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
366
src/external/dr_flac.h
vendored
366
src/external/dr_flac.h
vendored
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
|
||||
dr_flac - v0.13.0 - TBD
|
||||
dr_flac - v0.13.4 - TBD
|
||||
|
||||
David Reid - mackron@gmail.com
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ extern "C" {
|
|||
|
||||
#define DRFLAC_VERSION_MAJOR 0
|
||||
#define DRFLAC_VERSION_MINOR 13
|
||||
#define DRFLAC_VERSION_REVISION 0
|
||||
#define DRFLAC_VERSION_REVISION 4
|
||||
#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. */
|
||||
|
|
@ -331,6 +331,12 @@ typedef struct
|
|||
*/
|
||||
drflac_uint32 type;
|
||||
|
||||
/* The size in bytes of the block and the buffer pointed to by pRawData if it's non-NULL. */
|
||||
drflac_uint32 rawDataSize;
|
||||
|
||||
/* The offset in the stream of the raw data. */
|
||||
drflac_uint64 rawDataOffset;
|
||||
|
||||
/*
|
||||
A pointer to the raw data. This points to a temporary buffer so don't hold on to it. It's best to
|
||||
not modify the contents of this buffer. Use the structures below for more meaningful and structured
|
||||
|
|
@ -338,9 +344,6 @@ typedef struct
|
|||
*/
|
||||
const void* pRawData;
|
||||
|
||||
/* The size in bytes of the block and the buffer pointed to by pRawData if it's non-NULL. */
|
||||
drflac_uint32 rawDataSize;
|
||||
|
||||
union
|
||||
{
|
||||
drflac_streaminfo streaminfo;
|
||||
|
|
@ -392,6 +395,7 @@ typedef struct
|
|||
drflac_uint32 colorDepth;
|
||||
drflac_uint32 indexColorCount;
|
||||
drflac_uint32 pictureDataSize;
|
||||
drflac_uint64 pictureDataOffset; /* Offset from the start of the stream. */
|
||||
const drflac_uint8* pPictureData;
|
||||
} picture;
|
||||
} data;
|
||||
|
|
@ -1543,6 +1547,8 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void)
|
|||
#define DRFLAC_ZERO_OBJECT(p) DRFLAC_ZERO_MEMORY((p), sizeof(*(p)))
|
||||
#endif
|
||||
|
||||
#define DRFLAC_MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
#define DRFLAC_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */
|
||||
|
||||
/* Result Codes */
|
||||
|
|
@ -2712,9 +2718,17 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x)
|
|||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#if defined(DRFLAC_X64)
|
||||
{
|
||||
/*
|
||||
A note on lzcnt.
|
||||
|
||||
We check for the presence of the lzcnt instruction at runtime before calling this function, but we still generate this code. I have had
|
||||
a report where the assembler does not recognize the lzcnt instruction. To work around this we are going to use `rep; bsr` instead which
|
||||
has an identical byte encoding as lzcnt, and should hopefully improve compatibility with older assemblers.
|
||||
*/
|
||||
drflac_uint64 r;
|
||||
__asm__ __volatile__ (
|
||||
"lzcnt{ %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
|
||||
"rep; bsr{q %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
|
||||
/*"lzcnt{ %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"*/
|
||||
);
|
||||
|
||||
return (drflac_uint32)r;
|
||||
|
|
@ -2723,12 +2737,13 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x)
|
|||
{
|
||||
drflac_uint32 r;
|
||||
__asm__ __volatile__ (
|
||||
"lzcnt{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
|
||||
"rep; bsr{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
|
||||
/*"lzcnt{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"*/
|
||||
);
|
||||
|
||||
return r;
|
||||
}
|
||||
#elif defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(__ARM_ARCH_6M__) && !defined(DRFLAC_64BIT) /* <-- I haven't tested 64-bit inline assembly, so only enabling this for the 32-bit build for now. */
|
||||
#elif defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(__ARM_ARCH_6M__) && !(defined(__thumb__) && !defined(__thumb2__)) && !defined(DRFLAC_64BIT) /* <-- I haven't tested 64-bit inline assembly, so only enabling this for the 32-bit build for now. */
|
||||
{
|
||||
unsigned int r;
|
||||
__asm__ __volatile__ (
|
||||
|
|
@ -5967,8 +5982,6 @@ static drflac_bool32 drflac__seek_to_pcm_frame__binary_search_internal(drflac* p
|
|||
break; /* Failed to seek to FLAC frame. */
|
||||
}
|
||||
} else {
|
||||
const float approxCompressionRatio = (drflac_int64)(lastSuccessfulSeekOffset - pFlac->firstFLACFramePosInBytes) / ((drflac_int64)(pcmRangeLo * pFlac->channels * pFlac->bitsPerSample)/8.0f);
|
||||
|
||||
if (pcmRangeLo > pcmFrameIndex) {
|
||||
/* We seeked too far forward. We need to move our target byte backward and try again. */
|
||||
byteRangeHi = lastSuccessfulSeekOffset;
|
||||
|
|
@ -5991,12 +6004,14 @@ static drflac_bool32 drflac__seek_to_pcm_frame__binary_search_internal(drflac* p
|
|||
break; /* Failed to seek to FLAC frame. */
|
||||
}
|
||||
} else {
|
||||
const double approxCompressionRatio = (drflac_int64)(lastSuccessfulSeekOffset - pFlac->firstFLACFramePosInBytes) / ((drflac_int64)(pcmRangeLo * pFlac->channels * pFlac->bitsPerSample)/8.0);
|
||||
|
||||
byteRangeLo = lastSuccessfulSeekOffset;
|
||||
if (byteRangeHi < byteRangeLo) {
|
||||
byteRangeHi = byteRangeLo;
|
||||
}
|
||||
|
||||
targetByte = lastSuccessfulSeekOffset + (drflac_uint64)(((drflac_int64)((pcmFrameIndex-pcmRangeLo) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * approxCompressionRatio);
|
||||
targetByte = lastSuccessfulSeekOffset + (drflac_uint64)(((drflac_int64)((pcmFrameIndex-pcmRangeLo) * pFlac->channels * pFlac->bitsPerSample)/8.0) * approxCompressionRatio);
|
||||
if (targetByte > byteRangeHi) {
|
||||
targetByte = byteRangeHi;
|
||||
}
|
||||
|
|
@ -6389,7 +6404,7 @@ static void* drflac__realloc_from_callbacks(void* p, size_t szNew, size_t szOld,
|
|||
}
|
||||
|
||||
if (p != NULL) {
|
||||
DRFLAC_COPY_MEMORY(p2, p, szOld);
|
||||
DRFLAC_COPY_MEMORY(p2, p, DRFLAC_MIN(szNew, szOld));
|
||||
pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
|
||||
}
|
||||
|
||||
|
|
@ -6417,11 +6432,22 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
|
|||
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
|
||||
we'll be sitting on byte 42.
|
||||
*/
|
||||
drflac_uint64 runningFilePos = 42;
|
||||
drflac_uint64 seektablePos = 0;
|
||||
drflac_uint32 seektableSize = 0;
|
||||
drflac_uint64 runningFilePos = 42;
|
||||
drflac_uint64 seektablePos = 0;
|
||||
drflac_uint32 seektableSize = 0;
|
||||
drflac_int64 fileSize = 0;
|
||||
drflac_bool32 hasKnownFileSize = DRFLAC_FALSE;
|
||||
|
||||
(void)onTell;
|
||||
/* We'll be doing some memory allocations here against untrusted data. We'll do a basic validation check that they don't exceed the size of the file. */
|
||||
if (onTell != NULL && onSeek != NULL) {
|
||||
if (onSeek(pUserData, 0, DRFLAC_SEEK_END)) {
|
||||
if (onTell(pUserData, &fileSize)) {
|
||||
hasKnownFileSize = DRFLAC_TRUE;
|
||||
}
|
||||
|
||||
onSeek(pUserData, runningFilePos, DRFLAC_SEEK_SET);
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
drflac_metadata metadata;
|
||||
|
|
@ -6431,11 +6457,17 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
|
|||
if (drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == DRFLAC_FALSE) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
|
||||
if (hasKnownFileSize && (blockSize > ((drflac_uint64)fileSize - runningFilePos))) {
|
||||
return DRFLAC_FALSE; /* Block size exceeds the size of the file. */
|
||||
}
|
||||
|
||||
runningFilePos += 4;
|
||||
|
||||
metadata.type = blockType;
|
||||
metadata.pRawData = NULL;
|
||||
metadata.rawDataSize = 0;
|
||||
metadata.rawDataOffset = runningFilePos;
|
||||
metadata.pRawData = NULL;
|
||||
|
||||
switch (blockType)
|
||||
{
|
||||
|
|
@ -6545,7 +6577,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
|
|||
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength;
|
||||
metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength;
|
||||
metadata.data.vorbis_comment.commentCount = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
|
||||
|
||||
/* Need space for 'commentCount' comments after the block, which at minimum is a drflac_uint32 per comment */
|
||||
|
|
@ -6712,59 +6744,161 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
|
|||
}
|
||||
|
||||
if (onMeta) {
|
||||
void* pRawData;
|
||||
const char* pRunningData;
|
||||
const char* pRunningDataEnd;
|
||||
drflac_bool32 result = DRFLAC_TRUE;
|
||||
drflac_uint32 blockSizeRemaining = blockSize;
|
||||
char* pMime = NULL;
|
||||
char* pDescription = NULL;
|
||||
void* pPictureData = NULL;
|
||||
|
||||
pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
|
||||
if (pRawData == NULL) {
|
||||
return DRFLAC_FALSE;
|
||||
if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.type, 4) != 4) {
|
||||
result = DRFLAC_FALSE;
|
||||
goto done_flac;
|
||||
}
|
||||
blockSizeRemaining -= 4;
|
||||
metadata.data.picture.type = drflac__be2host_32(metadata.data.picture.type);
|
||||
|
||||
|
||||
if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.mimeLength, 4) != 4) {
|
||||
result = DRFLAC_FALSE;
|
||||
goto done_flac;
|
||||
}
|
||||
blockSizeRemaining -= 4;
|
||||
metadata.data.picture.mimeLength = drflac__be2host_32(metadata.data.picture.mimeLength);
|
||||
|
||||
if (blockSizeRemaining < metadata.data.picture.mimeLength) {
|
||||
result = DRFLAC_FALSE;
|
||||
goto done_flac;
|
||||
}
|
||||
|
||||
if (onRead(pUserData, pRawData, blockSize) != blockSize) {
|
||||
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
|
||||
return DRFLAC_FALSE;
|
||||
pMime = (char*)drflac__malloc_from_callbacks(metadata.data.picture.mimeLength + 1, pAllocationCallbacks); /* +1 for null terminator. */
|
||||
if (pMime == NULL) {
|
||||
result = DRFLAC_FALSE;
|
||||
goto done_flac;
|
||||
}
|
||||
|
||||
metadata.pRawData = pRawData;
|
||||
metadata.rawDataSize = blockSize;
|
||||
|
||||
pRunningData = (const char*)pRawData;
|
||||
pRunningDataEnd = (const char*)pRawData + blockSize;
|
||||
|
||||
metadata.data.picture.type = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
|
||||
metadata.data.picture.mimeLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
|
||||
|
||||
/* Need space for the rest of the block */
|
||||
if ((pRunningDataEnd - pRunningData) - 24 < (drflac_int64)metadata.data.picture.mimeLength) { /* <-- Note the order of operations to avoid overflow to a valid value */
|
||||
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
|
||||
return DRFLAC_FALSE;
|
||||
if (onRead(pUserData, pMime, metadata.data.picture.mimeLength) != metadata.data.picture.mimeLength) {
|
||||
result = DRFLAC_FALSE;
|
||||
goto done_flac;
|
||||
}
|
||||
metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength;
|
||||
metadata.data.picture.descriptionLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
|
||||
blockSizeRemaining -= metadata.data.picture.mimeLength;
|
||||
pMime[metadata.data.picture.mimeLength] = '\0'; /* Null terminate for safety. */
|
||||
metadata.data.picture.mime = (const char*)pMime;
|
||||
|
||||
/* Need space for the rest of the block */
|
||||
if ((pRunningDataEnd - pRunningData) - 20 < (drflac_int64)metadata.data.picture.descriptionLength) { /* <-- Note the order of operations to avoid overflow to a valid value */
|
||||
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
|
||||
return DRFLAC_FALSE;
|
||||
|
||||
if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.descriptionLength, 4) != 4) {
|
||||
result = DRFLAC_FALSE;
|
||||
goto done_flac;
|
||||
}
|
||||
metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength;
|
||||
metadata.data.picture.width = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
|
||||
metadata.data.picture.height = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
|
||||
metadata.data.picture.colorDepth = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
|
||||
metadata.data.picture.indexColorCount = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
|
||||
metadata.data.picture.pictureDataSize = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
|
||||
metadata.data.picture.pPictureData = (const drflac_uint8*)pRunningData;
|
||||
blockSizeRemaining -= 4;
|
||||
metadata.data.picture.descriptionLength = drflac__be2host_32(metadata.data.picture.descriptionLength);
|
||||
|
||||
/* Need space for the picture after the block */
|
||||
if (pRunningDataEnd - pRunningData < (drflac_int64)metadata.data.picture.pictureDataSize) { /* <-- Note the order of operations to avoid overflow to a valid value */
|
||||
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
|
||||
return DRFLAC_FALSE;
|
||||
if (blockSizeRemaining < metadata.data.picture.descriptionLength) {
|
||||
result = DRFLAC_FALSE;
|
||||
goto done_flac;
|
||||
}
|
||||
|
||||
onMeta(pUserDataMD, &metadata);
|
||||
pDescription = (char*)drflac__malloc_from_callbacks(metadata.data.picture.descriptionLength + 1, pAllocationCallbacks); /* +1 for null terminator. */
|
||||
if (pDescription == NULL) {
|
||||
result = DRFLAC_FALSE;
|
||||
goto done_flac;
|
||||
}
|
||||
|
||||
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
|
||||
if (onRead(pUserData, pDescription, metadata.data.picture.descriptionLength) != metadata.data.picture.descriptionLength) {
|
||||
result = DRFLAC_FALSE;
|
||||
goto done_flac;
|
||||
}
|
||||
blockSizeRemaining -= metadata.data.picture.descriptionLength;
|
||||
pDescription[metadata.data.picture.descriptionLength] = '\0'; /* Null terminate for safety. */
|
||||
metadata.data.picture.description = (const char*)pDescription;
|
||||
|
||||
|
||||
if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.width, 4) != 4) {
|
||||
result = DRFLAC_FALSE;
|
||||
goto done_flac;
|
||||
}
|
||||
blockSizeRemaining -= 4;
|
||||
metadata.data.picture.width = drflac__be2host_32(metadata.data.picture.width);
|
||||
|
||||
if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.height, 4) != 4) {
|
||||
result = DRFLAC_FALSE;
|
||||
goto done_flac;
|
||||
}
|
||||
blockSizeRemaining -= 4;
|
||||
metadata.data.picture.height = drflac__be2host_32(metadata.data.picture.height);
|
||||
|
||||
if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.colorDepth, 4) != 4) {
|
||||
result = DRFLAC_FALSE;
|
||||
goto done_flac;
|
||||
}
|
||||
blockSizeRemaining -= 4;
|
||||
metadata.data.picture.colorDepth = drflac__be2host_32(metadata.data.picture.colorDepth);
|
||||
|
||||
if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.indexColorCount, 4) != 4) {
|
||||
result = DRFLAC_FALSE;
|
||||
goto done_flac;
|
||||
}
|
||||
blockSizeRemaining -= 4;
|
||||
metadata.data.picture.indexColorCount = drflac__be2host_32(metadata.data.picture.indexColorCount);
|
||||
|
||||
|
||||
/* Picture data. */
|
||||
if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.pictureDataSize, 4) != 4) {
|
||||
result = DRFLAC_FALSE;
|
||||
goto done_flac;
|
||||
}
|
||||
blockSizeRemaining -= 4;
|
||||
metadata.data.picture.pictureDataSize = drflac__be2host_32(metadata.data.picture.pictureDataSize);
|
||||
|
||||
if (blockSizeRemaining < metadata.data.picture.pictureDataSize) {
|
||||
result = DRFLAC_FALSE;
|
||||
goto done_flac;
|
||||
}
|
||||
|
||||
/* For the actual image data we want to store the offset to the start of the stream. */
|
||||
metadata.data.picture.pictureDataOffset = runningFilePos + (blockSize - blockSizeRemaining);
|
||||
|
||||
/*
|
||||
For the allocation of image data, we can allow memory allocation to fail, in which case we just leave
|
||||
the pointer as null. If it fails, we need to fall back to seeking past the image data.
|
||||
*/
|
||||
#ifndef DR_FLAC_NO_PICTURE_METADATA_MALLOC
|
||||
pPictureData = drflac__malloc_from_callbacks(metadata.data.picture.pictureDataSize, pAllocationCallbacks);
|
||||
if (pPictureData != NULL) {
|
||||
if (onRead(pUserData, pPictureData, metadata.data.picture.pictureDataSize) != metadata.data.picture.pictureDataSize) {
|
||||
result = DRFLAC_FALSE;
|
||||
goto done_flac;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/* Allocation failed. We need to seek past the picture data. */
|
||||
if (!onSeek(pUserData, metadata.data.picture.pictureDataSize, DRFLAC_SEEK_CUR)) {
|
||||
result = DRFLAC_FALSE;
|
||||
goto done_flac;
|
||||
}
|
||||
}
|
||||
|
||||
blockSizeRemaining -= metadata.data.picture.pictureDataSize;
|
||||
(void)blockSizeRemaining;
|
||||
|
||||
metadata.data.picture.pPictureData = (const drflac_uint8*)pPictureData;
|
||||
|
||||
|
||||
/* Only fire the callback if we actually have a way to read the image data. We must have either a valid offset, or a valid data pointer. */
|
||||
if (metadata.data.picture.pictureDataOffset != 0 || metadata.data.picture.pPictureData != NULL) {
|
||||
onMeta(pUserDataMD, &metadata);
|
||||
} else {
|
||||
/* Don't have a valid offset or data pointer, so just pretend we don't have a picture metadata. */
|
||||
}
|
||||
|
||||
done_flac:
|
||||
drflac__free_from_callbacks(pMime, pAllocationCallbacks);
|
||||
drflac__free_from_callbacks(pDescription, pAllocationCallbacks);
|
||||
drflac__free_from_callbacks(pPictureData, pAllocationCallbacks);
|
||||
|
||||
if (result != DRFLAC_TRUE) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
|
|
@ -6800,13 +6934,16 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
|
|||
*/
|
||||
if (onMeta) {
|
||||
void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
|
||||
if (pRawData == NULL) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
|
||||
if (onRead(pUserData, pRawData, blockSize) != blockSize) {
|
||||
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
|
||||
return DRFLAC_FALSE;
|
||||
if (pRawData != NULL) {
|
||||
if (onRead(pUserData, pRawData, blockSize) != blockSize) {
|
||||
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
} else {
|
||||
/* Allocation failed. We need to seek past the block. */
|
||||
if (!onSeek(pUserData, blockSize, DRFLAC_SEEK_CUR)) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
metadata.pRawData = pRawData;
|
||||
|
|
@ -7985,11 +8122,17 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if ((0xFFFFFFFF - (seekpointCount * sizeof(drflac_seekpoint))) < allocationSize) {
|
||||
#ifndef DR_FLAC_NO_OGG
|
||||
drflac__free_from_callbacks(pOggbs, &allocationCallbacks);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
allocationSize += seekpointCount * sizeof(drflac_seekpoint);
|
||||
}
|
||||
|
||||
|
||||
pFlac = (drflac*)drflac__malloc_from_callbacks(allocationSize, &allocationCallbacks);
|
||||
pFlac = (drflac*)drflac__malloc_from_callbacks((size_t)allocationSize, &allocationCallbacks);
|
||||
if (pFlac == NULL) {
|
||||
#ifndef DR_FLAC_NO_OGG
|
||||
drflac__free_from_callbacks(pOggbs, &allocationCallbacks);
|
||||
|
|
@ -8699,7 +8842,7 @@ static drflac_bool32 drflac__on_tell_stdio(void* pUserData, drflac_int64* pCurso
|
|||
DRFLAC_ASSERT(pFileStdio != NULL);
|
||||
DRFLAC_ASSERT(pCursor != NULL);
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if defined(_WIN32) && !defined(NXDK)
|
||||
#if defined(_MSC_VER) && _MSC_VER > 1200
|
||||
result = _ftelli64(pFileStdio);
|
||||
#else
|
||||
|
|
@ -8821,8 +8964,6 @@ static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_
|
|||
|
||||
DRFLAC_ASSERT(memoryStream != NULL);
|
||||
|
||||
newCursor = memoryStream->currentReadPos;
|
||||
|
||||
if (origin == DRFLAC_SEEK_SET) {
|
||||
newCursor = 0;
|
||||
} else if (origin == DRFLAC_SEEK_CUR) {
|
||||
|
|
@ -11702,58 +11843,43 @@ static type* drflac__full_read_and_close_ ## extension (drflac* pFlac, unsigned
|
|||
{ \
|
||||
type* pSampleData = NULL; \
|
||||
drflac_uint64 totalPCMFrameCount; \
|
||||
type buffer[4096]; \
|
||||
drflac_uint64 pcmFramesRead; \
|
||||
size_t sampleDataBufferSize = sizeof(buffer); \
|
||||
\
|
||||
DRFLAC_ASSERT(pFlac != NULL); \
|
||||
\
|
||||
totalPCMFrameCount = pFlac->totalPCMFrameCount; \
|
||||
totalPCMFrameCount = 0; \
|
||||
\
|
||||
if (totalPCMFrameCount == 0) { \
|
||||
type buffer[4096]; \
|
||||
drflac_uint64 pcmFramesRead; \
|
||||
size_t sampleDataBufferSize = sizeof(buffer); \
|
||||
pSampleData = (type*)drflac__malloc_from_callbacks(sampleDataBufferSize, &pFlac->allocationCallbacks); \
|
||||
if (pSampleData == NULL) { \
|
||||
goto on_error; \
|
||||
} \
|
||||
\
|
||||
pSampleData = (type*)drflac__malloc_from_callbacks(sampleDataBufferSize, &pFlac->allocationCallbacks); \
|
||||
if (pSampleData == NULL) { \
|
||||
goto on_error; \
|
||||
} \
|
||||
while ((pcmFramesRead = (drflac_uint64)drflac_read_pcm_frames_##extension(pFlac, sizeof(buffer)/sizeof(buffer[0])/pFlac->channels, buffer)) > 0) { \
|
||||
if (((totalPCMFrameCount + pcmFramesRead) * pFlac->channels * sizeof(type)) > sampleDataBufferSize) { \
|
||||
type* pNewSampleData; \
|
||||
size_t newSampleDataBufferSize; \
|
||||
\
|
||||
while ((pcmFramesRead = (drflac_uint64)drflac_read_pcm_frames_##extension(pFlac, sizeof(buffer)/sizeof(buffer[0])/pFlac->channels, buffer)) > 0) { \
|
||||
if (((totalPCMFrameCount + pcmFramesRead) * pFlac->channels * sizeof(type)) > sampleDataBufferSize) { \
|
||||
type* pNewSampleData; \
|
||||
size_t newSampleDataBufferSize; \
|
||||
\
|
||||
newSampleDataBufferSize = sampleDataBufferSize * 2; \
|
||||
pNewSampleData = (type*)drflac__realloc_from_callbacks(pSampleData, newSampleDataBufferSize, sampleDataBufferSize, &pFlac->allocationCallbacks); \
|
||||
if (pNewSampleData == NULL) { \
|
||||
drflac__free_from_callbacks(pSampleData, &pFlac->allocationCallbacks); \
|
||||
goto on_error; \
|
||||
} \
|
||||
\
|
||||
sampleDataBufferSize = newSampleDataBufferSize; \
|
||||
pSampleData = pNewSampleData; \
|
||||
newSampleDataBufferSize = sampleDataBufferSize * 2; \
|
||||
pNewSampleData = (type*)drflac__realloc_from_callbacks(pSampleData, newSampleDataBufferSize, sampleDataBufferSize, &pFlac->allocationCallbacks); \
|
||||
if (pNewSampleData == NULL) { \
|
||||
drflac__free_from_callbacks(pSampleData, &pFlac->allocationCallbacks); \
|
||||
goto on_error; \
|
||||
} \
|
||||
\
|
||||
DRFLAC_COPY_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), buffer, (size_t)(pcmFramesRead*pFlac->channels*sizeof(type))); \
|
||||
totalPCMFrameCount += pcmFramesRead; \
|
||||
sampleDataBufferSize = newSampleDataBufferSize; \
|
||||
pSampleData = pNewSampleData; \
|
||||
} \
|
||||
\
|
||||
/* At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to \
|
||||
protect those ears from random noise! */ \
|
||||
DRFLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type))); \
|
||||
} else { \
|
||||
drflac_uint64 dataSize = totalPCMFrameCount*pFlac->channels*sizeof(type); \
|
||||
if (dataSize > (drflac_uint64)DRFLAC_SIZE_MAX) { \
|
||||
goto on_error; /* The decoded data is too big. */ \
|
||||
} \
|
||||
\
|
||||
pSampleData = (type*)drflac__malloc_from_callbacks((size_t)dataSize, &pFlac->allocationCallbacks); /* <-- Safe cast as per the check above. */ \
|
||||
if (pSampleData == NULL) { \
|
||||
goto on_error; \
|
||||
} \
|
||||
\
|
||||
totalPCMFrameCount = drflac_read_pcm_frames_##extension(pFlac, pFlac->totalPCMFrameCount, pSampleData); \
|
||||
DRFLAC_COPY_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), buffer, (size_t)(pcmFramesRead*pFlac->channels*sizeof(type))); \
|
||||
totalPCMFrameCount += pcmFramesRead; \
|
||||
} \
|
||||
\
|
||||
/* At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to \
|
||||
protect those ears from random noise! */ \
|
||||
DRFLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type))); \
|
||||
\
|
||||
if (sampleRateOut) *sampleRateOut = pFlac->sampleRate; \
|
||||
if (channelsOut) *channelsOut = pFlac->channels; \
|
||||
if (totalPCMFrameCountOut) *totalPCMFrameCountOut = totalPCMFrameCount; \
|
||||
|
|
@ -12077,7 +12203,23 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
|
|||
/*
|
||||
REVISION HISTORY
|
||||
================
|
||||
v0.13.0 - TBD
|
||||
v0.13.4 - TBD
|
||||
- Add a bounds check when allocating memory during metadata processing.
|
||||
- Fix a possible overflow error when parsing picture metadata.
|
||||
|
||||
v0.13.3 - 2026-01-17
|
||||
- Fix a compiler compatibility issue with some inlined assembly.
|
||||
- Fix a compilation warning.
|
||||
|
||||
v0.13.2 - 2025-12-02
|
||||
- Improve robustness of the parsing of picture metadata to improve support for memory constrained embedded devices.
|
||||
- Fix a warning about an assigned by unused variable.
|
||||
- Improvements to drflac_open_and_read_pcm_frames_*() and family to avoid excessively large memory allocations from malformed files.
|
||||
|
||||
v0.13.1 - 2025-09-10
|
||||
- Fix an error with the NXDK build.
|
||||
|
||||
v0.13.0 - 2025-07-23
|
||||
- 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
|
||||
|
|
|
|||
232
src/external/dr_mp3.h
vendored
232
src/external/dr_mp3.h
vendored
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
MP3 audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
|
||||
dr_mp3 - v0.7.0 - TBD
|
||||
dr_mp3 - v0.7.4 - TBD
|
||||
|
||||
David Reid - mackron@gmail.com
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ extern "C" {
|
|||
|
||||
#define DRMP3_VERSION_MAJOR 0
|
||||
#define DRMP3_VERSION_MINOR 7
|
||||
#define DRMP3_VERSION_REVISION 0
|
||||
#define DRMP3_VERSION_REVISION 4
|
||||
#define DRMP3_VERSION_STRING DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION)
|
||||
|
||||
#include <stddef.h> /* For size_t. */
|
||||
|
|
@ -257,16 +257,45 @@ typedef struct
|
|||
Low Level Push API
|
||||
==================
|
||||
*/
|
||||
#define DRMP3_MAX_BITRESERVOIR_BYTES 511
|
||||
#define DRMP3_MAX_FREE_FORMAT_FRAME_SIZE 2304 /* more than ISO spec's */
|
||||
#define DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES DRMP3_MAX_FREE_FORMAT_FRAME_SIZE /* MUST be >= 320000/8/32000*1152 = 1440 */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int frame_bytes, channels, sample_rate, layer, bitrate_kbps;
|
||||
} drmp3dec_frame_info;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const drmp3_uint8 *buf;
|
||||
int pos, limit;
|
||||
} drmp3_bs;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const drmp3_uint8 *sfbtab;
|
||||
drmp3_uint16 part_23_length, big_values, scalefac_compress;
|
||||
drmp3_uint8 global_gain, block_type, mixed_block_flag, n_long_sfb, n_short_sfb;
|
||||
drmp3_uint8 table_select[3], region_count[3], subblock_gain[3];
|
||||
drmp3_uint8 preflag, scalefac_scale, count1_table, scfsi;
|
||||
} drmp3_L3_gr_info;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
drmp3_bs bs;
|
||||
drmp3_uint8 maindata[DRMP3_MAX_BITRESERVOIR_BYTES + DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES];
|
||||
drmp3_L3_gr_info gr_info[4];
|
||||
float grbuf[2][576], scf[40], syn[18 + 15][2*32];
|
||||
drmp3_uint8 ist_pos[2][39];
|
||||
} drmp3dec_scratch;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float mdct_overlap[2][9*32], qmf_state[15*2*32];
|
||||
int reserv, free_format_bytes;
|
||||
drmp3_uint8 header[4], reserv_buf[511];
|
||||
drmp3dec_scratch scratch;
|
||||
} drmp3dec;
|
||||
|
||||
/* Initializes a low level decoder. */
|
||||
|
|
@ -592,14 +621,10 @@ DRMP3_API const char* drmp3_version_string(void)
|
|||
|
||||
#define DRMP3_OFFSET_PTR(p, offset) ((void*)((drmp3_uint8*)(p) + (offset)))
|
||||
|
||||
#define DRMP3_MAX_FREE_FORMAT_FRAME_SIZE 2304 /* more than ISO spec's */
|
||||
#ifndef DRMP3_MAX_FRAME_SYNC_MATCHES
|
||||
#define DRMP3_MAX_FRAME_SYNC_MATCHES 10
|
||||
#endif
|
||||
|
||||
#define DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES DRMP3_MAX_FREE_FORMAT_FRAME_SIZE /* MUST be >= 320000/8/32000*1152 = 1440 */
|
||||
|
||||
#define DRMP3_MAX_BITRESERVOIR_BYTES 511
|
||||
#define DRMP3_SHORT_BLOCK_TYPE 2
|
||||
#define DRMP3_STOP_BLOCK_TYPE 3
|
||||
#define DRMP3_MODE_MONO 3
|
||||
|
|
@ -632,8 +657,10 @@ DRMP3_API const char* drmp3_version_string(void)
|
|||
|
||||
#if !defined(DR_MP3_NO_SIMD)
|
||||
|
||||
#if !defined(DR_MP3_ONLY_SIMD) && (defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC))
|
||||
/* x64 always have SSE2, arm64 always have neon, no need for generic code */
|
||||
#if !defined(DR_MP3_ONLY_SIMD) && ((defined(_MSC_VER) && _MSC_VER >= 1400) && defined(_M_X64)) || ((defined(__i386) || defined(_M_IX86) || defined(__i386__) || defined(__x86_64__)) && ((defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__)))
|
||||
#define DR_MP3_ONLY_SIMD
|
||||
#endif
|
||||
#if !defined(DR_MP3_ONLY_SIMD) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC))
|
||||
#define DR_MP3_ONLY_SIMD
|
||||
#endif
|
||||
|
||||
|
|
@ -655,7 +682,7 @@ DRMP3_API const char* drmp3_version_string(void)
|
|||
#define DRMP3_VMUL_S(x, s) _mm_mul_ps(x, _mm_set1_ps(s))
|
||||
#define DRMP3_VREV(x) _mm_shuffle_ps(x, x, _MM_SHUFFLE(0, 1, 2, 3))
|
||||
typedef __m128 drmp3_f4;
|
||||
#if defined(_MSC_VER) || defined(DR_MP3_ONLY_SIMD)
|
||||
#if (defined(_MSC_VER) || defined(DR_MP3_ONLY_SIMD)) && !defined(__clang__)
|
||||
#define drmp3_cpuid __cpuid
|
||||
#else
|
||||
static __inline__ __attribute__((always_inline)) void drmp3_cpuid(int CPUInfo[], const int InfoType)
|
||||
|
|
@ -779,11 +806,7 @@ static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_ar
|
|||
#define DRMP3_FREE(p) free((p))
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const drmp3_uint8 *buf;
|
||||
int pos, limit;
|
||||
} drmp3_bs;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
|
@ -796,24 +819,6 @@ typedef struct
|
|||
drmp3_uint8 tab_offset, code_tab_width, band_count;
|
||||
} drmp3_L12_subband_alloc;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const drmp3_uint8 *sfbtab;
|
||||
drmp3_uint16 part_23_length, big_values, scalefac_compress;
|
||||
drmp3_uint8 global_gain, block_type, mixed_block_flag, n_long_sfb, n_short_sfb;
|
||||
drmp3_uint8 table_select[3], region_count[3], subblock_gain[3];
|
||||
drmp3_uint8 preflag, scalefac_scale, count1_table, scfsi;
|
||||
} drmp3_L3_gr_info;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
drmp3_bs bs;
|
||||
drmp3_uint8 maindata[DRMP3_MAX_BITRESERVOIR_BYTES + DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES];
|
||||
drmp3_L3_gr_info gr_info[4];
|
||||
float grbuf[2][576], scf[40], syn[18 + 15][2*32];
|
||||
drmp3_uint8 ist_pos[2][39];
|
||||
} drmp3dec_scratch;
|
||||
|
||||
static void drmp3_bs_init(drmp3_bs *bs, const drmp3_uint8 *data, int bytes)
|
||||
{
|
||||
bs->buf = data;
|
||||
|
|
@ -1227,6 +1232,14 @@ static float drmp3_L3_ldexp_q2(float y, int exp_q2)
|
|||
return y;
|
||||
}
|
||||
|
||||
/*
|
||||
I've had reports of GCC 14 throwing an incorrect -Wstringop-overflow warning here. This is an attempt
|
||||
to silence this warning.
|
||||
*/
|
||||
#if (defined(__GNUC__) && (__GNUC__ >= 13)) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstringop-overflow"
|
||||
#endif
|
||||
static void drmp3_L3_decode_scalefactors(const drmp3_uint8 *hdr, drmp3_uint8 *ist_pos, drmp3_bs *bs, const drmp3_L3_gr_info *gr, float *scf, int ch)
|
||||
{
|
||||
static const drmp3_uint8 g_scf_partitions[3][28] = {
|
||||
|
|
@ -1288,6 +1301,9 @@ static void drmp3_L3_decode_scalefactors(const drmp3_uint8 *hdr, drmp3_uint8 *is
|
|||
scf[i] = drmp3_L3_ldexp_q2(gain, iscf[i] << scf_shift);
|
||||
}
|
||||
}
|
||||
#if (defined(__GNUC__) && (__GNUC__ >= 13)) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
static const float g_drmp3_pow43[129 + 16] = {
|
||||
0,-1,-2.519842f,-4.326749f,-6.349604f,-8.549880f,-10.902724f,-13.390518f,-16.000000f,-18.720754f,-21.544347f,-24.463781f,-27.473142f,-30.567351f,-33.741992f,-36.993181f,
|
||||
|
|
@ -2299,7 +2315,6 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m
|
|||
int i = 0, igr, frame_size = 0, success = 1;
|
||||
const drmp3_uint8 *hdr;
|
||||
drmp3_bs bs_frame[1];
|
||||
drmp3dec_scratch scratch;
|
||||
|
||||
if (mp3_bytes > 4 && dec->header[0] == 0xff && drmp3_hdr_compare(dec->header, mp3))
|
||||
{
|
||||
|
|
@ -2336,23 +2351,23 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m
|
|||
|
||||
if (info->layer == 3)
|
||||
{
|
||||
int main_data_begin = drmp3_L3_read_side_info(bs_frame, scratch.gr_info, hdr);
|
||||
int main_data_begin = drmp3_L3_read_side_info(bs_frame, dec->scratch.gr_info, hdr);
|
||||
if (main_data_begin < 0 || bs_frame->pos > bs_frame->limit)
|
||||
{
|
||||
drmp3dec_init(dec);
|
||||
return 0;
|
||||
}
|
||||
success = drmp3_L3_restore_reservoir(dec, bs_frame, &scratch, main_data_begin);
|
||||
success = drmp3_L3_restore_reservoir(dec, bs_frame, &dec->scratch, main_data_begin);
|
||||
if (success && pcm != NULL)
|
||||
{
|
||||
for (igr = 0; igr < (DRMP3_HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*576*info->channels))
|
||||
{
|
||||
DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float));
|
||||
drmp3_L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels);
|
||||
drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]);
|
||||
DRMP3_ZERO_MEMORY(dec->scratch.grbuf[0], 576*2*sizeof(float));
|
||||
drmp3_L3_decode(dec, &dec->scratch, dec->scratch.gr_info + igr*info->channels, info->channels);
|
||||
drmp3d_synth_granule(dec->qmf_state, dec->scratch.grbuf[0], 18, info->channels, (drmp3d_sample_t*)pcm, dec->scratch.syn[0]);
|
||||
}
|
||||
}
|
||||
drmp3_L3_save_reservoir(dec, &scratch);
|
||||
drmp3_L3_save_reservoir(dec, &dec->scratch);
|
||||
} else
|
||||
{
|
||||
#ifdef DR_MP3_ONLY_MP3
|
||||
|
|
@ -2366,15 +2381,15 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m
|
|||
|
||||
drmp3_L12_read_scale_info(hdr, bs_frame, sci);
|
||||
|
||||
DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float));
|
||||
DRMP3_ZERO_MEMORY(dec->scratch.grbuf[0], 576*2*sizeof(float));
|
||||
for (i = 0, igr = 0; igr < 3; igr++)
|
||||
{
|
||||
if (12 == (i += drmp3_L12_dequantize_granule(scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1)))
|
||||
if (12 == (i += drmp3_L12_dequantize_granule(dec->scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1)))
|
||||
{
|
||||
i = 0;
|
||||
drmp3_L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]);
|
||||
drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]);
|
||||
DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float));
|
||||
drmp3_L12_apply_scf_384(sci, sci->scf + igr, dec->scratch.grbuf[0]);
|
||||
drmp3d_synth_granule(dec->qmf_state, dec->scratch.grbuf[0], 12, info->channels, (drmp3d_sample_t*)pcm, dec->scratch.syn[0]);
|
||||
DRMP3_ZERO_MEMORY(dec->scratch.grbuf[0], 576*2*sizeof(float));
|
||||
pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*384*info->channels);
|
||||
}
|
||||
if (bs_frame->pos > bs_frame->limit)
|
||||
|
|
@ -3005,23 +3020,27 @@ static drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drm
|
|||
((drmp3_uint32)ape[26] << 16) |
|
||||
((drmp3_uint32)ape[27] << 24);
|
||||
|
||||
streamEndOffset -= 32 + tagSize;
|
||||
streamLen -= 32 + tagSize;
|
||||
|
||||
/* Fire a metadata callback for the APE data. Must include both the main content and footer. */
|
||||
if (onMeta != NULL) {
|
||||
/* We first need to seek to the start of the APE tag. */
|
||||
if (onSeek(pUserData, streamEndOffset, DRMP3_SEEK_END)) {
|
||||
size_t apeTagSize = (size_t)tagSize + 32;
|
||||
drmp3_uint8* pTagData = (drmp3_uint8*)drmp3_malloc(apeTagSize, pAllocationCallbacks);
|
||||
if (pTagData != NULL) {
|
||||
if (onRead(pUserData, pTagData, apeTagSize) == apeTagSize) {
|
||||
drmp3__on_meta(pMP3, DRMP3_METADATA_TYPE_APE, pTagData, apeTagSize);
|
||||
}
|
||||
if (32 + tagSize < streamLen) {
|
||||
streamEndOffset -= 32 + tagSize;
|
||||
streamLen -= 32 + tagSize;
|
||||
|
||||
/* Fire a metadata callback for the APE data. Must include both the main content and footer. */
|
||||
if (onMeta != NULL) {
|
||||
/* We first need to seek to the start of the APE tag. */
|
||||
if (onSeek(pUserData, streamEndOffset, DRMP3_SEEK_END)) {
|
||||
size_t apeTagSize = (size_t)tagSize + 32;
|
||||
drmp3_uint8* pTagData = (drmp3_uint8*)drmp3_malloc(apeTagSize, pAllocationCallbacks);
|
||||
if (pTagData != NULL) {
|
||||
if (onRead(pUserData, pTagData, apeTagSize) == apeTagSize) {
|
||||
drmp3__on_meta(pMP3, DRMP3_METADATA_TYPE_APE, pTagData, apeTagSize);
|
||||
}
|
||||
|
||||
drmp3_free(pTagData, pAllocationCallbacks);
|
||||
drmp3_free(pTagData, pAllocationCallbacks);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* The tag size is larger than the stream. Invalid APE tag. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3153,7 +3172,6 @@ static drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drm
|
|||
{
|
||||
drmp3_bs bs;
|
||||
drmp3_L3_gr_info grInfo[4];
|
||||
const drmp3_uint8* pTagData = pFirstFrameData;
|
||||
|
||||
drmp3_bs_init(&bs, pFirstFrameData + DRMP3_HDR_SIZE, firstFrameInfo.frame_bytes - DRMP3_HDR_SIZE);
|
||||
|
||||
|
|
@ -3164,11 +3182,16 @@ static drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drm
|
|||
if (drmp3_L3_read_side_info(&bs, grInfo, pFirstFrameData) >= 0) {
|
||||
drmp3_bool32 isXing = DRMP3_FALSE;
|
||||
drmp3_bool32 isInfo = DRMP3_FALSE;
|
||||
const drmp3_uint8* pTagData;
|
||||
const drmp3_uint8* pTagDataBeg;
|
||||
|
||||
pTagDataBeg = pFirstFrameData + DRMP3_HDR_SIZE + (bs.pos/8);
|
||||
pTagData = pTagDataBeg;
|
||||
|
||||
if (firstFrameInfo.frame_bytes - (size_t)(pTagData - pFirstFrameData) < 8) {
|
||||
goto done_xing_info; /* Frame too small for a Xing/Info tag. */
|
||||
}
|
||||
|
||||
/* Check for both "Xing" and "Info" identifiers. */
|
||||
isXing = (pTagData[0] == 'X' && pTagData[1] == 'i' && pTagData[2] == 'n' && pTagData[3] == 'g');
|
||||
isInfo = (pTagData[0] == 'I' && pTagData[1] == 'n' && pTagData[2] == 'f' && pTagData[3] == 'o');
|
||||
|
|
@ -3180,42 +3203,60 @@ static drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drm
|
|||
pTagData += 8; /* Skip past the ID and flags. */
|
||||
|
||||
if (flags & 0x01) { /* FRAMES flag. */
|
||||
if (firstFrameInfo.frame_bytes - (size_t)(pTagData - pFirstFrameData) < 4) {
|
||||
goto done_xing_info; /* Invalid Xing/Info tag. */
|
||||
}
|
||||
|
||||
detectedMP3FrameCount = (drmp3_uint32)pTagData[0] << 24 | (drmp3_uint32)pTagData[1] << 16 | (drmp3_uint32)pTagData[2] << 8 | (drmp3_uint32)pTagData[3];
|
||||
pTagData += 4;
|
||||
}
|
||||
|
||||
if (flags & 0x02) { /* BYTES flag. */
|
||||
if (firstFrameInfo.frame_bytes - (size_t)(pTagData - pFirstFrameData) < 4) {
|
||||
goto done_xing_info; /* Invalid Xing/Info tag. */
|
||||
}
|
||||
|
||||
bytes = (drmp3_uint32)pTagData[0] << 24 | (drmp3_uint32)pTagData[1] << 16 | (drmp3_uint32)pTagData[2] << 8 | (drmp3_uint32)pTagData[3];
|
||||
(void)bytes; /* <-- Just to silence a warning about `bytes` being assigned but unused. Want to leave this here in case I want to make use of it later. */
|
||||
pTagData += 4;
|
||||
}
|
||||
|
||||
if (flags & 0x04) { /* TOC flag. */
|
||||
if (firstFrameInfo.frame_bytes - (size_t)(pTagData - pFirstFrameData) < 100) {
|
||||
goto done_xing_info; /* Invalid Xing/Info tag. */
|
||||
}
|
||||
|
||||
/* TODO: Extract and bind seek points. */
|
||||
pTagData += 100;
|
||||
}
|
||||
|
||||
if (flags & 0x08) { /* SCALE flag. */
|
||||
if (firstFrameInfo.frame_bytes - (size_t)(pTagData - pFirstFrameData) < 4) {
|
||||
goto done_xing_info; /* Invalid Xing/Info tag. */
|
||||
}
|
||||
|
||||
pTagData += 4;
|
||||
}
|
||||
|
||||
/* At this point we're done with the Xing/Info header. Now we can look at the LAME data. */
|
||||
if (pTagData[0]) {
|
||||
int delayInPCMFrames;
|
||||
int paddingInPCMFrames;
|
||||
|
||||
if (firstFrameInfo.frame_bytes - (size_t)(pTagData - pFirstFrameData) < 36) {
|
||||
goto done_xing_info; /* Invalid Xing/Info tag. */
|
||||
}
|
||||
|
||||
pTagData += 21;
|
||||
|
||||
if (pTagData - pFirstFrameData + 14 < firstFrameInfo.frame_bytes) {
|
||||
int delayInPCMFrames;
|
||||
int paddingInPCMFrames;
|
||||
|
||||
delayInPCMFrames = (( (drmp3_uint32)pTagData[0] << 4) | ((drmp3_uint32)pTagData[1] >> 4)) + (528 + 1);
|
||||
paddingInPCMFrames = ((((drmp3_uint32)pTagData[1] & 0xF) << 8) | ((drmp3_uint32)pTagData[2] )) - (528 + 1);
|
||||
if (paddingInPCMFrames < 0) {
|
||||
paddingInPCMFrames = 0; /* Padding cannot be negative. Probably a malformed file. Ignore. */
|
||||
}
|
||||
|
||||
pMP3->delayInPCMFrames = (drmp3_uint32)delayInPCMFrames;
|
||||
pMP3->paddingInPCMFrames = (drmp3_uint32)paddingInPCMFrames;
|
||||
delayInPCMFrames = (( (drmp3_uint32)pTagData[0] << 4) | ((drmp3_uint32)pTagData[1] >> 4)) + (528 + 1);
|
||||
paddingInPCMFrames = ((((drmp3_uint32)pTagData[1] & 0xF) << 8) | ((drmp3_uint32)pTagData[2] )) - (528 + 1);
|
||||
if (paddingInPCMFrames < 0) {
|
||||
paddingInPCMFrames = 0; /* Padding cannot be negative. Probably a malformed file. Ignore. */
|
||||
}
|
||||
|
||||
pMP3->delayInPCMFrames = (drmp3_uint32)delayInPCMFrames;
|
||||
pMP3->paddingInPCMFrames = (drmp3_uint32)paddingInPCMFrames;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3246,7 +3287,16 @@ static drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drm
|
|||
/* The start offset needs to be moved to the end of this frame so it's not included in any audio processing after seeking. */
|
||||
pMP3->streamStartOffset += (drmp3_uint32)(firstFrameInfo.frame_bytes);
|
||||
pMP3->streamCursor = pMP3->streamStartOffset;
|
||||
|
||||
/*
|
||||
The internal decoder needs to be reset to clear out any state. If we don't reset this state, it's possible for
|
||||
there to be inconsistencies in the number of samples read when reading to the end of the stream depending on
|
||||
whether or not the caller seeks to the start of the stream.
|
||||
*/
|
||||
drmp3dec_init(&pMP3->decoder);
|
||||
}
|
||||
|
||||
done_xing_info:;
|
||||
} else {
|
||||
/* Failed to read the side info. */
|
||||
}
|
||||
|
|
@ -3259,7 +3309,7 @@ static drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drm
|
|||
}
|
||||
|
||||
if (detectedMP3FrameCount != 0xFFFFFFFF) {
|
||||
pMP3->totalPCMFrameCount = detectedMP3FrameCount * firstFramePCMFrameCount;
|
||||
pMP3->totalPCMFrameCount = (drmp3_uint64)detectedMP3FrameCount * firstFramePCMFrameCount;
|
||||
}
|
||||
|
||||
pMP3->channels = pMP3->mp3FrameChannels;
|
||||
|
|
@ -3307,8 +3357,6 @@ static drmp3_bool32 drmp3__on_seek_memory(void* pUserData, int byteOffset, drmp3
|
|||
|
||||
DRMP3_ASSERT(pMP3 != NULL);
|
||||
|
||||
newCursor = pMP3->memory.currentReadPos;
|
||||
|
||||
if (origin == DRMP3_SEEK_SET) {
|
||||
newCursor = 0;
|
||||
} else if (origin == DRMP3_SEEK_CUR) {
|
||||
|
|
@ -3981,7 +4029,7 @@ static drmp3_bool32 drmp3__on_tell_stdio(void* pUserData, drmp3_int64* pCursor)
|
|||
DRMP3_ASSERT(pFileStdio != NULL);
|
||||
DRMP3_ASSERT(pCursor != NULL);
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if defined(_WIN32) && !defined(NXDK)
|
||||
#if defined(_MSC_VER) && _MSC_VER > 1200
|
||||
result = _ftelli64(pFileStdio);
|
||||
#else
|
||||
|
|
@ -4223,7 +4271,7 @@ DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_f32(drmp3* pMP3, drmp3_uint64 frame
|
|||
#else
|
||||
/* Slow path. Convert from s16 to f32. */
|
||||
{
|
||||
drmp3_int16 pTempS16[8192];
|
||||
drmp3_int16 pTempS16[1152*2]; /* MP3 frames have a maximum per-channel sample count of 1152. Times 2 to account for stereo. */
|
||||
drmp3_uint64 totalPCMFramesRead = 0;
|
||||
|
||||
while (totalPCMFramesRead < framesToRead) {
|
||||
|
|
@ -4260,7 +4308,7 @@ DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_s16(drmp3* pMP3, drmp3_uint64 frame
|
|||
#else
|
||||
/* Slow path. Convert from f32 to s16. */
|
||||
{
|
||||
float pTempF32[4096];
|
||||
float pTempF32[1152*2]; /* MP3 frames have a maximum per-channel sample count of 1152. Times 2 to account for stereo. */
|
||||
drmp3_uint64 totalPCMFramesRead = 0;
|
||||
|
||||
while (totalPCMFramesRead < framesToRead) {
|
||||
|
|
@ -4748,7 +4796,7 @@ static float* drmp3__full_read_and_close_f32(drmp3* pMP3, drmp3_config* pConfig,
|
|||
drmp3_uint64 totalFramesRead = 0;
|
||||
drmp3_uint64 framesCapacity = 0;
|
||||
float* pFrames = NULL;
|
||||
float temp[4096];
|
||||
float temp[1152*2]; /* MP3 frames have a maximum per-channel sample count of 1152. Times 2 to account for stereo. */
|
||||
|
||||
DRMP3_ASSERT(pMP3 != NULL);
|
||||
|
||||
|
|
@ -4780,6 +4828,8 @@ static float* drmp3__full_read_and_close_f32(drmp3* pMP3, drmp3_config* pConfig,
|
|||
pNewFrames = (float*)drmp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks);
|
||||
if (pNewFrames == NULL) {
|
||||
drmp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks);
|
||||
pFrames = NULL;
|
||||
totalFramesRead = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -4815,7 +4865,7 @@ static drmp3_int16* drmp3__full_read_and_close_s16(drmp3* pMP3, drmp3_config* pC
|
|||
drmp3_uint64 totalFramesRead = 0;
|
||||
drmp3_uint64 framesCapacity = 0;
|
||||
drmp3_int16* pFrames = NULL;
|
||||
drmp3_int16 temp[4096];
|
||||
drmp3_int16 temp[1152*2]; /* MP3 frames have a maximum per-channel sample count of 1152. Times 2 to account for stereo. */
|
||||
|
||||
DRMP3_ASSERT(pMP3 != NULL);
|
||||
|
||||
|
|
@ -4847,6 +4897,8 @@ static drmp3_int16* drmp3__full_read_and_close_s16(drmp3* pMP3, drmp3_config* pC
|
|||
pNewFrames = (drmp3_int16*)drmp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks);
|
||||
if (pNewFrames == NULL) {
|
||||
drmp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks);
|
||||
pFrames = NULL;
|
||||
totalFramesRead = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -4981,7 +5033,27 @@ DIFFERENCES BETWEEN minimp3 AND dr_mp3
|
|||
/*
|
||||
REVISION HISTORY
|
||||
================
|
||||
v0.7.0 - TBD
|
||||
v0.7.4 - TBD
|
||||
- Fix an overflow error with "Xing" and "Info" tag parsing.
|
||||
- Add some validation checks for "Xing" and "Info" tag parsing.
|
||||
- Reduce size of some stack allocations.
|
||||
- Improvements to SIMD detection.
|
||||
|
||||
v0.7.3 - 2026-01-17
|
||||
- Fix an error in drmp3_open_and_read_pcm_frames_s16() and family when memory allocation fails.
|
||||
- Fix some compilation warnings.
|
||||
|
||||
v0.7.2 - 2025-12-02
|
||||
- Reduce stack space to improve robustness on embedded systems.
|
||||
- Fix a compilation error with MSVC Clang toolset relating to cpuid.
|
||||
- Fix an error with APE tag parsing.
|
||||
|
||||
v0.7.1 - 2025-09-10
|
||||
- Silence a warning with GCC.
|
||||
- Fix an error with the NXDK build.
|
||||
- Fix a decoding inconsistency when seeking. Prior to this change, reading to the end of the stream immediately after initializing will result in a different number of samples read than if the stream is seeked to the start and read to the end.
|
||||
|
||||
v0.7.0 - 2025-07-23
|
||||
- The old `DRMP3_IMPLEMENTATION` has been removed. Use `DR_MP3_IMPLEMENTATION` instead. The reason for this change is that in the future everything will eventually be using the underscored naming convention in the future, so `drmp3` will become `dr_mp3`.
|
||||
- API CHANGE: Seek origins have been renamed to match the naming convention used by dr_wav and my other libraries.
|
||||
- drmp3_seek_origin_start -> DRMP3_SEEK_SET
|
||||
|
|
|
|||
190
src/external/dr_wav.h
vendored
190
src/external/dr_wav.h
vendored
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file.
|
||||
dr_wav - v0.14.0 - TBD
|
||||
dr_wav - v0.14.6 - TBD
|
||||
|
||||
David Reid - mackron@gmail.com
|
||||
|
||||
|
|
@ -147,7 +147,7 @@ extern "C" {
|
|||
|
||||
#define DRWAV_VERSION_MAJOR 0
|
||||
#define DRWAV_VERSION_MINOR 14
|
||||
#define DRWAV_VERSION_REVISION 0
|
||||
#define DRWAV_VERSION_REVISION 6
|
||||
#define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION)
|
||||
|
||||
#include <stddef.h> /* For size_t. */
|
||||
|
|
@ -1971,7 +1971,15 @@ DRWAV_PRIVATE drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void
|
|||
return DRWAV_INVALID_FILE;
|
||||
}
|
||||
|
||||
pHeaderOut->sizeInBytes = drwav_bytes_to_u64(sizeInBytes) - 24; /* <-- Subtract 24 because w64 includes the size of the header. */
|
||||
pHeaderOut->sizeInBytes = drwav_bytes_to_u64(sizeInBytes);
|
||||
|
||||
/* Subtract 24 from the size because with w64 the reported chunk size includes the size of the header itself. */
|
||||
if (pHeaderOut->sizeInBytes >= 24) {
|
||||
pHeaderOut->sizeInBytes -= 24;
|
||||
} else {
|
||||
return DRWAV_INVALID_FILE;
|
||||
}
|
||||
|
||||
pHeaderOut->paddingSize = drwav__chunk_padding_size_w64(pHeaderOut->sizeInBytes);
|
||||
*pRunningBytesReadOut += 24;
|
||||
} else {
|
||||
|
|
@ -2189,6 +2197,22 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_pars
|
|||
|
||||
if (pMetadata != NULL && bytesJustRead == sizeof(smplHeaderData)) {
|
||||
drwav_uint32 iSampleLoop;
|
||||
drwav_uint32 loopCount;
|
||||
drwav_uint32 calculatedLoopCount;
|
||||
|
||||
/*
|
||||
When we calcualted the amount of memory required for the "smpl" chunk we excluded the chunk entirely
|
||||
if the loop count in the header did not match with the calculated count based on the size of the
|
||||
chunk. When this happens, the second stage will still hit this path but the `pMetadata` will be
|
||||
non-null, but will either be pointing at the very end of the allocation or at the start of another
|
||||
chunk. We need to check the loop counts for consistency *before* dereferencing the pMetadata object
|
||||
so it's consistent with how we do it in the first stage.
|
||||
*/
|
||||
loopCount = drwav_bytes_to_u32(smplHeaderData + 28);
|
||||
calculatedLoopCount = (drwav_uint32)((pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES);
|
||||
if (loopCount != calculatedLoopCount) {
|
||||
return totalBytesRead;
|
||||
}
|
||||
|
||||
pMetadata->type = drwav_metadata_type_smpl;
|
||||
pMetadata->data.smpl.manufacturerId = drwav_bytes_to_u32(smplHeaderData + 0);
|
||||
|
|
@ -2205,7 +2229,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_pars
|
|||
The loop count needs to be validated against the size of the chunk for safety so we don't
|
||||
attempt to read over the boundary of the chunk.
|
||||
*/
|
||||
if (pMetadata->data.smpl.sampleLoopCount == (pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES) {
|
||||
if (pMetadata->data.smpl.sampleLoopCount == calculatedLoopCount) {
|
||||
pMetadata->data.smpl.pLoops = (drwav_smpl_loop*)drwav__metadata_get_memory(pParser, sizeof(drwav_smpl_loop) * pMetadata->data.smpl.sampleLoopCount, DRWAV_METADATA_ALIGNMENT);
|
||||
|
||||
for (iSampleLoop = 0; iSampleLoop < pMetadata->data.smpl.sampleLoopCount; ++iSampleLoop) {
|
||||
|
|
@ -2230,6 +2254,15 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_pars
|
|||
|
||||
drwav__metadata_parser_read(pParser, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, &totalBytesRead);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
Getting here means the loop count in the header does not match up with the size of the
|
||||
chunk. Clear out the data to zero just to be safe.
|
||||
|
||||
This should never actually get hit because we check for it above, but keeping this here
|
||||
for added safety.
|
||||
*/
|
||||
DRWAV_ZERO_OBJECT(&pMetadata->data.smpl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2555,8 +2588,10 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_bext_to_metadata_obj(drwav__metadata_pars
|
|||
pMetadata->data.bext.pCodingHistory = (char*)drwav__metadata_get_memory(pParser, extraBytes + 1, 1);
|
||||
DRWAV_ASSERT(pMetadata->data.bext.pCodingHistory != NULL);
|
||||
|
||||
bytesRead += drwav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL);
|
||||
pMetadata->data.bext.codingHistorySize = (drwav_uint32)drwav__strlen(pMetadata->data.bext.pCodingHistory);
|
||||
pMetadata->data.bext.codingHistorySize = (drwav_uint32)drwav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL);
|
||||
pMetadata->data.bext.pCodingHistory[pMetadata->data.bext.codingHistorySize] = '\0'; /* <-- Explicit null terminator in case of a badly formed file. */
|
||||
|
||||
bytesRead += pMetadata->data.bext.codingHistorySize;
|
||||
} else {
|
||||
pMetadata->data.bext.pCodingHistory = NULL;
|
||||
pMetadata->data.bext.codingHistorySize = 0;
|
||||
|
|
@ -2730,10 +2765,10 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser*
|
|||
bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead);
|
||||
if (bytesJustRead == sizeof(buffer)) {
|
||||
drwav_uint32 loopCount = drwav_bytes_to_u32(buffer);
|
||||
drwav_uint64 calculatedLoopCount;
|
||||
drwav_uint32 calculatedLoopCount;
|
||||
|
||||
/* The loop count must be validated against the size of the chunk. */
|
||||
calculatedLoopCount = (pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES;
|
||||
calculatedLoopCount = (drwav_uint32)((pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES);
|
||||
if (calculatedLoopCount == loopCount) {
|
||||
bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead);
|
||||
if (bytesJustRead == sizeof(buffer)) {
|
||||
|
|
@ -2835,7 +2870,9 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser*
|
|||
return bytesRead;
|
||||
}
|
||||
allocSizeNeeded += drwav__strlen(buffer) + 1;
|
||||
allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - DRWAV_BEXT_BYTES + 1; /* Coding history. */
|
||||
|
||||
/* Coding history. */
|
||||
allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - DRWAV_BEXT_BYTES + 1;
|
||||
|
||||
drwav__metadata_request_extra_memory_for_stage_2(pParser, allocSizeNeeded, 1);
|
||||
|
||||
|
|
@ -3296,6 +3333,10 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
|||
((pWav->container == drwav_container_w64) && drwav_guid_equal(header.id.guid, drwavGUID_W64_FMT))) {
|
||||
drwav_uint8 fmtData[16];
|
||||
|
||||
if (header.sizeInBytes < sizeof(fmtData)) {
|
||||
return DRWAV_FALSE; /* Invalid fmt chunk. */
|
||||
}
|
||||
|
||||
foundChunk_fmt = DRWAV_TRUE;
|
||||
|
||||
if (pWav->onRead(pWav->pUserData, fmtData, sizeof(fmtData)) != sizeof(fmtData)) {
|
||||
|
|
@ -3605,7 +3646,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
|||
we'll need to abort because we can't be doing a backwards seek back to the SSND chunk in order to read the
|
||||
data. For this reason, this configuration of AIFF files are not supported with sequential mode.
|
||||
*/
|
||||
return DRWAV_FALSE;
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
} else {
|
||||
chunkSize += header.paddingSize; /* <-- Make sure we seek past the padding. */
|
||||
|
|
@ -3808,6 +3849,11 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
|||
|
||||
/* We decode two samples per byte. There will be blockCount headers in the data chunk. This is enough to know how to calculate the total PCM frame count. */
|
||||
totalBlockHeaderSizeInBytes = blockCount * (6*fmt.channels);
|
||||
if (totalBlockHeaderSizeInBytes >= dataChunkSize) { /* <-- We'll be subtracting totalBlockHeaderSizeInBytes from dataChunkSize next so it must be validated. */
|
||||
drwav_free(pWav->pMetadata, &pWav->allocationCallbacks);
|
||||
return DRWAV_FALSE; /* Invalid file. */
|
||||
}
|
||||
|
||||
pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
|
||||
}
|
||||
if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
|
||||
|
|
@ -3821,6 +3867,11 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
|||
|
||||
/* We decode two samples per byte. There will be blockCount headers in the data chunk. This is enough to know how to calculate the total PCM frame count. */
|
||||
totalBlockHeaderSizeInBytes = blockCount * (4*fmt.channels);
|
||||
if (totalBlockHeaderSizeInBytes >= dataChunkSize) { /* <-- We'll be subtracting totalBlockHeaderSizeInBytes from dataChunkSize next so it must be validated. */
|
||||
drwav_free(pWav->pMetadata, &pWav->allocationCallbacks);
|
||||
return DRWAV_FALSE; /* Invalid file. */
|
||||
}
|
||||
|
||||
pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
|
||||
|
||||
/* The header includes a decoded sample for each channel which acts as the initial predictor sample. */
|
||||
|
|
@ -5285,7 +5336,7 @@ DRWAV_PRIVATE drwav_bool32 drwav__on_tell_stdio(void* pUserData, drwav_int64* pC
|
|||
DRWAV_ASSERT(pFileStdio != NULL);
|
||||
DRWAV_ASSERT(pCursor != NULL);
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if defined(_WIN32) && !defined(NXDK)
|
||||
#if defined(_MSC_VER) && _MSC_VER > 1200
|
||||
result = _ftelli64(pFileStdio);
|
||||
#else
|
||||
|
|
@ -5492,8 +5543,6 @@ DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, dr
|
|||
|
||||
DRWAV_ASSERT(pWav != NULL);
|
||||
|
||||
newCursor = pWav->memoryStream.currentReadPos;
|
||||
|
||||
if (origin == DRWAV_SEEK_SET) {
|
||||
newCursor = 0;
|
||||
} else if (origin == DRWAV_SEEK_CUR) {
|
||||
|
|
@ -5566,8 +5615,6 @@ DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offs
|
|||
|
||||
DRWAV_ASSERT(pWav != NULL);
|
||||
|
||||
newCursor = pWav->memoryStreamWrite.currentWritePos;
|
||||
|
||||
if (origin == DRWAV_SEEK_SET) {
|
||||
newCursor = 0;
|
||||
} else if (origin == DRWAV_SEEK_CUR) {
|
||||
|
|
@ -5576,7 +5623,7 @@ DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offs
|
|||
newCursor = (drwav_int64)pWav->memoryStreamWrite.dataSize;
|
||||
} else {
|
||||
DRWAV_ASSERT(!"Invalid seek origin");
|
||||
return DRWAV_INVALID_ARGS;
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
|
||||
newCursor += offset;
|
||||
|
|
@ -6258,12 +6305,12 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav
|
|||
{
|
||||
drwav_uint64 totalFramesRead = 0;
|
||||
|
||||
static drwav_int32 adaptationTable[] = {
|
||||
static const drwav_int32 adaptationTable[] = {
|
||||
230, 230, 230, 230, 307, 409, 512, 614,
|
||||
768, 614, 512, 409, 307, 230, 230, 230
|
||||
};
|
||||
static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 };
|
||||
static drwav_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 };
|
||||
static const drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 };
|
||||
static const drwav_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 };
|
||||
|
||||
DRWAV_ASSERT(pWav != NULL);
|
||||
DRWAV_ASSERT(framesToRead > 0);
|
||||
|
|
@ -6292,7 +6339,7 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav
|
|||
pWav->msadpcm.cachedFrameCount = 2;
|
||||
|
||||
/* The predictor is used as an index into coeff1Table so we'll need to validate to ensure it never overflows. */
|
||||
if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table)) {
|
||||
if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[0] >= drwav_countof(coeff2Table)) {
|
||||
return totalFramesRead; /* Invalid file. */
|
||||
}
|
||||
} else {
|
||||
|
|
@ -6319,7 +6366,8 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav
|
|||
pWav->msadpcm.cachedFrameCount = 2;
|
||||
|
||||
/* The predictor is used as an index into coeff1Table so we'll need to validate to ensure it never overflows. */
|
||||
if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[1] >= drwav_countof(coeff2Table)) {
|
||||
if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[0] >= drwav_countof(coeff2Table) ||
|
||||
pWav->msadpcm.predictor[1] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[1] >= drwav_countof(coeff2Table)) {
|
||||
return totalFramesRead; /* Invalid file. */
|
||||
}
|
||||
}
|
||||
|
|
@ -6373,15 +6421,17 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav
|
|||
drwav_int32 newSample0;
|
||||
drwav_int32 newSample1;
|
||||
|
||||
/* The predictor is read from the file and then indexed into a table. Check that it's in bounds. */
|
||||
if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[0] >= drwav_countof(coeff2Table)) {
|
||||
return totalFramesRead;
|
||||
}
|
||||
|
||||
newSample0 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
|
||||
newSample0 += nibble0 * pWav->msadpcm.delta[0];
|
||||
newSample0 = drwav_clamp(newSample0, -32768, 32767);
|
||||
|
||||
pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8;
|
||||
if (pWav->msadpcm.delta[0] < 16) {
|
||||
pWav->msadpcm.delta[0] = 16;
|
||||
}
|
||||
|
||||
pWav->msadpcm.delta[0] = (drwav_int32)drwav_clamp(((drwav_int64)adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8, 16, 0x7FFFFFFF);
|
||||
|
||||
pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
|
||||
pWav->msadpcm.prevFrames[0][1] = newSample0;
|
||||
|
||||
|
|
@ -6390,15 +6440,11 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav
|
|||
newSample1 += nibble1 * pWav->msadpcm.delta[0];
|
||||
newSample1 = drwav_clamp(newSample1, -32768, 32767);
|
||||
|
||||
pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[0]) >> 8;
|
||||
if (pWav->msadpcm.delta[0] < 16) {
|
||||
pWav->msadpcm.delta[0] = 16;
|
||||
}
|
||||
pWav->msadpcm.delta[0] = (drwav_int32)drwav_clamp(((drwav_int64)adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[0]) >> 8, 16, 0x7FFFFFFF);
|
||||
|
||||
pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
|
||||
pWav->msadpcm.prevFrames[0][1] = newSample1;
|
||||
|
||||
|
||||
pWav->msadpcm.cachedFrames[2] = newSample0;
|
||||
pWav->msadpcm.cachedFrames[3] = newSample1;
|
||||
pWav->msadpcm.cachedFrameCount = 2;
|
||||
|
|
@ -6408,28 +6454,30 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav
|
|||
drwav_int32 newSample1;
|
||||
|
||||
/* Left. */
|
||||
if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[0] >= drwav_countof(coeff2Table)) {
|
||||
return totalFramesRead; /* Out of bounds. Invalid file. */
|
||||
}
|
||||
|
||||
newSample0 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
|
||||
newSample0 += nibble0 * pWav->msadpcm.delta[0];
|
||||
newSample0 = drwav_clamp(newSample0, -32768, 32767);
|
||||
|
||||
pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8;
|
||||
if (pWav->msadpcm.delta[0] < 16) {
|
||||
pWav->msadpcm.delta[0] = 16;
|
||||
}
|
||||
pWav->msadpcm.delta[0] = (drwav_int32)drwav_clamp(((drwav_int64)adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8, 16, 0x7FFFFFFF);
|
||||
|
||||
pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
|
||||
pWav->msadpcm.prevFrames[0][1] = newSample0;
|
||||
|
||||
|
||||
/* Right. */
|
||||
if (pWav->msadpcm.predictor[1] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[1] >= drwav_countof(coeff2Table)) {
|
||||
return totalFramesRead; /* Out of bounds. Invalid file. */
|
||||
}
|
||||
|
||||
newSample1 = ((pWav->msadpcm.prevFrames[1][1] * coeff1Table[pWav->msadpcm.predictor[1]]) + (pWav->msadpcm.prevFrames[1][0] * coeff2Table[pWav->msadpcm.predictor[1]])) >> 8;
|
||||
newSample1 += nibble1 * pWav->msadpcm.delta[1];
|
||||
newSample1 = drwav_clamp(newSample1, -32768, 32767);
|
||||
|
||||
pWav->msadpcm.delta[1] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[1]) >> 8;
|
||||
if (pWav->msadpcm.delta[1] < 16) {
|
||||
pWav->msadpcm.delta[1] = 16;
|
||||
}
|
||||
pWav->msadpcm.delta[1] = (drwav_int32)drwav_clamp(((drwav_int64)adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[1]) >> 8, 16, 0x7FFFFFFF);
|
||||
|
||||
pWav->msadpcm.prevFrames[1][0] = pWav->msadpcm.prevFrames[1][1];
|
||||
pWav->msadpcm.prevFrames[1][1] = newSample1;
|
||||
|
|
@ -6451,12 +6499,12 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin
|
|||
drwav_uint64 totalFramesRead = 0;
|
||||
drwav_uint32 iChannel;
|
||||
|
||||
static drwav_int32 indexTable[16] = {
|
||||
static const drwav_int32 indexTable[16] = {
|
||||
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||
-1, -1, -1, -1, 2, 4, 6, 8
|
||||
};
|
||||
|
||||
static drwav_int32 stepTable[89] = {
|
||||
static const drwav_int32 stepTable[89] = {
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
|
||||
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
|
||||
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
|
||||
|
|
@ -6606,7 +6654,7 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin
|
|||
|
||||
|
||||
#ifndef DR_WAV_NO_CONVERSION_API
|
||||
static unsigned short g_drwavAlawTable[256] = {
|
||||
static const unsigned short g_drwavAlawTable[256] = {
|
||||
0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580,
|
||||
0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0,
|
||||
0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600,
|
||||
|
|
@ -6625,7 +6673,7 @@ static unsigned short g_drwavAlawTable[256] = {
|
|||
0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350
|
||||
};
|
||||
|
||||
static unsigned short g_drwavMulawTable[256] = {
|
||||
static const unsigned short g_drwavMulawTable[256] = {
|
||||
0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84,
|
||||
0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84,
|
||||
0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004,
|
||||
|
|
@ -6703,6 +6751,10 @@ DRWAV_PRIVATE void drwav__pcm_to_s16(drwav_int16* pOut, const drwav_uint8* pIn,
|
|||
shift += 8;
|
||||
}
|
||||
|
||||
if (!drwav__is_little_endian()) {
|
||||
sample = drwav__bswap64(sample);
|
||||
}
|
||||
|
||||
pIn += j;
|
||||
*pOut++ = (drwav_int16)((drwav_int64)sample >> 48);
|
||||
}
|
||||
|
|
@ -7144,6 +7196,10 @@ DRWAV_PRIVATE void drwav__pcm_to_f32(float* pOut, const drwav_uint8* pIn, size_t
|
|||
shift += 8;
|
||||
}
|
||||
|
||||
if (!drwav__is_little_endian()) {
|
||||
sample = drwav__bswap64(sample);
|
||||
}
|
||||
|
||||
pIn += j;
|
||||
*pOut++ = (float)((drwav_int64)sample / 9223372036854775807.0);
|
||||
}
|
||||
|
|
@ -7628,6 +7684,10 @@ DRWAV_PRIVATE void drwav__pcm_to_s32(drwav_int32* pOut, const drwav_uint8* pIn,
|
|||
shift += 8;
|
||||
}
|
||||
|
||||
if (!drwav__is_little_endian()) {
|
||||
sample = drwav__bswap64(sample);
|
||||
}
|
||||
|
||||
pIn += j;
|
||||
*pOut++ = (drwav_int32)((drwav_int64)sample >> 32);
|
||||
}
|
||||
|
|
@ -8053,6 +8113,12 @@ DRWAV_PRIVATE drwav_int16* drwav__read_pcm_frames_and_close_s16(drwav* pWav, uns
|
|||
|
||||
DRWAV_ASSERT(pWav != NULL);
|
||||
|
||||
/* Check for overflow before multiplication. */
|
||||
if (pWav->channels == 0 || pWav->totalPCMFrameCount > DRWAV_SIZE_MAX / pWav->channels / sizeof(drwav_int16)) {
|
||||
drwav_uninit(pWav);
|
||||
return NULL; /* Overflow or invalid channels. */
|
||||
}
|
||||
|
||||
sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int16);
|
||||
if (sampleDataSize > DRWAV_SIZE_MAX) {
|
||||
drwav_uninit(pWav);
|
||||
|
|
@ -8095,6 +8161,12 @@ DRWAV_PRIVATE float* drwav__read_pcm_frames_and_close_f32(drwav* pWav, unsigned
|
|||
|
||||
DRWAV_ASSERT(pWav != NULL);
|
||||
|
||||
/* Check for overflow before multiplication. */
|
||||
if (pWav->channels == 0 || pWav->totalPCMFrameCount > DRWAV_SIZE_MAX / pWav->channels / sizeof(float)) {
|
||||
drwav_uninit(pWav);
|
||||
return NULL; /* Overflow or invalid channels. */
|
||||
}
|
||||
|
||||
sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(float);
|
||||
if (sampleDataSize > DRWAV_SIZE_MAX) {
|
||||
drwav_uninit(pWav);
|
||||
|
|
@ -8137,6 +8209,12 @@ DRWAV_PRIVATE drwav_int32* drwav__read_pcm_frames_and_close_s32(drwav* pWav, uns
|
|||
|
||||
DRWAV_ASSERT(pWav != NULL);
|
||||
|
||||
/* Check for overflow before multiplication. */
|
||||
if (pWav->channels == 0 || pWav->totalPCMFrameCount > DRWAV_SIZE_MAX / pWav->channels / sizeof(drwav_int32)) {
|
||||
drwav_uninit(pWav);
|
||||
return NULL; /* Overflow or invalid channels. */
|
||||
}
|
||||
|
||||
sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int32);
|
||||
if (sampleDataSize > DRWAV_SIZE_MAX) {
|
||||
drwav_uninit(pWav);
|
||||
|
|
@ -8517,7 +8595,31 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b)
|
|||
/*
|
||||
REVISION HISTORY
|
||||
================
|
||||
v0.14.0 - TBD
|
||||
v0.14.6 - TBD
|
||||
- Fix an error when loading files with a malformed "bext" chunk.
|
||||
- Fix an error when loading files with a malformed "fmt" chunk.
|
||||
- Fix an underflow error with badly formed ADPCM encoded files.
|
||||
- Fix an underflow error with badly formed W64 files.
|
||||
- Fix an error when converting from >32 bit samples to s16/f32/s32 on big-endian architectures.
|
||||
|
||||
v0.14.5 - 2026-03-03
|
||||
- Fix a crash when loading files with a malformed "smpl" chunk.
|
||||
- Fix a signed overflow bug with the MS-ADPCM decoder.
|
||||
|
||||
v0.14.4 - 2026-01-17
|
||||
- Fix some compilation warnings.
|
||||
|
||||
v0.14.3 - 2025-12-14
|
||||
- Fix a possible out-of-bounds read when reading from MS-ADPCM encoded files.
|
||||
- Fix a possible integer overflow error.
|
||||
|
||||
v0.14.2 - 2025-12-02
|
||||
- Fix a compilation warning.
|
||||
|
||||
v0.14.1 - 2025-09-10
|
||||
- Fix an error with the NXDK build.
|
||||
|
||||
v0.14.0 - 2025-07-23
|
||||
- API CHANGE: Seek origin enums have been renamed to the following:
|
||||
- drwav_seek_origin_start -> DRWAV_SEEK_SET
|
||||
- drwav_seek_origin_current -> DRWAV_SEEK_CUR
|
||||
|
|
|
|||
4
src/external/jar_mod.h
vendored
4
src/external/jar_mod.h
vendored
|
|
@ -1538,10 +1538,10 @@ mulong jar_mod_load_file(jar_mod_context_t * modctx, const char* filename)
|
|||
modctx->modfile = (muchar *) JARMOD_MALLOC(fsize);
|
||||
modctx->modfilesize = fsize;
|
||||
memset(modctx->modfile, 0, fsize);
|
||||
fread(modctx->modfile, fsize, 1, f);
|
||||
if(fread(modctx->modfile, fsize, 1, f) != 1) fsize = 0;
|
||||
fclose(f);
|
||||
|
||||
if(!jar_mod_load(modctx, (void *)modctx->modfile, fsize)) fsize = 0;
|
||||
if(fsize && !jar_mod_load(modctx, (void *)modctx->modfile, fsize)) fsize = 0;
|
||||
} else fsize = 0;
|
||||
}
|
||||
return fsize;
|
||||
|
|
|
|||
53
src/external/m3d.h
vendored
53
src/external/m3d.h
vendored
|
|
@ -236,7 +236,8 @@ typedef struct {
|
|||
#ifdef M3D_ASCII
|
||||
#define M3D_PROPERTYDEF(f,i,n) { (f), (i), (char*)(n) }
|
||||
char *key;
|
||||
#else
|
||||
#endif
|
||||
#ifndef M3D_ASCII
|
||||
#define M3D_PROPERTYDEF(f,i,n) { (f), (i) }
|
||||
#endif
|
||||
} m3dpd_t;
|
||||
|
|
@ -414,7 +415,8 @@ typedef struct {
|
|||
#ifdef M3D_ASCII
|
||||
#define M3D_CMDDEF(t,n,p,a,b,c,d,e,f,g,h) { (char*)(n), (p), { (a), (b), (c), (d), (e), (f), (g), (h) } }
|
||||
char *key;
|
||||
#else
|
||||
#endif
|
||||
#ifndef M3D_ASCII
|
||||
#define M3D_CMDDEF(t,n,p,a,b,c,d,e,f,g,h) { (p), { (a), (b), (c), (d), (e), (f), (g), (h) } }
|
||||
#endif
|
||||
uint8_t p;
|
||||
|
|
@ -674,6 +676,10 @@ static m3dcd_t m3d_commandtypes[] = {
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* we'll need this with M3D_NOTEXTURE */
|
||||
char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);
|
||||
|
||||
#ifndef M3D_NOTEXTURE
|
||||
#if !defined(M3D_NOIMPORTER) && !defined(STBI_INCLUDE_STB_IMAGE_H)
|
||||
/* PNG decompressor from
|
||||
|
||||
|
|
@ -1868,6 +1874,11 @@ static void *_m3dstbi__png_load(_m3dstbi__context *s, int *x, int *y, int *comp,
|
|||
#if !defined(M3D_NOIMPORTER) && defined(STBI_INCLUDE_STB_IMAGE_H) && !defined(STB_IMAGE_IMPLEMENTATION)
|
||||
#error "stb_image.h included without STB_IMAGE_IMPLEMENTATION. Sorry, we need some stuff defined inside the ifguard for proper integration"
|
||||
#endif
|
||||
#else
|
||||
#if !defined(STBI_INCLUDE_STB_IMAGE_H) || defined(STBI_NO_ZLIB)
|
||||
#error "stb_image.h not included or STBI_NO_ZLIB defined. Sorry, we need its zlib implementation for proper integration"
|
||||
#endif
|
||||
#endif /* M3D_NOTEXTURE */
|
||||
|
||||
#if defined(M3D_EXPORTER) && !defined(INCLUDE_STB_IMAGE_WRITE_H)
|
||||
/* zlib_compressor from
|
||||
|
|
@ -2168,9 +2179,11 @@ M3D_INDEX _m3d_gettx(m3d_t *model, m3dread_t readfilecb, m3dfree_t freecb, char
|
|||
unsigned int i, len = 0;
|
||||
unsigned char *buff = NULL;
|
||||
char *fn2;
|
||||
#ifndef M3D_NOTEXTURE
|
||||
unsigned int w, h;
|
||||
stbi__context s;
|
||||
stbi__result_info ri;
|
||||
#endif
|
||||
|
||||
/* failsafe */
|
||||
if(!fn || !*fn) return M3D_UNDEF;
|
||||
|
|
@ -2209,13 +2222,17 @@ M3D_INDEX _m3d_gettx(m3d_t *model, m3dread_t readfilecb, m3dfree_t freecb, char
|
|||
if(!model->texture) {
|
||||
if(buff && freecb) (*freecb)(buff);
|
||||
model->errcode = M3D_ERR_ALLOC;
|
||||
model->numtexture = 0;
|
||||
return M3D_UNDEF;
|
||||
}
|
||||
memset(&model->texture[i], 0, sizeof(m3dtx_t));
|
||||
model->texture[i].name = fn;
|
||||
model->texture[i].w = model->texture[i].h = 0; model->texture[i].d = NULL;
|
||||
if(buff) {
|
||||
if(buff[0] == 0x89 && buff[1] == 'P' && buff[2] == 'N' && buff[3] == 'G') {
|
||||
s.read_from_callbacks = 0;
|
||||
#ifndef M3D_NOTEXTURE
|
||||
/* return pixel buffer of the decoded texture */
|
||||
memset(&s, 0, sizeof(s));
|
||||
memset(&ri, 0, sizeof(ri));
|
||||
s.img_buffer = s.img_buffer_original = (unsigned char *) buff;
|
||||
s.img_buffer_end = s.img_buffer_original_end = (unsigned char *) buff+len;
|
||||
/* don't use model->texture[i].w directly, it's a uint16_t */
|
||||
|
|
@ -2225,6 +2242,16 @@ M3D_INDEX _m3d_gettx(m3d_t *model, m3dread_t readfilecb, m3dfree_t freecb, char
|
|||
model->texture[i].w = w;
|
||||
model->texture[i].h = h;
|
||||
model->texture[i].f = (uint8_t)len;
|
||||
#else
|
||||
/* return only the raw undecoded texture */
|
||||
if((model->texture[i].d = (uint8_t*)M3D_MALLOC(len))) {
|
||||
memcpy(model->texture[i].d, buff, len);
|
||||
model->texture[i].w = len & 0xffff;
|
||||
model->texture[i].h = (len >> 16) & 0xffff;
|
||||
model->texture[i].f = 0;
|
||||
} else
|
||||
model->errcode = M3D_ERR_ALLOC;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef M3D_TX_INTERP
|
||||
if((model->errcode = M3D_TX_INTERP(fn, buff, len, &model->texture[i])) != M3D_SUCCESS) {
|
||||
|
|
@ -4280,7 +4307,7 @@ m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec)
|
|||
if(l != msec) {
|
||||
model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, (model->numvertex + 2 * model->numbone) * sizeof(m3dv_t));
|
||||
if(!model->vertex) {
|
||||
free(ret);
|
||||
M3D_FREE(ret);
|
||||
model->errcode = M3D_ERR_ALLOC;
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -4492,7 +4519,7 @@ void m3d_free(m3d_t *model)
|
|||
if(model->label) M3D_FREE(model->label);
|
||||
if(model->inlined) M3D_FREE(model->inlined);
|
||||
if(model->extra) M3D_FREE(model->extra);
|
||||
free(model);
|
||||
M3D_FREE(model);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -4568,15 +4595,15 @@ static uint32_t _m3d_stridx(m3dstr_t *str, uint32_t numstr, char *s)
|
|||
safe = _m3d_safestr(s, 0);
|
||||
if(!safe) return 0;
|
||||
if(!*safe) {
|
||||
free(safe);
|
||||
M3D_FREE(safe);
|
||||
return 0;
|
||||
}
|
||||
for(i = 0; i < numstr; i++)
|
||||
if(!strcmp(str[i].str, s)) {
|
||||
free(safe);
|
||||
M3D_FREE(safe);
|
||||
return str[i].offs;
|
||||
}
|
||||
free(safe);
|
||||
M3D_FREE(safe);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -4889,7 +4916,7 @@ unsigned char *m3d_save(m3d_t *model, int quality, int flags, unsigned int *size
|
|||
if(cmd->type == m3dc_mesh) {
|
||||
if(numgrp + 2 < maxgrp) {
|
||||
maxgrp += 1024;
|
||||
grpidx = (uint32_t*)realloc(grpidx, maxgrp * sizeof(uint32_t));
|
||||
grpidx = (uint32_t*)M3D_REALLOC(grpidx, maxgrp * sizeof(uint32_t));
|
||||
if(!grpidx) goto memerr;
|
||||
if(!numgrp) {
|
||||
grpidx[0] = 0;
|
||||
|
|
@ -5194,7 +5221,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx);
|
|||
if(sa) M3D_FREE(sa);
|
||||
if(sd) M3D_FREE(sd);
|
||||
if(out) M3D_FREE(out);
|
||||
if(opa) free(opa);
|
||||
if(opa) M3D_FREE(opa);
|
||||
if(h) M3D_FREE(h);
|
||||
M3D_LOG("Out of memory");
|
||||
model->errcode = M3D_ERR_ALLOC;
|
||||
|
|
@ -6285,7 +6312,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx);
|
|||
if(skin) M3D_FREE(skin);
|
||||
if(str) M3D_FREE(str);
|
||||
if(vrtx) M3D_FREE(vrtx);
|
||||
if(opa) free(opa);
|
||||
if(opa) M3D_FREE(opa);
|
||||
if(h) M3D_FREE(h);
|
||||
return out;
|
||||
}
|
||||
|
|
@ -6310,7 +6337,7 @@ namespace M3D {
|
|||
|
||||
public:
|
||||
Model() {
|
||||
this->model = (m3d_t*)malloc(sizeof(m3d_t)); memset(this->model, 0, sizeof(m3d_t));
|
||||
this->model = (m3d_t*)M3D_MALLOC(sizeof(m3d_t)); memset(this->model, 0, sizeof(m3d_t));
|
||||
}
|
||||
Model(_unused const std::string &data, _unused m3dread_t ReadFileCB,
|
||||
_unused m3dfree_t FreeCB, _unused M3D::Model mtllib) {
|
||||
|
|
|
|||
60
src/external/qoa.h
vendored
60
src/external/qoa.h
vendored
|
|
@ -31,7 +31,7 @@ struct {
|
|||
struct {
|
||||
char magic[4]; // magic bytes "qoaf"
|
||||
uint32_t samples; // samples per channel in this file
|
||||
} file_header;
|
||||
} file_header;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
|
|
@ -39,12 +39,12 @@ struct {
|
|||
uint24_t samplerate; // samplerate in hz
|
||||
uint16_t fsamples; // samples per channel in this frame
|
||||
uint16_t fsize; // frame size (includes this header)
|
||||
} frame_header;
|
||||
} frame_header;
|
||||
|
||||
struct {
|
||||
int16_t history[4]; // most recent last
|
||||
int16_t weights[4]; // most recent last
|
||||
} lms_state[num_channels];
|
||||
} lms_state[num_channels];
|
||||
|
||||
qoa_slice_t slices[256][num_channels];
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ frame may contain between 1 .. 256 (inclusive) slices per channel. The last
|
|||
slice (for each channel) in the last frame may contain less than 20 samples; the
|
||||
slice still must be 8 bytes wide, with the unused samples zeroed out.
|
||||
|
||||
Channels are interleaved per slice. E.g. for 2 channel stereo:
|
||||
Channels are interleaved per slice. E.g. for 2 channel stereo:
|
||||
slice[0] = L, slice[1] = R, slice[2] = L, slice[3] = R ...
|
||||
|
||||
A valid QOA file or stream must have at least one frame. Each frame must contain
|
||||
|
|
@ -74,7 +74,7 @@ at least one channel and one sample with a samplerate between 1 .. 16777215
|
|||
(inclusive).
|
||||
|
||||
If the total number of samples is not known by the encoder, the samples in the
|
||||
file header may be set to 0x00000000 to indicate that the encoder is
|
||||
file header may be set to 0x00000000 to indicate that the encoder is
|
||||
"streaming". In a streaming context, the samplerate and number of channels may
|
||||
differ from frame to frame. For static files (those with samples set to a
|
||||
non-zero value), each frame must have the same number of channels and same
|
||||
|
|
@ -88,15 +88,15 @@ counts 1 .. 8 is:
|
|||
|
||||
1. Mono
|
||||
2. L, R
|
||||
3. L, R, C
|
||||
4. FL, FR, B/SL, B/SR
|
||||
5. FL, FR, C, B/SL, B/SR
|
||||
3. L, R, C
|
||||
4. FL, FR, B/SL, B/SR
|
||||
5. FL, FR, C, B/SL, B/SR
|
||||
6. FL, FR, C, LFE, B/SL, B/SR
|
||||
7. FL, FR, C, LFE, B, SL, SR
|
||||
7. FL, FR, C, LFE, B, SL, SR
|
||||
8. FL, FR, C, LFE, BL, BR, SL, SR
|
||||
|
||||
QOA predicts each audio sample based on the previously decoded ones using a
|
||||
"Sign-Sign Least Mean Squares Filter" (LMS). This prediction plus the
|
||||
"Sign-Sign Least Mean Squares Filter" (LMS). This prediction plus the
|
||||
dequantized residual forms the final output sample.
|
||||
|
||||
*/
|
||||
|
|
@ -178,9 +178,9 @@ typedef unsigned long long qoa_uint64_t;
|
|||
|
||||
|
||||
/* The quant_tab provides an index into the dequant_tab for residuals in the
|
||||
range of -8 .. 8. It maps this range to just 3bits and becomes less accurate at
|
||||
the higher end. Note that the residual zero is identical to the lowest positive
|
||||
value. This is mostly fine, since the qoa_div() function always rounds away
|
||||
range of -8 .. 8. It maps this range to just 3bits and becomes less accurate at
|
||||
the higher end. Note that the residual zero is identical to the lowest positive
|
||||
value. This is mostly fine, since the qoa_div() function always rounds away
|
||||
from zero. */
|
||||
|
||||
static const int qoa_quant_tab[17] = {
|
||||
|
|
@ -193,8 +193,8 @@ static const int qoa_quant_tab[17] = {
|
|||
/* We have 16 different scalefactors. Like the quantized residuals these become
|
||||
less accurate at the higher end. In theory, the highest scalefactor that we
|
||||
would need to encode the highest 16bit residual is (2**16)/8 = 8192. However we
|
||||
rely on the LMS filter to predict samples accurately enough that a maximum
|
||||
residual of one quarter of the 16 bit range is sufficient. I.e. with the
|
||||
rely on the LMS filter to predict samples accurately enough that a maximum
|
||||
residual of one quarter of the 16 bit range is sufficient. I.e. with the
|
||||
scalefactor 2048 times the quant range of 8 we can encode residuals up to 2**14.
|
||||
|
||||
The scalefactor values are computed as:
|
||||
|
|
@ -205,9 +205,9 @@ static const int qoa_scalefactor_tab[16] = {
|
|||
};
|
||||
|
||||
|
||||
/* The reciprocal_tab maps each of the 16 scalefactors to their rounded
|
||||
reciprocals 1/scalefactor. This allows us to calculate the scaled residuals in
|
||||
the encoder with just one multiplication instead of an expensive division. We
|
||||
/* The reciprocal_tab maps each of the 16 scalefactors to their rounded
|
||||
reciprocals 1/scalefactor. This allows us to calculate the scaled residuals in
|
||||
the encoder with just one multiplication instead of an expensive division. We
|
||||
do this in .16 fixed point with integers, instead of floats.
|
||||
|
||||
The reciprocal_tab is computed as:
|
||||
|
|
@ -218,11 +218,11 @@ static const int qoa_reciprocal_tab[16] = {
|
|||
};
|
||||
|
||||
|
||||
/* The dequant_tab maps each of the scalefactors and quantized residuals to
|
||||
/* The dequant_tab maps each of the scalefactors and quantized residuals to
|
||||
their unscaled & dequantized version.
|
||||
|
||||
Since qoa_div rounds away from the zero, the smallest entries are mapped to 3/4
|
||||
instead of 1. The dequant_tab assumes the following dequantized values for each
|
||||
instead of 1. The dequant_tab assumes the following dequantized values for each
|
||||
of the quant_tab indices and is computed as:
|
||||
float dqt[8] = {0.75, -0.75, 2.5, -2.5, 4.5, -4.5, 7, -7};
|
||||
dequant_tab[s][q] <- round_ties_away_from_zero(scalefactor_tab[s] * dqt[q])
|
||||
|
|
@ -258,7 +258,7 @@ adjusting 4 weights based on the residual of the previous prediction.
|
|||
The next sample is predicted as the sum of (weight[i] * history[i]).
|
||||
|
||||
The adjustment of the weights is done with a "Sign-Sign-LMS" that adds or
|
||||
subtracts the residual to each weight, based on the corresponding sample from
|
||||
subtracts the residual to each weight, based on the corresponding sample from
|
||||
the history. This, surprisingly, is sufficient to get worthwhile predictions.
|
||||
|
||||
This is all done with fixed point integers. Hence the right-shifts when updating
|
||||
|
|
@ -285,8 +285,8 @@ static void qoa_lms_update(qoa_lms_t *lms, int sample, int residual) {
|
|||
}
|
||||
|
||||
|
||||
/* qoa_div() implements a rounding division, but avoids rounding to zero for
|
||||
small numbers. E.g. 0.1 will be rounded to 1. Note that 0 itself still
|
||||
/* qoa_div() implements a rounding division, but avoids rounding to zero for
|
||||
small numbers. E.g. 0.1 will be rounded to 1. Note that 0 itself still
|
||||
returns as 0, which is handled in the qoa_quant_tab[].
|
||||
qoa_div() takes an index into the .16 fixed point qoa_reciprocal_tab as an
|
||||
argument, so it can do the division with a cheaper integer multiplication. */
|
||||
|
|
@ -385,10 +385,10 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned
|
|||
for (unsigned int c = 0; c < channels; c++) {
|
||||
int slice_len = qoa_clamp(QOA_SLICE_LEN, 0, frame_len - sample_index);
|
||||
int slice_start = sample_index * channels + c;
|
||||
int slice_end = (sample_index + slice_len) * channels + c;
|
||||
int slice_end = (sample_index + slice_len) * channels + c;
|
||||
|
||||
/* Brute for search for the best scalefactor. Just go through all
|
||||
16 scalefactors, encode all samples for the current slice and
|
||||
/* Brute force search for the best scalefactor. Just go through all
|
||||
16 scalefactors, encode all samples for the current slice and
|
||||
meassure the total squared error. */
|
||||
qoa_uint64_t best_rank = -1;
|
||||
#ifdef QOA_RECORD_TOTAL_ERROR
|
||||
|
|
@ -402,7 +402,7 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned
|
|||
/* There is a strong correlation between the scalefactors of
|
||||
neighboring slices. As an optimization, start testing
|
||||
the best scalefactor of the previous slice first. */
|
||||
int scalefactor = (sfi + prev_scalefactor[c]) % 16;
|
||||
int scalefactor = (sfi + prev_scalefactor[c]) & (16 - 1);
|
||||
|
||||
/* We have to reset the LMS state to the last known good one
|
||||
before trying each scalefactor, as each pass updates the LMS
|
||||
|
|
@ -500,7 +500,7 @@ void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len)
|
|||
num_frames * QOA_LMS_LEN * 4 * qoa->channels + /* 4 * 4 bytes lms state per channel */
|
||||
num_slices * 8 * qoa->channels; /* 8 byte slices */
|
||||
|
||||
unsigned char *bytes = (unsigned char *)QOA_MALLOC(encoded_size);
|
||||
unsigned char *bytes = QOA_MALLOC(encoded_size);
|
||||
|
||||
for (unsigned int c = 0; c < qoa->channels; c++) {
|
||||
/* Set the initial LMS weights to {0, 0, -1, 2}. This helps with the
|
||||
|
|
@ -657,7 +657,7 @@ short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *qoa) {
|
|||
|
||||
/* Calculate the required size of the sample buffer and allocate */
|
||||
int total_samples = qoa->samples * qoa->channels;
|
||||
short *sample_data = (short *)QOA_MALLOC(total_samples * sizeof(short));
|
||||
short *sample_data = QOA_MALLOC(total_samples * sizeof(short));
|
||||
|
||||
unsigned int sample_index = 0;
|
||||
unsigned int frame_len;
|
||||
|
|
@ -733,7 +733,7 @@ void *qoa_read(const char *filename, qoa_desc *qoa) {
|
|||
bytes_read = fread(data, 1, size, f);
|
||||
fclose(f);
|
||||
|
||||
sample_data = qoa_decode((const unsigned char *)data, bytes_read, qoa);
|
||||
sample_data = qoa_decode(data, bytes_read, qoa);
|
||||
QOA_FREE(data);
|
||||
return sample_data;
|
||||
}
|
||||
|
|
|
|||
4
src/external/qoi.h
vendored
4
src/external/qoi.h
vendored
|
|
@ -427,7 +427,7 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
|
|||
run = 0;
|
||||
}
|
||||
|
||||
index_pos = QOI_COLOR_HASH(px) % 64;
|
||||
index_pos = QOI_COLOR_HASH(px) & (64 - 1);
|
||||
|
||||
if (index[index_pos].v == px.v) {
|
||||
bytes[p++] = QOI_OP_INDEX | index_pos;
|
||||
|
|
@ -574,7 +574,7 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
|
|||
run = (b1 & 0x3f);
|
||||
}
|
||||
|
||||
index[QOI_COLOR_HASH(px) % 64] = px;
|
||||
index[QOI_COLOR_HASH(px) & (64 - 1)] = px;
|
||||
}
|
||||
|
||||
pixels[px_pos + 0] = px.rgba.r;
|
||||
|
|
|
|||
245
src/external/rlsw.h
vendored
245
src/external/rlsw.h
vendored
|
|
@ -153,7 +153,7 @@
|
|||
#define SW_MAX_TEXTURES 128
|
||||
#endif
|
||||
|
||||
// Enables the use of a lookup table for uint8_t to float conversion
|
||||
// Enable the use of a lookup table for uint8_t to float conversion
|
||||
// Requires an additional 1KB of global memory
|
||||
// Disabled when SIMD intrinsics are enabled
|
||||
#ifndef SW_USE_COLOR_LUT
|
||||
|
|
@ -164,6 +164,19 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
// Fast power-of-two texture wrap (SW_REPEAT mode only)
|
||||
// When defined, textures whose width/height are powers of two use a bitmask
|
||||
// wrap (`x & (size-1)`) instead of `floorf`-based fractional wrap or the
|
||||
// signed `%` chain in the linear sampler. Saves a software divide on Xtensa
|
||||
// and a few instructions everywhere. NPOT textures keep using the original
|
||||
// path via a runtime `(size & (size-1)) == 0` check, so SW_REPEAT remains
|
||||
// correct for them. The only observable behavior change is for POT textures
|
||||
// sampled with negative UV coordinates: bitmask wrap (two's complement) can
|
||||
// differ from `sw_fract` by one texel. Off by default to keep bit-for-bit
|
||||
// behavior; opt in if you control your asset UVs.
|
||||
//
|
||||
// #define SW_TEXTURE_REPEAT_POT_FAST
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// OpenGL Compatibility Types
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -200,6 +213,7 @@ typedef double GLclampd;
|
|||
#define GL_RENDERER 0x1F01
|
||||
#define GL_VERSION 0x1F02
|
||||
#define GL_EXTENSIONS 0x1F03
|
||||
#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
|
||||
|
||||
//#define GL_ATTRIB_STACK_DEPTH 0x0BB0
|
||||
//#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1
|
||||
|
|
@ -507,6 +521,7 @@ typedef enum {
|
|||
SW_RENDERER = GL_RENDERER,
|
||||
SW_VERSION = GL_VERSION,
|
||||
SW_EXTENSIONS = GL_EXTENSIONS,
|
||||
SW_SHADING_LANGUAGE_VERSION = GL_SHADING_LANGUAGE_VERSION,
|
||||
SW_COLOR_CLEAR_VALUE = GL_COLOR_CLEAR_VALUE,
|
||||
SW_DEPTH_CLEAR_VALUE = GL_DEPTH_CLEAR_VALUE,
|
||||
SW_CURRENT_COLOR = GL_CURRENT_COLOR,
|
||||
|
|
@ -844,6 +859,17 @@ SWAPI void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWatta
|
|||
#endif
|
||||
#endif
|
||||
|
||||
// ESP-DSP acceleration: ESP-IDF ships an optimized math library that includes
|
||||
// `dspm_mult_4x4x4_f32` (4x4 matrix multiply) and `dspm_mult_4x4x1_f32`
|
||||
// (matrix * vector). These are S3-tuned hand-vectorized kernels that beat the
|
||||
// scalar versions for both throughput and code-size. Detection is opt-in to
|
||||
// keep the dependency optional: define SW_USE_ESP_DSP from your build system
|
||||
// (or rely on the `idf_component.yml` example shown in the rlsw docs).
|
||||
#if defined(ESP_PLATFORM) && defined(SW_USE_ESP_DSP)
|
||||
#define SW_HAS_ESP_DSP
|
||||
#include "dspm_mult.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define SW_CURLY_INIT(name) name
|
||||
#else
|
||||
|
|
@ -1038,6 +1064,9 @@ typedef struct {
|
|||
SWmatrix currentMatrixMode; // Current matrix mode (e.g., sw_MODELVIEW, sw_PROJECTION)
|
||||
sw_matrix_t *currentMatrix; // Pointer to the currently used matrix according to the mode
|
||||
sw_matrix_t matMVP; // Model view projection matrix, calculated and used internally
|
||||
#ifdef SW_HAS_ESP_DSP
|
||||
float matMVP_rm[16]; // Row-major MVP, kept in sync for esp-dsp dspm_mult_4x4x1_f32 vertex transform
|
||||
#endif
|
||||
bool isDirtyMVP; // Indicates if the MVP matrix should be rebuilt
|
||||
|
||||
sw_handle_t boundFramebufferId; // Framebuffer currently bound
|
||||
|
|
@ -1141,6 +1170,14 @@ static inline void sw_matrix_id(sw_matrix_t dst)
|
|||
|
||||
static inline void sw_matrix_mul_rst(float *SW_RESTRICT dst, const float *SW_RESTRICT left, const float *SW_RESTRICT right)
|
||||
{
|
||||
#ifdef SW_HAS_ESP_DSP
|
||||
// dspm_mult_4x4x4_f32 treats its operands as row-major. rlsw stores matrices
|
||||
// column-major, so passing them flat is equivalent to passing transposes:
|
||||
// dspm_mult(L^T, R^T) computes (L^T)*(R^T) = (R*L)^T, written back into a
|
||||
// flat array gives the same bit pattern as the column-major product (R*L)
|
||||
// -- exactly the semantic the scalar fallback below has.
|
||||
dspm_mult_4x4x4_f32(left, right, dst);
|
||||
#else
|
||||
float l00 = left[0], l01 = left[1], l02 = left[2], l03 = left[3];
|
||||
float l10 = left[4], l11 = left[5], l12 = left[6], l13 = left[7];
|
||||
float l20 = left[8], l21 = left[9], l22 = left[10], l23 = left[11];
|
||||
|
|
@ -1165,6 +1202,7 @@ static inline void sw_matrix_mul_rst(float *SW_RESTRICT dst, const float *SW_RES
|
|||
dst[7] = l10*right[3] + l11*right[7] + l12*right[11] + l13*right[15];
|
||||
dst[11] = l20*right[3] + l21*right[7] + l22*right[11] + l23*right[15];
|
||||
dst[15] = l30*right[3] + l31*right[7] + l32*right[11] + l33*right[15];
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void sw_matrix_mul(sw_matrix_t dst, const sw_matrix_t left, const sw_matrix_t right)
|
||||
|
|
@ -1210,6 +1248,33 @@ static inline float sw_fract(float x)
|
|||
return (x - floorf(x));
|
||||
}
|
||||
|
||||
// Fast reciprocal: 1-ULP accurate in ~7 instructions on Xtensa using the
|
||||
// hardware `recip0.s` seed + two Newton-Raphson refinement steps. All work
|
||||
// stays in FPU registers — no `__divsf3` software call. Hot-path divisions
|
||||
// in the rasterizer (span/triangle setup, perspective divide, etc.) call
|
||||
// this. On non-Xtensa targets it transparently expands to `1.0f / x`, so
|
||||
// generated code is identical to before.
|
||||
#if defined(__XTENSA__)
|
||||
__attribute__((always_inline))
|
||||
static inline float sw_rcp(float x)
|
||||
{
|
||||
float result, temp;
|
||||
__asm__(
|
||||
"recip0.s %0, %2\n"
|
||||
"const.s %1, 1\n"
|
||||
"msub.s %1, %2, %0\n"
|
||||
"madd.s %0, %0, %1\n"
|
||||
"const.s %1, 1\n"
|
||||
"msub.s %1, %2, %0\n"
|
||||
"maddn.s %0, %0, %1\n"
|
||||
: "=&f"(result), "=&f"(temp) : "f"(x)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
static inline float sw_rcp(float x) { return 1.0f/x; }
|
||||
#endif
|
||||
|
||||
static inline uint8_t sw_luminance8(const uint8_t *color)
|
||||
{
|
||||
return (uint8_t)((color[0]*77 + color[1]*150 + color[2]*29) >> 8);
|
||||
|
|
@ -2281,7 +2346,7 @@ static inline sw_pixel_write_color_f sw_pixel_get_write_color_func(sw_pixelforma
|
|||
{
|
||||
case SW_PIXELFORMAT_COLOR_GRAYSCALE: return sw_pixel_write_color_GRAYSCALE;
|
||||
case SW_PIXELFORMAT_COLOR_GRAYALPHA: return sw_pixel_write_color_GRAYALPHA;
|
||||
case SW_PIXELFORMAT_COLOR_R3G3B2: return sw_pixel_write_color_R3G3B2;
|
||||
case SW_PIXELFORMAT_COLOR_R3G3B2: return sw_pixel_write_color_R3G3B2;
|
||||
case SW_PIXELFORMAT_COLOR_R5G6B5: return sw_pixel_write_color_R5G6B5;
|
||||
case SW_PIXELFORMAT_COLOR_R8G8B8: return sw_pixel_write_color_R8G8B8;
|
||||
case SW_PIXELFORMAT_COLOR_R5G5B5A1: return sw_pixel_write_color_R5G5B5A1;
|
||||
|
|
@ -2357,7 +2422,8 @@ static inline bool sw_texture_alloc(sw_texture_t *texture, const void *data, int
|
|||
|
||||
sw_pixel_read_color8_f readColor8 = NULL;
|
||||
sw_pixel_read_color_f readColor = NULL;
|
||||
if (!isDepth) {
|
||||
if (!isDepth)
|
||||
{
|
||||
readColor8 = sw_pixel_get_read_color8_func(format);
|
||||
readColor = sw_pixel_get_read_color_func(format);
|
||||
}
|
||||
|
|
@ -2405,18 +2471,38 @@ static inline void sw_texture_free(sw_texture_t *texture)
|
|||
|
||||
static inline void sw_texture_sample_nearest(float *SW_RESTRICT color, const sw_texture_t *SW_RESTRICT tex, float u, float v)
|
||||
{
|
||||
u = (tex->sWrap == SW_REPEAT)? sw_fract(u) : sw_saturate(u);
|
||||
v = (tex->tWrap == SW_REPEAT)? sw_fract(v) : sw_saturate(v);
|
||||
int x, y;
|
||||
|
||||
int x = u*tex->width;
|
||||
int y = v*tex->height;
|
||||
#ifdef SW_TEXTURE_REPEAT_POT_FAST
|
||||
if ((tex->sWrap == SW_REPEAT) && ((tex->width & tex->wMinus1) == 0))
|
||||
{
|
||||
x = (int)(u*tex->width) & tex->wMinus1;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
u = (tex->sWrap == SW_REPEAT)? sw_fract(u) : sw_saturate(u);
|
||||
x = (int)(u*tex->width);
|
||||
}
|
||||
|
||||
#ifdef SW_TEXTURE_REPEAT_POT_FAST
|
||||
if ((tex->tWrap == SW_REPEAT) && ((tex->height & tex->hMinus1) == 0))
|
||||
{
|
||||
y = (int)(v*tex->height) & tex->hMinus1;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
v = (tex->tWrap == SW_REPEAT)? sw_fract(v) : sw_saturate(v);
|
||||
y = (int)(v*tex->height);
|
||||
}
|
||||
|
||||
tex->readColor(color, tex->pixels, y*tex->width + x);
|
||||
}
|
||||
|
||||
static inline void sw_texture_sample_linear(float *SW_RESTRICT color, const sw_texture_t *SW_RESTRICT tex, float u, float v)
|
||||
{
|
||||
// TODO: With a bit more cleverness thee number of operations can
|
||||
// TODO: With a bit more cleverness the number of operations can
|
||||
// be clearly reduced, but for now it works fine
|
||||
|
||||
float xf = (u*tex->width) - 0.5f;
|
||||
|
|
@ -2431,13 +2517,19 @@ static inline void sw_texture_sample_linear(float *SW_RESTRICT color, const sw_t
|
|||
int x1 = x0 + 1;
|
||||
int y1 = y0 + 1;
|
||||
|
||||
// NOTE: If the textures are POT, avoid the division for SW_REPEAT
|
||||
|
||||
if (tex->sWrap == SW_CLAMP)
|
||||
{
|
||||
x0 = (x0 > tex->wMinus1)? tex->wMinus1 : x0;
|
||||
x1 = (x1 > tex->wMinus1)? tex->wMinus1 : x1;
|
||||
}
|
||||
#ifdef SW_TEXTURE_REPEAT_POT_FAST
|
||||
else if ((tex->width & tex->wMinus1) == 0)
|
||||
{
|
||||
// POT fast path: bitmask wrap covers negative ints via two's complement
|
||||
x0 = x0 & tex->wMinus1;
|
||||
x1 = x1 & tex->wMinus1;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
x0 = (x0%tex->width + tex->width)%tex->width;
|
||||
|
|
@ -2449,6 +2541,13 @@ static inline void sw_texture_sample_linear(float *SW_RESTRICT color, const sw_t
|
|||
y0 = (y0 > tex->hMinus1)? tex->hMinus1 : y0;
|
||||
y1 = (y1 > tex->hMinus1)? tex->hMinus1 : y1;
|
||||
}
|
||||
#ifdef SW_TEXTURE_REPEAT_POT_FAST
|
||||
else if ((tex->height & tex->hMinus1) == 0)
|
||||
{
|
||||
y0 = y0 & tex->hMinus1;
|
||||
y1 = y1 & tex->hMinus1;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
y0 = (y0%tex->height + tex->height)%tex->height;
|
||||
|
|
@ -2472,7 +2571,7 @@ static inline void sw_texture_sample_linear(float *SW_RESTRICT color, const sw_t
|
|||
static inline void sw_texture_sample(float *SW_RESTRICT color, const sw_texture_t *SW_RESTRICT tex,
|
||||
float u, float v, float dUdx, float dUdy, float dVdx, float dVdy)
|
||||
{
|
||||
// NOTE: Commented there is the previous method used
|
||||
// NOTE: Commented there is the previous method used
|
||||
// There was no need to compute the square root because
|
||||
// using the squared value, the comparison remains (L2 > 1.0f*1.0f)
|
||||
//float du = sqrtf(dUdx*dUdx + dUdy*dUdy);
|
||||
|
|
@ -2673,7 +2772,7 @@ static inline void sw_framebuffer_output_copy(void *dst, const sw_texture_t *buf
|
|||
}
|
||||
}
|
||||
|
||||
static inline void sw_framebuffer_output_blit(void *dst, const sw_texture_t *buffer,
|
||||
static inline void sw_framebuffer_output_blit(void *dst, const sw_texture_t *buffer,
|
||||
int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, sw_pixelformat_t format)
|
||||
{
|
||||
const uint8_t *srcBase = buffer->pixels;
|
||||
|
|
@ -2803,7 +2902,8 @@ static const sw_blend_f SW_BLEND_TABLE[SW_BLEND_FACTOR_COUNT][SW_BLEND_FACTOR_CO
|
|||
// Maps a GL blend factor enum to its compact table index
|
||||
static inline int sw_blend_factor_index(SWfactor f)
|
||||
{
|
||||
switch (f) {
|
||||
switch (f)
|
||||
{
|
||||
case SW_ZERO: return 0;
|
||||
case SW_ONE: return 1;
|
||||
case SW_SRC_COLOR: return 2;
|
||||
|
|
@ -2821,7 +2921,8 @@ static inline int sw_blend_factor_index(SWfactor f)
|
|||
|
||||
static bool sw_blend_factor_needs_alpha(SWfactor f)
|
||||
{
|
||||
switch (f) {
|
||||
switch (f)
|
||||
{
|
||||
case SW_SRC_ALPHA:
|
||||
case SW_ONE_MINUS_SRC_ALPHA:
|
||||
case SW_DST_ALPHA:
|
||||
|
|
@ -2829,6 +2930,7 @@ static bool sw_blend_factor_needs_alpha(SWfactor f)
|
|||
case SW_SRC_ALPHA_SATURATE: return true;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -3007,25 +3109,25 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES]
|
|||
#define RLSW_TEMPLATE_RASTER_TRIANGLE BASE
|
||||
#include __FILE__ // IWYU pragma: keep
|
||||
#undef RLSW_TEMPLATE_RASTER_TRIANGLE
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_TRIANGLE TEX
|
||||
#define SW_ENABLE_TEXTURE
|
||||
#include __FILE__
|
||||
#undef SW_ENABLE_TEXTURE
|
||||
#undef RLSW_TEMPLATE_RASTER_TRIANGLE
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_TRIANGLE DEPTH
|
||||
#define SW_ENABLE_DEPTH_TEST
|
||||
#include __FILE__
|
||||
#undef SW_ENABLE_DEPTH_TEST
|
||||
#undef RLSW_TEMPLATE_RASTER_TRIANGLE
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_TRIANGLE BLEND
|
||||
#define SW_ENABLE_BLEND
|
||||
#include __FILE__
|
||||
#undef SW_ENABLE_BLEND
|
||||
#undef RLSW_TEMPLATE_RASTER_TRIANGLE
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_TRIANGLE TEX_DEPTH
|
||||
#define SW_ENABLE_TEXTURE
|
||||
#define SW_ENABLE_DEPTH_TEST
|
||||
|
|
@ -3033,7 +3135,7 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES]
|
|||
#undef SW_ENABLE_DEPTH_TEST
|
||||
#undef SW_ENABLE_TEXTURE
|
||||
#undef RLSW_TEMPLATE_RASTER_TRIANGLE
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_TRIANGLE TEX_BLEND
|
||||
#define SW_ENABLE_TEXTURE
|
||||
#define SW_ENABLE_BLEND
|
||||
|
|
@ -3041,7 +3143,7 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES]
|
|||
#undef SW_ENABLE_BLEND
|
||||
#undef SW_ENABLE_TEXTURE
|
||||
#undef RLSW_TEMPLATE_RASTER_TRIANGLE
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_TRIANGLE DEPTH_BLEND
|
||||
#define SW_ENABLE_DEPTH_TEST
|
||||
#define SW_ENABLE_BLEND
|
||||
|
|
@ -3049,7 +3151,7 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES]
|
|||
#undef SW_ENABLE_BLEND
|
||||
#undef SW_ENABLE_DEPTH_TEST
|
||||
#undef RLSW_TEMPLATE_RASTER_TRIANGLE
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_TRIANGLE TEX_DEPTH_BLEND
|
||||
#define SW_ENABLE_TEXTURE
|
||||
#define SW_ENABLE_DEPTH_TEST
|
||||
|
|
@ -3059,7 +3161,7 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES]
|
|||
#undef SW_ENABLE_DEPTH_TEST
|
||||
#undef SW_ENABLE_TEXTURE
|
||||
#undef RLSW_TEMPLATE_RASTER_TRIANGLE
|
||||
|
||||
|
||||
// Dispatch table (auto-generated from SW_RASTER_VARIANTS)
|
||||
#define SW_TABLE_ENTRY(NAME, FLAGS) [FLAGS] = sw_raster_triangle_##NAME,
|
||||
static const sw_raster_triangle_f SW_RASTER_TRIANGLE_TABLE[] = {
|
||||
|
|
@ -3106,25 +3208,25 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES]
|
|||
#define RLSW_TEMPLATE_RASTER_QUAD BASE
|
||||
#include __FILE__ // IWYU pragma: keep
|
||||
#undef RLSW_TEMPLATE_RASTER_QUAD
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_QUAD TEX
|
||||
#define SW_ENABLE_TEXTURE
|
||||
#include __FILE__
|
||||
#undef SW_ENABLE_TEXTURE
|
||||
#undef RLSW_TEMPLATE_RASTER_QUAD
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_QUAD DEPTH
|
||||
#define SW_ENABLE_DEPTH_TEST
|
||||
#include __FILE__
|
||||
#undef SW_ENABLE_DEPTH_TEST
|
||||
#undef RLSW_TEMPLATE_RASTER_QUAD
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_QUAD BLEND
|
||||
#define SW_ENABLE_BLEND
|
||||
#include __FILE__
|
||||
#undef SW_ENABLE_BLEND
|
||||
#undef RLSW_TEMPLATE_RASTER_QUAD
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_QUAD TEX_DEPTH
|
||||
#define SW_ENABLE_TEXTURE
|
||||
#define SW_ENABLE_DEPTH_TEST
|
||||
|
|
@ -3132,7 +3234,7 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES]
|
|||
#undef SW_ENABLE_DEPTH_TEST
|
||||
#undef SW_ENABLE_TEXTURE
|
||||
#undef RLSW_TEMPLATE_RASTER_QUAD
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_QUAD TEX_BLEND
|
||||
#define SW_ENABLE_TEXTURE
|
||||
#define SW_ENABLE_BLEND
|
||||
|
|
@ -3140,7 +3242,7 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES]
|
|||
#undef SW_ENABLE_BLEND
|
||||
#undef SW_ENABLE_TEXTURE
|
||||
#undef RLSW_TEMPLATE_RASTER_QUAD
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_QUAD DEPTH_BLEND
|
||||
#define SW_ENABLE_DEPTH_TEST
|
||||
#define SW_ENABLE_BLEND
|
||||
|
|
@ -3148,7 +3250,7 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES]
|
|||
#undef SW_ENABLE_BLEND
|
||||
#undef SW_ENABLE_DEPTH_TEST
|
||||
#undef RLSW_TEMPLATE_RASTER_QUAD
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_QUAD TEX_DEPTH_BLEND
|
||||
#define SW_ENABLE_TEXTURE
|
||||
#define SW_ENABLE_DEPTH_TEST
|
||||
|
|
@ -3158,7 +3260,7 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES]
|
|||
#undef SW_ENABLE_DEPTH_TEST
|
||||
#undef SW_ENABLE_TEXTURE
|
||||
#undef RLSW_TEMPLATE_RASTER_QUAD
|
||||
|
||||
|
||||
// Dispatch table (auto-generated from SW_RASTER_VARIANTS)
|
||||
#define SW_TABLE_ENTRY(NAME, FLAGS) [FLAGS] = sw_raster_quad_##NAME,
|
||||
static const sw_raster_quad_f SW_RASTER_QUAD_TABLE[] = {
|
||||
|
|
@ -3202,19 +3304,19 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES]
|
|||
#define RLSW_TEMPLATE_RASTER_LINE BASE
|
||||
#include __FILE__ // IWYU pragma: keep
|
||||
#undef RLSW_TEMPLATE_RASTER_LINE
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_LINE DEPTH
|
||||
#define SW_ENABLE_DEPTH_TEST
|
||||
#include __FILE__
|
||||
#undef SW_ENABLE_DEPTH_TEST
|
||||
#undef RLSW_TEMPLATE_RASTER_LINE
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_LINE BLEND
|
||||
#define SW_ENABLE_BLEND
|
||||
#include __FILE__
|
||||
#undef SW_ENABLE_BLEND
|
||||
#undef RLSW_TEMPLATE_RASTER_LINE
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_LINE DEPTH_BLEND
|
||||
#define SW_ENABLE_DEPTH_TEST
|
||||
#define SW_ENABLE_BLEND
|
||||
|
|
@ -3222,7 +3324,7 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES]
|
|||
#undef SW_ENABLE_BLEND
|
||||
#undef SW_ENABLE_DEPTH_TEST
|
||||
#undef RLSW_TEMPLATE_RASTER_LINE
|
||||
|
||||
|
||||
// Dispatch table (auto-generated from SW_RASTER_VARIANTS)
|
||||
#define SW_TABLE_ENTRY0(NAME, FLAGS) [FLAGS] = sw_raster_line_##NAME,
|
||||
#define SW_TABLE_ENTRY1(NAME, FLAGS) [FLAGS] = sw_raster_line_thick_##NAME,
|
||||
|
|
@ -3266,19 +3368,19 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES]
|
|||
#define RLSW_TEMPLATE_RASTER_POINT BASE
|
||||
#include __FILE__ // IWYU pragma: keep
|
||||
#undef RLSW_TEMPLATE_RASTER_POINT
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_POINT DEPTH
|
||||
#define SW_ENABLE_DEPTH_TEST
|
||||
#include __FILE__
|
||||
#undef SW_ENABLE_DEPTH_TEST
|
||||
#undef RLSW_TEMPLATE_RASTER_POINT
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_POINT BLEND
|
||||
#define SW_ENABLE_BLEND
|
||||
#include __FILE__
|
||||
#undef SW_ENABLE_BLEND
|
||||
#undef RLSW_TEMPLATE_RASTER_POINT
|
||||
|
||||
|
||||
#define RLSW_TEMPLATE_RASTER_POINT DEPTH_BLEND
|
||||
#define SW_ENABLE_DEPTH_TEST
|
||||
#define SW_ENABLE_BLEND
|
||||
|
|
@ -3286,7 +3388,7 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES]
|
|||
#undef SW_ENABLE_BLEND
|
||||
#undef SW_ENABLE_DEPTH_TEST
|
||||
#undef RLSW_TEMPLATE_RASTER_POINT
|
||||
|
||||
|
||||
// Dispatch table (auto-generated from SW_RASTER_VARIANTS)
|
||||
#define SW_TABLE_ENTRY(NAME, FLAGS) [FLAGS] = sw_raster_point_##NAME,
|
||||
static const sw_raster_point_f SW_RASTER_POINT_TABLE[] = {
|
||||
|
|
@ -3362,7 +3464,7 @@ static void sw_triangle_clip_and_project(void)
|
|||
|
||||
// Calculation of the reciprocal of W for normalization
|
||||
// as well as perspective-correct attributes
|
||||
const float wRcp = 1.0f/v->position[3];
|
||||
const float wRcp = sw_rcp(v->position[3]);
|
||||
|
||||
// Division of XYZ coordinates by weight
|
||||
v->position[0] *= wRcp;
|
||||
|
|
@ -3477,7 +3579,7 @@ static void sw_quad_clip_and_project(void)
|
|||
|
||||
// Calculation of the reciprocal of W for normalization
|
||||
// as well as perspective-correct attributes
|
||||
const float wRcp = 1.0f/v->position[3];
|
||||
const float wRcp = sw_rcp(v->position[3]);
|
||||
|
||||
// Division of XYZ coordinates by weight
|
||||
v->position[0] *= wRcp;
|
||||
|
|
@ -3655,8 +3757,8 @@ static bool sw_line_clip_and_project(sw_vertex_t *v0, sw_vertex_t *v1)
|
|||
if (!sw_line_clip(v0, v1)) return false;
|
||||
|
||||
// Convert clip coordinates to NDC
|
||||
v0->position[3] = 1.0f/v0->position[3];
|
||||
v1->position[3] = 1.0f/v1->position[3];
|
||||
v0->position[3] = sw_rcp(v0->position[3]);
|
||||
v1->position[3] = sw_rcp(v1->position[3]);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
v0->position[i] *= v0->position[3];
|
||||
|
|
@ -3705,7 +3807,7 @@ static bool sw_point_clip_and_project(sw_vertex_t *v)
|
|||
if ((v->position[i] < -v->position[3]) || (v->position[i] > v->position[3])) return false;
|
||||
}
|
||||
|
||||
v->position[3] = 1.0f/v->position[3];
|
||||
v->position[3] = sw_rcp(v->position[3]);
|
||||
v->position[0] *= v->position[3];
|
||||
v->position[1] *= v->position[3];
|
||||
v->position[2] *= v->position[3];
|
||||
|
|
@ -3787,6 +3889,19 @@ static void sw_immediate_begin(SWdraw mode)
|
|||
RLSW.stackModelview[RLSW.stackModelviewCounter - 1],
|
||||
RLSW.stackProjection[RLSW.stackProjectionCounter - 1]);
|
||||
|
||||
#ifdef SW_HAS_ESP_DSP
|
||||
// Pre-transpose to row-major so dspm_mult_4x4x1_f32(matMVP_rm, v, out)
|
||||
// computes M*v directly in the per-vertex hot path. 16 scalar copies
|
||||
// per MVP update vs. saving ~20 cycles per vertex transform.
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
RLSW.matMVP_rm[4*i + j] = RLSW.matMVP[4*j + i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
RLSW.isDirtyMVP = false;
|
||||
}
|
||||
|
||||
|
|
@ -3838,11 +3953,17 @@ static void sw_immediate_push_vertex(const float position[4])
|
|||
sw_vertex_t *vertex = &RLSW.primitive.buffer[RLSW.primitive.vertexCount++];
|
||||
|
||||
// Calculate clip coordinates
|
||||
#ifdef SW_HAS_ESP_DSP
|
||||
// dspm_mult_4x4x1_f32 declares its inputs non-const; rlsw treats them as
|
||||
// read-only and the cast is safe (the kernel only loads from B).
|
||||
dspm_mult_4x4x1_f32(RLSW.matMVP_rm, (float *)position, vertex->position);
|
||||
#else
|
||||
const float *m = RLSW.matMVP;
|
||||
vertex->position[0] = m[0]*position[0] + m[4]*position[1] + m[8]*position[2] + m[12]*position[3];
|
||||
vertex->position[1] = m[1]*position[0] + m[5]*position[1] + m[9]*position[2] + m[13]*position[3];
|
||||
vertex->position[2] = m[2]*position[0] + m[6]*position[1] + m[10]*position[2] + m[14]*position[3];
|
||||
vertex->position[3] = m[3]*position[0] + m[7]*position[1] + m[11]*position[2] + m[15]*position[3];
|
||||
#endif
|
||||
|
||||
// Copy the attributes in the current vertex
|
||||
for (int i = 0; i < 4; i++) vertex->color[i] = RLSW.primitive.color[i];
|
||||
|
|
@ -4160,6 +4281,7 @@ const char *swGetString(SWget name)
|
|||
case SW_RENDERER: result = "RLSW OpenGL Software Renderer"; break;
|
||||
case SW_VERSION: result = RLSW_VERSION; break;
|
||||
case SW_EXTENSIONS: result = "None"; break;
|
||||
case SW_SHADING_LANGUAGE_VERSION: result = "Not supported"; break;
|
||||
default: RLSW.errCode = SW_INVALID_ENUM; break;
|
||||
}
|
||||
|
||||
|
|
@ -5171,7 +5293,7 @@ void swFramebufferTexture2D(SWattachment attach, uint32_t texture)
|
|||
RLSW.colorBuffer = sw_pool_get(&RLSW.texturePool, texture);
|
||||
} break;
|
||||
case SW_DEPTH_ATTACHMENT:
|
||||
{
|
||||
{
|
||||
fb->depthAttachment = texture;
|
||||
RLSW.depthBuffer = sw_pool_get(&RLSW.texturePool, texture);
|
||||
} break;
|
||||
|
|
@ -5262,13 +5384,13 @@ void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWattachget
|
|||
|
||||
static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t *end, float dUdy, float dVdy)
|
||||
{
|
||||
// Gets the start/end coordinates and skip empty lines
|
||||
// Gets the start/end coordinates and skip empty lines
|
||||
int xStart = (int)start->position[0];
|
||||
int xEnd = (int)end->position[0];
|
||||
if (xStart == xEnd) return;
|
||||
|
||||
// Compute the inverse horizontal distance along the X axis
|
||||
float dxRcp = 1.0f/(end->position[0] - start->position[0]);
|
||||
float dxRcp = sw_rcp(end->position[0] - start->position[0]);
|
||||
|
||||
// Compute the interpolation steps along the X axis
|
||||
float dWdx = (end->position[3] - start->position[3])*dxRcp;
|
||||
|
|
@ -5322,12 +5444,12 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t
|
|||
int blockEnd = x + SW_AFFINE_BLOCK;
|
||||
if (blockEnd > xEnd) blockEnd = xEnd;
|
||||
float blockLenF = (float)(blockEnd - x);
|
||||
float blockLenRcp = 1.0f/blockLenF;
|
||||
float blockLenRcp = sw_rcp(blockLenF);
|
||||
|
||||
// Only 2 '1/w' here; none inside the pixel loop
|
||||
float wRcpA = 1.0f/w;
|
||||
float wRcpA = sw_rcp(w);
|
||||
float wB = w + dWdx*blockLenF;
|
||||
float wRcpB = 1.0f/wB;
|
||||
float wRcpB = sw_rcp(wB);
|
||||
|
||||
// Perspective-correct color at both block endpoints, then affine gradient
|
||||
float srcColor[4] = {
|
||||
|
|
@ -5398,7 +5520,9 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef SW_ENABLE_DEPTH_TEST
|
||||
discard:
|
||||
#endif
|
||||
srcColor[0] += dSrcColordx[0];
|
||||
srcColor[1] += dSrcColordx[1];
|
||||
srcColor[2] += dSrcColordx[2];
|
||||
|
|
@ -5443,9 +5567,10 @@ static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, con
|
|||
if (v0->position[1] > v1->position[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; }
|
||||
|
||||
// Extracting coordinates from the sorted vertices
|
||||
float x0 = v0->position[0], y0 = v0->position[1];
|
||||
float x1 = v1->position[0], y1 = v1->position[1];
|
||||
float x2 = v2->position[0], y2 = v2->position[1];
|
||||
// Put x away for safe keeping. Only y is used right now. Silences warnings.
|
||||
float y0 = v0->position[1];
|
||||
float y1 = v1->position[1];
|
||||
float y2 = v2->position[1];
|
||||
|
||||
// Compute height differences
|
||||
float h02 = y2 - y0;
|
||||
|
|
@ -5455,9 +5580,9 @@ static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, con
|
|||
if (h02 < 1e-6f) return;
|
||||
|
||||
// Inverse edge dy for per-edge dV/dy (scanline interpolation)
|
||||
float h02Rcp = 1.0f/h02;
|
||||
float h01Rcp = (h01 > 1e-6f)? 1.0f/h01 : 0.0f;
|
||||
float h12Rcp = (h12 > 1e-6f)? 1.0f/h12 : 0.0f;
|
||||
float h02Rcp = sw_rcp(h02);
|
||||
float h01Rcp = (h01 > 1e-6f)? sw_rcp(h01) : 0.0f;
|
||||
float h12Rcp = (h12 > 1e-6f)? sw_rcp(h12) : 0.0f;
|
||||
|
||||
// Compute gradients for each side of the triangle
|
||||
sw_vertex_t dVXdy02, dVXdy01, dVXdy12;
|
||||
|
|
@ -5556,8 +5681,8 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
|
|||
float h = (float)(yMax - yMin);
|
||||
if ((w <= 0) || (h <= 0)) return;
|
||||
|
||||
float wRcp = 1.0f/w;
|
||||
float hRcp = 1.0f/h;
|
||||
float wRcp = sw_rcp(w);
|
||||
float hRcp = sw_rcp(h);
|
||||
|
||||
// Subpixel corrections
|
||||
float xSubstep = 1.0f - sw_fract(tl->position[0]);
|
||||
|
|
@ -5655,7 +5780,9 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef SW_ENABLE_DEPTH_TEST
|
||||
discard:
|
||||
#endif
|
||||
color[0] += dCdx[0];
|
||||
color[1] += dCdx[1];
|
||||
color[2] += dCdx[2];
|
||||
|
|
@ -5742,7 +5869,7 @@ static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1)
|
|||
// Compute per pixel increments
|
||||
float xInc = dx/steps;
|
||||
float yInc = dy/steps;
|
||||
float stepRcp = 1.0f/steps;
|
||||
float stepRcp = sw_rcp(steps);
|
||||
#ifdef SW_ENABLE_DEPTH_TEST
|
||||
float zInc = (v1->position[2] - v0->position[2])*stepRcp;
|
||||
#endif
|
||||
|
|
@ -5808,7 +5935,9 @@ static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef SW_ENABLE_DEPTH_TEST
|
||||
discard:
|
||||
#endif
|
||||
x += xInc;
|
||||
y += yInc;
|
||||
#ifdef SW_ENABLE_DEPTH_TEST
|
||||
|
|
|
|||
662
src/external/stb_image_resize2.h
vendored
662
src/external/stb_image_resize2.h
vendored
File diff suppressed because it is too large
Load diff
12
src/external/win32_clipboard.h
vendored
12
src/external/win32_clipboard.h
vendored
|
|
@ -4,14 +4,14 @@
|
|||
|
||||
#ifndef WIN32_CLIPBOARD_
|
||||
#define WIN32_CLIPBOARD_
|
||||
unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned long long int *dataSize);
|
||||
unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned int *dataSize);
|
||||
#endif // WIN32_CLIPBOARD_
|
||||
|
||||
#ifdef WIN32_CLIPBOARD_IMPLEMENTATION
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
// NOTE: These search for architecture is taken from "windows.h", and it's necessary to avoid including windows.h
|
||||
// and still make it compile on msvc, because import indirectly importing "winnt.h" (e.g. <minwindef.h>) can cause problems is these are not defined
|
||||
|
|
@ -213,7 +213,7 @@ static int GetPixelDataOffset(BITMAPINFOHEADER bih); // Get pixel data offset fr
|
|||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned long long int *dataSize)
|
||||
unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned int *dataSize)
|
||||
{
|
||||
unsigned char *bmpData = NULL;
|
||||
|
||||
|
|
@ -228,7 +228,7 @@ unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned long
|
|||
*width = bmpInfoHeader->biWidth;
|
||||
*height = bmpInfoHeader->biHeight;
|
||||
SIZE_T clipDataSize = GlobalSize(clipHandle);
|
||||
if (clipDataSize >= sizeof(BITMAPINFOHEADER))
|
||||
if ((clipDataSize >= sizeof(BITMAPINFOHEADER)) && (clipDataSize < INT_MAX))
|
||||
{
|
||||
int pixelOffset = GetPixelDataOffset(*bmpInfoHeader);
|
||||
|
||||
|
|
@ -236,7 +236,7 @@ unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned long
|
|||
//------------------------------------------------------------------------
|
||||
BITMAPFILEHEADER bmpFileHeader = { 0 };
|
||||
SIZE_T bmpFileSize = sizeof(bmpFileHeader) + clipDataSize;
|
||||
*dataSize = bmpFileSize;
|
||||
*dataSize = (unsigned int)bmpFileSize;
|
||||
|
||||
bmpFileHeader.bfType = 0x4D42; // BMP fil type constant
|
||||
bmpFileHeader.bfSize = (DWORD)bmpFileSize; // Up to 4GB works fine
|
||||
|
|
@ -254,7 +254,7 @@ unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned long
|
|||
}
|
||||
else
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "Clipboard data is malformed");
|
||||
TRACELOG(LOG_WARNING, "Clipboard data is not supported (>2GB?)");
|
||||
GlobalUnlock(clipHandle);
|
||||
CloseClipboard();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -616,13 +616,13 @@ void ShowCursor(void)
|
|||
CORE.Input.Mouse.cursorHidden = false;
|
||||
}
|
||||
|
||||
// Hides mouse cursor
|
||||
// Hide mouse cursor
|
||||
void HideCursor(void)
|
||||
{
|
||||
CORE.Input.Mouse.cursorHidden = true;
|
||||
}
|
||||
|
||||
// Enables cursor (unlock cursor)
|
||||
// Enable cursor (unlock cursor)
|
||||
void EnableCursor(void)
|
||||
{
|
||||
// Set cursor position in the middle
|
||||
|
|
@ -656,9 +656,9 @@ double GetTime(void)
|
|||
double time = 0.0;
|
||||
struct timespec ts = { 0 };
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
|
||||
unsigned long long nanoSeconds = (unsigned long long)ts.tv_sec*1000000000LLU + (unsigned long long)ts.tv_nsec;
|
||||
|
||||
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
|
||||
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
|
||||
|
||||
return time;
|
||||
}
|
||||
|
|
@ -1273,27 +1273,28 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
|||
int32_t keycode = AKeyEvent_getKeyCode(event);
|
||||
//int32_t AKeyEvent_getMetaState(event);
|
||||
|
||||
// Handle gamepad button presses and releases
|
||||
// NOTE: Skip gamepad handling if this is a keyboard event, as some devices
|
||||
// report both AINPUT_SOURCE_KEYBOARD and AINPUT_SOURCE_GAMEPAD flags
|
||||
if ((FLAG_IS_SET(source, AINPUT_SOURCE_JOYSTICK) ||
|
||||
FLAG_IS_SET(source, AINPUT_SOURCE_GAMEPAD)) &&
|
||||
!FLAG_IS_SET(source, AINPUT_SOURCE_KEYBOARD))
|
||||
// Handle gamepad button presses and releases. AOSP stamps the
|
||||
// KEYBOARD source bit on every key event from a gamepad, so
|
||||
// discriminate on the keycode rather than gating on source bits.
|
||||
if (FLAG_IS_SET(source, AINPUT_SOURCE_JOYSTICK) ||
|
||||
FLAG_IS_SET(source, AINPUT_SOURCE_GAMEPAD))
|
||||
{
|
||||
// Assuming a single gamepad, "detected" on its input event
|
||||
CORE.Input.Gamepad.ready[0] = true;
|
||||
|
||||
GamepadButton button = AndroidTranslateGamepadButton(keycode);
|
||||
|
||||
if (button == GAMEPAD_BUTTON_UNKNOWN) return 1;
|
||||
|
||||
if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN)
|
||||
if (button != GAMEPAD_BUTTON_UNKNOWN)
|
||||
{
|
||||
CORE.Input.Gamepad.currentButtonState[0][button] = 1;
|
||||
}
|
||||
else CORE.Input.Gamepad.currentButtonState[0][button] = 0; // Key up
|
||||
// Assuming a single gamepad, "detected" on its input event
|
||||
CORE.Input.Gamepad.ready[0] = true;
|
||||
|
||||
return 1; // Handled gamepad button
|
||||
if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN)
|
||||
{
|
||||
CORE.Input.Gamepad.currentButtonState[0][button] = 1;
|
||||
}
|
||||
else CORE.Input.Gamepad.currentButtonState[0][button] = 0; // Key up
|
||||
|
||||
return 1; // Handled gamepad button
|
||||
}
|
||||
// Unknown keycode: fall through to the keyboard handler below.
|
||||
}
|
||||
|
||||
KeyboardKey key = ((keycode > 0) && (keycode < KEYCODE_MAP_SIZE))? mapKeycode[keycode] : KEY_NULL;
|
||||
|
|
|
|||
|
|
@ -111,6 +111,12 @@
|
|||
//----------------------------------------------------------------------------------
|
||||
typedef struct {
|
||||
GLFWwindow *handle; // GLFW window handle (graphic device)
|
||||
#if defined(__linux__) && defined(_GLFW_X11)
|
||||
// Local storage for the window handle returned by glfwGetX11Window
|
||||
// This is needed as X11 handles are integers and may not fit inside a pointer depending on platform
|
||||
// Storing the handle locally and returning a pointer in GetWindowHandle allows the code to work regardless of pointer width
|
||||
XID windowHandleX11;
|
||||
#endif
|
||||
} PlatformData;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -755,12 +761,6 @@ void SetWindowFocused(void)
|
|||
glfwFocusWindow(platform.handle);
|
||||
}
|
||||
|
||||
#if defined(__linux__) && defined(_GLFW_X11)
|
||||
// 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)
|
||||
{
|
||||
|
|
@ -778,17 +778,16 @@ void *GetWindowHandle(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
X11WindowHandle = glfwGetX11Window(platform.handle);
|
||||
return &X11WindowHandle;
|
||||
platform.windowHandleX11 = glfwGetX11Window(platform.handle);
|
||||
return &platform.windowHandleX11;
|
||||
}
|
||||
#else
|
||||
return glfwGetWaylandWindow(platform.handle);
|
||||
#endif
|
||||
#elif defined(_GLFW_X11)
|
||||
// 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;
|
||||
platform.windowHandleX11 = glfwGetX11Window(platform.handle);
|
||||
return &platform.windowHandleX11;
|
||||
#endif
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
|
|
@ -1055,12 +1054,13 @@ Image GetClipboardImage(void)
|
|||
|
||||
#if SUPPORT_CLIPBOARD_IMAGE && SUPPORT_MODULE_RTEXTURES
|
||||
#if defined(_WIN32)
|
||||
unsigned long long int dataSize = 0;
|
||||
|
||||
unsigned int dataSize = 0;
|
||||
void *bmpData = NULL;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
bmpData = (void *)Win32GetClipboardImageData(&width, &height, &dataSize);
|
||||
bmpData = (void *)Win32GetClipboardImageData(&width, &height, &dataSize);
|
||||
|
||||
if (bmpData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data.");
|
||||
else image = LoadImageFromMemory(".bmp", (const unsigned char *)bmpData, (int)dataSize);
|
||||
|
|
@ -1113,7 +1113,7 @@ Image GetClipboardImage(void)
|
|||
XCloseDisplay(dpy);
|
||||
#else
|
||||
TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform");
|
||||
#endif // defined(_WIN32)
|
||||
#endif // _WIN32
|
||||
#else
|
||||
TRACELOG(LOG_WARNING, "Clipboard image: SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly");
|
||||
#endif // SUPPORT_CLIPBOARD_IMAGE
|
||||
|
|
@ -1129,7 +1129,7 @@ void ShowCursor(void)
|
|||
CORE.Input.Mouse.cursorHidden = false;
|
||||
}
|
||||
|
||||
// Hides mouse cursor
|
||||
// Hide mouse cursor
|
||||
void HideCursor(void)
|
||||
{
|
||||
glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
|
|
@ -1137,7 +1137,7 @@ void HideCursor(void)
|
|||
CORE.Input.Mouse.cursorHidden = true;
|
||||
}
|
||||
|
||||
// Enables cursor (unlock cursor)
|
||||
// Enable cursor (unlock cursor)
|
||||
void EnableCursor(void)
|
||||
{
|
||||
glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||
|
|
@ -1151,7 +1151,7 @@ void EnableCursor(void)
|
|||
CORE.Input.Mouse.cursorLocked = false;
|
||||
}
|
||||
|
||||
// Disables cursor (lock cursor)
|
||||
// Disable cursor (lock cursor)
|
||||
void DisableCursor(void)
|
||||
{
|
||||
// Reset mouse position within the window area before disabling cursor
|
||||
|
|
|
|||
363
src/platforms/rcore_desktop_rgfw.c
Executable file → Normal file
363
src/platforms/rcore_desktop_rgfw.c
Executable file → Normal file
|
|
@ -177,6 +177,13 @@ typedef struct {
|
|||
RGFW_window *window; // Native display device (physical screen connection)
|
||||
RGFW_monitor *monitor;
|
||||
mg_gamepads minigamepad;
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
|
||||
RGFW_surface *surface;
|
||||
u8 *surfacePixels;
|
||||
i32 surfaceWidth;
|
||||
i32 surfaceHeight;
|
||||
#endif
|
||||
} PlatformData;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -723,7 +730,7 @@ void SetWindowIcon(Image image)
|
|||
TRACELOG(LOG_WARNING, "RGFW: Window icon image must be in R8G8B8A8 pixel format");
|
||||
return;
|
||||
}
|
||||
RGFW_window_setIcon(platform.window, (u8 *)image.data, image.width, image.height, 4);
|
||||
RGFW_window_setIcon(platform.window, (u8 *)image.data, image.width, image.height, RGFW_formatRGBA8);
|
||||
}
|
||||
|
||||
// Set icon for window
|
||||
|
|
@ -749,8 +756,8 @@ void SetWindowIcons(Image *images, int count)
|
|||
if ((smallIcon == NULL) || ((images[i].width < smallIcon->width) && (images[i].height > smallIcon->height))) smallIcon = &images[i];
|
||||
}
|
||||
|
||||
if (smallIcon != NULL) RGFW_window_setIconEx(platform.window, (u8 *)smallIcon->data, smallIcon->width, smallIcon->height, 4, RGFW_iconWindow);
|
||||
if (bigIcon != NULL) RGFW_window_setIconEx(platform.window, (u8 *)bigIcon->data, bigIcon->width, bigIcon->height, 4, RGFW_iconTaskbar);
|
||||
if (smallIcon != NULL) RGFW_window_setIconEx(platform.window, (u8 *)smallIcon->data, smallIcon->width, smallIcon->height, RGFW_formatRGBA8, RGFW_iconWindow);
|
||||
if (bigIcon != NULL) RGFW_window_setIconEx(platform.window, (u8 *)bigIcon->data, bigIcon->width, bigIcon->height, RGFW_formatRGBA8, RGFW_iconTaskbar);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -821,6 +828,11 @@ void SetWindowSize(int width, int height)
|
|||
CORE.Window.screen.height = height;
|
||||
}
|
||||
|
||||
if (!CORE.Window.usingFbo)
|
||||
{
|
||||
SetupViewport(CORE.Window.screen.width, CORE.Window.screen.height);
|
||||
}
|
||||
|
||||
RGFW_window_resize(platform.window, CORE.Window.screen.width, CORE.Window.screen.height);
|
||||
}
|
||||
|
||||
|
|
@ -1012,15 +1024,15 @@ Image GetClipboardImage(void)
|
|||
#if SUPPORT_CLIPBOARD_IMAGE && SUPPORT_MODULE_RTEXTURES
|
||||
#if defined(_WIN32)
|
||||
|
||||
unsigned long long int dataSize = 0; // moved into _WIN32 scope until other platforms gain support
|
||||
void *fileData = NULL; // moved into _WIN32 scope until other platforms gain support
|
||||
unsigned int dataSize = 0;
|
||||
void *fileData = NULL;
|
||||
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
fileData = (void *)Win32GetClipboardImageData(&width, &height, &dataSize);
|
||||
fileData = (void *)Win32GetClipboardImageData(&width, &height, &dataSize);
|
||||
|
||||
if (fileData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data");
|
||||
else image = LoadImageFromMemory(".bmp", (const unsigned char *)fileData, dataSize);
|
||||
else image = LoadImageFromMemory(".bmp", (const unsigned char *)fileData, (int)dataSize);
|
||||
|
||||
#elif defined(__linux__) && defined(DRGFW_X11)
|
||||
|
||||
|
|
@ -1070,7 +1082,7 @@ Image GetClipboardImage(void)
|
|||
XCloseDisplay(dpy);
|
||||
#else
|
||||
TRACELOG(LOG_WARNING, "Clipboard image: PLATFORM_DESKTOP_RGFW doesn't implement GetClipboardImage() for this OS");
|
||||
#endif // defined(_WIN32)
|
||||
#endif // _WIN32
|
||||
#else
|
||||
TRACELOG(LOG_WARNING, "Clipboard image: SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly");
|
||||
#endif // SUPPORT_CLIPBOARD_IMAGE
|
||||
|
|
@ -1085,14 +1097,14 @@ void ShowCursor(void)
|
|||
CORE.Input.Mouse.cursorHidden = false;
|
||||
}
|
||||
|
||||
// Hides mouse cursor
|
||||
// Hide mouse cursor
|
||||
void HideCursor(void)
|
||||
{
|
||||
RGFW_window_showMouse(platform.window, false);
|
||||
CORE.Input.Mouse.cursorHidden = true;
|
||||
}
|
||||
|
||||
// Enables cursor (unlock cursor)
|
||||
// Enable cursor (unlock cursor)
|
||||
void EnableCursor(void)
|
||||
{
|
||||
RGFW_window_captureRawMouse(platform.window, false);
|
||||
|
|
@ -1104,7 +1116,7 @@ void EnableCursor(void)
|
|||
CORE.Input.Mouse.cursorLocked = true;
|
||||
}
|
||||
|
||||
// Disables cursor (lock cursor)
|
||||
// Disable cursor (lock cursor)
|
||||
void DisableCursor(void)
|
||||
{
|
||||
RGFW_window_captureRawMouse(platform.window, true);
|
||||
|
|
@ -1116,7 +1128,35 @@ void DisableCursor(void)
|
|||
// Swap back buffer with front buffer (screen drawing)
|
||||
void SwapScreenBuffer(void)
|
||||
{
|
||||
RGFW_window_swapBuffers_OpenGL(platform.window);
|
||||
#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
|
||||
{
|
||||
if (platform.surface)
|
||||
{
|
||||
// copy rlsw pixel data to the surface framebuffer
|
||||
swReadPixels(0, 0, platform.surfaceWidth, platform.surfaceHeight, SW_RGBA, SW_UNSIGNED_BYTE, platform.surfacePixels);
|
||||
|
||||
// Mac wants a different pixel order. I cant seem to get this to work any other way
|
||||
#if defined(__APPLE__)
|
||||
unsigned char temp = 0;
|
||||
unsigned char *p = NULL;
|
||||
for (int i = 0; i < (platform.surfaceWidth * platform.surfaceHeight); i += 1)
|
||||
{
|
||||
p = platform.surfacePixels + (i * 4);
|
||||
temp = p[0];
|
||||
p[0] = p[2];
|
||||
p[2] = temp;
|
||||
}
|
||||
#endif
|
||||
|
||||
// blit surface to the window
|
||||
RGFW_window_blitSurface(platform.window, platform.surface);
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
RGFW_window_swapBuffers_OpenGL(platform.window);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -1126,7 +1166,9 @@ void SwapScreenBuffer(void)
|
|||
// Get elapsed time measure in seconds since InitTimer()
|
||||
double GetTime(void)
|
||||
{
|
||||
double time = get_time_seconds() - CORE.Time.base;
|
||||
// CORE.Time.base is nanoseconds as integer
|
||||
double baseTime = (double)CORE.Time.base*1e-9;
|
||||
double time = get_time_seconds() - baseTime;
|
||||
|
||||
return time;
|
||||
}
|
||||
|
|
@ -1308,6 +1350,9 @@ void PollInputEvents(void)
|
|||
// Window events are also polled (Minimized, maximized, close...)
|
||||
case RGFW_windowResized:
|
||||
{
|
||||
// set flag that the window was resized
|
||||
CORE.Window.resizedLastFrame = true;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
|
||||
{
|
||||
|
|
@ -1356,7 +1401,42 @@ void PollInputEvents(void)
|
|||
CORE.Window.currentFbo.width = CORE.Window.screen.width;
|
||||
CORE.Window.currentFbo.height = CORE.Window.screen.height;
|
||||
#endif
|
||||
CORE.Window.resizedLastFrame = true;
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
|
||||
#if defined(__APPLE__)
|
||||
RGFW_monitor* currentMonitor = RGFW_window_getMonitor(platform.window);
|
||||
CORE.Window.screenScale = MatrixScale(currentMonitor->pixelRatio, currentMonitor->pixelRatio, 1.0f);
|
||||
SetupViewport(platform.window->w * currentMonitor->pixelRatio, platform.window->h * currentMonitor->pixelRatio);
|
||||
|
||||
CORE.Window.render.width = CORE.Window.screen.width * currentMonitor->pixelRatio;
|
||||
CORE.Window.render.height = CORE.Window.screen.height * currentMonitor->pixelRatio;
|
||||
CORE.Window.currentFbo.width = CORE.Window.render.width;
|
||||
CORE.Window.currentFbo.height = CORE.Window.render.height;
|
||||
#endif
|
||||
platform.surfaceWidth = CORE.Window.currentFbo.width;
|
||||
platform.surfaceHeight = CORE.Window.currentFbo.height;
|
||||
|
||||
// in software mode we dont have the viewport so we need to reverse the highdpi changes
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
|
||||
{
|
||||
Vector2 scaleDpi = GetWindowScaleDPI();
|
||||
platform.surfaceWidth *= scaleDpi.x;
|
||||
platform.surfaceHeight *= scaleDpi.y;
|
||||
}
|
||||
|
||||
if (platform.surfacePixels != NULL)
|
||||
{
|
||||
RL_FREE(platform.surfacePixels);
|
||||
platform.surfacePixels = RL_MALLOC(platform.surfaceWidth * platform.surfaceHeight * 4);
|
||||
}
|
||||
|
||||
if (platform.surface != NULL)
|
||||
{
|
||||
RGFW_surface_free(platform.surface);
|
||||
platform.surface = RGFW_window_createSurface(platform.window, platform.surfacePixels, platform.surfaceWidth, platform.surfaceHeight, RGFW_formatBGRA8);
|
||||
swResize(platform.surfaceWidth, platform.surfaceHeight);
|
||||
}
|
||||
#endif
|
||||
} break;
|
||||
case RGFW_windowMaximized:
|
||||
{
|
||||
|
|
@ -1447,37 +1527,35 @@ void PollInputEvents(void)
|
|||
} break;
|
||||
case RGFW_mousePosChanged:
|
||||
{
|
||||
float event_x = 0.0f, event_y = 0.0f;
|
||||
float mouseX = 0.0f;
|
||||
float mouseY = 0.0f;
|
||||
if (RGFW_window_isCaptured(platform.window))
|
||||
{
|
||||
event_x = (float)rgfw_event.mouse.vecX;
|
||||
event_y = (float)rgfw_event.mouse.vecY;
|
||||
mouseX = (float)rgfw_event.mouse.vecX;
|
||||
mouseY = (float)rgfw_event.mouse.vecY;
|
||||
}
|
||||
else
|
||||
{
|
||||
event_x = (float)rgfw_event.mouse.x;
|
||||
event_y = (float)rgfw_event.mouse.y;
|
||||
mouseX = (float)rgfw_event.mouse.x;
|
||||
mouseY = (float)rgfw_event.mouse.y;
|
||||
}
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
{
|
||||
double canvasWidth = 0.0;
|
||||
double canvasHeight = 0.0;
|
||||
emscripten_get_element_css_size("#canvas", &canvasWidth, &canvasHeight);
|
||||
event_x *= ((float)GetScreenWidth() / (float)canvasWidth);
|
||||
event_y *= ((float)GetScreenHeight() / (float)canvasHeight);
|
||||
}
|
||||
double canvasWidth = 0.0;
|
||||
double canvasHeight = 0.0;
|
||||
emscripten_get_element_css_size("#canvas", &canvasWidth, &canvasHeight);
|
||||
mouseX *= ((float)GetScreenWidth()/(float)canvasWidth);
|
||||
mouseY *= ((float)GetScreenHeight()/(float)canvasHeight);
|
||||
#endif
|
||||
|
||||
if (RGFW_window_isCaptured(platform.window))
|
||||
{
|
||||
CORE.Input.Mouse.currentPosition.x += event_x;
|
||||
CORE.Input.Mouse.currentPosition.y += event_y;
|
||||
CORE.Input.Mouse.currentPosition.x += mouseX;
|
||||
CORE.Input.Mouse.currentPosition.y += mouseY;
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE.Input.Mouse.currentPosition.x = event_x;
|
||||
CORE.Input.Mouse.currentPosition.y = event_y;
|
||||
CORE.Input.Mouse.currentPosition.x = mouseX;
|
||||
CORE.Input.Mouse.currentPosition.y = mouseY;
|
||||
}
|
||||
|
||||
CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
|
||||
|
|
@ -1599,10 +1677,62 @@ int InitPlatform(void)
|
|||
// Initialize RGFW internal global state, only required systems
|
||||
unsigned int flags = RGFW_windowCenter | RGFW_windowAllowDND;
|
||||
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED)) FLAG_SET(flags, RGFW_windowNoBorder);
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) FLAG_SET(flags, RGFW_windowNoResize);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TRANSPARENT)) FLAG_SET(flags, RGFW_windowTransparent);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) FLAG_SET(flags, RGFW_windowHide);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_SET(flags, RGFW_windowMaximize);
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) FLAG_SET(flags, RGFW_windowFocusOnShow | RGFW_windowFocus);
|
||||
|
||||
if ((CORE.Window.screen.width == 0) || (CORE.Window.screen.height == 0))
|
||||
{
|
||||
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
|
||||
}
|
||||
|
||||
// Check window creation flags
|
||||
|
||||
// Init window in fullscreen mode if requested
|
||||
// NOTE: Keeping original screen size for toggle
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
|
||||
{
|
||||
FLAG_SET(flags, RGFW_windowFullscreen);
|
||||
int result = RGFW_init();
|
||||
if (result != 0)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "RGFW: Failed to initialize RGFW");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// NOTE: Fullscreen applications default to the primary monitor
|
||||
RGFW_monitor *monitor = RGFW_getPrimaryMonitor();
|
||||
if (!monitor)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "RGFW: Failed to get primary monitor");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Default display resolution to that of the current mode
|
||||
CORE.Window.display.width = monitor->mode.w;
|
||||
CORE.Window.display.height = monitor->mode.h;
|
||||
|
||||
// Check if user requested some screen size
|
||||
if ((CORE.Window.screen.width == 0) || (CORE.Window.screen.height == 0))
|
||||
{
|
||||
// Set some default screen size in case user decides to exit fullscreen mode
|
||||
CORE.Window.previousScreen.width = 800;
|
||||
CORE.Window.previousScreen.height = 450;
|
||||
CORE.Window.previousPosition.x = (CORE.Window.display.width - CORE.Window.previousScreen.width)/2;
|
||||
CORE.Window.previousPosition.y = (CORE.Window.display.height - CORE.Window.previousScreen.height)/2;
|
||||
|
||||
// Set screen width/height to the display width/height
|
||||
if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width;
|
||||
if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height;
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE.Window.previousScreen = CORE.Window.screen;
|
||||
CORE.Window.screen = CORE.Window.display;
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE))
|
||||
|
|
@ -1610,16 +1740,16 @@ int InitPlatform(void)
|
|||
FLAG_SET(flags, RGFW_windowedFullscreen);
|
||||
}
|
||||
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED)) FLAG_SET(flags, RGFW_windowNoBorder);
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) FLAG_SET(flags, RGFW_windowNoResize);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TRANSPARENT)) FLAG_SET(flags, RGFW_windowTransparent);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) FLAG_SET(flags, RGFW_windowFullscreen);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) FLAG_SET(flags, RGFW_windowHide);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_SET(flags, RGFW_windowMaximize);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
|
||||
{
|
||||
#if !defined(__APPLE__)
|
||||
CORE.Window.screen.width = CORE.Window.screen.width * GetWindowScaleDPI().x;
|
||||
CORE.Window.screen.height = CORE.Window.screen.height * GetWindowScaleDPI().y;
|
||||
#endif
|
||||
}
|
||||
|
||||
// NOTE: Some OpenGL context attributes must be set before window creation
|
||||
// Check selection OpenGL version
|
||||
|
||||
RGFW_glHints* hints = RGFW_getGlobalHints_OpenGL();
|
||||
if (rlGetVersion() == RL_OPENGL_21)
|
||||
{
|
||||
|
|
@ -1636,22 +1766,16 @@ int InitPlatform(void)
|
|||
hints->major = 4;
|
||||
hints->minor = 3;
|
||||
}
|
||||
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT)) hints->samples = 4;
|
||||
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) FLAG_SET(flags, RGFW_windowFocusOnShow | RGFW_windowFocus);
|
||||
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
|
||||
else if (rlGetVersion() == RL_OPENGL_SOFTWARE)
|
||||
{
|
||||
#if !defined(__APPLE__)
|
||||
CORE.Window.screen.width = CORE.Window.screen.width * GetWindowScaleDPI().x;
|
||||
CORE.Window.screen.height = CORE.Window.screen.height * GetWindowScaleDPI().y;
|
||||
#endif
|
||||
hints->major = 1;
|
||||
hints->minor = 1;
|
||||
hints->renderer = RGFW_glSoftware;
|
||||
}
|
||||
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT)) hints->samples = 4;
|
||||
RGFW_setGlobalHints_OpenGL(hints);
|
||||
|
||||
platform.window = RGFW_createWindow((CORE.Window.title != 0)? CORE.Window.title : " ", 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, flags | RGFW_windowOpenGL);
|
||||
CORE.Time.base = get_time_seconds();
|
||||
|
||||
#ifndef PLATFORM_WEB_RGFW
|
||||
i32 screenSizeWidth;
|
||||
|
|
@ -1716,7 +1840,41 @@ int InitPlatform(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
|
||||
#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
|
||||
// apple always scales for retina
|
||||
#if defined(__APPLE__)
|
||||
RGFW_monitor* currentMonitor = RGFW_window_getMonitor(platform.window);
|
||||
CORE.Window.screenScale = MatrixScale(currentMonitor->pixelRatio, currentMonitor->pixelRatio, 1.0f);
|
||||
|
||||
CORE.Window.render.width = CORE.Window.screen.width * currentMonitor->pixelRatio;
|
||||
CORE.Window.render.height = CORE.Window.screen.height * currentMonitor->pixelRatio;
|
||||
CORE.Window.currentFbo.width = CORE.Window.render.width;
|
||||
CORE.Window.currentFbo.height = CORE.Window.render.height;
|
||||
#endif
|
||||
|
||||
platform.surfaceWidth = CORE.Window.currentFbo.width;
|
||||
platform.surfaceHeight = CORE.Window.currentFbo.height;
|
||||
|
||||
platform.surfacePixels = RL_MALLOC(platform.surfaceWidth * platform.surfaceHeight * 4);
|
||||
if (platform.surfacePixels == NULL)
|
||||
{
|
||||
TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize software pixel buffer");
|
||||
return -1;
|
||||
}
|
||||
|
||||
platform.surface = RGFW_window_createSurface(platform.window, platform.surfacePixels, platform.surfaceWidth, platform.surfaceHeight, RGFW_formatBGRA8);
|
||||
|
||||
if (platform.surface == NULL)
|
||||
{
|
||||
RL_FREE(platform.surfacePixels);
|
||||
|
||||
TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize software surface");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully %s",
|
||||
FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)? "(HighDPI)" : "");
|
||||
TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
|
||||
TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
|
||||
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
|
||||
|
|
@ -1745,20 +1903,63 @@ int InitPlatform(void)
|
|||
//----------------------------------------------------------------------------
|
||||
|
||||
#if defined(RGFW_WAYLAND)
|
||||
if (RGFW_usingWayland()) TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Wayland): Initialized successfully");
|
||||
else TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11 (fallback)): Initialized successfully");
|
||||
if (rlGetVersion() == RL_OPENGL_SOFTWARE)
|
||||
{
|
||||
if (RGFW_usingWayland()) TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Wayland, Software): Initialized successfully");
|
||||
else TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11, Software (fallback)): Initialized successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RGFW_usingWayland()) TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Wayland): Initialized successfully");
|
||||
else TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11 (fallback)): Initialized successfully");
|
||||
}
|
||||
#elif defined(RGFW_X11)
|
||||
#if defined(__APPLE__)
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11 (MacOS)): Initialized successfully");
|
||||
if (rlGetVersion() == RL_OPENGL_SOFTWARE)
|
||||
{
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11, Software, (MacOS)): Initialized successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11, (MacOS)): Initialized successfully");
|
||||
}
|
||||
#else
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11): Initialized successfully");
|
||||
if (rlGetVersion() == RL_OPENGL_SOFTWARE)
|
||||
{
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11, Software): Initialized successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11): Initialized successfully");
|
||||
}
|
||||
#endif
|
||||
#elif defined (RGFW_WINDOWS)
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Win32): Initialized successfully");
|
||||
if (rlGetVersion() == RL_OPENGL_SOFTWARE)
|
||||
{
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Win32, Software): Initialized successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Win32): Initialized successfully");
|
||||
}
|
||||
#elif defined(RGFW_WASM)
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - WASMs): Initialized successfully");
|
||||
if (rlGetVersion() == RL_OPENGL_SOFTWARE)
|
||||
{
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - WASMs, Software): Initialized successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - WASMs): Initialized successfully");
|
||||
}
|
||||
#elif defined(RGFW_MACOS)
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - MacOS): Initialized successfully");
|
||||
if (rlGetVersion() == RL_OPENGL_SOFTWARE)
|
||||
{
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - MacOS, Software): Initialized successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - MacOS): Initialized successfully");
|
||||
}
|
||||
#endif
|
||||
|
||||
mg_gamepads_init(&platform.minigamepad);
|
||||
|
|
@ -1771,6 +1972,18 @@ void ClosePlatform(void)
|
|||
{
|
||||
mg_gamepads_free(&platform.minigamepad);
|
||||
RGFW_window_close(platform.window);
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
|
||||
if (platform.surfacePixels != NULL)
|
||||
{
|
||||
RL_FREE(platform.surfacePixels);
|
||||
}
|
||||
|
||||
if (platform.surface != NULL)
|
||||
{
|
||||
RGFW_surface_free(platform.surface);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Keycode mapping
|
||||
|
|
@ -1788,34 +2001,36 @@ double get_time_seconds(void)
|
|||
|
||||
#if defined(_WIN32)
|
||||
static LARGE_INTEGER freq = { 0 };
|
||||
static int freq_init = 0;
|
||||
LARGE_INTEGER counter;
|
||||
if (!freq_init) {
|
||||
static bool freqInitialized = false;
|
||||
LARGE_INTEGER counter = { 0 };
|
||||
if (!freqInitialized)
|
||||
{
|
||||
// Lazy initialization
|
||||
QueryPerformanceFrequency(&freq);
|
||||
freq_init = 1;
|
||||
freqInitialized = true;
|
||||
}
|
||||
QueryPerformanceCounter(&counter);
|
||||
currentTime = (double)counter.QuadPart / (double)freq.QuadPart;
|
||||
currentTime = (double)counter.QuadPart/(double)freq.QuadPart;
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
currentTime = emscripten_get_now() / 1000.0;
|
||||
currentTime = emscripten_get_now()/1000.0;
|
||||
#elif defined(__APPLE__)
|
||||
static mach_timebase_info_data_t tb;
|
||||
static int tb_initialized = 0;
|
||||
|
||||
if (!tb_initialized) {
|
||||
static mach_timebase_info_data_t tb = { 0 };
|
||||
static bool tbInitialized = false;
|
||||
if (!tbInitialized)
|
||||
{
|
||||
mach_timebase_info(&tb);
|
||||
tb_initialized = 1;
|
||||
tbInitialized = true;
|
||||
}
|
||||
uint64_t ticks = mach_absolute_time();
|
||||
|
||||
currentTime = (double)ticks * (double)tb.numer / (double)tb.denom / 1e9;
|
||||
currentTime = (double)ticks*(double)tb.numer/(double)tb.denom/1e9;
|
||||
#elif defined(__linux__)
|
||||
struct timespec ts;
|
||||
struct timespec ts = { 0 };
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
currentTime = (double)ts.tv_sec + (double)ts.tv_nsec / 1e9;
|
||||
currentTime = (double)ts.tv_sec + (double)ts.tv_nsec/1e9;
|
||||
#else
|
||||
// fallback to cstd
|
||||
currentTime = (double)clock() / (double)CLOCKS_PER_SEC;
|
||||
// Fallback to cstd
|
||||
currentTime = (double)clock()/(double)CLOCKS_PER_SEC;
|
||||
#endif
|
||||
|
||||
return currentTime;
|
||||
|
|
|
|||
|
|
@ -1144,7 +1144,7 @@ const char *GetClipboardText(void)
|
|||
|
||||
char *clipboard = SDL_GetClipboardText();
|
||||
|
||||
int clipboardSize = snprintf(buffer, sizeof(buffer), "%s", clipboard);
|
||||
int clipboardSize = snprintf(buffer, MAX_CLIPBOARD_BUFFER_LENGTH, "%s", clipboard);
|
||||
if (clipboardSize >= MAX_CLIPBOARD_BUFFER_LENGTH)
|
||||
{
|
||||
char *truncate = buffer + MAX_CLIPBOARD_BUFFER_LENGTH - 4;
|
||||
|
|
@ -1227,7 +1227,7 @@ void ShowCursor(void)
|
|||
CORE.Input.Mouse.cursorHidden = false;
|
||||
}
|
||||
|
||||
// Hides mouse cursor
|
||||
// Hide mouse cursor
|
||||
void HideCursor(void)
|
||||
{
|
||||
#if defined(USING_VERSION_SDL3)
|
||||
|
|
@ -1238,7 +1238,7 @@ void HideCursor(void)
|
|||
CORE.Input.Mouse.cursorHidden = true;
|
||||
}
|
||||
|
||||
// Enables cursor (unlock cursor)
|
||||
// Enable cursor (unlock cursor)
|
||||
void EnableCursor(void)
|
||||
{
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
|
|
@ -1247,7 +1247,7 @@ void EnableCursor(void)
|
|||
CORE.Input.Mouse.cursorLocked = false;
|
||||
}
|
||||
|
||||
// Disables cursor (lock cursor)
|
||||
// Disable cursor (lock cursor)
|
||||
void DisableCursor(void)
|
||||
{
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
|
|
@ -1528,6 +1528,10 @@ void PollInputEvents(void)
|
|||
if ((width + borderLeft + borderRight != usableBounds.w) && (height + borderTop + borderBottom != usableBounds.h)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
|
||||
swResize(width, height);
|
||||
#endif
|
||||
} break;
|
||||
|
||||
case SDL_WINDOWEVENT_ENTER: CORE.Input.Mouse.cursorOnScreen = true; break;
|
||||
|
|
@ -1671,8 +1675,13 @@ void PollInputEvents(void)
|
|||
} break;
|
||||
case SDL_MOUSEWHEEL:
|
||||
{
|
||||
CORE.Input.Mouse.currentWheelMove.x = (float)event.wheel.x;
|
||||
CORE.Input.Mouse.currentWheelMove.y = (float)event.wheel.y;
|
||||
#if defined(USING_VERSION_SDL3)
|
||||
CORE.Input.Mouse.currentWheelMove.x = event.wheel.x;
|
||||
CORE.Input.Mouse.currentWheelMove.y = event.wheel.y;
|
||||
#else
|
||||
CORE.Input.Mouse.currentWheelMove.x = event.wheel.preciseX;
|
||||
CORE.Input.Mouse.currentWheelMove.y = event.wheel.preciseY;
|
||||
#endif
|
||||
} break;
|
||||
case SDL_MOUSEMOTION:
|
||||
{
|
||||
|
|
@ -2064,7 +2073,8 @@ int InitPlatform(void)
|
|||
CORE.Window.currentFbo.width = CORE.Window.render.width;
|
||||
CORE.Window.currentFbo.height = CORE.Window.render.height;
|
||||
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully %s",
|
||||
FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)? "(HighDPI)" : "");
|
||||
TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
|
||||
TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
|
||||
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
|
||||
|
|
|
|||
|
|
@ -1063,14 +1063,14 @@ Vector2 GetMonitorPosition(int monitor)
|
|||
// Get selected monitor width (currently used by monitor)
|
||||
int GetMonitorWidth(int monitor)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetMonitorWidth not implemented");
|
||||
//TRACELOG(LOG_WARNING, "GetMonitorWidth not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get selected monitor height (currently used by monitor)
|
||||
int GetMonitorHeight(int monitor)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetMonitorHeight not implemented");
|
||||
//TRACELOG(LOG_WARNING, "GetMonitorHeight not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1105,7 +1105,7 @@ const char *GetMonitorName(int monitor)
|
|||
// Get window position XY on monitor
|
||||
Vector2 GetWindowPosition(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetWindowPosition not implemented");
|
||||
//TRACELOG(LOG_WARNING, "GetWindowPosition not implemented");
|
||||
return (Vector2){ 0, 0 };
|
||||
}
|
||||
|
||||
|
|
@ -1146,7 +1146,7 @@ void ShowCursor(void)
|
|||
CORE.Input.Mouse.cursorHidden = false;
|
||||
}
|
||||
|
||||
// Hides mouse cursor
|
||||
// Hide mouse cursor
|
||||
void HideCursor(void)
|
||||
{
|
||||
// NOTE: Using SetCursor() instead of ShowCursor() because
|
||||
|
|
@ -1155,7 +1155,7 @@ void HideCursor(void)
|
|||
CORE.Input.Mouse.cursorHidden = true;
|
||||
}
|
||||
|
||||
// Enables cursor (unlock cursor)
|
||||
// Enable cursor (unlock cursor)
|
||||
void EnableCursor(void)
|
||||
{
|
||||
if (CORE.Input.Mouse.cursorLocked)
|
||||
|
|
@ -1526,7 +1526,6 @@ int InitPlatform(void)
|
|||
if (hr < 0) TRACELOG(LOG_ERROR, "%s failed, hresult=0x%lx", "SetProcessDpiAwareness", (DWORD)hr);
|
||||
}
|
||||
*/
|
||||
|
||||
HINSTANCE hInstance = GetModuleHandleW(0);
|
||||
|
||||
// Define window class
|
||||
|
|
@ -1643,7 +1642,8 @@ int InitPlatform(void)
|
|||
CORE.Window.render.height = CORE.Window.screen.height;
|
||||
CORE.Window.currentFbo.width = CORE.Window.render.width;
|
||||
CORE.Window.currentFbo.height = CORE.Window.render.height;
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully %s",
|
||||
FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)? "(HighDPI)" : "");
|
||||
TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
|
||||
TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
|
||||
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
|
||||
|
|
@ -1760,13 +1760,31 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
|
|||
memset(CORE.Input.Keyboard.previousKeyState, 0, sizeof(CORE.Input.Keyboard.previousKeyState));
|
||||
memset(CORE.Input.Keyboard.currentKeyState, 0, sizeof(CORE.Input.Keyboard.currentKeyState));
|
||||
} break;
|
||||
case WM_SIZING:
|
||||
case WM_SIZING: // Sent to a window that the user is resizing
|
||||
{
|
||||
if (!(CORE.Window.flags & FLAG_WINDOW_RESIZABLE))
|
||||
TRACELOG(LOG_WARNING, "WIN32: WINDOW: Trying to resize a non-resizable window");
|
||||
if (CORE.Window.flags & FLAG_WINDOW_RESIZABLE)
|
||||
{
|
||||
//HandleWindowResize(hwnd, &platform.appScreenWidth, &platform.appScreenHeight);
|
||||
}
|
||||
|
||||
result = TRUE;
|
||||
} break;
|
||||
case WM_SIZE:
|
||||
{
|
||||
// WARNING: Don't trust the docs, they say this message can not be obtained if not calling DefWindowProc()
|
||||
// in response to WM_WINDOWPOSCHANGED but looks like when a window is created,
|
||||
// this message can be obtained without getting WM_WINDOWPOSCHANGED
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
|
||||
// WARNING: Waiting two frames before resizing because software-renderer backend is initilized with swInit() later
|
||||
// than InitPlatform(), that triggers WM_SIZE, so avoid crashing
|
||||
if (CORE.Time.frameCounter > 2) HandleWindowResize(hwnd, &platform.appScreenWidth, &platform.appScreenHeight);
|
||||
#else
|
||||
// NOTE: This message is only triggered on window creation
|
||||
HandleWindowResize(hwnd, &platform.appScreenWidth, &platform.appScreenHeight);
|
||||
#endif
|
||||
result = 0; // If an application processes WM_SIZE message, it should return zero
|
||||
} break;
|
||||
case WM_GETMINMAXINFO:
|
||||
{
|
||||
DWORD style = MakeWindowStyle(platform.desiredFlags);
|
||||
|
|
@ -1865,19 +1883,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
|
|||
default: break;
|
||||
}
|
||||
} break;
|
||||
case WM_SIZE:
|
||||
{
|
||||
// WARNING: Don't trust the docs, they say this message can not be obtained if not calling DefWindowProc()
|
||||
// in response to WM_WINDOWPOSCHANGED but looks like when a window is created,
|
||||
// this message can be obtained without getting WM_WINDOWPOSCHANGED
|
||||
// WARNING: This call fails for Software-Renderer backend
|
||||
//HandleWindowResize(hwnd, &platform.appScreenWidth, &platform.appScreenHeight);
|
||||
} break;
|
||||
//case WM_MOVE
|
||||
//case WM_MOVE: break;
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
{
|
||||
WINDOWPOS *pos = (WINDOWPOS*)lparam;
|
||||
if (!(pos->flags & SWP_NOSIZE)) HandleWindowResize(hwnd, &platform.appScreenWidth, &platform.appScreenHeight);
|
||||
|
||||
DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
} break;
|
||||
case WM_GETDPISCALEDSIZE:
|
||||
{
|
||||
|
|
@ -2091,6 +2103,10 @@ static void HandleWindowResize(HWND hwnd, int *width, int *height)
|
|||
|
||||
CORE.Window.screenScale = MatrixScale( (float)CORE.Window.render.width/CORE.Window.screen.width,
|
||||
(float)CORE.Window.render.height/CORE.Window.screen.height, 1.0f);
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
|
||||
swResize(clientSize.cx, clientSize.cy);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Update window style
|
||||
|
|
|
|||
|
|
@ -266,9 +266,12 @@ static void PollKeyboardEvents(void); // Process evdev keyboard events
|
|||
static void PollGamepadEvents(void); // Process evdev gamepad events
|
||||
static void PollMouseEvents(void); // Process evdev mouse events
|
||||
|
||||
// Not used by software rendering.
|
||||
#if !defined(GRAPHICS_API_OPENGL_SOFTWARE)
|
||||
static int FindMatchingConnectorMode(const drmModeConnector *connector, const drmModeModeInfo *mode); // Search matching DRM mode in connector's mode list
|
||||
static int FindExactConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search exactly matching DRM connector mode in connector's list
|
||||
static int FindNearestConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search the nearest matching DRM connector mode in connector's list
|
||||
#endif
|
||||
|
||||
static void SetupFramebuffer(int width, int height); // Setup main framebuffer (required by InitPlatform())
|
||||
|
||||
|
|
@ -561,13 +564,13 @@ void ShowCursor(void)
|
|||
CORE.Input.Mouse.cursorHidden = false;
|
||||
}
|
||||
|
||||
// Hides mouse cursor
|
||||
// Hide mouse cursor
|
||||
void HideCursor(void)
|
||||
{
|
||||
CORE.Input.Mouse.cursorHidden = true;
|
||||
}
|
||||
|
||||
// Enables cursor (unlock cursor)
|
||||
// Enable cursor (unlock cursor)
|
||||
void EnableCursor(void)
|
||||
{
|
||||
// Set cursor position in the middle
|
||||
|
|
@ -577,7 +580,7 @@ void EnableCursor(void)
|
|||
CORE.Input.Mouse.cursorLocked = false;
|
||||
}
|
||||
|
||||
// Disables cursor (lock cursor)
|
||||
// Disable cursor (lock cursor)
|
||||
void DisableCursor(void)
|
||||
{
|
||||
// Set cursor position in the middle
|
||||
|
|
@ -837,14 +840,8 @@ void SwapScreenBuffer(void)
|
|||
uint32_t height = mode->vdisplay;
|
||||
|
||||
// Dumb buffers use a fixed format based on bpp
|
||||
#if SW_COLOR_BUFFER_BITS == 24
|
||||
const uint32_t bpp = 32; // 32 bits per pixel (XRGB8888 format)
|
||||
const uint32_t depth = 24; // Color depth, here only 24 bits, alpha is not used
|
||||
#else
|
||||
// REVIEW: Not sure how it will be interpreted (RGB or RGBA?)
|
||||
const uint32_t bpp = SW_COLOR_BUFFER_BITS;
|
||||
const uint32_t depth = SW_COLOR_BUFFER_BITS;
|
||||
#endif
|
||||
|
||||
// Create a dumb buffer for software rendering
|
||||
struct drm_mode_create_dumb creq = { 0 };
|
||||
|
|
@ -899,7 +896,7 @@ void SwapScreenBuffer(void)
|
|||
|
||||
// Copy the software rendered buffer to the dumb buffer with scaling if needed
|
||||
// NOTE: RLSW will make a simple copy if the dimensions match
|
||||
swBlitFramebuffer(0, 0, width, height, 0, 0, width, height, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
|
||||
swBlitPixels(0, 0, width, height, 0, 0, width, height, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
|
||||
|
||||
// Unmap the buffer
|
||||
munmap(dumbBuffer, creq.size);
|
||||
|
|
@ -1009,9 +1006,9 @@ double GetTime(void)
|
|||
double time = 0.0;
|
||||
struct timespec ts = { 0 };
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
|
||||
unsigned long long nanoSeconds = (unsigned long long)ts.tv_sec*1000000000LLU + (unsigned long long)ts.tv_nsec;
|
||||
|
||||
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
|
||||
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
|
||||
|
||||
return time;
|
||||
}
|
||||
|
|
@ -1432,7 +1429,7 @@ int InitPlatform(void)
|
|||
if (eglGetPlatformDisplayEXT != NULL) platform.device = eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_KHR, platform.gbmDevice, NULL);
|
||||
}
|
||||
|
||||
// In case extension not found or display could not be retrieved, try useing legacy version
|
||||
// In case extension not found or display could not be retrieved, try using legacy version
|
||||
if (platform.device == EGL_NO_DISPLAY) platform.device = eglGetDisplay((EGLNativeDisplayType)platform.gbmDevice);
|
||||
#endif
|
||||
if (platform.device == EGL_NO_DISPLAY)
|
||||
|
|
@ -1555,12 +1552,6 @@ int InitPlatform(void)
|
|||
CORE.Window.render.height = CORE.Window.screen.height;
|
||||
CORE.Window.currentFbo.width = CORE.Window.render.width;
|
||||
CORE.Window.currentFbo.height = CORE.Window.render.height;
|
||||
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
|
||||
TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
|
||||
TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
|
||||
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
|
||||
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1586,13 +1577,14 @@ int InitPlatform(void)
|
|||
CORE.Window.render.height = CORE.Window.screen.height;
|
||||
CORE.Window.currentFbo.width = CORE.Window.render.width;
|
||||
CORE.Window.currentFbo.height = CORE.Window.render.height;
|
||||
#endif
|
||||
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully (Software Rendering)");
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully %s",
|
||||
FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)? "(HighDPI)" : "");
|
||||
TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
|
||||
TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
|
||||
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
|
||||
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
|
||||
#endif
|
||||
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) MinimizeWindow();
|
||||
|
||||
|
|
@ -2571,6 +2563,7 @@ static void PollMouseEvents(void)
|
|||
}
|
||||
}
|
||||
|
||||
#if !defined(GRAPHICS_API_OPENGL_SOFTWARE)
|
||||
// Search matching DRM mode in connector's mode list
|
||||
static int FindMatchingConnectorMode(const drmModeConnector *connector, const drmModeModeInfo *mode)
|
||||
{
|
||||
|
|
@ -2659,6 +2652,7 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
|
|||
|
||||
return nearestIndex;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Compute framebuffer size relative to screen size and display size
|
||||
// NOTE: Global variables CORE.Window.render.width/CORE.Window.render.height and CORE.Window.renderOffset.x/CORE.Window.renderOffset.y can be modified
|
||||
|
|
|
|||
|
|
@ -324,13 +324,13 @@ void ShowCursor(void)
|
|||
CORE.Input.Mouse.cursorHidden = false;
|
||||
}
|
||||
|
||||
// Hides mouse cursor
|
||||
// Hide mouse cursor
|
||||
void HideCursor(void)
|
||||
{
|
||||
CORE.Input.Mouse.cursorHidden = true;
|
||||
}
|
||||
|
||||
// Enables cursor (unlock cursor)
|
||||
// Enable cursor (unlock cursor)
|
||||
void EnableCursor(void)
|
||||
{
|
||||
// Set cursor position in the middle
|
||||
|
|
@ -339,7 +339,7 @@ void EnableCursor(void)
|
|||
CORE.Input.Mouse.cursorHidden = false;
|
||||
}
|
||||
|
||||
// Disables cursor (lock cursor)
|
||||
// Disable cursor (lock cursor)
|
||||
void DisableCursor(void)
|
||||
{
|
||||
// Set cursor position in the middle
|
||||
|
|
@ -364,14 +364,16 @@ double GetTime(void)
|
|||
{
|
||||
double time = 0.0;
|
||||
#if defined(_WIN32)
|
||||
LARGE_INTEGER now = { 0 };
|
||||
QueryPerformanceCounter(&now);
|
||||
return (double)(now.QuadPart - CORE.Time.base)/(double)platform.timerFrequency.QuadPart;
|
||||
LARGE_INTEGER currentTicks = { 0 };
|
||||
QueryPerformanceCounter(¤tTicks);
|
||||
|
||||
time = (double)(currentTicks.QuadPart - CORE.Time.base)/(double)platform.timerFrequency.QuadPart;
|
||||
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
|
||||
struct timespec ts = { 0 };
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
|
||||
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
|
||||
unsigned long long nanoSeconds = (unsigned long long)ts.tv_sec*1000000000LLU + (unsigned long long)ts.tv_nsec;
|
||||
|
||||
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
|
||||
#endif
|
||||
return time;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -303,13 +303,13 @@ void ShowCursor(void)
|
|||
CORE.Input.Mouse.cursorHidden = false;
|
||||
}
|
||||
|
||||
// Hides mouse cursor
|
||||
// Hide mouse cursor
|
||||
void HideCursor(void)
|
||||
{
|
||||
CORE.Input.Mouse.cursorHidden = true;
|
||||
}
|
||||
|
||||
// Enables cursor (unlock cursor)
|
||||
// Enable cursor (unlock cursor)
|
||||
void EnableCursor(void)
|
||||
{
|
||||
// Set cursor position in the middle
|
||||
|
|
@ -318,7 +318,7 @@ void EnableCursor(void)
|
|||
CORE.Input.Mouse.cursorHidden = false;
|
||||
}
|
||||
|
||||
// Disables cursor (lock cursor)
|
||||
// Disable cursor (lock cursor)
|
||||
void DisableCursor(void)
|
||||
{
|
||||
// Set cursor position in the middle
|
||||
|
|
@ -341,10 +341,12 @@ void SwapScreenBuffer(void)
|
|||
double GetTime(void)
|
||||
{
|
||||
double time = 0.0;
|
||||
|
||||
struct timespec ts = { 0 };
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
|
||||
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
|
||||
unsigned long long nanoSeconds = (unsigned long long)ts.tv_sec*1000000000LLU + (unsigned long long)ts.tv_nsec;
|
||||
|
||||
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
|
||||
|
||||
return time;
|
||||
}
|
||||
|
|
@ -474,12 +476,6 @@ int InitPlatform(void)
|
|||
CORE.Window.render.height = CORE.Window.screen.height;
|
||||
CORE.Window.currentFbo.width = CORE.Window.render.width;
|
||||
CORE.Window.currentFbo.height = CORE.Window.render.height;
|
||||
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
|
||||
TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
|
||||
TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
|
||||
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
|
||||
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -494,7 +490,8 @@ int InitPlatform(void)
|
|||
CORE.Window.currentFbo.width = CORE.Window.render.width;
|
||||
CORE.Window.currentFbo.height = CORE.Window.render.height;
|
||||
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully %s",
|
||||
FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)? "(HighDPI)" : "");
|
||||
TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
|
||||
TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
|
||||
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
|
||||
|
|
|
|||
|
|
@ -76,7 +76,6 @@ typedef struct {
|
|||
|
||||
char canvasId[64]; // Keep current canvas id where wasm app is running
|
||||
// NOTE: Useful when trying to run multiple wasms in different canvases in same webpage
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
|
||||
unsigned int *pixels; // Pointer to pixel data buffer (RGBA 32bit format)
|
||||
#endif
|
||||
|
|
@ -913,7 +912,7 @@ void ShowCursor(void)
|
|||
}
|
||||
}
|
||||
|
||||
// Hides mouse cursor
|
||||
// Hide mouse cursor
|
||||
void HideCursor(void)
|
||||
{
|
||||
if (!CORE.Input.Mouse.cursorHidden)
|
||||
|
|
@ -924,7 +923,7 @@ void HideCursor(void)
|
|||
}
|
||||
}
|
||||
|
||||
// Enables cursor (unlock cursor)
|
||||
// Enable cursor (unlock cursor)
|
||||
void EnableCursor(void)
|
||||
{
|
||||
emscripten_exit_pointerlock();
|
||||
|
|
@ -935,7 +934,7 @@ void EnableCursor(void)
|
|||
// NOTE: CORE.Input.Mouse.cursorLocked handled by EmscriptenPointerlockCallback()
|
||||
}
|
||||
|
||||
// Disables cursor (lock cursor)
|
||||
// Disable cursor (lock cursor)
|
||||
void DisableCursor(void)
|
||||
{
|
||||
emscripten_request_pointerlock(platform.canvasId, 1);
|
||||
|
|
@ -1423,7 +1422,8 @@ int InitPlatform(void)
|
|||
CORE.Window.currentFbo.width = fbWidth;
|
||||
CORE.Window.currentFbo.height = fbHeight;
|
||||
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully %s",
|
||||
FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)? "(HighDPI)" : "");
|
||||
TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
|
||||
TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
|
||||
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
|
||||
|
|
|
|||
|
|
@ -891,7 +891,7 @@ void ShowCursor(void)
|
|||
}
|
||||
}
|
||||
|
||||
// Hides mouse cursor
|
||||
// Hide mouse cursor
|
||||
void HideCursor(void)
|
||||
{
|
||||
if (!CORE.Input.Mouse.cursorHidden)
|
||||
|
|
@ -902,7 +902,7 @@ void HideCursor(void)
|
|||
}
|
||||
}
|
||||
|
||||
// Enables cursor (unlock cursor)
|
||||
// Enable cursor (unlock cursor)
|
||||
void EnableCursor(void)
|
||||
{
|
||||
emscripten_exit_pointerlock();
|
||||
|
|
@ -913,7 +913,7 @@ void EnableCursor(void)
|
|||
// NOTE: CORE.Input.Mouse.cursorLocked handled by EmscriptenPointerlockCallback()
|
||||
}
|
||||
|
||||
// Disables cursor (lock cursor)
|
||||
// Disable cursor (lock cursor)
|
||||
void DisableCursor(void)
|
||||
{
|
||||
emscripten_request_pointerlock(platform.canvasId, 1);
|
||||
|
|
@ -1245,7 +1245,8 @@ int InitPlatform(void)
|
|||
CORE.Window.currentFbo.width = fbWidth;
|
||||
CORE.Window.currentFbo.height = fbHeight;
|
||||
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully %s",
|
||||
FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)? "(HighDPI)" : "");
|
||||
TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
|
||||
TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
|
||||
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
|
||||
|
|
|
|||
160
src/raudio.c
160
src/raudio.c
|
|
@ -11,22 +11,22 @@
|
|||
* - Play/Stop/Pause/Resume loaded audio
|
||||
*
|
||||
* CONFIGURATION:
|
||||
* #define SUPPORT_MODULE_RAUDIO
|
||||
* #define SUPPORT_MODULE_RAUDIO 1
|
||||
* 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 SUPPORT_FILEFORMAT_WAV
|
||||
* #define SUPPORT_FILEFORMAT_OGG
|
||||
* #define SUPPORT_FILEFORMAT_MP3
|
||||
* #define SUPPORT_FILEFORMAT_QOA
|
||||
* #define SUPPORT_FILEFORMAT_FLAC
|
||||
* #define SUPPORT_FILEFORMAT_XM
|
||||
* #define SUPPORT_FILEFORMAT_MOD
|
||||
* #define SUPPORT_FILEFORMAT_WAV 1
|
||||
* #define SUPPORT_FILEFORMAT_OGG 1
|
||||
* #define SUPPORT_FILEFORMAT_MP3 1
|
||||
* #define SUPPORT_FILEFORMAT_QOA 1
|
||||
* #define SUPPORT_FILEFORMAT_FLAC 0
|
||||
* #define SUPPORT_FILEFORMAT_XM 1
|
||||
* #define SUPPORT_FILEFORMAT_MOD 1
|
||||
* Selected desired fileformats to be supported for loading. Some of those formats are
|
||||
* supported by default, to remove support, comment unrequired #define in this module
|
||||
* supported by default, to remove support, #define as 0 in this module or your build system
|
||||
*
|
||||
* DEPENDENCIES:
|
||||
* miniaudio.h - Audio device management lib (https://github.com/mackron/miniaudio)
|
||||
|
|
@ -378,7 +378,7 @@ struct rAudioProcessor {
|
|||
rAudioProcessor *prev; // Previous audio processor on the list
|
||||
};
|
||||
|
||||
#define AudioBuffer rAudioBuffer // HACK: To avoid CoreAudio (macOS) symbol collision
|
||||
#define AudioBuffer rAudioBuffer // WARNING: Renamed to avoid symbol collision with CoreAudio (macOS) AudioBuffer type
|
||||
|
||||
// Audio data context
|
||||
typedef struct AudioData {
|
||||
|
|
@ -434,6 +434,7 @@ static const char *GetFileName(const char *filePath); // Get point
|
|||
static const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string)
|
||||
|
||||
static unsigned char *LoadFileData(const char *fileName, int *dataSize); // Load file data as byte array (read)
|
||||
static void UnloadFileData(unsigned char *data); // Unload file data allocated by LoadFileData()
|
||||
static bool SaveFileData(const char *fileName, void *data, int dataSize); // Save data to file from byte array (write)
|
||||
static bool SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated
|
||||
#endif
|
||||
|
|
@ -857,7 +858,7 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int
|
|||
else if ((strcmp(fileType, ".mp3") == 0) || (strcmp(fileType, ".MP3") == 0))
|
||||
{
|
||||
drmp3_config config = { 0 };
|
||||
unsigned long long int totalFrameCount = 0;
|
||||
unsigned long long totalFrameCount = 0;
|
||||
|
||||
// NOTE: Forcing conversion to 32bit float sample size on reading
|
||||
wave.data = drmp3_open_memory_and_read_pcm_frames_f32(fileData, dataSize, &config, &totalFrameCount, NULL);
|
||||
|
|
@ -867,7 +868,7 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int
|
|||
{
|
||||
wave.channels = config.channels;
|
||||
wave.sampleRate = config.sampleRate;
|
||||
wave.frameCount = (int)totalFrameCount;
|
||||
wave.frameCount = (unsigned int)totalFrameCount; // WARNING: Potential loss of data
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "WAVE: Failed to load MP3 data");
|
||||
|
||||
|
|
@ -895,13 +896,13 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int
|
|||
#if SUPPORT_FILEFORMAT_FLAC
|
||||
else if ((strcmp(fileType, ".flac") == 0) || (strcmp(fileType, ".FLAC") == 0))
|
||||
{
|
||||
unsigned long long int totalFrameCount = 0;
|
||||
unsigned long long totalFrameCount = 0;
|
||||
|
||||
// NOTE: Forcing conversion to 16bit sample size on reading
|
||||
wave.data = drflac_open_memory_and_read_pcm_frames_s16(fileData, dataSize, &wave.channels, &wave.sampleRate, &totalFrameCount, NULL);
|
||||
wave.sampleSize = 16;
|
||||
|
||||
if (wave.data != NULL) wave.frameCount = (unsigned int)totalFrameCount;
|
||||
if (wave.data != NULL) wave.frameCount = (unsigned int)totalFrameCount; // WARNING: Potential loss of data
|
||||
else TRACELOG(LOG_WARNING, "WAVE: Failed to load FLAC data");
|
||||
}
|
||||
#endif
|
||||
|
|
@ -912,7 +913,7 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int
|
|||
return wave;
|
||||
}
|
||||
|
||||
// Checks if wave data is valid (data loaded and parameters)
|
||||
// Check if wave data is valid (data loaded and parameters)
|
||||
bool IsWaveValid(Wave wave)
|
||||
{
|
||||
bool result = false;
|
||||
|
|
@ -963,26 +964,24 @@ Sound LoadSoundFromWave(Wave wave)
|
|||
if (frameCount == 0) TRACELOG(LOG_WARNING, "SOUND: Failed to get frame count for format conversion");
|
||||
|
||||
AudioBuffer *audioBuffer = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, frameCount, AUDIO_BUFFER_USAGE_STATIC);
|
||||
if (audioBuffer == NULL)
|
||||
if (audioBuffer != NULL)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SOUND: Failed to create buffer");
|
||||
return sound; // early return to avoid dereferencing the audioBuffer null pointer
|
||||
frameCount = (ma_uint32)ma_convert_frames(audioBuffer->data, frameCount, AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, wave.data, frameCountIn, formatIn, wave.channels, wave.sampleRate);
|
||||
if (frameCount == 0) TRACELOG(LOG_WARNING, "SOUND: Failed format conversion");
|
||||
|
||||
sound.frameCount = frameCount;
|
||||
sound.stream.sampleRate = AUDIO.System.device.sampleRate;
|
||||
sound.stream.sampleSize = 32;
|
||||
sound.stream.channels = AUDIO_DEVICE_CHANNELS;
|
||||
sound.stream.buffer = audioBuffer;
|
||||
}
|
||||
|
||||
frameCount = (ma_uint32)ma_convert_frames(audioBuffer->data, frameCount, AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, wave.data, frameCountIn, formatIn, wave.channels, wave.sampleRate);
|
||||
if (frameCount == 0) TRACELOG(LOG_WARNING, "SOUND: Failed format conversion");
|
||||
|
||||
sound.frameCount = frameCount;
|
||||
sound.stream.sampleRate = AUDIO.System.device.sampleRate;
|
||||
sound.stream.sampleSize = 32;
|
||||
sound.stream.channels = AUDIO_DEVICE_CHANNELS;
|
||||
sound.stream.buffer = audioBuffer;
|
||||
else TRACELOG(LOG_WARNING, "SOUND: Failed to create buffer");
|
||||
}
|
||||
|
||||
return sound;
|
||||
}
|
||||
|
||||
// Clone sound from existing sound data, clone does not own wave data
|
||||
// Load sound alias, clone sound from existing sound data, clone does not own wave data
|
||||
// NOTE: Wave data must be unallocated manually and will be shared across all clones
|
||||
Sound LoadSoundAlias(Sound source)
|
||||
{
|
||||
|
|
@ -992,31 +991,29 @@ Sound LoadSoundAlias(Sound source)
|
|||
{
|
||||
AudioBuffer *audioBuffer = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, 0, AUDIO_BUFFER_USAGE_STATIC);
|
||||
|
||||
if (audioBuffer == NULL)
|
||||
if (audioBuffer != NULL)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SOUND: Failed to create buffer");
|
||||
return sound; // Early return to avoid dereferencing the audioBuffer null pointer
|
||||
audioBuffer->sizeInFrames = source.stream.buffer->sizeInFrames;
|
||||
audioBuffer->data = source.stream.buffer->data;
|
||||
|
||||
// Initalize the buffer as if it was new
|
||||
audioBuffer->volume = 1.0f;
|
||||
audioBuffer->pitch = 1.0f;
|
||||
audioBuffer->pan = 0.0f; // Center
|
||||
|
||||
sound.frameCount = source.frameCount;
|
||||
sound.stream.sampleRate = AUDIO.System.device.sampleRate;
|
||||
sound.stream.sampleSize = 32;
|
||||
sound.stream.channels = AUDIO_DEVICE_CHANNELS;
|
||||
sound.stream.buffer = audioBuffer;
|
||||
}
|
||||
|
||||
audioBuffer->sizeInFrames = source.stream.buffer->sizeInFrames;
|
||||
audioBuffer->data = source.stream.buffer->data;
|
||||
|
||||
// Initalize the buffer as if it was new
|
||||
audioBuffer->volume = 1.0f;
|
||||
audioBuffer->pitch = 1.0f;
|
||||
audioBuffer->pan = 0.0f; // Center
|
||||
|
||||
sound.frameCount = source.frameCount;
|
||||
sound.stream.sampleRate = AUDIO.System.device.sampleRate;
|
||||
sound.stream.sampleSize = 32;
|
||||
sound.stream.channels = AUDIO_DEVICE_CHANNELS;
|
||||
sound.stream.buffer = audioBuffer;
|
||||
else TRACELOG(LOG_WARNING, "SOUND: Failed to create buffer");
|
||||
}
|
||||
|
||||
return sound;
|
||||
}
|
||||
|
||||
// Checks if a sound is valid (data loaded and buffers initialized)
|
||||
// Check if a sound is valid (data loaded and buffers initialized)
|
||||
bool IsSoundValid(Sound sound)
|
||||
{
|
||||
bool result = false;
|
||||
|
|
@ -1051,6 +1048,7 @@ void UnloadSoundAlias(Sound alias)
|
|||
{
|
||||
UntrackAudioBuffer(alias.stream.buffer);
|
||||
ma_data_converter_uninit(&alias.stream.buffer->converter, NULL);
|
||||
RL_FREE(alias.stream.buffer->converterResidual);
|
||||
RL_FREE(alias.stream.buffer);
|
||||
}
|
||||
}
|
||||
|
|
@ -1071,7 +1069,7 @@ void UpdateSound(Sound sound, const void *data, int frameCount)
|
|||
// Export wave data to file
|
||||
bool ExportWave(Wave wave, const char *fileName)
|
||||
{
|
||||
bool success = false;
|
||||
bool result = false;
|
||||
|
||||
if (false) { }
|
||||
#if SUPPORT_FILEFORMAT_WAV
|
||||
|
|
@ -1088,11 +1086,11 @@ bool ExportWave(Wave wave, const char *fileName)
|
|||
|
||||
void *fileData = NULL;
|
||||
size_t fileDataSize = 0;
|
||||
success = drwav_init_memory_write(&wav, &fileData, &fileDataSize, &format, NULL);
|
||||
if (success) success = (int)drwav_write_pcm_frames(&wav, wave.frameCount, wave.data);
|
||||
result = drwav_init_memory_write(&wav, &fileData, &fileDataSize, &format, NULL);
|
||||
if (result) result = (int)drwav_write_pcm_frames(&wav, wave.frameCount, wave.data);
|
||||
drwav_result result = drwav_uninit(&wav);
|
||||
|
||||
if (result == DRWAV_SUCCESS) success = SaveFileData(fileName, (unsigned char *)fileData, (unsigned int)fileDataSize);
|
||||
if (result == DRWAV_SUCCESS) result = SaveFileData(fileName, (unsigned char *)fileData, (unsigned int)fileDataSize);
|
||||
|
||||
drwav_free(fileData, NULL);
|
||||
}
|
||||
|
|
@ -1108,7 +1106,7 @@ bool ExportWave(Wave wave, const char *fileName)
|
|||
qoa.samples = wave.frameCount;
|
||||
|
||||
int bytesWritten = qoa_write(fileName, (const short *)wave.data, &qoa);
|
||||
if (bytesWritten > 0) success = true;
|
||||
if (bytesWritten > 0) result = true;
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "AUDIO: Wave data must be 16 bit per sample for QOA format export");
|
||||
}
|
||||
|
|
@ -1117,19 +1115,19 @@ bool ExportWave(Wave wave, const char *fileName)
|
|||
{
|
||||
// Export raw sample data (without header)
|
||||
// NOTE: It's up to the user to track wave parameters
|
||||
success = SaveFileData(fileName, wave.data, wave.frameCount*wave.channels*wave.sampleSize/8);
|
||||
result = SaveFileData(fileName, wave.data, wave.frameCount*wave.channels*wave.sampleSize/8);
|
||||
}
|
||||
|
||||
if (success) TRACELOG(LOG_INFO, "FILEIO: [%s] Wave data exported successfully", fileName);
|
||||
if (result) TRACELOG(LOG_INFO, "FILEIO: [%s] Wave data exported successfully", fileName);
|
||||
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export wave data", fileName);
|
||||
|
||||
return success;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Export wave sample data to code (.h)
|
||||
bool ExportWaveAsCode(Wave wave, const char *fileName)
|
||||
{
|
||||
bool success = false;
|
||||
bool result = false;
|
||||
|
||||
#ifndef TEXT_BYTES_PER_LINE
|
||||
#define TEXT_BYTES_PER_LINE 20
|
||||
|
|
@ -1183,14 +1181,14 @@ bool ExportWaveAsCode(Wave wave, const char *fileName)
|
|||
}
|
||||
|
||||
// NOTE: Text data length exported is determined by '\0' (NULL) character
|
||||
success = SaveFileText(fileName, txtData);
|
||||
result = SaveFileText(fileName, txtData);
|
||||
|
||||
RL_FREE(txtData);
|
||||
|
||||
if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Wave as code exported successfully", fileName);
|
||||
if (result != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Wave as code exported successfully", fileName);
|
||||
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export wave as code", fileName);
|
||||
|
||||
return success;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Play a sound
|
||||
|
|
@ -1706,8 +1704,7 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data,
|
|||
|
||||
// Copy data to allocated memory for default UnloadMusicStream
|
||||
unsigned char *newData = (unsigned char *)RL_MALLOC(dataSize);
|
||||
int it = dataSize/sizeof(unsigned char);
|
||||
for (int i = 0; i < it; i++) newData[i] = data[i];
|
||||
for (int i = 0; i < dataSize; i++) newData[i] = data[i];
|
||||
|
||||
// Memory loaded version for jar_mod_load_file()
|
||||
if (dataSize && (dataSize < 32*1024*1024))
|
||||
|
|
@ -1754,7 +1751,7 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data,
|
|||
return music;
|
||||
}
|
||||
|
||||
// Checks if a music stream is valid (context and buffers initialized)
|
||||
// Check if a music stream is valid (context and buffers initialized)
|
||||
bool IsMusicValid(Music music)
|
||||
{
|
||||
return ((music.ctxData != NULL) && // Validate context loaded
|
||||
|
|
@ -1767,6 +1764,8 @@ bool IsMusicValid(Music music)
|
|||
// Unload music stream
|
||||
void UnloadMusicStream(Music music)
|
||||
{
|
||||
if (IsMusicStreamPlaying(music)) StopMusicStream(music);
|
||||
|
||||
UnloadAudioStream(music.stream);
|
||||
|
||||
if (music.ctxData != NULL)
|
||||
|
|
@ -2069,7 +2068,7 @@ void SetMusicPitch(Music music, float pitch)
|
|||
SetAudioBufferPitch(music.stream.buffer, pitch);
|
||||
}
|
||||
|
||||
// Set pan for a music
|
||||
// Set pan for music
|
||||
void SetMusicPan(Music music, float pan)
|
||||
{
|
||||
SetAudioBufferPan(music.stream.buffer, pan);
|
||||
|
|
@ -2157,7 +2156,7 @@ AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
|
|||
return stream;
|
||||
}
|
||||
|
||||
// Checks if an audio stream is valid (buffers initialized)
|
||||
// Check if an audio stream is valid (buffers initialized)
|
||||
bool IsAudioStreamValid(AudioStream stream)
|
||||
{
|
||||
return ((stream.buffer != NULL) && // Validate stream buffer
|
||||
|
|
@ -2187,12 +2186,15 @@ void UpdateAudioStream(AudioStream stream, const void *data, int frameCount)
|
|||
// Check if any audio stream buffers requires refill
|
||||
bool IsAudioStreamProcessed(AudioStream stream)
|
||||
{
|
||||
if (stream.buffer == NULL) return false;
|
||||
|
||||
bool result = false;
|
||||
ma_mutex_lock(&AUDIO.System.lock);
|
||||
result = stream.buffer->isSubBufferProcessed[0] || stream.buffer->isSubBufferProcessed[1];
|
||||
ma_mutex_unlock(&AUDIO.System.lock);
|
||||
|
||||
if (stream.buffer != NULL)
|
||||
{
|
||||
ma_mutex_lock(&AUDIO.System.lock);
|
||||
result = stream.buffer->isSubBufferProcessed[0] || stream.buffer->isSubBufferProcessed[1];
|
||||
ma_mutex_unlock(&AUDIO.System.lock);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -2882,9 +2884,17 @@ static unsigned char *LoadFileData(const char *fileName, int *dataSize)
|
|||
return data;
|
||||
}
|
||||
|
||||
// Unload file data allocated by LoadFileData()
|
||||
static void UnloadFileData(unsigned char *data)
|
||||
{
|
||||
RL_FREE(data);
|
||||
}
|
||||
|
||||
// Save data to file from buffer
|
||||
static bool SaveFileData(const char *fileName, void *data, int dataSize)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
if (fileName != NULL)
|
||||
{
|
||||
FILE *file = fopen(fileName, "wb");
|
||||
|
|
@ -2902,21 +2912,23 @@ static bool SaveFileData(const char *fileName, void *data, int dataSize)
|
|||
else
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName);
|
||||
return false;
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
|
||||
return false;
|
||||
result = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Save text data to file (write), string must be '\0' terminated
|
||||
static bool SaveFileText(const char *fileName, char *text)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
if (fileName != NULL)
|
||||
{
|
||||
FILE *file = fopen(fileName, "wt");
|
||||
|
|
@ -2934,16 +2946,16 @@ static bool SaveFileText(const char *fileName, char *text)
|
|||
else
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName);
|
||||
return false;
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
|
||||
return false;
|
||||
result = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
GLFW_ICON ICON "raylib.ico"
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 5,5,0,0
|
||||
PRODUCTVERSION 5,5,0,0
|
||||
FILEVERSION 6,0,0,0
|
||||
PRODUCTVERSION 6,0,0,0
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
|
|
@ -11,12 +11,12 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "raylib technologies"
|
||||
VALUE "FileDescription", "raylib dynamic library (www.raylib.com)"
|
||||
VALUE "FileVersion", "5.5.0"
|
||||
VALUE "FileVersion", "6.0.0"
|
||||
VALUE "InternalName", "raylib.dll"
|
||||
VALUE "LegalCopyright", "(c) 2025 Ramon Santamaria (@raysan5)"
|
||||
VALUE "LegalCopyright", "(c) 2026 Ramon Santamaria (@raysan5)"
|
||||
VALUE "OriginalFilename", "raylib.dll"
|
||||
VALUE "ProductName", "raylib"
|
||||
VALUE "ProductVersion", "5.5.0"
|
||||
VALUE "ProductVersion", "6.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
|
|||
Binary file not shown.
167
src/raylib.h
167
src/raylib.h
|
|
@ -1,6 +1,6 @@
|
|||
/**********************************************************************************************
|
||||
*
|
||||
* raylib v6.0 - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com)
|
||||
* raylib v6.1-dev - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com)
|
||||
*
|
||||
* FEATURES:
|
||||
* - NO external dependencies, all required libraries included with raylib
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
* - Software renderer optional, for systems with no GPU: [rlsw]
|
||||
* - Custom OpenGL abstraction layer (usable as standalone module): [rlgl]
|
||||
* - Multiple Fonts formats supported (TTF, OTF, FNT, BDF, Sprite fonts)
|
||||
* - Many texture formats supportted, including compressed formats (DXT, ETC, ASTC)
|
||||
* - Many texture formats supported, including compressed formats (DXT, ETC, ASTC)
|
||||
* - Full 3d support for 3d Shapes, Models, Billboards, Heightmaps and more!
|
||||
* - Flexible Materials system, supporting classic maps and PBR maps
|
||||
* - Animated 3D models supported (skeletal bones animation) (IQM, M3D, GLTF)
|
||||
|
|
@ -35,14 +35,14 @@
|
|||
* [rcore] sinfl (Micha Mettke) for DEFLATE decompression algorithm
|
||||
* [rcore] sdefl (Micha Mettke) for DEFLATE compression algorithm
|
||||
* [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)
|
||||
* [rtextures] stb_image_resize2 (Sean Barret) for image resizing algorithms
|
||||
* [rtextures] stb_perlin (Sean Barret) for Perlin Noise image generation
|
||||
* [rtextures] qoi (Dominic Szablewski - https://phoboslab.org) for QOI image management
|
||||
* [rtextures] stb_image (Sean Barrett) for images loading (BMP, TGA, PNG, JPEG, HDR...)
|
||||
* [rtextures] stb_image_write (Sean Barrett) for image writing (BMP, TGA, PNG, JPG)
|
||||
* [rtextures] stb_image_resize2 (Sean Barrett) for image resizing algorithms
|
||||
* [rtextures] stb_perlin (Sean Barrett) for Perlin Noise image generation
|
||||
* [rtextures] rltexgpu (Ramon Santamaria) for GPU-compressed texture formats
|
||||
* [rtext] stb_truetype (Sean Barret) for ttf fonts loading
|
||||
* [rtext] stb_rect_pack (Sean Barret) for rectangles packing
|
||||
* [rtext] stb_truetype (Sean Barrett) for ttf fonts loading
|
||||
* [rtext] stb_rect_pack (Sean Barrett) for rectangles packing
|
||||
* [rmodels] par_shapes (Philip Rideout) for parametric 3d shapes generation
|
||||
* [rmodels] tinyobj_loader_c (Syoyo Fujita) for models loading (OBJ, MTL)
|
||||
* [rmodels] cgltf (Johannes Kuhlmann) for models loading (glTF)
|
||||
|
|
@ -51,10 +51,10 @@
|
|||
* [raudio] dr_wav (David Reid) for WAV audio file loading
|
||||
* [raudio] dr_flac (David Reid) for FLAC audio file loading
|
||||
* [raudio] dr_mp3 (David Reid) for MP3 audio file loading
|
||||
* [raudio] stb_vorbis (Sean Barret) for OGG audio loading
|
||||
* [raudio] stb_vorbis (Sean Barrett) for OGG audio loading
|
||||
* [raudio] jar_xm (Joshua Reisenauer) for XM audio module loading
|
||||
* [raudio] jar_mod (Joshua Reisenauer) for MOD audio module loading
|
||||
* [raudio] qoa (Dominic Szablewski - https://phoboslab.org) for QOA audio manage
|
||||
* [raudio] qoa (Dominic Szablewski - https://phoboslab.org) for QOA audio management
|
||||
*
|
||||
*
|
||||
* LICENSE: zlib/libpng
|
||||
|
|
@ -87,9 +87,9 @@
|
|||
#include <stdarg.h> // Required for: va_list - Only used by TraceLogCallback
|
||||
|
||||
#define RAYLIB_VERSION_MAJOR 6
|
||||
#define RAYLIB_VERSION_MINOR 0
|
||||
#define RAYLIB_VERSION_MINOR 1
|
||||
#define RAYLIB_VERSION_PATCH 0
|
||||
#define RAYLIB_VERSION "6.0"
|
||||
#define RAYLIB_VERSION "6.1-dev"
|
||||
|
||||
// Function specifiers in case library is build/used as a shared library
|
||||
// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
|
||||
|
|
@ -203,12 +203,14 @@
|
|||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
// Boolean type
|
||||
#if !defined(__cplusplus)
|
||||
#if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
|
||||
#include <stdbool.h>
|
||||
#elif !defined(__cplusplus) && !defined(bool)
|
||||
#elif !defined(bool)
|
||||
typedef enum bool { false = 0, true = !false } bool;
|
||||
#define RL_BOOL_TYPE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Vector2, 2 components
|
||||
typedef struct Vector2 {
|
||||
|
|
@ -963,10 +965,10 @@ typedef enum {
|
|||
|
||||
// Callbacks to hook some internal functions
|
||||
// WARNING: These callbacks are intended for advanced users
|
||||
typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args); // Logging: Redirect trace log messages
|
||||
typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, int *dataSize); // FileIO: Load binary data
|
||||
typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, int dataSize); // FileIO: Save binary data
|
||||
typedef char *(*LoadFileTextCallback)(const char *fileName); // FileIO: Load text data
|
||||
typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args); // Logging: Redirect trace log messages
|
||||
typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, int *dataSize); // FileIO: Load binary data
|
||||
typedef bool (*SaveFileDataCallback)(const char *fileName, const void *data, int dataSize); // FileIO: Save binary data
|
||||
typedef char *(*LoadFileTextCallback)(const char *fileName); // FileIO: Load text data
|
||||
typedef bool (*SaveFileTextCallback)(const char *fileName, const char *text); // FileIO: Save text data
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
|
|
@ -1034,23 +1036,23 @@ RLAPI void EnableEventWaiting(void); // Enable wait
|
|||
RLAPI void DisableEventWaiting(void); // Disable waiting for events on EndDrawing(), automatic events polling
|
||||
|
||||
// Cursor-related functions
|
||||
RLAPI void ShowCursor(void); // Shows cursor
|
||||
RLAPI void HideCursor(void); // Hides cursor
|
||||
RLAPI void ShowCursor(void); // Show cursor
|
||||
RLAPI void HideCursor(void); // Hide cursor
|
||||
RLAPI bool IsCursorHidden(void); // Check if cursor is not visible
|
||||
RLAPI void EnableCursor(void); // Enables cursor (unlock cursor)
|
||||
RLAPI void DisableCursor(void); // Disables cursor (lock cursor)
|
||||
RLAPI void EnableCursor(void); // Enable cursor (unlock cursor)
|
||||
RLAPI void DisableCursor(void); // Disable cursor (lock cursor)
|
||||
RLAPI bool IsCursorOnScreen(void); // Check if cursor is on the screen
|
||||
|
||||
// Drawing-related functions
|
||||
RLAPI void ClearBackground(Color color); // Set background color (framebuffer clear color)
|
||||
RLAPI void BeginDrawing(void); // Setup canvas (framebuffer) to start drawing
|
||||
RLAPI void EndDrawing(void); // End canvas drawing and swap buffers (double buffering)
|
||||
RLAPI void ClearBackground(Color color); // Clear background (framebuffer) to color
|
||||
RLAPI void BeginDrawing(void); // Begin canvas (framebuffer) drawing
|
||||
RLAPI void EndDrawing(void); // End canvas (framebuffer) drawing and swap buffers (double buffering)
|
||||
RLAPI void BeginMode2D(Camera2D camera); // Begin 2D mode with custom camera (2D)
|
||||
RLAPI void EndMode2D(void); // Ends 2D mode with custom camera
|
||||
RLAPI void EndMode2D(void); // End 2D mode with custom camera
|
||||
RLAPI void BeginMode3D(Camera3D camera); // Begin 3D mode with custom camera (3D)
|
||||
RLAPI void EndMode3D(void); // Ends 3D mode and returns to default 2D orthographic mode
|
||||
RLAPI void EndMode3D(void); // End 3D mode and returns to default 2D orthographic mode
|
||||
RLAPI void BeginTextureMode(RenderTexture2D target); // Begin drawing to render texture
|
||||
RLAPI void EndTextureMode(void); // Ends drawing to render texture
|
||||
RLAPI void EndTextureMode(void); // End drawing to render texture
|
||||
RLAPI void BeginShaderMode(Shader shader); // Begin custom shader drawing
|
||||
RLAPI void EndShaderMode(void); // End custom shader drawing (use default shader)
|
||||
RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied, subtract, custom)
|
||||
|
|
@ -1071,9 +1073,9 @@ RLAPI Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode); // Lo
|
|||
RLAPI bool IsShaderValid(Shader shader); // Check if a shader is valid (loaded on GPU)
|
||||
RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location
|
||||
RLAPI int GetShaderLocationAttrib(Shader shader, const char *attribName); // Get shader attribute location
|
||||
RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType); // Set shader uniform value
|
||||
RLAPI void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count); // Set shader uniform value vector
|
||||
RLAPI void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat); // Set shader uniform value (matrix 4x4)
|
||||
RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType); // Set shader uniform value
|
||||
RLAPI void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count); // Set shader uniform value vector
|
||||
RLAPI void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat); // Set shader uniform value (matrix 4x4)
|
||||
RLAPI void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture); // Set shader uniform value and bind the texture (sampler2d)
|
||||
RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM)
|
||||
|
||||
|
|
@ -1081,10 +1083,10 @@ RLAPI void UnloadShader(Shader shader); // Un
|
|||
#define GetMouseRay GetScreenToWorldRay // Compatibility hack for previous raylib versions
|
||||
RLAPI Ray GetScreenToWorldRay(Vector2 position, Camera camera); // Get a ray trace from screen position (i.e mouse)
|
||||
RLAPI Ray GetScreenToWorldRayEx(Vector2 position, Camera camera, int width, int height); // Get a ray trace from screen position (i.e mouse) in a viewport
|
||||
RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Get the screen space position for a 3d world space position
|
||||
RLAPI Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int height); // Get size position for a 3d world space position
|
||||
RLAPI Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera); // Get the screen space position for a 2d camera world space position
|
||||
RLAPI Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera); // Get the world space position for a 2d camera screen space position
|
||||
RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Get screen space position for a 3d world space position
|
||||
RLAPI Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int height); // Get sized screen space position for a 3d world space position
|
||||
RLAPI Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera); // Get screen space position for a 2d camera world space position
|
||||
RLAPI Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera); // Get world space position for a 2d camera screen space position
|
||||
RLAPI Matrix GetCameraMatrix(Camera camera); // Get camera transform matrix (view matrix)
|
||||
RLAPI Matrix GetCameraMatrix2D(Camera2D camera); // Get camera 2d transform matrix
|
||||
|
||||
|
|
@ -1110,7 +1112,7 @@ RLAPI void UnloadRandomSequence(int *sequence); // Unload random values
|
|||
|
||||
// Misc. functions
|
||||
RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (filename extension defines format)
|
||||
RLAPI void SetConfigFlags(unsigned int flags); // Setup init configuration flags (view FLAGS)
|
||||
RLAPI void SetConfigFlags(unsigned int flags); // Set up init configuration flags (view FLAGS)
|
||||
RLAPI void OpenURL(const char *url); // Open URL with default system browser (if available)
|
||||
|
||||
// Logging system
|
||||
|
|
@ -1126,7 +1128,7 @@ RLAPI void MemFree(void *ptr); // Internal memo
|
|||
// File system management functions
|
||||
RLAPI unsigned char *LoadFileData(const char *fileName, int *dataSize); // Load file data as byte array (read)
|
||||
RLAPI void UnloadFileData(unsigned char *data); // Unload file data allocated by LoadFileData()
|
||||
RLAPI bool SaveFileData(const char *fileName, void *data, int dataSize); // Save data to file from byte array (write), returns true on success
|
||||
RLAPI bool SaveFileData(const char *fileName, const void *data, int dataSize); // Save data to file from byte array (write), returns true on success
|
||||
RLAPI bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName); // Export data to code (.h), returns true on success
|
||||
RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string
|
||||
RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText()
|
||||
|
|
@ -1161,8 +1163,8 @@ RLAPI int MakeDirectory(const char *dirPath); // Create di
|
|||
RLAPI bool ChangeDirectory(const char *dirPath); // Change working directory, return true on success
|
||||
RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory
|
||||
RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS
|
||||
RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths
|
||||
RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result
|
||||
RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths, files and directories, no subdirs scan
|
||||
RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and subdir scan; some filters available: `*.*`,`FILES*`,`DIRS*`
|
||||
RLAPI void UnloadDirectoryFiles(FilePathList files); // Unload filepaths
|
||||
RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window
|
||||
RLAPI FilePathList LoadDroppedFiles(void); // Load dropped filepaths
|
||||
|
|
@ -1175,10 +1177,10 @@ RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *
|
|||
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 (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)
|
||||
RLAPI unsigned int *ComputeSHA256(unsigned char *data, int dataSize); // Compute SHA256 hash code, returns static int[8] (32 bytes)
|
||||
RLAPI unsigned int ComputeCRC32(const unsigned char *data, int dataSize); // Compute CRC32 hash code
|
||||
RLAPI unsigned int *ComputeMD5(const unsigned char *data, int dataSize); // Compute MD5 hash code, returns static int[4] (16 bytes)
|
||||
RLAPI unsigned int *ComputeSHA1(const unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes)
|
||||
RLAPI unsigned int *ComputeSHA256(const unsigned char *data, int dataSize); // Compute SHA256 hash code, returns static int[8] (32 bytes)
|
||||
|
||||
// Automation events functionality
|
||||
RLAPI AutomationEventList LoadAutomationEventList(const char *fileName); // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS
|
||||
|
|
@ -1245,7 +1247,7 @@ RLAPI int GetTouchPointCount(void); // Get number of t
|
|||
// Gestures and Touch Handling Functions (Module: rgestures)
|
||||
//------------------------------------------------------------------------------------
|
||||
RLAPI void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags
|
||||
RLAPI bool IsGestureDetected(unsigned int gesture); // Check if a gesture have been detected
|
||||
RLAPI bool IsGestureDetected(unsigned int gesture); // Check if a gesture has been detected
|
||||
RLAPI int GetGestureDetected(void); // Get latest detected gesture
|
||||
RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in seconds
|
||||
RLAPI Vector2 GetGestureDragVector(void); // Get gesture drag vector
|
||||
|
|
@ -1279,10 +1281,10 @@ RLAPI void DrawLineStrip(const Vector2 *points, int pointCount, Color color);
|
|||
RLAPI void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw line segment cubic-bezier in-out interpolation
|
||||
RLAPI void DrawLineDashed(Vector2 startPos, Vector2 endPos, int dashSize, int spaceSize, Color color); // Draw a dashed line
|
||||
RLAPI void DrawCircle(int centerX, int centerY, float radius, Color color); // Draw a color-filled circle
|
||||
RLAPI void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw a piece of a circle
|
||||
RLAPI void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw circle sector outline
|
||||
RLAPI void DrawCircleGradient(int centerX, int centerY, float radius, Color inner, Color outer); // Draw a gradient-filled circle
|
||||
RLAPI void DrawCircleV(Vector2 center, float radius, Color color); // Draw a color-filled circle (Vector version)
|
||||
RLAPI void DrawCircleGradient(Vector2 center, float radius, Color inner, Color outer); // Draw a gradient-filled circle
|
||||
RLAPI void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw a piece of a circle
|
||||
RLAPI void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw circle sector outline
|
||||
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
|
||||
|
|
@ -1290,7 +1292,7 @@ RLAPI void DrawEllipseV(Vector2 center, float radiusH, float radiusV, Color colo
|
|||
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 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
|
||||
RLAPI void DrawRectangleV(Vector2 position, Vector2 size, Color color); // Draw a color-filled rectangle (Vector version)
|
||||
RLAPI void DrawRectangleRec(Rectangle rec, Color color); // Draw a color-filled rectangle
|
||||
|
|
@ -1302,12 +1304,13 @@ RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color c
|
|||
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
|
||||
RLAPI void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Color color); // Draw rectangle lines with rounded edges
|
||||
RLAPI void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, float lineThick, Color color); // Draw rectangle with rounded edges outline
|
||||
RLAPI void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, float lineThick, Color color); // Draw rectangle lines with rounded edges outline
|
||||
RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw a color-filled triangle (vertex in counter-clockwise order!)
|
||||
RLAPI void DrawTriangleGradient(Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3); // Draw triangle with interpolated colors (vertex in counter-clockwise order!)
|
||||
RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline (vertex in counter-clockwise order!)
|
||||
RLAPI void DrawTriangleFan(const Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points (first vertex is the center)
|
||||
RLAPI void DrawTriangleStrip(const Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points
|
||||
RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version)
|
||||
RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a polygon of n sides
|
||||
RLAPI void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a polygon outline of n sides
|
||||
RLAPI void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float lineThick, Color color); // Draw a polygon outline of n sides with extended parameters
|
||||
|
||||
|
|
@ -1327,14 +1330,14 @@ RLAPI void DrawSplineSegmentBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vect
|
|||
RLAPI Vector2 GetSplinePointLinear(Vector2 startPos, Vector2 endPos, float t); // Get (evaluate) spline point: Linear
|
||||
RLAPI Vector2 GetSplinePointBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t); // Get (evaluate) spline point: B-Spline
|
||||
RLAPI Vector2 GetSplinePointCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t); // Get (evaluate) spline point: Catmull-Rom
|
||||
RLAPI Vector2 GetSplinePointBezierQuad(Vector2 p1, Vector2 c2, Vector2 p3, float t); // Get (evaluate) spline point: Quadratic Bezier
|
||||
RLAPI Vector2 GetSplinePointBezierQuadratic(Vector2 p1, Vector2 c2, Vector2 p3, float t); // Get (evaluate) spline point: Quadratic Bezier
|
||||
RLAPI Vector2 GetSplinePointBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float t); // Get (evaluate) spline point: Cubic Bezier
|
||||
|
||||
// Basic shapes collision detection functions
|
||||
RLAPI bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2); // Check collision between two rectangles
|
||||
RLAPI bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2); // Check collision between two circles
|
||||
RLAPI bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec); // Check collision between circle and rectangle
|
||||
RLAPI bool CheckCollisionCircleLine(Vector2 center, float radius, Vector2 p1, Vector2 p2); // Check if circle collides with a line created betweeen two points [p1] and [p2]
|
||||
RLAPI bool CheckCollisionCircleLine(Vector2 center, float radius, Vector2 p1, Vector2 p2); // Check if circle collides with a line created between two points [p1] and [p2]
|
||||
RLAPI bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle
|
||||
RLAPI bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius); // Check if point is inside circle
|
||||
RLAPI bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3); // Check if point is inside a triangle
|
||||
|
|
@ -1355,11 +1358,11 @@ RLAPI Image LoadImageAnim(const char *fileName, int *frames);
|
|||
RLAPI Image LoadImageAnimFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int *frames); // Load image sequence from memory buffer
|
||||
RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load image from memory buffer, fileType refers to extension: i.e. '.png'
|
||||
RLAPI Image LoadImageFromTexture(Texture2D texture); // Load image from GPU texture data
|
||||
RLAPI Image LoadImageFromScreen(void); // Load image from screen buffer and (screenshot)
|
||||
RLAPI Image LoadImageFromScreen(void); // Load image from screen buffer (screenshot)
|
||||
RLAPI bool IsImageValid(Image image); // Check if an image is valid (data and parameters)
|
||||
RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM)
|
||||
RLAPI bool ExportImage(Image image, const char *fileName); // Export image data to file, returns true on success
|
||||
RLAPI unsigned char *ExportImageToMemory(Image image, const char *fileType, int *fileSize); // Export image to memory buffer
|
||||
RLAPI unsigned char *ExportImageToMemory(Image image, const char *fileType, int *fileSize); // Export image to memory buffer, memory must be MemFree()
|
||||
RLAPI bool ExportImageAsCode(Image image, const char *fileName); // Export image as code file defining an array of bytes, returns true on success
|
||||
|
||||
// Image generation functions
|
||||
|
|
@ -1401,7 +1404,7 @@ RLAPI void ImageRotateCCW(Image *image);
|
|||
RLAPI void ImageColorTint(Image *image, Color color); // Modify image color: tint
|
||||
RLAPI void ImageColorInvert(Image *image); // Modify image color: invert
|
||||
RLAPI void ImageColorGrayscale(Image *image); // Modify image color: grayscale
|
||||
RLAPI void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100)
|
||||
RLAPI void ImageColorContrast(Image *image, int contrast); // Modify image color: contrast (-100 to 100)
|
||||
RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255)
|
||||
RLAPI void ImageColorReplace(Image *image, Color color, Color replace); // Modify image color: replace color
|
||||
RLAPI Color *LoadImageColors(Image image); // Load color data from image as a Color array (RGBA - 32bit)
|
||||
|
|
@ -1426,9 +1429,10 @@ RLAPI void ImageDrawCircleLinesV(Image *dst, Vector2 center, int radius, Color c
|
|||
RLAPI void ImageDrawRectangle(Image *dst, int posX, int posY, int width, int height, Color color); // Draw rectangle within an image
|
||||
RLAPI void ImageDrawRectangleV(Image *dst, Vector2 position, Vector2 size, Color color); // Draw rectangle within an image (Vector version)
|
||||
RLAPI void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color); // Draw rectangle within an image
|
||||
RLAPI void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color); // Draw rectangle lines within an image
|
||||
RLAPI void ImageDrawRectangleLines(Image *dst, int posX, int posY, int width, int height, Color color); // Draw rectangle lines within an image
|
||||
RLAPI void ImageDrawRectangleLinesEx(Image *dst, Rectangle rec, int thick, Color color); // Draw rectangle lines within an image with extended parameters
|
||||
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 ImageDrawTriangleGradient(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, 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
|
||||
|
|
@ -1460,7 +1464,7 @@ RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint);
|
|||
RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters
|
||||
RLAPI void DrawTextureRec(Texture2D texture, Rectangle source, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle
|
||||
RLAPI void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters
|
||||
RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draws a texture (or part of it) that stretches or shrinks nicely
|
||||
RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draw a texture (or part of it) that stretches or shrinks nicely
|
||||
|
||||
// Color/pixel related functions
|
||||
RLAPI bool ColorIsEqual(Color col1, Color col2); // Check if two colors are equal
|
||||
|
|
@ -1504,7 +1508,7 @@ RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color co
|
|||
RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters
|
||||
RLAPI void DrawTextPro(Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint); // Draw text using Font and pro parameters (rotation)
|
||||
RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint); // Draw one character (codepoint)
|
||||
RLAPI void DrawTextCodepoints(Font font, const int *codepoints, int codepointCount, Vector2 position, float fontSize, float spacing, Color tint); // Draw multiple character (codepoint)
|
||||
RLAPI void DrawTextCodepoints(Font font, const int *codepoints, int codepointCount, Vector2 position, float fontSize, float spacing, Color tint); // Draw multiple characters (codepoint)
|
||||
|
||||
// Text font info functions
|
||||
RLAPI void SetTextLineSpacing(int spacing); // Set vertical line spacing when drawing with line-breaks
|
||||
|
|
@ -1528,19 +1532,22 @@ RLAPI const char *CodepointToUTF8(int codepoint, int *utf8Size);
|
|||
|
||||
// Text strings management functions (no UTF-8 strings, only byte chars)
|
||||
// WARNING 1: Most of these functions use internal static buffers[], it's recommended to store returned data on user-side for re-use
|
||||
// WARNING 2: Some strings allocate memory internally for the returned strings, those strings must be free by user using MemFree()
|
||||
// WARNING 2: Some functions allocate memory internally for the returned strings, those strings must be freed by user using MemFree()
|
||||
RLAPI char **LoadTextLines(const char *text, int *count); // Load text as separate lines ('\n')
|
||||
RLAPI void UnloadTextLines(char **text, int lineCount); // Unload text lines
|
||||
RLAPI int TextCopy(char *dst, const char *src); // Copy one string to another, returns bytes copied
|
||||
RLAPI bool TextIsEqual(const char *text1, const char *text2); // Check if two text string are equal
|
||||
RLAPI bool TextIsEqual(const char *text1, const char *text2); // Check if two text strings are equal
|
||||
RLAPI unsigned int TextLength(const char *text); // Get text length, checks for '\0' ending
|
||||
RLAPI const char *TextFormat(const char *text, ...); // Text formatting with variables (sprintf() style)
|
||||
RLAPI const char *TextSubtext(const char *text, int position, int length); // Get a piece of a text string
|
||||
RLAPI const char *TextRemoveSpaces(const char *text); // Remove text spaces, concat words
|
||||
RLAPI char *GetTextBetween(const char *text, const char *begin, const char *end); // Get text between two strings
|
||||
RLAPI char *TextReplace(const char *text, const char *search, const char *replacement); // Replace text string (WARNING: memory must be freed!)
|
||||
RLAPI char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement); // Replace text between two specific strings (WARNING: memory must be freed!)
|
||||
RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a position (WARNING: memory must be freed!)
|
||||
RLAPI char *TextReplace(const char *text, const char *search, const char *replacement); // Replace text string with new string
|
||||
RLAPI char *TextReplaceAlloc(const char *text, const char *search, const char *replacement); // Replace text string with new string, memory must be MemFree()
|
||||
RLAPI char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement); // Replace text between two specific strings
|
||||
RLAPI char *TextReplaceBetweenAlloc(const char *text, const char *begin, const char *end, const char *replacement); // Replace text between two specific strings, memory must be MemFree()
|
||||
RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a defined byte position
|
||||
RLAPI char *TextInsertAlloc(const char *text, const char *insert, int position); // Insert text in a defined byte position, memory must be MemFree()
|
||||
RLAPI char *TextJoin(char **textList, int count, const char *delimiter); // Join text strings with delimiter
|
||||
RLAPI char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings
|
||||
RLAPI void TextAppend(char *text, const char *append, int *position); // Append text at specific position and move cursor
|
||||
|
|
@ -1573,9 +1580,9 @@ RLAPI void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slice
|
|||
RLAPI void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone
|
||||
RLAPI void DrawCylinderEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color); // Draw a cylinder with base at startPos and top at endPos
|
||||
RLAPI void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone wires
|
||||
RLAPI void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color); // Draw a cylinder wires with base at startPos and top at endPos
|
||||
RLAPI void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color); // Draw a capsule with the center of its sphere caps at startPos and endPos
|
||||
RLAPI void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color); // Draw capsule wireframe with the center of its sphere caps at startPos and endPos
|
||||
RLAPI void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int slices, Color color); // Draw a cylinder wires with base at startPos and top at endPos
|
||||
RLAPI void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int rings, int slices, Color color); // Draw a capsule with the center of its sphere caps at startPos and endPos
|
||||
RLAPI void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int rings, int slices, Color color); // Draw capsule wireframe with the center of its sphere caps at startPos and endPos
|
||||
RLAPI void DrawPlane(Vector3 centerPos, Vector2 size, Color color); // Draw a plane XZ
|
||||
RLAPI void DrawRay(Ray ray, Color color); // Draw a ray line
|
||||
RLAPI void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0))
|
||||
|
|
@ -1596,10 +1603,8 @@ RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint);
|
|||
RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters
|
||||
RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set)
|
||||
RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters
|
||||
RLAPI void DrawModelPoints(Model model, Vector3 position, float scale, Color tint); // Draw a model as points
|
||||
RLAPI void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model as points with extended parameters
|
||||
RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires)
|
||||
RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint); // Draw a billboard texture
|
||||
RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint); // Draw a billboard texture
|
||||
RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint); // Draw a billboard texture defined by source
|
||||
RLAPI void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint); // Draw a billboard texture defined by source and rotation
|
||||
|
||||
|
|
@ -1667,15 +1672,15 @@ RLAPI float GetMasterVolume(void); // Get mas
|
|||
// Wave/Sound loading/unloading functions
|
||||
RLAPI Wave LoadWave(const char *fileName); // Load wave data from file
|
||||
RLAPI Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load wave from memory buffer, fileType refers to extension: i.e. '.wav'
|
||||
RLAPI bool IsWaveValid(Wave wave); // Checks if wave data is valid (data loaded and parameters)
|
||||
RLAPI bool IsWaveValid(Wave wave); // Check if wave data is valid (data loaded and parameters)
|
||||
RLAPI Sound LoadSound(const char *fileName); // Load sound from file
|
||||
RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data
|
||||
RLAPI Sound LoadSoundAlias(Sound source); // 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 (default data format: 32 bit float, stereo)
|
||||
RLAPI Sound LoadSoundAlias(Sound source); // Load sound alias, new sound that shares the same sample data as the source sound, does not own the sound data
|
||||
RLAPI bool IsSoundValid(Sound sound); // Check if a sound is valid (data loaded and buffers initialized)
|
||||
RLAPI void UpdateSound(Sound sound, const void *data, int frameCount); // Update sound buffer with new data (default data format: 32 bit float, stereo)
|
||||
RLAPI void UnloadWave(Wave wave); // Unload wave data
|
||||
RLAPI void UnloadSound(Sound sound); // Unload sound
|
||||
RLAPI void UnloadSoundAlias(Sound alias); // Unload a sound alias (does not deallocate sample data)
|
||||
RLAPI void UnloadSoundAlias(Sound alias); // Unload sound alias (does not deallocate sample data)
|
||||
RLAPI bool ExportWave(Wave wave, const char *fileName); // Export wave data to file, returns true on success
|
||||
RLAPI bool ExportWaveAsCode(Wave wave, const char *fileName); // Export wave sample data to code (.h), returns true on success
|
||||
|
||||
|
|
@ -1697,24 +1702,24 @@ RLAPI void UnloadWaveSamples(float *samples); // Unload
|
|||
// Music management functions
|
||||
RLAPI Music LoadMusicStream(const char *fileName); // Load music stream from file
|
||||
RLAPI Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, int dataSize); // Load music stream from data
|
||||
RLAPI bool IsMusicValid(Music music); // Checks if a music stream is valid (context and buffers initialized)
|
||||
RLAPI bool IsMusicValid(Music music); // Check if a music stream is valid (context and buffers initialized)
|
||||
RLAPI void UnloadMusicStream(Music music); // Unload music stream
|
||||
RLAPI void PlayMusicStream(Music music); // Start music playing
|
||||
RLAPI bool IsMusicStreamPlaying(Music music); // Check if music is playing
|
||||
RLAPI void UpdateMusicStream(Music music); // Updates buffers for music streaming
|
||||
RLAPI void UpdateMusicStream(Music music); // Update buffers for music streaming
|
||||
RLAPI void StopMusicStream(Music music); // Stop music playing
|
||||
RLAPI void PauseMusicStream(Music music); // Pause music playing
|
||||
RLAPI void ResumeMusicStream(Music music); // Resume playing paused music
|
||||
RLAPI void SeekMusicStream(Music music, float position); // Seek music to a position (in seconds)
|
||||
RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level)
|
||||
RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level)
|
||||
RLAPI void SetMusicPan(Music music, float pan); // Set pan for a music (-1.0 left, 0.0 center, 1.0 right)
|
||||
RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for music (1.0 is base level)
|
||||
RLAPI void SetMusicPan(Music music, float pan); // Set pan for music (-1.0 left, 0.0 center, 1.0 right)
|
||||
RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds)
|
||||
RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
|
||||
|
||||
// AudioStream management functions
|
||||
RLAPI AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Load audio stream (to stream raw audio pcm data)
|
||||
RLAPI bool IsAudioStreamValid(AudioStream stream); // Checks if an audio stream is valid (buffers initialized)
|
||||
RLAPI bool IsAudioStreamValid(AudioStream stream); // Check if an audio stream is valid (buffers initialized)
|
||||
RLAPI void UnloadAudioStream(AudioStream stream); // Unload audio stream and free memory
|
||||
RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int frameCount); // Update audio stream buffers with data
|
||||
RLAPI bool IsAudioStreamProcessed(AudioStream stream); // Check if any audio stream buffers requires refill
|
||||
|
|
@ -1725,7 +1730,7 @@ RLAPI bool IsAudioStreamPlaying(AudioStream stream); // Check i
|
|||
RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream
|
||||
RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level)
|
||||
RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level)
|
||||
RLAPI void SetAudioStreamPan(AudioStream stream, float pan); // Set pan for audio stream (-1.0 to 1.0 range, 0.0 is centered)
|
||||
RLAPI void SetAudioStreamPan(AudioStream stream, float pan); // Set pan for audio stream (-1.0 left, 0.0 center, 1.0 right)
|
||||
RLAPI void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams
|
||||
RLAPI void SetAudioStreamCallback(AudioStream stream, AudioCallback callback); // Audio thread callback to request new data
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
GLFW_ICON ICON "raylib.ico"
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 5,5,0,0
|
||||
PRODUCTVERSION 5,5,0,0
|
||||
FILEVERSION 6,0,0,0
|
||||
PRODUCTVERSION 6,0,0,0
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
|
|
@ -11,12 +11,12 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "raylib technologies"
|
||||
VALUE "FileDescription", "raylib application (www.raylib.com)"
|
||||
VALUE "FileVersion", "5.5.0"
|
||||
VALUE "FileVersion", "6.0.0"
|
||||
VALUE "InternalName", "raylib"
|
||||
VALUE "LegalCopyright", "(c) 2025 Ramon Santamaria (@raysan5)"
|
||||
VALUE "LegalCopyright", "(c) 2026 Ramon Santamaria (@raysan5)"
|
||||
VALUE "OriginalFilename", "raylib"
|
||||
VALUE "ProductName", "raylib app"
|
||||
VALUE "ProductVersion", "5.5.0"
|
||||
VALUE "ProductVersion", "6.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,6 +1,6 @@
|
|||
/**********************************************************************************************
|
||||
*
|
||||
* raymath v2.0 - Math functions to work with Vector2, Vector3, Matrix and Quaternions
|
||||
* raymath v2.0 - Math functions to work with Vector2, Vector3, Vector4, Matrix and Quaternions
|
||||
*
|
||||
* CONVENTIONS:
|
||||
* - Matrix structure is defined as row-major (memory layout) but parameters naming AND all
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
* - Functions use always a "result" variable for return (except C++ operators)
|
||||
* - Functions are always defined inline
|
||||
* - Angles are always in radians (DEG2RAD/RAD2DEG macros provided for convenience)
|
||||
* - No compound literals used to make sure libray is compatible with C++
|
||||
* - No compound literals used to make sure the library is compatible with C++
|
||||
*
|
||||
* CONFIGURATION:
|
||||
* #define RAYMATH_IMPLEMENTATION
|
||||
|
|
@ -183,7 +183,7 @@ typedef struct float16 {
|
|||
#if RAYMATH_USE_SIMD_INTRINSICS
|
||||
// SIMD is used on the most costly raymath function MatrixMultiply()
|
||||
// NOTE: Only SSE intrinsics support implemented
|
||||
// TODO: Consider support for other SIMD instrinsics:
|
||||
// TODO: Consider support for other SIMD intrinsics:
|
||||
// - SSEx, AVX, AVX2, FMA, NEON, RVV
|
||||
/*
|
||||
#if defined(__SSE4_2__)
|
||||
|
|
@ -1151,7 +1151,7 @@ RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view)
|
|||
// Create quaternion from source point
|
||||
Quaternion quat = { source.x, source.y, source.z, 1.0f };
|
||||
|
||||
// Multiply quat point by unprojecte matrix
|
||||
// Multiply quat point by unprojected matrix
|
||||
Quaternion qtransformed = { // QuaternionTransform(quat, matViewProjInv)
|
||||
matViewProjInv.m0*quat.x + matViewProjInv.m4*quat.y + matViewProjInv.m8*quat.z + matViewProjInv.m12*quat.w,
|
||||
matViewProjInv.m1*quat.x + matViewProjInv.m5*quat.y + matViewProjInv.m9*quat.z + matViewProjInv.m13*quat.w,
|
||||
|
|
@ -1264,19 +1264,21 @@ RMAPI Vector3 Vector3Refract(Vector3 v, Vector3 n, float r)
|
|||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition - Vector4 math
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Get vector zero
|
||||
RMAPI Vector4 Vector4Zero(void)
|
||||
{
|
||||
Vector4 result = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get vector one
|
||||
RMAPI Vector4 Vector4One(void)
|
||||
{
|
||||
Vector4 result = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
return result;
|
||||
}
|
||||
|
||||
// Add two vectors
|
||||
RMAPI Vector4 Vector4Add(Vector4 v1, Vector4 v2)
|
||||
{
|
||||
Vector4 result = {
|
||||
|
|
@ -1288,6 +1290,7 @@ RMAPI Vector4 Vector4Add(Vector4 v1, Vector4 v2)
|
|||
return result;
|
||||
}
|
||||
|
||||
// Add value to vector components
|
||||
RMAPI Vector4 Vector4AddValue(Vector4 v, float add)
|
||||
{
|
||||
Vector4 result = {
|
||||
|
|
@ -1299,6 +1302,7 @@ RMAPI Vector4 Vector4AddValue(Vector4 v, float add)
|
|||
return result;
|
||||
}
|
||||
|
||||
// Substract vectors
|
||||
RMAPI Vector4 Vector4Subtract(Vector4 v1, Vector4 v2)
|
||||
{
|
||||
Vector4 result = {
|
||||
|
|
@ -1310,6 +1314,7 @@ RMAPI Vector4 Vector4Subtract(Vector4 v1, Vector4 v2)
|
|||
return result;
|
||||
}
|
||||
|
||||
// Substract value from vector components
|
||||
RMAPI Vector4 Vector4SubtractValue(Vector4 v, float add)
|
||||
{
|
||||
Vector4 result = {
|
||||
|
|
@ -1321,18 +1326,21 @@ RMAPI Vector4 Vector4SubtractValue(Vector4 v, float add)
|
|||
return result;
|
||||
}
|
||||
|
||||
// Vector length
|
||||
RMAPI float Vector4Length(Vector4 v)
|
||||
{
|
||||
float result = sqrtf((v.x*v.x) + (v.y*v.y) + (v.z*v.z) + (v.w*v.w));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Vector square length
|
||||
RMAPI float Vector4LengthSqr(Vector4 v)
|
||||
{
|
||||
float result = (v.x*v.x) + (v.y*v.y) + (v.z*v.z) + (v.w*v.w);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Vectors dot product
|
||||
RMAPI float Vector4DotProduct(Vector4 v1, Vector4 v2)
|
||||
{
|
||||
float result = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z + v1.w*v2.w);
|
||||
|
|
@ -1358,6 +1366,7 @@ RMAPI float Vector4DistanceSqr(Vector4 v1, Vector4 v2)
|
|||
return result;
|
||||
}
|
||||
|
||||
// Scale vector components by value (multiply)
|
||||
RMAPI Vector4 Vector4Scale(Vector4 v, float scale)
|
||||
{
|
||||
Vector4 result = { v.x*scale, v.y*scale, v.z*scale, v.w*scale };
|
||||
|
|
@ -1753,13 +1762,14 @@ RMAPI Matrix MatrixMultiply(Matrix left, Matrix right)
|
|||
return result;
|
||||
}
|
||||
|
||||
// Multiply matrix components by value
|
||||
RMAPI Matrix MatrixMultiplyValue(Matrix left, float value)
|
||||
{
|
||||
Matrix result = {
|
||||
left.m0 * value, left.m4 * value, left.m8 * value, left.m12 * value,
|
||||
left.m1 * value, left.m5 * value, left.m9 * value, left.m13 * value,
|
||||
left.m2 * value, left.m6 * value, left.m10 * value, left.m14 * value,
|
||||
left.m3 * value, left.m7 * value, left.m11 * value, left.m15 * value
|
||||
left.m0*value, left.m4*value, left.m8*value, left.m12*value,
|
||||
left.m1*value, left.m5*value, left.m9*value, left.m13*value,
|
||||
left.m2*value, left.m6*value, left.m10*value, left.m14*value,
|
||||
left.m3*value, left.m7*value, left.m11*value, left.m15*value
|
||||
};
|
||||
|
||||
return result;
|
||||
|
|
@ -2495,19 +2505,14 @@ RMAPI Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle)
|
|||
{
|
||||
Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
|
||||
float axisLength = sqrtf(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z);
|
||||
float length = sqrtf(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z);
|
||||
|
||||
if (axisLength != 0.0f)
|
||||
if (length != 0.0f)
|
||||
{
|
||||
angle *= 0.5f;
|
||||
|
||||
float length = 0.0f;
|
||||
float ilength = 0.0f;
|
||||
|
||||
// Vector3Normalize(axis)
|
||||
length = axisLength;
|
||||
if (length == 0.0f) length = 1.0f;
|
||||
ilength = 1.0f/length;
|
||||
float ilength = 1.0f/length;
|
||||
axis.x *= ilength;
|
||||
axis.y *= ilength;
|
||||
axis.z *= ilength;
|
||||
|
|
@ -2797,6 +2802,11 @@ inline const Vector2& operator -= (Vector2& lhs, const Vector2& rhs)
|
|||
return lhs;
|
||||
}
|
||||
|
||||
inline Vector2 operator * (const float& lhs, const Vector2& rhs)
|
||||
{
|
||||
return Vector2Scale(rhs, lhs);
|
||||
}
|
||||
|
||||
inline Vector2 operator * (const Vector2& lhs, const float& rhs)
|
||||
{
|
||||
return Vector2Scale(lhs, rhs);
|
||||
|
|
@ -2891,6 +2901,11 @@ inline const Vector3& operator -= (Vector3& lhs, const Vector3& rhs)
|
|||
return lhs;
|
||||
}
|
||||
|
||||
inline Vector3 operator * (const float& lhs, const Vector3& rhs)
|
||||
{
|
||||
return Vector3Scale(rhs, lhs);
|
||||
}
|
||||
|
||||
inline Vector3 operator * (const Vector3& lhs, const float& rhs)
|
||||
{
|
||||
return Vector3Scale(lhs, rhs);
|
||||
|
|
@ -2986,6 +3001,11 @@ inline const Vector4& operator -= (Vector4& lhs, const Vector4& rhs)
|
|||
return lhs;
|
||||
}
|
||||
|
||||
inline Vector4 operator * (const float& lhs, const Vector4& rhs)
|
||||
{
|
||||
return Vector4Scale(rhs, lhs);
|
||||
}
|
||||
|
||||
inline Vector4 operator * (const Vector4& lhs, const float& rhs)
|
||||
{
|
||||
return Vector4Scale(lhs, rhs);
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@
|
|||
Vector3 position; // Camera position
|
||||
Vector3 target; // Camera target it looks-at
|
||||
Vector3 up; // Camera up vector (rotation over its axis)
|
||||
float fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic
|
||||
float fovy; // Camera field-of-view aperture in Y (degrees) in perspective, used as near plane width in orthographic
|
||||
int projection; // Camera projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC
|
||||
} Camera3D;
|
||||
|
||||
|
|
@ -352,7 +352,7 @@ void CameraYaw(Camera *camera, float angle, bool rotateAroundTarget)
|
|||
// Rotates the camera around its right vector, pitch is "looking up and down"
|
||||
// - lockView prevents camera overrotation (aka "somersaults")
|
||||
// - rotateAroundTarget defines if rotation is around target or around its position
|
||||
// - rotateUp rotates the up direction as well (typically only usefull in CAMERA_FREE)
|
||||
// - rotateUp rotates the up direction as well (typically only useful in CAMERA_FREE)
|
||||
// NOTE: [angle] must be provided in radians
|
||||
void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp)
|
||||
{
|
||||
|
|
|
|||
274
src/rcore.c
274
src/rcore.c
|
|
@ -35,31 +35,31 @@
|
|||
* - Memory framebuffer output, using software renderer, no OS required
|
||||
*
|
||||
* CONFIGURATION:
|
||||
* #define SUPPORT_CAMERA_SYSTEM
|
||||
* #define SUPPORT_CAMERA_SYSTEM 1
|
||||
* Camera module is included (rcamera.h) and multiple predefined cameras are available:
|
||||
* free, 1st/3rd person, orbital, custom
|
||||
*
|
||||
* #define SUPPORT_GESTURES_SYSTEM
|
||||
* #define SUPPORT_GESTURES_SYSTEM 1
|
||||
* Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag
|
||||
*
|
||||
* #define SUPPORT_MOUSE_GESTURES
|
||||
* #define SUPPORT_MOUSE_GESTURES 1
|
||||
* Mouse gestures are directly mapped like touches and processed by gestures system
|
||||
*
|
||||
* #define SUPPORT_BUSY_WAIT_LOOP
|
||||
* #define SUPPORT_BUSY_WAIT_LOOP 1
|
||||
* Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used
|
||||
*
|
||||
* #define SUPPORT_PARTIALBUSY_WAIT_LOOP
|
||||
* #define SUPPORT_PARTIALBUSY_WAIT_LOOP 0
|
||||
* Use a partial-busy wait loop, in this case frame sleeps for most of the time and runs a busy-wait-loop at the end
|
||||
*
|
||||
* #define SUPPORT_SCREEN_CAPTURE
|
||||
* #define SUPPORT_SCREEN_CAPTURE 1
|
||||
* Allow automatic screen capture of current screen pressing F12, defined in KeyCallback()
|
||||
*
|
||||
* #define SUPPORT_COMPRESSION_API
|
||||
* #define SUPPORT_COMPRESSION_API 1
|
||||
* Support CompressData() and DecompressData() functions, those functions use zlib implementation
|
||||
* provided by stb_image and stb_image_write libraries, so, those libraries must be enabled on textures module
|
||||
* for linkage
|
||||
*
|
||||
* #define SUPPORT_AUTOMATION_EVENTS
|
||||
* #define SUPPORT_AUTOMATION_EVENTS 1
|
||||
* Support automatic events recording and playing, useful for automated testing systems or AI based game playing
|
||||
*
|
||||
* DEPENDENCIES:
|
||||
|
|
@ -106,7 +106,7 @@
|
|||
|
||||
#include "config.h" // Defines module configuration flags
|
||||
|
||||
#include <stdlib.h> // Required for: srand(), rand(), atexit(), exit()
|
||||
#include <stdlib.h> // Required for: srand(), rand(), exit()
|
||||
#include <stdio.h> // Required for: FILE, fopen(), fseek(), ftell(), fread(), fwrite(), fprintf(), vprintf(), fclose(), sprintf() [Used in OpenURL()]
|
||||
#include <string.h> // Required for: strlen(), strncpy(), strcmp(), strrchr(), memset(), strcat()
|
||||
#include <stdarg.h> // Required for: va_list, va_start(), va_end() [Used in TraceLog()]
|
||||
|
|
@ -267,15 +267,18 @@
|
|||
#define MAX_AUTOMATION_EVENTS 16384 // Maximum number of automation events to record
|
||||
#endif
|
||||
|
||||
// File and directory scan filters
|
||||
// NOTE: Used in ScanDirectoryFiles(), LoadDirectoryFilesEx() and GetDirectoryFileCountEx()
|
||||
// WARNING: Custom file filters can be specified but following raylib IsFileExtension() convention: ".png;.wav;.glb"
|
||||
#ifndef FILE_FILTER_TAG_ALL
|
||||
#define FILE_FILTER_TAG_ALL "*.*" // Filter to include all file types and directories on directory scan
|
||||
#endif // NOTE: Used in ScanDirectoryFiles(), LoadDirectoryFilesEx() and GetDirectoryFileCountEx()
|
||||
#define FILE_FILTER_TAG_ALL "*.*" // Filter to include all file types and directories on scan
|
||||
#endif
|
||||
#ifndef FILE_FILTER_TAG_FILE_ONLY
|
||||
#define FILE_FILTER_TAG_FILE_ONLY "FILES*" // Filter to include all file types on directory scan
|
||||
#endif // NOTE: Used in ScanDirectoryFiles(), LoadDirectoryFilesEx() and GetDirectoryFileCountEx()
|
||||
#define FILE_FILTER_TAG_FILE_ONLY "FILES*" // Filter to include all file types on scan (no directories)
|
||||
#endif
|
||||
#ifndef FILE_FILTER_TAG_DIR_ONLY
|
||||
#define FILE_FILTER_TAG_DIR_ONLY "DIR*" // Filter to include directories on directory scan
|
||||
#endif // NOTE: Used in ScanDirectoryFiles(), LoadDirectoryFilesEx() and GetDirectoryFileCountEx()
|
||||
#define FILE_FILTER_TAG_DIR_ONLY "DIRS*" // Filter to include only directories on scan
|
||||
#endif
|
||||
|
||||
// Flags bitwise operation macros
|
||||
#define FLAG_SET(n, f) ((n) |= (f))
|
||||
|
|
@ -304,7 +307,7 @@ typedef struct CoreData {
|
|||
Size screen; // Screen current width and height
|
||||
Point position; // Window current position
|
||||
Size previousScreen; // Screen previous width and height (required on fullscreen/borderless-windowed toggle)
|
||||
Point previousPosition; // Window previous position (required on fullscreeen/borderless-windowed toggle)
|
||||
Point previousPosition; // Window previous position (required on fullscreen/borderless-windowed toggle)
|
||||
Size render; // Screen framebuffer width and height
|
||||
Point renderOffset; // Screen framebuffer render offset (Not required anymore?)
|
||||
Size currentFbo; // Current framebuffer render width and height (depends on active render texture)
|
||||
|
|
@ -326,7 +329,7 @@ typedef struct CoreData {
|
|||
char currentKeyState[MAX_KEYBOARD_KEYS]; // Registers current frame key state
|
||||
char previousKeyState[MAX_KEYBOARD_KEYS]; // Registers previous frame key state
|
||||
|
||||
// NOTE: Since key press logic involves comparing previous vs currrent key state,
|
||||
// NOTE: Since key press logic involves comparing previous vs current key state,
|
||||
// key repeats needs to be handled specially
|
||||
char keyRepeatInFrame[MAX_KEYBOARD_KEYS]; // Registers key repeats for current frame
|
||||
|
||||
|
|
@ -376,14 +379,14 @@ typedef struct CoreData {
|
|||
} Gamepad;
|
||||
} Input;
|
||||
struct {
|
||||
double current; // Current time measure
|
||||
double previous; // Previous time measure
|
||||
double update; // Time measure for frame update
|
||||
double draw; // Time measure for frame draw
|
||||
double frame; // Time measure for one frame
|
||||
double target; // Desired time for one frame, if 0 not applied
|
||||
unsigned long long int base; // Base time measure for hi-res timer (PLATFORM_ANDROID, PLATFORM_DRM)
|
||||
unsigned int frameCounter; // Frame counter
|
||||
double current; // Current time measure (seconds)
|
||||
double previous; // Previous time measure (seconds)
|
||||
double update; // Time measure for frame update (seconds)
|
||||
double draw; // Time measure for frame draw (seconds)
|
||||
double frame; // Time measure for one frame (seconds)
|
||||
double target; // Desired time for one frame, if 0 not applied (seconds)
|
||||
unsigned long long base; // Base time measure for hi-res timer (ticks or nanoseconds)
|
||||
unsigned int frameCounter; // Frame counter (frames)
|
||||
|
||||
} Time;
|
||||
} CoreData;
|
||||
|
|
@ -439,18 +442,6 @@ typedef enum AutomationEventType {
|
|||
ACTION_SETTARGETFPS // param[0]: fps
|
||||
} AutomationEventType;
|
||||
|
||||
// Event type to config events flags
|
||||
// WARNING: Not used at the moment
|
||||
typedef enum {
|
||||
EVENT_INPUT_KEYBOARD = 0,
|
||||
EVENT_INPUT_MOUSE = 1,
|
||||
EVENT_INPUT_GAMEPAD = 2,
|
||||
EVENT_INPUT_TOUCH = 4,
|
||||
EVENT_INPUT_GESTURE = 8,
|
||||
EVENT_WINDOW = 16,
|
||||
EVENT_CUSTOM = 32
|
||||
} EventType;
|
||||
|
||||
// Event type name strings, required for export
|
||||
static const char *autoEventTypeName[] = {
|
||||
"EVENT_NONE",
|
||||
|
|
@ -479,16 +470,6 @@ static const char *autoEventTypeName[] = {
|
|||
"ACTION_SETTARGETFPS"
|
||||
};
|
||||
|
||||
/*
|
||||
// Automation event (24 bytes)
|
||||
// NOTE: Opaque struct, internal to raylib
|
||||
struct AutomationEvent {
|
||||
unsigned int frame; // Event frame
|
||||
unsigned int type; // Event type (AutomationEventType)
|
||||
int params[4]; // Event parameters (if required)
|
||||
};
|
||||
*/
|
||||
|
||||
static AutomationEventList *currentEventList = NULL; // Current automation events list, set by user, keep internal pointer
|
||||
static bool automationEventRecording = false; // Recording automation events flag
|
||||
//static short automationEventEnabled = 0b0000001111111111; // TODO: Automation events enabled for recording/playing
|
||||
|
|
@ -684,7 +665,7 @@ void InitWindow(int width, int height, const char *title)
|
|||
}
|
||||
|
||||
// Initialize render dimensions for embedded platforms
|
||||
// NOTE: On desktop platforms (GLFW, SDL, etc.), CORE.Window.render.width/height are set during window creation
|
||||
// NOTE: On desktop platforms (GLFW, SDL, etc.), CORE.Window.render.width/height are set during window creation
|
||||
// On embedded platforms with no window manager, InitPlatform() doesn't set these values, so they should be initialized
|
||||
// here from screen dimensions (which are set from the InitWindow parameters)
|
||||
if ((CORE.Window.render.width == 0) || (CORE.Window.render.height == 0))
|
||||
|
|
@ -711,7 +692,7 @@ void InitWindow(int width, int height, const char *title)
|
|||
Rectangle rec = GetFontDefault().recs[95];
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
|
||||
{
|
||||
// NOTE: Try to maxime rec padding to avoid pixel bleeding on MSAA filtering
|
||||
// NOTE: Try to maximize rec padding to avoid pixel bleeding on MSAA filtering
|
||||
SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 });
|
||||
}
|
||||
else
|
||||
|
|
@ -821,7 +802,7 @@ int GetRenderWidth(void)
|
|||
{
|
||||
int width = 0;
|
||||
|
||||
if (CORE.Window.usingFbo) return CORE.Window.currentFbo.width;
|
||||
if (CORE.Window.usingFbo) width = CORE.Window.currentFbo.width;
|
||||
else width = CORE.Window.render.width;
|
||||
|
||||
return width;
|
||||
|
|
@ -832,7 +813,7 @@ int GetRenderHeight(void)
|
|||
{
|
||||
int height = 0;
|
||||
|
||||
if (CORE.Window.usingFbo) return CORE.Window.currentFbo.height;
|
||||
if (CORE.Window.usingFbo) height = CORE.Window.currentFbo.height;
|
||||
else height = CORE.Window.render.height;
|
||||
|
||||
return height;
|
||||
|
|
@ -866,14 +847,14 @@ bool IsCursorOnScreen(void)
|
|||
// Module Functions Definition: Screen Drawing
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Set background color (framebuffer clear color)
|
||||
// Clear background (framebuffer) to color
|
||||
void ClearBackground(Color color)
|
||||
{
|
||||
rlClearColor(color.r, color.g, color.b, color.a); // Set clear color
|
||||
rlClearScreenBuffers(); // Clear current framebuffers
|
||||
}
|
||||
|
||||
// Setup canvas (framebuffer) to start drawing
|
||||
// Begin canvas (framebuffer) drawing
|
||||
void BeginDrawing(void)
|
||||
{
|
||||
// WARNING: Previously to BeginDrawing() other render textures drawing could happen,
|
||||
|
|
@ -890,7 +871,7 @@ void BeginDrawing(void)
|
|||
// NOTE: Not required with OpenGL 3.3+
|
||||
}
|
||||
|
||||
// End canvas drawing and swap buffers (double buffering)
|
||||
// End canvas (framebuffer) drawing and swap buffers (double buffering)
|
||||
void EndDrawing(void)
|
||||
{
|
||||
rlDrawRenderBatchActive(); // Update and draw internal render batch
|
||||
|
|
@ -946,7 +927,7 @@ void BeginMode2D(Camera2D camera)
|
|||
rlMultMatrixf(MatrixToFloat(GetCameraMatrix2D(camera)));
|
||||
}
|
||||
|
||||
// Ends 2D mode with custom camera
|
||||
// End 2D mode with custom camera
|
||||
void EndMode2D(void)
|
||||
{
|
||||
rlDrawRenderBatchActive(); // Update and draw internal render batch
|
||||
|
|
@ -995,7 +976,7 @@ void BeginMode3D(Camera camera)
|
|||
rlEnableDepthTest(); // Enable DEPTH_TEST for 3D
|
||||
}
|
||||
|
||||
// Ends 3D mode and returns to default 2D orthographic mode
|
||||
// End 3D mode and returns to default 2D orthographic mode
|
||||
void EndMode3D(void)
|
||||
{
|
||||
rlDrawRenderBatchActive(); // Update and draw internal render batch
|
||||
|
|
@ -1042,7 +1023,7 @@ void BeginTextureMode(RenderTexture2D target)
|
|||
CORE.Window.usingFbo = true;
|
||||
}
|
||||
|
||||
// Ends drawing to render texture
|
||||
// End drawing to render texture
|
||||
void EndTextureMode(void)
|
||||
{
|
||||
rlDrawRenderBatchActive(); // Update and draw internal render batch
|
||||
|
|
@ -1227,7 +1208,7 @@ void UnloadVrStereoConfig(VrStereoConfig config)
|
|||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Load shader from files and bind default locations
|
||||
// NOTE: If shader string is NULL, using default vertex/fragment shaders
|
||||
// NOTE: If shader filename is NULL, using default vertex/fragment shaders
|
||||
Shader LoadShader(const char *vsFileName, const char *fsFileName)
|
||||
{
|
||||
Shader shader = { 0 };
|
||||
|
|
@ -1511,7 +1492,7 @@ Matrix GetCameraMatrix2D(Camera2D camera)
|
|||
return matTransform;
|
||||
}
|
||||
|
||||
// Get the screen space position from a 3d world space position
|
||||
// Get screen space position from a 3d world space position
|
||||
Vector2 GetWorldToScreen(Vector3 position, Camera camera)
|
||||
{
|
||||
Vector2 screenPosition = GetWorldToScreenEx(position, camera, GetScreenWidth(), GetScreenHeight());
|
||||
|
|
@ -1519,7 +1500,7 @@ Vector2 GetWorldToScreen(Vector3 position, Camera camera)
|
|||
return screenPosition;
|
||||
}
|
||||
|
||||
// Get size position for a 3d world space position (useful for texture drawing)
|
||||
// Get sized screen space position for a 3d world space position (useful for texture drawing)
|
||||
Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int height)
|
||||
{
|
||||
// Calculate projection matrix (from perspective instead of frustum
|
||||
|
|
@ -1561,7 +1542,7 @@ Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int heigh
|
|||
return screenPosition;
|
||||
}
|
||||
|
||||
// Get the screen space position for a 2d camera world space position
|
||||
// Get screen space position for a 2d camera world space position
|
||||
Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera)
|
||||
{
|
||||
Matrix matCamera = GetCameraMatrix2D(camera);
|
||||
|
|
@ -1570,7 +1551,7 @@ Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera)
|
|||
return (Vector2){ transform.x, transform.y };
|
||||
}
|
||||
|
||||
// Get the world space position for a 2d camera screen space position
|
||||
// Get world space position for a 2d camera screen space position
|
||||
Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera)
|
||||
{
|
||||
Matrix invMatCamera = MatrixInvert(GetCameraMatrix2D(camera));
|
||||
|
|
@ -1621,18 +1602,20 @@ int GetFPS(void)
|
|||
for (int i = 0; i < FPS_CAPTURE_FRAMES_COUNT; i++) history[i] = 0;
|
||||
}
|
||||
|
||||
if (fpsFrame == 0) return 0;
|
||||
|
||||
if ((GetTime() - last) > FPS_STEP)
|
||||
if (fpsFrame != 0)
|
||||
{
|
||||
last = (float)GetTime();
|
||||
index = (index + 1)%FPS_CAPTURE_FRAMES_COUNT;
|
||||
average -= history[index];
|
||||
history[index] = fpsFrame/FPS_CAPTURE_FRAMES_COUNT;
|
||||
average += history[index];
|
||||
}
|
||||
if ((GetTime() - last) > FPS_STEP)
|
||||
{
|
||||
last = (float)GetTime();
|
||||
index = (index + 1)%FPS_CAPTURE_FRAMES_COUNT;
|
||||
average -= history[index];
|
||||
history[index] = fpsFrame/FPS_CAPTURE_FRAMES_COUNT;
|
||||
average += history[index];
|
||||
}
|
||||
|
||||
fps = (int)roundf(1.0f/average);
|
||||
fps = (int)roundf(1.0f/average);
|
||||
}
|
||||
else fps = 0;
|
||||
#endif
|
||||
|
||||
return fps;
|
||||
|
|
@ -1752,9 +1735,9 @@ int GetRandomValue(int min, int max)
|
|||
else
|
||||
{
|
||||
// Rejection sampling to get a uniform integer in [min, max]
|
||||
unsigned long c = (unsigned long)RAND_MAX + 1UL; // number of possible rand() results
|
||||
unsigned long m = (unsigned long)range; // size of the target interval
|
||||
unsigned long t = c - (c%m); // largest multiple of m <= c
|
||||
unsigned long c = (unsigned long)RAND_MAX + 1UL; // Number of possible results
|
||||
unsigned long m = (unsigned long)range; // Size of the target interval
|
||||
unsigned long t = c - (c%m); // Largest multiple of m <= c
|
||||
unsigned long r = 0;
|
||||
|
||||
for (;;)
|
||||
|
|
@ -1848,7 +1831,7 @@ void TakeScreenshot(const char *fileName)
|
|||
#endif
|
||||
}
|
||||
|
||||
// Setup window configuration flags (view FLAGS)
|
||||
// Set up window configuration flags (view FLAGS)
|
||||
// NOTE: This function is expected to be called before window creation,
|
||||
// because it sets up some flags for the window creation process
|
||||
// To configure window states after creation, use SetWindowState()
|
||||
|
|
@ -1987,7 +1970,7 @@ unsigned char *LoadFileData(const char *fileName, int *dataSize)
|
|||
size_t count = fread(data, sizeof(unsigned char), size, file);
|
||||
|
||||
// WARNING: fread() returns a size_t value, usually 'unsigned int' (32bit compilation) and 'unsigned long long' (64bit compilation)
|
||||
// dataSize is unified along raylib as a 'int' type, so, for file-sizes > INT_MAX (2147483647 bytes) there is a limitation
|
||||
// dataSize is unified along raylib as a 'int' type, so, for file-sizes >INT_MAX (2147483647 bytes) there is a limitation
|
||||
if (count > 2147483647)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "FILEIO: [%s] File is bigger than 2147483647 bytes, avoid using LoadFileData()", fileName);
|
||||
|
|
@ -1999,7 +1982,7 @@ unsigned char *LoadFileData(const char *fileName, int *dataSize)
|
|||
{
|
||||
*dataSize = (int)count;
|
||||
|
||||
if ((*dataSize) != size) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially loaded (%i bytes out of %i)", fileName, dataSize, count);
|
||||
if ((*dataSize) != size) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially loaded (%i bytes out of %i)", fileName, *dataSize, size);
|
||||
else TRACELOG(LOG_INFO, "FILEIO: [%s] File loaded successfully", fileName);
|
||||
}
|
||||
}
|
||||
|
|
@ -2023,9 +2006,9 @@ void UnloadFileData(unsigned char *data)
|
|||
}
|
||||
|
||||
// Save data to file from buffer
|
||||
bool SaveFileData(const char *fileName, void *data, int dataSize)
|
||||
bool SaveFileData(const char *fileName, const void *data, int dataSize)
|
||||
{
|
||||
bool success = false;
|
||||
bool result = false;
|
||||
|
||||
if (fileName != NULL)
|
||||
{
|
||||
|
|
@ -2043,20 +2026,20 @@ bool SaveFileData(const char *fileName, void *data, int dataSize)
|
|||
else if (count != dataSize) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially written", fileName);
|
||||
else TRACELOG(LOG_INFO, "FILEIO: [%s] File saved successfully", fileName);
|
||||
|
||||
int result = fclose(file);
|
||||
if (result == 0) success = true;
|
||||
int closed = fclose(file);
|
||||
if (closed == 0) result = true;
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName);
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
|
||||
|
||||
return success;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Export data to code (.h), returns true on success
|
||||
bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName)
|
||||
{
|
||||
bool success = false;
|
||||
bool result = false;
|
||||
|
||||
#ifndef TEXT_BYTES_PER_LINE
|
||||
#define TEXT_BYTES_PER_LINE 20
|
||||
|
|
@ -2096,14 +2079,14 @@ bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileN
|
|||
byteCount += sprintf(txtData + byteCount, "0x%x };\n", data[dataSize - 1]);
|
||||
|
||||
// NOTE: Text data size exported is determined by '\0' (NULL) character
|
||||
success = SaveFileText(fileName, txtData);
|
||||
result = SaveFileText(fileName, txtData);
|
||||
|
||||
RL_FREE(txtData);
|
||||
|
||||
if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Data as code exported successfully", fileName);
|
||||
if (result != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Data as code exported successfully", fileName);
|
||||
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export data as code", fileName);
|
||||
|
||||
return success;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Load text data from file, returns a '\0' terminated string
|
||||
|
|
@ -2166,7 +2149,7 @@ void UnloadFileText(char *text)
|
|||
// Save text data to file (write), string must be '\0' terminated
|
||||
bool SaveFileText(const char *fileName, const char *text)
|
||||
{
|
||||
bool success = false;
|
||||
bool result = false;
|
||||
|
||||
if (fileName != NULL)
|
||||
{
|
||||
|
|
@ -2181,14 +2164,14 @@ bool SaveFileText(const char *fileName, const char *text)
|
|||
if (count < 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write text file", fileName);
|
||||
else TRACELOG(LOG_INFO, "FILEIO: [%s] Text file saved successfully", fileName);
|
||||
|
||||
int result = fclose(file);
|
||||
if (result == 0) success = true;
|
||||
int closed = fclose(file);
|
||||
if (closed == 0) result = true;
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName);
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
|
||||
|
||||
return success;
|
||||
return result;
|
||||
}
|
||||
|
||||
// File access custom callbacks
|
||||
|
|
@ -2278,10 +2261,11 @@ int FileMove(const char *srcPath, const char *dstPath)
|
|||
|
||||
if (FileExists(srcPath))
|
||||
{
|
||||
if (FileCopy(srcPath, dstPath) == 0)
|
||||
result = FileRemove(srcPath);
|
||||
else
|
||||
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to copy file to [%s]", srcPath, dstPath);
|
||||
FileCopy(srcPath, dstPath);
|
||||
|
||||
// Make sure file has been correctly copied before removing
|
||||
if (FileExists(dstPath) && (GetFileLength(srcPath) == GetFileLength(dstPath))) result = FileRemove(srcPath);
|
||||
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to copy file to [%s]", srcPath, dstPath);
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Source file does not exist", srcPath);
|
||||
|
||||
|
|
@ -2300,7 +2284,7 @@ int FileTextReplace(const char *fileName, const char *search, const char *replac
|
|||
if (FileExists(fileName))
|
||||
{
|
||||
fileText = LoadFileText(fileName);
|
||||
fileTextUpdated = TextReplace(fileText, search, replacement);
|
||||
fileTextUpdated = TextReplaceAlloc(fileText, search, replacement);
|
||||
result = SaveFileText(fileName, fileTextUpdated);
|
||||
MemFree(fileTextUpdated);
|
||||
UnloadFileText(fileText);
|
||||
|
|
@ -2359,8 +2343,7 @@ bool IsFileExtension(const char *fileName, const char *ext)
|
|||
{
|
||||
int fileExtLength = (int)strlen(fileExt);
|
||||
char fileExtLower[16] = { 0 };
|
||||
char *fileExtLowerPtr = fileExtLower;
|
||||
for (int i = 0; (i < fileExtLength) && (i < 16); i++)
|
||||
for (int i = 0; (i < fileExtLength) && (i < 15); i++)
|
||||
{
|
||||
// Copy and convert to lower-case
|
||||
if ((fileExt[i] >= 'A') && (fileExt[i] <= 'Z')) fileExtLower[i] = fileExt[i] + 32;
|
||||
|
|
@ -2371,7 +2354,7 @@ bool IsFileExtension(const char *fileName, const char *ext)
|
|||
int extLength = (int)strlen(ext);
|
||||
char *extList = (char *)RL_CALLOC(extLength + 1, 1);
|
||||
char *extListPtrs[MAX_FILE_EXTENSIONS] = { 0 };
|
||||
strncpy(extList, ext, extLength);
|
||||
memcpy(extList, ext, extLength);
|
||||
extListPtrs[0] = extList;
|
||||
|
||||
for (int i = 0; i < extLength; i++)
|
||||
|
|
@ -2380,11 +2363,15 @@ bool IsFileExtension(const char *fileName, const char *ext)
|
|||
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)))
|
||||
if (extList[i] == ';')
|
||||
{
|
||||
extList[i] = '\0';
|
||||
extListPtrs[extCount] = extList + i + 1;
|
||||
extCount++;
|
||||
|
||||
if (extCount < MAX_FILE_EXTENSIONS)
|
||||
{
|
||||
extListPtrs[extCount] = extList + i + 1;
|
||||
extCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2392,7 +2379,7 @@ bool IsFileExtension(const char *fileName, const char *ext)
|
|||
{
|
||||
// Consider the case where extension provided
|
||||
// does not start with the '.'
|
||||
fileExtLowerPtr = fileExtLower;
|
||||
char *fileExtLowerPtr = fileExtLower;
|
||||
if (extListPtrs[i][0] != '.') fileExtLowerPtr++;
|
||||
|
||||
if (strcmp(fileExtLowerPtr, extListPtrs[i]) == 0)
|
||||
|
|
@ -2511,9 +2498,9 @@ const char *GetFileNameWithoutExt(const char *filePath)
|
|||
if (filePath != NULL)
|
||||
{
|
||||
strncpy(fileName, GetFileName(filePath), MAX_FILENAME_LENGTH - 1); // Get filename.ext without path
|
||||
int fileNameLenght = (int)strlen(fileName); // Get size in bytes
|
||||
int fileNameLength = (int)strlen(fileName); // Get size in bytes
|
||||
|
||||
for (int i = fileNameLenght; i > 0; i--) // Reverse search '.'
|
||||
for (int i = fileNameLength; i > 0; i--) // Reverse search '.'
|
||||
{
|
||||
if (fileName[i] == '.')
|
||||
{
|
||||
|
|
@ -2605,7 +2592,7 @@ const char *GetWorkingDirectory(void)
|
|||
static char currentDir[MAX_FILEPATH_LENGTH] = { 0 };
|
||||
memset(currentDir, 0, MAX_FILEPATH_LENGTH);
|
||||
|
||||
char *path = GETCWD(currentDir, MAX_FILEPATH_LENGTH - 1);
|
||||
char *path = GETCWD(currentDir, MAX_FILEPATH_LENGTH);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
|
@ -2720,17 +2707,18 @@ const char *GetApplicationDirectory(void)
|
|||
|
||||
// Load directory filepaths
|
||||
// NOTE: Base path is prepended to the scanned filepaths
|
||||
// WARNING: Directory is scanned twice, first time to get files count
|
||||
// No recursive scanning is done!
|
||||
// WARNING: Directory is scanned twice, first time to get paths count
|
||||
// Scanneed files and directories, no recursive/subdirs scanning
|
||||
FilePathList LoadDirectoryFiles(const char *dirPath)
|
||||
{
|
||||
return LoadDirectoryFilesEx(dirPath, FILE_FILTER_TAG_ALL, false);
|
||||
}
|
||||
|
||||
// Load directory filepaths with extension filtering and recursive directory scan
|
||||
// Use 'DIR*' to include directories on directory scan
|
||||
// Use '*.*' to include all file types and directories on directory scan
|
||||
// WARNING: Directory is scanned twice, first time to get files count
|
||||
// Use "*.*" to include all files and directories on scan
|
||||
// Use "FILES*" to include only files on scan
|
||||
// Use "DIRS*" to include only directories on scan
|
||||
// WARNING: Directory is scanned twice, first time to get paths count
|
||||
FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs)
|
||||
{
|
||||
FilePathList files = { 0 };
|
||||
|
|
@ -2951,9 +2939,9 @@ unsigned int GetDirectoryFileCountEx(const char *basePath, const char *filter, b
|
|||
{
|
||||
// Construct new path from our base path
|
||||
#if defined(_WIN32)
|
||||
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s\\%s", basePath, entity->d_name);
|
||||
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH, "%s\\%s", basePath, entity->d_name);
|
||||
#else
|
||||
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s/%s", basePath, entity->d_name);
|
||||
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH, "%s/%s", basePath, entity->d_name);
|
||||
#endif
|
||||
// Don't add to count if path too long
|
||||
if ((pathLength < 0) || (pathLength >= MAX_FILEPATH_LENGTH))
|
||||
|
|
@ -3035,7 +3023,7 @@ unsigned char *DecompressData(const unsigned char *compData, int compDataSize, i
|
|||
char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize)
|
||||
{
|
||||
// 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)
|
||||
// NOTE: They represent 64 values (6 bits), to encode 3 bytes of data into 4 "sextets" (6bit characters)
|
||||
static const char base64EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
// Compute expected size and padding
|
||||
|
|
@ -3122,7 +3110,7 @@ unsigned char *DecodeDataBase64(const char *text, int *outputSize)
|
|||
int outputCount = 0;
|
||||
for (int i = 0; i < dataSize;)
|
||||
{
|
||||
// Every 4 sixtets must generate 3 octets
|
||||
// Every 4 sextets must generate 3 octets
|
||||
if ((i + 2) >= dataSize)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "BASE64: Decoding error: Input data size is not valid");
|
||||
|
|
@ -3156,7 +3144,7 @@ unsigned char *DecodeDataBase64(const char *text, int *outputSize)
|
|||
}
|
||||
|
||||
// Compute CRC32 hash code
|
||||
unsigned int ComputeCRC32(unsigned char *data, int dataSize)
|
||||
unsigned int ComputeCRC32(const unsigned char *data, int dataSize)
|
||||
{
|
||||
static unsigned int crcTable[256] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
|
|
@ -3202,7 +3190,7 @@ unsigned int ComputeCRC32(unsigned char *data, int dataSize)
|
|||
|
||||
// Compute MD5 hash code
|
||||
// NOTE: Returns a static int[4] array (16 bytes)
|
||||
unsigned int *ComputeMD5(unsigned char *data, int dataSize)
|
||||
unsigned int *ComputeMD5(const unsigned char *data, int dataSize)
|
||||
{
|
||||
#define ROTATE_LEFT(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
|
||||
|
||||
|
|
@ -3320,7 +3308,7 @@ unsigned int *ComputeMD5(unsigned char *data, int dataSize)
|
|||
|
||||
// Compute SHA-1 hash code
|
||||
// NOTE: Returns a static int[5] array (20 bytes)
|
||||
unsigned int *ComputeSHA1(unsigned char *data, int dataSize)
|
||||
unsigned int *ComputeSHA1(const unsigned char *data, int dataSize)
|
||||
{
|
||||
#define SHA1_ROTATE_LEFT(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
|
||||
|
||||
|
|
@ -3348,15 +3336,15 @@ unsigned int *ComputeSHA1(unsigned char *data, int dataSize)
|
|||
memcpy(msg, data, dataSize);
|
||||
msg[dataSize] = 128; // Write the '1' bit
|
||||
|
||||
unsigned long long bitsLen = 8ULL * dataSize;
|
||||
msg[newDataSize-1] = (unsigned char)(bitsLen);
|
||||
msg[newDataSize-2] = (unsigned char)(bitsLen >> 8);
|
||||
msg[newDataSize-3] = (unsigned char)(bitsLen >> 16);
|
||||
msg[newDataSize-4] = (unsigned char)(bitsLen >> 24);
|
||||
msg[newDataSize-5] = (unsigned char)(bitsLen >> 32);
|
||||
msg[newDataSize-6] = (unsigned char)(bitsLen >> 40);
|
||||
msg[newDataSize-7] = (unsigned char)(bitsLen >> 48);
|
||||
msg[newDataSize-8] = (unsigned char)(bitsLen >> 56);
|
||||
unsigned long long bitsLen = 8ULL*dataSize;
|
||||
msg[newDataSize - 1] = (unsigned char)(bitsLen);
|
||||
msg[newDataSize - 2] = (unsigned char)(bitsLen >> 8);
|
||||
msg[newDataSize - 3] = (unsigned char)(bitsLen >> 16);
|
||||
msg[newDataSize - 4] = (unsigned char)(bitsLen >> 24);
|
||||
msg[newDataSize - 5] = (unsigned char)(bitsLen >> 32);
|
||||
msg[newDataSize - 6] = (unsigned char)(bitsLen >> 40);
|
||||
msg[newDataSize - 7] = (unsigned char)(bitsLen >> 48);
|
||||
msg[newDataSize - 8] = (unsigned char)(bitsLen >> 56);
|
||||
|
||||
// Process the message in successive 512-bit chunks
|
||||
for (int offset = 0; offset < newDataSize; offset += (512/8))
|
||||
|
|
@ -3430,7 +3418,7 @@ unsigned int *ComputeSHA1(unsigned char *data, int dataSize)
|
|||
|
||||
// Compute SHA-256 hash code
|
||||
// NOTE: Returns a static int[8] array (32 bytes)
|
||||
unsigned int *ComputeSHA256(unsigned char *data, int dataSize)
|
||||
unsigned int *ComputeSHA256(const unsigned char *data, int dataSize)
|
||||
{
|
||||
#define SHA256_ROTATE_RIGHT(x, c) ((x >> c) | (x << ((sizeof(unsigned int)*8) - c)))
|
||||
#define SHA256_A0(x) (SHA256_ROTATE_RIGHT(x, 7) ^ SHA256_ROTATE_RIGHT(x, 18) ^ (x >> 3))
|
||||
|
|
@ -3465,8 +3453,8 @@ unsigned int *ComputeSHA256(unsigned char *data, int dataSize)
|
|||
hash[6] = 0x1f83d9ab;
|
||||
hash[7] = 0x5be0cd19;
|
||||
|
||||
const unsigned long long int bitLen = ((unsigned long long int)dataSize)*8;
|
||||
unsigned long long int paddedSize = dataSize + sizeof(dataSize);
|
||||
const unsigned long long bitLen = 8ULL*dataSize;
|
||||
unsigned long long paddedSize = dataSize + sizeof(dataSize);
|
||||
paddedSize += (64 - (paddedSize%64));
|
||||
unsigned char *buffer = (unsigned char *)RL_CALLOC(paddedSize, sizeof(unsigned char));
|
||||
|
||||
|
|
@ -3477,7 +3465,7 @@ unsigned int *ComputeSHA256(unsigned char *data, int dataSize)
|
|||
buffer[(paddedSize - sizeof(bitLen)) + (i - 1)] = (bitLen >> (8*(sizeof(bitLen) - i))) & 0xFF;
|
||||
}
|
||||
|
||||
for (unsigned long long int blockN = 0; blockN < paddedSize/64; blockN++)
|
||||
for (unsigned long long blockN = 0; blockN < paddedSize/64; blockN++)
|
||||
{
|
||||
unsigned int a = hash[0];
|
||||
unsigned int b = hash[1];
|
||||
|
|
@ -3499,7 +3487,7 @@ unsigned int *ComputeSHA256(unsigned char *data, int dataSize)
|
|||
}
|
||||
for (int t = 16; t < 64; t++) w[t] = SHA256_A1(w[t - 2]) + w[t - 7] + SHA256_A0(w[t - 15]) + w[t - 16];
|
||||
|
||||
for (unsigned long long int t = 0; t < 64; t++)
|
||||
for (int t = 0; t < 64; t++)
|
||||
{
|
||||
unsigned int e1 = (SHA256_ROTATE_RIGHT(e, 6) ^ SHA256_ROTATE_RIGHT(e, 11) ^ SHA256_ROTATE_RIGHT(e, 25));
|
||||
unsigned int ch = ((e & f) ^ (~e & g));
|
||||
|
|
@ -3630,7 +3618,7 @@ void UnloadAutomationEventList(AutomationEventList list)
|
|||
// Export automation events list as text file
|
||||
bool ExportAutomationEventList(AutomationEventList list, const char *fileName)
|
||||
{
|
||||
bool success = false;
|
||||
bool result = false;
|
||||
|
||||
#if SUPPORT_AUTOMATION_EVENTS
|
||||
// Export events as binary file
|
||||
|
|
@ -3648,7 +3636,7 @@ bool ExportAutomationEventList(AutomationEventList list, const char *fileName)
|
|||
memcpy(binBuffer + offset, list.events, sizeof(AutomationEvent)*list.count);
|
||||
offset += sizeof(AutomationEvent)*list.count;
|
||||
|
||||
success = SaveFileData(TextFormat("%s.rae",fileName), binBuffer, binarySize);
|
||||
result = SaveFileData(TextFormat("%s.rae",fileName), binBuffer, binarySize);
|
||||
RL_FREE(binBuffer);
|
||||
}
|
||||
*/
|
||||
|
|
@ -3679,12 +3667,12 @@ bool ExportAutomationEventList(AutomationEventList list, const char *fileName)
|
|||
}
|
||||
|
||||
// NOTE: Text data size exported is determined by '\0' (NULL) character
|
||||
success = SaveFileText(fileName, txtData);
|
||||
result = SaveFileText(fileName, txtData);
|
||||
|
||||
RL_FREE(txtData);
|
||||
#endif
|
||||
|
||||
return success;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Setup automation event list to record to
|
||||
|
|
@ -4121,8 +4109,8 @@ Vector2 GetMouseDelta(void)
|
|||
{
|
||||
Vector2 delta = { 0 };
|
||||
|
||||
delta.x = CORE.Input.Mouse.currentPosition.x - CORE.Input.Mouse.previousPosition.x;
|
||||
delta.y = CORE.Input.Mouse.currentPosition.y - CORE.Input.Mouse.previousPosition.y;
|
||||
delta.x = (CORE.Input.Mouse.currentPosition.x - CORE.Input.Mouse.previousPosition.x)*CORE.Input.Mouse.scale.x;
|
||||
delta.y = (CORE.Input.Mouse.currentPosition.y - CORE.Input.Mouse.previousPosition.y)*CORE.Input.Mouse.scale.y;
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
|
@ -4231,7 +4219,7 @@ void InitTimer(void)
|
|||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) // Success
|
||||
{
|
||||
CORE.Time.base = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec;
|
||||
CORE.Time.base = (unsigned long long)now.tv_sec*1000000000LLU + (unsigned long long)now.tv_nsec;
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "TIMER: Hi-resolution timer not available");
|
||||
#endif
|
||||
|
|
@ -4279,9 +4267,9 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const
|
|||
{
|
||||
// Construct new path from our base path
|
||||
#if defined(_WIN32)
|
||||
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s\\%s", basePath, dp->d_name);
|
||||
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH, "%s\\%s", basePath, dp->d_name);
|
||||
#else
|
||||
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s/%s", basePath, dp->d_name);
|
||||
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH, "%s/%s", basePath, dp->d_name);
|
||||
#endif
|
||||
|
||||
if ((pathLength < 0) || (pathLength >= MAX_FILEPATH_LENGTH))
|
||||
|
|
@ -4293,7 +4281,7 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const
|
|||
if ((filter == NULL) || (strstr(filter, FILE_FILTER_TAG_ALL) != NULL) ||
|
||||
(strstr(filter, FILE_FILTER_TAG_FILE_ONLY) != NULL) || IsFileExtension(path, filter))
|
||||
{
|
||||
strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
|
||||
memcpy(files->paths[files->count], path, pathLength);
|
||||
files->count++;
|
||||
}
|
||||
}
|
||||
|
|
@ -4301,7 +4289,7 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const
|
|||
{
|
||||
if ((filter != NULL) && ((strstr(filter, FILE_FILTER_TAG_DIR_ONLY) != NULL) || (strstr(filter, FILE_FILTER_TAG_ALL) != NULL)))
|
||||
{
|
||||
strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
|
||||
memcpy(files->paths[files->count], path, pathLength);
|
||||
files->count++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,10 +59,13 @@
|
|||
// NOTE: Below types are required for standalone usage
|
||||
//----------------------------------------------------------------------------------
|
||||
// Boolean type
|
||||
#if !defined(__cplusplus)
|
||||
#if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
|
||||
#include <stdbool.h>
|
||||
#elif !defined(__cplusplus) && !defined(bool) && !defined(RL_BOOL_TYPE)
|
||||
#elif !defined(bool)
|
||||
typedef enum bool { false = 0, true = !false } bool;
|
||||
#define RL_BOOL_TYPE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(RL_VECTOR2_TYPE)
|
||||
|
|
@ -124,7 +127,7 @@ void UpdateGestures(void); // Update gestures detec
|
|||
|
||||
#if defined(RGESTURES_STANDALONE)
|
||||
void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags
|
||||
bool IsGestureDetected(int gesture); // Check if a gesture have been detected
|
||||
bool IsGestureDetected(int gesture); // Check if a gesture has been detected
|
||||
int GetGestureDetected(void); // Get latest detected gesture
|
||||
|
||||
float GetGestureHoldDuration(void); // Get gesture hold time in seconds
|
||||
|
|
@ -154,8 +157,8 @@ float GetGesturePinchAngle(void); // Get gesture pinch ang
|
|||
extern "C" { // Prevents name mangling of functions
|
||||
#endif
|
||||
// Functions required to query time on Windows
|
||||
int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount);
|
||||
int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency);
|
||||
int __stdcall QueryPerformanceCounter(unsigned long long *lpPerformanceCount);
|
||||
int __stdcall QueryPerformanceFrequency(unsigned long long *lpFrequency);
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
@ -297,10 +300,10 @@ void ProcessGestureEvent(GestureEvent event)
|
|||
}
|
||||
else if (event.touchAction == TOUCH_ACTION_UP)
|
||||
{
|
||||
// A swipe can happen while the current gesture is drag, but (specially for web) also hold, so set upPosition for both cases
|
||||
// A swipe can happen while the current gesture is drag, but (especially for web) also hold, so set upPosition for both cases
|
||||
if (GESTURES.current == GESTURE_DRAG || GESTURES.current == GESTURE_HOLD) GESTURES.Touch.upPosition = event.position[0];
|
||||
|
||||
// NOTE: GESTURES.Drag.intensity dependent on the resolution of the screen
|
||||
// NOTE: GESTURES.Drag.intensity is dependent on the resolution of the screen
|
||||
GESTURES.Drag.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition);
|
||||
GESTURES.Drag.intensity = GESTURES.Drag.distance/(float)((rgGetCurrentTime() - GESTURES.Swipe.startTime));
|
||||
|
||||
|
|
@ -515,37 +518,36 @@ static double rgGetCurrentTime(void)
|
|||
time = GetTime();
|
||||
#else
|
||||
#if defined(_WIN32)
|
||||
unsigned long long int clockFrequency, currentTime;
|
||||
unsigned long long clockFrequency = 0;
|
||||
unsigned long long currentClockTicks = 0;
|
||||
|
||||
QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation!
|
||||
QueryPerformanceCounter(¤tTime);
|
||||
QueryPerformanceCounter(¤tClockTicks);
|
||||
|
||||
time = (double)currentTime/clockFrequency; // Time in seconds
|
||||
time = (double)currentClockTicks/clockFrequency; // Time in seconds
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
// NOTE: Only for Linux-based systems
|
||||
struct timespec now;
|
||||
struct timespec now = { 0 };
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; // Time in nanoseconds
|
||||
unsigned long long nanoSeconds = (unsigned long long)now.tv_sec*1000000000LLU + (unsigned long long)now.tv_nsec;
|
||||
|
||||
time = ((double)nowTime*1e-9); // Time in seconds
|
||||
time = ((double)nanoSeconds*1e-9); // Time in seconds
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
//#define CLOCK_REALTIME CALENDAR_CLOCK // returns UTC time since 1970-01-01
|
||||
//#define CLOCK_MONOTONIC SYSTEM_CLOCK // returns the time since boot time
|
||||
|
||||
clock_serv_t cclock;
|
||||
mach_timespec_t now;
|
||||
clock_serv_t cclock = { 0 };
|
||||
mach_timespec_t now = { 0 };
|
||||
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
|
||||
|
||||
// NOTE: OS X does not have clock_gettime(), using clock_get_time()
|
||||
clock_get_time(cclock, &now);
|
||||
mach_port_deallocate(mach_task_self(), cclock);
|
||||
unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; // Time in nanoseconds
|
||||
unsigned long long nanoSeconds = (unsigned long long)now.tv_sec*1000000000LLU + (unsigned long long)now.tv_nsec;
|
||||
|
||||
time = ((double)nowTime*1e-9); // Time in seconds
|
||||
time = ((double)nanoSeconds*1e-9); // Time in seconds
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
|||
63
src/rlgl.h
63
src/rlgl.h
|
|
@ -7,10 +7,10 @@
|
|||
* that provides a pseudo-OpenGL 1.1 immediate-mode style API (rlVertex, rlTranslate, rlRotate...)
|
||||
*
|
||||
* ADDITIONAL NOTES:
|
||||
* When choosing an OpenGL backend different than OpenGL 1.1, some internal buffer are
|
||||
* When choosing an OpenGL backend different than OpenGL 1.1, some internal buffers are
|
||||
* initialized on rlglInit() to accumulate vertex data
|
||||
*
|
||||
* When an internal state change is required all the stored vertex data is rendered in batch,
|
||||
* When an internal state change is required all the stored vertex data is rendered in a batch,
|
||||
* additionally, rlDrawRenderBatchActive() could be called to force flushing of the batch
|
||||
*
|
||||
* Some resources are also loaded for convenience, here the complete list:
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
* #define GRAPHICS_API_OPENGL_ES2
|
||||
* #define GRAPHICS_API_OPENGL_ES3
|
||||
* Use selected OpenGL graphics backend, should be supported by platform
|
||||
* Those preprocessor defines are only used on rlgl module, if OpenGL version is
|
||||
* Those preprocessor defines are only used on the rlgl module, if OpenGL version is
|
||||
* required by any other module, use rlGetVersion() to check it
|
||||
*
|
||||
* #define RLGL_IMPLEMENTATION
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
* #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 8192 // Default internal render batch elements limits
|
||||
* #define RL_DEFAULT_BATCH_BUFFERS 1 // Default number of batch buffers (multi-buffering)
|
||||
* #define RL_DEFAULT_BATCH_DRAWCALLS 256 // Default number of batch draw calls (by state changes: mode, texture)
|
||||
* #define RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS 4 // Maximum number of textures units that can be activated on batch drawing (SetShaderValueTexture())
|
||||
* #define RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS 4 // Maximum number of texture units that can be activated on batch drawing (SetShaderValueTexture())
|
||||
*
|
||||
* #define RL_MAX_MATRIX_STACK_SIZE 32 // Maximum size of internal Matrix stack
|
||||
* #define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported
|
||||
|
|
@ -359,11 +359,13 @@
|
|||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
#if !defined(__cplusplus)
|
||||
#if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
|
||||
#include <stdbool.h>
|
||||
#elif !defined(__cplusplus) && !defined(bool) && !defined(RL_BOOL_TYPE)
|
||||
// Boolean type
|
||||
typedef enum bool { false = 0, true = !false } bool;
|
||||
#elif !defined(bool)
|
||||
typedef enum bool { false = 0, true = !false } bool;
|
||||
#define RL_BOOL_TYPE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(RL_MATRIX_TYPE)
|
||||
|
|
@ -881,7 +883,7 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
|
|||
#elif defined(GRAPHICS_API_OPENGL_ES2)
|
||||
// NOTE: OpenGL ES 2.0 can be enabled on Desktop platforms,
|
||||
// in that case, functions are loaded from a custom glad for OpenGL ES 2.0
|
||||
// TODO: OpenGL ES 2.0 support shouldn't be platform-dependant, neither require GLAD
|
||||
// TODO: OpenGL ES 2.0 support shouldn't be platform-dependent, neither require GLAD
|
||||
#if defined(PLATFORM_DESKTOP_GLFW) || defined(PLATFORM_DESKTOP_SDL)
|
||||
#define GLAD_GLES2_IMPLEMENTATION
|
||||
#include "external/glad_gles2.h"
|
||||
|
|
@ -894,7 +896,7 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
|
|||
|
||||
// It seems OpenGL ES 2.0 instancing entry points are not defined on Raspberry Pi
|
||||
// provided headers (despite being defined in official Khronos GLES2 headers)
|
||||
// TODO: Avoid raylib platform-dependant code on rlgl, it should be a completely portable library
|
||||
// TODO: Avoid raylib platform-dependent code on rlgl, it should be a completely portable library
|
||||
#if defined(PLATFORM_DRM)
|
||||
typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount);
|
||||
typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
|
||||
|
|
@ -1016,9 +1018,7 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
|
|||
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES
|
||||
#define RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES "boneMatrices" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEMATRICES
|
||||
#endif
|
||||
|
||||
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM "instanceTransform" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM
|
||||
#endif
|
||||
|
|
@ -1142,21 +1142,23 @@ typedef struct rlglData {
|
|||
//----------------------------------------------------------------------------------
|
||||
// Global Variables Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
static bool isGpuReady = false;
|
||||
static double rlCullDistanceNear = RL_CULL_DISTANCE_NEAR;
|
||||
static double rlCullDistanceFar = RL_CULL_DISTANCE_FAR;
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
static rlglData RLGL = { 0 };
|
||||
#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
|
||||
static bool isGpuReady = false;
|
||||
#endif
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_ES2) && !defined(GRAPHICS_API_OPENGL_ES3)
|
||||
// VAO functions entry points
|
||||
// NOTE: VAO functionality is exposed through extensions (OES)
|
||||
static PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays = NULL;
|
||||
static PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray = NULL;
|
||||
static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays = NULL;
|
||||
|
||||
// NOTE: Instancing functionality could also be available through extension
|
||||
// Instancing functionality entry points
|
||||
// NOTE: Instancing functionality could be available through extensions
|
||||
static PFNGLDRAWARRAYSINSTANCEDEXTPROC glDrawArraysInstanced = NULL;
|
||||
static PFNGLDRAWELEMENTSINSTANCEDEXTPROC glDrawElementsInstanced = NULL;
|
||||
static PFNGLVERTEXATTRIBDIVISOREXTPROC glVertexAttribDivisor = NULL;
|
||||
|
|
@ -1393,7 +1395,7 @@ void rlFrustum(double left, double right, double bottom, double top, double znea
|
|||
void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar)
|
||||
{
|
||||
// NOTE: If left-right and top-botton values are equal it could create a division by zero,
|
||||
// response to it is platform/compiler dependant
|
||||
// response to it is platform/compiler dependent
|
||||
Matrix matOrtho = { 0 };
|
||||
|
||||
float rl = (float)(right - left);
|
||||
|
|
@ -1512,7 +1514,7 @@ void rlBegin(int mode)
|
|||
// Finish vertex providing
|
||||
void rlEnd(void)
|
||||
{
|
||||
// NOTE: Depth increment is dependant on rlOrtho(): z-near and z-far values,
|
||||
// NOTE: Depth increment is dependent on rlOrtho(): z-near and z-far values,
|
||||
// as well as depth buffer bit-depth (16bit or 24bit or 32bit)
|
||||
// Correct increment formula would be: depthInc = (zfar - znear)/pow(2, bits)
|
||||
RLGL.currentBatch->currentDepth += (1.0f/20000.0f);
|
||||
|
|
@ -1624,6 +1626,11 @@ void rlNormal3f(float x, float y, float z)
|
|||
normaly = RLGL.State.transform.m1*x + RLGL.State.transform.m5*y + RLGL.State.transform.m9*z;
|
||||
normalz = RLGL.State.transform.m2*x + RLGL.State.transform.m6*y + RLGL.State.transform.m10*z;
|
||||
}
|
||||
|
||||
// NOTE: Default behavior assumes the normal vector is in the correct space for what the shader expects,
|
||||
// it could be not normalized to 0.0f..1.0f, magnitud can be useed for some effects
|
||||
/*
|
||||
// WARNING: Vector normalization if required
|
||||
float length = sqrtf(normalx*normalx + normaly*normaly + normalz*normalz);
|
||||
if (length != 0.0f)
|
||||
{
|
||||
|
|
@ -1632,6 +1639,7 @@ void rlNormal3f(float x, float y, float z)
|
|||
normaly *= ilength;
|
||||
normalz *= ilength;
|
||||
}
|
||||
*/
|
||||
RLGL.State.normalx = normalx;
|
||||
RLGL.State.normaly = normaly;
|
||||
RLGL.State.normalz = normalz;
|
||||
|
|
@ -1914,7 +1922,7 @@ void rlBindFramebuffer(unsigned int target, unsigned int framebuffer)
|
|||
void rlActiveDrawBuffers(int count)
|
||||
{
|
||||
#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3))
|
||||
// NOTE: Maximum number of draw buffers supported is implementation dependant,
|
||||
// NOTE: Maximum number of draw buffers supported is implementation dependent,
|
||||
// it can be queried with glGet*() but it must be at least 8
|
||||
//GLint maxDrawBuffers = 0;
|
||||
//glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
|
||||
|
|
@ -3372,8 +3380,15 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format,
|
|||
// Texture parameters configuration
|
||||
// NOTE: glTexParameteri does NOT affect texture uploading
|
||||
#if defined(GRAPHICS_API_OPENGL_ES2)
|
||||
|
||||
// Check if texture is power-of-two (POT)
|
||||
bool texIsPOT = false;
|
||||
|
||||
if (((width > 0) && ((width & (width - 1)) == 0)) &&
|
||||
((height > 0) && ((height & (height - 1)) == 0))) texIsPOT = true;
|
||||
|
||||
// NOTE: OpenGL ES 2.0 with no GL_OES_texture_npot support (i.e. WebGL) has limited NPOT support, so CLAMP_TO_EDGE must be used
|
||||
if (RLGL.ExtSupported.texNPOT)
|
||||
if ((texIsPOT) || (RLGL.ExtSupported.texNPOT))
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture to repeat on x-axis
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture to repeat on y-axis
|
||||
|
|
@ -3644,7 +3659,7 @@ void rlGetGlTextureFormats(int format, unsigned int *glInternalFormat, unsigned
|
|||
case RL_PIXELFORMAT_UNCOMPRESSED_R16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_HALF_FLOAT_ARB; break;
|
||||
case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_HALF_FLOAT_ARB; break;
|
||||
case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_HALF_FLOAT_ARB; break;
|
||||
#else // defined(GRAPHICS_API_OPENGL_ES2)
|
||||
#else // GRAPHICS_API_OPENGL_ES2
|
||||
case RL_PIXELFORMAT_UNCOMPRESSED_R16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float
|
||||
case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float
|
||||
case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float
|
||||
|
|
@ -3693,6 +3708,8 @@ void rlUnloadTexture(unsigned int id)
|
|||
// NOTE: Only supports GPU mipmap generation
|
||||
void rlGenTextureMipmaps(unsigned int id, int width, int height, int format, int *mipmaps)
|
||||
{
|
||||
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return; }
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
|
||||
|
|
@ -4659,14 +4676,14 @@ void rlUpdateShaderBuffer(unsigned int id, const void *data, unsigned int dataSi
|
|||
// Get SSBO buffer size
|
||||
unsigned int rlGetShaderBufferSize(unsigned int id)
|
||||
{
|
||||
unsigned int result = 0;
|
||||
#if defined(GRAPHICS_API_OPENGL_43)
|
||||
GLint64 size = 0;
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, id);
|
||||
glGetBufferParameteri64v(GL_SHADER_STORAGE_BUFFER, GL_BUFFER_SIZE, &size);
|
||||
return (size > 0)? (unsigned int)size : 0;
|
||||
#else
|
||||
return 0;
|
||||
if (size > 0) result = (unsigned int)size;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read SSBO buffer data (GPU->CPU)
|
||||
|
|
|
|||
135
src/rmodels.c
135
src/rmodels.c
|
|
@ -3,18 +3,19 @@
|
|||
* rmodels - Basic functions to draw 3d shapes and load and draw 3d models
|
||||
*
|
||||
* CONFIGURATION:
|
||||
* #define SUPPORT_MODULE_RMODELS
|
||||
* #define SUPPORT_MODULE_RMODELS 1
|
||||
* rmodels module is included in the build
|
||||
*
|
||||
* #define SUPPORT_FILEFORMAT_OBJ
|
||||
* #define SUPPORT_FILEFORMAT_MTL
|
||||
* #define SUPPORT_FILEFORMAT_IQM
|
||||
* #define SUPPORT_FILEFORMAT_GLTF
|
||||
* #define SUPPORT_FILEFORMAT_VOX
|
||||
* #define SUPPORT_FILEFORMAT_M3D
|
||||
* #define SUPPORT_FILEFORMAT_OBJ 1
|
||||
* #define SUPPORT_FILEFORMAT_MTL 1
|
||||
* #define SUPPORT_FILEFORMAT_IQM 1
|
||||
* #define SUPPORT_FILEFORMAT_GLTF 1
|
||||
* #define SUPPORT_FILEFORMAT_GLTF_WRITE 0
|
||||
* #define SUPPORT_FILEFORMAT_VOX 1
|
||||
* #define SUPPORT_FILEFORMAT_M3D 1
|
||||
* Selected desired fileformats to be supported for model data loading
|
||||
*
|
||||
* #define SUPPORT_MESH_GENERATION
|
||||
* #define SUPPORT_MESH_GENERATION 1
|
||||
* Support procedural mesh generation functions, uses external par_shapes.h library
|
||||
* NOTE: Some generated meshes DO NOT include generated texture coordinates
|
||||
*
|
||||
|
|
@ -71,6 +72,11 @@
|
|||
#define CGLTF_IMPLEMENTATION
|
||||
#include "external/cgltf.h" // glTF file format loading
|
||||
#endif
|
||||
#if SUPPORT_FILEFORMAT_GLTF_WRITE
|
||||
// NOTE: No need for custom allocators, memory buffer provided
|
||||
#define CGLTF_WRITE_IMPLEMENTATION
|
||||
#include "external/cgltf_write.h" // glTF file format writing
|
||||
#endif
|
||||
|
||||
#if SUPPORT_FILEFORMAT_VOX
|
||||
#define VOX_MALLOC RL_MALLOC
|
||||
|
|
@ -79,7 +85,7 @@
|
|||
#define VOX_FREE RL_FREE
|
||||
|
||||
#define VOX_LOADER_IMPLEMENTATION
|
||||
#include "external/vox_loader.h" // VOX file format loading (MagikaVoxel)
|
||||
#include "external/vox_loader.h" // VOX file format loading (MagicaVoxel)
|
||||
#endif
|
||||
|
||||
#if SUPPORT_FILEFORMAT_M3D
|
||||
|
|
@ -713,9 +719,9 @@ void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, fl
|
|||
|
||||
// Draw a wired cylinder with base at startPos and top at endPos
|
||||
// NOTE: It could be also used for pyramid and cone
|
||||
void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color)
|
||||
void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int slices, Color color)
|
||||
{
|
||||
if (sides < 3) sides = 3;
|
||||
if (slices < 3) slices = 3;
|
||||
|
||||
Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
|
||||
if ((direction.x == 0) && (direction.y == 0) && (direction.z == 0)) return; // Security check
|
||||
|
|
@ -724,12 +730,12 @@ void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, fl
|
|||
Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction));
|
||||
Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction));
|
||||
|
||||
float baseAngle = (2.0f*PI)/sides;
|
||||
float baseAngle = (2.0f*PI)/slices;
|
||||
|
||||
rlBegin(RL_LINES);
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
|
||||
for (int i = 0; i < sides; i++)
|
||||
for (int i = 0; i < slices; i++)
|
||||
{
|
||||
// Compute the four vertices
|
||||
float s1 = sinf(baseAngle*(i + 0))*startRadius;
|
||||
|
|
@ -758,7 +764,7 @@ void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, fl
|
|||
}
|
||||
|
||||
// Draw a capsule with the center of its sphere caps at startPos and endPos
|
||||
void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color)
|
||||
void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int rings, int slices, Color color)
|
||||
{
|
||||
if (slices < 3) slices = 3;
|
||||
|
||||
|
|
@ -897,7 +903,7 @@ void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int
|
|||
}
|
||||
|
||||
// Draw capsule wires with the center of its sphere caps at startPos and endPos
|
||||
void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color)
|
||||
void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int rings, int slices, Color color)
|
||||
{
|
||||
if (slices < 3) slices = 3;
|
||||
|
||||
|
|
@ -1171,16 +1177,17 @@ bool IsModelValid(Model model)
|
|||
// but some VBOs could not be used, it depends on Mesh vertex data
|
||||
for (int i = 0; i < model.meshCount; i++)
|
||||
{
|
||||
if ((model.meshes[i].vertices != NULL) && (model.meshes[i].vboId[0] == 0)) { result = false; break; } // Vertex position buffer not uploaded to GPU
|
||||
if ((model.meshes[i].vertices != NULL) && (model.meshes[i].vboId[0] == 0)) { result = false; break; } // Vertex position buffer not uploaded to GPU
|
||||
if ((model.meshes[i].texcoords != NULL) && (model.meshes[i].vboId[1] == 0)) { result = false; break; } // Vertex textcoords buffer not uploaded to GPU
|
||||
if ((model.meshes[i].normals != NULL) && (model.meshes[i].vboId[2] == 0)) { result = false; break; } // Vertex normals buffer not uploaded to GPU
|
||||
if ((model.meshes[i].colors != NULL) && (model.meshes[i].vboId[3] == 0)) { result = false; break; } // Vertex colors buffer not uploaded to GPU
|
||||
if ((model.meshes[i].tangents != NULL) && (model.meshes[i].vboId[4] == 0)) { result = false; break; } // Vertex tangents buffer not uploaded to GPU
|
||||
if ((model.meshes[i].texcoords2 != NULL) && (model.meshes[i].vboId[5] == 0)) { result = false; break; } // Vertex texcoords2 buffer not uploaded to GPU
|
||||
if ((model.meshes[i].indices != NULL) && (model.meshes[i].vboId[6] == 0)) { result = false; break; } // Vertex indices buffer not uploaded to GPU
|
||||
if ((model.meshes[i].boneIndices != NULL) && (model.meshes[i].vboId[7] == 0)) { result = false; break; } // Vertex boneIndices buffer not uploaded to GPU
|
||||
if ((model.meshes[i].boneWeights != NULL) && (model.meshes[i].vboId[8] == 0)) { result = false; break; } // Vertex boneWeights buffer not uploaded to GPU
|
||||
|
||||
if ((model.meshes[i].normals != NULL) && (model.meshes[i].vboId[2] == 0)) { result = false; break; } // Vertex normals buffer not uploaded to GPU
|
||||
if ((model.meshes[i].colors != NULL) && (model.meshes[i].vboId[3] == 0)) { result = false; break; } // Vertex colors buffer not uploaded to GPU
|
||||
if ((model.meshes[i].tangents != NULL) && (model.meshes[i].vboId[4] == 0)) { result = false; break; } // Vertex tangents buffer not uploaded to GPU
|
||||
if ((model.meshes[i].texcoords2 != NULL) && (model.meshes[i].vboId[5] == 0)) { result = false; break; } // Vertex texcoords2 buffer not uploaded to GPU
|
||||
if ((model.meshes[i].indices != NULL) && (model.meshes[i].vboId[6] == 0)) { result = false; break; } // Vertex indices buffer not uploaded to GPU
|
||||
#if SUPPORT_GPU_SKINNING
|
||||
if ((model.meshes[i].boneIndices != NULL) && (model.meshes[i].vboId[7] == 0)) { result = false; break; } // Vertex boneIndices buffer not uploaded to GPU
|
||||
if ((model.meshes[i].boneWeights != NULL) && (model.meshes[i].vboId[8] == 0)) { result = false; break; } // Vertex boneWeights buffer not uploaded to GPU
|
||||
#endif
|
||||
// NOTE: Some OpenGL versions do not support VAO, so avoid below check
|
||||
//if (model.meshes[i].vaoId == 0) { result = false; break }
|
||||
}
|
||||
|
|
@ -1276,7 +1283,6 @@ void UploadMesh(Mesh *mesh, bool dynamic)
|
|||
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
mesh->vaoId = rlLoadVertexArray();
|
||||
if (mesh->vaoId == 0) return;
|
||||
|
||||
rlEnableVertexArray(mesh->vaoId);
|
||||
|
||||
|
|
@ -1945,7 +1951,7 @@ void UnloadMesh(Mesh mesh)
|
|||
// Export mesh data to file
|
||||
bool ExportMesh(Mesh mesh, const char *fileName)
|
||||
{
|
||||
bool success = false;
|
||||
bool result = false;
|
||||
|
||||
if (IsFileExtension(fileName, ".obj"))
|
||||
{
|
||||
|
|
@ -2009,22 +2015,35 @@ bool ExportMesh(Mesh mesh, const char *fileName)
|
|||
}
|
||||
|
||||
// NOTE: Text data length exported is determined by '\0' (NULL) character
|
||||
success = SaveFileText(fileName, txtData);
|
||||
result = SaveFileText(fileName, txtData);
|
||||
|
||||
RL_FREE(txtData);
|
||||
}
|
||||
else if (IsFileExtension(fileName, ".gltf")) // Or .glb
|
||||
{
|
||||
// TODO: Implement gltf/glb support
|
||||
/*
|
||||
cgltf_size expected = cgltf_write(options, NULL, 0, data);
|
||||
char *buffer = (char *)RL_CALLOC(expected, 0);
|
||||
cgltf_size actual = cgltf_write(options, buffer, expected, data);
|
||||
|
||||
// NOTE: cgltf_write() includes a NULL terminator that should be ommited in case of a .glb
|
||||
if (options->type == cgltf_file_type_glb) cgltf_write_glb(file, buffer, actual - 1, data->bin, data->bin_size);
|
||||
else SaveFileText(fileName, buffer); // Write a plain JSON file
|
||||
*/
|
||||
}
|
||||
else if (IsFileExtension(fileName, ".raw"))
|
||||
{
|
||||
// TODO: Support additional file formats to export mesh vertex data
|
||||
}
|
||||
|
||||
return success;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Export mesh as code file (.h) defining multiple arrays of vertex attributes
|
||||
bool ExportMeshAsCode(Mesh mesh, const char *fileName)
|
||||
{
|
||||
bool success = false;
|
||||
bool result = false;
|
||||
|
||||
#ifndef TEXT_BYTES_PER_LINE
|
||||
#define TEXT_BYTES_PER_LINE 20
|
||||
|
|
@ -2108,14 +2127,14 @@ bool ExportMeshAsCode(Mesh mesh, const char *fileName)
|
|||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
// NOTE: Text data size exported is determined by '\0' (NULL) character
|
||||
success = SaveFileText(fileName, txtData);
|
||||
result = SaveFileText(fileName, txtData);
|
||||
|
||||
RL_FREE(txtData);
|
||||
|
||||
//if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image as code exported successfully", fileName);
|
||||
//if (result != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image as code exported successfully", fileName);
|
||||
//else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export image as code", fileName);
|
||||
|
||||
return success;
|
||||
return result;
|
||||
}
|
||||
|
||||
#if SUPPORT_FILEFORMAT_OBJ || SUPPORT_FILEFORMAT_MTL
|
||||
|
|
@ -3912,7 +3931,7 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota
|
|||
Color colDiffuse = mat.maps[MATERIAL_MAP_DIFFUSE].color;
|
||||
|
||||
// Applying color tint directly to material diffuse map,
|
||||
// because is comes as an input paramter to the function
|
||||
// because it comes as an input parameter to the function
|
||||
Color colTinted = { 0 };
|
||||
colTinted.r = (unsigned char)(((int)colDiffuse.r*(int)tint.r)/255);
|
||||
colTinted.g = (unsigned char)(((int)colDiffuse.g*(int)tint.g)/255);
|
||||
|
|
@ -3956,32 +3975,6 @@ void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float
|
|||
rlDisableWireMode();
|
||||
}
|
||||
|
||||
// Draw a model points
|
||||
// WARNING: OpenGL ES 2.0 does not support point mode drawing
|
||||
void DrawModelPoints(Model model, Vector3 position, float scale, Color tint)
|
||||
{
|
||||
rlEnablePointMode();
|
||||
rlDisableBackfaceCulling();
|
||||
|
||||
DrawModel(model, position, scale, tint);
|
||||
|
||||
rlEnableBackfaceCulling();
|
||||
rlDisablePointMode();
|
||||
}
|
||||
|
||||
// Draw a model points
|
||||
// WARNING: OpenGL ES 2.0 does not support point mode drawing
|
||||
void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
|
||||
{
|
||||
rlEnablePointMode();
|
||||
rlDisableBackfaceCulling();
|
||||
|
||||
DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint);
|
||||
|
||||
rlEnableBackfaceCulling();
|
||||
rlDisablePointMode();
|
||||
}
|
||||
|
||||
// Draw a billboard
|
||||
void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint)
|
||||
{
|
||||
|
|
@ -4107,7 +4100,8 @@ bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, floa
|
|||
*/
|
||||
|
||||
// Check for distances squared to avoid sqrtf()
|
||||
if (Vector3DotProduct(Vector3Subtract(center2, center1), Vector3Subtract(center2, center1)) <= (radius1 + radius2)*(radius1 + radius2)) collision = true;
|
||||
float radSum = radius1 + radius2;
|
||||
if (Vector3DistanceSqr(center1, center2) <= (radSum*radSum)) collision = true;
|
||||
|
||||
return collision;
|
||||
}
|
||||
|
|
@ -4133,18 +4127,13 @@ bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius)
|
|||
{
|
||||
bool collision = false;
|
||||
|
||||
float dmin = 0;
|
||||
Vector3 closestPoint = {
|
||||
Clamp(center.x, box.min.x, box.max.x),
|
||||
Clamp(center.y, box.min.y, box.max.y),
|
||||
Clamp(center.z, box.min.z, box.max.z)
|
||||
};
|
||||
|
||||
if (center.x < box.min.x) dmin += powf(center.x - box.min.x, 2);
|
||||
else if (center.x > box.max.x) dmin += powf(center.x - box.max.x, 2);
|
||||
|
||||
if (center.y < box.min.y) dmin += powf(center.y - box.min.y, 2);
|
||||
else if (center.y > box.max.y) dmin += powf(center.y - box.max.y, 2);
|
||||
|
||||
if (center.z < box.min.z) dmin += powf(center.z - box.min.z, 2);
|
||||
else if (center.z > box.max.z) dmin += powf(center.z - box.max.z, 2);
|
||||
|
||||
if (dmin <= (radius*radius)) collision = true;
|
||||
if (Vector3DistanceSqr(center, closestPoint) <= (radius*radius)) collision = true;
|
||||
|
||||
return collision;
|
||||
}
|
||||
|
|
@ -5286,7 +5275,7 @@ static cgltf_result LoadFileGLTFCallback(const struct cgltf_memory_options *memo
|
|||
}
|
||||
|
||||
// Release file data callback for cgltf
|
||||
static void ReleaseFileGLTFCallback(const struct cgltf_memory_options *memoryOptions, const struct cgltf_file_options *fileOptions, void *data)
|
||||
static void ReleaseFileGLTFCallback(const struct cgltf_memory_options *memoryOptions, const struct cgltf_file_options *fileOptions, void *data, cgltf_size size)
|
||||
{
|
||||
UnloadFileData((unsigned char *)data);
|
||||
}
|
||||
|
|
@ -6900,7 +6889,7 @@ static Model LoadM3D(const char *fileName)
|
|||
mi = m3d->face[i].materialid;
|
||||
|
||||
// Only allocate colors VertexBuffer if there's a color vertex in the model for this material batch
|
||||
// if all colors are fully transparent black for all verteces of this materal, then assuming no vertex colors
|
||||
// if all colors are fully transparent black for all vertices of this material, then assuming no vertex colors
|
||||
for (j = i, l = vcolor = 0; (j < (int)m3d->numface) && (mi == m3d->face[j].materialid); j++, l++)
|
||||
{
|
||||
if (!m3d->vertex[m3d->face[j].vertex[0]].color ||
|
||||
|
|
|
|||
116
src/rshapes.c
116
src/rshapes.c
|
|
@ -8,18 +8,18 @@
|
|||
* 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
|
||||
* user-provided texture with SetShapesTexture(), the purpose of this implementation
|
||||
* 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
|
||||
* white character of default font [rtext], this way, raylib text and shapes can be drawn with
|
||||
* a single draw call and it also allows users to configure it the same way with their own fonts
|
||||
*
|
||||
* CONFIGURATION:
|
||||
* #define SUPPORT_MODULE_RSHAPES
|
||||
* #define SUPPORT_MODULE_RSHAPES 1
|
||||
* rshapes module is included in the build
|
||||
*
|
||||
* #define SUPPORT_QUADS_DRAW_MODE
|
||||
* #define SUPPORT_QUADS_DRAW_MODE 1
|
||||
* Use QUADS instead of TRIANGLES for drawing when possible. Lines-based shapes still use LINES
|
||||
*
|
||||
*
|
||||
|
|
@ -289,6 +289,22 @@ void DrawCircleV(Vector2 center, float radius, Color color)
|
|||
DrawCircleSector(center, radius, 0, 360, 36, color);
|
||||
}
|
||||
|
||||
// Draw a gradient-filled circle
|
||||
void DrawCircleGradient(Vector2 center, float radius, Color inner, Color outer)
|
||||
{
|
||||
rlBegin(RL_TRIANGLES);
|
||||
for (int i = 0; i < 360; i += 10)
|
||||
{
|
||||
rlColor4ub(inner.r, inner.g, inner.b, inner.a);
|
||||
rlVertex2f(center.x, center.y);
|
||||
rlColor4ub(outer.r, outer.g, outer.b, outer.a);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radius, center.y + sinf(DEG2RAD*(i + 10))*radius);
|
||||
rlColor4ub(outer.r, outer.g, outer.b, outer.a);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*i)*radius, center.y + sinf(DEG2RAD*i)*radius);
|
||||
}
|
||||
rlEnd();
|
||||
}
|
||||
|
||||
// Draw a piece of a circle
|
||||
void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color)
|
||||
{
|
||||
|
|
@ -438,22 +454,6 @@ void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float
|
|||
rlEnd();
|
||||
}
|
||||
|
||||
// Draw a gradient-filled circle
|
||||
void DrawCircleGradient(int centerX, int centerY, float radius, Color inner, Color outer)
|
||||
{
|
||||
rlBegin(RL_TRIANGLES);
|
||||
for (int i = 0; i < 360; i += 10)
|
||||
{
|
||||
rlColor4ub(inner.r, inner.g, inner.b, inner.a);
|
||||
rlVertex2f((float)centerX, (float)centerY);
|
||||
rlColor4ub(outer.r, outer.g, outer.b, outer.a);
|
||||
rlVertex2f((float)centerX + cosf(DEG2RAD*(i + 10))*radius, (float)centerY + sinf(DEG2RAD*(i + 10))*radius);
|
||||
rlColor4ub(outer.r, outer.g, outer.b, outer.a);
|
||||
rlVertex2f((float)centerX + cosf(DEG2RAD*i)*radius, (float)centerY + sinf(DEG2RAD*i)*radius);
|
||||
}
|
||||
rlEnd();
|
||||
}
|
||||
|
||||
// Draw circle outline
|
||||
void DrawCircleLines(int centerX, int centerY, float radius, Color color)
|
||||
{
|
||||
|
|
@ -1386,6 +1386,12 @@ void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, f
|
|||
// Draw a triangle
|
||||
// NOTE: Vertex must be provided in counter-clockwise order
|
||||
void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
|
||||
{
|
||||
DrawTriangleGradient(v1, v2, v3, color, color, color);
|
||||
}
|
||||
|
||||
// Draw triangle with interpolated colors (vertex in counter-clockwise order!)
|
||||
void DrawTriangleGradient(Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3)
|
||||
{
|
||||
#if SUPPORT_QUADS_DRAW_MODE
|
||||
rlSetTexture(GetShapesTexture().id);
|
||||
|
|
@ -1393,17 +1399,20 @@ void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
|
|||
|
||||
rlBegin(RL_QUADS);
|
||||
rlNormal3f(0.0f, 0.0f, 1.0f);
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
|
||||
rlColor4ub(c1.r, c1.g, c1.b, c1.a);
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(v1.x, v1.y);
|
||||
|
||||
rlColor4ub(c2.r, c2.g, c2.b, c2.a);
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(v2.x, v2.y);
|
||||
|
||||
rlColor4ub(c3.r, c3.g, c3.b, c3.a);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(v3.x, v3.y);
|
||||
|
||||
rlColor4ub(c3.r, c3.g, c3.b, c3.a);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(v3.x, v3.y);
|
||||
rlEnd();
|
||||
|
|
@ -1411,9 +1420,11 @@ void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
|
|||
rlSetTexture(0);
|
||||
#else
|
||||
rlBegin(RL_TRIANGLES);
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlColor4ub(c1.r, c1.g, c1.b, c1.a);
|
||||
rlVertex2f(v1.x, v1.y);
|
||||
rlColor4ub(c2.r, c2.g, c2.b, c2.a);
|
||||
rlVertex2f(v2.x, v2.y);
|
||||
rlColor4ub(c3.r, c3.g, c3.b, c3.a);
|
||||
rlVertex2f(v3.x, v3.y);
|
||||
rlEnd();
|
||||
#endif
|
||||
|
|
@ -1496,7 +1507,7 @@ void DrawTriangleStrip(const Vector2 *points, int pointCount, Color color)
|
|||
}
|
||||
}
|
||||
|
||||
// Draw a regular polygon of n sides (Vector version)
|
||||
// Draw a polygon of n sides
|
||||
void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color)
|
||||
{
|
||||
if (sides < 3) sides = 3;
|
||||
|
|
@ -2179,7 +2190,7 @@ Vector2 GetSplinePointCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4,
|
|||
}
|
||||
|
||||
// Get spline point for a given t [0.0f .. 1.0f], Quadratic Bezier
|
||||
Vector2 GetSplinePointBezierQuad(Vector2 startPos, Vector2 controlPos, Vector2 endPos, float t)
|
||||
Vector2 GetSplinePointBezierQuadratic(Vector2 startPos, Vector2 controlPos, Vector2 endPos, float t)
|
||||
{
|
||||
Vector2 point = { 0 };
|
||||
|
||||
|
|
@ -2313,16 +2324,18 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
|
|||
float dx = fabsf(center.x - recCenterX);
|
||||
float dy = fabsf(center.y - recCenterY);
|
||||
|
||||
if (dx > (rec.width/2.0f + radius)) { return false; }
|
||||
if (dy > (rec.height/2.0f + radius)) { return false; }
|
||||
if ((dx <= (rec.width/2.0f + radius)) && (dy <= (rec.height/2.0f + radius)))
|
||||
{
|
||||
if (dx <= (rec.width/2.0f)) collision = true;
|
||||
else if (dy <= (rec.height/2.0f)) collision = true;
|
||||
else
|
||||
{
|
||||
float cornerDistanceSq = (dx - rec.width/2.0f)*(dx - rec.width/2.0f) +
|
||||
(dy - rec.height/2.0f)*(dy - rec.height/2.0f);
|
||||
|
||||
if (dx <= (rec.width/2.0f)) { return true; }
|
||||
if (dy <= (rec.height/2.0f)) { return true; }
|
||||
|
||||
float cornerDistanceSq = (dx - rec.width/2.0f)*(dx - rec.width/2.0f) +
|
||||
(dy - rec.height/2.0f)*(dy - rec.height/2.0f);
|
||||
|
||||
collision = (cornerDistanceSq <= (radius*radius));
|
||||
collision = (cornerDistanceSq <= (radius*radius));
|
||||
}
|
||||
}
|
||||
|
||||
return collision;
|
||||
}
|
||||
|
|
@ -2350,8 +2363,11 @@ bool CheckCollisionLines(Vector2 startPos1, Vector2 endPos1, Vector2 startPos2,
|
|||
|
||||
if ((0.0f <= t) && (t <= 1.0f) && (0.0f <= u) && (u <= 1.0f))
|
||||
{
|
||||
collisionPoint->x = startPos1.x + t*rx;
|
||||
collisionPoint->y = startPos1.y + t*ry;
|
||||
if (collisionPoint)
|
||||
{
|
||||
collisionPoint->x = startPos1.x + t*rx;
|
||||
collisionPoint->y = startPos1.y + t*ry;
|
||||
}
|
||||
|
||||
collision = true;
|
||||
}
|
||||
|
|
@ -2383,25 +2399,31 @@ bool CheckCollisionPointLine(Vector2 point, Vector2 p1, Vector2 p2, int threshol
|
|||
// Check if circle collides with a line created between two points [p1] and [p2]
|
||||
bool CheckCollisionCircleLine(Vector2 center, float radius, Vector2 p1, Vector2 p2)
|
||||
{
|
||||
bool collision = false;
|
||||
|
||||
float dx = p1.x - p2.x;
|
||||
float dy = p1.y - p2.y;
|
||||
|
||||
if ((fabsf(dx) + fabsf(dy)) <= FLT_EPSILON)
|
||||
{
|
||||
return CheckCollisionCircles(p1, 0, center, radius);
|
||||
collision = CheckCollisionCircles(p1, 0, center, radius);
|
||||
}
|
||||
else
|
||||
{
|
||||
float lengthSQ = ((dx*dx) + (dy*dy));
|
||||
float dotProduct = (((center.x - p1.x)*(p2.x - p1.x)) + ((center.y - p1.y)*(p2.y - p1.y)))/(lengthSQ);
|
||||
|
||||
if (dotProduct > 1.0f) dotProduct = 1.0f;
|
||||
else if (dotProduct < 0.0f) dotProduct = 0.0f;
|
||||
|
||||
float dx2 = (p1.x - (dotProduct*(dx))) - center.x;
|
||||
float dy2 = (p1.y - (dotProduct*(dy))) - center.y;
|
||||
float distanceSQ = ((dx2*dx2) + (dy2*dy2));
|
||||
|
||||
if (distanceSQ <= radius*radius) collision = true;
|
||||
}
|
||||
|
||||
float lengthSQ = ((dx*dx) + (dy*dy));
|
||||
float dotProduct = (((center.x - p1.x)*(p2.x - p1.x)) + ((center.y - p1.y)*(p2.y - p1.y)))/(lengthSQ);
|
||||
|
||||
if (dotProduct > 1.0f) dotProduct = 1.0f;
|
||||
else if (dotProduct < 0.0f) dotProduct = 0.0f;
|
||||
|
||||
float dx2 = (p1.x - (dotProduct*(dx))) - center.x;
|
||||
float dy2 = (p1.y - (dotProduct*(dy))) - center.y;
|
||||
float distanceSQ = ((dx2*dx2) + (dy2*dy2));
|
||||
|
||||
return (distanceSQ <= radius*radius);
|
||||
return collision;
|
||||
}
|
||||
|
||||
// Get collision rectangle for two rectangles collision
|
||||
|
|
|
|||
196
src/rtext.c
196
src/rtext.c
|
|
@ -3,22 +3,22 @@
|
|||
* rtext - Basic functions to load fonts and draw text
|
||||
*
|
||||
* CONFIGURATION:
|
||||
* #define SUPPORT_MODULE_RTEXT
|
||||
* #define SUPPORT_MODULE_RTEXT 1
|
||||
* rtext module is included in the build
|
||||
*
|
||||
* #define SUPPORT_FILEFORMAT_FNT
|
||||
* #define SUPPORT_FILEFORMAT_TTF
|
||||
* #define SUPPORT_FILEFORMAT_BDF
|
||||
* #define SUPPORT_FILEFORMAT_FNT 1
|
||||
* #define SUPPORT_FILEFORMAT_TTF 1
|
||||
* #define SUPPORT_FILEFORMAT_BDF 0
|
||||
* Selected desired fileformats to be supported for loading. Some of those formats are
|
||||
* supported by default, to remove support, comment unrequired #define in this module
|
||||
* supported by default, to remove support, #define as 0 in this module or your build system
|
||||
*
|
||||
* #define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
|
||||
* TextSplit() function static buffer max size
|
||||
* #define MAX_TEXT_BUFFER_LENGTH 1024
|
||||
* Text functions using static buffer max size
|
||||
*
|
||||
* #define MAX_TEXTSPLIT_COUNT
|
||||
* #define MAX_TEXTSPLIT_COUNT 128
|
||||
* TextSplit() function static substrings pointers array (pointing to static buffer)
|
||||
*
|
||||
* #define FONT_ATLAS_CORNER_REC_SIZE
|
||||
* #define FONT_ATLAS_CORNER_REC_SIZE 3
|
||||
* On font atlas image generation [GenImageFontAtlas()], add a NxN 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()]
|
||||
|
|
@ -156,7 +156,7 @@ extern void LoadFontDefault(void)
|
|||
{
|
||||
#define BIT_CHECK(a,b) ((a) & (1u << (b)))
|
||||
|
||||
// Check to see if the font for an image has alreeady been allocated,
|
||||
// Check to see if the font for an image has already been allocated,
|
||||
// and if no need to upload, then return
|
||||
if (defaultFont.glyphs != NULL) return;
|
||||
|
||||
|
|
@ -447,7 +447,7 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
|
|||
int j = 0;
|
||||
|
||||
while (((lineSpacing + j) < image.height) &&
|
||||
!COLOR_EQUAL(pixels[(lineSpacing + j)*image.width + charSpacing], key)) j++;
|
||||
!COLOR_EQUAL(pixels[(lineSpacing + j)*image.width + charSpacing], key)) j++;
|
||||
|
||||
charHeight = j;
|
||||
|
||||
|
|
@ -1017,7 +1017,7 @@ void UnloadFont(Font font)
|
|||
// Export font as code file, returns true on success
|
||||
bool ExportFontAsCode(Font font, const char *fileName)
|
||||
{
|
||||
bool success = false;
|
||||
bool result = false;
|
||||
|
||||
#ifndef TEXT_BYTES_PER_LINE
|
||||
#define TEXT_BYTES_PER_LINE 20
|
||||
|
|
@ -1159,14 +1159,14 @@ bool ExportFontAsCode(Font font, const char *fileName)
|
|||
UnloadImage(image);
|
||||
|
||||
// NOTE: Text data size exported is determined by '\0' (NULL) character
|
||||
success = SaveFileText(fileName, txtData);
|
||||
result = SaveFileText(fileName, txtData);
|
||||
|
||||
RL_FREE(txtData);
|
||||
|
||||
if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Font as code exported successfully", fileName);
|
||||
if (result != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Font as code exported successfully", fileName);
|
||||
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export font as code", fileName);
|
||||
|
||||
return success;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Draw current FPS
|
||||
|
|
@ -1279,7 +1279,7 @@ void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSiz
|
|||
DrawTexturePro(font.texture, srcRec, dstRec, (Vector2){ 0, 0 }, 0.0f, tint);
|
||||
}
|
||||
|
||||
// Draw multiple character (codepoints)
|
||||
// Draw multiple characters (codepoints)
|
||||
void DrawTextCodepoints(Font font, const int *codepoints, int codepointCount, Vector2 position, float fontSize, float spacing, Color tint)
|
||||
{
|
||||
float textOffsetY = 0; // Offset between lines (on linebreak '\n')
|
||||
|
|
@ -1395,8 +1395,7 @@ Vector2 MeasureTextCodepoints(Font font, const int *codepoints, int length, floa
|
|||
{
|
||||
Vector2 textSize = { 0 };
|
||||
|
||||
// Security check
|
||||
if ((font.texture.id == 0) || (codepoints == NULL) || (length == 0)) return textSize;
|
||||
if ((font.texture.id == 0) || (codepoints == NULL) || (length == 0)) return textSize; // Security check
|
||||
|
||||
float textWidth = 0.0f;
|
||||
// Used to count longer text line width
|
||||
|
|
@ -1675,7 +1674,7 @@ int TextCopy(char *dst, const char *src)
|
|||
return bytes;
|
||||
}
|
||||
|
||||
// Check if two text string are equal
|
||||
// Check if two text strings are equal
|
||||
// REQUIRES: strcmp()
|
||||
bool TextIsEqual(const char *text1, const char *text2)
|
||||
{
|
||||
|
|
@ -1699,17 +1698,18 @@ const char *TextSubtext(const char *text, int position, int length)
|
|||
{
|
||||
int textLength = TextLength(text);
|
||||
|
||||
if (position >= textLength) return buffer; // First char is already '\0' by memset
|
||||
if (position < textLength)
|
||||
{
|
||||
int maxLength = textLength - position;
|
||||
if (length > maxLength) length = maxLength;
|
||||
if (length >= MAX_TEXT_BUFFER_LENGTH) length = MAX_TEXT_BUFFER_LENGTH - 1;
|
||||
|
||||
int maxLength = textLength - position;
|
||||
if (length > maxLength) length = maxLength;
|
||||
if (length >= MAX_TEXT_BUFFER_LENGTH) length = MAX_TEXT_BUFFER_LENGTH - 1;
|
||||
// NOTE: Alternative: memcpy(buffer, text + position, length)
|
||||
|
||||
// NOTE: Alternative: memcpy(buffer, text + position, length)
|
||||
for (int c = 0; c < length; c++) buffer[c] = text[position + c];
|
||||
|
||||
for (int c = 0; c < length; c++) buffer[c] = text[position + c];
|
||||
|
||||
buffer[length] = '\0';
|
||||
buffer[length] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
|
|
@ -1724,7 +1724,7 @@ const char *TextRemoveSpaces(const char *text)
|
|||
if (text != NULL)
|
||||
{
|
||||
// Avoid copying the ' ' characters
|
||||
for (int i = 0, j = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); i++)
|
||||
for (int i = 0, j = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[i] != '\0'); i++)
|
||||
{
|
||||
if (text[i] != ' ') { buffer[j] = text[i]; j++; }
|
||||
}
|
||||
|
|
@ -1736,8 +1736,6 @@ const char *TextRemoveSpaces(const char *text)
|
|||
// Get text between two strings
|
||||
char *GetTextBetween(const char *text, const char *begin, const char *end)
|
||||
{
|
||||
#define MAX_TEXT_BETWEEN_SIZE 1024
|
||||
|
||||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
|
||||
|
||||
|
|
@ -1752,8 +1750,8 @@ char *GetTextBetween(const char *text, const char *begin, const char *end)
|
|||
{
|
||||
endIndex += (beginIndex + beginLen);
|
||||
int len = (endIndex - beginIndex - beginLen);
|
||||
if (len < (MAX_TEXT_BETWEEN_SIZE - 1)) strncpy(buffer, text + beginIndex + beginLen, len);
|
||||
else strncpy(buffer, text + beginIndex + beginLen, MAX_TEXT_BETWEEN_SIZE - 1);
|
||||
if (len < (MAX_TEXT_BUFFER_LENGTH - 1)) strncpy(buffer, text + beginIndex + beginLen, len);
|
||||
else strncpy(buffer, text + beginIndex + beginLen, MAX_TEXT_BUFFER_LENGTH - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1762,8 +1760,74 @@ char *GetTextBetween(const char *text, const char *begin, const char *end)
|
|||
|
||||
// Replace text string
|
||||
// REQUIRES: strstr(), strncpy()
|
||||
// WARNING: Allocated memory must be manually freed
|
||||
// NOTE: Limited text replace functionality, using static string
|
||||
char *TextReplace(const char *text, const char *search, const char *replacement)
|
||||
{
|
||||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
|
||||
|
||||
if ((text != NULL) && (search != NULL) && (search[0] != '\0'))
|
||||
{
|
||||
if (replacement == NULL) replacement = "";
|
||||
|
||||
char *insertPoint = NULL; // Next insert point
|
||||
char *tempPtr = NULL; // Temp pointer
|
||||
int textLen = 0; // Text string length
|
||||
int searchLen = 0; // Search string length of (the string to remove)
|
||||
int replaceLen = 0; // Replacement length (the string to replace by)
|
||||
int lastReplacePos = 0; // Distance between next search and end of last replace
|
||||
int count = 0; // Number of replacements
|
||||
|
||||
textLen = TextLength(text);
|
||||
searchLen = TextLength(search);
|
||||
replaceLen = TextLength(replacement);
|
||||
|
||||
// Count the number of replacements needed
|
||||
insertPoint = (char *)text;
|
||||
for (count = 0; (tempPtr = strstr(insertPoint, search)); count++) insertPoint = tempPtr + searchLen;
|
||||
|
||||
if ((textLen + count*(replaceLen - searchLen)) < (MAX_TEXT_BUFFER_LENGTH - 1))
|
||||
{
|
||||
// TODO: Allow copying data replaced up to maximum buffer size and stop
|
||||
|
||||
tempPtr = buffer; // Point to result start
|
||||
|
||||
// First time through the loop, all the variable are set correctly from here on,
|
||||
// - 'temp' points to the end of the result string
|
||||
// - 'insertPoint' points to the next occurrence of replace in text
|
||||
// - 'text' points to the remainder of text after "end of replace"
|
||||
while (count > 0)
|
||||
{
|
||||
insertPoint = (char *)strstr(text, search);
|
||||
lastReplacePos = (int)(insertPoint - text);
|
||||
|
||||
memcpy(tempPtr, text, lastReplacePos);
|
||||
tempPtr += lastReplacePos;
|
||||
|
||||
if (replaceLen > 0)
|
||||
{
|
||||
memcpy(tempPtr, replacement, replaceLen);
|
||||
tempPtr += replaceLen;
|
||||
}
|
||||
|
||||
text += (lastReplacePos + searchLen); // Move to next "end of replace"
|
||||
count--;
|
||||
}
|
||||
|
||||
// Copy remaind text part after replacement to result (pointed by moving temp)
|
||||
// NOTE: Text pointer internal copy has been updated along the process
|
||||
strncpy(tempPtr, text, TextLength(text));
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "Text with replacement is longer than internal buffer, use TextReplaceAlloc()");
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Replace text string
|
||||
// REQUIRES: strstr(), strncpy()
|
||||
// WARNING: Allocated memory must be manually freed
|
||||
char *TextReplaceAlloc(const char *text, const char *search, const char *replacement)
|
||||
{
|
||||
char *result = NULL;
|
||||
|
||||
|
|
@ -1825,11 +1889,46 @@ char *TextReplace(const char *text, const char *search, const char *replacement)
|
|||
return result;
|
||||
}
|
||||
|
||||
// Replace text between two specific strings
|
||||
// REQUIRES: strncpy()
|
||||
// NOTE: If (replacement == NULL) removes "begin"[ ]"end" text
|
||||
char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement)
|
||||
{
|
||||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
|
||||
|
||||
if ((text != NULL) && (begin != NULL) && (end != NULL))
|
||||
{
|
||||
int beginIndex = TextFindIndex(text, begin);
|
||||
|
||||
if (beginIndex > -1)
|
||||
{
|
||||
int beginLen = TextLength(begin);
|
||||
int endIndex = TextFindIndex(text + beginIndex + beginLen, end);
|
||||
|
||||
if (endIndex > -1)
|
||||
{
|
||||
endIndex += (beginIndex + beginLen);
|
||||
|
||||
int textLen = TextLength(text);
|
||||
int replaceLen = (replacement == NULL)? 0 : TextLength(replacement);
|
||||
//int toreplaceLen = endIndex - beginIndex - beginLen;
|
||||
|
||||
strncpy(buffer, text, beginIndex + beginLen); // Copy first text part
|
||||
if (replacement != NULL) strncpy(buffer + beginIndex + beginLen, replacement, replaceLen); // Copy replacement (if provided)
|
||||
strncpy(buffer + beginIndex + beginLen + replaceLen, text + endIndex, textLen - endIndex); // Copy end text part
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Replace text between two specific strings
|
||||
// REQUIRES: strncpy()
|
||||
// NOTE: If (replacement == NULL) remove "begin"[ ]"end" text
|
||||
// WARNING: Returned string must be freed by user
|
||||
char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement)
|
||||
char *TextReplaceBetweenAlloc(const char *text, const char *begin, const char *end, const char *replacement)
|
||||
{
|
||||
char *result = NULL;
|
||||
|
||||
|
|
@ -1864,6 +1963,34 @@ char *TextReplaceBetween(const char *text, const char *begin, const char *end, c
|
|||
// Insert text in a specific position, moves all text forward
|
||||
// WARNING: Allocated memory must be manually freed
|
||||
char *TextInsert(const char *text, const char *insert, int position)
|
||||
{
|
||||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
|
||||
|
||||
if ((text != NULL) && (insert != NULL))
|
||||
{
|
||||
int textLen = TextLength(text);
|
||||
int insertLen = TextLength(insert);
|
||||
|
||||
if ((textLen + insertLen) < (MAX_TEXT_BUFFER_LENGTH - 1))
|
||||
{
|
||||
// TODO: Allow copying data inserted up to maximum buffer size and stop
|
||||
|
||||
for (int i = 0; i < position; i++) buffer[i] = text[i];
|
||||
for (int i = position; i < insertLen + position; i++) buffer[i] = insert[i - position];
|
||||
for (int i = (insertLen + position); i < (textLen + insertLen); i++) buffer[i] = text[i];
|
||||
|
||||
buffer[textLen + insertLen] = '\0'; // Add EOL
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "Text with inserted string is longer than internal buffer, use TextInserExt()");
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Insert text in a specific position, moves all text forward
|
||||
// WARNING: Allocated memory must be manually freed
|
||||
char *TextInsertAlloc(const char *text, const char *insert, int position)
|
||||
{
|
||||
char *result = NULL;
|
||||
|
||||
|
|
@ -2265,7 +2392,6 @@ int GetCodepoint(const char *text, int *codepointSize)
|
|||
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
*/
|
||||
|
||||
|
||||
int codepoint = 0x3f; // Codepoint (defaults to '?')
|
||||
*codepointSize = 1;
|
||||
if (text == NULL) return codepoint;
|
||||
|
|
|
|||
141
src/rtextures.c
141
src/rtextures.c
|
|
@ -3,31 +3,31 @@
|
|||
* rtextures - Basic functions to load and draw textures
|
||||
*
|
||||
* CONFIGURATION:
|
||||
* #define SUPPORT_MODULE_RTEXTURES
|
||||
* #define SUPPORT_MODULE_RTEXTURES 1
|
||||
* rtextures module is included in the build
|
||||
*
|
||||
* #define SUPPORT_FILEFORMAT_BMP
|
||||
* #define SUPPORT_FILEFORMAT_PNG
|
||||
* #define SUPPORT_FILEFORMAT_TGA
|
||||
* #define SUPPORT_FILEFORMAT_JPG
|
||||
* #define SUPPORT_FILEFORMAT_GIF
|
||||
* #define SUPPORT_FILEFORMAT_QOI
|
||||
* #define SUPPORT_FILEFORMAT_PSD
|
||||
* #define SUPPORT_FILEFORMAT_HDR
|
||||
* #define SUPPORT_FILEFORMAT_PIC
|
||||
* #define SUPPORT_FILEFORMAT_PNM
|
||||
* #define SUPPORT_FILEFORMAT_DDS
|
||||
* #define SUPPORT_FILEFORMAT_PKM
|
||||
* #define SUPPORT_FILEFORMAT_KTX
|
||||
* #define SUPPORT_FILEFORMAT_PVR
|
||||
* #define SUPPORT_FILEFORMAT_ASTC
|
||||
* Select desired fileformats to be supported for image data loading. Some of those formats are
|
||||
* supported by default, to remove support, comment unrequired #define in this module
|
||||
* #define SUPPORT_FILEFORMAT_BMP 1
|
||||
* #define SUPPORT_FILEFORMAT_PNG 1
|
||||
* #define SUPPORT_FILEFORMAT_TGA 0
|
||||
* #define SUPPORT_FILEFORMAT_JPG 0
|
||||
* #define SUPPORT_FILEFORMAT_GIF 1
|
||||
* #define SUPPORT_FILEFORMAT_QOI 1
|
||||
* #define SUPPORT_FILEFORMAT_PSD 0
|
||||
* #define SUPPORT_FILEFORMAT_HDR 0
|
||||
* #define SUPPORT_FILEFORMAT_PIC 0
|
||||
* #define SUPPORT_FILEFORMAT_PNM 0
|
||||
* #define SUPPORT_FILEFORMAT_DDS 1
|
||||
* #define SUPPORT_FILEFORMAT_PKM 0
|
||||
* #define SUPPORT_FILEFORMAT_KTX 0
|
||||
* #define SUPPORT_FILEFORMAT_PVR 0
|
||||
* #define SUPPORT_FILEFORMAT_ASTC 0
|
||||
* Selected desired fileformats to be supported for image data loading. Some of those formats are
|
||||
* supported by default, to remove support, #define as 0 in this module or your build system
|
||||
*
|
||||
* #define SUPPORT_IMAGE_EXPORT
|
||||
* #define SUPPORT_IMAGE_EXPORT 1
|
||||
* Support image export in multiple file formats
|
||||
*
|
||||
* #define SUPPORT_IMAGE_GENERATION
|
||||
* #define SUPPORT_IMAGE_GENERATION 1
|
||||
* Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)
|
||||
*
|
||||
* DEPENDENCIES:
|
||||
|
|
@ -366,7 +366,7 @@ Image LoadImageAnim(const char *fileName, int *frames)
|
|||
return image;
|
||||
}
|
||||
|
||||
// Load animated image data
|
||||
// Load animated image data from memory
|
||||
// - Image.data buffer includes all frames: [image#0][image#1][image#2][...]
|
||||
// - Number of frames is returned through 'frames' parameter
|
||||
// - All frames are returned in RGBA format
|
||||
|
|
@ -376,8 +376,7 @@ Image LoadImageAnimFromMemory(const char *fileType, const unsigned char *fileDat
|
|||
Image image = { 0 };
|
||||
int frameCount = 0;
|
||||
|
||||
// Security check for input data
|
||||
if ((fileType == NULL) || (fileData == NULL) || (dataSize == 0)) return image;
|
||||
if ((fileType == NULL) || (fileData == NULL) || (dataSize == 0)) return image; // Security check
|
||||
|
||||
#if SUPPORT_FILEFORMAT_GIF
|
||||
if ((strcmp(fileType, ".gif") == 0) || (strcmp(fileType, ".GIF") == 0))
|
||||
|
|
@ -581,7 +580,7 @@ Image LoadImageFromTexture(Texture2D texture)
|
|||
return image;
|
||||
}
|
||||
|
||||
// Load image from screen buffer and (screenshot)
|
||||
// Load image from screen buffer (screenshot)
|
||||
Image LoadImageFromScreen(void)
|
||||
{
|
||||
Image image = { 0 };
|
||||
|
|
@ -621,8 +620,7 @@ bool ExportImage(Image image, const char *fileName)
|
|||
{
|
||||
int result = 0;
|
||||
|
||||
// Security check for input data
|
||||
if ((image.width == 0) || (image.height == 0) || (image.data == NULL)) return result;
|
||||
if ((image.width == 0) || (image.height == 0) || (image.data == NULL)) return result; // Security check
|
||||
|
||||
#if SUPPORT_IMAGE_EXPORT
|
||||
int channels = 4;
|
||||
|
|
@ -709,8 +707,7 @@ unsigned char *ExportImageToMemory(Image image, const char *fileType, int *dataS
|
|||
unsigned char *fileData = NULL;
|
||||
*dataSize = 0;
|
||||
|
||||
// Security check for input data
|
||||
if ((image.width == 0) || (image.height == 0) || (image.data == NULL)) return NULL;
|
||||
if ((image.width == 0) || (image.height == 0) || (image.data == NULL)) return fileData; // Security check
|
||||
|
||||
int channels = 4;
|
||||
|
||||
|
|
@ -734,7 +731,7 @@ unsigned char *ExportImageToMemory(Image image, const char *fileType, int *dataS
|
|||
// Export image as code file (.h) defining an array of bytes
|
||||
bool ExportImageAsCode(Image image, const char *fileName)
|
||||
{
|
||||
bool success = false;
|
||||
bool result = false;
|
||||
|
||||
#ifndef TEXT_BYTES_PER_LINE
|
||||
#define TEXT_BYTES_PER_LINE 20
|
||||
|
|
@ -774,14 +771,14 @@ bool ExportImageAsCode(Image image, const char *fileName)
|
|||
byteCount += sprintf(txtData + byteCount, "0x%x };\n", ((unsigned char *)image.data)[dataSize - 1]);
|
||||
|
||||
// NOTE: Text data size exported is determined by '\0' (NULL) character
|
||||
success = SaveFileText(fileName, txtData);
|
||||
result = SaveFileText(fileName, txtData);
|
||||
|
||||
RL_FREE(txtData);
|
||||
|
||||
if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image as code exported successfully", fileName);
|
||||
if (result != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image as code exported successfully", fileName);
|
||||
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export image as code", fileName);
|
||||
|
||||
return success;
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
|
|
@ -1536,8 +1533,7 @@ Image ImageFromChannel(Image image, int selectedChannel)
|
|||
{
|
||||
Image result = { 0 };
|
||||
|
||||
// Security check to avoid program crash
|
||||
if ((image.data == NULL) || (image.width == 0) || (image.height == 0)) return result;
|
||||
if ((image.data == NULL) || (image.width == 0) || (image.height == 0)) return result; // Security check
|
||||
|
||||
// Check selected channel is valid
|
||||
if (selectedChannel < 0)
|
||||
|
|
@ -1579,7 +1575,7 @@ Image ImageFromChannel(Image image, int selectedChannel)
|
|||
// Check for RGBA formats
|
||||
if (selectedChannel > 3)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ImageFromChannel supports channels 0 to 3 (rgba). Setting channel to alpha.");
|
||||
TRACELOG(LOG_WARNING, "ImageFromChannel supports channels 0 to 3 (RGBA). Setting channel to alpha.");
|
||||
selectedChannel = 3;
|
||||
}
|
||||
|
||||
|
|
@ -2799,7 +2795,7 @@ void ImageColorGrayscale(Image *image)
|
|||
|
||||
// Modify image color: contrast
|
||||
// NOTE: Contrast values between -100 and 100
|
||||
void ImageColorContrast(Image *image, float contrast)
|
||||
void ImageColorContrast(Image *image, int contrast)
|
||||
{
|
||||
// Security check to avoid program crash
|
||||
if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
|
||||
|
|
@ -2807,8 +2803,8 @@ void ImageColorContrast(Image *image, float contrast)
|
|||
if (contrast < -100) contrast = -100;
|
||||
if (contrast > 100) contrast = 100;
|
||||
|
||||
contrast = (100.0f + contrast)/100.0f;
|
||||
contrast *= contrast;
|
||||
float factor = (float)(100.0f + contrast)/100.0f;
|
||||
factor *= factor;
|
||||
|
||||
Color *pixels = LoadImageColors(*image);
|
||||
|
||||
|
|
@ -2816,7 +2812,7 @@ void ImageColorContrast(Image *image, float contrast)
|
|||
{
|
||||
float pR = (float)pixels[i].r/255.0f;
|
||||
pR -= 0.5f;
|
||||
pR *= contrast;
|
||||
pR *= factor;
|
||||
pR += 0.5f;
|
||||
pR *= 255;
|
||||
if (pR < 0) pR = 0;
|
||||
|
|
@ -2824,7 +2820,7 @@ void ImageColorContrast(Image *image, float contrast)
|
|||
|
||||
float pG = (float)pixels[i].g/255.0f;
|
||||
pG -= 0.5f;
|
||||
pG *= contrast;
|
||||
pG *= factor;
|
||||
pG += 0.5f;
|
||||
pG *= 255;
|
||||
if (pG < 0) pG = 0;
|
||||
|
|
@ -2832,7 +2828,7 @@ void ImageColorContrast(Image *image, float contrast)
|
|||
|
||||
float pB = (float)pixels[i].b/255.0f;
|
||||
pB -= 0.5f;
|
||||
pB *= contrast;
|
||||
pB *= factor;
|
||||
pB += 0.5f;
|
||||
pB *= 255;
|
||||
if (pB < 0) pB = 0;
|
||||
|
|
@ -2937,7 +2933,7 @@ void ImageColorReplace(Image *image, Color color, Color replace)
|
|||
// NOTE: Memory allocated should be freed using UnloadImageColors();
|
||||
Color *LoadImageColors(Image image)
|
||||
{
|
||||
if ((image.width == 0) || (image.height == 0)) return NULL;
|
||||
if ((image.width == 0) || (image.height == 0)) return NULL; // Security check
|
||||
|
||||
Color *pixels = (Color *)RL_MALLOC(image.width*image.height*sizeof(Color));
|
||||
|
||||
|
|
@ -3734,7 +3730,14 @@ void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color)
|
|||
}
|
||||
|
||||
// Draw rectangle lines within an image
|
||||
void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color)
|
||||
void ImageDrawRectangleLines(Image *dst, int posX, int posY, int width, int height, Color color)
|
||||
{
|
||||
Rectangle rec = { posX, posY, width, height };
|
||||
ImageDrawRectangleLinesEx(dst, rec, 1, color);
|
||||
}
|
||||
|
||||
// Draw rectangle lines within an image with extended parameters
|
||||
void ImageDrawRectangleLinesEx(Image *dst, Rectangle rec, int thick, Color color)
|
||||
{
|
||||
ImageDrawRectangle(dst, (int)rec.x, (int)rec.y, (int)rec.width, thick, color);
|
||||
ImageDrawRectangle(dst, (int)rec.x, (int)(rec.y + thick), thick, (int)(rec.height - thick*2), color);
|
||||
|
|
@ -3810,7 +3813,7 @@ void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color col
|
|||
}
|
||||
|
||||
// Draw triangle with interpolated colors within an image
|
||||
void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3)
|
||||
void ImageDrawTriangleGradient(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3)
|
||||
{
|
||||
// Calculate the 2D bounding box of the triangle
|
||||
// Determine the minimum and maximum x and y coordinates of the triangle vertices
|
||||
|
|
@ -4628,7 +4631,7 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2
|
|||
}
|
||||
}
|
||||
|
||||
// Draws a texture (or part of it) that stretches or shrinks nicely using n-patch info
|
||||
// Draw a texture (or part of it) that stretches or shrinks nicely using n-patch info
|
||||
void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint)
|
||||
{
|
||||
if (texture.id > 0)
|
||||
|
|
@ -4903,44 +4906,44 @@ Vector3 ColorToHSV(Color color)
|
|||
float max = 0.0f;
|
||||
float delta = 0.0f;
|
||||
|
||||
min = rgb.x < rgb.y? rgb.x : rgb.y;
|
||||
min = min < rgb.z? min : rgb.z;
|
||||
min = (rgb.x < rgb.y)? rgb.x : rgb.y;
|
||||
min = (min < rgb.z)? min : rgb.z;
|
||||
|
||||
max = rgb.x > rgb.y? rgb.x : rgb.y;
|
||||
max = max > rgb.z? max : rgb.z;
|
||||
max = (rgb.x > rgb.y)? rgb.x : rgb.y;
|
||||
max = (max > rgb.z)? max : rgb.z;
|
||||
|
||||
hsv.z = max; // Value
|
||||
hsv.z = max; // Value
|
||||
delta = max - min;
|
||||
|
||||
if (delta < 0.00001f)
|
||||
{
|
||||
hsv.y = 0.0f;
|
||||
hsv.x = 0.0f; // Undefined, maybe NAN?
|
||||
hsv.x = 0.0f; // Undefined, maybe NAN?
|
||||
return hsv;
|
||||
}
|
||||
|
||||
if (max > 0.0f)
|
||||
{
|
||||
// NOTE: If max is 0, this divide would cause a crash
|
||||
hsv.y = (delta/max); // Saturation
|
||||
hsv.y = (delta/max); // Saturation
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined
|
||||
hsv.y = 0.0f;
|
||||
hsv.x = NAN; // Undefined
|
||||
hsv.x = NAN; // Undefined
|
||||
return hsv;
|
||||
}
|
||||
|
||||
// NOTE: Comparing float values could not work properly
|
||||
if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta
|
||||
if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta
|
||||
else
|
||||
{
|
||||
if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow
|
||||
else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan
|
||||
if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow
|
||||
else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan
|
||||
}
|
||||
|
||||
hsv.x *= 60.0f; // Convert to degrees
|
||||
hsv.x *= 60.0f; // Convert to degrees
|
||||
|
||||
if (hsv.x < 0.0f) hsv.x += 360.0f;
|
||||
|
||||
|
|
@ -5093,7 +5096,7 @@ Color ColorAlpha(Color color, float alpha)
|
|||
// Get src alpha-blended into dst color with tint
|
||||
Color ColorAlphaBlend(Color dst, Color src, Color tint)
|
||||
{
|
||||
Color out = WHITE;
|
||||
Color result = WHITE;
|
||||
|
||||
// Apply color tint to source color
|
||||
src.r = (unsigned char)(((unsigned int)src.r*((unsigned int)tint.r+1)) >> 8);
|
||||
|
|
@ -5104,24 +5107,24 @@ Color ColorAlphaBlend(Color dst, Color src, Color tint)
|
|||
//#define COLORALPHABLEND_FLOAT
|
||||
#define COLORALPHABLEND_INTEGERS
|
||||
#if defined(COLORALPHABLEND_INTEGERS)
|
||||
if (src.a == 0) out = dst;
|
||||
else if (src.a == 255) out = src;
|
||||
if (src.a == 0) result = dst;
|
||||
else if (src.a == 255) result = src;
|
||||
else
|
||||
{
|
||||
unsigned int alpha = (unsigned int)src.a + 1; // Shifting by 8 (dividing by 256), so need to take that excess into account
|
||||
out.a = (unsigned char)(((unsigned int)alpha*256 + (unsigned int)dst.a*(256 - alpha)) >> 8);
|
||||
result.a = (unsigned char)(((unsigned int)alpha*256 + (unsigned int)dst.a*(256 - alpha)) >> 8);
|
||||
|
||||
if (out.a > 0)
|
||||
if (result.a > 0)
|
||||
{
|
||||
out.r = (unsigned char)((((unsigned int)src.r*alpha*256 + (unsigned int)dst.r*(unsigned int)dst.a*(256 - alpha))/out.a) >> 8);
|
||||
out.g = (unsigned char)((((unsigned int)src.g*alpha*256 + (unsigned int)dst.g*(unsigned int)dst.a*(256 - alpha))/out.a) >> 8);
|
||||
out.b = (unsigned char)((((unsigned int)src.b*alpha*256 + (unsigned int)dst.b*(unsigned int)dst.a*(256 - alpha))/out.a) >> 8);
|
||||
result.r = (unsigned char)((((unsigned int)src.r*alpha*256 + (unsigned int)dst.r*(unsigned int)dst.a*(256 - alpha))/result.a) >> 8);
|
||||
result.g = (unsigned char)((((unsigned int)src.g*alpha*256 + (unsigned int)dst.g*(unsigned int)dst.a*(256 - alpha))/result.a) >> 8);
|
||||
result.b = (unsigned char)((((unsigned int)src.b*alpha*256 + (unsigned int)dst.b*(unsigned int)dst.a*(256 - alpha))/result.a) >> 8);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined(COLORALPHABLEND_FLOAT)
|
||||
if (src.a == 0) out = dst;
|
||||
else if (src.a == 255) out = src;
|
||||
if (src.a == 0) result = dst;
|
||||
else if (src.a == 255) result = src;
|
||||
else
|
||||
{
|
||||
Vector4 fdst = ColorNormalize(dst);
|
||||
|
|
@ -5138,11 +5141,11 @@ Color ColorAlphaBlend(Color dst, Color src, Color tint)
|
|||
fout.z = (fsrc.z*fsrc.w + fdst.z*fdst.w*(1 - fsrc.w))/fout.w;
|
||||
}
|
||||
|
||||
out = (Color){ (unsigned char)(fout.x*255.0f), (unsigned char)(fout.y*255.0f), (unsigned char)(fout.z*255.0f), (unsigned char)(fout.w*255.0f) };
|
||||
result = (Color){ (unsigned char)(fout.x*255.0f), (unsigned char)(fout.y*255.0f), (unsigned char)(fout.z*255.0f), (unsigned char)(fout.w*255.0f) };
|
||||
}
|
||||
#endif
|
||||
|
||||
return out;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get color lerp interpolation between two colors, factor [0.0f..1.0f]
|
||||
|
|
|
|||
Loading…
Reference in a new issue