Rework bone and animation structure

This commit is contained in:
Camden Dixie O'Brien committed 2025-10-02 15:32:46 +01:00
1 parent ffa0beb55a
commit 2a603dc364
3 files changed
+74 -79

No files matched your search

+6 -11
View File
@@ -34,18 +34,13 @@ void model_cleanup(model_t *m)
free(m->inverse_bind_matrices); free(m->inverse_bind_matrices);
m->inverse_bind_matrices = nullptr; m->inverse_bind_matrices = nullptr;
} }
if (m->animation.times != nullptr) { if (m->animation.times_us != nullptr) {
free(m->animation.times); free(m->animation.times_us);
m->animation.times = nullptr; m->animation.times_us = nullptr;
} }
if (m->animation.bones != nullptr) { if (m->animation.keyframes != nullptr) {
for (unsigned i = 0; i < m->bone_count; ++i) { free(m->animation.keyframes);
free(m->animation.bones[i].translations); m->animation.keyframes = nullptr;
free(m->animation.bones[i].rotations);
free(m->animation.bones[i].scales);
}
free(m->animation.bones);
m->animation.bones = nullptr;
} }
m->vertex_count = m->index_count = m->bone_count m->vertex_count = m->index_count = m->bone_count
= m->animation.keyframe_count = 0; = m->animation.keyframe_count = 0;
+5 -12
View File
@@ -3,8 +3,8 @@
#include "linear_alg.h" #include "linear_alg.h"
#include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h>
typedef uint16_t index_t; typedef uint16_t index_t;
@@ -16,28 +16,21 @@ typedef struct {
} vertex_t; } vertex_t;
typedef struct { typedef struct {
uint32_t parent;
vec3_t translation; vec3_t translation;
vec4_t rotation; vec4_t rotation;
vec3_t scale;
} bone_t; } bone_t;
typedef struct { typedef struct {
vec3_t *translations; uint32_t *times_us;
vec4_t *rotations; bone_t *keyframes;
vec3_t *scales; size_t length_us, keyframe_count;
} animation_bone_t;
typedef struct {
float *times;
size_t keyframe_count;
animation_bone_t *bones;
} animation_t; } animation_t;
typedef struct { typedef struct {
vertex_t *vertices; vertex_t *vertices;
index_t *indices; index_t *indices;
bone_t *bones; bone_t *bones;
uint32_t *bone_parents;
mat4_t *inverse_bind_matrices; mat4_t *inverse_bind_matrices;
animation_t animation; animation_t animation;
size_t vertex_count; size_t vertex_count;
+63 -56
View File
@@ -159,6 +159,7 @@ typedef struct {
typedef struct { typedef struct {
bone_t *bones; bone_t *bones;
uint32_t *bone_parents;
gltf_info_member_t normals; gltf_info_member_t normals;
gltf_info_member_t positions; gltf_info_member_t positions;
gltf_info_member_t bone_indices; gltf_info_member_t bone_indices;
@@ -490,7 +491,7 @@ static skin_t read_skins(const uint8_t *p)
} }
static void read_joint_children( static void read_joint_children(
const uint8_t **p, skin_t skin, bone_t bones[MAX_BONE_COUNT], const uint8_t **p, skin_t skin, uint32_t bone_parents[MAX_BONE_COUNT],
uint32_t parent) uint32_t parent)
{ {
assert(**p == '['); assert(**p == '[');
@@ -505,9 +506,9 @@ static void read_joint_children(
} }
assert(j < skin.joint_count); assert(j < skin.joint_count);
assert(bones[j].parent == UINT32_MAX); assert(bone_parents[j] == UINT32_MAX);
assert(parent < j); assert(parent < j);
bones[j].parent = parent; bone_parents[j] = parent;
if (**p == ',') if (**p == ',')
++(*p); ++(*p);
@@ -515,13 +516,13 @@ static void read_joint_children(
++(*p); ++(*p);
} }
static void static void read_joints(
read_joints(const uint8_t *p, skin_t skin, bone_t bones[MAX_BONE_COUNT]) const uint8_t *p, skin_t skin, bone_t *bones, uint32_t *bone_parents)
{ {
char buffer[MAX_STRING_SIZE]; char buffer[MAX_STRING_SIZE];
for (uint32_t i = 0; i < skin.joint_count; ++i) for (uint32_t i = 0; i < skin.joint_count; ++i)
bones[i].parent = UINT32_MAX; bone_parents[i] = UINT32_MAX;
assert(*p == '['); assert(*p == '[');
++p; ++p;
@@ -547,16 +548,20 @@ read_joints(const uint8_t *p, skin_t skin, bone_t bones[MAX_BONE_COUNT])
assert(*p == ':'); assert(*p == ':');
++p; ++p;
if (strcmp("children", buffer) == 0) if (strcmp("children", buffer) == 0) {
read_joint_children(&p, skin, bones, j); read_joint_children(&p, skin, bone_parents, j);
else if (strcmp("translation", buffer) == 0) } else if (strcmp("translation", buffer) == 0) {
bones[j].translation = read_vec3(&p); bones[j].translation = read_vec3(&p);
else if (strcmp("rotation", buffer) == 0) } else if (strcmp("rotation", buffer) == 0) {
bones[j].rotation = read_vec4(&p); bones[j].rotation = read_vec4(&p);
else if (strcmp("scale", buffer) == 0) } else if (strcmp("scale", buffer) == 0) {
bones[j].scale = read_vec3(&p); const vec3_t scale = read_vec3(&p);
else assert(fabsf(scale.x - 1.0f) < 1e-4);
assert(fabsf(scale.y - 1.0f) < 1e-4);
assert(fabsf(scale.z - 1.0f) < 1e-4);
} else {
skip_value(&p); skip_value(&p);
}
if (*p == ',') if (*p == ',')
++p; ++p;
@@ -1010,7 +1015,9 @@ static gltf_info_t read_json(const uint8_t *json)
bone_t *bones = calloc(skin.joint_count, sizeof(bone_t)); bone_t *bones = calloc(skin.joint_count, sizeof(bone_t));
assert(bones != nullptr); assert(bones != nullptr);
read_joints(nodes_json, skin, bones); uint32_t *bone_parents = calloc(skin.joint_count, sizeof(uint32_t));
assert(bone_parents != nullptr);
read_joints(nodes_json, skin, bones, bone_parents);
animation_component_t animation[MAX_BONE_COUNT]; animation_component_t animation[MAX_BONE_COUNT];
read_animations(animations_json, skin, animation); read_animations(animations_json, skin, animation);
@@ -1070,6 +1077,7 @@ static gltf_info_t read_json(const uint8_t *json)
gltf_info_t info = { gltf_info_t info = {
.bones = bones, .bones = bones,
.bone_parents = bone_parents,
.positions = info_member(accessors.positions, views.positions), .positions = info_member(accessors.positions, views.positions),
.normals = info_member(accessors.normals, views.normals), .normals = info_member(accessors.normals, views.normals),
.bone_indices .bone_indices
@@ -1110,6 +1118,27 @@ static void load_vertices(
} }
} }
static void load_keyframes(
bone_t *restrict keyframes, const uint8_t *restrict bin,
const gltf_info_member_t *translations_info,
const gltf_info_member_t *rotations_info, size_t keyframe_count,
size_t bone_count)
{
for (unsigned b = 0; b < bone_count; ++b) {
const uint8_t *translations = bin + translations_info[b].offset;
const uint8_t *rotations = bin + rotations_info[b].offset;
for (unsigned f = 0; f < keyframe_count; ++f) {
bone_t *dest = keyframes + bone_count * f + b;
memcpy(
&dest->translation, translations + f * sizeof(vec3_t),
sizeof(vec3_t));
memcpy(
&dest->rotation, rotations + f * sizeof(vec4_t),
sizeof(vec4_t));
}
}
}
model_t model_format_glb_read(const char *path) model_t model_format_glb_read(const char *path)
{ {
uint8_t *file = map_file(path); uint8_t *file = map_file(path);
@@ -1140,6 +1169,7 @@ model_t model_format_glb_read(const char *path)
model_t model = model_init(info.vertex_count, info.index_count); model_t model = model_init(info.vertex_count, info.index_count);
model.bone_count = info.bone_count; model.bone_count = info.bone_count;
model.bones = info.bones; model.bones = info.bones;
model.bone_parents = info.bone_parents;
load_vertices( load_vertices(
model.vertices, (const vec3_t *)(bin_data + info.positions.offset), model.vertices, (const vec3_t *)(bin_data + info.positions.offset),
(const vec3_t *)(bin_data + info.normals.offset), (const vec3_t *)(bin_data + info.normals.offset),
@@ -1155,57 +1185,34 @@ model_t model_format_glb_read(const char *path)
// Load animation data // Load animation data
model.animation.keyframe_count = info.animation.keyframe_count; model.animation.keyframe_count = info.animation.keyframe_count;
const size_t times_size = model.animation.keyframe_count * sizeof(float); model.animation.times_us
model.animation.times = malloc(times_size); = malloc(model.animation.keyframe_count * sizeof(uint32_t));
assert(model.animation.times != nullptr); assert(model.animation.times_us != nullptr);
memcpy( const float *times
model.animation.times, bin_data + info.animation.times[0].offset, = (const float *)(bin_data + info.animation.times[0].offset);
times_size); for (unsigned i = 0; i < model.animation.keyframe_count; ++i)
model.animation.length_us = (size_t)roundf( model.animation.times_us[i] = (size_t)roundf(1'000'000 * times[i]);
1'000'000 model.animation.length_us
* model.animation.times[model.animation.keyframe_count - 1]); = model.animation.times_us[model.animation.keyframe_count - 1];
for (unsigned i = 1; i < info.bone_count; ++i) { for (unsigned i = 1; i < info.bone_count; ++i) {
// Verify that all time series data matches // Verify that all time series data matches
if (info.animation.times[i].offset if (info.animation.times[i].offset
!= info.animation.times[0].offset) { != info.animation.times[0].offset) {
assert( assert(
memcmp( memcmp(
model.animation.times, bin_data + info.animation.times[0].offset,
bin_data + info.animation.times[i].offset, times_size) bin_data + info.animation.times[i].offset,
model.animation.keyframe_count * sizeof(float))
== 0); == 0);
} }
} }
model.animation.bones model.animation.keyframes = malloc(
= malloc(model.bone_count * sizeof(animation_bone_t)); model.animation.keyframe_count * model.bone_count * sizeof(bone_t));
assert(model.animation.bones != nullptr); assert(model.animation.keyframes != nullptr);
for (unsigned i = 0; i < info.bone_count; ++i) { load_keyframes(
// Load translations model.animation.keyframes, bin_data, info.animation.translations,
model.animation.bones[i].translations info.animation.rotations, model.animation.keyframe_count,
= malloc(model.animation.keyframe_count * sizeof(vec3_t)); model.bone_count);
assert(model.animation.bones[i].translations != nullptr);
memcpy(
model.animation.bones[i].translations,
bin_data + info.animation.translations[i].offset,
model.animation.keyframe_count * sizeof(vec3_t));
// Load rotations
model.animation.bones[i].rotations
= malloc(model.animation.keyframe_count * sizeof(vec4_t));
assert(model.animation.bones[i].rotations != nullptr);
memcpy(
model.animation.bones[i].rotations,
bin_data + info.animation.rotations[i].offset,
model.animation.keyframe_count * sizeof(vec4_t));
// Load scales
model.animation.bones[i].scales
= malloc(model.animation.keyframe_count * sizeof(vec3_t));
assert(model.animation.bones[i].scales != nullptr);
memcpy(
model.animation.bones[i].scales,
bin_data + info.animation.scales[i].offset,
model.animation.keyframe_count * sizeof(vec3_t));
}
munmap(file, len); munmap(file, len);
return model; return model;