summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOmni <omniscient.oce@gmail.com>2024-08-17 17:17:11 +1000
committerOmni <omniscient.oce@gmail.com>2024-08-17 17:17:11 +1000
commiteadfaaa86c29c36dd5ef5d0b6b6fa27af0cdb8b3 (patch)
treeaf18d90ba02d5e26dd6ca746154ce9df6d3b0327
parentcfd7266c21a43cbd37fa712725cea85cdd1f7aab (diff)
improving the way I load animation data and store it. Load -> Tick(Armature*) -> RenderEnt.Armature -> matrix shenanigans
-rw-r--r--deps/cgltf/cgltf.h413
-rw-r--r--examples/game_demo/game_demo.c20
-rw-r--r--examples/skinned_animation/ex_skinned_animation.c24
-rw-r--r--src/animation.c21
-rw-r--r--src/animation.h46
-rw-r--r--src/maths/primitives.c11
-rw-r--r--src/render/pbr.c22
-rw-r--r--src/render/render_types.h5
-rw-r--r--src/resources/gltf.c93
9 files changed, 392 insertions, 263 deletions
diff --git a/deps/cgltf/cgltf.h b/deps/cgltf/cgltf.h
index af24c65..36fd644 100644
--- a/deps/cgltf/cgltf.h
+++ b/deps/cgltf/cgltf.h
@@ -1,7 +1,7 @@
/**
* cgltf - a single-file glTF 2.0 parser written in C99.
*
- * Version: 1.13
+ * Version: 1.14
*
* Website: https://github.com/jkuhlmann/cgltf
*
@@ -63,9 +63,14 @@
* By passing null for the output pointer, users can find out how many floats are required in the
* output buffer.
*
+ * `cgltf_accessor_unpack_indices` reads in the index data from an accessor. Assumes that
+ * `cgltf_load_buffers` has already been called. By passing null for the output pointer, users can
+ * find out how many indices are required in the output buffer. Returns 0 if the accessor is
+ * sparse or if the output component size is less than the accessor's component size.
+ *
* `cgltf_num_components` is a tiny utility that tells you the dimensionality of
* a certain accessor type. This can be used before `cgltf_accessor_unpack_floats` to help allocate
- * the necessary amount of memory. `cgltf_component_size` and `cgltf_calc_size` exist for
+ * the necessary amount of memory. `cgltf_component_size` and `cgltf_calc_size` exist for
* similar purposes.
*
* `cgltf_accessor_read_float` reads a certain element from a non-sparse accessor and converts it to
@@ -75,7 +80,7 @@
*
* `cgltf_accessor_read_uint` is similar to its floating-point counterpart, but limited to reading
* vector types and does not support matrix types. The passed-in element size is the number of uints
- * in the output buffer, which should be in the range [1, 4]. Returns false if the passed-in
+ * in the output buffer, which should be in the range [1, 4]. Returns false if the passed-in
* element_size is too small, or if the accessor is sparse.
*
* `cgltf_accessor_read_index` is similar to its floating-point counterpart, but it returns size_t
@@ -197,6 +202,7 @@ typedef enum cgltf_type
typedef enum cgltf_primitive_type
{
+ cgltf_primitive_type_invalid,
cgltf_primitive_type_points,
cgltf_primitive_type_lines,
cgltf_primitive_type_line_loop,
@@ -328,15 +334,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
@@ -398,6 +395,8 @@ typedef struct cgltf_texture
cgltf_sampler* sampler;
cgltf_bool has_basisu;
cgltf_image* basisu_image;
+ cgltf_bool has_webp;
+ cgltf_image* webp_image;
cgltf_extras extras;
cgltf_size extensions_count;
cgltf_extension* extensions;
@@ -419,9 +418,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
@@ -511,6 +507,11 @@ typedef struct cgltf_anisotropy
cgltf_texture_view anisotropy_texture;
} cgltf_anisotropy;
+typedef struct cgltf_dispersion
+{
+ cgltf_float dispersion;
+} cgltf_dispersion;
+
typedef struct cgltf_material
{
char* name;
@@ -525,6 +526,7 @@ typedef struct cgltf_material
cgltf_bool has_emissive_strength;
cgltf_bool has_iridescence;
cgltf_bool has_anisotropy;
+ cgltf_bool has_dispersion;
cgltf_pbr_metallic_roughness pbr_metallic_roughness;
cgltf_pbr_specular_glossiness pbr_specular_glossiness;
cgltf_clearcoat clearcoat;
@@ -536,6 +538,7 @@ typedef struct cgltf_material
cgltf_emissive_strength emissive_strength;
cgltf_iridescence iridescence;
cgltf_anisotropy anisotropy;
+ cgltf_dispersion dispersion;
cgltf_texture_view normal_texture;
cgltf_texture_view occlusion_texture;
cgltf_texture_view emissive_texture;
@@ -850,7 +853,7 @@ 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);
+cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, void* out, cgltf_size out_component_size, 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);
@@ -950,8 +953,8 @@ static int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t
#ifndef CGLTF_CONSTS
-static const cgltf_size GlbHeaderSize = 12;
-static const cgltf_size GlbChunkHeaderSize = 8;
+#define GlbHeaderSize 12
+#define GlbChunkHeaderSize 8
static const uint32_t GlbVersion = 2;
static const uint32_t GlbMagic = 0x46546C67;
static const uint32_t GlbMagicJsonChunk = 0x4E4F534A;
@@ -1045,7 +1048,7 @@ static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* m
fclose(file);
return cgltf_result_out_of_memory;
}
-
+
cgltf_size read_size = fread(file_data, 1, file_size, file);
fclose(file);
@@ -1153,7 +1156,7 @@ cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_s
// JSON chunk: length
uint32_t json_length;
memcpy(&json_length, json_chunk, 4);
- if (GlbHeaderSize + GlbChunkHeaderSize + json_length > size)
+ if (json_length > size - GlbHeaderSize - GlbChunkHeaderSize)
{
return cgltf_result_data_too_short;
}
@@ -1167,10 +1170,10 @@ 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)
+ if (GlbChunkHeaderSize <= size - GlbHeaderSize - GlbChunkHeaderSize - json_length)
{
// We can read another chunk
const uint8_t* bin_chunk = json_chunk + json_length;
@@ -1178,7 +1181,7 @@ cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_s
// Bin chunk: length
uint32_t bin_length;
memcpy(&bin_length, bin_chunk, 4);
- if (GlbHeaderSize + GlbChunkHeaderSize + json_length + GlbChunkHeaderSize + bin_length > size)
+ if (bin_length > size - GlbHeaderSize - GlbChunkHeaderSize - json_length - GlbChunkHeaderSize)
{
return cgltf_result_data_too_short;
}
@@ -1564,6 +1567,9 @@ cgltf_result cgltf_validate(cgltf_data* data)
{
cgltf_accessor* accessor = &data->accessors[i];
+ CGLTF_ASSERT_IF(data->accessors[i].component_type == cgltf_component_type_invalid, cgltf_result_invalid_gltf);
+ CGLTF_ASSERT_IF(data->accessors[i].type == cgltf_type_invalid, cgltf_result_invalid_gltf);
+
cgltf_size element_size = cgltf_calc_size(accessor->type, accessor->component_type);
if (accessor->buffer_view)
@@ -1577,7 +1583,7 @@ cgltf_result cgltf_validate(cgltf_data* data)
{
cgltf_accessor_sparse* sparse = &accessor->sparse;
- cgltf_size indices_component_size = cgltf_calc_size(cgltf_type_scalar, sparse->indices_component_type);
+ cgltf_size indices_component_size = cgltf_component_size(sparse->indices_component_type);
cgltf_size indices_req_size = sparse->indices_byte_offset + indices_component_size * sparse->count;
cgltf_size values_req_size = sparse->values_byte_offset + element_size * sparse->count;
@@ -1643,43 +1649,48 @@ cgltf_result cgltf_validate(cgltf_data* data)
for (cgltf_size j = 0; j < data->meshes[i].primitives_count; ++j)
{
+ CGLTF_ASSERT_IF(data->meshes[i].primitives[j].type == cgltf_primitive_type_invalid, cgltf_result_invalid_gltf);
CGLTF_ASSERT_IF(data->meshes[i].primitives[j].targets_count != data->meshes[i].primitives[0].targets_count, cgltf_result_invalid_gltf);
- if (data->meshes[i].primitives[j].attributes_count)
+ CGLTF_ASSERT_IF(data->meshes[i].primitives[j].attributes_count == 0, cgltf_result_invalid_gltf);
+
+ cgltf_accessor* first = data->meshes[i].primitives[j].attributes[0].data;
+
+ CGLTF_ASSERT_IF(first->count == 0, cgltf_result_invalid_gltf);
+
+ for (cgltf_size k = 0; k < data->meshes[i].primitives[j].attributes_count; ++k)
{
- cgltf_accessor* first = data->meshes[i].primitives[j].attributes[0].data;
+ CGLTF_ASSERT_IF(data->meshes[i].primitives[j].attributes[k].data->count != first->count, cgltf_result_invalid_gltf);
+ }
- for (cgltf_size k = 0; k < data->meshes[i].primitives[j].attributes_count; ++k)
+ for (cgltf_size k = 0; k < data->meshes[i].primitives[j].targets_count; ++k)
+ {
+ for (cgltf_size m = 0; m < data->meshes[i].primitives[j].targets[k].attributes_count; ++m)
{
- CGLTF_ASSERT_IF(data->meshes[i].primitives[j].attributes[k].data->count != first->count, cgltf_result_invalid_gltf);
+ CGLTF_ASSERT_IF(data->meshes[i].primitives[j].targets[k].attributes[m].data->count != first->count, cgltf_result_invalid_gltf);
}
+ }
- for (cgltf_size k = 0; k < data->meshes[i].primitives[j].targets_count; ++k)
- {
- for (cgltf_size m = 0; m < data->meshes[i].primitives[j].targets[k].attributes_count; ++m)
- {
- CGLTF_ASSERT_IF(data->meshes[i].primitives[j].targets[k].attributes[m].data->count != first->count, cgltf_result_invalid_gltf);
- }
- }
+ cgltf_accessor* indices = data->meshes[i].primitives[j].indices;
- cgltf_accessor* indices = data->meshes[i].primitives[j].indices;
+ CGLTF_ASSERT_IF(indices &&
+ indices->component_type != cgltf_component_type_r_8u &&
+ indices->component_type != cgltf_component_type_r_16u &&
+ indices->component_type != cgltf_component_type_r_32u, cgltf_result_invalid_gltf);
- CGLTF_ASSERT_IF(indices &&
- indices->component_type != cgltf_component_type_r_8u &&
- indices->component_type != cgltf_component_type_r_16u &&
- indices->component_type != cgltf_component_type_r_32u, cgltf_result_invalid_gltf);
+ CGLTF_ASSERT_IF(indices && indices->type != cgltf_type_scalar, cgltf_result_invalid_gltf);
+ CGLTF_ASSERT_IF(indices && indices->stride != cgltf_component_size(indices->component_type), cgltf_result_invalid_gltf);
- if (indices && indices->buffer_view && indices->buffer_view->buffer->data)
- {
- cgltf_size index_bound = cgltf_calc_index_bound(indices->buffer_view, indices->offset, indices->component_type, indices->count);
+ if (indices && indices->buffer_view && indices->buffer_view->buffer->data)
+ {
+ cgltf_size index_bound = cgltf_calc_index_bound(indices->buffer_view, indices->offset, indices->component_type, indices->count);
- CGLTF_ASSERT_IF(index_bound >= first->count, cgltf_result_data_too_short);
- }
+ CGLTF_ASSERT_IF(index_bound >= first->count, cgltf_result_data_too_short);
+ }
- for (cgltf_size k = 0; k < data->meshes[i].primitives[j].mappings_count; ++k)
- {
- CGLTF_ASSERT_IF(data->meshes[i].primitives[j].mappings[k].variant >= data->variants_count, cgltf_result_invalid_gltf);
- }
+ for (cgltf_size k = 0; k < data->meshes[i].primitives[j].mappings_count; ++k)
+ {
+ CGLTF_ASSERT_IF(data->meshes[i].primitives[j].mappings[k].variant >= data->variants_count, cgltf_result_invalid_gltf);
}
}
}
@@ -1688,7 +1699,20 @@ cgltf_result cgltf_validate(cgltf_data* data)
{
if (data->nodes[i].weights && data->nodes[i].mesh)
{
- CGLTF_ASSERT_IF (data->nodes[i].mesh->primitives_count && data->nodes[i].mesh->primitives[0].targets_count != data->nodes[i].weights_count, cgltf_result_invalid_gltf);
+ CGLTF_ASSERT_IF(data->nodes[i].mesh->primitives_count && data->nodes[i].mesh->primitives[0].targets_count != data->nodes[i].weights_count, cgltf_result_invalid_gltf);
+ }
+
+ if (data->nodes[i].has_mesh_gpu_instancing)
+ {
+ CGLTF_ASSERT_IF(data->nodes[i].mesh == NULL, cgltf_result_invalid_gltf);
+ CGLTF_ASSERT_IF(data->nodes[i].mesh_gpu_instancing.attributes_count == 0, cgltf_result_invalid_gltf);
+
+ cgltf_accessor* first = data->nodes[i].mesh_gpu_instancing.attributes[0].data;
+
+ for (cgltf_size k = 0; k < data->nodes[i].mesh_gpu_instancing.attributes_count; ++k)
+ {
+ CGLTF_ASSERT_IF(data->nodes[i].mesh_gpu_instancing.attributes[k].data->count != first->count, cgltf_result_invalid_gltf);
+ }
}
}
@@ -1736,10 +1760,15 @@ cgltf_result cgltf_validate(cgltf_data* data)
cgltf_size values = channel->sampler->interpolation == cgltf_interpolation_type_cubic_spline ? 3 : 1;
- CGLTF_ASSERT_IF(channel->sampler->input->count * components * values != channel->sampler->output->count, cgltf_result_data_too_short);
+ CGLTF_ASSERT_IF(channel->sampler->input->count * components * values != channel->sampler->output->count, cgltf_result_invalid_gltf);
}
}
+ for (cgltf_size i = 0; i < data->variants_count; ++i)
+ {
+ CGLTF_ASSERT_IF(!data->variants[i].name, cgltf_result_invalid_gltf);
+ }
+
return cgltf_result_success;
}
@@ -1786,12 +1815,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)
@@ -1813,15 +1836,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);
}
@@ -1923,61 +1937,13 @@ 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);
- }
- if (data->materials[i].has_anisotropy)
- {
- cgltf_free_texture_view(data, &data->materials[i].anisotropy.anisotropy_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);
}
data->memory.free_func(data->memory.user_data, data->materials);
- for (cgltf_size i = 0; i < data->images_count; ++i)
+ for (cgltf_size i = 0; i < data->images_count; ++i)
{
data->memory.free_func(data->memory.user_data, data->images[i].name);
data->memory.free_func(data->memory.user_data, data->images[i].uri);
@@ -2225,8 +2191,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:
@@ -2244,8 +2208,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:
@@ -2629,7 +2591,7 @@ cgltf_size cgltf_animation_channel_index(const cgltf_animation* animation, const
return (cgltf_size)(object - animation->channels);
}
-cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, cgltf_uint* out, cgltf_size index_count)
+cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, void* out, cgltf_size out_component_size, cgltf_size index_count)
{
if (out == NULL)
{
@@ -2637,6 +2599,7 @@ cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, cgltf_u
}
index_count = accessor->count < index_count ? accessor->count : index_count;
+ cgltf_size index_component_size = cgltf_component_size(accessor->component_type);
if (accessor->is_sparse)
{
@@ -2646,6 +2609,10 @@ cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, cgltf_u
{
return 0;
}
+ if (index_component_size > out_component_size)
+ {
+ return 0;
+ }
const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view);
if (element == NULL)
{
@@ -2653,18 +2620,29 @@ cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, cgltf_u
}
element += accessor->offset;
- if (accessor->component_type == cgltf_component_type_r_32u && accessor->stride == sizeof(cgltf_uint))
+ if (index_component_size == out_component_size && accessor->stride == out_component_size)
{
- memcpy(out, element, index_count * sizeof(cgltf_uint));
+ memcpy(out, element, index_count * index_component_size);
+ return index_count;
}
- else
- {
- cgltf_uint* dest = out;
- for (cgltf_size index = 0; index < index_count; index++, dest++, element += accessor->stride)
+ // The component size of the output array is larger than the component size of the index data, so index data will be padded.
+ switch (out_component_size)
+ {
+ case 2:
+ for (cgltf_size index = 0; index < index_count; index++, element += accessor->stride)
+ {
+ ((uint16_t*)out)[index] = (uint16_t)cgltf_component_read_index(element, accessor->component_type);
+ }
+ break;
+ case 4:
+ for (cgltf_size index = 0; index < index_count; index++, element += accessor->stride)
{
- *dest = (cgltf_uint)cgltf_component_read_index(element, accessor->component_type);
+ ((uint32_t*)out)[index] = (uint32_t)cgltf_component_read_index(element, accessor->component_type);
}
+ break;
+ default:
+ break;
}
return index_count;
@@ -2675,7 +2653,7 @@ cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, cgltf_u
#define CGLTF_ERROR_LEGACY -3
#define CGLTF_CHECK_TOKTYPE(tok_, type_) if ((tok_).type != (type_)) { return CGLTF_ERROR_JSON; }
-#define CGLTF_CHECK_TOKTYPE_RETTYPE(tok_, type_, ret_) if ((tok_).type != (type_)) { return (ret_)CGLTF_ERROR_JSON; }
+#define CGLTF_CHECK_TOKTYPE_RET(tok_, type_, ret_) if ((tok_).type != (type_)) { return ret_; }
#define CGLTF_CHECK_KEY(tok_) if ((tok_).type != JSMN_STRING || (tok_).size == 0) { return CGLTF_ERROR_JSON; } /* checking size for 0 verifies that a value follows the key */
#define CGLTF_PTRINDEX(type, idx) (type*)((cgltf_size)idx + 1)
@@ -2702,12 +2680,13 @@ static int cgltf_json_to_int(jsmntok_t const* tok, const uint8_t* json_chunk)
static cgltf_size cgltf_json_to_size(jsmntok_t const* tok, const uint8_t* json_chunk)
{
- CGLTF_CHECK_TOKTYPE_RETTYPE(*tok, JSMN_PRIMITIVE, cgltf_size);
+ CGLTF_CHECK_TOKTYPE_RET(*tok, JSMN_PRIMITIVE, 0);
char tmp[128];
int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1);
strncpy(tmp, (const char*)json_chunk + tok->start, size);
tmp[size] = 0;
- return (cgltf_size)CGLTF_ATOLL(tmp);
+ long long res = CGLTF_ATOLL(tmp);
+ return res < 0 ? 0 : (cgltf_size)res;
}
static cgltf_float cgltf_json_to_float(jsmntok_t const* tok, const uint8_t* json_chunk)
@@ -2889,6 +2868,11 @@ static void cgltf_parse_attribute_type(const char* name, cgltf_attribute_type* o
if (us && *out_type != cgltf_attribute_type_invalid)
{
*out_index = CGLTF_ATOI(us + 1);
+ if (*out_index < 0)
+ {
+ *out_type = cgltf_attribute_type_invalid;
+ *out_index = 0;
+ }
}
}
@@ -3221,6 +3205,31 @@ static int cgltf_parse_json_material_mappings(cgltf_options* options, jsmntok_t
return i;
}
+static cgltf_primitive_type cgltf_json_to_primitive_type(jsmntok_t const* tok, const uint8_t* json_chunk)
+{
+ int type = cgltf_json_to_int(tok, json_chunk);
+
+ switch (type)
+ {
+ case 0:
+ return cgltf_primitive_type_points;
+ case 1:
+ return cgltf_primitive_type_lines;
+ case 2:
+ return cgltf_primitive_type_line_loop;
+ case 3:
+ return cgltf_primitive_type_line_strip;
+ case 4:
+ return cgltf_primitive_type_triangles;
+ case 5:
+ return cgltf_primitive_type_triangle_strip;
+ case 6:
+ return cgltf_primitive_type_triangle_fan;
+ default:
+ return cgltf_primitive_type_invalid;
+ }
+}
+
static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_primitive* out_prim)
{
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
@@ -3237,9 +3246,7 @@ static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* t
if (cgltf_json_strcmp(tokens+i, json_chunk, "mode") == 0)
{
++i;
- out_prim->type
- = (cgltf_primitive_type)
- cgltf_json_to_int(tokens+i, json_chunk);
+ out_prim->type = cgltf_json_to_primitive_type(tokens+i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens+i, json_chunk, "indices") == 0)
@@ -3475,7 +3482,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);
@@ -3489,7 +3496,7 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co
if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0)
{
++i;
- out_sparse->count = cgltf_json_to_int(tokens + i, json_chunk);
+ out_sparse->count = cgltf_json_to_size(tokens + i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens+i, json_chunk, "indices") == 0)
@@ -3522,14 +3529,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);
@@ -3565,14 +3564,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);
@@ -3584,14 +3575,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);
@@ -3649,8 +3632,7 @@ static int cgltf_parse_json_accessor(cgltf_options* options, jsmntok_t const* to
else if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0)
{
++i;
- out_accessor->count =
- cgltf_json_to_int(tokens+i, json_chunk);
+ out_accessor->count = cgltf_json_to_size(tokens+i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens+i, json_chunk, "type") == 0)
@@ -3705,7 +3687,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)
{
@@ -3777,6 +3759,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;
@@ -3801,7 +3785,7 @@ static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const
out_texture_view->texcoord = cgltf_json_to_int(tokens + i, json_chunk);
++i;
}
- else if (cgltf_json_strcmp(tokens + i, json_chunk, "scale") == 0)
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "scale") == 0)
{
++i;
out_texture_view->scale = cgltf_json_to_float(tokens + i, json_chunk);
@@ -3813,28 +3797,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;
@@ -3849,7 +3817,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)
@@ -3886,11 +3854,11 @@ static int cgltf_parse_json_pbr_metallic_roughness(cgltf_options* options, jsmnt
if (cgltf_json_strcmp(tokens+i, json_chunk, "metallicFactor") == 0)
{
++i;
- out_pbr->metallic_factor =
+ out_pbr->metallic_factor =
cgltf_json_to_float(tokens + i, json_chunk);
++i;
}
- else if (cgltf_json_strcmp(tokens+i, json_chunk, "roughnessFactor") == 0)
+ else if (cgltf_json_strcmp(tokens+i, json_chunk, "roughnessFactor") == 0)
{
++i;
out_pbr->roughness_factor =
@@ -3903,13 +3871,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
{
@@ -4353,6 +4319,37 @@ static int cgltf_parse_json_anisotropy(cgltf_options* options, jsmntok_t const*
return i;
}
+static int cgltf_parse_json_dispersion(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_dispersion* out_dispersion)
+{
+ 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, "dispersion") == 0)
+ {
+ ++i;
+ out_dispersion->dispersion = cgltf_json_to_float(tokens + i, json_chunk);
+ ++i;
+ }
+ 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);
@@ -4360,11 +4357,11 @@ static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* token
int size = tokens[i].size;
++i;
- for (int j = 0; j < size; ++j)
+ for (int j = 0; j < size; ++j)
{
CGLTF_CHECK_KEY(tokens[i]);
- if (cgltf_json_strcmp(tokens + i, json_chunk, "uri") == 0)
+ if (cgltf_json_strcmp(tokens + i, json_chunk, "uri") == 0)
{
i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_image->uri);
}
@@ -4444,7 +4441,7 @@ static int cgltf_parse_json_sampler(cgltf_options* options, jsmntok_t const* tok
= cgltf_json_to_int(tokens + i, json_chunk);
++i;
}
- else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapT") == 0)
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapT") == 0)
{
++i;
out_sampler->wrap_t
@@ -4494,7 +4491,7 @@ static int cgltf_parse_json_texture(cgltf_options* options, jsmntok_t const* tok
out_texture->sampler = CGLTF_PTRINDEX(cgltf_sampler, cgltf_json_to_int(tokens + i, json_chunk));
++i;
}
- else if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0)
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0)
{
++i;
out_texture->image = CGLTF_PTRINDEX(cgltf_image, cgltf_json_to_int(tokens + i, json_chunk));
@@ -4556,6 +4553,34 @@ static int cgltf_parse_json_texture(cgltf_options* options, jsmntok_t const* tok
}
}
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "EXT_texture_webp") == 0)
+ {
+ out_texture->has_webp = 1;
+ ++i;
+ CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
+ int num_properties = tokens[i].size;
+ ++i;
+
+ for (int t = 0; t < num_properties; ++t)
+ {
+ CGLTF_CHECK_KEY(tokens[i]);
+
+ if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0)
+ {
+ ++i;
+ out_texture->webp_image = CGLTF_PTRINDEX(cgltf_image, cgltf_json_to_int(tokens + i, json_chunk));
+ ++i;
+ }
+ else
+ {
+ i = cgltf_skip_json(tokens, i + 1);
+ }
+ if (i < 0)
+ {
+ return i;
+ }
+ }
+ }
else
{
i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_texture->extensions[out_texture->extensions_count++]));
@@ -4746,6 +4771,11 @@ static int cgltf_parse_json_material(cgltf_options* options, jsmntok_t const* to
out_material->has_anisotropy = 1;
i = cgltf_parse_json_anisotropy(options, tokens, i + 1, json_chunk, &out_material->anisotropy);
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_dispersion") == 0)
+ {
+ out_material->has_dispersion = 1;
+ i = cgltf_parse_json_dispersion(tokens, i + 1, json_chunk, &out_material->dispersion);
+ }
else
{
i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_material->extensions[out_material->extensions_count++]));
@@ -4905,7 +4935,7 @@ static int cgltf_parse_json_meshopt_compression(cgltf_options* options, jsmntok_
else if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0)
{
++i;
- out_meshopt_compression->count = cgltf_json_to_int(tokens+i, json_chunk);
+ out_meshopt_compression->count = cgltf_json_to_size(tokens+i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens+i, json_chunk, "mode") == 0)
@@ -6561,6 +6591,7 @@ static int cgltf_fixup_pointers(cgltf_data* data)
{
CGLTF_PTRFIXUP(data->textures[i].image, data->images, data->images_count);
CGLTF_PTRFIXUP(data->textures[i].basisu_image, data->images, data->images_count);
+ CGLTF_PTRFIXUP(data->textures[i].webp_image, data->images, data->images_count);
CGLTF_PTRFIXUP(data->textures[i].sampler, data->samplers, data->samplers_count);
}
diff --git a/examples/game_demo/game_demo.c b/examples/game_demo/game_demo.c
index 88de681..69023d7 100644
--- a/examples/game_demo/game_demo.c
+++ b/examples/game_demo/game_demo.c
@@ -117,20 +117,24 @@ int main() {
// Y Axis (blue)
Immdraw_Cone(transform_create(vec3(0.0, 2.0, 0.0), quat_ident(), vec3(0.3, 1.0, 0.3)),
vec4(0.0, 0.0, 1.0, 1.0), false);
- Immdraw_Cylinder(transform_create(VEC3_ZERO, quat_ident(), vec3(thickness, 1.1, thickness)), vec4(0.0, 0.0, 1.0, 1.0),
- false);
+ Immdraw_Cylinder(transform_create(VEC3_ZERO, quat_ident(), vec3(thickness, 1.1, thickness)),
+ vec4(0.0, 0.0, 1.0, 1.0), false);
// X Axis (green)
- Immdraw_Cone(transform_create(vec3(2.0, 0.0, 0.0), quat_from_axis_angle(VEC3_Z, HALF_PI, true), vec3(0.3, 1.0, 0.3)),
+ Immdraw_Cone(transform_create(vec3(2.0, 0.0, 0.0), quat_from_axis_angle(VEC3_Z, HALF_PI, true),
+ vec3(0.3, 1.0, 0.3)),
vec4(0.0, 1.0, 0.0, 1.0), false);
- Immdraw_Cylinder(transform_create(VEC3_ZERO, quat_from_axis_angle(VEC3_Z, HALF_PI, true), vec3(thickness, 1.1, thickness)), vec4(0.0, 1.0, 0.0, 1.0),
- false);
+ Immdraw_Cylinder(transform_create(VEC3_ZERO, quat_from_axis_angle(VEC3_Z, HALF_PI, true),
+ vec3(thickness, 1.1, thickness)),
+ vec4(0.0, 1.0, 0.0, 1.0), false);
// Z Axis (red)
- Immdraw_Cone(transform_create(vec3(0.0, 0.0, 2.0), quat_from_axis_angle(VEC3_X, -HALF_PI, true), vec3(0.3, 1.0, 0.3)),
+ Immdraw_Cone(transform_create(vec3(0.0, 0.0, 2.0), quat_from_axis_angle(VEC3_X, -HALF_PI, true),
+ vec3(0.3, 1.0, 0.3)),
vec4(1.0, 0.0, 0.0, 1.0), false);
- Immdraw_Cylinder(transform_create(VEC3_ZERO, quat_from_axis_angle(VEC3_X, -HALF_PI, true), vec3(thickness, 1.1, thickness)), vec4(1.0, 0.0, 0.0, 1.0),
- false);
+ Immdraw_Cylinder(transform_create(VEC3_ZERO, quat_from_axis_angle(VEC3_X, -HALF_PI, true),
+ vec3(thickness, 1.1, thickness)),
+ vec4(1.0, 0.0, 0.0, 1.0), false);
if (draw_debug) {
// draw the player model with shadows
diff --git a/examples/skinned_animation/ex_skinned_animation.c b/examples/skinned_animation/ex_skinned_animation.c
index e1ebd64..81642ae 100644
--- a/examples/skinned_animation/ex_skinned_animation.c
+++ b/examples/skinned_animation/ex_skinned_animation.c
@@ -15,7 +15,7 @@
int main() {
double currentFrame = glfwGetTime();
double lastFrame = currentFrame;
- double deltaTime;
+ double delta_time;
Core_Bringup("Skinned Animation", NULL);
@@ -40,7 +40,7 @@ int main() {
// scene our_scene = make_default_scene();
- Vec3 cam_pos = vec3_create(0, 1.2, 4);
+ Vec3 cam_pos = vec3_create(1.5, 2.2, 8);
Camera cam = Camera_Create(cam_pos, VEC3_NEG_Z, VEC3_Y, deg_to_rad(45.0));
SetCamera(cam);
@@ -50,18 +50,20 @@ int main() {
// animation
// animation_clip track = simple_skin->animations->data[0];
- // f64 total_time = 0.0;
+ CASSERT(AnimationClip_darray_len(simple_skin->animations) > 0);
+ AnimationClip track = simple_skin->animations->data[0];
+ f64 total_time = 0.0;
while (!ShouldExit()) {
Frame_Begin();
currentFrame = glfwGetTime();
- deltaTime = currentFrame - lastFrame;
+ delta_time = currentFrame - lastFrame;
lastFrame = currentFrame;
- // total_time += deltaTime;
+ total_time += delta_time;
// printf("delta time %f\n", deltaTime);
- // f64 t = fmod(total_time, track.rotation->max);
- // INFO("Total time: %f", t);
+ f64 t = fmod(total_time, track.channels->data[0].max);
+ INFO("Delta time %f Animation time: %f", delta_time, t);
// bone rotation
// Quat rot = animation_sample(track.rotation, t).rotation;
@@ -75,17 +77,17 @@ int main() {
Mesh* m = Mesh_Get(simple_skin->meshes[0]);
RenderEnt render_ents[1] = { (RenderEnt){ .mesh = simple_skin->meshes[0],
.material = m->material,
- .animation_clip = simple_skin->animations->data[0],
- .is_playing = true,
- .t = 0.0,
+ .armature = &m->armature,
.affine = mat4_ident(),
.flags = 0 } };
// ModelExtractRenderEnts(rend_ents, handle, mat4_translation(vec3(0, 0, 0)), 0);
// draw_skinned_model(&core->renderer, &game.camera, simple_skin, tf, &our_scene);
+ Animation_Tick(&track, &m->armature, t);
+
Render_RenderEntities(render_ents, 1);
- // Animation_VisualiseJoints(&m->armature);
+ Animation_VisualiseJoints(&m->armature);
RenderEnt_darray_clear(rend_ents);
diff --git a/src/animation.c b/src/animation.c
index 48a5ff1..274602c 100644
--- a/src/animation.c
+++ b/src/animation.c
@@ -4,7 +4,6 @@
#include "maths.h"
#include "maths_types.h"
#include "ral_types.h"
-#include "transform_hierarchy.h"
Keyframe Animation_Sample(AnimationSampler* sampler, f32 t) {
size_t previous_index = 0;
@@ -47,6 +46,26 @@ Keyframe Animation_Sample(AnimationSampler* sampler, f32 t) {
}
}
+void Animation_Tick(AnimationClip* clip, Armature* armature, f32 time) {
+ TRACE("Ticking animation %s", clip->clip_name);
+
+ for (u32 c_i = 0; c_i < clip->channels->len; c_i++) {
+ AnimationSampler* sampler = clip->channels->data;
+
+ // Interpolated keyframe based on time
+ Keyframe k = Animation_Sample(sampler, time);
+
+ // Get the joint in the armature
+ Joint* joint = &armature->joints->data[sampler->target_joint_idx];
+ if (sampler->animation.values.kind == KEYFRAME_ROTATION) {
+ // Update the joints rotation
+ joint->transform_components.rotation = k.rotation;
+ } else {
+ WARN("not yet implemented animation kind");
+ }
+ }
+}
+
void Animation_VisualiseJoints(Armature* armature) {
for (int j = 0; j < armature->joints->len; j++) {
Joint joint = armature->joints->data[j];
diff --git a/src/animation.h b/src/animation.h
index e0ad543..2a489b8 100644
--- a/src/animation.h
+++ b/src/animation.h
@@ -1,5 +1,6 @@
#pragma once
+#include "cgltf.h"
#include "darray.h"
#include "defines.h"
#include "maths_types.h"
@@ -36,9 +37,16 @@ typedef struct Keyframes {
} Keyframes;
typedef struct Joint {
+ // used instead of pointers later to update correct joints
+ size_t node_idx;
+ ssize_t parent; // parent bone. -1 means its the root
+ size_t children[8]; // children bones, upto 8
+ u8 children_count;
char* debug_label; // optional
Mat4 inverse_bind_matrix;
Mat4 local_transform;
+ /** @brief holds position, rotation, and scale that will be written to by animation
+ samplers every tick of the animation system. */
Transform transform_components;
} Joint;
#ifndef TYPED_JOINT_ARRAY
@@ -50,7 +58,6 @@ typedef u32 JointIdx;
typedef struct Armature {
char* label;
- arena arena;
Joint_darray* joints;
} Armature;
@@ -65,41 +72,52 @@ typedef struct AnimationSpline {
Interpolation interpolation;
} AnimationSpline;
+// combines a sampler and a channel in gltf
typedef struct AnimationSampler {
int current_index;
f32 min;
f32 max;
AnimationSpline animation;
+ u32 target_joint_idx; // index into the array of joints in an armature
} AnimationSampler;
+#ifndef TYPED_ANIM_SAMPLER_ARRAY
+KITC_DECL_TYPED_ARRAY(AnimationSampler);
+#define TYPED_ANIM_SAMPLER_ARRAY
+#endif
/** @brief Sample an animation at a given time `t` returning an interpolated keyframe */
PUB Keyframe Animation_Sample(AnimationSampler* sampler, f32 t);
+/** @brief A clip contains one or more animation curves. */
typedef struct AnimationClip {
- // A clip contains one or more animation curves.
- // For now I think we can just enumerate all of the properties (assuming *only* one per type is in
- // a clip) and NULL = the property is not animated in this clip
- // NOTE: when I call 'property' is typically referred to as a 'channel' by GLTF
- AnimationSampler* rotation;
- AnimationSampler* translation;
- AnimationSampler* scale;
- AnimationSampler* weights;
+ const char* clip_name;
+ bool is_playing;
+ f32 time;
+ AnimationSampler_darray* channels;
} AnimationClip;
#ifndef TYPED_ANIM_CLIP_ARRAY
KITC_DECL_TYPED_ARRAY(AnimationClip);
#define TYPED_ANIM_CLIP_ARRAY
#endif
-typedef struct SkinnedAnimation {
- Mat4* joint_matrices;
- size_t n_joints;
-} SkinnedAnimation;
+// typedef struct SkinnedAnimation {
+// Mat4* joint_matrices;
+// size_t n_joints;
+// } SkinnedAnimation;
PUB void Animation_Play(AnimationClip* clip);
+void Animation_Tick(AnimationClip* clip, Armature* armature, f32 delta_time);
+
void Animation_VisualiseJoints(Armature* armature);
+#define MAX_BONES 100
+
typedef struct AnimDataUniform {
- Mat4 bone_matrices[4];
+ Mat4 bone_matrices[MAX_BONES];
} AnimDataUniform;
ShaderDataLayout AnimData_GetLayout(void* data);
+
+// Animation Targets:
+// - Mesh
+// - Joint
diff --git a/src/maths/primitives.c b/src/maths/primitives.c
index 551a5df..c24d1e2 100644
--- a/src/maths/primitives.c
+++ b/src/maths/primitives.c
@@ -296,7 +296,8 @@ Geometry Geo_CreateCylinder(f32 radius, f32 height, u32 resolution) {
// bot cap
VERT_3D(vertices, VEC3_ZERO, VEC3_NEG_Y, vec2(0, 0));
for (u32 i = 0; i < resolution; i++) {
- VERT_3D(vertices, vec3(cos(step * i) * radius, 0.0, sin(step * i) * radius), VEC3_NEG_Y, vec2(0, 0));
+ VERT_3D(vertices, vec3(cos(step * i) * radius, 0.0, sin(step * i) * radius), VEC3_NEG_Y,
+ vec2(0, 0));
}
for (u32 i = 1; i < resolution; i++) {
push_triangle(indices, 0, i, i + 1);
@@ -325,10 +326,10 @@ Geometry Geo_CreateCylinder(f32 radius, f32 height, u32 resolution) {
VERT_3D(vertices, vec3(x, 0.0, z), vec3_normalise(vec3(x, 0.0, z)), vec2(0, 0));
}
for (u32 i = 0; i < resolution; i++) {
- u32 current = sides_start + i * 2;
- u32 next = sides_start + ((i + 1) % resolution) * 2;
- push_triangle(indices, current, next, current + 1);
- push_triangle(indices, current + 1, next, next + 1);
+ u32 current = sides_start + i * 2;
+ u32 next = sides_start + ((i + 1) % resolution) * 2;
+ push_triangle(indices, current, next, current + 1);
+ push_triangle(indices, current + 1, next, next + 1);
}
Geometry geo = {
diff --git a/src/render/pbr.c b/src/render/pbr.c
index 044e6eb..6ea5746 100644
--- a/src/render/pbr.c
+++ b/src/render/pbr.c
@@ -13,6 +13,7 @@
#include "render_types.h"
#include "shader_layouts.h"
+
void PBR_Init(PBR_Storage* storage) {
INFO("PBR shaders init");
storage->pbr_pass = PBR_RPassCreate();
@@ -144,12 +145,27 @@ void PBR_Execute(PBR_Storage* storage, Camera camera, TextureHandle shadowmap_te
Binding_Model model_data = { .model = renderable.affine };
GPU_EncodeBindShaderData(enc, 1, Binding_Model_GetLayout(&model_data));
+ // Skinning matrices
+
+ // 1. calculate matrices
AnimDataUniform anim_data = { 0 };
- for (int i = 0; i < 4; i++) {
- anim_data.bone_matrices[i] = mat4_ident();
+ CASSERT(renderable.armature);
+ Armature* skeleton = renderable.armature;
+ // Skip the first one as we assume its root for this test
+ for (int j_i = 1; j_i < skeleton->joints->len; j_i++) {
+ Joint* j = &skeleton->joints->data[j_i];
+ j->local_transform = transform_to_mat(&j->transform_components);
+ Mat4 m = mat4_mult(j->local_transform, j->inverse_bind_matrix);
+ Joint* p = &skeleton->joints->data[j->parent];
+ j->local_transform = mat4_mult(j->local_transform, p->local_transform);
+ printf("Quat %f \n", j->transform_components.rotation.z);
+ }
+
+ // 2. bind and upload
+ for (int j_i = 1; j_i < skeleton->joints->len; j_i++) {
+ anim_data.bone_matrices[j_i] = skeleton->joints->data[j_i].local_transform;
}
GPU_EncodeBindShaderData(enc, 3, AnimData_GetLayout(&anim_data));
- // Calculate matrices here
// set buffers
GPU_EncodeSetVertexBuffer(enc, mesh->vertex_buffer);
diff --git a/src/render/render_types.h b/src/render/render_types.h
index dd09896..16dee1d 100644
--- a/src/render/render_types.h
+++ b/src/render/render_types.h
@@ -135,9 +135,8 @@ typedef u32 RenderEntityFlags;
typedef struct RenderEnt {
MeshHandle mesh;
MaterialHandle material;
- AnimationClip animation_clip;
- bool is_playing;
- f32 t;
+ /** If NULL, no armature and the mesh is static geometry, else it is to be skinned */
+ Armature* armature;
Mat4 affine; // In the future this should be updated by the transform graph
Bbox_3D bounding_box;
RenderEntityFlags flags;
diff --git a/src/resources/gltf.c b/src/resources/gltf.c
index 76ba0a5..8d9217e 100644
--- a/src/resources/gltf.c
+++ b/src/resources/gltf.c
@@ -37,6 +37,7 @@ KITC_DECL_TYPED_ARRAY(Vec4u)
KITC_DECL_TYPED_ARRAY(Vec4i)
KITC_DECL_TYPED_ARRAY(Vec4)
KITC_DECL_TYPED_ARRAY(face)
+KITC_DECL_TYPED_ARRAY(i32)
size_t GLTF_LoadMaterials(cgltf_data* data, Str8 relative_path, Material_darray* out_materials);
@@ -149,7 +150,7 @@ bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 rel
Vec4_darray* tmp_weights = Vec4_darray_new(1000);
Material_darray* tmp_materials = Material_darray_new(1);
Mesh_darray* tmp_meshes = Mesh_darray_new(1);
- u32_darray* tmp_material_indexes = u32_darray_new(1);
+ i32_darray* tmp_material_indexes = i32_darray_new(1);
Joint_darray* joints = Joint_darray_new(256);
@@ -183,24 +184,35 @@ bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 rel
DEBUG("# Joints %d", num_joints);
// Create our data that will be placed onto the model
- Armature armature = { .arena = arena_create(malloc(MB(1)), MB(1)) };
+ Armature armature = {
+ .label = "test_skin"};
printf("Skin %s\n", gltf_skin->name);
- armature.label = "test_skin";
// armature.label = Clone_cstr(&armature.arena, gltf_skin->name);
armature.joints = joints; // ! Make sure not to free this
cgltf_accessor* gltf_inverse_bind_matrices = gltf_skin->inverse_bind_matrices;
+ // --- Joints
// for each one we'll spit out a joint
for (size_t i = 0; i < num_joints; i++) {
- TRACE("Joint %d", i);
+ // Get the joint and assign its node index for later referencing
cgltf_node* joint_node = gltf_skin->joints[i];
- Joint joint_i = { .debug_label = "test_joint" };
+ TRACE("Joint %d (node index %d)", i, cgltf_node_index(data, joint_node));
+ Joint joint_i = {
+ .debug_label = "test_joint",
+ .node_idx = cgltf_node_index(data, joint_node),
+ .inverse_bind_matrix = mat4_ident()
+ };
if (joint_node->children_count > 0 && !joint_node->has_translation &&
!joint_node->has_rotation) {
- WARN("joint Node with index %d is the root node", i);
+ WARN("Joint node with index %d is the root node", i);
joint_i.transform_components = TRANSFORM_DEFAULT;
+ joint_i.parent = -1;
+ for (u32 c_i = 0; c_i < joint_node->children_count; c_i++) {
+ joint_i.children[c_i] = cgltf_node_index(data, joint_node->children[c_i]);
+ joint_i.children_count++;
+ }
} else {
TRACE("Storing joint transform");
joint_i.transform_components = TRANSFORM_DEFAULT;
@@ -213,8 +225,11 @@ bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 rel
if (joint_node->has_scale) {
memcpy(&joint_i.transform_components.scale, &joint_node->scale, 3 * sizeof(f32));
}
+ joint_i.parent = cgltf_node_index(data, joint_node->parent);
}
+ // Calculate and store the starting transform of the joint
joint_i.local_transform = transform_to_mat(&joint_i.transform_components);
+ // Read in the inverse bind matrix
cgltf_accessor_read_float(gltf_inverse_bind_matrices, i, &joint_i.inverse_bind_matrix.data[0],
16);
Joint_darray_push(armature.joints, joint_i);
@@ -280,10 +295,12 @@ bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 rel
if (strcmp(primitive.material->name, tmp_materials->data[i].name) == 0) {
INFO("Found material");
mat_idx = i;
- u32_darray_push(tmp_material_indexes, mat_idx);
+ i32_darray_push(tmp_material_indexes, mat_idx);
break;
}
}
+ } else {
+ i32_darray_push(tmp_material_indexes, -1);
}
TRACE("Vertex data has been loaded");
@@ -361,34 +378,32 @@ bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 rel
out_model->anim_arena = arena_create(malloc(MB(1)), MB(1));
arena* arena = &out_model->anim_arena;
+ // Iterate over each animation in the GLTF
for (int anim_idx = 0; anim_idx < data->animations_count; anim_idx++) {
cgltf_animation animation = data->animations[anim_idx];
AnimationClip clip = { 0 };
+ clip.clip_name = "test anim clip";
+ clip.channels = AnimationSampler_darray_new(1);
// for each animation, loop through all the channels
for (size_t c = 0; c < animation.channels_count; c++) {
cgltf_animation_channel channel = animation.channels[c];
- AnimationSampler* sampler = arena_alloc(arena, sizeof(AnimationSampler));
+ AnimationSampler sampler = {0};
- AnimationSampler** target_property;
KeyframeKind data_type;
switch (channel.target_path) {
case cgltf_animation_path_type_rotation:
- target_property = &clip.rotation;
data_type = KEYFRAME_ROTATION;
break;
case cgltf_animation_path_type_translation:
- target_property = &clip.translation;
data_type = KEYFRAME_TRANSLATION;
break;
case cgltf_animation_path_type_scale:
- target_property = &clip.scale;
data_type = KEYFRAME_SCALE;
break;
case cgltf_animation_path_type_weights:
- target_property = &clip.weights;
data_type = KEYFRAME_WEIGHTS;
WARN("Morph target weights arent supported yet");
return false;
@@ -397,16 +412,16 @@ bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 rel
return false;
}
- sampler->current_index = 0;
- sampler->animation.interpolation = INTERPOLATION_LINEAR; // NOTE: hardcoded for now
+ sampler.current_index = 0;
+ sampler.animation.interpolation = INTERPOLATION_LINEAR; // NOTE: hardcoded for now
// Keyframe times
size_t n_frames = channel.sampler->input->count;
CASSERT_MSG(channel.sampler->input->component_type == cgltf_component_type_r_32f,
"Expected animation sampler input component to be type f32");
f32* times = arena_alloc(arena, n_frames * sizeof(f32));
- sampler->animation.n_timestamps = n_frames;
- sampler->animation.timestamps = times;
+ sampler.animation.n_timestamps = n_frames;
+ sampler.animation.timestamps = times;
cgltf_accessor_unpack_floats(channel.sampler->input, times, n_frames);
// Keyframe values
@@ -422,7 +437,7 @@ bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 rel
case KEYFRAME_ROTATION: {
Quat rot;
cgltf_accessor_read_float(channel.sampler->output, v, &rot.x, 4);
- printf("Quat %f %f %f %f\n", rot.x, rot.y, rot.z, rot.w);
+ // printf("Quat %f %f %f %f\n", rot.x, rot.y, rot.z, rot.w);
keyframes.values[v].rotation = rot;
break;
}
@@ -444,18 +459,35 @@ bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 rel
}
}
}
- sampler->animation.values = keyframes;
- sampler->min = channel.sampler->input->min[0];
- sampler->max = channel.sampler->input->max[0];
-
- *target_property = sampler;
- printf("%d timestamps between %f and %f\n", sampler->animation.n_timestamps, sampler->min,
- sampler->max);
+ sampler.animation.values = keyframes;
+ sampler.min = channel.sampler->input->min[0];
+ sampler.max = channel.sampler->input->max[0];
+
+ // *target_property = sampler;
+ printf("%d timestamps between %f and %f\n", sampler.animation.n_timestamps, sampler.min,
+ sampler.max);
+
+ // TODO: get target
+ size_t target_index = cgltf_node_index(data, channel.target_node);
+ size_t joint_index = 0;
+ bool found = false;
+ for (u32 ji = 0; ji < main_skeleton.joints->len; ji++) {
+ if (main_skeleton.joints->data[ji].node_idx == target_index) {
+ joint_index = ji;
+ found = true;
+ break;
+ }
+ }
+ if (!found) { WARN("Coulndnt find joint index");}
+ sampler.target_joint_idx = joint_index; // NOTE: this assuming the target is a joint at the moment
+ AnimationSampler_darray_push(clip.channels, sampler);
}
AnimationClip_darray_push(out_model->animations, clip);
}
}
+
+ // exit(0);
}
num_meshes = tmp_meshes->len;
@@ -474,8 +506,15 @@ bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 rel
memcpy(out_model->materials, mat_handles, num_materials * sizeof(MaterialHandle));
for (u32 mesh_i = 0; mesh_i < num_meshes; mesh_i++) {
- u32 mat_idx = tmp_material_indexes->data[mesh_i];
- tmp_meshes->data[mesh_i].material = mat_handles[mat_idx];
+ i32 mat_idx = tmp_material_indexes->data[mesh_i];
+ if (mat_idx > 0) {
+ tmp_meshes->data[mesh_i].material = mat_handles[mat_idx];
+
+ } else {
+ Material default_mat = PBRMaterialDefault();
+ tmp_meshes->data[mesh_i].material =
+ Material_pool_insert(Render_GetMaterialPool(), &default_mat);
+ }
MeshHandle mesh = Mesh_pool_insert(Render_GetMeshPool(), &tmp_meshes->data[mesh_i]);
out_model->meshes[mesh_i] = mesh;
}