Update C sources

This commit is contained in:
Milan Nikolic 2023-11-09 14:32:33 +01:00
parent 07d1374c41
commit d0612c27b2
No known key found for this signature in database
GPG key ID: 9229D0EAA3AA4E75
17 changed files with 2216 additions and 1053 deletions

View file

@ -328,15 +328,6 @@ typedef struct cgltf_accessor_sparse
cgltf_component_type indices_component_type; cgltf_component_type indices_component_type;
cgltf_buffer_view* values_buffer_view; cgltf_buffer_view* values_buffer_view;
cgltf_size values_byte_offset; cgltf_size values_byte_offset;
cgltf_extras extras;
cgltf_extras indices_extras;
cgltf_extras values_extras;
cgltf_size extensions_count;
cgltf_extension* extensions;
cgltf_size indices_extensions_count;
cgltf_extension* indices_extensions;
cgltf_size values_extensions_count;
cgltf_extension* values_extensions;
} cgltf_accessor_sparse; } cgltf_accessor_sparse;
typedef struct cgltf_accessor typedef struct cgltf_accessor
@ -419,9 +410,6 @@ typedef struct cgltf_texture_view
cgltf_float scale; /* equivalent to strength for occlusion_texture */ cgltf_float scale; /* equivalent to strength for occlusion_texture */
cgltf_bool has_transform; cgltf_bool has_transform;
cgltf_texture_transform transform; cgltf_texture_transform transform;
cgltf_extras extras;
cgltf_size extensions_count;
cgltf_extension* extensions;
} cgltf_texture_view; } cgltf_texture_view;
typedef struct cgltf_pbr_metallic_roughness typedef struct cgltf_pbr_metallic_roughness
@ -504,6 +492,13 @@ typedef struct cgltf_iridescence
cgltf_texture_view iridescence_thickness_texture; cgltf_texture_view iridescence_thickness_texture;
} cgltf_iridescence; } cgltf_iridescence;
typedef struct cgltf_anisotropy
{
cgltf_float anisotropy_strength;
cgltf_float anisotropy_rotation;
cgltf_texture_view anisotropy_texture;
} cgltf_anisotropy;
typedef struct cgltf_material typedef struct cgltf_material
{ {
char* name; char* name;
@ -517,6 +512,7 @@ typedef struct cgltf_material
cgltf_bool has_sheen; cgltf_bool has_sheen;
cgltf_bool has_emissive_strength; cgltf_bool has_emissive_strength;
cgltf_bool has_iridescence; cgltf_bool has_iridescence;
cgltf_bool has_anisotropy;
cgltf_pbr_metallic_roughness pbr_metallic_roughness; cgltf_pbr_metallic_roughness pbr_metallic_roughness;
cgltf_pbr_specular_glossiness pbr_specular_glossiness; cgltf_pbr_specular_glossiness pbr_specular_glossiness;
cgltf_clearcoat clearcoat; cgltf_clearcoat clearcoat;
@ -527,6 +523,7 @@ typedef struct cgltf_material
cgltf_volume volume; cgltf_volume volume;
cgltf_emissive_strength emissive_strength; cgltf_emissive_strength emissive_strength;
cgltf_iridescence iridescence; cgltf_iridescence iridescence;
cgltf_anisotropy anisotropy;
cgltf_texture_view normal_texture; cgltf_texture_view normal_texture;
cgltf_texture_view occlusion_texture; cgltf_texture_view occlusion_texture;
cgltf_texture_view emissive_texture; cgltf_texture_view emissive_texture;
@ -559,7 +556,6 @@ typedef struct cgltf_draco_mesh_compression {
} cgltf_draco_mesh_compression; } cgltf_draco_mesh_compression;
typedef struct cgltf_mesh_gpu_instancing { typedef struct cgltf_mesh_gpu_instancing {
cgltf_buffer_view* buffer_view;
cgltf_attribute* attributes; cgltf_attribute* attributes;
cgltf_size attributes_count; cgltf_size attributes_count;
} cgltf_mesh_gpu_instancing; } cgltf_mesh_gpu_instancing;
@ -842,10 +838,28 @@ cgltf_size cgltf_component_size(cgltf_component_type component_type);
cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type); cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type);
cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_float* out, cgltf_size float_count); cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_float* out, cgltf_size float_count);
cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, cgltf_uint* out, cgltf_size index_count);
/* this function is deprecated and will be removed in the future; use cgltf_extras::data instead */ /* this function is deprecated and will be removed in the future; use cgltf_extras::data instead */
cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size); cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size);
cgltf_size cgltf_mesh_index(const cgltf_data* data, const cgltf_mesh* object);
cgltf_size cgltf_material_index(const cgltf_data* data, const cgltf_material* object);
cgltf_size cgltf_accessor_index(const cgltf_data* data, const cgltf_accessor* object);
cgltf_size cgltf_buffer_view_index(const cgltf_data* data, const cgltf_buffer_view* object);
cgltf_size cgltf_buffer_index(const cgltf_data* data, const cgltf_buffer* object);
cgltf_size cgltf_image_index(const cgltf_data* data, const cgltf_image* object);
cgltf_size cgltf_texture_index(const cgltf_data* data, const cgltf_texture* object);
cgltf_size cgltf_sampler_index(const cgltf_data* data, const cgltf_sampler* object);
cgltf_size cgltf_skin_index(const cgltf_data* data, const cgltf_skin* object);
cgltf_size cgltf_camera_index(const cgltf_data* data, const cgltf_camera* object);
cgltf_size cgltf_light_index(const cgltf_data* data, const cgltf_light* object);
cgltf_size cgltf_node_index(const cgltf_data* data, const cgltf_node* object);
cgltf_size cgltf_scene_index(const cgltf_data* data, const cgltf_scene* object);
cgltf_size cgltf_animation_index(const cgltf_data* data, const cgltf_animation* object);
cgltf_size cgltf_animation_sampler_index(const cgltf_animation* animation, const cgltf_animation_sampler* object);
cgltf_size cgltf_animation_channel_index(const cgltf_animation* animation, const cgltf_animation_channel* object);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
@ -866,6 +880,7 @@ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras*
#ifdef CGLTF_IMPLEMENTATION #ifdef CGLTF_IMPLEMENTATION
#include <assert.h> /* For assert */
#include <string.h> /* For strncpy */ #include <string.h> /* For strncpy */
#include <stdio.h> /* For fopen */ #include <stdio.h> /* For fopen */
#include <limits.h> /* For UINT_MAX etc */ #include <limits.h> /* For UINT_MAX etc */
@ -875,10 +890,6 @@ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras*
#include <stdlib.h> /* For malloc, free, atoi, atof */ #include <stdlib.h> /* For malloc, free, atoi, atof */
#endif #endif
#if CGLTF_VALIDATE_ENABLE_ASSERTS
#include <assert.h>
#endif
/* JSMN_PARENT_LINKS is necessary to make parsing large structures linear in input size */ /* JSMN_PARENT_LINKS is necessary to make parsing large structures linear in input size */
#define JSMN_PARENT_LINKS #define JSMN_PARENT_LINKS
@ -1000,7 +1011,7 @@ static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* m
{ {
fseek(file, 0, SEEK_END); fseek(file, 0, SEEK_END);
#ifdef _WIN32 #ifdef _MSC_VER
__int64 length = _ftelli64(file); __int64 length = _ftelli64(file);
#else #else
long length = ftell(file); long length = ftell(file);
@ -1144,7 +1155,7 @@ cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_s
json_chunk += GlbChunkHeaderSize; json_chunk += GlbChunkHeaderSize;
const void* bin = 0; const void* bin = NULL;
cgltf_size bin_size = 0; cgltf_size bin_size = 0;
if (GlbHeaderSize + GlbChunkHeaderSize + json_length + GlbChunkHeaderSize <= size) if (GlbHeaderSize + GlbChunkHeaderSize + json_length + GlbChunkHeaderSize <= size)
@ -1763,12 +1774,6 @@ static void cgltf_free_extensions(cgltf_data* data, cgltf_extension* extensions,
data->memory.free_func(data->memory.user_data, extensions); data->memory.free_func(data->memory.user_data, extensions);
} }
static void cgltf_free_texture_view(cgltf_data* data, cgltf_texture_view* view)
{
cgltf_free_extensions(data, view->extensions, view->extensions_count);
cgltf_free_extras(data, &view->extras);
}
void cgltf_free(cgltf_data* data) void cgltf_free(cgltf_data* data)
{ {
if (!data) if (!data)
@ -1790,15 +1795,6 @@ void cgltf_free(cgltf_data* data)
{ {
data->memory.free_func(data->memory.user_data, data->accessors[i].name); data->memory.free_func(data->memory.user_data, data->accessors[i].name);
if(data->accessors[i].is_sparse)
{
cgltf_free_extensions(data, data->accessors[i].sparse.extensions, data->accessors[i].sparse.extensions_count);
cgltf_free_extensions(data, data->accessors[i].sparse.indices_extensions, data->accessors[i].sparse.indices_extensions_count);
cgltf_free_extensions(data, data->accessors[i].sparse.values_extensions, data->accessors[i].sparse.values_extensions_count);
cgltf_free_extras(data, &data->accessors[i].sparse.extras);
cgltf_free_extras(data, &data->accessors[i].sparse.indices_extras);
cgltf_free_extras(data, &data->accessors[i].sparse.values_extras);
}
cgltf_free_extensions(data, data->accessors[i].extensions, data->accessors[i].extensions_count); cgltf_free_extensions(data, data->accessors[i].extensions, data->accessors[i].extensions_count);
cgltf_free_extras(data, &data->accessors[i].extras); cgltf_free_extras(data, &data->accessors[i].extras);
} }
@ -1900,50 +1896,6 @@ void cgltf_free(cgltf_data* data)
{ {
data->memory.free_func(data->memory.user_data, data->materials[i].name); data->memory.free_func(data->memory.user_data, data->materials[i].name);
if(data->materials[i].has_pbr_metallic_roughness)
{
cgltf_free_texture_view(data, &data->materials[i].pbr_metallic_roughness.metallic_roughness_texture);
cgltf_free_texture_view(data, &data->materials[i].pbr_metallic_roughness.base_color_texture);
}
if(data->materials[i].has_pbr_specular_glossiness)
{
cgltf_free_texture_view(data, &data->materials[i].pbr_specular_glossiness.diffuse_texture);
cgltf_free_texture_view(data, &data->materials[i].pbr_specular_glossiness.specular_glossiness_texture);
}
if(data->materials[i].has_clearcoat)
{
cgltf_free_texture_view(data, &data->materials[i].clearcoat.clearcoat_texture);
cgltf_free_texture_view(data, &data->materials[i].clearcoat.clearcoat_roughness_texture);
cgltf_free_texture_view(data, &data->materials[i].clearcoat.clearcoat_normal_texture);
}
if(data->materials[i].has_specular)
{
cgltf_free_texture_view(data, &data->materials[i].specular.specular_texture);
cgltf_free_texture_view(data, &data->materials[i].specular.specular_color_texture);
}
if(data->materials[i].has_transmission)
{
cgltf_free_texture_view(data, &data->materials[i].transmission.transmission_texture);
}
if (data->materials[i].has_volume)
{
cgltf_free_texture_view(data, &data->materials[i].volume.thickness_texture);
}
if(data->materials[i].has_sheen)
{
cgltf_free_texture_view(data, &data->materials[i].sheen.sheen_color_texture);
cgltf_free_texture_view(data, &data->materials[i].sheen.sheen_roughness_texture);
}
if(data->materials[i].has_iridescence)
{
cgltf_free_texture_view(data, &data->materials[i].iridescence.iridescence_texture);
cgltf_free_texture_view(data, &data->materials[i].iridescence.iridescence_thickness_texture);
}
cgltf_free_texture_view(data, &data->materials[i].normal_texture);
cgltf_free_texture_view(data, &data->materials[i].occlusion_texture);
cgltf_free_texture_view(data, &data->materials[i].emissive_texture);
cgltf_free_extensions(data, data->materials[i].extensions, data->materials[i].extensions_count); cgltf_free_extensions(data, data->materials[i].extensions, data->materials[i].extensions_count);
cgltf_free_extras(data, &data->materials[i].extras); cgltf_free_extras(data, &data->materials[i].extras);
} }
@ -2198,8 +2150,6 @@ static cgltf_ssize cgltf_component_read_integer(const void* in, cgltf_component_
return *((const uint16_t*) in); return *((const uint16_t*) in);
case cgltf_component_type_r_32u: case cgltf_component_type_r_32u:
return *((const uint32_t*) in); return *((const uint32_t*) in);
case cgltf_component_type_r_32f:
return (cgltf_ssize)*((const float*) in);
case cgltf_component_type_r_8: case cgltf_component_type_r_8:
return *((const int8_t*) in); return *((const int8_t*) in);
case cgltf_component_type_r_8u: case cgltf_component_type_r_8u:
@ -2217,8 +2167,6 @@ static cgltf_size cgltf_component_read_index(const void* in, cgltf_component_typ
return *((const uint16_t*) in); return *((const uint16_t*) in);
case cgltf_component_type_r_32u: case cgltf_component_type_r_32u:
return *((const uint32_t*) in); return *((const uint32_t*) in);
case cgltf_component_type_r_32f:
return (cgltf_size)((cgltf_ssize)*((const float*) in));
case cgltf_component_type_r_8u: case cgltf_component_type_r_8u:
return *((const uint8_t*) in); return *((const uint8_t*) in);
default: default:
@ -2356,21 +2304,41 @@ cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_fl
cgltf_size element_count = float_count / floats_per_element; cgltf_size element_count = float_count / floats_per_element;
// First pass: convert each element in the base accessor. // First pass: convert each element in the base accessor.
cgltf_float* dest = out; if (accessor->buffer_view == NULL)
cgltf_accessor dense = *accessor;
dense.is_sparse = 0;
for (cgltf_size index = 0; index < element_count; index++, dest += floats_per_element)
{ {
if (!cgltf_accessor_read_float(&dense, index, dest, floats_per_element)) memset(out, 0, element_count * floats_per_element * sizeof(cgltf_float));
}
else
{
const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view);
if (element == NULL)
{ {
return 0; return 0;
} }
element += accessor->offset;
if (accessor->component_type == cgltf_component_type_r_32f && accessor->stride == floats_per_element * sizeof(cgltf_float))
{
memcpy(out, element, element_count * floats_per_element * sizeof(cgltf_float));
}
else
{
cgltf_float* dest = out;
for (cgltf_size index = 0; index < element_count; index++, dest += floats_per_element, element += accessor->stride)
{
if (!cgltf_element_read_float(element, accessor->type, accessor->component_type, accessor->normalized, dest, floats_per_element))
{
return 0;
}
}
}
} }
// Second pass: write out each element in the sparse accessor. // Second pass: write out each element in the sparse accessor.
if (accessor->is_sparse) if (accessor->is_sparse)
{ {
const cgltf_accessor_sparse* sparse = &dense.sparse; const cgltf_accessor_sparse* sparse = &accessor->sparse;
const uint8_t* index_data = cgltf_buffer_view_data(sparse->indices_buffer_view); const uint8_t* index_data = cgltf_buffer_view_data(sparse->indices_buffer_view);
const uint8_t* reader_head = cgltf_buffer_view_data(sparse->values_buffer_view); const uint8_t* reader_head = cgltf_buffer_view_data(sparse->values_buffer_view);
@ -2384,17 +2352,15 @@ cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_fl
reader_head += sparse->values_byte_offset; reader_head += sparse->values_byte_offset;
cgltf_size index_stride = cgltf_component_size(sparse->indices_component_type); cgltf_size index_stride = cgltf_component_size(sparse->indices_component_type);
for (cgltf_size reader_index = 0; reader_index < sparse->count; reader_index++, index_data += index_stride) for (cgltf_size reader_index = 0; reader_index < sparse->count; reader_index++, index_data += index_stride, reader_head += accessor->stride)
{ {
size_t writer_index = cgltf_component_read_index(index_data, sparse->indices_component_type); size_t writer_index = cgltf_component_read_index(index_data, sparse->indices_component_type);
float* writer_head = out + writer_index * floats_per_element; float* writer_head = out + writer_index * floats_per_element;
if (!cgltf_element_read_float(reader_head, dense.type, dense.component_type, dense.normalized, writer_head, floats_per_element)) if (!cgltf_element_read_float(reader_head, accessor->type, accessor->component_type, accessor->normalized, writer_head, floats_per_element))
{ {
return 0; return 0;
} }
reader_head += dense.stride;
} }
} }
@ -2488,6 +2454,143 @@ cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size
return cgltf_component_read_index(element, accessor->component_type); return cgltf_component_read_index(element, accessor->component_type);
} }
cgltf_size cgltf_mesh_index(const cgltf_data* data, const cgltf_mesh* object)
{
assert(object && (cgltf_size)(object - data->meshes) < data->meshes_count);
return (cgltf_size)(object - data->meshes);
}
cgltf_size cgltf_material_index(const cgltf_data* data, const cgltf_material* object)
{
assert(object && (cgltf_size)(object - data->materials) < data->materials_count);
return (cgltf_size)(object - data->materials);
}
cgltf_size cgltf_accessor_index(const cgltf_data* data, const cgltf_accessor* object)
{
assert(object && (cgltf_size)(object - data->accessors) < data->accessors_count);
return (cgltf_size)(object - data->accessors);
}
cgltf_size cgltf_buffer_view_index(const cgltf_data* data, const cgltf_buffer_view* object)
{
assert(object && (cgltf_size)(object - data->buffer_views) < data->buffer_views_count);
return (cgltf_size)(object - data->buffer_views);
}
cgltf_size cgltf_buffer_index(const cgltf_data* data, const cgltf_buffer* object)
{
assert(object && (cgltf_size)(object - data->buffers) < data->buffers_count);
return (cgltf_size)(object - data->buffers);
}
cgltf_size cgltf_image_index(const cgltf_data* data, const cgltf_image* object)
{
assert(object && (cgltf_size)(object - data->images) < data->images_count);
return (cgltf_size)(object - data->images);
}
cgltf_size cgltf_texture_index(const cgltf_data* data, const cgltf_texture* object)
{
assert(object && (cgltf_size)(object - data->textures) < data->textures_count);
return (cgltf_size)(object - data->textures);
}
cgltf_size cgltf_sampler_index(const cgltf_data* data, const cgltf_sampler* object)
{
assert(object && (cgltf_size)(object - data->samplers) < data->samplers_count);
return (cgltf_size)(object - data->samplers);
}
cgltf_size cgltf_skin_index(const cgltf_data* data, const cgltf_skin* object)
{
assert(object && (cgltf_size)(object - data->skins) < data->skins_count);
return (cgltf_size)(object - data->skins);
}
cgltf_size cgltf_camera_index(const cgltf_data* data, const cgltf_camera* object)
{
assert(object && (cgltf_size)(object - data->cameras) < data->cameras_count);
return (cgltf_size)(object - data->cameras);
}
cgltf_size cgltf_light_index(const cgltf_data* data, const cgltf_light* object)
{
assert(object && (cgltf_size)(object - data->lights) < data->lights_count);
return (cgltf_size)(object - data->lights);
}
cgltf_size cgltf_node_index(const cgltf_data* data, const cgltf_node* object)
{
assert(object && (cgltf_size)(object - data->nodes) < data->nodes_count);
return (cgltf_size)(object - data->nodes);
}
cgltf_size cgltf_scene_index(const cgltf_data* data, const cgltf_scene* object)
{
assert(object && (cgltf_size)(object - data->scenes) < data->scenes_count);
return (cgltf_size)(object - data->scenes);
}
cgltf_size cgltf_animation_index(const cgltf_data* data, const cgltf_animation* object)
{
assert(object && (cgltf_size)(object - data->animations) < data->animations_count);
return (cgltf_size)(object - data->animations);
}
cgltf_size cgltf_animation_sampler_index(const cgltf_animation* animation, const cgltf_animation_sampler* object)
{
assert(object && (cgltf_size)(object - animation->samplers) < animation->samplers_count);
return (cgltf_size)(object - animation->samplers);
}
cgltf_size cgltf_animation_channel_index(const cgltf_animation* animation, const cgltf_animation_channel* object)
{
assert(object && (cgltf_size)(object - animation->channels) < animation->channels_count);
return (cgltf_size)(object - animation->channels);
}
cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, cgltf_uint* out, cgltf_size index_count)
{
if (out == NULL)
{
return accessor->count;
}
index_count = accessor->count < index_count ? accessor->count : index_count;
if (accessor->is_sparse)
{
return 0;
}
if (accessor->buffer_view == NULL)
{
return 0;
}
const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view);
if (element == NULL)
{
return 0;
}
element += accessor->offset;
if (accessor->component_type == cgltf_component_type_r_32u && accessor->stride == sizeof(cgltf_uint))
{
memcpy(out, element, index_count * sizeof(cgltf_uint));
}
else
{
cgltf_uint* dest = out;
for (cgltf_size index = 0; index < index_count; index++, dest++, element += accessor->stride)
{
*dest = (cgltf_uint)cgltf_component_read_index(element, accessor->component_type);
}
}
return index_count;
}
#define CGLTF_ERROR_JSON -1 #define CGLTF_ERROR_JSON -1
#define CGLTF_ERROR_NOMEM -2 #define CGLTF_ERROR_NOMEM -2
#define CGLTF_ERROR_LEGACY -3 #define CGLTF_ERROR_LEGACY -3
@ -2864,6 +2967,10 @@ static int cgltf_parse_json_draco_mesh_compression(cgltf_options* options, jsmnt
out_draco_mesh_compression->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk)); out_draco_mesh_compression->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk));
++i; ++i;
} }
else
{
i = cgltf_skip_json(tokens, i+1);
}
if (i < 0) if (i < 0)
{ {
@ -2889,11 +2996,9 @@ static int cgltf_parse_json_mesh_gpu_instancing(cgltf_options* options, jsmntok_
{ {
i = cgltf_parse_json_attribute_list(options, tokens, i + 1, json_chunk, &out_mesh_gpu_instancing->attributes, &out_mesh_gpu_instancing->attributes_count); i = cgltf_parse_json_attribute_list(options, tokens, i + 1, json_chunk, &out_mesh_gpu_instancing->attributes, &out_mesh_gpu_instancing->attributes_count);
} }
else if (cgltf_json_strcmp(tokens + i, json_chunk, "bufferView") == 0) else
{ {
++i; i = cgltf_skip_json(tokens, i+1);
out_mesh_gpu_instancing->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk));
++i;
} }
if (i < 0) if (i < 0)
@ -3291,7 +3396,7 @@ static cgltf_component_type cgltf_json_to_component_type(jsmntok_t const* tok, c
} }
} }
static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_accessor_sparse* out_sparse) static int cgltf_parse_json_accessor_sparse(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_accessor_sparse* out_sparse)
{ {
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
@ -3338,14 +3443,6 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co
out_sparse->indices_component_type = cgltf_json_to_component_type(tokens + i, json_chunk); out_sparse->indices_component_type = cgltf_json_to_component_type(tokens + i, json_chunk);
++i; ++i;
} }
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
{
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sparse->indices_extras);
}
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
{
i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sparse->indices_extensions_count, &out_sparse->indices_extensions);
}
else else
{ {
i = cgltf_skip_json(tokens, i+1); i = cgltf_skip_json(tokens, i+1);
@ -3381,14 +3478,6 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co
out_sparse->values_byte_offset = cgltf_json_to_size(tokens + i, json_chunk); out_sparse->values_byte_offset = cgltf_json_to_size(tokens + i, json_chunk);
++i; ++i;
} }
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
{
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sparse->values_extras);
}
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
{
i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sparse->values_extensions_count, &out_sparse->values_extensions);
}
else else
{ {
i = cgltf_skip_json(tokens, i+1); i = cgltf_skip_json(tokens, i+1);
@ -3400,14 +3489,6 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co
} }
} }
} }
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
{
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sparse->extras);
}
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
{
i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sparse->extensions_count, &out_sparse->extensions);
}
else else
{ {
i = cgltf_skip_json(tokens, i+1); i = cgltf_skip_json(tokens, i+1);
@ -3521,7 +3602,7 @@ static int cgltf_parse_json_accessor(cgltf_options* options, jsmntok_t const* to
else if (cgltf_json_strcmp(tokens + i, json_chunk, "sparse") == 0) else if (cgltf_json_strcmp(tokens + i, json_chunk, "sparse") == 0)
{ {
out_accessor->is_sparse = 1; out_accessor->is_sparse = 1;
i = cgltf_parse_json_accessor_sparse(options, tokens, i + 1, json_chunk, &out_accessor->sparse); i = cgltf_parse_json_accessor_sparse(tokens, i + 1, json_chunk, &out_accessor->sparse);
} }
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
{ {
@ -3593,6 +3674,8 @@ static int cgltf_parse_json_texture_transform(jsmntok_t const* tokens, int i, co
static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_texture_view* out_texture_view) static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_texture_view* out_texture_view)
{ {
(void)options;
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
out_texture_view->scale = 1.0f; out_texture_view->scale = 1.0f;
@ -3629,28 +3712,12 @@ static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const
out_texture_view->scale = cgltf_json_to_float(tokens + i, json_chunk); out_texture_view->scale = cgltf_json_to_float(tokens + i, json_chunk);
++i; ++i;
} }
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
{
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_texture_view->extras);
}
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
{ {
++i; ++i;
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
if(out_texture_view->extensions)
{
return CGLTF_ERROR_JSON;
}
int extensions_size = tokens[i].size; int extensions_size = tokens[i].size;
out_texture_view->extensions_count = 0;
out_texture_view->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size);
if (!out_texture_view->extensions)
{
return CGLTF_ERROR_NOMEM;
}
++i; ++i;
@ -3665,7 +3732,7 @@ static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const
} }
else else
{ {
i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_texture_view->extensions[out_texture_view->extensions_count++])); i = cgltf_skip_json(tokens, i + 1);
} }
if (i < 0) if (i < 0)
@ -3719,13 +3786,11 @@ static int cgltf_parse_json_pbr_metallic_roughness(cgltf_options* options, jsmnt
} }
else if (cgltf_json_strcmp(tokens+i, json_chunk, "baseColorTexture") == 0) else if (cgltf_json_strcmp(tokens+i, json_chunk, "baseColorTexture") == 0)
{ {
i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->base_color_texture);
&out_pbr->base_color_texture);
} }
else if (cgltf_json_strcmp(tokens + i, json_chunk, "metallicRoughnessTexture") == 0) else if (cgltf_json_strcmp(tokens + i, json_chunk, "metallicRoughnessTexture") == 0)
{ {
i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->metallic_roughness_texture);
&out_pbr->metallic_roughness_texture);
} }
else else
{ {
@ -4128,6 +4193,47 @@ static int cgltf_parse_json_iridescence(cgltf_options* options, jsmntok_t const*
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);
int size = tokens[i].size;
++i;
for (int j = 0; j < size; ++j)
{
CGLTF_CHECK_KEY(tokens[i]);
if (cgltf_json_strcmp(tokens + i, json_chunk, "anisotropyStrength") == 0)
{
++i;
out_anisotropy->anisotropy_strength = cgltf_json_to_float(tokens + i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens + i, json_chunk, "anisotropyRotation") == 0)
{
++i;
out_anisotropy->anisotropy_rotation = cgltf_json_to_float(tokens + i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens + i, json_chunk, "anisotropyTexture") == 0)
{
i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_anisotropy->anisotropy_texture);
}
else
{
i = cgltf_skip_json(tokens, i + 1);
}
if (i < 0)
{
return i;
}
}
return i;
}
static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_image* out_image) static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_image* out_image)
{ {
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
@ -4516,6 +4622,11 @@ static int cgltf_parse_json_material(cgltf_options* options, jsmntok_t const* to
out_material->has_iridescence = 1; out_material->has_iridescence = 1;
i = cgltf_parse_json_iridescence(options, tokens, i + 1, json_chunk, &out_material->iridescence); 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_anisotropy") == 0)
{
out_material->has_anisotropy = 1;
i = cgltf_parse_json_anisotropy(options, tokens, i + 1, json_chunk, &out_material->anisotropy);
}
else else
{ {
i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_material->extensions[out_material->extensions_count++])); i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_material->extensions[out_material->extensions_count++]));
@ -6367,6 +6478,8 @@ 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_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].iridescence.iridescence_thickness_texture.texture, data->textures, data->textures_count);
CGLTF_PTRFIXUP(data->materials[i].anisotropy.anisotropy_texture.texture, data->textures, data->textures_count);
} }
for (cgltf_size i = 0; i < data->buffer_views_count; ++i) for (cgltf_size i = 0; i < data->buffer_views_count; ++i)
@ -6411,7 +6524,6 @@ static int cgltf_fixup_pointers(cgltf_data* data)
if (data->nodes[i].has_mesh_gpu_instancing) if (data->nodes[i].has_mesh_gpu_instancing)
{ {
CGLTF_PTRFIXUP_REQ(data->nodes[i].mesh_gpu_instancing.buffer_view, data->buffer_views, data->buffer_views_count);
for (cgltf_size m = 0; m < data->nodes[i].mesh_gpu_instancing.attributes_count; ++m) for (cgltf_size m = 0; m < data->nodes[i].mesh_gpu_instancing.attributes_count; ++m)
{ {
CGLTF_PTRFIXUP_REQ(data->nodes[i].mesh_gpu_instancing.attributes[m].data, data->accessors, data->accessors_count); CGLTF_PTRFIXUP_REQ(data->nodes[i].mesh_gpu_instancing.attributes[m].data, data->accessors, data->accessors_count);

View file

@ -1,6 +1,6 @@
/* /*
FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file. FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
dr_flac - v0.12.39 - 2022-09-17 dr_flac - v0.12.42 - 2023-11-02
David Reid - mackron@gmail.com David Reid - mackron@gmail.com
@ -235,12 +235,12 @@ extern "C" {
#define DRFLAC_VERSION_MAJOR 0 #define DRFLAC_VERSION_MAJOR 0
#define DRFLAC_VERSION_MINOR 12 #define DRFLAC_VERSION_MINOR 12
#define DRFLAC_VERSION_REVISION 39 #define DRFLAC_VERSION_REVISION 42
#define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION) #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. */ #include <stddef.h> /* For size_t. */
/* Sized types. */ /* Sized Types */
typedef signed char drflac_int8; typedef signed char drflac_int8;
typedef unsigned char drflac_uint8; typedef unsigned char drflac_uint8;
typedef signed short drflac_int16; typedef signed short drflac_int16;
@ -273,7 +273,9 @@ typedef drflac_uint8 drflac_bool8;
typedef drflac_uint32 drflac_bool32; typedef drflac_uint32 drflac_bool32;
#define DRFLAC_TRUE 1 #define DRFLAC_TRUE 1
#define DRFLAC_FALSE 0 #define DRFLAC_FALSE 0
/* End Sized Types */
/* Decorations */
#if !defined(DRFLAC_API) #if !defined(DRFLAC_API)
#if defined(DRFLAC_DLL) #if defined(DRFLAC_DLL)
#if defined(_WIN32) #if defined(_WIN32)
@ -303,6 +305,7 @@ typedef drflac_uint32 drflac_bool32;
#define DRFLAC_PRIVATE static #define DRFLAC_PRIVATE static
#endif #endif
#endif #endif
/* End Decorations */
#if defined(_MSC_VER) && _MSC_VER >= 1700 /* Visual Studio 2012 */ #if defined(_MSC_VER) && _MSC_VER >= 1700 /* Visual Studio 2012 */
#define DRFLAC_DEPRECATED __declspec(deprecated) #define DRFLAC_DEPRECATED __declspec(deprecated)
@ -321,6 +324,16 @@ typedef drflac_uint32 drflac_bool32;
DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision); DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision);
DRFLAC_API const char* drflac_version_string(void); DRFLAC_API const char* drflac_version_string(void);
/* Allocation Callbacks */
typedef struct
{
void* pUserData;
void* (* onMalloc)(size_t sz, void* pUserData);
void* (* onRealloc)(void* p, size_t sz, void* pUserData);
void (* onFree)(void* p, void* pUserData);
} drflac_allocation_callbacks;
/* End Allocation Callbacks */
/* /*
As data is read from the client it is placed into an internal buffer for fast access. This controls the size of that buffer. Larger values means more speed, As data is read from the client it is placed into an internal buffer for fast access. This controls the size of that buffer. Larger values means more speed,
but also more memory. In my testing there is diminishing returns after about 4KB, but you can fiddle with this to suit your own needs. Must be a multiple of 8. but also more memory. In my testing there is diminishing returns after about 4KB, but you can fiddle with this to suit your own needs. Must be a multiple of 8.
@ -329,11 +342,22 @@ but also more memory. In my testing there is diminishing returns after about 4KB
#define DR_FLAC_BUFFER_SIZE 4096 #define DR_FLAC_BUFFER_SIZE 4096
#endif #endif
/* Check if we can enable 64-bit optimizations. */
/* Architecture Detection */
#if defined(_WIN64) || defined(_LP64) || defined(__LP64__) #if defined(_WIN64) || defined(_LP64) || defined(__LP64__)
#define DRFLAC_64BIT #define DRFLAC_64BIT
#endif #endif
#if defined(__x86_64__) || defined(_M_X64)
#define DRFLAC_X64
#elif defined(__i386) || defined(_M_IX86)
#define DRFLAC_X86
#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64)
#define DRFLAC_ARM
#endif
/* End Architecture Detection */
#ifdef DRFLAC_64BIT #ifdef DRFLAC_64BIT
typedef drflac_uint64 drflac_cache_t; typedef drflac_uint64 drflac_cache_t;
#else #else
@ -562,14 +586,6 @@ will be set to one of the DRFLAC_METADATA_BLOCK_TYPE_* tokens.
typedef void (* drflac_meta_proc)(void* pUserData, drflac_metadata* pMetadata); typedef void (* drflac_meta_proc)(void* pUserData, drflac_metadata* pMetadata);
typedef struct
{
void* pUserData;
void* (* onMalloc)(size_t sz, void* pUserData);
void* (* onRealloc)(void* p, size_t sz, void* pUserData);
void (* onFree)(void* p, void* pUserData);
} drflac_allocation_callbacks;
/* Structure for internal use. Only used for decoders opened with drflac_open_memory. */ /* Structure for internal use. Only used for decoders opened with drflac_open_memory. */
typedef struct typedef struct
{ {
@ -1351,6 +1367,7 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
/* Inline */
#ifdef _MSC_VER #ifdef _MSC_VER
#define DRFLAC_INLINE __forceinline #define DRFLAC_INLINE __forceinline
#elif defined(__GNUC__) #elif defined(__GNUC__)
@ -1377,15 +1394,7 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
#else #else
#define DRFLAC_INLINE #define DRFLAC_INLINE
#endif #endif
/* End Inline */
/* CPU architecture. */
#if defined(__x86_64__) || defined(_M_X64)
#define DRFLAC_X64
#elif defined(__i386) || defined(_M_IX86)
#define DRFLAC_X86
#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64)
#define DRFLAC_ARM
#endif
/* /*
Intrinsics Support Intrinsics Support
@ -1623,6 +1632,7 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void)
#define DRFLAC_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */ #define DRFLAC_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */
/* Result Codes */
typedef drflac_int32 drflac_result; typedef drflac_int32 drflac_result;
#define DRFLAC_SUCCESS 0 #define DRFLAC_SUCCESS 0
#define DRFLAC_ERROR -1 /* A generic error. */ #define DRFLAC_ERROR -1 /* A generic error. */
@ -1678,7 +1688,10 @@ typedef drflac_int32 drflac_result;
#define DRFLAC_CANCELLED -51 #define DRFLAC_CANCELLED -51
#define DRFLAC_MEMORY_ALREADY_MAPPED -52 #define DRFLAC_MEMORY_ALREADY_MAPPED -52
#define DRFLAC_AT_END -53 #define DRFLAC_AT_END -53
#define DRFLAC_CRC_MISMATCH -128
#define DRFLAC_CRC_MISMATCH -100
/* End Result Codes */
#define DRFLAC_SUBFRAME_CONSTANT 0 #define DRFLAC_SUBFRAME_CONSTANT 0
#define DRFLAC_SUBFRAME_VERBATIM 1 #define DRFLAC_SUBFRAME_VERBATIM 1
@ -1838,7 +1851,7 @@ static DRFLAC_INLINE drflac_uint32 drflac__swap_endian_uint32(drflac_uint32 n)
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER) && !defined(__clang__)
return _byteswap_ulong(n); return _byteswap_ulong(n);
#elif defined(__GNUC__) || defined(__clang__) #elif defined(__GNUC__) || defined(__clang__)
#if defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(DRFLAC_64BIT) /* <-- 64-bit inline assembly has not been tested, so disabling for now. */ #if defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(__ARM_ARCH_6M__) && !defined(DRFLAC_64BIT) /* <-- 64-bit inline assembly has not been tested, so disabling for now. */
/* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */ /* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */
drflac_uint32 r; drflac_uint32 r;
__asm__ __volatile__ ( __asm__ __volatile__ (
@ -2802,7 +2815,7 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x)
return r; return r;
} }
#elif defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !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(DRFLAC_64BIT) /* <-- I haven't tested 64-bit inline assembly, so only enabling this for the 32-bit build for now. */
{ {
unsigned int r; unsigned int r;
__asm__ __volatile__ ( __asm__ __volatile__ (
@ -6479,7 +6492,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
for (;;) { for (;;) {
drflac_metadata metadata; drflac_metadata metadata;
drflac_uint8 isLastBlock = 0; drflac_uint8 isLastBlock = 0;
drflac_uint8 blockType; drflac_uint8 blockType = 0;
drflac_uint32 blockSize; drflac_uint32 blockSize;
if (drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == DRFLAC_FALSE) { if (drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == DRFLAC_FALSE) {
return DRFLAC_FALSE; return DRFLAC_FALSE;
@ -8141,6 +8154,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
#include <wchar.h> /* For wcslen(), wcsrtombs() */ #include <wchar.h> /* For wcslen(), wcsrtombs() */
#endif #endif
/* Errno */
/* drflac_result_from_errno() is only used for fopen() and wfopen() so putting it inside DR_WAV_NO_STDIO for now. If something else needs this later we can move it out. */ /* drflac_result_from_errno() is only used for fopen() and wfopen() so putting it inside DR_WAV_NO_STDIO for now. If something else needs this later we can move it out. */
#include <errno.h> #include <errno.h>
static drflac_result drflac_result_from_errno(int e) static drflac_result drflac_result_from_errno(int e)
@ -8544,7 +8558,9 @@ static drflac_result drflac_result_from_errno(int e)
default: return DRFLAC_ERROR; default: return DRFLAC_ERROR;
} }
} }
/* End Errno */
/* fopen */
static drflac_result drflac_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode) static drflac_result drflac_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
{ {
#if defined(_MSC_VER) && _MSC_VER >= 1400 #if defined(_MSC_VER) && _MSC_VER >= 1400
@ -8702,6 +8718,7 @@ static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, cons
return DRFLAC_SUCCESS; return DRFLAC_SUCCESS;
} }
#endif #endif
/* End fopen */
static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead) static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead)
{ {
@ -11666,6 +11683,7 @@ DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 p
/* High Level APIs */ /* High Level APIs */
/* SIZE_MAX */
#if defined(SIZE_MAX) #if defined(SIZE_MAX)
#define DRFLAC_SIZE_MAX SIZE_MAX #define DRFLAC_SIZE_MAX SIZE_MAX
#else #else
@ -11675,6 +11693,7 @@ DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 p
#define DRFLAC_SIZE_MAX 0xFFFFFFFF #define DRFLAC_SIZE_MAX 0xFFFFFFFF
#endif #endif
#endif #endif
/* End SIZE_MAX */
/* Using a macro as the definition of the drflac__full_decode_and_close_*() API family. Sue me. */ /* Using a macro as the definition of the drflac__full_decode_and_close_*() API family. Sue me. */
@ -12058,6 +12077,16 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
/* /*
REVISION HISTORY REVISION HISTORY
================ ================
v0.12.42 - 2023-11-02
- Fix build for ARMv6-M.
- Fix a compilation warning with GCC.
v0.12.41 - 2023-06-17
- Fix an incorrect date in revision history. No functional change.
v0.12.40 - 2023-05-22
- Minor code restructure. No functional change.
v0.12.39 - 2022-09-17 v0.12.39 - 2022-09-17
- Fix compilation with DJGPP. - Fix compilation with DJGPP.
- Fix compilation error with Visual Studio 2019 and the ARM build. - Fix compilation error with Visual Studio 2019 and the ARM build.
@ -12488,7 +12517,7 @@ For more information, please refer to <http://unlicense.org/>
=============================================================================== ===============================================================================
ALTERNATIVE 2 - MIT No Attribution ALTERNATIVE 2 - MIT No Attribution
=============================================================================== ===============================================================================
Copyright 2020 David Reid Copyright 2023 David Reid
Permission is hereby granted, free of charge, to any person obtaining a copy of Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in this software and associated documentation files (the "Software"), to deal in

View file

@ -1,6 +1,6 @@
/* /*
MP3 audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file. MP3 audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
dr_mp3 - v0.6.34 - 2022-09-17 dr_mp3 - v0.6.38 - 2023-11-02
David Reid - mackron@gmail.com David Reid - mackron@gmail.com
@ -95,12 +95,12 @@ extern "C" {
#define DRMP3_VERSION_MAJOR 0 #define DRMP3_VERSION_MAJOR 0
#define DRMP3_VERSION_MINOR 6 #define DRMP3_VERSION_MINOR 6
#define DRMP3_VERSION_REVISION 34 #define DRMP3_VERSION_REVISION 38
#define DRMP3_VERSION_STRING DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION) #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. */ #include <stddef.h> /* For size_t. */
/* Sized types. */ /* Sized Types */
typedef signed char drmp3_int8; typedef signed char drmp3_int8;
typedef unsigned char drmp3_uint8; typedef unsigned char drmp3_uint8;
typedef signed short drmp3_int16; typedef signed short drmp3_int16;
@ -133,7 +133,9 @@ typedef drmp3_uint8 drmp3_bool8;
typedef drmp3_uint32 drmp3_bool32; typedef drmp3_uint32 drmp3_bool32;
#define DRMP3_TRUE 1 #define DRMP3_TRUE 1
#define DRMP3_FALSE 0 #define DRMP3_FALSE 0
/* End Sized Types */
/* Decorations */
#if !defined(DRMP3_API) #if !defined(DRMP3_API)
#if defined(DRMP3_DLL) #if defined(DRMP3_DLL)
#if defined(_WIN32) #if defined(_WIN32)
@ -163,7 +165,9 @@ typedef drmp3_uint32 drmp3_bool32;
#define DRMP3_PRIVATE static #define DRMP3_PRIVATE static
#endif #endif
#endif #endif
/* End Decorations */
/* Result Codes */
typedef drmp3_int32 drmp3_result; typedef drmp3_int32 drmp3_result;
#define DRMP3_SUCCESS 0 #define DRMP3_SUCCESS 0
#define DRMP3_ERROR -1 /* A generic error. */ #define DRMP3_ERROR -1 /* A generic error. */
@ -219,11 +223,12 @@ typedef drmp3_int32 drmp3_result;
#define DRMP3_CANCELLED -51 #define DRMP3_CANCELLED -51
#define DRMP3_MEMORY_ALREADY_MAPPED -52 #define DRMP3_MEMORY_ALREADY_MAPPED -52
#define DRMP3_AT_END -53 #define DRMP3_AT_END -53
/* End Result Codes */
#define DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME 1152 #define DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME 1152
#define DRMP3_MAX_SAMPLES_PER_FRAME (DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME*2) #define DRMP3_MAX_SAMPLES_PER_FRAME (DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME*2)
/* Inline */
#ifdef _MSC_VER #ifdef _MSC_VER
#define DRMP3_INLINE __forceinline #define DRMP3_INLINE __forceinline
#elif defined(__GNUC__) #elif defined(__GNUC__)
@ -250,12 +255,24 @@ typedef drmp3_int32 drmp3_result;
#else #else
#define DRMP3_INLINE #define DRMP3_INLINE
#endif #endif
/* End Inline */
DRMP3_API void drmp3_version(drmp3_uint32* pMajor, drmp3_uint32* pMinor, drmp3_uint32* pRevision); DRMP3_API void drmp3_version(drmp3_uint32* pMajor, drmp3_uint32* pMinor, drmp3_uint32* pRevision);
DRMP3_API const char* drmp3_version_string(void); DRMP3_API const char* drmp3_version_string(void);
/* Allocation Callbacks */
typedef struct
{
void* pUserData;
void* (* onMalloc)(size_t sz, void* pUserData);
void* (* onRealloc)(void* p, size_t sz, void* pUserData);
void (* onFree)(void* p, void* pUserData);
} drmp3_allocation_callbacks;
/* End Allocation Callbacks */
/* /*
Low Level Push API Low Level Push API
================== ==================
@ -329,14 +346,6 @@ will be either drmp3_seek_origin_start or drmp3_seek_origin_current.
*/ */
typedef drmp3_bool32 (* drmp3_seek_proc)(void* pUserData, int offset, drmp3_seek_origin origin); typedef drmp3_bool32 (* drmp3_seek_proc)(void* pUserData, int offset, drmp3_seek_origin origin);
typedef struct
{
void* pUserData;
void* (* onMalloc)(size_t sz, void* pUserData);
void* (* onRealloc)(void* p, size_t sz, void* pUserData);
void (* onFree)(void* p, void* pUserData);
} drmp3_allocation_callbacks;
typedef struct typedef struct
{ {
drmp3_uint32 channels; drmp3_uint32 channels;
@ -704,7 +713,7 @@ static int drmp3_have_simd(void)
#endif #endif
#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) #if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) && !defined(__ARM_ARCH_6M__)
#define DRMP3_HAVE_ARMV6 1 #define DRMP3_HAVE_ARMV6 1
static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_arm(drmp3_int32 a) static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_arm(drmp3_int32 a)
{ {
@ -2415,6 +2424,7 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num
Main Public API Main Public API
************************************************************************************************************************************************************/ ************************************************************************************************************************************************************/
/* SIZE_MAX */
#if defined(SIZE_MAX) #if defined(SIZE_MAX)
#define DRMP3_SIZE_MAX SIZE_MAX #define DRMP3_SIZE_MAX SIZE_MAX
#else #else
@ -2424,6 +2434,7 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num
#define DRMP3_SIZE_MAX 0xFFFFFFFF #define DRMP3_SIZE_MAX 0xFFFFFFFF
#endif #endif
#endif #endif
/* End SIZE_MAX */
/* Options. */ /* Options. */
#ifndef DRMP3_SEEK_LEADING_MP3_FRAMES #ifndef DRMP3_SEEK_LEADING_MP3_FRAMES
@ -2690,6 +2701,11 @@ static drmp3_uint32 drmp3_decode_next_frame_ex__callbacks(drmp3* pMP3, drmp3d_sa
DRMP3_ASSERT(pMP3->pData != NULL); DRMP3_ASSERT(pMP3->pData != NULL);
DRMP3_ASSERT(pMP3->dataCapacity > 0); DRMP3_ASSERT(pMP3->dataCapacity > 0);
/* Do a runtime check here to try silencing a false-positive from clang-analyzer. */
if (pMP3->pData == NULL) {
return 0;
}
pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->pData + pMP3->dataConsumed, (int)pMP3->dataSize, pPCMFrames, &info); /* <-- Safe size_t -> int conversion thanks to the check above. */ pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->pData + pMP3->dataConsumed, (int)pMP3->dataSize, pPCMFrames, &info); /* <-- Safe size_t -> int conversion thanks to the check above. */
/* Consume the data. */ /* Consume the data. */
@ -2931,6 +2947,7 @@ DRMP3_API drmp3_bool32 drmp3_init_memory(drmp3* pMP3, const void* pData, size_t
#include <stdio.h> #include <stdio.h>
#include <wchar.h> /* For wcslen(), wcsrtombs() */ #include <wchar.h> /* For wcslen(), wcsrtombs() */
/* Errno */
/* drmp3_result_from_errno() is only used inside DR_MP3_NO_STDIO for now. Move this out if it's ever used elsewhere. */ /* drmp3_result_from_errno() is only used inside DR_MP3_NO_STDIO for now. Move this out if it's ever used elsewhere. */
#include <errno.h> #include <errno.h>
static drmp3_result drmp3_result_from_errno(int e) static drmp3_result drmp3_result_from_errno(int e)
@ -3334,7 +3351,9 @@ static drmp3_result drmp3_result_from_errno(int e)
default: return DRMP3_ERROR; default: return DRMP3_ERROR;
} }
} }
/* End Errno */
/* fopen */
static drmp3_result drmp3_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode) static drmp3_result drmp3_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
{ {
#if defined(_MSC_VER) && _MSC_VER >= 1400 #if defined(_MSC_VER) && _MSC_VER >= 1400
@ -3490,7 +3509,7 @@ static drmp3_result drmp3_wfopen(FILE** ppFile, const wchar_t* pFilePath, const
return DRMP3_SUCCESS; return DRMP3_SUCCESS;
} }
/* End fopen */
static size_t drmp3__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead) static size_t drmp3__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead)
@ -4476,6 +4495,18 @@ counts rather than sample counts.
/* /*
REVISION HISTORY REVISION HISTORY
================ ================
v0.6.38 - 2023-11-02
- Fix build for ARMv6-M.
v0.6.37 - 2023-07-07
- Silence a static analysis warning.
v0.6.36 - 2023-06-17
- Fix an incorrect date in revision history. No functional change.
v0.6.35 - 2023-05-22
- Minor code restructure. No functional change.
v0.6.34 - 2022-09-17 v0.6.34 - 2022-09-17
- Fix compilation with DJGPP. - Fix compilation with DJGPP.
- Fix compilation when compiling with x86 with no SSE2. - Fix compilation when compiling with x86 with no SSE2.
@ -4777,7 +4808,7 @@ For more information, please refer to <http://unlicense.org/>
=============================================================================== ===============================================================================
ALTERNATIVE 2 - MIT No Attribution ALTERNATIVE 2 - MIT No Attribution
=============================================================================== ===============================================================================
Copyright 2020 David Reid Copyright 2023 David Reid
Permission is hereby granted, free of charge, to any person obtaining a copy of Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in this software and associated documentation files (the "Software"), to deal in

1311
raylib/external/dr_wav.h vendored

File diff suppressed because it is too large Load diff

40
raylib/external/m3d.h vendored
View file

@ -89,7 +89,7 @@ typedef uint8_t M3D_VOXEL;
#define M3D_NUMBONE 4 #define M3D_NUMBONE 4
#endif #endif
#ifndef M3D_BONEMAXLEVEL #ifndef M3D_BONEMAXLEVEL
#define M3D_BONEMAXLEVEL 8 #define M3D_BONEMAXLEVEL 64
#endif #endif
#ifndef _MSC_VER #ifndef _MSC_VER
#ifndef _inline #ifndef _inline
@ -2172,6 +2172,8 @@ M3D_INDEX _m3d_gettx(m3d_t *model, m3dread_t readfilecb, m3dfree_t freecb, char
stbi__context s; stbi__context s;
stbi__result_info ri; stbi__result_info ri;
/* failsafe */
if(!fn || !*fn) return M3D_UNDEF;
/* do we have loaded this texture already? */ /* do we have loaded this texture already? */
for(i = 0; i < model->numtexture; i++) for(i = 0; i < model->numtexture; i++)
if(!strcmp(fn, model->texture[i].name)) return i; if(!strcmp(fn, model->texture[i].name)) return i;
@ -2246,9 +2248,9 @@ void _m3d_getpr(m3d_t *model, _unused m3dread_t readfilecb, _unused m3dfree_t f
{ {
#ifdef M3D_PR_INTERP #ifdef M3D_PR_INTERP
unsigned int i, len = 0; unsigned int i, len = 0;
unsigned char *buff = readfilecb ? (*readfilecb)(fn, &len) : NULL; unsigned char *buff = readfilecb && fn && *fn ? (*readfilecb)(fn, &len) : NULL;
if(!buff && model->inlined) { if(!buff && fn && *fn && model->inlined) {
for(i = 0; i < model->numinlined; i++) for(i = 0; i < model->numinlined; i++)
if(!strcmp(fn, model->inlined[i].name)) { if(!strcmp(fn, model->inlined[i].name)) {
buff = model->inlined[i].data; buff = model->inlined[i].data;
@ -3439,6 +3441,7 @@ memerr: M3D_LOG("Out of memory");
model->bone[i].numweight = 0; model->bone[i].numweight = 0;
model->bone[i].weight = NULL; model->bone[i].weight = NULL;
} }
if(i != model->numbone) { M3D_LOG("Truncated bone chunk"); model->numbone = i; model->numskin = 0; model->errcode = M3D_ERR_BONE; }
/* read skin definitions */ /* read skin definitions */
if(model->numskin) { if(model->numskin) {
model->skin = (m3ds_t*)M3D_MALLOC(model->numskin * sizeof(m3ds_t)); model->skin = (m3ds_t*)M3D_MALLOC(model->numskin * sizeof(m3ds_t));
@ -3471,6 +3474,7 @@ memerr: M3D_LOG("Out of memory");
model->skin[i].weight[j] /= w; model->skin[i].weight[j] /= w;
} }
} }
if(i != model->numskin) { M3D_LOG("Truncated skin in bone chunk"); model->numskin = i; model->errcode = M3D_ERR_BONE; }
} }
} else } else
/* material */ /* material */
@ -4726,14 +4730,14 @@ unsigned char *m3d_save(m3d_t *model, int quality, int flags, unsigned int *size
unsigned char *out = NULL, *z = NULL, weights[M3D_NUMBONE < 8 ? 8 : M3D_NUMBONE], *norm = NULL; unsigned char *out = NULL, *z = NULL, weights[M3D_NUMBONE < 8 ? 8 : M3D_NUMBONE], *norm = NULL;
unsigned int i, j, k, l, n, o, len, chunklen, *length; unsigned int i, j, k, l, n, o, len, chunklen, *length;
int maxvox = 0, minvox = 0; int maxvox = 0, minvox = 0;
M3D_FLOAT scale = (M3D_FLOAT)0.0, min_x, max_x, min_y, max_y, min_z, max_z; M3D_FLOAT scale = (M3D_FLOAT)0.0, min_x, max_x, min_y, max_y, min_z, max_z, mw;
M3D_INDEX last, *vrtxidx = NULL, *mtrlidx = NULL, *tmapidx = NULL, *skinidx = NULL; M3D_INDEX last, *vrtxidx = NULL, *mtrlidx = NULL, *tmapidx = NULL, *skinidx = NULL;
#ifdef M3D_VERTEXMAX #ifdef M3D_VERTEXMAX
M3D_INDEX lastp; M3D_INDEX lastp;
#endif #endif
uint32_t idx, numcmap = 0, *cmap = NULL, numvrtx = 0, maxvrtx = 0, numtmap = 0, maxtmap = 0, numproc = 0; uint32_t idx, numcmap = 0, *cmap = NULL, numvrtx = 0, maxvrtx = 0, numtmap = 0, maxtmap = 0, numproc = 0;
uint32_t numskin = 0, maxskin = 0, numstr = 0, maxt = 0, maxbone = 0, numgrp = 0, maxgrp = 0, *grpidx = NULL; uint32_t numskin = 0, maxskin = 0, numstr = 0, maxt = 0, maxbone = 0, numgrp = 0, maxgrp = 0, *grpidx = NULL;
uint8_t *opa; uint8_t *opa = NULL;
m3dcd_t *cd; m3dcd_t *cd;
m3dc_t *cmd; m3dc_t *cmd;
m3dstr_t *str = NULL; m3dstr_t *str = NULL;
@ -5072,10 +5076,9 @@ unsigned char *m3d_save(m3d_t *model, int quality, int flags, unsigned int *size
for(i = 0; i < model->numskin; i++) { for(i = 0; i < model->numskin; i++) {
if(skinidx[i] == M3D_UNDEF) continue; if(skinidx[i] == M3D_UNDEF) continue;
memset(&sk, 0, sizeof(m3dssave_t)); memset(&sk, 0, sizeof(m3dssave_t));
for(j = 0, min_x = (M3D_FLOAT)0.0; j < M3D_NUMBONE && model->skin[i].boneid[j] != M3D_UNDEF && for(j = 0, min_x = (M3D_FLOAT)0.0; j < M3D_NUMBONE && model->skin[i].boneid[j] != M3D_UNDEF; j++) {
model->skin[i].weight[j] > (M3D_FLOAT)0.0; j++) {
sk.data.boneid[j] = model->skin[i].boneid[j]; sk.data.boneid[j] = model->skin[i].boneid[j];
sk.data.weight[j] = model->skin[i].weight[j]; sk.data.weight[j] = model->skin[i].weight[j] > (M3D_FLOAT)0.0 ? model->skin[i].weight[j] : (M3D_FLOAT)0.01;
min_x += sk.data.weight[j]; min_x += sk.data.weight[j];
} }
if(j > maxbone) maxbone = j; if(j > maxbone) maxbone = j;
@ -5191,6 +5194,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx);
if(sa) M3D_FREE(sa); if(sa) M3D_FREE(sa);
if(sd) M3D_FREE(sd); if(sd) M3D_FREE(sd);
if(out) M3D_FREE(out); if(out) M3D_FREE(out);
if(opa) free(opa);
if(h) M3D_FREE(h); if(h) M3D_FREE(h);
M3D_LOG("Out of memory"); M3D_LOG("Out of memory");
model->errcode = M3D_ERR_ALLOC; model->errcode = M3D_ERR_ALLOC;
@ -5218,8 +5222,16 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx);
if(model->preview.data && model->preview.length) { if(model->preview.data && model->preview.length) {
sl = _m3d_safestr(sn, 0); sl = _m3d_safestr(sn, 0);
if(sl) { if(sl) {
/* gcc thinks that "ptr is used after free", well, gcc is simply wrong. */
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuse-after-free"
#endif
ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)20 + strlen(sl)); ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)20 + strlen(sl));
out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out;
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; }
ptr += sprintf(ptr, "Preview\r\n%s.png\r\n\r\n", sl); ptr += sprintf(ptr, "Preview\r\n%s.png\r\n\r\n", sl);
M3D_FREE(sl); sl = NULL; M3D_FREE(sl); sl = NULL;
@ -5228,6 +5240,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx);
M3D_FREE(sn); sn = NULL; M3D_FREE(sn); sn = NULL;
/* texture map */ /* texture map */
if(numtmap && tmap && !(flags & M3D_EXP_NOTXTCRD) && !(flags & M3D_EXP_NOFACE)) { if(numtmap && tmap && !(flags & M3D_EXP_NOTXTCRD) && !(flags & M3D_EXP_NOFACE)) {
/* interestingly gcc does not complain about "ptr is used after free" here, although the code is 100% the same */
ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)(maxtmap * 32) + (uintptr_t)12); ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)(maxtmap * 32) + (uintptr_t)12);
out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out;
if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; }
@ -5846,9 +5859,13 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx);
if(skin[i].newidx == last) continue; if(skin[i].newidx == last) continue;
last = skin[i].newidx; last = skin[i].newidx;
memset(&weights, 0, nb_s); memset(&weights, 0, nb_s);
for(j = 0; j < (uint32_t)nb_s && skin[i].data.boneid[j] != M3D_UNDEF && for(j = k = l = 0, mw = 0.0; j < (uint32_t)nb_s && skin[i].data.boneid[j] != M3D_UNDEF &&
skin[i].data.weight[j] > (M3D_FLOAT)0.0; j++) skin[i].data.weight[j] > (M3D_FLOAT)0.0; j++) {
if(mw < skin[i].data.weight[j]) { mw = skin[i].data.weight[j]; k = j; }
weights[j] = (uint8_t)(skin[i].data.weight[j] * 255); weights[j] = (uint8_t)(skin[i].data.weight[j] * 255);
if(!weights[j]) { weights[j]++; l--; }
}
weights[k] += l;
switch(nb_s) { switch(nb_s) {
case 1: weights[0] = 255; break; case 1: weights[0] = 255; break;
case 2: memcpy(out, weights, 2); out += 2; break; case 2: memcpy(out, weights, 2); out += 2; break;
@ -5941,7 +5958,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx);
} }
/* mesh face */ /* mesh face */
if(model->numface && face && !(flags & M3D_EXP_NOFACE)) { if(model->numface && face && !(flags & M3D_EXP_NOFACE)) {
chunklen = 8 + si_s + model->numface * (6 * vi_s + 3 * ti_s + si_s + 1); chunklen = 8 + si_s + model->numface * (9 * vi_s + 3 * ti_s + si_s + 1);
h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen);
if(!h) goto memerr; if(!h) goto memerr;
memcpy((uint8_t*)h + len, "MESH", 4); memcpy((uint8_t*)h + len, "MESH", 4);
@ -6268,6 +6285,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx);
if(skin) M3D_FREE(skin); if(skin) M3D_FREE(skin);
if(str) M3D_FREE(str); if(str) M3D_FREE(str);
if(vrtx) M3D_FREE(vrtx); if(vrtx) M3D_FREE(vrtx);
if(opa) free(opa);
if(h) M3D_FREE(h); if(h) M3D_FREE(h);
return out; return out;
} }

View file

@ -1,6 +1,6 @@
/* /*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.11.19 - TBD miniaudio - v0.11.19 - 2023-11-04
David Reid - mackron@gmail.com David Reid - mackron@gmail.com
@ -7042,7 +7042,7 @@ struct ma_device_config
ma_uint32 periods; ma_uint32 periods;
ma_performance_profile performanceProfile; ma_performance_profile performanceProfile;
ma_bool8 noPreSilencedOutputBuffer; /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to silence. */ ma_bool8 noPreSilencedOutputBuffer; /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to silence. */
ma_bool8 noClip; /* When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. Only applies when the playback sample format is f32. */ ma_bool8 noClip; /* When set to true, the contents of the output buffer passed into the data callback will not be clipped after returning. Only applies when the playback sample format is f32. */
ma_bool8 noDisableDenormals; /* Do not disable denormals when firing the data callback. */ ma_bool8 noDisableDenormals; /* Do not disable denormals when firing the data callback. */
ma_bool8 noFixedSizedCallback; /* Disables strict fixed-sized data callbacks. Setting this to true will result in the period size being treated only as a hint to the backend. This is an optimization for those who don't need fixed sized callbacks. */ ma_bool8 noFixedSizedCallback; /* Disables strict fixed-sized data callbacks. Setting this to true will result in the period size being treated only as a hint to the backend. This is an optimization for those who don't need fixed sized callbacks. */
ma_device_data_proc dataCallback; ma_device_data_proc dataCallback;
@ -8626,8 +8626,8 @@ then be set directly on the structure. Below are the members of the `ma_device_c
callback will write to every sample in the output buffer, or if you are doing your own clearing. callback will write to every sample in the output buffer, or if you are doing your own clearing.
noClip noClip
When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. When set to false (default), the When set to true, the contents of the output buffer are left alone after returning and it will be left up to the backend itself to decide whether or
contents of the output buffer are left alone after returning and it will be left up to the backend itself to decide whether or not the clip. This only not to clip. When set to false (default), the contents of the output buffer passed into the data callback will be clipped after returning. This only
applies when the playback sample format is f32. applies when the playback sample format is f32.
noDisableDenormals noDisableDenormals
@ -40464,7 +40464,7 @@ static ma_result ma_context_init__webaudio(ma_context* pContext, const ma_contex
}; };
miniaudio.unlock_event_types = (function(){ miniaudio.unlock_event_types = (function(){
return ['touchstart', 'touchend', 'click']; return ['touchend', 'click'];
})(); })();
miniaudio.unlock = function() { miniaudio.unlock = function() {
@ -60158,7 +60158,7 @@ extern "C" {
#define MA_DR_FLAC_XSTRINGIFY(x) MA_DR_FLAC_STRINGIFY(x) #define MA_DR_FLAC_XSTRINGIFY(x) MA_DR_FLAC_STRINGIFY(x)
#define MA_DR_FLAC_VERSION_MAJOR 0 #define MA_DR_FLAC_VERSION_MAJOR 0
#define MA_DR_FLAC_VERSION_MINOR 12 #define MA_DR_FLAC_VERSION_MINOR 12
#define MA_DR_FLAC_VERSION_REVISION 41 #define MA_DR_FLAC_VERSION_REVISION 42
#define MA_DR_FLAC_VERSION_STRING MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_MAJOR) "." MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_MINOR) "." MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_REVISION) #define MA_DR_FLAC_VERSION_STRING MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_MAJOR) "." MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_MINOR) "." MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_REVISION)
#include <stddef.h> #include <stddef.h>
#if defined(_MSC_VER) && _MSC_VER >= 1700 #if defined(_MSC_VER) && _MSC_VER >= 1700
@ -60445,7 +60445,7 @@ extern "C" {
#define MA_DR_MP3_XSTRINGIFY(x) MA_DR_MP3_STRINGIFY(x) #define MA_DR_MP3_XSTRINGIFY(x) MA_DR_MP3_STRINGIFY(x)
#define MA_DR_MP3_VERSION_MAJOR 0 #define MA_DR_MP3_VERSION_MAJOR 0
#define MA_DR_MP3_VERSION_MINOR 6 #define MA_DR_MP3_VERSION_MINOR 6
#define MA_DR_MP3_VERSION_REVISION 37 #define MA_DR_MP3_VERSION_REVISION 38
#define MA_DR_MP3_VERSION_STRING MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_MAJOR) "." MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_MINOR) "." MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_REVISION) #define MA_DR_MP3_VERSION_STRING MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_MAJOR) "." MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_MINOR) "." MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_REVISION)
#include <stddef.h> #include <stddef.h>
#define MA_DR_MP3_MAX_PCM_FRAMES_PER_MP3_FRAME 1152 #define MA_DR_MP3_MAX_PCM_FRAMES_PER_MP3_FRAME 1152
@ -82387,7 +82387,7 @@ static MA_INLINE ma_uint32 ma_dr_flac__swap_endian_uint32(ma_uint32 n)
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER) && !defined(__clang__)
return _byteswap_ulong(n); return _byteswap_ulong(n);
#elif defined(__GNUC__) || defined(__clang__) #elif defined(__GNUC__) || defined(__clang__)
#if defined(MA_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(MA_64BIT) #if defined(MA_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(__ARM_ARCH_6M__) && !defined(MA_64BIT)
ma_uint32 r; ma_uint32 r;
__asm__ __volatile__ ( __asm__ __volatile__ (
#if defined(MA_64BIT) #if defined(MA_64BIT)
@ -83128,7 +83128,7 @@ static MA_INLINE ma_uint32 ma_dr_flac__clz_lzcnt(ma_dr_flac_cache_t x)
); );
return r; return r;
} }
#elif defined(MA_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(MA_64BIT) #elif defined(MA_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(__ARM_ARCH_6M__) && !defined(MA_64BIT)
{ {
unsigned int r; unsigned int r;
__asm__ __volatile__ ( __asm__ __volatile__ (
@ -85869,7 +85869,7 @@ static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRea
for (;;) { for (;;) {
ma_dr_flac_metadata metadata; ma_dr_flac_metadata metadata;
ma_uint8 isLastBlock = 0; ma_uint8 isLastBlock = 0;
ma_uint8 blockType; ma_uint8 blockType = 0;
ma_uint32 blockSize; ma_uint32 blockSize;
if (ma_dr_flac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == MA_FALSE) { if (ma_dr_flac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == MA_FALSE) {
return MA_FALSE; return MA_FALSE;
@ -89949,7 +89949,7 @@ static int ma_dr_mp3_have_simd(void)
#else #else
#define MA_DR_MP3_HAVE_SIMD 0 #define MA_DR_MP3_HAVE_SIMD 0
#endif #endif
#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) #if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) && !defined(__ARM_ARCH_6M__)
#define MA_DR_MP3_HAVE_ARMV6 1 #define MA_DR_MP3_HAVE_ARMV6 1
static __inline__ __attribute__((always_inline)) ma_int32 ma_dr_mp3_clip_int16_arm(ma_int32 a) static __inline__ __attribute__((always_inline)) ma_int32 ma_dr_mp3_clip_int16_arm(ma_int32 a)
{ {

170
raylib/external/qoa.h vendored
View file

@ -8,71 +8,96 @@ QOA - The "Quite OK Audio" format for fast, lossy audio compression
-- Data Format -- Data Format
A QOA file has an 8 byte file header, followed by a number of frames. Each frame QOA encodes pulse-code modulated (PCM) audio data with up to 255 channels,
consists of an 8 byte frame header, the current 8 byte en-/decoder state per sample rates from 1 up to 16777215 hertz and a bit depth of 16 bits.
channel and 256 slices per channel. Each slice is 8 bytes wide and encodes 20
samples of audio data.
Note that the last frame of a file may contain less than 256 slices per channel. The compression method employed in QOA is lossy; it discards some information
The last slice (per channel) in the last frame may contain less 20 samples, but from the uncompressed PCM data. For many types of audio signals this compression
the slice will still be 8 bytes wide, with the unused samples zeroed out. is "transparent", i.e. the difference from the original file is often not
audible.
The samplerate and number of channels is only stated in the frame headers, but QOA encodes 20 samples of 16 bit PCM data into slices of 64 bits. A single
not in the file header. A decoder may peek into the first frame of the file to sample therefore requires 3.2 bits of storage space, resulting in a 5x
find these values. compression (16 / 3.2).
In a valid QOA file all frames have the same number of channels and the same A QOA file consists of an 8 byte file header, followed by a number of frames.
samplerate. These restrictions may be relaxed for streaming. This remains to Each frame contains an 8 byte frame header, the current 16 byte en-/decoder
be decided. state per channel and 256 slices per channel. Each slice is 8 bytes wide and
encodes 20 samples of audio data.
All values in a QOA file are BIG ENDIAN. Luckily, EVERYTHING in a QOA file, All values, including the slices, are big endian. The file layout is as follows:
including the headers, is 64 bit aligned, so it's possible to read files with
just a read_u64() that does the byte swapping if necessary.
In pseudocode, the file layout is as follows:
struct { struct {
struct { struct {
char magic[4]; // magic bytes 'qoaf' char magic[4]; // magic bytes "qoaf"
uint32_t samples; // number of samples per channel in this file uint32_t samples; // samples per channel in this file
} file_header; // = 64 bits } file_header;
struct { struct {
struct { struct {
uint8_t num_channels; // number of channels uint8_t num_channels; // no. of channels
uint24_t samplerate; // samplerate in hz uint24_t samplerate; // samplerate in hz
uint16_t fsamples; // sample count per channel in this frame uint16_t fsamples; // samples per channel in this frame
uint16_t fsize; // frame size (including the frame header) uint16_t fsize; // frame size (includes this header)
} frame_header; // = 64 bits } frame_header;
struct { struct {
int16_t history[4]; // = 64 bits int16_t history[4]; // most recent last
int16_t weights[4]; // = 64 bits int16_t weights[4]; // most recent last
} lms_state[num_channels]; } lms_state[num_channels];
qoa_slice_t slices[256][num_channels]; // = 64 bits each qoa_slice_t slices[256][num_channels];
} frames[samples * channels / qoa_max_framesize()];
} qoa_file;
Wheras the 64bit qoa_slice_t is defined as follows: } frames[ceil(samples / (256 * 20))];
} qoa_file_t;
Each `qoa_slice_t` contains a quantized scalefactor `sf_quant` and 20 quantized
residuals `qrNN`:
.- QOA_SLICE -- 64 bits, 20 samples --------------------------/ /------------. .- QOA_SLICE -- 64 bits, 20 samples --------------------------/ /------------.
| Byte[0] | Byte[1] | Byte[2] \ \ Byte[7] | | Byte[0] | Byte[1] | Byte[2] \ \ Byte[7] |
| 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | 7 6 5 / / 2 1 0 | | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | 7 6 5 / / 2 1 0 |
|------------+--------+--------+--------+---------+---------+-\ \--+---------| |------------+--------+--------+--------+---------+---------+-\ \--+---------|
| sf_index | r00 | r01 | r02 | r03 | r04 | / / | r19 | | sf_quant | qr00 | qr01 | qr02 | qr03 | qr04 | / / | qr19 |
`-------------------------------------------------------------\ \------------` `-------------------------------------------------------------\ \------------`
`sf_index` defines the scalefactor to use for this slice as an index into the Each frame except the last must contain exactly 256 slices per channel. The last
qoa_scalefactor_tab[16] 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.
`r00`--`r19` are the residuals for the individual samples, divided by the Channels are interleaved per slice. E.g. for 2 channel stereo:
scalefactor and quantized by the qoa_quant_tab[]. slice[0] = L, slice[1] = R, slice[2] = L, slice[3] = R ...
In the decoder, a prediction of the next sample is computed by multiplying the A valid QOA file or stream must have at least one frame. Each frame must contain
state (the last four output samples) with the predictor. The residual from the at least one channel and one sample with a samplerate between 1 .. 16777215
slice is then dequantized using the qoa_dequant_tab[] and added to the (inclusive).
prediction. The result is clamped to int16 to form the final output sample.
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
"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
samplerate.
Note that this implementation of QOA only handles files with a known total
number of samples.
A decoder should support at least 8 channels. The channel layout for channel
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
6. FL, FR, C, LFE, B/SL, B/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
dequantized residual forms the final output sample.
*/ */
@ -158,7 +183,7 @@ 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 value. This is mostly fine, since the qoa_div() function always rounds away
from zero. */ from zero. */
static int qoa_quant_tab[17] = { static const int qoa_quant_tab[17] = {
7, 7, 7, 5, 5, 3, 3, 1, /* -8..-1 */ 7, 7, 7, 5, 5, 3, 3, 1, /* -8..-1 */
0, /* 0 */ 0, /* 0 */
0, 2, 2, 4, 4, 6, 6, 6 /* 1.. 8 */ 0, 2, 2, 4, 4, 6, 6, 6 /* 1.. 8 */
@ -169,13 +194,13 @@ static int qoa_quant_tab[17] = {
less accurate at the higher end. In theory, the highest scalefactor that we 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 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 rely on the LMS filter to predict samples accurately enough that a maximum
residual of one quarter of the 16 bit range is high sufficient. I.e. with the 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. scalefactor 2048 times the quant range of 8 we can encode residuals up to 2**14.
The scalefactor values are computed as: The scalefactor values are computed as:
scalefactor_tab[s] <- round(pow(s + 1, 2.75)) */ scalefactor_tab[s] <- round(pow(s + 1, 2.75)) */
static int qoa_scalefactor_tab[16] = { static const int qoa_scalefactor_tab[16] = {
1, 7, 21, 45, 84, 138, 211, 304, 421, 562, 731, 928, 1157, 1419, 1715, 2048 1, 7, 21, 45, 84, 138, 211, 304, 421, 562, 731, 928, 1157, 1419, 1715, 2048
}; };
@ -188,7 +213,7 @@ do this in .16 fixed point with integers, instead of floats.
The reciprocal_tab is computed as: The reciprocal_tab is computed as:
reciprocal_tab[s] <- ((1<<16) + scalefactor_tab[s] - 1) / scalefactor_tab[s] */ reciprocal_tab[s] <- ((1<<16) + scalefactor_tab[s] - 1) / scalefactor_tab[s] */
static int qoa_reciprocal_tab[16] = { static const int qoa_reciprocal_tab[16] = {
65536, 9363, 3121, 1457, 781, 475, 311, 216, 156, 117, 90, 71, 57, 47, 39, 32 65536, 9363, 3121, 1457, 781, 475, 311, 216, 156, 117, 90, 71, 57, 47, 39, 32
}; };
@ -200,9 +225,13 @@ 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: 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}; float dqt[8] = {0.75, -0.75, 2.5, -2.5, 4.5, -4.5, 7, -7};
dequant_tab[s][q] <- round(scalefactor_tab[s] * dqt[q]) */ dequant_tab[s][q] <- round_ties_away_from_zero(scalefactor_tab[s] * dqt[q])
static int qoa_dequant_tab[16][8] = { The rounding employed here is "to nearest, ties away from zero", i.e. positive
and negative values are treated symmetrically.
*/
static const int qoa_dequant_tab[16][8] = {
{ 1, -1, 3, -3, 5, -5, 7, -7}, { 1, -1, 3, -3, 5, -5, 7, -7},
{ 5, -5, 18, -18, 32, -32, 49, -49}, { 5, -5, 18, -18, 32, -32, 49, -49},
{ 16, -16, 53, -53, 95, -95, 147, -147}, { 16, -16, 53, -53, 95, -95, 147, -147},
@ -270,7 +299,21 @@ static inline int qoa_div(int v, int scalefactor) {
} }
static inline int qoa_clamp(int v, int min, int max) { static inline int qoa_clamp(int v, int min, int max) {
return (v < min) ? min : (v > max) ? max : v; if (v < min) { return min; }
if (v > max) { return max; }
return v;
}
/* This specialized clamp function for the signed 16 bit range improves decode
performance quite a bit. The extra if() statement works nicely with the CPUs
branch prediction as this branch is rarely taken. */
static inline int qoa_clamp_s16(int v) {
if ((unsigned int)(v + 32768) > 65535) {
if (v < -32768) { return -32768; }
if (v > 32767) { return 32767; }
}
return v;
} }
static inline qoa_uint64_t qoa_read_u64(const unsigned char *bytes, unsigned int *p) { static inline qoa_uint64_t qoa_read_u64(const unsigned char *bytes, unsigned int *p) {
@ -312,6 +355,7 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned
unsigned int p = 0; unsigned int p = 0;
unsigned int slices = (frame_len + QOA_SLICE_LEN - 1) / QOA_SLICE_LEN; unsigned int slices = (frame_len + QOA_SLICE_LEN - 1) / QOA_SLICE_LEN;
unsigned int frame_size = QOA_FRAME_SIZE(channels, slices); unsigned int frame_size = QOA_FRAME_SIZE(channels, slices);
int prev_scalefactor[QOA_MAX_CHANNELS] = {0};
/* Write the frame header */ /* Write the frame header */
qoa_write_u64(( qoa_write_u64((
@ -321,8 +365,24 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned
(qoa_uint64_t)frame_size (qoa_uint64_t)frame_size
), bytes, &p); ), bytes, &p);
/* Write the current LMS state */
for (int c = 0; c < channels; c++) { for (int c = 0; c < channels; c++) {
/* If the weights have grown too large, reset them to 0. This may happen
with certain high-frequency sounds. This is a last resort and will
introduce quite a bit of noise, but should at least prevent pops/clicks */
int weights_sum =
qoa->lms[c].weights[0] * qoa->lms[c].weights[0] +
qoa->lms[c].weights[1] * qoa->lms[c].weights[1] +
qoa->lms[c].weights[2] * qoa->lms[c].weights[2] +
qoa->lms[c].weights[3] * qoa->lms[c].weights[3];
if (weights_sum > 0x2fffffff) {
qoa->lms[c].weights[0] = 0;
qoa->lms[c].weights[1] = 0;
qoa->lms[c].weights[2] = 0;
qoa->lms[c].weights[3] = 0;
}
/* Write the current LMS state */
qoa_uint64_t weights = 0; qoa_uint64_t weights = 0;
qoa_uint64_t history = 0; qoa_uint64_t history = 0;
for (int i = 0; i < QOA_LMS_LEN; i++) { for (int i = 0; i < QOA_LMS_LEN; i++) {
@ -348,8 +408,13 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned
qoa_uint64_t best_error = -1; qoa_uint64_t best_error = -1;
qoa_uint64_t best_slice; qoa_uint64_t best_slice;
qoa_lms_t best_lms; qoa_lms_t best_lms;
int best_scalefactor;
for (int scalefactor = 0; scalefactor < 16; scalefactor++) { for (int sfi = 0; sfi < 16; sfi++) {
/* 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;
/* We have to reset the LMS state to the last known good one /* We have to reset the LMS state to the last known good one
before trying each scalefactor, as each pass updates the LMS before trying each scalefactor, as each pass updates the LMS
@ -367,7 +432,7 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned
int clamped = qoa_clamp(scaled, -8, 8); int clamped = qoa_clamp(scaled, -8, 8);
int quantized = qoa_quant_tab[clamped + 8]; int quantized = qoa_quant_tab[clamped + 8];
int dequantized = qoa_dequant_tab[scalefactor][quantized]; int dequantized = qoa_dequant_tab[scalefactor][quantized];
int reconstructed = qoa_clamp(predicted + dequantized, -32768, 32767); int reconstructed = qoa_clamp_s16(predicted + dequantized);
long long error = (sample - reconstructed); long long error = (sample - reconstructed);
current_error += error * error; current_error += error * error;
@ -383,9 +448,12 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned
best_error = current_error; best_error = current_error;
best_slice = slice; best_slice = slice;
best_lms = lms; best_lms = lms;
best_scalefactor = scalefactor;
} }
} }
prev_scalefactor[c] = best_scalefactor;
qoa->lms[c] = best_lms; qoa->lms[c] = best_lms;
#ifdef QOA_RECORD_TOTAL_ERROR #ifdef QOA_RECORD_TOTAL_ERROR
qoa->error += best_error; qoa->error += best_error;
@ -553,7 +621,7 @@ unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa
int predicted = qoa_lms_predict(&qoa->lms[c]); int predicted = qoa_lms_predict(&qoa->lms[c]);
int quantized = (slice >> 57) & 0x7; int quantized = (slice >> 57) & 0x7;
int dequantized = qoa_dequant_tab[scalefactor][quantized]; int dequantized = qoa_dequant_tab[scalefactor][quantized];
int reconstructed = qoa_clamp(predicted + dequantized, -32768, 32767); int reconstructed = qoa_clamp_s16(predicted + dequantized);
sample_data[si] = reconstructed; sample_data[si] = reconstructed;
slice <<= 3; slice <<= 3;

12
raylib/external/qoi.h vendored
View file

@ -594,7 +594,7 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
int qoi_write(const char *filename, const void *data, const qoi_desc *desc) { int qoi_write(const char *filename, const void *data, const qoi_desc *desc) {
FILE *f = fopen(filename, "wb"); FILE *f = fopen(filename, "wb");
int size; int size, err;
void *encoded; void *encoded;
if (!f) { if (!f) {
@ -608,10 +608,12 @@ int qoi_write(const char *filename, const void *data, const qoi_desc *desc) {
} }
fwrite(encoded, 1, size, f); fwrite(encoded, 1, size, f);
fflush(f);
err = ferror(f);
fclose(f); fclose(f);
QOI_FREE(encoded); QOI_FREE(encoded);
return size; return err ? 0 : size;
} }
void *qoi_read(const char *filename, qoi_desc *desc, int channels) { void *qoi_read(const char *filename, qoi_desc *desc, int channels) {
@ -625,11 +627,10 @@ void *qoi_read(const char *filename, qoi_desc *desc, int channels) {
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
size = ftell(f); size = ftell(f);
if (size <= 0) { if (size <= 0 || fseek(f, 0, SEEK_SET) != 0) {
fclose(f); fclose(f);
return NULL; return NULL;
} }
fseek(f, 0, SEEK_SET);
data = QOI_MALLOC(size); data = QOI_MALLOC(size);
if (!data) { if (!data) {
@ -639,8 +640,7 @@ void *qoi_read(const char *filename, qoi_desc *desc, int channels) {
bytes_read = fread(data, 1, size, f); bytes_read = fread(data, 1, size, f);
fclose(f); fclose(f);
pixels = (bytes_read != size) ? NULL : qoi_decode(data, bytes_read, desc, channels);
pixels = qoi_decode(data, bytes_read, desc, channels);
QOI_FREE(data); QOI_FREE(data);
return pixels; return pixels;
} }

View file

@ -1,6 +1,6 @@
/********************************************************************************************** /**********************************************************************************************
* *
* rl_gputex - GPU compressed textures loading and saving * rl_gputex v1.0 - GPU compressed textures loading and saving
* *
* DESCRIPTION: * DESCRIPTION:
* *

View file

@ -186,7 +186,7 @@ int *rprand_load_sequence(unsigned int count, int min, int max)
{ {
int *sequence = NULL; int *sequence = NULL;
if (count > (abs(max - min) + 1)) if (count > (unsigned int)(abs(max - min) + 1))
{ {
RPRAND_LOG("WARNING: Sequence count required is greater than range provided\n"); RPRAND_LOG("WARNING: Sequence count required is greater than range provided\n");
//count = (max - min); //count = (max - min);
@ -198,9 +198,9 @@ int *rprand_load_sequence(unsigned int count, int min, int max)
int value = 0; int value = 0;
bool value_is_dup = false; bool value_is_dup = false;
for (int i = 0; i < count;) for (unsigned int i = 0; i < count;)
{ {
value = (rprand_xoshiro()%(abs(max - min) + 1)) + min; value = ((int)rprand_xoshiro()%(abs(max - min) + 1)) + min;
value_is_dup = false; value_is_dup = false;
for (int j = 0; j < i; j++) for (int j = 0; j < i; j++)

View file

@ -122,6 +122,7 @@ extern "C" {
struct sinfl { struct sinfl {
const unsigned char *bitptr; const unsigned char *bitptr;
const unsigned char *bitend; // @raysan5: added
unsigned long long bitbuf; unsigned long long bitbuf;
int bitcnt; int bitcnt;
@ -185,9 +186,10 @@ sinfl_read64(const void *p) {
} }
static void static void
sinfl_copy64(unsigned char **dst, unsigned char **src) { sinfl_copy64(unsigned char **dst, unsigned char **src) {
unsigned long long n; //unsigned long long n;
memcpy(&n, *src, 8); //memcpy(&n, *src, 8);
memcpy(*dst, &n, 8); //memcpy(*dst, &n, 8);
memcpy(*dst, *src, 8); // @raysan5
*dst += 8, *src += 8; *dst += 8, *src += 8;
} }
static unsigned char* static unsigned char*
@ -210,9 +212,22 @@ sinfl_copy128(unsigned char **dst, unsigned char **src) {
#endif #endif
static void static void
sinfl_refill(struct sinfl *s) { sinfl_refill(struct sinfl *s) {
if (s->bitend - s->bitptr >= 8) {
// @raysan5: original code, only those 3 lines
s->bitbuf |= sinfl_read64(s->bitptr) << s->bitcnt; s->bitbuf |= sinfl_read64(s->bitptr) << s->bitcnt;
s->bitptr += (63 - s->bitcnt) >> 3; s->bitptr += (63 - s->bitcnt) >> 3;
s->bitcnt |= 56; /* bitcount in range [56,63] */ s->bitcnt |= 56; /* bitcount in range [56,63] */
} else {
// @raysan5: added this case when bits remaining < 8
int bitswant = 63 - s->bitcnt;
int byteswant = bitswant >> 3;
int bytesuse = s->bitend - s->bitptr <= byteswant ? (int)(s->bitend - s->bitptr) : byteswant;
unsigned long long n = 0;
memcpy(&n, s->bitptr, bytesuse);
s->bitbuf |= n << s->bitcnt;
s->bitptr += bytesuse;
s->bitcnt += bytesuse << 3;
}
} }
static int static int
sinfl_peek(struct sinfl *s, int cnt) { sinfl_peek(struct sinfl *s, int cnt) {
@ -384,6 +399,7 @@ sinfl_decompress(unsigned char *out, int cap, const unsigned char *in, int size)
int last = 0; int last = 0;
s.bitptr = in; s.bitptr = in;
s.bitend = e; // @raysan5: added
while (1) { while (1) {
switch (state) { switch (state) {
case hdr: { case hdr: {

View file

@ -123,6 +123,9 @@ typedef struct {
// NOTE: currentButtonState[] can't be written directly due to multithreading, app could miss the update // NOTE: currentButtonState[] can't be written directly due to multithreading, app could miss the update
char currentButtonStateEvdev[MAX_MOUSE_BUTTONS]; // Holds the new mouse state for the next polling event to grab char currentButtonStateEvdev[MAX_MOUSE_BUTTONS]; // Holds the new mouse state for the next polling event to grab
bool cursorRelative; // Relative cursor mode bool cursorRelative; // Relative cursor mode
int mouseFd; // File descriptor for the evdev mouse/touch/gestures
Rectangle absRange; // Range of values for absolute pointing devices (touchscreens)
int touchSlot; // Hold the touch slot number of the currently being sent multitouch block
// Gamepad data // Gamepad data
pthread_t gamepadThreadId; // Gamepad reading thread id pthread_t gamepadThreadId; // Gamepad reading thread id
@ -170,11 +173,6 @@ static const int EvkeyToUnicodeLUT[] = {
// LUT currently incomplete, just mapped the most essential keys // LUT currently incomplete, just mapped the most essential keys
}; };
#if defined(SUPPORT_GESTURES_SYSTEM)
GestureEvent gestureEvent = { 0 }; // Gesture event to hold data between EventThread() and PollInputEvents()
bool newGesture = false; // Var to trigger ProcessGestureEvent(gestureEvent) on PollInputEvents()
#endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Internal Functions Declaration // Module Internal Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -448,7 +446,7 @@ void EnableCursor(void)
void DisableCursor(void) void DisableCursor(void)
{ {
// Set cursor position in the middle // Set cursor position in the middle
SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); SetMousePosition(0, 0);
platform.cursorRelative = true; platform.cursorRelative = true;
CORE.Input.Mouse.cursorHidden = true; CORE.Input.Mouse.cursorHidden = true;
@ -565,11 +563,8 @@ void PollInputEvents(void)
PollKeyboardEvents(); PollKeyboardEvents();
// Register previous mouse position // Register previous mouse position
if (platform.cursorRelative) if (platform.cursorRelative) CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f };
{ else CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f };
}
// Register previous mouse states // Register previous mouse states
CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove; CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove;
@ -600,15 +595,6 @@ void PollInputEvents(void)
// Map touch position to mouse position for convenience // Map touch position to mouse position for convenience
CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
#if defined(SUPPORT_GESTURES_SYSTEM)
// Call the ProcessGestureEvent here instead of on EventThread() to workaround the threads not matching
if (newGesture)
{
ProcessGestureEvent(gestureEvent);
newGesture = false;
}
#endif
#if defined(SUPPORT_SSH_KEYBOARD_RPI) #if defined(SUPPORT_SSH_KEYBOARD_RPI)
// NOTE: Keyboard reading could be done using input_event(s) or just read from stdin, both methods are used here. // NOTE: Keyboard reading could be done using input_event(s) or just read from stdin, both methods are used here.
// stdin reading is still used for legacy purposes, it allows keyboard input trough SSH console // stdin reading is still used for legacy purposes, it allows keyboard input trough SSH console
@ -618,6 +604,183 @@ void PollInputEvents(void)
// NOTE: Mouse input events polling is done asynchronously in another pthread - EventThread() // NOTE: Mouse input events polling is done asynchronously in another pthread - EventThread()
// NOTE: Gamepad (Joystick) input events polling is done asynchonously in another pthread - GamepadThread() // NOTE: Gamepad (Joystick) input events polling is done asynchonously in another pthread - GamepadThread()
#endif #endif
// Handle the mouse/touch/gestures events:
// NOTE: Replaces the EventThread handling that is now commented.
{
int fd = platform.mouseFd;
if (fd == -1) return;
struct input_event event = { 0 };
int touchAction = -1; // 0-TOUCH_ACTION_UP, 1-TOUCH_ACTION_DOWN, 2-TOUCH_ACTION_MOVE
bool gestureUpdate = false; // Flag to note gestures require to update
// Try to read data from the mouse/touch/gesture and only continue if successful
while (read(fd, &event, sizeof(event)) == (int)sizeof(event))
{
// Relative movement parsing
if (event.type == EV_REL)
{
if (event.code == REL_X)
{
if (platform.cursorRelative)
{
CORE.Input.Mouse.currentPosition.x = event.value;
CORE.Input.Mouse.previousPosition.x = 0.0f;
}
else CORE.Input.Mouse.currentPosition.x += event.value;
CORE.Input.Touch.position[0].x = CORE.Input.Mouse.currentPosition.x;
touchAction = 2; // TOUCH_ACTION_MOVE
gestureUpdate = true;
}
if (event.code == REL_Y)
{
if (platform.cursorRelative)
{
CORE.Input.Mouse.currentPosition.y = event.value;
CORE.Input.Mouse.previousPosition.y = 0.0f;
}
else CORE.Input.Mouse.currentPosition.y += event.value;
CORE.Input.Touch.position[0].y = CORE.Input.Mouse.currentPosition.y;
touchAction = 2; // TOUCH_ACTION_MOVE
gestureUpdate = true;
}
if (event.code == REL_WHEEL) platform.eventWheelMove.y += event.value;
}
// Absolute movement parsing
if (event.type == EV_ABS)
{
// Basic movement
if (event.code == ABS_X)
{
CORE.Input.Mouse.currentPosition.x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange
CORE.Input.Touch.position[0].x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange
touchAction = 2; // TOUCH_ACTION_MOVE
gestureUpdate = true;
}
if (event.code == ABS_Y)
{
CORE.Input.Mouse.currentPosition.y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange
CORE.Input.Touch.position[0].y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange
touchAction = 2; // TOUCH_ACTION_MOVE
gestureUpdate = true;
}
// Multitouch movement
if (event.code == ABS_MT_SLOT) platform.touchSlot = event.value; // Remember the slot number for the folowing events
if (event.code == ABS_MT_POSITION_X)
{
if (platform.touchSlot < MAX_TOUCH_POINTS) CORE.Input.Touch.position[platform.touchSlot].x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange
}
if (event.code == ABS_MT_POSITION_Y)
{
if (platform.touchSlot < MAX_TOUCH_POINTS) CORE.Input.Touch.position[platform.touchSlot].y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange
}
if (event.code == ABS_MT_TRACKING_ID)
{
if ((event.value < 0) && (platform.touchSlot < MAX_TOUCH_POINTS))
{
// Touch has ended for this point
CORE.Input.Touch.position[platform.touchSlot].x = -1;
CORE.Input.Touch.position[platform.touchSlot].y = -1;
}
}
// Touchscreen tap
if (event.code == ABS_PRESSURE)
{
int previousMouseLeftButtonState = platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT];
if (!event.value && previousMouseLeftButtonState)
{
platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 0;
touchAction = 0; // TOUCH_ACTION_UP
gestureUpdate = true;
}
if (event.value && !previousMouseLeftButtonState)
{
platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 1;
touchAction = 1; // TOUCH_ACTION_DOWN
gestureUpdate = true;
}
}
}
// Button parsing
if (event.type == EV_KEY)
{
// Mouse button parsing
if ((event.code == BTN_TOUCH) || (event.code == BTN_LEFT))
{
platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = event.value;
if (event.value > 0) touchAction = 1; // TOUCH_ACTION_DOWN
else touchAction = 0; // TOUCH_ACTION_UP
gestureUpdate = true;
}
if (event.code == BTN_RIGHT) platform.currentButtonStateEvdev[MOUSE_BUTTON_RIGHT] = event.value;
if (event.code == BTN_MIDDLE) platform.currentButtonStateEvdev[MOUSE_BUTTON_MIDDLE] = event.value;
if (event.code == BTN_SIDE) platform.currentButtonStateEvdev[MOUSE_BUTTON_SIDE] = event.value;
if (event.code == BTN_EXTRA) platform.currentButtonStateEvdev[MOUSE_BUTTON_EXTRA] = event.value;
if (event.code == BTN_FORWARD) platform.currentButtonStateEvdev[MOUSE_BUTTON_FORWARD] = event.value;
if (event.code == BTN_BACK) platform.currentButtonStateEvdev[MOUSE_BUTTON_BACK] = event.value;
}
// Screen confinement
if (!CORE.Input.Mouse.cursorHidden)
{
if (CORE.Input.Mouse.currentPosition.x < 0) CORE.Input.Mouse.currentPosition.x = 0;
if (CORE.Input.Mouse.currentPosition.x > CORE.Window.screen.width/CORE.Input.Mouse.scale.x) CORE.Input.Mouse.currentPosition.x = CORE.Window.screen.width/CORE.Input.Mouse.scale.x;
if (CORE.Input.Mouse.currentPosition.y < 0) CORE.Input.Mouse.currentPosition.y = 0;
if (CORE.Input.Mouse.currentPosition.y > CORE.Window.screen.height/CORE.Input.Mouse.scale.y) CORE.Input.Mouse.currentPosition.y = CORE.Window.screen.height/CORE.Input.Mouse.scale.y;
}
// Update touch point count
CORE.Input.Touch.pointCount = 0;
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
{
if (CORE.Input.Touch.position[i].x >= 0) CORE.Input.Touch.pointCount++;
}
#if defined(SUPPORT_GESTURES_SYSTEM)
if (gestureUpdate)
{
GestureEvent gestureEvent = { 0 };
gestureEvent.touchAction = touchAction;
gestureEvent.pointCount = CORE.Input.Touch.pointCount;
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
{
gestureEvent.pointId[i] = i;
gestureEvent.position[i] = CORE.Input.Touch.position[i];
}
ProcessGestureEvent(gestureEvent);
gestureUpdate = false;
}
#endif
}
}
} }
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -1386,9 +1549,14 @@ static void ConfigureEvdevDevice(char *device)
ioctl(fd, EVIOCGABS(ABS_X), &absinfo); ioctl(fd, EVIOCGABS(ABS_X), &absinfo);
worker->absRange.x = absinfo.minimum; worker->absRange.x = absinfo.minimum;
worker->absRange.width = absinfo.maximum - absinfo.minimum; worker->absRange.width = absinfo.maximum - absinfo.minimum;
platform.absRange.x = absinfo.minimum;
platform.absRange.width = absinfo.maximum - absinfo.minimum;
ioctl(fd, EVIOCGABS(ABS_Y), &absinfo); ioctl(fd, EVIOCGABS(ABS_Y), &absinfo);
worker->absRange.y = absinfo.minimum; worker->absRange.y = absinfo.minimum;
worker->absRange.height = absinfo.maximum - absinfo.minimum; worker->absRange.height = absinfo.maximum - absinfo.minimum;
platform.absRange.y = absinfo.minimum;
platform.absRange.height = absinfo.maximum - absinfo.minimum;
} }
// Check for multiple absolute movement support (usually multitouch touchscreens) // Check for multiple absolute movement support (usually multitouch touchscreens)
@ -1400,9 +1568,14 @@ static void ConfigureEvdevDevice(char *device)
ioctl(fd, EVIOCGABS(ABS_X), &absinfo); ioctl(fd, EVIOCGABS(ABS_X), &absinfo);
worker->absRange.x = absinfo.minimum; worker->absRange.x = absinfo.minimum;
worker->absRange.width = absinfo.maximum - absinfo.minimum; worker->absRange.width = absinfo.maximum - absinfo.minimum;
platform.absRange.x = absinfo.minimum;
platform.absRange.width = absinfo.maximum - absinfo.minimum;
ioctl(fd, EVIOCGABS(ABS_Y), &absinfo); ioctl(fd, EVIOCGABS(ABS_Y), &absinfo);
worker->absRange.y = absinfo.minimum; worker->absRange.y = absinfo.minimum;
worker->absRange.height = absinfo.maximum - absinfo.minimum; worker->absRange.height = absinfo.maximum - absinfo.minimum;
platform.absRange.y = absinfo.minimum;
platform.absRange.height = absinfo.maximum - absinfo.minimum;
} }
} }
@ -1462,15 +1635,20 @@ static void ConfigureEvdevDevice(char *device)
worker->isMultitouch? "multitouch " : "", worker->isMultitouch? "multitouch " : "",
worker->isTouch? "touchscreen " : "", worker->isTouch? "touchscreen " : "",
worker->isGamepad? "gamepad " : ""); worker->isGamepad? "gamepad " : "");
platform.mouseFd = worker->fd;
// NOTE: moved the mouse/touch/gesture input to PollInputEvents()/
// so added the "platform.mouseFd = worker->fd;" line above
// and commented the thread code below:
// Create a thread for this device // Create a thread for this device
int error = pthread_create(&worker->threadId, NULL, &EventThread, (void *)worker); //int error = pthread_create(&worker->threadId, NULL, &EventThread, (void *)worker);
if (error != 0) //if (error != 0)
{ //{
TRACELOG(LOG_WARNING, "RPI: Failed to create input device thread: %s (error: %d)", device, error); // TRACELOG(LOG_WARNING, "RPI: Failed to create input device thread: %s (error: %d)", device, error);
worker->threadId = 0; // worker->threadId = 0;
close(fd); // close(fd);
} //}
#if defined(USE_LAST_TOUCH_DEVICE) #if defined(USE_LAST_TOUCH_DEVICE)
// Find touchscreen with the highest index // Find touchscreen with the highest index
@ -1570,6 +1748,7 @@ static void PollKeyboardEvents(void)
// Input device events reading thread // Input device events reading thread
static void *EventThread(void *arg) static void *EventThread(void *arg)
{ {
/*
struct input_event event = { 0 }; struct input_event event = { 0 };
InputEventWorker *worker = (InputEventWorker *)arg; InputEventWorker *worker = (InputEventWorker *)arg;
@ -1731,7 +1910,7 @@ static void *EventThread(void *arg)
#if defined(SUPPORT_GESTURES_SYSTEM) #if defined(SUPPORT_GESTURES_SYSTEM)
if (gestureUpdate) if (gestureUpdate)
{ {
//GestureEvent gestureEvent = { 0 }; GestureEvent gestureEvent = { 0 };
gestureEvent.touchAction = touchAction; gestureEvent.touchAction = touchAction;
gestureEvent.pointCount = CORE.Input.Touch.pointCount; gestureEvent.pointCount = CORE.Input.Touch.pointCount;
@ -1742,8 +1921,7 @@ static void *EventThread(void *arg)
gestureEvent.position[i] = CORE.Input.Touch.position[i]; gestureEvent.position[i] = CORE.Input.Touch.position[i];
} }
//ProcessGestureEvent(gestureEvent); ProcessGestureEvent(gestureEvent);
newGesture = true;
} }
#endif #endif
} }
@ -1752,7 +1930,7 @@ static void *EventThread(void *arg)
} }
close(worker->fd); close(worker->fd);
*/
return NULL; return NULL;
} }

View file

@ -1221,14 +1221,10 @@ RLAPI void SetShapesTexture(Texture2D texture, Rectangle source); // Set t
RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel
RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel (Vector version) RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel (Vector version)
RLAPI void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw a line RLAPI void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw a line
RLAPI void DrawLineV(Vector2 startPos, Vector2 endPos, Color color); // Draw a line (Vector version) RLAPI void DrawLineV(Vector2 startPos, Vector2 endPos, Color color); // Draw a line (using gl lines)
RLAPI void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line defining thickness RLAPI void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line (using triangles/quads)
RLAPI void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line using cubic-bezier curves in-out RLAPI void DrawLineStrip(Vector2 *points, int pointCount, Color color); // Draw lines sequence (using gl lines)
RLAPI void DrawLineBezierQuad(Vector2 startPos, Vector2 endPos, Vector2 controlPos, float thick, Color color); // Draw line using quadratic bezier curves with a control point RLAPI void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw line segment cubic-bezier in-out interpolation
RLAPI void DrawLineBezierCubic(Vector2 startPos, Vector2 endPos, Vector2 startControlPos, Vector2 endControlPos, float thick, Color color); // Draw line using cubic bezier curves with 2 control points
RLAPI void DrawLineBSpline(Vector2 *points, int pointCount, float thick, Color color); // Draw a B-Spline line, minimum 4 points
RLAPI void DrawLineCatmullRom(Vector2 *points, int pointCount, float thick, Color color); // Draw a Catmull Rom spline line, minimum 4 points
RLAPI void DrawLineStrip(Vector2 *points, int pointCount, Color color); // Draw lines sequence
RLAPI void DrawCircle(int centerX, int centerY, float radius, Color color); // Draw a color-filled circle 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 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 DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw circle sector outline
@ -1259,6 +1255,25 @@ RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Col
RLAPI void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a polygon outline 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 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
// Splines drawing functions
RLAPI void DrawSplineLinear(Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Linear, minimum 2 points
RLAPI void DrawSplineBasis(Vector2 *points, int pointCount, float thick, Color color); // Draw spline: B-Spline, minimum 4 points
RLAPI void DrawSplineCatmullRom(Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Catmull-Rom, minimum 4 points
RLAPI void DrawSplineBezierQuadratic(Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...]
RLAPI void DrawSplineBezierCubic(Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...]
RLAPI void DrawSplineSegmentLinear(Vector2 p1, Vector2 p2, float thick, Color color); // Draw spline segment: Linear, 2 points
RLAPI void DrawSplineSegmentBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color); // Draw spline segment: B-Spline, 4 points
RLAPI void DrawSplineSegmentCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color); // Draw spline segment: Catmull-Rom, 4 points
RLAPI void DrawSplineSegmentBezierQuadratic(Vector2 p1, Vector2 c2, Vector2 p3, float thick, Color color); // Draw spline segment: Quadratic Bezier, 2 points, 1 control point
RLAPI void DrawSplineSegmentBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float thick, Color color); // Draw spline segment: Cubic Bezier, 2 points, 2 control points
// Spline segment point evaluation functions, for a given t [0.0f .. 1.0f]
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 GetSplinePointBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float t); // Get (evaluate) spline point: Cubic Bezier
// Basic shapes collision detection functions // Basic shapes collision detection functions
RLAPI bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2); // Check collision between two rectangles 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 CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2); // Check collision between two circles

View file

@ -189,7 +189,11 @@ __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigne
#define MAX_FILEPATH_CAPACITY 8192 // Maximum capacity for filepath #define MAX_FILEPATH_CAPACITY 8192 // Maximum capacity for filepath
#endif #endif
#ifndef MAX_FILEPATH_LENGTH #ifndef MAX_FILEPATH_LENGTH
#define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value) #if defined(_WIN32)
#define MAX_FILEPATH_LENGTH 256 // On Win32, MAX_PATH = 260 (limits.h) but Windows 10, Version 1607 enables long paths...
#else
#define MAX_FILEPATH_LENGTH 4096 // On Linux, PATH_MAX = 4096 by default (limits.h)
#endif
#endif #endif
#ifndef MAX_KEYBOARD_KEYS #ifndef MAX_KEYBOARD_KEYS
@ -252,6 +256,7 @@ typedef struct CoreData {
bool shouldClose; // Check if window set for closing bool shouldClose; // Check if window set for closing
bool resizedLastFrame; // Check if window has been resized last frame bool resizedLastFrame; // Check if window has been resized last frame
bool eventWaiting; // Wait for events before ending frame bool eventWaiting; // Wait for events before ending frame
bool usingFbo; // Using FBO (RenderTexture) for rendering instead of default framebuffer
Point position; // Window position (required on fullscreen toggle) Point position; // Window position (required on fullscreen toggle)
Point previousPosition; // Window previous position (required on borderless windowed toggle) Point previousPosition; // Window previous position (required on borderless windowed toggle)
@ -1035,6 +1040,7 @@ void BeginTextureMode(RenderTexture2D target)
// calculation when using BeginMode3D() // calculation when using BeginMode3D()
CORE.Window.currentFbo.width = target.texture.width; CORE.Window.currentFbo.width = target.texture.width;
CORE.Window.currentFbo.height = target.texture.height; CORE.Window.currentFbo.height = target.texture.height;
CORE.Window.usingFbo = true;
} }
// Ends drawing to render texture // Ends drawing to render texture
@ -1050,6 +1056,7 @@ void EndTextureMode(void)
// Reset current fbo to screen size // Reset current fbo to screen size
CORE.Window.currentFbo.width = CORE.Window.render.width; CORE.Window.currentFbo.width = CORE.Window.render.width;
CORE.Window.currentFbo.height = CORE.Window.render.height; CORE.Window.currentFbo.height = CORE.Window.render.height;
CORE.Window.usingFbo = false;
} }
// Begin custom shader mode // Begin custom shader mode
@ -1086,19 +1093,22 @@ void BeginScissorMode(int x, int y, int width, int height)
rlEnableScissorTest(); rlEnableScissorTest();
#if defined(__APPLE__) #if defined(__APPLE__)
if (CORE.Window.usingFbo)
{
Vector2 scale = GetWindowScaleDPI(); Vector2 scale = GetWindowScaleDPI();
rlScissor((int)(x*scale.x), (int)(GetScreenHeight()*scale.y - (((y + height)*scale.y))), (int)(width*scale.x), (int)(height*scale.y)); rlScissor((int)(x*scale.x), (int)(GetScreenHeight()*scale.y - (((y + height)*scale.y))), (int)(width*scale.x), (int)(height*scale.y));
}
#else #else
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) if (CORE.Window.usingFbo && ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0))
{ {
Vector2 scale = GetWindowScaleDPI(); Vector2 scale = GetWindowScaleDPI();
rlScissor((int)(x*scale.x), (int)(CORE.Window.currentFbo.height - (y + height)*scale.y), (int)(width*scale.x), (int)(height*scale.y)); rlScissor((int)(x*scale.x), (int)(CORE.Window.currentFbo.height - (y + height)*scale.y), (int)(width*scale.x), (int)(height*scale.y));
} }
#endif
else else
{ {
rlScissor(x, CORE.Window.currentFbo.height - (y + height), width, height); rlScissor(x, CORE.Window.currentFbo.height - (y + height), width, height);
} }
#endif
} }
// End scissor mode // End scissor mode
@ -2513,7 +2523,7 @@ bool ExportAutomationEventList(AutomationEventList list, const char *fileName)
// Add events data // Add events data
byteCount += sprintf(txtData + byteCount, "c %i\n", list.count); byteCount += sprintf(txtData + byteCount, "c %i\n", list.count);
for (int i = 0; i < list.count; i++) for (unsigned int i = 0; i < list.count; i++)
{ {
byteCount += snprintf(txtData + byteCount, 256, "e %i %i %i %i %i %i // Event: %s\n", list.events[i].frame, list.events[i].type, byteCount += snprintf(txtData + byteCount, 256, "e %i %i %i %i %i %i // Event: %s\n", list.events[i].frame, list.events[i].type,
list.events[i].params[0], list.events[i].params[1], list.events[i].params[2], list.events[i].params[3], autoEventTypeName[list.events[i].type]); list.events[i].params[0], list.events[i].params[1], list.events[i].params[2], list.events[i].params[3], autoEventTypeName[list.events[i].type]);
@ -3167,7 +3177,11 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const
if ((strcmp(dp->d_name, ".") != 0) && if ((strcmp(dp->d_name, ".") != 0) &&
(strcmp(dp->d_name, "..") != 0)) (strcmp(dp->d_name, "..") != 0))
{ {
#if defined(_WIN32)
sprintf(path, "%s\\%s", basePath, dp->d_name);
#else
sprintf(path, "%s/%s", basePath, dp->d_name); sprintf(path, "%s/%s", basePath, dp->d_name);
#endif
if (filter != NULL) if (filter != NULL)
{ {
@ -3206,7 +3220,11 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi
if ((strcmp(dp->d_name, ".") != 0) && (strcmp(dp->d_name, "..") != 0)) if ((strcmp(dp->d_name, ".") != 0) && (strcmp(dp->d_name, "..") != 0))
{ {
// Construct new path from our base path // Construct new path from our base path
#if defined(_WIN32)
sprintf(path, "%s\\%s", basePath, dp->d_name);
#else
sprintf(path, "%s/%s", basePath, dp->d_name); sprintf(path, "%s/%s", basePath, dp->d_name);
#endif
if (IsPathFile(path)) if (IsPathFile(path))
{ {

View file

@ -67,8 +67,8 @@
#ifndef SMOOTH_CIRCLE_ERROR_RATE #ifndef SMOOTH_CIRCLE_ERROR_RATE
#define SMOOTH_CIRCLE_ERROR_RATE 0.5f // Circle error rate #define SMOOTH_CIRCLE_ERROR_RATE 0.5f // Circle error rate
#endif #endif
#ifndef SPLINE_LINE_DIVISIONS #ifndef SPLINE_SEGMENT_DIVISIONS
#define SPLINE_LINE_DIVISIONS 24 // Spline lines segment divisions #define SPLINE_SEGMENT_DIVISIONS 24 // Spline segment divisions
#endif #endif
@ -161,7 +161,7 @@ void DrawPixelV(Vector2 position, Color color)
#endif #endif
} }
// Draw a line // Draw a line (using gl lines)
void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color) void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color)
{ {
rlBegin(RL_LINES); rlBegin(RL_LINES);
@ -171,7 +171,7 @@ void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color colo
rlEnd(); rlEnd();
} }
// Draw a line (Vector version) // Draw a line (using gl lines)
void DrawLineV(Vector2 startPos, Vector2 endPos, Color color) void DrawLineV(Vector2 startPos, Vector2 endPos, Color color)
{ {
rlBegin(RL_LINES); rlBegin(RL_LINES);
@ -181,6 +181,61 @@ void DrawLineV(Vector2 startPos, Vector2 endPos, Color color)
rlEnd(); rlEnd();
} }
// Draw lines sequuence (using gl lines)
void DrawLineStrip(Vector2 *points, int pointCount, Color color)
{
if (pointCount >= 2)
{
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
for (int i = 0; i < pointCount - 1; i++)
{
rlVertex2f(points[i].x, points[i].y);
rlVertex2f(points[i + 1].x, points[i + 1].y);
}
rlEnd();
}
}
// Draw line using cubic-bezier spline, in-out interpolation, no control points
void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color)
{
Vector2 previous = startPos;
Vector2 current = { 0 };
Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
for (int i = 1; i <= SPLINE_SEGMENT_DIVISIONS; i++)
{
// Cubic easing in-out
// NOTE: Easing is calculated only for y position value
current.y = EaseCubicInOut((float)i, startPos.y, endPos.y - startPos.y, (float)SPLINE_SEGMENT_DIVISIONS);
current.x = previous.x + (endPos.x - startPos.x)/(float)SPLINE_SEGMENT_DIVISIONS;
float dy = current.y - previous.y;
float dx = current.x - previous.x;
float size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
if (i == 1)
{
points[0].x = previous.x + dy*size;
points[0].y = previous.y - dx*size;
points[1].x = previous.x - dy*size;
points[1].y = previous.y + dx*size;
}
points[2*i + 1].x = current.x - dy*size;
points[2*i + 1].y = current.y + dx*size;
points[2*i].x = current.x + dy*size;
points[2*i].y = current.y - dx*size;
previous = current;
}
DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
}
// Draw a line defining thickness // Draw a line defining thickness
void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color) void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color)
{ {
@ -203,295 +258,6 @@ void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color)
} }
} }
// Draw line using cubic-bezier curves in-out
void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color)
{
Vector2 previous = startPos;
Vector2 current = { 0 };
Vector2 points[2*SPLINE_LINE_DIVISIONS + 2] = { 0 };
for (int i = 1; i <= SPLINE_LINE_DIVISIONS; i++)
{
// Cubic easing in-out
// NOTE: Easing is calculated only for y position value
current.y = EaseCubicInOut((float)i, startPos.y, endPos.y - startPos.y, (float)SPLINE_LINE_DIVISIONS);
current.x = previous.x + (endPos.x - startPos.x)/(float)SPLINE_LINE_DIVISIONS;
float dy = current.y - previous.y;
float dx = current.x - previous.x;
float size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
if (i == 1)
{
points[0].x = previous.x + dy*size;
points[0].y = previous.y - dx*size;
points[1].x = previous.x - dy*size;
points[1].y = previous.y + dx*size;
}
points[2*i + 1].x = current.x - dy*size;
points[2*i + 1].y = current.y + dx*size;
points[2*i].x = current.x + dy*size;
points[2*i].y = current.y - dx*size;
previous = current;
}
DrawTriangleStrip(points, 2*SPLINE_LINE_DIVISIONS + 2, color);
}
// Draw line using quadratic bezier curves with a control point
void DrawLineBezierQuad(Vector2 startPos, Vector2 endPos, Vector2 controlPos, float thick, Color color)
{
const float step = 1.0f/SPLINE_LINE_DIVISIONS;
Vector2 previous = startPos;
Vector2 current = { 0 };
float t = 0.0f;
Vector2 points[2*SPLINE_LINE_DIVISIONS + 2] = { 0 };
for (int i = 1; i <= SPLINE_LINE_DIVISIONS; i++)
{
t = step*i;
float a = powf(1.0f - t, 2);
float b = 2.0f*(1.0f - t)*t;
float c = powf(t, 2);
// NOTE: The easing functions aren't suitable here because they don't take a control point
current.y = a*startPos.y + b*controlPos.y + c*endPos.y;
current.x = a*startPos.x + b*controlPos.x + c*endPos.x;
float dy = current.y - previous.y;
float dx = current.x - previous.x;
float size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
if (i == 1)
{
points[0].x = previous.x + dy*size;
points[0].y = previous.y - dx*size;
points[1].x = previous.x - dy*size;
points[1].y = previous.y + dx*size;
}
points[2*i + 1].x = current.x - dy*size;
points[2*i + 1].y = current.y + dx*size;
points[2*i].x = current.x + dy*size;
points[2*i].y = current.y - dx*size;
previous = current;
}
DrawTriangleStrip(points, 2*SPLINE_LINE_DIVISIONS + 2, color);
}
// Draw line using cubic bezier curves with 2 control points
void DrawLineBezierCubic(Vector2 startPos, Vector2 endPos, Vector2 startControlPos, Vector2 endControlPos, float thick, Color color)
{
const float step = 1.0f/SPLINE_LINE_DIVISIONS;
Vector2 previous = startPos;
Vector2 current = { 0 };
float t = 0.0f;
Vector2 points[2*SPLINE_LINE_DIVISIONS + 2] = { 0 };
for (int i = 1; i <= SPLINE_LINE_DIVISIONS; i++)
{
t = step*i;
float a = powf(1.0f - t, 3);
float b = 3.0f*powf(1.0f - t, 2)*t;
float c = 3.0f*(1.0f - t)*powf(t, 2);
float d = powf(t, 3);
current.y = a*startPos.y + b*startControlPos.y + c*endControlPos.y + d*endPos.y;
current.x = a*startPos.x + b*startControlPos.x + c*endControlPos.x + d*endPos.x;
float dy = current.y - previous.y;
float dx = current.x - previous.x;
float size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
if (i == 1)
{
points[0].x = previous.x + dy*size;
points[0].y = previous.y - dx*size;
points[1].x = previous.x - dy*size;
points[1].y = previous.y + dx*size;
}
points[2*i + 1].x = current.x - dy*size;
points[2*i + 1].y = current.y + dx*size;
points[2*i].x = current.x + dy*size;
points[2*i].y = current.y - dx*size;
previous = current;
}
DrawTriangleStrip(points, 2*SPLINE_LINE_DIVISIONS + 2, color);
}
// Draw a B-Spline line, minimum 4 points
void DrawLineBSpline(Vector2 *points, int pointCount, float thick, Color color)
{
if (pointCount < 4) return;
float a[4] = { 0 };
float b[4] = { 0 };
float dy = 0.0f;
float dx = 0.0f;
float size = 0.0f;
Vector2 currentPoint = { 0 };
Vector2 nextPoint = { 0 };
Vector2 vertices[2*SPLINE_LINE_DIVISIONS + 2] = { 0 };
for (int i = 0; i < (pointCount - 3); i++)
{
float t = 0.0f;
Vector2 p1 = points[i], p2 = points[i + 1], p3 = points[i + 2], p4 = points[i + 3];
a[0] = (-p1.x + 3.0f*p2.x - 3.0f*p3.x + p4.x)/6.0f;
a[1] = (3.0f*p1.x - 6.0f*p2.x + 3.0f*p3.x)/6.0f;
a[2] = (-3.0f*p1.x + 3.0f*p3.x)/6.0f;
a[3] = (p1.x + 4.0f*p2.x + p3.x)/6.0f;
b[0] = (-p1.y + 3.0f*p2.y - 3.0f*p3.y + p4.y)/6.0f;
b[1] = (3.0f*p1.y - 6.0f*p2.y + 3.0f*p3.y)/6.0f;
b[2] = (-3.0f*p1.y + 3.0f*p3.y)/6.0f;
b[3] = (p1.y + 4.0f*p2.y + p3.y)/6.0f;
currentPoint.x = a[3];
currentPoint.y = b[3];
if (i == 0) DrawCircleV(currentPoint, thick/2.0f, color); // Draw init line circle-cap
if (i > 0)
{
vertices[0].x = currentPoint.x + dy*size;
vertices[0].y = currentPoint.y - dx*size;
vertices[1].x = currentPoint.x - dy*size;
vertices[1].y = currentPoint.y + dx*size;
}
for (int j = 1; j <= SPLINE_LINE_DIVISIONS; j++)
{
t = ((float)j)/((float)SPLINE_LINE_DIVISIONS);
nextPoint.x = a[3] + t*(a[2] + t*(a[1] + t*a[0]));
nextPoint.y = b[3] + t*(b[2] + t*(b[1] + t*b[0]));
dy = nextPoint.y - currentPoint.y;
dx = nextPoint.x - currentPoint.x;
size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
if ((i == 0) && (j == 1))
{
vertices[0].x = currentPoint.x + dy*size;
vertices[0].y = currentPoint.y - dx*size;
vertices[1].x = currentPoint.x - dy*size;
vertices[1].y = currentPoint.y + dx*size;
}
vertices[2*j + 1].x = nextPoint.x - dy*size;
vertices[2*j + 1].y = nextPoint.y + dx*size;
vertices[2*j].x = nextPoint.x + dy*size;
vertices[2*j].y = nextPoint.y - dx*size;
currentPoint = nextPoint;
}
DrawTriangleStrip(vertices, 2*SPLINE_LINE_DIVISIONS + 2, color);
}
DrawCircleV(currentPoint, thick/2.0f, color); // Draw end line circle-cap
}
// Draw a Catmull Rom spline line, minimum 4 points
void DrawLineCatmullRom(Vector2 *points, int pointCount, float thick, Color color)
{
if (pointCount < 4) return;
float dy = 0.0f;
float dx = 0.0f;
float size = 0.0f;
Vector2 currentPoint = points[1];
Vector2 nextPoint = { 0 };
Vector2 vertices[2*SPLINE_LINE_DIVISIONS + 2] = { 0 };
DrawCircleV(currentPoint, thick/2.0f, color); // Draw init line circle-cap
for (int i = 0; i < (pointCount - 3); i++)
{
float t = 0.0f;
Vector2 p1 = points[i], p2 = points[i + 1], p3 = points[i + 2], p4 = points[i + 3];
if (i > 0)
{
vertices[0].x = currentPoint.x + dy*size;
vertices[0].y = currentPoint.y - dx*size;
vertices[1].x = currentPoint.x - dy*size;
vertices[1].y = currentPoint.y + dx*size;
}
for (int j = 1; j <= SPLINE_LINE_DIVISIONS; j++)
{
t = ((float)j)/((float)SPLINE_LINE_DIVISIONS);
float q0 = (-1.0f*t*t*t) + (2.0f*t*t) + (-1.0f*t);
float q1 = (3.0f*t*t*t) + (-5.0f*t*t) + 2.0f;
float q2 = (-3.0f*t*t*t) + (4.0f*t*t) + t;
float q3 = t*t*t - t*t;
nextPoint.x = 0.5f*((p1.x*q0) + (p2.x*q1) + (p3.x*q2) + (p4.x*q3));
nextPoint.y = 0.5f*((p1.y*q0) + (p2.y*q1) + (p3.y*q2) + (p4.y*q3));
dy = nextPoint.y - currentPoint.y;
dx = nextPoint.x - currentPoint.x;
size = (0.5f*thick)/sqrtf(dx*dx + dy*dy);
if ((i == 0) && (j == 1))
{
vertices[0].x = currentPoint.x + dy*size;
vertices[0].y = currentPoint.y - dx*size;
vertices[1].x = currentPoint.x - dy*size;
vertices[1].y = currentPoint.y + dx*size;
}
vertices[2*j + 1].x = nextPoint.x - dy*size;
vertices[2*j + 1].y = nextPoint.y + dx*size;
vertices[2*j].x = nextPoint.x + dy*size;
vertices[2*j].y = nextPoint.y - dx*size;
currentPoint = nextPoint;
}
DrawTriangleStrip(vertices, 2*SPLINE_LINE_DIVISIONS + 2, color);
}
DrawCircleV(currentPoint, thick/2.0f, color); // Draw end line circle-cap
}
// Draw lines sequence
void DrawLineStrip(Vector2 *points, int pointCount, Color color)
{
if (pointCount >= 2)
{
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
for (int i = 0; i < pointCount - 1; i++)
{
rlVertex2f(points[i].x, points[i].y);
rlVertex2f(points[i + 1].x, points[i + 1].y);
}
rlEnd();
}
}
// Draw a color-filled circle // Draw a color-filled circle
void DrawCircle(int centerX, int centerY, float radius, Color color) void DrawCircle(int centerX, int centerY, float radius, Color color)
{ {
@ -1773,6 +1539,504 @@ void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, fl
#endif #endif
} }
//----------------------------------------------------------------------------------
// Module Functions Definition - Splines functions
//----------------------------------------------------------------------------------
// Draw spline: linear, minimum 2 points
void DrawSplineLinear(Vector2 *points, int pointCount, float thick, Color color)
{
Vector2 delta = { 0 };
float length = 0.0f;
float scale = 0.0f;
for (int i = 0; i < pointCount - 1; i++)
{
delta = (Vector2){ points[i + 1].x - points[i].x, points[i + 1].y - points[i].y };
length = sqrtf(delta.x*delta.x + delta.y*delta.y);
if (length > 0) scale = thick/(2*length);
Vector2 radius = { -scale*delta.y, scale*delta.x };
Vector2 strip[4] = {
{ points[i].x - radius.x, points[i].y - radius.y },
{ points[i].x + radius.x, points[i].y + radius.y },
{ points[i + 1].x - radius.x, points[i + 1].y - radius.y },
{ points[i + 1].x + radius.x, points[i + 1].y + radius.y }
};
DrawTriangleStrip(strip, 4, color);
}
#if defined(SUPPORT_SPLINE_SEGMENT_CAPS)
#endif
}
// Draw spline: B-Spline, minimum 4 points
void DrawSplineBasis(Vector2 *points, int pointCount, float thick, Color color)
{
if (pointCount < 4) return;
float a[4] = { 0 };
float b[4] = { 0 };
float dy = 0.0f;
float dx = 0.0f;
float size = 0.0f;
Vector2 currentPoint = { 0 };
Vector2 nextPoint = { 0 };
Vector2 vertices[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
for (int i = 0; i < (pointCount - 3); i++)
{
float t = 0.0f;
Vector2 p1 = points[i], p2 = points[i + 1], p3 = points[i + 2], p4 = points[i + 3];
a[0] = (-p1.x + 3.0f*p2.x - 3.0f*p3.x + p4.x)/6.0f;
a[1] = (3.0f*p1.x - 6.0f*p2.x + 3.0f*p3.x)/6.0f;
a[2] = (-3.0f*p1.x + 3.0f*p3.x)/6.0f;
a[3] = (p1.x + 4.0f*p2.x + p3.x)/6.0f;
b[0] = (-p1.y + 3.0f*p2.y - 3.0f*p3.y + p4.y)/6.0f;
b[1] = (3.0f*p1.y - 6.0f*p2.y + 3.0f*p3.y)/6.0f;
b[2] = (-3.0f*p1.y + 3.0f*p3.y)/6.0f;
b[3] = (p1.y + 4.0f*p2.y + p3.y)/6.0f;
currentPoint.x = a[3];
currentPoint.y = b[3];
if (i == 0) DrawCircleV(currentPoint, thick/2.0f, color); // Draw init line circle-cap
if (i > 0)
{
vertices[0].x = currentPoint.x + dy*size;
vertices[0].y = currentPoint.y - dx*size;
vertices[1].x = currentPoint.x - dy*size;
vertices[1].y = currentPoint.y + dx*size;
}
for (int j = 1; j <= SPLINE_SEGMENT_DIVISIONS; j++)
{
t = ((float)j)/((float)SPLINE_SEGMENT_DIVISIONS);
nextPoint.x = a[3] + t*(a[2] + t*(a[1] + t*a[0]));
nextPoint.y = b[3] + t*(b[2] + t*(b[1] + t*b[0]));
dy = nextPoint.y - currentPoint.y;
dx = nextPoint.x - currentPoint.x;
size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
if ((i == 0) && (j == 1))
{
vertices[0].x = currentPoint.x + dy*size;
vertices[0].y = currentPoint.y - dx*size;
vertices[1].x = currentPoint.x - dy*size;
vertices[1].y = currentPoint.y + dx*size;
}
vertices[2*j + 1].x = nextPoint.x - dy*size;
vertices[2*j + 1].y = nextPoint.y + dx*size;
vertices[2*j].x = nextPoint.x + dy*size;
vertices[2*j].y = nextPoint.y - dx*size;
currentPoint = nextPoint;
}
DrawTriangleStrip(vertices, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
}
DrawCircleV(currentPoint, thick/2.0f, color); // Draw end line circle-cap
}
// Draw spline: Catmull-Rom, minimum 4 points
void DrawSplineCatmullRom(Vector2 *points, int pointCount, float thick, Color color)
{
if (pointCount < 4) return;
float dy = 0.0f;
float dx = 0.0f;
float size = 0.0f;
Vector2 currentPoint = points[1];
Vector2 nextPoint = { 0 };
Vector2 vertices[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
DrawCircleV(currentPoint, thick/2.0f, color); // Draw init line circle-cap
for (int i = 0; i < (pointCount - 3); i++)
{
float t = 0.0f;
Vector2 p1 = points[i], p2 = points[i + 1], p3 = points[i + 2], p4 = points[i + 3];
if (i > 0)
{
vertices[0].x = currentPoint.x + dy*size;
vertices[0].y = currentPoint.y - dx*size;
vertices[1].x = currentPoint.x - dy*size;
vertices[1].y = currentPoint.y + dx*size;
}
for (int j = 1; j <= SPLINE_SEGMENT_DIVISIONS; j++)
{
t = ((float)j)/((float)SPLINE_SEGMENT_DIVISIONS);
float q0 = (-1.0f*t*t*t) + (2.0f*t*t) + (-1.0f*t);
float q1 = (3.0f*t*t*t) + (-5.0f*t*t) + 2.0f;
float q2 = (-3.0f*t*t*t) + (4.0f*t*t) + t;
float q3 = t*t*t - t*t;
nextPoint.x = 0.5f*((p1.x*q0) + (p2.x*q1) + (p3.x*q2) + (p4.x*q3));
nextPoint.y = 0.5f*((p1.y*q0) + (p2.y*q1) + (p3.y*q2) + (p4.y*q3));
dy = nextPoint.y - currentPoint.y;
dx = nextPoint.x - currentPoint.x;
size = (0.5f*thick)/sqrtf(dx*dx + dy*dy);
if ((i == 0) && (j == 1))
{
vertices[0].x = currentPoint.x + dy*size;
vertices[0].y = currentPoint.y - dx*size;
vertices[1].x = currentPoint.x - dy*size;
vertices[1].y = currentPoint.y + dx*size;
}
vertices[2*j + 1].x = nextPoint.x - dy*size;
vertices[2*j + 1].y = nextPoint.y + dx*size;
vertices[2*j].x = nextPoint.x + dy*size;
vertices[2*j].y = nextPoint.y - dx*size;
currentPoint = nextPoint;
}
DrawTriangleStrip(vertices, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
}
DrawCircleV(currentPoint, thick/2.0f, color); // Draw end line circle-cap
}
// Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...]
void DrawSplineBezierQuadratic(Vector2 *points, int pointCount, float thick, Color color)
{
if (pointCount < 3) return;
for (int i = 0; i < pointCount - 2; i++)
{
DrawSplineSegmentBezierQuadratic(points[i], points[i + 1], points[i + 2], thick, color);
}
}
// Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...]
void DrawSplineBezierCubic(Vector2 *points, int pointCount, float thick, Color color)
{
if (pointCount < 4) return;
for (int i = 0; i < pointCount - 3; i++)
{
DrawSplineSegmentBezierCubic(points[i], points[i + 1], points[i + 2], points[i + 3], thick, color);
}
}
// Draw spline segment: Linear, 2 points
void DrawSplineSegmentLinear(Vector2 p1, Vector2 p2, float thick, Color color)
{
// NOTE: For the linear spline we don't use subdivisions, just a single quad
Vector2 delta = { p2.x - p1.x, p2.y - p1.y };
float length = sqrtf(delta.x*delta.x + delta.y*delta.y);
if ((length > 0) && (thick > 0))
{
float scale = thick/(2*length);
Vector2 radius = { -scale*delta.y, scale*delta.x };
Vector2 strip[4] = {
{ p1.x - radius.x, p1.y - radius.y },
{ p1.x + radius.x, p1.y + radius.y },
{ p2.x - radius.x, p2.y - radius.y },
{ p2.x + radius.x, p2.y + radius.y }
};
DrawTriangleStrip(strip, 4, color);
}
}
// Draw spline segment: B-Spline, 4 points
void DrawSplineSegmentBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color)
{
const float step = 1.0f/SPLINE_SEGMENT_DIVISIONS;
Vector2 currentPoint = { 0 };
Vector2 nextPoint = { 0 };
float t = 0.0f;
Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
float a[4] = { 0 };
float b[4] = { 0 };
a[0] = (-p1.x + 3*p2.x - 3*p3.x + p4.x)/6.0f;
a[1] = (3*p1.x - 6*p2.x + 3*p3.x)/6.0f;
a[2] = (-3*p1.x + 3*p3.x)/6.0f;
a[3] = (p1.x + 4*p2.x + p3.x)/6.0f;
b[0] = (-p1.y + 3*p2.y - 3*p3.y + p4.y)/6.0f;
b[1] = (3*p1.y - 6*p2.y + 3*p3.y)/6.0f;
b[2] = (-3*p1.y + 3*p3.y)/6.0f;
b[3] = (p1.y + 4*p2.y + p3.y)/6.0f;
currentPoint.x = a[3];
currentPoint.y = b[3];
for (int i = 0; i <= SPLINE_SEGMENT_DIVISIONS; i++)
{
t = step*(float)i;
nextPoint.x = a[3] + t*(a[2] + t*(a[1] + t*a[0]));
nextPoint.y = b[3] + t*(b[2] + t*(b[1] + t*b[0]));
float dy = nextPoint.y - currentPoint.y;
float dx = nextPoint.x - currentPoint.x;
float size = (0.5f*thick)/sqrtf(dx*dx + dy*dy);
if (i == 1)
{
points[0].x = currentPoint.x + dy*size;
points[0].y = currentPoint.y - dx*size;
points[1].x = currentPoint.x - dy*size;
points[1].y = currentPoint.y + dx*size;
}
points[2*i + 1].x = nextPoint.x - dy*size;
points[2*i + 1].y = nextPoint.y + dx*size;
points[2*i].x = nextPoint.x + dy*size;
points[2*i].y = nextPoint.y - dx*size;
currentPoint = nextPoint;
}
DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS+2, color);
}
// Draw spline segment: Catmull-Rom, 4 points
void DrawSplineSegmentCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color)
{
const float step = 1.0f/SPLINE_SEGMENT_DIVISIONS;
Vector2 currentPoint = p1;
Vector2 nextPoint = { 0 };
float t = 0.0f;
Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
for (int i = 0; i <= SPLINE_SEGMENT_DIVISIONS; i++)
{
t = step*(float)i;
float q0 = (-1*t*t*t) + (2*t*t) + (-1*t);
float q1 = (3*t*t*t) + (-5*t*t) + 2;
float q2 = (-3*t*t*t) + (4*t*t) + t;
float q3 = t*t*t - t*t;
nextPoint.x = 0.5f*((p1.x*q0) + (p2.x*q1) + (p3.x*q2) + (p4.x*q3));
nextPoint.y = 0.5f*((p1.y*q0) + (p2.y*q1) + (p3.y*q2) + (p4.y*q3));
float dy = nextPoint.y - currentPoint.y;
float dx = nextPoint.x - currentPoint.x;
float size = (0.5f*thick)/sqrtf(dx*dx + dy*dy);
if (i == 1)
{
points[0].x = currentPoint.x + dy*size;
points[0].y = currentPoint.y - dx*size;
points[1].x = currentPoint.x - dy*size;
points[1].y = currentPoint.y + dx*size;
}
points[2*i + 1].x = nextPoint.x - dy*size;
points[2*i + 1].y = nextPoint.y + dx*size;
points[2*i].x = nextPoint.x + dy*size;
points[2*i].y = nextPoint.y - dx*size;
currentPoint = nextPoint;
}
DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
}
// Draw spline segment: Quadratic Bezier, 2 points, 1 control point
void DrawSplineSegmentBezierQuadratic(Vector2 p1, Vector2 c2, Vector2 p3, float thick, Color color)
{
const float step = 1.0f/SPLINE_SEGMENT_DIVISIONS;
Vector2 previous = p1;
Vector2 current = { 0 };
float t = 0.0f;
Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
for (int i = 1; i <= SPLINE_SEGMENT_DIVISIONS; i++)
{
t = step*(float)i;
float a = powf(1.0f - t, 2);
float b = 2.0f*(1.0f - t)*t;
float c = powf(t, 2);
// NOTE: The easing functions aren't suitable here because they don't take a control point
current.y = a*p1.y + b*c2.y + c*p3.y;
current.x = a*p1.x + b*c2.x + c*p3.x;
float dy = current.y - previous.y;
float dx = current.x - previous.x;
float size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
if (i == 1)
{
points[0].x = previous.x + dy*size;
points[0].y = previous.y - dx*size;
points[1].x = previous.x - dy*size;
points[1].y = previous.y + dx*size;
}
points[2*i + 1].x = current.x - dy*size;
points[2*i + 1].y = current.y + dx*size;
points[2*i].x = current.x + dy*size;
points[2*i].y = current.y - dx*size;
previous = current;
}
DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
}
// Draw spline segment: Cubic Bezier, 2 points, 2 control points
void DrawSplineSegmentBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float thick, Color color)
{
const float step = 1.0f/SPLINE_SEGMENT_DIVISIONS;
Vector2 previous = p1;
Vector2 current = { 0 };
float t = 0.0f;
Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
for (int i = 1; i <= SPLINE_SEGMENT_DIVISIONS; i++)
{
t = step*(float)i;
float a = powf(1.0f - t, 3);
float b = 3.0f*powf(1.0f - t, 2)*t;
float c = 3.0f*(1.0f - t)*powf(t, 2);
float d = powf(t, 3);
current.y = a*p1.y + b*c2.y + c*c3.y + d*p4.y;
current.x = a*p1.x + b*c2.x + c*c3.x + d*p4.x;
float dy = current.y - previous.y;
float dx = current.x - previous.x;
float size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
if (i == 1)
{
points[0].x = previous.x + dy*size;
points[0].y = previous.y - dx*size;
points[1].x = previous.x - dy*size;
points[1].y = previous.y + dx*size;
}
points[2*i + 1].x = current.x - dy*size;
points[2*i + 1].y = current.y + dx*size;
points[2*i].x = current.x + dy*size;
points[2*i].y = current.y - dx*size;
previous = current;
}
DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
}
// Get spline point for a given t [0.0f .. 1.0f], Linear
Vector2 GetSplinePointLinear(Vector2 startPos, Vector2 endPos, float t)
{
Vector2 point = { 0 };
point.x = startPos.x*(1.0f - t) + endPos.x*t;
point.y = startPos.y*(1.0f - t) + endPos.y*t;
return point;
}
// Get spline point for a given t [0.0f .. 1.0f], B-Spline
Vector2 GetSplinePointBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t)
{
Vector2 point = { 0 };
float a[4] = { 0 };
float b[4] = { 0 };
a[0] = (-p1.x + 3*p2.x - 3*p3.x + p4.x)/6.0f;
a[1] = (3*p1.x - 6*p2.x + 3*p3.x)/6.0f;
a[2] = (-3*p1.x + 3*p3.x)/6.0f;
a[3] = (p1.x + 4*p2.x + p3.x)/6.0f;
b[0] = (-p1.y + 3*p2.y - 3*p3.y + p4.y)/6.0f;
b[1] = (3*p1.y - 6*p2.y + 3*p3.y)/6.0f;
b[2] = (-3*p1.y + 3*p3.y)/6.0f;
b[3] = (p1.y + 4*p2.y + p3.y)/6.0f;
point.x = a[3] + t*(a[2] + t*(a[1] + t*a[0]));
point.y = b[3] + t*(b[2] + t*(b[1] + t*b[0]));
return point;
}
// Get spline point for a given t [0.0f .. 1.0f], Catmull-Rom
Vector2 GetSplinePointCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t)
{
Vector2 point = { 0 };
float q0 = (-1*t*t*t) + (2*t*t) + (-1*t);
float q1 = (3*t*t*t) + (-5*t*t) + 2;
float q2 = (-3*t*t*t) + (4*t*t) + t;
float q3 = t*t*t - t*t;
point.x = 0.5f*((p1.x*q0) + (p2.x*q1) + (p3.x*q2) + (p4.x*q3));
point.y = 0.5f*((p1.y*q0) + (p2.y*q1) + (p3.y*q2) + (p4.y*q3));
return point;
}
// Get spline point for a given t [0.0f .. 1.0f], Quadratic Bezier
Vector2 GetSplinePointBezierQuad(Vector2 startPos, Vector2 controlPos, Vector2 endPos, float t)
{
Vector2 point = { 0 };
float a = powf(1.0f - t, 2);
float b = 2.0f*(1.0f - t)*t;
float c = powf(t, 2);
point.y = a*startPos.y + b*controlPos.y + c*endPos.y;
point.x = a*startPos.x + b*controlPos.x + c*endPos.x;
return point;
}
// Get spline point for a given t [0.0f .. 1.0f], Cubic Bezier
Vector2 GetSplinePointBezierCubic(Vector2 startPos, Vector2 startControlPos, Vector2 endControlPos, Vector2 endPos, float t)
{
Vector2 point = { 0 };
float a = powf(1.0f - t, 3);
float b = 3.0f*powf(1.0f - t, 2)*t;
float c = 3.0f*(1.0f - t)*powf(t, 2);
float d = powf(t, 3);
point.y = a*startPos.y + b*startControlPos.y + c*endControlPos.y + d*endPos.y;
point.x = a*startPos.x + b*startControlPos.x + c*endControlPos.x + d*endPos.x;
return point;
}
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition - Collision Detection functions // Module Functions Definition - Collision Detection functions
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------

View file

@ -59,6 +59,14 @@ func DrawLineEx(startPos, endPos Vector2, thick float32, col color.RGBA) {
C.DrawLineEx(*cstartPos, *cendPos, cthick, *ccolor) C.DrawLineEx(*cstartPos, *cendPos, cthick, *ccolor)
} }
// DrawLineStrip - Draw lines sequence
func DrawLineStrip(points []Vector2, pointCount int32, col color.RGBA) {
cpoints := (*C.Vector2)(unsafe.Pointer(&points[0]))
cpointCount := (C.int)(pointCount)
ccolor := colorCptr(col)
C.DrawLineStrip(cpoints, cpointCount, *ccolor)
}
// DrawLineBezier - Draw a line using cubic-bezier curves in-out // DrawLineBezier - Draw a line using cubic-bezier curves in-out
func DrawLineBezier(startPos, endPos Vector2, thick float32, col color.RGBA) { func DrawLineBezier(startPos, endPos Vector2, thick float32, col color.RGBA) {
cstartPos := startPos.cptr() cstartPos := startPos.cptr()
@ -68,53 +76,6 @@ func DrawLineBezier(startPos, endPos Vector2, thick float32, col color.RGBA) {
C.DrawLineBezier(*cstartPos, *cendPos, cthick, *ccolor) C.DrawLineBezier(*cstartPos, *cendPos, cthick, *ccolor)
} }
// DrawLineBezierQuad - Draw line using quadratic bezier curves with a control point
func DrawLineBezierQuad(startPos Vector2, endPos Vector2, controlPos Vector2, thick float32, col color.RGBA) {
cstartPos := startPos.cptr()
cendPos := endPos.cptr()
ccontrolPos := controlPos.cptr()
cthick := (C.float)(thick)
ccolor := colorCptr(col)
C.DrawLineBezierQuad(*cstartPos, *cendPos, *ccontrolPos, cthick, *ccolor)
}
// DrawLineBezierCubic - Draw line using cubic bezier curves with 2 contrl points
func DrawLineBezierCubic(startPos Vector2, endPos Vector2, startControlPos Vector2, endControlPos Vector2, thick float32, col color.RGBA) {
cstartPos := startPos.cptr()
cendPos := endPos.cptr()
cstartControlPos := startControlPos.cptr()
cendControlPos := endControlPos.cptr()
cthick := (C.float)(thick)
ccolor := colorCptr(col)
C.DrawLineBezierCubic(*cstartPos, *cendPos, *cstartControlPos, *cendControlPos, cthick, *ccolor)
}
// DrawLineBSpline - Draw a B-Spline line, minimum 4 points
func DrawLineBSpline(points []Vector2, pointCount int32, thick float32, col color.RGBA) {
cpoints := (*C.Vector2)(unsafe.Pointer(&points[0]))
cpointCount := (C.int)(pointCount)
cthick := (C.float)(thick)
ccolor := colorCptr(col)
C.DrawLineBSpline(cpoints, cpointCount, cthick, *ccolor)
}
// DrawLineCatmullRom - Draw a Catmull Rom spline line, minimum 4 points
func DrawLineCatmullRom(points []Vector2, pointCount int32, thick float32, col color.RGBA) {
cpoints := (*C.Vector2)(unsafe.Pointer(&points[0]))
cpointCount := (C.int)(pointCount)
cthick := (C.float)(thick)
ccolor := colorCptr(col)
C.DrawLineCatmullRom(cpoints, cpointCount, cthick, *ccolor)
}
// DrawLineStrip - Draw lines sequence
func DrawLineStrip(points []Vector2, pointCount int32, col color.RGBA) {
cpoints := (*C.Vector2)(unsafe.Pointer(&points[0]))
cpointCount := (C.int)(pointCount)
ccolor := colorCptr(col)
C.DrawLineStrip(cpoints, cpointCount, *ccolor)
}
// DrawCircle - Draw a color-filled circle // DrawCircle - Draw a color-filled circle
func DrawCircle(centerX, centerY int32, radius float32, col color.RGBA) { func DrawCircle(centerX, centerY int32, radius float32, col color.RGBA) {
ccenterX := (C.int)(centerX) ccenterX := (C.int)(centerX)

View file

@ -347,7 +347,7 @@ Image LoadImageSvg(const char *fileNameOrString, int width, int height)
(fileNameOrString[2] == 'v') && (fileNameOrString[2] == 'v') &&
(fileNameOrString[3] == 'g')) (fileNameOrString[3] == 'g'))
{ {
fileData = fileNameOrString; fileData = (unsigned char *)fileNameOrString;
isSvgStringValid = true; isSvgStringValid = true;
} }
} }