Update C sources
This commit is contained in:
parent
07d1374c41
commit
d0612c27b2
17 changed files with 2216 additions and 1053 deletions
400
raylib/external/cgltf.h
vendored
400
raylib/external/cgltf.h
vendored
|
@ -328,15 +328,6 @@ typedef struct cgltf_accessor_sparse
|
|||
cgltf_component_type indices_component_type;
|
||||
cgltf_buffer_view* values_buffer_view;
|
||||
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;
|
||||
|
||||
typedef struct cgltf_accessor
|
||||
|
@ -419,9 +410,6 @@ typedef struct cgltf_texture_view
|
|||
cgltf_float scale; /* equivalent to strength for occlusion_texture */
|
||||
cgltf_bool has_transform;
|
||||
cgltf_texture_transform transform;
|
||||
cgltf_extras extras;
|
||||
cgltf_size extensions_count;
|
||||
cgltf_extension* extensions;
|
||||
} cgltf_texture_view;
|
||||
|
||||
typedef struct cgltf_pbr_metallic_roughness
|
||||
|
@ -504,6 +492,13 @@ typedef struct cgltf_iridescence
|
|||
cgltf_texture_view iridescence_thickness_texture;
|
||||
} 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
|
||||
{
|
||||
char* name;
|
||||
|
@ -517,6 +512,7 @@ typedef struct cgltf_material
|
|||
cgltf_bool has_sheen;
|
||||
cgltf_bool has_emissive_strength;
|
||||
cgltf_bool has_iridescence;
|
||||
cgltf_bool has_anisotropy;
|
||||
cgltf_pbr_metallic_roughness pbr_metallic_roughness;
|
||||
cgltf_pbr_specular_glossiness pbr_specular_glossiness;
|
||||
cgltf_clearcoat clearcoat;
|
||||
|
@ -527,6 +523,7 @@ typedef struct cgltf_material
|
|||
cgltf_volume volume;
|
||||
cgltf_emissive_strength emissive_strength;
|
||||
cgltf_iridescence iridescence;
|
||||
cgltf_anisotropy anisotropy;
|
||||
cgltf_texture_view normal_texture;
|
||||
cgltf_texture_view occlusion_texture;
|
||||
cgltf_texture_view emissive_texture;
|
||||
|
@ -559,7 +556,6 @@ typedef struct cgltf_draco_mesh_compression {
|
|||
} cgltf_draco_mesh_compression;
|
||||
|
||||
typedef struct cgltf_mesh_gpu_instancing {
|
||||
cgltf_buffer_view* buffer_view;
|
||||
cgltf_attribute* attributes;
|
||||
cgltf_size attributes_count;
|
||||
} 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_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 */
|
||||
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
|
||||
}
|
||||
#endif
|
||||
|
@ -866,6 +880,7 @@ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras*
|
|||
|
||||
#ifdef CGLTF_IMPLEMENTATION
|
||||
|
||||
#include <assert.h> /* For assert */
|
||||
#include <string.h> /* For strncpy */
|
||||
#include <stdio.h> /* For fopen */
|
||||
#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 */
|
||||
#endif
|
||||
|
||||
#if CGLTF_VALIDATE_ENABLE_ASSERTS
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
/* JSMN_PARENT_LINKS is necessary to make parsing large structures linear in input size */
|
||||
#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);
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _MSC_VER
|
||||
__int64 length = _ftelli64(file);
|
||||
#else
|
||||
long length = ftell(file);
|
||||
|
@ -1144,7 +1155,7 @@ cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_s
|
|||
|
||||
json_chunk += GlbChunkHeaderSize;
|
||||
|
||||
const void* bin = 0;
|
||||
const void* bin = NULL;
|
||||
cgltf_size bin_size = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (!data)
|
||||
|
@ -1790,15 +1795,6 @@ void cgltf_free(cgltf_data* data)
|
|||
{
|
||||
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_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);
|
||||
|
||||
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_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);
|
||||
case cgltf_component_type_r_32u:
|
||||
return *((const uint32_t*) in);
|
||||
case cgltf_component_type_r_32f:
|
||||
return (cgltf_ssize)*((const float*) in);
|
||||
case cgltf_component_type_r_8:
|
||||
return *((const int8_t*) in);
|
||||
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);
|
||||
case cgltf_component_type_r_32u:
|
||||
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:
|
||||
return *((const uint8_t*) in);
|
||||
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;
|
||||
|
||||
// First pass: convert each element in the base accessor.
|
||||
cgltf_float* dest = out;
|
||||
cgltf_accessor dense = *accessor;
|
||||
dense.is_sparse = 0;
|
||||
for (cgltf_size index = 0; index < element_count; index++, dest += floats_per_element)
|
||||
if (accessor->buffer_view == NULL)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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.
|
||||
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* 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;
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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_NOMEM -2
|
||||
#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));
|
||||
++i;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = cgltf_skip_json(tokens, i+1);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "bufferView") == 0)
|
||||
else
|
||||
{
|
||||
++i;
|
||||
out_mesh_gpu_instancing->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk));
|
||||
++i;
|
||||
i = cgltf_skip_json(tokens, i+1);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
@ -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);
|
||||
++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
|
||||
{
|
||||
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);
|
||||
++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
|
||||
{
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
(void)options;
|
||||
|
||||
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
|
||||
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);
|
||||
++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)
|
||||
{
|
||||
++i;
|
||||
|
||||
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
if(out_texture_view->extensions)
|
||||
{
|
||||
return CGLTF_ERROR_JSON;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -3665,7 +3732,7 @@ static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const
|
|||
}
|
||||
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)
|
||||
|
@ -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)
|
||||
{
|
||||
i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk,
|
||||
&out_pbr->base_color_texture);
|
||||
i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->base_color_texture);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "metallicRoughnessTexture") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk,
|
||||
&out_pbr->metallic_roughness_texture);
|
||||
i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->metallic_roughness_texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -4128,6 +4193,47 @@ static int cgltf_parse_json_iridescence(cgltf_options* options, jsmntok_t const*
|
|||
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)
|
||||
{
|
||||
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;
|
||||
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
|
||||
{
|
||||
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_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)
|
||||
|
@ -6411,7 +6524,6 @@ static int cgltf_fixup_pointers(cgltf_data* data)
|
|||
|
||||
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)
|
||||
{
|
||||
CGLTF_PTRFIXUP_REQ(data->nodes[i].mesh_gpu_instancing.attributes[m].data, data->accessors, data->accessors_count);
|
||||
|
|
81
raylib/external/dr_flac.h
vendored
81
raylib/external/dr_flac.h
vendored
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
|
||||
dr_flac - v0.12.39 - 2022-09-17
|
||||
dr_flac - v0.12.42 - 2023-11-02
|
||||
|
||||
David Reid - mackron@gmail.com
|
||||
|
||||
|
@ -235,12 +235,12 @@ extern "C" {
|
|||
|
||||
#define DRFLAC_VERSION_MAJOR 0
|
||||
#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)
|
||||
|
||||
#include <stddef.h> /* For size_t. */
|
||||
|
||||
/* Sized types. */
|
||||
/* Sized Types */
|
||||
typedef signed char drflac_int8;
|
||||
typedef unsigned char drflac_uint8;
|
||||
typedef signed short drflac_int16;
|
||||
|
@ -273,7 +273,9 @@ typedef drflac_uint8 drflac_bool8;
|
|||
typedef drflac_uint32 drflac_bool32;
|
||||
#define DRFLAC_TRUE 1
|
||||
#define DRFLAC_FALSE 0
|
||||
/* End Sized Types */
|
||||
|
||||
/* Decorations */
|
||||
#if !defined(DRFLAC_API)
|
||||
#if defined(DRFLAC_DLL)
|
||||
#if defined(_WIN32)
|
||||
|
@ -303,6 +305,7 @@ typedef drflac_uint32 drflac_bool32;
|
|||
#define DRFLAC_PRIVATE static
|
||||
#endif
|
||||
#endif
|
||||
/* End Decorations */
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1700 /* Visual Studio 2012 */
|
||||
#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 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,
|
||||
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
|
||||
#endif
|
||||
|
||||
/* Check if we can enable 64-bit optimizations. */
|
||||
|
||||
/* Architecture Detection */
|
||||
#if defined(_WIN64) || defined(_LP64) || defined(__LP64__)
|
||||
#define DRFLAC_64BIT
|
||||
#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
|
||||
typedef drflac_uint64 drflac_cache_t;
|
||||
#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 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. */
|
||||
typedef struct
|
||||
{
|
||||
|
@ -1351,6 +1367,7 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Inline */
|
||||
#ifdef _MSC_VER
|
||||
#define DRFLAC_INLINE __forceinline
|
||||
#elif defined(__GNUC__)
|
||||
|
@ -1377,15 +1394,7 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
|
|||
#else
|
||||
#define DRFLAC_INLINE
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
/* End Inline */
|
||||
|
||||
/*
|
||||
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. */
|
||||
|
||||
/* Result Codes */
|
||||
typedef drflac_int32 drflac_result;
|
||||
#define DRFLAC_SUCCESS 0
|
||||
#define DRFLAC_ERROR -1 /* A generic error. */
|
||||
|
@ -1678,7 +1688,10 @@ typedef drflac_int32 drflac_result;
|
|||
#define DRFLAC_CANCELLED -51
|
||||
#define DRFLAC_MEMORY_ALREADY_MAPPED -52
|
||||
#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_VERBATIM 1
|
||||
|
@ -1838,7 +1851,7 @@ static DRFLAC_INLINE drflac_uint32 drflac__swap_endian_uint32(drflac_uint32 n)
|
|||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
return _byteswap_ulong(n);
|
||||
#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(). */
|
||||
drflac_uint32 r;
|
||||
__asm__ __volatile__ (
|
||||
|
@ -2802,7 +2815,7 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x)
|
|||
|
||||
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;
|
||||
__asm__ __volatile__ (
|
||||
|
@ -6479,7 +6492,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
|
|||
for (;;) {
|
||||
drflac_metadata metadata;
|
||||
drflac_uint8 isLastBlock = 0;
|
||||
drflac_uint8 blockType;
|
||||
drflac_uint8 blockType = 0;
|
||||
drflac_uint32 blockSize;
|
||||
if (drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == 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() */
|
||||
#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. */
|
||||
#include <errno.h>
|
||||
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;
|
||||
}
|
||||
}
|
||||
/* End Errno */
|
||||
|
||||
/* fopen */
|
||||
static drflac_result drflac_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
|
||||
{
|
||||
#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;
|
||||
}
|
||||
#endif
|
||||
/* End fopen */
|
||||
|
||||
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 */
|
||||
|
||||
/* SIZE_MAX */
|
||||
#if defined(SIZE_MAX)
|
||||
#define DRFLAC_SIZE_MAX SIZE_MAX
|
||||
#else
|
||||
|
@ -11675,6 +11693,7 @@ DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 p
|
|||
#define DRFLAC_SIZE_MAX 0xFFFFFFFF
|
||||
#endif
|
||||
#endif
|
||||
/* End SIZE_MAX */
|
||||
|
||||
|
||||
/* 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
|
||||
================
|
||||
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
|
||||
- Fix compilation with DJGPP.
|
||||
- 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
|
||||
===============================================================================
|
||||
Copyright 2020 David Reid
|
||||
Copyright 2023 David Reid
|
||||
|
||||
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
|
||||
|
|
61
raylib/external/dr_mp3.h
vendored
61
raylib/external/dr_mp3.h
vendored
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
MP3 audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
|
||||
dr_mp3 - v0.6.34 - 2022-09-17
|
||||
dr_mp3 - v0.6.38 - 2023-11-02
|
||||
|
||||
David Reid - mackron@gmail.com
|
||||
|
||||
|
@ -95,12 +95,12 @@ extern "C" {
|
|||
|
||||
#define DRMP3_VERSION_MAJOR 0
|
||||
#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)
|
||||
|
||||
#include <stddef.h> /* For size_t. */
|
||||
|
||||
/* Sized types. */
|
||||
/* Sized Types */
|
||||
typedef signed char drmp3_int8;
|
||||
typedef unsigned char drmp3_uint8;
|
||||
typedef signed short drmp3_int16;
|
||||
|
@ -133,7 +133,9 @@ typedef drmp3_uint8 drmp3_bool8;
|
|||
typedef drmp3_uint32 drmp3_bool32;
|
||||
#define DRMP3_TRUE 1
|
||||
#define DRMP3_FALSE 0
|
||||
/* End Sized Types */
|
||||
|
||||
/* Decorations */
|
||||
#if !defined(DRMP3_API)
|
||||
#if defined(DRMP3_DLL)
|
||||
#if defined(_WIN32)
|
||||
|
@ -163,7 +165,9 @@ typedef drmp3_uint32 drmp3_bool32;
|
|||
#define DRMP3_PRIVATE static
|
||||
#endif
|
||||
#endif
|
||||
/* End Decorations */
|
||||
|
||||
/* Result Codes */
|
||||
typedef drmp3_int32 drmp3_result;
|
||||
#define DRMP3_SUCCESS 0
|
||||
#define DRMP3_ERROR -1 /* A generic error. */
|
||||
|
@ -219,11 +223,12 @@ typedef drmp3_int32 drmp3_result;
|
|||
#define DRMP3_CANCELLED -51
|
||||
#define DRMP3_MEMORY_ALREADY_MAPPED -52
|
||||
#define DRMP3_AT_END -53
|
||||
|
||||
/* End Result Codes */
|
||||
|
||||
#define DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME 1152
|
||||
#define DRMP3_MAX_SAMPLES_PER_FRAME (DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME*2)
|
||||
|
||||
/* Inline */
|
||||
#ifdef _MSC_VER
|
||||
#define DRMP3_INLINE __forceinline
|
||||
#elif defined(__GNUC__)
|
||||
|
@ -250,12 +255,24 @@ typedef drmp3_int32 drmp3_result;
|
|||
#else
|
||||
#define DRMP3_INLINE
|
||||
#endif
|
||||
/* End Inline */
|
||||
|
||||
|
||||
DRMP3_API void drmp3_version(drmp3_uint32* pMajor, drmp3_uint32* pMinor, drmp3_uint32* pRevision);
|
||||
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
|
||||
==================
|
||||
|
@ -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 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
|
||||
{
|
||||
drmp3_uint32 channels;
|
||||
|
@ -704,7 +713,7 @@ static int drmp3_have_simd(void)
|
|||
|
||||
#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
|
||||
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
|
||||
|
||||
************************************************************************************************************************************************************/
|
||||
/* SIZE_MAX */
|
||||
#if defined(SIZE_MAX)
|
||||
#define DRMP3_SIZE_MAX SIZE_MAX
|
||||
#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
|
||||
#endif
|
||||
#endif
|
||||
/* End SIZE_MAX */
|
||||
|
||||
/* Options. */
|
||||
#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->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. */
|
||||
|
||||
/* 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 <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. */
|
||||
#include <errno.h>
|
||||
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;
|
||||
}
|
||||
}
|
||||
/* End Errno */
|
||||
|
||||
/* fopen */
|
||||
static drmp3_result drmp3_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
|
||||
{
|
||||
#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;
|
||||
}
|
||||
|
||||
/* End fopen */
|
||||
|
||||
|
||||
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
|
||||
================
|
||||
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
|
||||
- Fix compilation with DJGPP.
|
||||
- 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
|
||||
===============================================================================
|
||||
Copyright 2020 David Reid
|
||||
Copyright 2023 David Reid
|
||||
|
||||
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
|
||||
|
|
1311
raylib/external/dr_wav.h
vendored
1311
raylib/external/dr_wav.h
vendored
File diff suppressed because it is too large
Load diff
40
raylib/external/m3d.h
vendored
40
raylib/external/m3d.h
vendored
|
@ -89,7 +89,7 @@ typedef uint8_t M3D_VOXEL;
|
|||
#define M3D_NUMBONE 4
|
||||
#endif
|
||||
#ifndef M3D_BONEMAXLEVEL
|
||||
#define M3D_BONEMAXLEVEL 8
|
||||
#define M3D_BONEMAXLEVEL 64
|
||||
#endif
|
||||
#ifndef _MSC_VER
|
||||
#ifndef _inline
|
||||
|
@ -2172,6 +2172,8 @@ M3D_INDEX _m3d_gettx(m3d_t *model, m3dread_t readfilecb, m3dfree_t freecb, char
|
|||
stbi__context s;
|
||||
stbi__result_info ri;
|
||||
|
||||
/* failsafe */
|
||||
if(!fn || !*fn) return M3D_UNDEF;
|
||||
/* do we have loaded this texture already? */
|
||||
for(i = 0; i < model->numtexture; 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
|
||||
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++)
|
||||
if(!strcmp(fn, model->inlined[i].name)) {
|
||||
buff = model->inlined[i].data;
|
||||
|
@ -3439,6 +3441,7 @@ memerr: M3D_LOG("Out of memory");
|
|||
model->bone[i].numweight = 0;
|
||||
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 */
|
||||
if(model->numskin) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
if(i != model->numskin) { M3D_LOG("Truncated skin in bone chunk"); model->numskin = i; model->errcode = M3D_ERR_BONE; }
|
||||
}
|
||||
} else
|
||||
/* 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 int i, j, k, l, n, o, len, chunklen, *length;
|
||||
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;
|
||||
#ifdef M3D_VERTEXMAX
|
||||
M3D_INDEX lastp;
|
||||
#endif
|
||||
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;
|
||||
uint8_t *opa;
|
||||
uint8_t *opa = NULL;
|
||||
m3dcd_t *cd;
|
||||
m3dc_t *cmd;
|
||||
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++) {
|
||||
if(skinidx[i] == M3D_UNDEF) continue;
|
||||
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 &&
|
||||
model->skin[i].weight[j] > (M3D_FLOAT)0.0; j++) {
|
||||
for(j = 0, min_x = (M3D_FLOAT)0.0; j < M3D_NUMBONE && model->skin[i].boneid[j] != M3D_UNDEF; 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];
|
||||
}
|
||||
if(j > maxbone) maxbone = j;
|
||||
|
@ -5191,6 +5194,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx);
|
|||
if(sa) M3D_FREE(sa);
|
||||
if(sd) M3D_FREE(sd);
|
||||
if(out) M3D_FREE(out);
|
||||
if(opa) free(opa);
|
||||
if(h) M3D_FREE(h);
|
||||
M3D_LOG("Out of memory");
|
||||
model->errcode = M3D_ERR_ALLOC;
|
||||
|
@ -5218,8 +5222,16 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx);
|
|||
if(model->preview.data && model->preview.length) {
|
||||
sl = _m3d_safestr(sn, 0);
|
||||
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));
|
||||
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; }
|
||||
ptr += sprintf(ptr, "Preview\r\n%s.png\r\n\r\n", sl);
|
||||
M3D_FREE(sl); sl = NULL;
|
||||
|
@ -5228,6 +5240,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx);
|
|||
M3D_FREE(sn); sn = NULL;
|
||||
/* texture map */
|
||||
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);
|
||||
out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out;
|
||||
if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; }
|
||||
|
@ -5846,9 +5859,13 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx);
|
|||
if(skin[i].newidx == last) continue;
|
||||
last = skin[i].newidx;
|
||||
memset(&weights, 0, nb_s);
|
||||
for(j = 0; j < (uint32_t)nb_s && skin[i].data.boneid[j] != M3D_UNDEF &&
|
||||
skin[i].data.weight[j] > (M3D_FLOAT)0.0; j++)
|
||||
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++) {
|
||||
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);
|
||||
if(!weights[j]) { weights[j]++; l--; }
|
||||
}
|
||||
weights[k] += l;
|
||||
switch(nb_s) {
|
||||
case 1: weights[0] = 255; break;
|
||||
case 2: memcpy(out, weights, 2); out += 2; break;
|
||||
|
@ -5941,7 +5958,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx);
|
|||
}
|
||||
/* mesh face */
|
||||
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);
|
||||
if(!h) goto memerr;
|
||||
memcpy((uint8_t*)h + len, "MESH", 4);
|
||||
|
@ -6268,6 +6285,7 @@ memerr: if(vrtxidx) M3D_FREE(vrtxidx);
|
|||
if(skin) M3D_FREE(skin);
|
||||
if(str) M3D_FREE(str);
|
||||
if(vrtx) M3D_FREE(vrtx);
|
||||
if(opa) free(opa);
|
||||
if(h) M3D_FREE(h);
|
||||
return out;
|
||||
}
|
||||
|
|
22
raylib/external/miniaudio.h
vendored
22
raylib/external/miniaudio.h
vendored
|
@ -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.
|
||||
miniaudio - v0.11.19 - TBD
|
||||
miniaudio - v0.11.19 - 2023-11-04
|
||||
|
||||
David Reid - mackron@gmail.com
|
||||
|
||||
|
@ -7042,7 +7042,7 @@ struct ma_device_config
|
|||
ma_uint32 periods;
|
||||
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 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 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;
|
||||
|
@ -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.
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
noDisableDenormals
|
||||
|
@ -40464,7 +40464,7 @@ static ma_result ma_context_init__webaudio(ma_context* pContext, const ma_contex
|
|||
};
|
||||
|
||||
miniaudio.unlock_event_types = (function(){
|
||||
return ['touchstart', 'touchend', 'click'];
|
||||
return ['touchend', 'click'];
|
||||
})();
|
||||
|
||||
miniaudio.unlock = function() {
|
||||
|
@ -60158,7 +60158,7 @@ extern "C" {
|
|||
#define MA_DR_FLAC_XSTRINGIFY(x) MA_DR_FLAC_STRINGIFY(x)
|
||||
#define MA_DR_FLAC_VERSION_MAJOR 0
|
||||
#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)
|
||||
#include <stddef.h>
|
||||
#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_VERSION_MAJOR 0
|
||||
#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)
|
||||
#include <stddef.h>
|
||||
#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__)
|
||||
return _byteswap_ulong(n);
|
||||
#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;
|
||||
__asm__ __volatile__ (
|
||||
#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;
|
||||
}
|
||||
#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;
|
||||
__asm__ __volatile__ (
|
||||
|
@ -85869,7 +85869,7 @@ static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRea
|
|||
for (;;) {
|
||||
ma_dr_flac_metadata metadata;
|
||||
ma_uint8 isLastBlock = 0;
|
||||
ma_uint8 blockType;
|
||||
ma_uint8 blockType = 0;
|
||||
ma_uint32 blockSize;
|
||||
if (ma_dr_flac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == MA_FALSE) {
|
||||
return MA_FALSE;
|
||||
|
@ -89949,7 +89949,7 @@ static int ma_dr_mp3_have_simd(void)
|
|||
#else
|
||||
#define MA_DR_MP3_HAVE_SIMD 0
|
||||
#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
|
||||
static __inline__ __attribute__((always_inline)) ma_int32 ma_dr_mp3_clip_int16_arm(ma_int32 a)
|
||||
{
|
||||
|
|
170
raylib/external/qoa.h
vendored
170
raylib/external/qoa.h
vendored
|
@ -8,71 +8,96 @@ QOA - The "Quite OK Audio" format for fast, lossy audio compression
|
|||
|
||||
-- Data Format
|
||||
|
||||
A QOA file has an 8 byte file header, followed by a number of frames. Each frame
|
||||
consists of an 8 byte frame header, the current 8 byte en-/decoder state per
|
||||
channel and 256 slices per channel. Each slice is 8 bytes wide and encodes 20
|
||||
samples of audio data.
|
||||
QOA encodes pulse-code modulated (PCM) audio data with up to 255 channels,
|
||||
sample rates from 1 up to 16777215 hertz and a bit depth of 16 bits.
|
||||
|
||||
Note that the last frame of a file may contain less than 256 slices per channel.
|
||||
The last slice (per channel) in the last frame may contain less 20 samples, but
|
||||
the slice will still be 8 bytes wide, with the unused samples zeroed out.
|
||||
The compression method employed in QOA is lossy; it discards some information
|
||||
from the uncompressed PCM data. For many types of audio signals this compression
|
||||
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
|
||||
not in the file header. A decoder may peek into the first frame of the file to
|
||||
find these values.
|
||||
QOA encodes 20 samples of 16 bit PCM data into slices of 64 bits. A single
|
||||
sample therefore requires 3.2 bits of storage space, resulting in a 5x
|
||||
compression (16 / 3.2).
|
||||
|
||||
In a valid QOA file all frames have the same number of channels and the same
|
||||
samplerate. These restrictions may be relaxed for streaming. This remains to
|
||||
be decided.
|
||||
A QOA file consists of an 8 byte file header, followed by a number of frames.
|
||||
Each frame contains an 8 byte frame header, the current 16 byte en-/decoder
|
||||
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,
|
||||
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:
|
||||
All values, including the slices, are big endian. The file layout is as follows:
|
||||
|
||||
struct {
|
||||
struct {
|
||||
char magic[4]; // magic bytes 'qoaf'
|
||||
uint32_t samples; // number of samples per channel in this file
|
||||
} file_header; // = 64 bits
|
||||
char magic[4]; // magic bytes "qoaf"
|
||||
uint32_t samples; // samples per channel in this file
|
||||
} file_header;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
uint8_t num_channels; // number of channels
|
||||
uint8_t num_channels; // no. of channels
|
||||
uint24_t samplerate; // samplerate in hz
|
||||
uint16_t fsamples; // sample count per channel in this frame
|
||||
uint16_t fsize; // frame size (including the frame header)
|
||||
} frame_header; // = 64 bits
|
||||
uint16_t fsamples; // samples per channel in this frame
|
||||
uint16_t fsize; // frame size (includes this header)
|
||||
} frame_header;
|
||||
|
||||
struct {
|
||||
int16_t history[4]; // = 64 bits
|
||||
int16_t weights[4]; // = 64 bits
|
||||
int16_t history[4]; // most recent last
|
||||
int16_t weights[4]; // most recent last
|
||||
} lms_state[num_channels];
|
||||
|
||||
qoa_slice_t slices[256][num_channels]; // = 64 bits each
|
||||
} frames[samples * channels / qoa_max_framesize()];
|
||||
} qoa_file;
|
||||
qoa_slice_t slices[256][num_channels];
|
||||
|
||||
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 --------------------------/ /------------.
|
||||
| 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 |
|
||||
|------------+--------+--------+--------+---------+---------+-\ \--+---------|
|
||||
| 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
|
||||
qoa_scalefactor_tab[16]
|
||||
Each frame except the last must contain exactly 256 slices per channel. The last
|
||||
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
|
||||
scalefactor and quantized by the qoa_quant_tab[].
|
||||
Channels are interleaved per slice. E.g. for 2 channel stereo:
|
||||
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
|
||||
state (the last four output samples) with the predictor. The residual from the
|
||||
slice is then dequantized using the qoa_dequant_tab[] and added to the
|
||||
prediction. The result is clamped to int16 to form the final output sample.
|
||||
A valid QOA file or stream must have at least one frame. Each frame must contain
|
||||
at least one channel and one sample with a samplerate between 1 .. 16777215
|
||||
(inclusive).
|
||||
|
||||
If the total number of samples is not known by the encoder, the samples in the
|
||||
file header may be set to 0x00000000 to indicate that the encoder is
|
||||
"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
|
||||
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 */
|
||||
0, /* 0 */
|
||||
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
|
||||
would need to encode the highest 16bit residual is (2**16)/8 = 8192. However we
|
||||
rely on the LMS filter to predict samples accurately enough that a maximum
|
||||
residual of one quarter of the 16 bit range is 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.
|
||||
|
||||
The scalefactor values are computed as:
|
||||
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
|
||||
};
|
||||
|
||||
|
@ -188,7 +213,7 @@ do this in .16 fixed point with integers, instead of floats.
|
|||
The reciprocal_tab is computed as:
|
||||
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
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
of the quant_tab indices and is computed as:
|
||||
float dqt[8] = {0.75, -0.75, 2.5, -2.5, 4.5, -4.5, 7, -7};
|
||||
dequant_tab[s][q] <- round(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},
|
||||
{ 5, -5, 18, -18, 32, -32, 49, -49},
|
||||
{ 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) {
|
||||
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) {
|
||||
|
@ -312,6 +355,7 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned
|
|||
unsigned int p = 0;
|
||||
unsigned int slices = (frame_len + QOA_SLICE_LEN - 1) / QOA_SLICE_LEN;
|
||||
unsigned int frame_size = QOA_FRAME_SIZE(channels, slices);
|
||||
int prev_scalefactor[QOA_MAX_CHANNELS] = {0};
|
||||
|
||||
/* Write the frame header */
|
||||
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
|
||||
), bytes, &p);
|
||||
|
||||
/* Write the current LMS state */
|
||||
|
||||
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 history = 0;
|
||||
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_slice;
|
||||
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
|
||||
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 quantized = qoa_quant_tab[clamped + 8];
|
||||
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);
|
||||
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_slice = slice;
|
||||
best_lms = lms;
|
||||
best_scalefactor = scalefactor;
|
||||
}
|
||||
}
|
||||
|
||||
prev_scalefactor[c] = best_scalefactor;
|
||||
|
||||
qoa->lms[c] = best_lms;
|
||||
#ifdef QOA_RECORD_TOTAL_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 quantized = (slice >> 57) & 0x7;
|
||||
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;
|
||||
slice <<= 3;
|
||||
|
|
12
raylib/external/qoi.h
vendored
12
raylib/external/qoi.h
vendored
|
@ -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) {
|
||||
FILE *f = fopen(filename, "wb");
|
||||
int size;
|
||||
int size, err;
|
||||
void *encoded;
|
||||
|
||||
if (!f) {
|
||||
|
@ -608,10 +608,12 @@ int qoi_write(const char *filename, const void *data, const qoi_desc *desc) {
|
|||
}
|
||||
|
||||
fwrite(encoded, 1, size, f);
|
||||
fflush(f);
|
||||
err = ferror(f);
|
||||
fclose(f);
|
||||
|
||||
QOI_FREE(encoded);
|
||||
return size;
|
||||
return err ? 0 : size;
|
||||
}
|
||||
|
||||
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);
|
||||
size = ftell(f);
|
||||
if (size <= 0) {
|
||||
if (size <= 0 || fseek(f, 0, SEEK_SET) != 0) {
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
data = QOI_MALLOC(size);
|
||||
if (!data) {
|
||||
|
@ -639,8 +640,7 @@ void *qoi_read(const char *filename, qoi_desc *desc, int channels) {
|
|||
|
||||
bytes_read = fread(data, 1, size, f);
|
||||
fclose(f);
|
||||
|
||||
pixels = qoi_decode(data, bytes_read, desc, channels);
|
||||
pixels = (bytes_read != size) ? NULL : qoi_decode(data, bytes_read, desc, channels);
|
||||
QOI_FREE(data);
|
||||
return pixels;
|
||||
}
|
||||
|
|
2
raylib/external/rl_gputex.h
vendored
2
raylib/external/rl_gputex.h
vendored
|
@ -1,6 +1,6 @@
|
|||
/**********************************************************************************************
|
||||
*
|
||||
* rl_gputex - GPU compressed textures loading and saving
|
||||
* rl_gputex v1.0 - GPU compressed textures loading and saving
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
|
|
6
raylib/external/rprand.h
vendored
6
raylib/external/rprand.h
vendored
|
@ -186,7 +186,7 @@ int *rprand_load_sequence(unsigned int count, int min, int max)
|
|||
{
|
||||
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");
|
||||
//count = (max - min);
|
||||
|
@ -198,9 +198,9 @@ int *rprand_load_sequence(unsigned int count, int min, int max)
|
|||
int value = 0;
|
||||
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;
|
||||
|
||||
for (int j = 0; j < i; j++)
|
||||
|
|
22
raylib/external/sinfl.h
vendored
22
raylib/external/sinfl.h
vendored
|
@ -122,6 +122,7 @@ extern "C" {
|
|||
|
||||
struct sinfl {
|
||||
const unsigned char *bitptr;
|
||||
const unsigned char *bitend; // @raysan5: added
|
||||
unsigned long long bitbuf;
|
||||
int bitcnt;
|
||||
|
||||
|
@ -185,9 +186,10 @@ sinfl_read64(const void *p) {
|
|||
}
|
||||
static void
|
||||
sinfl_copy64(unsigned char **dst, unsigned char **src) {
|
||||
unsigned long long n;
|
||||
memcpy(&n, *src, 8);
|
||||
memcpy(*dst, &n, 8);
|
||||
//unsigned long long n;
|
||||
//memcpy(&n, *src, 8);
|
||||
//memcpy(*dst, &n, 8);
|
||||
memcpy(*dst, *src, 8); // @raysan5
|
||||
*dst += 8, *src += 8;
|
||||
}
|
||||
static unsigned char*
|
||||
|
@ -210,9 +212,22 @@ sinfl_copy128(unsigned char **dst, unsigned char **src) {
|
|||
#endif
|
||||
static void
|
||||
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->bitptr += (63 - s->bitcnt) >> 3;
|
||||
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
|
||||
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;
|
||||
|
||||
s.bitptr = in;
|
||||
s.bitend = e; // @raysan5: added
|
||||
while (1) {
|
||||
switch (state) {
|
||||
case hdr: {
|
||||
|
|
|
@ -123,6 +123,9 @@ typedef struct {
|
|||
// 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
|
||||
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
|
||||
pthread_t gamepadThreadId; // Gamepad reading thread id
|
||||
|
@ -170,11 +173,6 @@ static const int EvkeyToUnicodeLUT[] = {
|
|||
// 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
|
||||
//----------------------------------------------------------------------------------
|
||||
|
@ -448,7 +446,7 @@ void EnableCursor(void)
|
|||
void DisableCursor(void)
|
||||
{
|
||||
// Set cursor position in the middle
|
||||
SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
|
||||
SetMousePosition(0, 0);
|
||||
|
||||
platform.cursorRelative = true;
|
||||
CORE.Input.Mouse.cursorHidden = true;
|
||||
|
@ -565,11 +563,8 @@ void PollInputEvents(void)
|
|||
PollKeyboardEvents();
|
||||
|
||||
// Register previous mouse position
|
||||
if (platform.cursorRelative)
|
||||
{
|
||||
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
||||
CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f };
|
||||
}
|
||||
if (platform.cursorRelative) CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f };
|
||||
else CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
||||
|
||||
// Register previous mouse states
|
||||
CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove;
|
||||
|
@ -600,15 +595,6 @@ void PollInputEvents(void)
|
|||
// Map touch position to mouse position for convenience
|
||||
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)
|
||||
// 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
|
||||
|
@ -618,6 +604,183 @@ void PollInputEvents(void)
|
|||
// 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()
|
||||
#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);
|
||||
worker->absRange.x = 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);
|
||||
worker->absRange.y = 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)
|
||||
|
@ -1400,9 +1568,14 @@ static void ConfigureEvdevDevice(char *device)
|
|||
ioctl(fd, EVIOCGABS(ABS_X), &absinfo);
|
||||
worker->absRange.x = 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);
|
||||
worker->absRange.y = 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->isTouch? "touchscreen " : "",
|
||||
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
|
||||
int error = pthread_create(&worker->threadId, NULL, &EventThread, (void *)worker);
|
||||
if (error != 0)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "RPI: Failed to create input device thread: %s (error: %d)", device, error);
|
||||
worker->threadId = 0;
|
||||
close(fd);
|
||||
}
|
||||
//int error = pthread_create(&worker->threadId, NULL, &EventThread, (void *)worker);
|
||||
//if (error != 0)
|
||||
//{
|
||||
// TRACELOG(LOG_WARNING, "RPI: Failed to create input device thread: %s (error: %d)", device, error);
|
||||
// worker->threadId = 0;
|
||||
// close(fd);
|
||||
//}
|
||||
|
||||
#if defined(USE_LAST_TOUCH_DEVICE)
|
||||
// Find touchscreen with the highest index
|
||||
|
@ -1570,6 +1748,7 @@ static void PollKeyboardEvents(void)
|
|||
// Input device events reading thread
|
||||
static void *EventThread(void *arg)
|
||||
{
|
||||
/*
|
||||
struct input_event event = { 0 };
|
||||
InputEventWorker *worker = (InputEventWorker *)arg;
|
||||
|
||||
|
@ -1731,7 +1910,7 @@ static void *EventThread(void *arg)
|
|||
#if defined(SUPPORT_GESTURES_SYSTEM)
|
||||
if (gestureUpdate)
|
||||
{
|
||||
//GestureEvent gestureEvent = { 0 };
|
||||
GestureEvent gestureEvent = { 0 };
|
||||
|
||||
gestureEvent.touchAction = touchAction;
|
||||
gestureEvent.pointCount = CORE.Input.Touch.pointCount;
|
||||
|
@ -1742,8 +1921,7 @@ static void *EventThread(void *arg)
|
|||
gestureEvent.position[i] = CORE.Input.Touch.position[i];
|
||||
}
|
||||
|
||||
//ProcessGestureEvent(gestureEvent);
|
||||
newGesture = true;
|
||||
ProcessGestureEvent(gestureEvent);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -1752,7 +1930,7 @@ static void *EventThread(void *arg)
|
|||
}
|
||||
|
||||
close(worker->fd);
|
||||
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 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 DrawLineV(Vector2 startPos, Vector2 endPos, Color color); // Draw a line (Vector version)
|
||||
RLAPI void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line defining thickness
|
||||
RLAPI void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line using cubic-bezier curves in-out
|
||||
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 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 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 (using triangles/quads)
|
||||
RLAPI void DrawLineStrip(Vector2 *points, int pointCount, Color color); // Draw lines sequence (using gl lines)
|
||||
RLAPI void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw line segment cubic-bezier in-out interpolation
|
||||
RLAPI void DrawCircle(int centerX, int centerY, float radius, Color color); // Draw a color-filled circle
|
||||
RLAPI void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw a piece of a circle
|
||||
RLAPI void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw circle sector outline
|
||||
|
@ -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 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
|
||||
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
|
||||
|
|
|
@ -189,7 +189,11 @@ __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigne
|
|||
#define MAX_FILEPATH_CAPACITY 8192 // Maximum capacity for filepath
|
||||
#endif
|
||||
#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
|
||||
|
||||
#ifndef MAX_KEYBOARD_KEYS
|
||||
|
@ -252,6 +256,7 @@ typedef struct CoreData {
|
|||
bool shouldClose; // Check if window set for closing
|
||||
bool resizedLastFrame; // Check if window has been resized last 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 previousPosition; // Window previous position (required on borderless windowed toggle)
|
||||
|
@ -1035,6 +1040,7 @@ void BeginTextureMode(RenderTexture2D target)
|
|||
// calculation when using BeginMode3D()
|
||||
CORE.Window.currentFbo.width = target.texture.width;
|
||||
CORE.Window.currentFbo.height = target.texture.height;
|
||||
CORE.Window.usingFbo = true;
|
||||
}
|
||||
|
||||
// Ends drawing to render texture
|
||||
|
@ -1050,6 +1056,7 @@ void EndTextureMode(void)
|
|||
// Reset current fbo to screen size
|
||||
CORE.Window.currentFbo.width = CORE.Window.render.width;
|
||||
CORE.Window.currentFbo.height = CORE.Window.render.height;
|
||||
CORE.Window.usingFbo = false;
|
||||
}
|
||||
|
||||
// Begin custom shader mode
|
||||
|
@ -1086,19 +1093,22 @@ void BeginScissorMode(int x, int y, int width, int height)
|
|||
rlEnableScissorTest();
|
||||
|
||||
#if defined(__APPLE__)
|
||||
if (CORE.Window.usingFbo)
|
||||
{
|
||||
Vector2 scale = GetWindowScaleDPI();
|
||||
rlScissor((int)(x*scale.x), (int)(GetScreenHeight()*scale.y - (((y + height)*scale.y))), (int)(width*scale.x), (int)(height*scale.y));
|
||||
}
|
||||
#else
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
if (CORE.Window.usingFbo && ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0))
|
||||
{
|
||||
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));
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
rlScissor(x, CORE.Window.currentFbo.height - (y + height), width, height);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// End scissor mode
|
||||
|
@ -2513,7 +2523,7 @@ bool ExportAutomationEventList(AutomationEventList list, const char *fileName)
|
|||
|
||||
// Add events data
|
||||
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,
|
||||
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) &&
|
||||
(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);
|
||||
#endif
|
||||
|
||||
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))
|
||||
{
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
if (IsPathFile(path))
|
||||
{
|
||||
|
|
850
raylib/rshapes.c
850
raylib/rshapes.c
|
@ -67,8 +67,8 @@
|
|||
#ifndef SMOOTH_CIRCLE_ERROR_RATE
|
||||
#define SMOOTH_CIRCLE_ERROR_RATE 0.5f // Circle error rate
|
||||
#endif
|
||||
#ifndef SPLINE_LINE_DIVISIONS
|
||||
#define SPLINE_LINE_DIVISIONS 24 // Spline lines segment divisions
|
||||
#ifndef SPLINE_SEGMENT_DIVISIONS
|
||||
#define SPLINE_SEGMENT_DIVISIONS 24 // Spline segment divisions
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -161,7 +161,7 @@ void DrawPixelV(Vector2 position, Color color)
|
|||
#endif
|
||||
}
|
||||
|
||||
// Draw a line
|
||||
// Draw a line (using gl lines)
|
||||
void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color)
|
||||
{
|
||||
rlBegin(RL_LINES);
|
||||
|
@ -171,7 +171,7 @@ void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color colo
|
|||
rlEnd();
|
||||
}
|
||||
|
||||
// Draw a line (Vector version)
|
||||
// Draw a line (using gl lines)
|
||||
void DrawLineV(Vector2 startPos, Vector2 endPos, Color color)
|
||||
{
|
||||
rlBegin(RL_LINES);
|
||||
|
@ -181,6 +181,61 @@ void DrawLineV(Vector2 startPos, Vector2 endPos, Color color)
|
|||
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
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// 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
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
|
@ -59,6 +59,14 @@ func DrawLineEx(startPos, endPos Vector2, thick float32, col color.RGBA) {
|
|||
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
|
||||
func DrawLineBezier(startPos, endPos Vector2, thick float32, col color.RGBA) {
|
||||
cstartPos := startPos.cptr()
|
||||
|
@ -68,53 +76,6 @@ func DrawLineBezier(startPos, endPos Vector2, thick float32, col color.RGBA) {
|
|||
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
|
||||
func DrawCircle(centerX, centerY int32, radius float32, col color.RGBA) {
|
||||
ccenterX := (C.int)(centerX)
|
||||
|
|
|
@ -347,7 +347,7 @@ Image LoadImageSvg(const char *fileNameOrString, int width, int height)
|
|||
(fileNameOrString[2] == 'v') &&
|
||||
(fileNameOrString[3] == 'g'))
|
||||
{
|
||||
fileData = fileNameOrString;
|
||||
fileData = (unsigned char *)fileNameOrString;
|
||||
isSvgStringValid = true;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue