Rework bone and animation structure
This commit is contained in:
1 parent
ffa0beb55a
commit
2a603dc364
3 files changed
+74
-79
No files matched your search
@@ -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;
|
||||||
|
|||||||
@@ -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
@@ -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;
|
||||||
|
|||||||
Reference in new issue
Block a user