summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2024-02-17 11:17:30 -0800
committer3gg <3gg@shellblade.net>2024-02-17 11:17:30 -0800
commit13c7adb42168a566c97f36db76080d80e02a6aae (patch)
tree45699619ee40d38733848364c5f0a12851c945e6
parent54f2b7a097c8d11984c351057f33be8c79a2d5eb (diff)
Pack joints into array to simplify animation data structure and make it easier to clone.
-rw-r--r--gfx/include/gfx/scene/animation.h48
-rw-r--r--gfx/include/gfx/scene/node.h13
-rw-r--r--gfx/src/asset/scene.c163
-rw-r--r--gfx/src/renderer/renderer.c21
-rw-r--r--gfx/src/scene/animation.c185
-rw-r--r--gfx/src/scene/animation_impl.h42
-rw-r--r--gfx/src/scene/node.c32
-rw-r--r--gfx/src/scene/node_impl.h1
-rw-r--r--gfx/src/scene/scene_memory.c6
-rw-r--r--gfx/src/scene/scene_memory.h1
10 files changed, 309 insertions, 203 deletions
diff --git a/gfx/include/gfx/scene/animation.h b/gfx/include/gfx/scene/animation.h
index eeb21fd..42c0c43 100644
--- a/gfx/include/gfx/scene/animation.h
+++ b/gfx/include/gfx/scene/animation.h
@@ -17,25 +17,26 @@
17typedef struct Buffer Buffer; 17typedef struct Buffer Buffer;
18typedef struct SceneNode SceneNode; 18typedef struct SceneNode SceneNode;
19 19
20typedef struct Anima Anima; 20typedef struct Anima Anima;
21typedef struct Joint Joint; 21typedef struct Joint Joint;
22// TODO: Remove this when removing gfx_get_anima_skeleton().
23typedef struct Skeleton Skeleton; 22typedef struct Skeleton Skeleton;
24 23
24/// Index type used to store relative indices into arrays.
25typedef uint16_t rel_idx;
26
27/// Index value denoting no index.
28static const rel_idx INDEX_NONE = (rel_idx)-1;
29
25/// Joint descriptor. 30/// Joint descriptor.
26typedef struct JointDesc { 31typedef struct JointDesc {
27 mat4 inv_bind_matrix; 32 rel_idx parent; /// Parent Joint; index into Anima's joints.
33 mat4 inv_bind_matrix; /// Transforms the mesh into the joint's local space.
28} JointDesc; 34} JointDesc;
29 35
30/// Skeleton descriptor. 36/// Skeleton descriptor.
31///
32/// The last element of the joints array is the root of the hierarchy. For
33/// flexibility (glTF), the root need not be the immediate parent of the
34/// top-level joints of the skeleton, but rather, intermediate non-joint nodes
35/// are allowed between the root and the skeleton.
36typedef struct SkeletonDesc { 37typedef struct SkeletonDesc {
37 size_t num_joints; // Number of joints and matrices. 38 size_t num_joints;
38 const SceneNode* joints[GFX_MAX_NUM_JOINTS]; 39 rel_idx joints[GFX_MAX_NUM_JOINTS]; /// Indices into Anima's joints array.
39} SkeletonDesc; 40} SkeletonDesc;
40 41
41/// Animation interpolation mode. 42/// Animation interpolation mode.
@@ -66,7 +67,7 @@ typedef struct KeyframeDesc {
66 67
67/// Animation channel descriptor. 68/// Animation channel descriptor.
68typedef struct ChannelDesc { 69typedef struct ChannelDesc {
69 SceneNode* target; 70 rel_idx target; /// Index into Anima's joints array.
70 ChannelType type; 71 ChannelType type;
71 AnimationInterpolation interpolation; 72 AnimationInterpolation interpolation;
72 size_t num_keyframes; 73 size_t num_keyframes;
@@ -75,19 +76,25 @@ typedef struct ChannelDesc {
75 76
76/// Animation descriptor. 77/// Animation descriptor.
77typedef struct AnimationDesc { 78typedef struct AnimationDesc {
78 // TODO: Replace the name with a hash for a smaller footprint and faster 79 // TODO: Store a name hash for faster comparisons.
79 // comparisons.
80 sstring name; // Animation name. Required for playback. 80 sstring name; // Animation name. Required for playback.
81 size_t num_channels; // Number of channels. 81 size_t num_channels; // Number of channels.
82 ChannelDesc channels[GFX_MAX_NUM_CHANNELS]; 82 ChannelDesc channels[GFX_MAX_NUM_CHANNELS];
83} AnimationDesc; 83} AnimationDesc;
84 84
85/// Anima object descriptor. 85/// Anima object descriptor.
86///
87/// The last joint of the joints array at index 'num_joints - 1' must be the
88/// root of all skeletons; specifically, the root of all joints that otherwise
89/// would have no parent (a skeleton need not have its own root and can be a set
90/// of disjoint node hierarchies).
86typedef struct AnimaDesc { 91typedef struct AnimaDesc {
87 size_t num_skeletons; 92 size_t num_skeletons;
88 size_t num_animations; 93 size_t num_animations;
94 size_t num_joints;
89 SkeletonDesc skeletons[GFX_MAX_NUM_SKELETONS]; 95 SkeletonDesc skeletons[GFX_MAX_NUM_SKELETONS];
90 AnimationDesc animations[GFX_MAX_NUM_ANIMATIONS]; 96 AnimationDesc animations[GFX_MAX_NUM_ANIMATIONS];
97 JointDesc joints[GFX_MAX_NUM_JOINTS];
91} AnimaDesc; 98} AnimaDesc;
92 99
93/// Animation play settings. 100/// Animation play settings.
@@ -97,15 +104,7 @@ typedef struct AnimationPlaySettings {
97 // TODO: Add animation speed. 104 // TODO: Add animation speed.
98} AnimationPlaySettings; 105} AnimationPlaySettings;
99 106
100/// Create a joint.
101Joint* gfx_make_joint(const JointDesc*);
102
103/// Destroy the joint.
104void gfx_destroy_joint(Joint**);
105
106/// Create an anima object. 107/// Create an anima object.
107///
108/// The anima owns its skeletons and animations.
109Anima* gfx_make_anima(const AnimaDesc*); 108Anima* gfx_make_anima(const AnimaDesc*);
110 109
111/// Destroy the anima. 110/// Destroy the anima.
@@ -120,8 +119,5 @@ void gfx_update_animation(Anima*, R t);
120/// Stop the current animation. 119/// Stop the current animation.
121void gfx_stop_animation(Anima*); 120void gfx_stop_animation(Anima*);
122 121
123// TODO: Remove this, it's ugly. Things would be much simpler if scene nodes 122/// Return the anima's ith skeleton.
124// were allocated in arrays. Then our descs can take indices instead of
125// pointers, and locating a node is simply a matter of indexing the array. The
126// same is true for skeletons here and other objects.
127const Skeleton* gfx_get_anima_skeleton(const Anima* anima, size_t i); 123const Skeleton* gfx_get_anima_skeleton(const Anima* anima, size_t i);
diff --git a/gfx/include/gfx/scene/node.h b/gfx/include/gfx/scene/node.h
index aedac92..7976ae8 100644
--- a/gfx/include/gfx/scene/node.h
+++ b/gfx/include/gfx/scene/node.h
@@ -8,7 +8,6 @@
8#include <stdint.h> 8#include <stdint.h>
9 9
10typedef struct Anima Anima; 10typedef struct Anima Anima;
11typedef struct Joint Joint;
12typedef struct Light Light; 11typedef struct Light Light;
13typedef struct SceneCamera SceneCamera; 12typedef struct SceneCamera SceneCamera;
14typedef struct SceneObject SceneObject; 13typedef struct SceneObject SceneObject;
@@ -21,7 +20,6 @@ typedef enum NodeType {
21 LogicalNode, 20 LogicalNode,
22 AnimaNode, 21 AnimaNode,
23 CameraNode, 22 CameraNode,
24 JointNode,
25 LightNode, 23 LightNode,
26 ObjectNode 24 ObjectNode
27} NodeType; 25} NodeType;
@@ -48,9 +46,6 @@ SceneNode* gfx_make_anima_node(Anima*);
48/// Create a new camera node. 46/// Create a new camera node.
49SceneNode* gfx_make_camera_node(SceneCamera*); 47SceneNode* gfx_make_camera_node(SceneCamera*);
50 48
51/// Create a joint node.
52SceneNode* gfx_make_joint_node(Joint*);
53
54/// Create a new light node. 49/// Create a new light node.
55SceneNode* gfx_make_light_node(Light*); 50SceneNode* gfx_make_light_node(Light*);
56 51
@@ -63,9 +58,6 @@ void gfx_construct_anima_node(SceneNode*, Anima*);
63/// Make the node a camera node. 58/// Make the node a camera node.
64void gfx_construct_camera_node(SceneNode*, SceneCamera*); 59void gfx_construct_camera_node(SceneNode*, SceneCamera*);
65 60
66/// Make the node a joint node.
67void gfx_construct_joint_node(SceneNode*, Joint*);
68
69/// Make the node a light node. 61/// Make the node a light node.
70void gfx_construct_light_node(SceneNode*, Light*); 62void gfx_construct_light_node(SceneNode*, Light*);
71 63
@@ -96,11 +88,6 @@ Anima* gfx_get_node_anima(const SceneNode*);
96/// The node must be of type CameraNode. 88/// The node must be of type CameraNode.
97SceneCamera* gfx_get_node_camera(const SceneNode* node); 89SceneCamera* gfx_get_node_camera(const SceneNode* node);
98 90
99/// Get the node's joint.
100///
101/// The node must be of type JointNode.
102Joint* gfx_get_node_joint(const SceneNode*);
103
104/// Get the node's light. 91/// Get the node's light.
105/// 92///
106/// The node must be of type LightNode. 93/// The node must be of type LightNode.
diff --git a/gfx/src/asset/scene.c b/gfx/src/asset/scene.c
index 156e7b6..ef2328c 100644
--- a/gfx/src/asset/scene.c
+++ b/gfx/src/asset/scene.c
@@ -1177,63 +1177,147 @@ static bool load_meshes(
1177 return true; 1177 return true;
1178} 1178}
1179 1179
1180/// Find the joint node with the smallest index across all skeletons.
1181///
1182/// The channels in glTF may target arbitrary nodes in the scene (those nodes
1183/// are the joints). However, we want to map the "base joint" (the joint/node
1184/// with the smallest index) to 0 in the AnimaDesc's joint array. We can do this
1185/// by subtracting the "base node index" from every joint index or channel
1186/// target.
1187///
1188/// There is an assumption in the animation library that joints are contiguous
1189/// anyway, so this "base joint index" works provided the joint nodes are also
1190/// contiguous in the glTF. The glTF does not guarantee this, but I think it's
1191/// a reasonable assumption that exporters write glTF files in such a way, and
1192/// Blender does appear to do so.
1193cgltf_size find_base_joint_index(const cgltf_data* data) {
1194 assert(data);
1195
1196 cgltf_size base_joint_index = (cgltf_size)-1;
1197
1198 for (cgltf_size s = 0; s < data->skins_count; ++s) {
1199 const cgltf_skin* skin = &data->skins[s];
1200 for (cgltf_size j = 0; j < skin->joints_count; ++j) {
1201 // Joint is an index/pointer into the nodes array.
1202 const cgltf_size node_index = skin->joints[j] - data->nodes;
1203 assert(node_index < data->nodes_count);
1204 // Min.
1205 if (node_index < base_joint_index) {
1206 base_joint_index = node_index;
1207 }
1208 }
1209 }
1210
1211 return base_joint_index;
1212}
1213
1180/// Load all skins (Gfx skeletons) from the glTF scene. 1214/// Load all skins (Gfx skeletons) from the glTF scene.
1181static void load_skins( 1215/// Return the total number of joints.
1182 const cgltf_data* data, Buffer* const* buffers, SceneNode** nodes, 1216static size_t load_skins(
1183 SkeletonDesc* descs) { 1217 const cgltf_data* data, Buffer* const* buffers, cgltf_size base_joint_index,
1218 AnimaDesc* anima_desc) {
1184 assert(data); 1219 assert(data);
1185 assert(buffers); 1220 assert(buffers);
1186 assert(nodes); 1221 assert(anima_desc);
1187 assert(descs); 1222 assert(base_joint_index < data->nodes_count);
1223
1224 // Determines whether the ith joint in the node hierarchy is a joint node.
1225 // This is then used to determine whether a joint is a root of the joint
1226 // hierarchy.
1227 bool is_joint_node[GFX_MAX_NUM_JOINTS] = {false};
1228
1229 size_t num_joints = 0;
1188 1230
1189 for (cgltf_size s = 0; s < data->skins_count; ++s) { 1231 for (cgltf_size s = 0; s < data->skins_count; ++s) {
1190 const cgltf_skin* skin = &data->skins[s]; 1232 const cgltf_skin* skin = &data->skins[s];
1191 const cgltf_accessor* matrices_accessor = skin->inverse_bind_matrices; 1233 const cgltf_accessor* matrices_accessor = skin->inverse_bind_matrices;
1192 assert(matrices_accessor->count == skin->joints_count); 1234 assert(matrices_accessor->count == skin->joints_count);
1193 SkeletonDesc* desc = &descs[s];
1194 1235
1195 *desc = (SkeletonDesc){.num_joints = skin->joints_count}; 1236 num_joints += skin->joints_count;
1237 assert(num_joints < GFX_MAX_NUM_JOINTS);
1238
1239 SkeletonDesc* skeleton_desc = &anima_desc->skeletons[s];
1240 *skeleton_desc = (SkeletonDesc){.num_joints = skin->joints_count};
1196 1241
1197 assert(skin->joints_count < GFX_MAX_NUM_JOINTS);
1198 // for (cgltf_size j = 0; j < skin->joints_count; ++j) { 1242 // for (cgltf_size j = 0; j < skin->joints_count; ++j) {
1199 ACCESSOR_FOREACH_MAT(4, matrices_accessor, { 1243 ACCESSOR_FOREACH_MAT(4, matrices_accessor, {
1200 const mat4 inv_bind_matrix = mat4_from_array(floats); 1244 const mat4 inv_bind_matrix = mat4_from_array(floats);
1201 1245
1246 // Joint is an index/pointer into the nodes array.
1202 const cgltf_size node_index = skin->joints[i] - data->nodes; 1247 const cgltf_size node_index = skin->joints[i] - data->nodes;
1203 assert(node_index < data->nodes_count); 1248 assert(node_index < data->nodes_count);
1204 SceneNode* node = nodes[node_index];
1205 1249
1206 // Transform the node into a joint node. 1250 const cgltf_size parent_node_index =
1207 const JointDesc joint_desc = 1251 skin->joints[i]->parent - data->nodes;
1208 (JointDesc){.inv_bind_matrix = inv_bind_matrix}; 1252 assert(parent_node_index < data->nodes_count);
1209 Joint* joint = gfx_make_joint(&joint_desc); 1253
1210 gfx_construct_joint_node(node, joint); 1254 // Subtract the base index to pack the joints as tightly as possible in
1255 // the AnimaDesc.
1256 assert(node_index >= base_joint_index);
1257 const cgltf_size joint_index = node_index - base_joint_index;
1211 1258
1212 desc->joints[i] = node; 1259 assert(parent_node_index >= base_joint_index);
1260 const cgltf_size parent_index = parent_node_index - base_joint_index;
1261
1262 skeleton_desc->joints[i] = joint_index;
1263
1264 JointDesc* joint_desc = &anima_desc->joints[joint_index];
1265 joint_desc->parent = parent_index;
1266 joint_desc->inv_bind_matrix = inv_bind_matrix;
1267
1268 is_joint_node[joint_index] = true;
1213 }); 1269 });
1214 1270
1215 // glTF may specify a "skeleton", which is the root of the skeleton's node 1271 // glTF may specify a "skeleton", which is the root of the skin's
1216 // hierarchy. TODO: We could use this root node to optimize the descend in 1272 // (skeleton's) node hierarchy.
1217 // joint matrix computation. The root node should be passed with the
1218 // AnimaDesc.
1219 // if (skin->skeleton) { 1273 // if (skin->skeleton) {
1220 // cgltf_size root_index = skin->skeleton - data->nodes; 1274 // // cgltf_size root_index = skin->skeleton - data->nodes;
1221 // assert(root_index <= data->nodes_count); 1275 // // assert(root_index <= data->nodes_count);
1222 // root_node = nodes[root_index]; 1276 // // root_node = nodes[root_index];
1223 // } 1277 // assert(false);
1278 //}
1279 }
1280
1281 // Animation library assumes that joints are contiguous.
1282 for (size_t i = 0; i < num_joints; ++i) {
1283 assert(is_joint_node[i]);
1224 } 1284 }
1285
1286 // Insert the root joint.
1287 // This is the root of all skeletons. It is, specifically, the root of all
1288 // joints that do not have a parent; skins (skeletons) in glTF are not
1289 // guaranteed to have a common parent, but are generally a set of disjoint
1290 // trees.
1291 const size_t root_index = num_joints;
1292 assert(root_index < GFX_MAX_NUM_JOINTS);
1293 anima_desc->joints[root_index] = (JointDesc){.parent = INDEX_NONE};
1294 num_joints++;
1295
1296 // Make root joints point to the root joint at index N.
1297 // The root joints are the ones that have a non-joint node in the glTF as a
1298 // parent.
1299 for (size_t i = 0; i < root_index; ++i) {
1300 JointDesc* joint = &anima_desc->joints[i];
1301 if ((joint->parent >= root_index) || !is_joint_node[joint->parent]) {
1302 joint->parent = root_index;
1303 }
1304 }
1305
1306 return num_joints;
1225} 1307}
1226 1308
1227/// Load all animations from the glTF scene. 1309/// Load all animations from the glTF scene.
1228static void load_animations( 1310static void load_animations(
1229 const cgltf_data* data, SceneNode** nodes, AnimationDesc* descs) { 1311 const cgltf_data* data, cgltf_size base_joint_index,
1312 AnimaDesc* anima_desc) {
1230 assert(data); 1313 assert(data);
1231 assert(nodes); 1314 assert(anima_desc);
1232 assert(descs); 1315 assert(base_joint_index < data->nodes_count);
1316 assert(data->animations_count <= GFX_MAX_NUM_ANIMATIONS);
1233 1317
1234 for (cgltf_size a = 0; a < data->animations_count; ++a) { 1318 for (cgltf_size a = 0; a < data->animations_count; ++a) {
1235 const cgltf_animation* animation = &data->animations[a]; 1319 const cgltf_animation* animation = &data->animations[a];
1236 AnimationDesc* animation_desc = &descs[a]; 1320 AnimationDesc* animation_desc = &anima_desc->animations[a];
1237 1321
1238 *animation_desc = (AnimationDesc){ 1322 *animation_desc = (AnimationDesc){
1239 .name = sstring_make(animation->name), 1323 .name = sstring_make(animation->name),
@@ -1244,13 +1328,16 @@ static void load_animations(
1244 const cgltf_animation_channel* channel = &animation->channels[c]; 1328 const cgltf_animation_channel* channel = &animation->channels[c];
1245 ChannelDesc* channel_desc = &animation_desc->channels[c]; 1329 ChannelDesc* channel_desc = &animation_desc->channels[c];
1246 const cgltf_animation_sampler* sampler = channel->sampler; 1330 const cgltf_animation_sampler* sampler = channel->sampler;
1247 const size_t node_index = channel->target_node - data->nodes; 1331
1248 assert(node_index < data->nodes_count); 1332 const size_t target_index = channel->target_node - data->nodes;
1249 SceneNode* target = nodes[node_index]; 1333 assert(target_index < data->nodes_count);
1250 assert(target); 1334
1335 assert(target_index >= base_joint_index);
1336 const size_t tight_target_index = target_index - base_joint_index;
1337 assert(tight_target_index < anima_desc->num_joints);
1251 1338
1252 *channel_desc = (ChannelDesc){ 1339 *channel_desc = (ChannelDesc){
1253 .target = target, 1340 .target = tight_target_index,
1254 .type = from_gltf_animation_path_type(channel->target_path), 1341 .type = from_gltf_animation_path_type(channel->target_path),
1255 .interpolation = from_gltf_interpolation_type(sampler->interpolation), 1342 .interpolation = from_gltf_interpolation_type(sampler->interpolation),
1256 .num_keyframes = 0}; 1343 .num_keyframes = 0};
@@ -1316,8 +1403,8 @@ static void load_nodes(
1316 const cgltf_size mesh_index = node->mesh - data->meshes; 1403 const cgltf_size mesh_index = node->mesh - data->meshes;
1317 assert(mesh_index < data->meshes_count); 1404 assert(mesh_index < data->meshes_count);
1318 SceneObject* object = objects[mesh_index]; 1405 SceneObject* object = objects[mesh_index];
1319
1320 gfx_construct_object_node(nodes[n], object); 1406 gfx_construct_object_node(nodes[n], object);
1407
1321 if (node->skin) { 1408 if (node->skin) {
1322 assert(anima); 1409 assert(anima);
1323 1410
@@ -1522,12 +1609,14 @@ static SceneNode* load_scene(
1522 goto cleanup; 1609 goto cleanup;
1523 } 1610 }
1524 1611
1525 load_skins(data, buffers, scene_nodes, anima_desc->skeletons); 1612 const cgltf_size base = find_base_joint_index(data);
1526 load_animations(data, scene_nodes, anima_desc->animations);
1527 1613
1528 anima_desc->num_skeletons = data->skins_count; 1614 anima_desc->num_skeletons = data->skins_count;
1529 anima_desc->num_animations = data->animations_count; 1615 anima_desc->num_animations = data->animations_count;
1530 anima = gfx_make_anima(anima_desc); 1616 anima_desc->num_joints = load_skins(data, buffers, base, anima_desc);
1617 load_animations(data, base, anima_desc);
1618
1619 anima = gfx_make_anima(anima_desc);
1531 gfx_construct_anima_node(root_node, anima); 1620 gfx_construct_anima_node(root_node, anima);
1532 } 1621 }
1533 gfx_set_node_parent(root_node, parent_node); 1622 gfx_set_node_parent(root_node, parent_node);
@@ -1535,6 +1624,8 @@ static SceneNode* load_scene(
1535 // The root node becomes the root of all scene nodes. 1624 // The root node becomes the root of all scene nodes.
1536 load_nodes(data, root_node, scene_objects, scene_cameras, anima, scene_nodes); 1625 load_nodes(data, root_node, scene_objects, scene_cameras, anima, scene_nodes);
1537 1626
1627 // TODO: Clean up scene nodes that correspond to joints in the glTF.
1628
1538 success = true; 1629 success = true;
1539 1630
1540cleanup: 1631cleanup:
diff --git a/gfx/src/renderer/renderer.c b/gfx/src/renderer/renderer.c
index ac6a45f..5cc06d6 100644
--- a/gfx/src/renderer/renderer.c
+++ b/gfx/src/renderer/renderer.c
@@ -175,9 +175,10 @@ typedef struct RenderState {
175 const mat4* camera_rotation; // From camera to world space, rotation only. 175 const mat4* camera_rotation; // From camera to world space, rotation only.
176 const mat4* view_matrix; 176 const mat4* view_matrix;
177 const mat4* projection; 177 const mat4* projection;
178 Light* environment_light;
179 const float fovy; 178 const float fovy;
180 const float aspect; 179 const float aspect;
180 Light* environment_light;
181 Anima* anima;
181 size_t num_joints; 182 size_t num_joints;
182 mat4 joint_matrices[GFX_MAX_NUM_JOINTS]; 183 mat4 joint_matrices[GFX_MAX_NUM_JOINTS];
183} RenderState; 184} RenderState;
@@ -191,15 +192,13 @@ static void load_skeleton(RenderState* state, skeleton_idx skeleton_index) {
191 assert(skeleton); 192 assert(skeleton);
192 assert(skeleton->num_joints <= GFX_MAX_NUM_JOINTS); 193 assert(skeleton->num_joints <= GFX_MAX_NUM_JOINTS);
193 194
195 state->num_joints = skeleton->num_joints;
196
194 for (size_t i = 0; i < skeleton->num_joints; ++i) { 197 for (size_t i = 0; i < skeleton->num_joints; ++i) {
195 const SceneNode* node = mem_get_node(skeleton->joints[i]); 198 const rel_idx joint_index = skeleton->joints[i];
196 assert(node); 199 const Joint* joint = &state->anima->joints[joint_index];
197 assert(node->type == JointNode); 200 state->joint_matrices[i] = joint->joint_matrix;
198 const Joint* joint = mem_get_joint(node->joint);
199 assert(joint);
200 state->joint_matrices[i] = joint->joint_matrix;
201 } 201 }
202 state->num_joints = skeleton->num_joints;
203} 202}
204 203
205/// Draw the scene recursively. 204/// Draw the scene recursively.
@@ -209,7 +208,9 @@ static void draw_recursively(
209 const mat4 node_transform = mat4_mul(parent_transform, node->transform); 208 const mat4 node_transform = mat4_mul(parent_transform, node->transform);
210 209
211 // Activate light. 210 // Activate light.
212 if (node->type == LightNode) { 211 if (node->type == AnimaNode) {
212 state->anima = gfx_get_node_anima(node);
213 } else if (node->type == LightNode) {
213 Light* light = mem_get_light(node->light); 214 Light* light = mem_get_light(node->light);
214 assert(light); 215 assert(light);
215 216
@@ -349,6 +350,6 @@ void gfx_render_scene(Renderer* renderer, const RenderSceneParams* params) {
349 // Assuming a perspective matrix. 350 // Assuming a perspective matrix.
350 .fovy = atan(1.0 / (mat4_at(projection, 1, 1))) * 2, 351 .fovy = atan(1.0 / (mat4_at(projection, 1, 1))) * 2,
351 .aspect = aspect}; 352 .aspect = aspect};
352 353
353 draw_recursively(&state, mat4_id(), scene->root); 354 draw_recursively(&state, mat4_id(), scene->root);
354} 355}
diff --git a/gfx/src/scene/animation.c b/gfx/src/scene/animation.c
index 459e864..18e2a99 100644
--- a/gfx/src/scene/animation.c
+++ b/gfx/src/scene/animation.c
@@ -3,42 +3,78 @@
3#include "node_impl.h" 3#include "node_impl.h"
4#include "scene_memory.h" 4#include "scene_memory.h"
5 5
6#include <string.h>
7
6// #include <log/log.h> // Debugging. 8// #include <log/log.h> // Debugging.
7 9
8static const R PLAYBACK_UNINITIALIZED = -1; 10static const R PLAYBACK_UNINITIALIZED = -1;
9 11
10Joint* gfx_make_joint(const JointDesc* desc) { 12static rel_idx get_anima_root_joint_index(Anima* anima) {
13 assert(anima);
14 assert(anima->num_joints > 0);
15 assert(anima->num_joints < GFX_MAX_NUM_JOINTS);
16 return anima->num_joints - 1;
17}
18
19static Joint* get_anima_root_joint(Anima* anima) {
20 assert(anima);
21 return &anima->joints[get_anima_root_joint_index(anima)];
22}
23
24static Joint* get_anima_joint(Anima* anima, rel_idx index) {
25 assert(anima);
26 assert(index < GFX_MAX_NUM_JOINTS);
27 assert(index != INDEX_NONE);
28 assert(index < anima->num_joints);
29 return &anima->joints[index];
30}
31
32static void set_joint_parent(
33 Anima* anima, rel_idx joint_index, rel_idx parent_index) {
34 assert(anima);
35 assert(joint_index != INDEX_NONE);
36 assert(joint_index != get_anima_root_joint_index(anima));
37 assert(parent_index != INDEX_NONE);
38
39 Joint* parent = get_anima_joint(anima, parent_index);
40
41 if (parent->child == INDEX_NONE) {
42 parent->child = joint_index;
43 } else {
44 // Find the last child in the chain of children.
45 Joint* child = get_anima_joint(anima, parent->child);
46 while (child->next != INDEX_NONE) {
47 child = get_anima_joint(anima, child->next);
48 }
49 // Wire up this joint as the last child's sibling.
50 child->next = joint_index;
51 }
52}
53
54static void make_joint(Anima* anima, const JointDesc* desc, Joint* joint) {
55 assert(anima);
11 assert(desc); 56 assert(desc);
57 assert(joint);
12 58
13 // The joint matrix needs to be initialized so that meshes look right even if 59 // The joint matrix needs to be initialized so that meshes look right even if
14 // no animation is played. Initializing joint matrices to the identity makes 60 // no animation is played. Initializing joint matrices to the identity makes
15 // meshes appear in their bind pose. 61 // meshes appear in their bind pose.
16 Joint* joint = mem_alloc_joint(); 62 joint->child = INDEX_NONE;
63 joint->next = INDEX_NONE;
64 joint->transform = mat4_id();
17 joint->inv_bind_matrix = desc->inv_bind_matrix; 65 joint->inv_bind_matrix = desc->inv_bind_matrix;
18 joint->joint_matrix = mat4_id(); 66 joint->joint_matrix = mat4_id();
19 return joint;
20}
21
22void gfx_destroy_joint(Joint** joint) {
23 assert(joint);
24
25 if (*joint) {
26 if ((*joint)->parent.val) {
27 gfx_del_node((*joint)->parent);
28 }
29 mem_free_joint(joint);
30 }
31} 67}
32 68
33static Skeleton* make_skeleton(const SkeletonDesc* desc) { 69static Skeleton* make_skeleton(const SkeletonDesc* desc) {
34 assert(desc); 70 assert(desc);
35 assert(desc->num_joints < GFX_MAX_NUM_JOINTS); 71 assert(desc->num_joints <= GFX_MAX_NUM_JOINTS);
36 72
37 Skeleton* skeleton = mem_alloc_skeleton(); 73 Skeleton* skeleton = mem_alloc_skeleton();
38 skeleton->num_joints = desc->num_joints; 74 skeleton->num_joints = desc->num_joints;
39 for (size_t i = 0; i < desc->num_joints; ++i) { 75 memcpy(
40 skeleton->joints[i] = mem_get_node_index(desc->joints[i]); 76 skeleton->joints, desc->joints,
41 } 77 desc->num_joints * sizeof(skeleton->joints[0]));
42 return skeleton; 78 return skeleton;
43} 79}
44 80
@@ -56,7 +92,7 @@ static Animation* make_animation(const AnimationDesc* desc) {
56 const ChannelDesc* channel_desc = &desc->channels[c]; 92 const ChannelDesc* channel_desc = &desc->channels[c];
57 Channel* channel = &animation->channels[c]; 93 Channel* channel = &animation->channels[c];
58 94
59 channel->target = mem_get_node_index(channel_desc->target); 95 channel->target = channel_desc->target;
60 channel->type = channel_desc->type; 96 channel->type = channel_desc->type;
61 channel->interpolation = channel_desc->interpolation; 97 channel->interpolation = channel_desc->interpolation;
62 channel->num_keyframes = channel_desc->num_keyframes; 98 channel->num_keyframes = channel_desc->num_keyframes;
@@ -82,6 +118,16 @@ static Animation* make_animation(const AnimationDesc* desc) {
82 118
83Anima* gfx_make_anima(const AnimaDesc* desc) { 119Anima* gfx_make_anima(const AnimaDesc* desc) {
84 assert(desc); 120 assert(desc);
121 assert(desc->num_joints > 0);
122 assert(desc->num_joints <= GFX_MAX_NUM_JOINTS);
123 // All joints should have a parent except for the root.
124 for (size_t i = 0; i < desc->num_joints - 1; ++i) {
125 const rel_idx parent = desc->joints[i].parent;
126 assert(parent != INDEX_NONE);
127 assert(parent < desc->num_joints);
128 }
129 // The root should have no parent.
130 assert(desc->joints[desc->num_joints - 1].parent == INDEX_NONE);
85 131
86 Anima* anima = mem_alloc_anima(); 132 Anima* anima = mem_alloc_anima();
87 133
@@ -114,6 +160,20 @@ Anima* gfx_make_anima(const AnimaDesc* desc) {
114 last_animation = animation; 160 last_animation = animation;
115 } 161 }
116 162
163 // Create joints.
164 anima->num_joints = desc->num_joints;
165 // Initialize all joints.
166 // Child and sibling pointers must be initialized before wiring up the
167 // hierarchy.
168 for (size_t i = 0; i < desc->num_joints; ++i) {
169 Joint* joint = get_anima_joint(anima, i);
170 make_joint(anima, &desc->joints[i], joint);
171 }
172 // Wire up joints to their parents. -1 to skip the root.
173 for (size_t i = 0; i < desc->num_joints - 1; ++i) {
174 set_joint_parent(anima, i, desc->joints[i].parent);
175 }
176
117 return anima; 177 return anima;
118} 178}
119 179
@@ -177,6 +237,16 @@ bool gfx_play_animation(Anima* anima, const AnimationPlaySettings* settings) {
177 return true; 237 return true;
178} 238}
179 239
240static void gfx_set_joint_position(Joint* joint, vec3 position) {
241 assert(joint);
242 mat4_set_v3(&joint->transform, position);
243}
244
245static void gfx_set_joint_rotation(Joint* joint, quat rotation) {
246 assert(joint);
247 mat4_set_3x3(&joint->transform, mat4_from_quat(rotation));
248}
249
180static void find_keyframes(const Channel* channel, R t, int* prev, int* next) { 250static void find_keyframes(const Channel* channel, R t, int* prev, int* next) {
181 assert(channel); 251 assert(channel);
182 assert(prev); 252 assert(prev);
@@ -255,9 +325,10 @@ static vec3 interpolate_translation(
255 } 325 }
256} 326}
257 327
258static void animate_channel(const Channel* channel, R t) { 328static void animate_channel(Anima* anima, const Channel* channel, R t) {
329 assert(anima);
259 assert(channel); 330 assert(channel);
260 assert(channel->target.val != 0); 331 assert(channel->target < anima->num_joints);
261 332
262 int prev, next; 333 int prev, next;
263 find_keyframes(channel, t, &prev, &next); 334 find_keyframes(channel, t, &prev, &next);
@@ -268,17 +339,17 @@ static void animate_channel(const Channel* channel, R t) {
268 // work. 339 // work.
269 t = t > channel->keyframes[next].time ? channel->keyframes[next].time : t; 340 t = t > channel->keyframes[next].time ? channel->keyframes[next].time : t;
270 341
271 SceneNode* target = mem_get_node(channel->target); 342 Joint* target = get_anima_joint(anima, channel->target);
272 343
273 switch (channel->type) { 344 switch (channel->type) {
274 case RotationChannel: { 345 case RotationChannel: {
275 const quat rotation = interpolate_rotation(channel, prev, next, t); 346 const quat rotation = interpolate_rotation(channel, prev, next, t);
276 gfx_set_node_rotation(target, &rotation); 347 gfx_set_joint_rotation(target, rotation);
277 break; 348 break;
278 } 349 }
279 case TranslationChannel: { 350 case TranslationChannel: {
280 const vec3 translation = interpolate_translation(channel, prev, next, t); 351 const vec3 translation = interpolate_translation(channel, prev, next, t);
281 gfx_set_node_position(target, &translation); 352 gfx_set_joint_position(target, translation);
282 break; 353 break;
283 } 354 }
284 // Not yet supported. 355 // Not yet supported.
@@ -292,35 +363,36 @@ static void animate_channel(const Channel* channel, R t) {
292} 363}
293 364
294static void compute_joint_matrices_rec( 365static void compute_joint_matrices_rec(
295 node_idx node_index, mat4 parent_global_joint_transform, 366 Anima* anima, Joint* joint, const mat4* parent_global_joint_transform,
296 const mat4* root_inv_global_transform) { 367 const mat4* root_inv_global_transform) {
297 if (node_index.val == 0) { 368 assert(anima);
298 return; 369 assert(joint);
299 } 370 assert(parent_global_joint_transform);
371 assert(root_inv_global_transform);
300 372
301 const SceneNode* node = mem_get_node(node_index); 373 const mat4 global_joint_transform =
302 const mat4 global_joint_transform = 374 mat4_mul(*parent_global_joint_transform, joint->transform);
303 mat4_mul(parent_global_joint_transform, node->transform);
304 375
305 // For flexibility (glTF), we allow non-joint nodes between the root of the 376 // Compute this joint's matrix.
306 // skeleton and its joint nodes. We check the node type as opposed to assert 377 joint->joint_matrix = mat4_mul(
307 // it. 378 *root_inv_global_transform,
308 if (node->type == JointNode) { 379 mat4_mul(global_joint_transform, joint->inv_bind_matrix));
309 // Compute this node's joint matrix.
310 Joint* joint = mem_get_joint(node->joint);
311 380
312 joint->joint_matrix = mat4_mul( 381 // Recursively compute the joint matrices for this joint's siblings.
313 *root_inv_global_transform, 382 if (joint->next != INDEX_NONE) {
314 mat4_mul(global_joint_transform, joint->inv_bind_matrix)); 383 Joint* sibling = get_anima_joint(anima, joint->next);
384
385 compute_joint_matrices_rec(
386 anima, sibling, parent_global_joint_transform,
387 root_inv_global_transform);
315 } 388 }
316 389
317 // Recursively compute the joint matrices for this node's children. 390 // Recursively compute the joint matrices for this joint's children.
318 node_idx child = node->child; 391 if (joint->child != INDEX_NONE) {
319 while (child.val != 0) { 392 Joint* child = get_anima_joint(anima, joint->child);
393
320 compute_joint_matrices_rec( 394 compute_joint_matrices_rec(
321 child, global_joint_transform, root_inv_global_transform); 395 anima, child, &global_joint_transform, root_inv_global_transform);
322 node = mem_get_node(child);
323 child = node->next; // Next sibling.
324 } 396 }
325} 397}
326 398
@@ -354,7 +426,7 @@ void gfx_update_animation(Anima* anima, R t) {
354 // Play through the animation to transform skeleton nodes. 426 // Play through the animation to transform skeleton nodes.
355 for (size_t i = 0; i < animation->num_channels; ++i) { 427 for (size_t i = 0; i < animation->num_channels; ++i) {
356 const Channel* channel = &animation->channels[i]; 428 const Channel* channel = &animation->channels[i];
357 animate_channel(channel, animation_time); 429 animate_channel(anima, channel, animation_time);
358 } 430 }
359 431
360 // Compute joint matrices after having transformed the skeletons. 432 // Compute joint matrices after having transformed the skeletons.
@@ -369,19 +441,14 @@ void gfx_update_animation(Anima* anima, R t) {
369 // 441 //
370 // Lack of a common parent aside, the procedure touches every joint exactly 442 // Lack of a common parent aside, the procedure touches every joint exactly
371 // once (and potentially other non-joint intermediate nodes). 443 // once (and potentially other non-joint intermediate nodes).
372 node_idx root_index = anima->parent; 444 SceneNode* root_node = mem_get_node(anima->parent);
373 SceneNode* root = mem_get_node(root_index); 445 // LOGD("Root: %u, child: %u", anima->parent.val, root->child.val);
374 // LOGD("Root: %u, child: %u", root_index.val, root->child.val); 446 const mat4 root_global_transform = gfx_get_node_global_transform(root_node);
375 const mat4 root_global_transform = gfx_get_node_global_transform(root);
376 const mat4 root_inv_global_transform = mat4_inverse(root_global_transform); 447 const mat4 root_inv_global_transform = mat4_inverse(root_global_transform);
377 // Step over root's children (siblings of the first child). 448
378 node_idx child = root->child; 449 Joint* root_joint = get_anima_root_joint(anima);
379 while (child.val != 0) { 450 compute_joint_matrices_rec(
380 compute_joint_matrices_rec( 451 anima, root_joint, &root_global_transform, &root_inv_global_transform);
381 child, root_global_transform, &root_inv_global_transform);
382 SceneNode* node = mem_get_node(child);
383 child = node->next; // Next sibling.
384 }
385} 452}
386 453
387const Skeleton* gfx_get_anima_skeleton(const Anima* anima, size_t i) { 454const Skeleton* gfx_get_anima_skeleton(const Anima* anima, size_t i) {
diff --git a/gfx/src/scene/animation_impl.h b/gfx/src/scene/animation_impl.h
index ceebbbf..7265858 100644
--- a/gfx/src/scene/animation_impl.h
+++ b/gfx/src/scene/animation_impl.h
@@ -20,32 +20,27 @@ typedef struct Buffer Buffer;
20// 20//
21// TODO: Simultaneous animation of disjoint animations. 21// TODO: Simultaneous animation of disjoint animations.
22 22
23/// Skeleton joint.
24/// Joints are mutable and store the transform and joint matrices that result
25/// from animation, aside from the inverse bind matrix.
23typedef struct Joint { 26typedef struct Joint {
24 node_idx parent; // Parent SceneNode. 27 rel_idx child; /// First child Joint; index into Anima's joints.
25 mat4 inv_bind_matrix; 28 rel_idx next; /// Next sibling Joint; index into Anima's joints.
26 mat4 joint_matrix; 29 mat4 transform; /// Local transform relative to parent.
30 mat4 inv_bind_matrix; /// Transforms the mesh into the joint's local space.
31 mat4 joint_matrix; /// inv(global) * global joint transform * inv(bind).
27} Joint; 32} Joint;
28 33
29/// Animation skeleton. 34/// Animation skeleton.
30///
31/// The joints array maps joint indices to scene nodes.
32///
33/// The last element of the joints array is the root of the hierarchy. Storing
34/// the root of the hierarchy allows us to compute joint matrices only for scene
35/// nodes that are actually part of a skeleton, since the root identifies the
36/// skeleton's node hierarchy.
37///
38/// Some model formats (glTF) may not actually specify a root. In that case, the
39/// client must create one to form a strict tree hierarchy.
40typedef struct Skeleton { 35typedef struct Skeleton {
41 skeleton_idx next; 36 skeleton_idx next;
42 size_t num_joints; 37 size_t num_joints;
43 node_idx joints[GFX_MAX_NUM_JOINTS]; // Last = root. 38 rel_idx joints[GFX_MAX_NUM_JOINTS]; /// Indices into Anima's joints array.
44} Skeleton; 39} Skeleton;
45 40
46/// A keyframe of animation. 41/// A keyframe of animation.
47typedef struct Keyframe { 42typedef struct Keyframe {
48 R time; // Start time in [0, end animation time] 43 R time; /// Start time in [0, end animation time]
49 union { 44 union {
50 vec3 translation; 45 vec3 translation;
51 quat rotation; 46 quat rotation;
@@ -54,7 +49,7 @@ typedef struct Keyframe {
54 49
55/// Animation channel. 50/// Animation channel.
56typedef struct Channel { 51typedef struct Channel {
57 node_idx target; 52 rel_idx target; /// Index into Anima's joints array.
58 ChannelType type; 53 ChannelType type;
59 AnimationInterpolation interpolation; 54 AnimationInterpolation interpolation;
60 size_t num_keyframes; 55 size_t num_keyframes;
@@ -87,9 +82,16 @@ typedef struct AnimationState {
87/// 82///
88/// For lack of a better name, this is called an Anima. It is short and the 83/// For lack of a better name, this is called an Anima. It is short and the
89/// Latin root of animation. 84/// Latin root of animation.
85///
86/// The last joint of the joints array at index 'num_joints - 1' is the root of
87/// all skeletons; specifically, the root of all joints that otherwise would
88/// have no parent (a skeleton need not have its own root and can be a set of
89/// disjoint node hierarchies).
90typedef struct Anima { 90typedef struct Anima {
91 AnimationState state; 91 node_idx parent; /// Parent SceneNode.
92 skeleton_idx skeleton; 92 skeleton_idx skeleton; /// Index of first skeleton.
93 animation_idx animation; // Index of first animation. 93 animation_idx animation; /// Index of first animation.
94 node_idx parent; // Parent SceneNode. 94 AnimationState state; /// Current animation state.
95 size_t num_joints; /// Number of actual joints in the array.
96 Joint joints[GFX_MAX_NUM_JOINTS]; /// Shared by all skeletons.
95} Anima; 97} Anima;
diff --git a/gfx/src/scene/node.c b/gfx/src/scene/node.c
index 333dc28..1a68216 100644
--- a/gfx/src/scene/node.c
+++ b/gfx/src/scene/node.c
@@ -41,15 +41,6 @@ SceneNode* gfx_make_camera_node(SceneCamera* camera) {
41 return node; 41 return node;
42} 42}
43 43
44SceneNode* gfx_make_joint_node(Joint* joint) {
45 assert(joint);
46 SceneNode* node = gfx_make_node();
47 node->type = JointNode;
48 node->joint = mem_get_joint_index(joint);
49 joint->parent = mem_get_node_index(node);
50 return node;
51}
52
53SceneNode* gfx_make_light_node(Light* light) { 44SceneNode* gfx_make_light_node(Light* light) {
54 assert(light); 45 assert(light);
55 SceneNode* node = gfx_make_node(); 46 SceneNode* node = gfx_make_node();
@@ -87,12 +78,6 @@ static void free_node_resource(SceneNode* node) {
87 gfx_destroy_camera(&camera); 78 gfx_destroy_camera(&camera);
88 break; 79 break;
89 } 80 }
90 case JointNode: {
91 Joint* joint = mem_get_joint(node->joint);
92 joint->parent.val = 0;
93 gfx_destroy_joint(&joint);
94 break;
95 }
96 case LightNode: { 81 case LightNode: {
97 Light* light = mem_get_light(node->light); 82 Light* light = mem_get_light(node->light);
98 light->parent.val = 0; 83 light->parent.val = 0;
@@ -129,16 +114,7 @@ void gfx_construct_camera_node(SceneNode* node, SceneCamera* camera) {
129} 114}
130 115
131// TODO: Add a common helper function between each gfx_make_xyz_node() and 116// TODO: Add a common helper function between each gfx_make_xyz_node() and
132// gfx_construct_xyz_node() pair. 117// gfx_construct_xyz_node() pair.
133void gfx_construct_joint_node(SceneNode* node, Joint* joint) {
134 assert(node);
135 assert(joint);
136 free_node_resource(node);
137 node->type = JointNode;
138 node->joint = mem_get_joint_index(joint);
139 joint->parent = mem_get_node_index(node);
140}
141
142void gfx_construct_light_node(SceneNode* node, Light* light) { 118void gfx_construct_light_node(SceneNode* node, Light* light) {
143 assert(node); 119 assert(node);
144 assert(light); 120 assert(light);
@@ -217,10 +193,6 @@ SceneCamera* gfx_get_node_camera(const SceneNode* node) {
217 NODE_GET(node, camera, CameraNode); 193 NODE_GET(node, camera, CameraNode);
218} 194}
219 195
220Joint* gfx_get_node_joint(const SceneNode* node) {
221 NODE_GET(node, joint, JointNode);
222}
223
224Light* gfx_get_node_light(const SceneNode* node) { 196Light* gfx_get_node_light(const SceneNode* node) {
225 NODE_GET(node, light, LightNode); 197 NODE_GET(node, light, LightNode);
226} 198}
@@ -309,8 +281,6 @@ static const char* get_node_type_str(NodeType type) {
309 return "AnimaNode"; 281 return "AnimaNode";
310 case CameraNode: 282 case CameraNode:
311 return "CameraNode"; 283 return "CameraNode";
312 case JointNode:
313 return "JointNode";
314 case LightNode: 284 case LightNode:
315 return "LightNode"; 285 return "LightNode";
316 case ObjectNode: 286 case ObjectNode:
diff --git a/gfx/src/scene/node_impl.h b/gfx/src/scene/node_impl.h
index e8d546f..4592fce 100644
--- a/gfx/src/scene/node_impl.h
+++ b/gfx/src/scene/node_impl.h
@@ -16,7 +16,6 @@ typedef struct SceneNode {
16 union { 16 union {
17 anima_idx anima; 17 anima_idx anima;
18 camera_idx camera; 18 camera_idx camera;
19 joint_idx joint;
20 light_idx light; 19 light_idx light;
21 object_idx object; 20 object_idx object;
22 }; 21 };
diff --git a/gfx/src/scene/scene_memory.c b/gfx/src/scene/scene_memory.c
index cace654..2b900b9 100644
--- a/gfx/src/scene/scene_memory.c
+++ b/gfx/src/scene/scene_memory.c
@@ -16,7 +16,6 @@
16DEF_MEMPOOL(anima_pool, Anima, GFX_MAX_NUM_ANIMAS) 16DEF_MEMPOOL(anima_pool, Anima, GFX_MAX_NUM_ANIMAS)
17DEF_MEMPOOL(animation_pool, Animation, GFX_MAX_NUM_ANIMATIONS) 17DEF_MEMPOOL(animation_pool, Animation, GFX_MAX_NUM_ANIMATIONS)
18DEF_MEMPOOL(camera_pool, SceneCamera, GFX_MAX_NUM_CAMERAS) 18DEF_MEMPOOL(camera_pool, SceneCamera, GFX_MAX_NUM_CAMERAS)
19DEF_MEMPOOL(joint_pool, Joint, GFX_MAX_NUM_JOINTS)
20DEF_MEMPOOL(light_pool, Light, GFX_MAX_NUM_LIGHTS) 19DEF_MEMPOOL(light_pool, Light, GFX_MAX_NUM_LIGHTS)
21DEF_MEMPOOL(material_pool, Material, GFX_MAX_NUM_MATERIALS) 20DEF_MEMPOOL(material_pool, Material, GFX_MAX_NUM_MATERIALS)
22DEF_MEMPOOL(mesh_pool, Mesh, GFX_MAX_NUM_MESHES) 21DEF_MEMPOOL(mesh_pool, Mesh, GFX_MAX_NUM_MESHES)
@@ -33,7 +32,6 @@ typedef struct SceneMemory {
33 anima_pool animas; 32 anima_pool animas;
34 animation_pool animations; 33 animation_pool animations;
35 camera_pool cameras; 34 camera_pool cameras;
36 joint_pool joints;
37 light_pool lights; 35 light_pool lights;
38 material_pool materials; 36 material_pool materials;
39 mesh_pool meshs; // Purposeful typo to make the PLURAL() macro work. 37 mesh_pool meshs; // Purposeful typo to make the PLURAL() macro work.
@@ -59,7 +57,6 @@ void scene_mem_init() {
59 mempool_make(&mem.animas); 57 mempool_make(&mem.animas);
60 mempool_make(&mem.animations); 58 mempool_make(&mem.animations);
61 mempool_make(&mem.cameras); 59 mempool_make(&mem.cameras);
62 mempool_make(&mem.joints);
63 mempool_make(&mem.lights); 60 mempool_make(&mem.lights);
64 mempool_make(&mem.materials); 61 mempool_make(&mem.materials);
65 mempool_make(&mem.meshs); 62 mempool_make(&mem.meshs);
@@ -74,7 +71,6 @@ void scene_mem_init() {
74 ALLOC_DUMMY(&mem.animas); 71 ALLOC_DUMMY(&mem.animas);
75 ALLOC_DUMMY(&mem.animations); 72 ALLOC_DUMMY(&mem.animations);
76 ALLOC_DUMMY(&mem.cameras); 73 ALLOC_DUMMY(&mem.cameras);
77 ALLOC_DUMMY(&mem.joints);
78 ALLOC_DUMMY(&mem.lights); 74 ALLOC_DUMMY(&mem.lights);
79 ALLOC_DUMMY(&mem.materials); 75 ALLOC_DUMMY(&mem.materials);
80 ALLOC_DUMMY(&mem.meshs); 76 ALLOC_DUMMY(&mem.meshs);
@@ -107,7 +103,6 @@ void scene_mem_destroy() {
107 DESTROY(anima); 103 DESTROY(anima);
108 // Animations are owned by animas and do not have a destructor. 104 // Animations are owned by animas and do not have a destructor.
109 DESTROY(camera); 105 DESTROY(camera);
110 DESTROY(joint);
111 DESTROY(light); 106 DESTROY(light);
112 DESTROY(material); 107 DESTROY(material);
113 DESTROY(mesh); 108 DESTROY(mesh);
@@ -136,7 +131,6 @@ void scene_mem_destroy() {
136DEF_MEMORY(anima, Anima) 131DEF_MEMORY(anima, Anima)
137DEF_MEMORY(animation, Animation) 132DEF_MEMORY(animation, Animation)
138DEF_MEMORY(camera, SceneCamera) 133DEF_MEMORY(camera, SceneCamera)
139DEF_MEMORY(joint, Joint)
140DEF_MEMORY(light, Light) 134DEF_MEMORY(light, Light)
141DEF_MEMORY(material, Material) 135DEF_MEMORY(material, Material)
142DEF_MEMORY(mesh, Mesh) 136DEF_MEMORY(mesh, Mesh)
diff --git a/gfx/src/scene/scene_memory.h b/gfx/src/scene/scene_memory.h
index 9486ee6..04dbd20 100644
--- a/gfx/src/scene/scene_memory.h
+++ b/gfx/src/scene/scene_memory.h
@@ -29,7 +29,6 @@ void scene_mem_destroy();
29DECL_MEMORY(anima, Anima) 29DECL_MEMORY(anima, Anima)
30DECL_MEMORY(animation, Animation) 30DECL_MEMORY(animation, Animation)
31DECL_MEMORY(camera, SceneCamera) 31DECL_MEMORY(camera, SceneCamera)
32DECL_MEMORY(joint, Joint)
33DECL_MEMORY(light, Light) 32DECL_MEMORY(light, Light)
34DECL_MEMORY(material, Material) 33DECL_MEMORY(material, Material)
35DECL_MEMORY(mesh, Mesh) 34DECL_MEMORY(mesh, Mesh)