summaryrefslogtreecommitdiff
path: root/gfx/src/scene/animation.c
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/src/scene/animation.c')
-rw-r--r--gfx/src/scene/animation.c104
1 files changed, 81 insertions, 23 deletions
diff --git a/gfx/src/scene/animation.c b/gfx/src/scene/animation.c
index 18e2a99..08d02ce 100644
--- a/gfx/src/scene/animation.c
+++ b/gfx/src/scene/animation.c
@@ -9,7 +9,7 @@
9 9
10static const R PLAYBACK_UNINITIALIZED = -1; 10static const R PLAYBACK_UNINITIALIZED = -1;
11 11
12static rel_idx get_anima_root_joint_index(Anima* anima) { 12static joint_idx get_anima_root_joint_index(Anima* anima) {
13 assert(anima); 13 assert(anima);
14 assert(anima->num_joints > 0); 14 assert(anima->num_joints > 0);
15 assert(anima->num_joints < GFX_MAX_NUM_JOINTS); 15 assert(anima->num_joints < GFX_MAX_NUM_JOINTS);
@@ -21,7 +21,7 @@ static Joint* get_anima_root_joint(Anima* anima) {
21 return &anima->joints[get_anima_root_joint_index(anima)]; 21 return &anima->joints[get_anima_root_joint_index(anima)];
22} 22}
23 23
24static Joint* get_anima_joint(Anima* anima, rel_idx index) { 24static const Joint* get_anima_joint(const Anima* anima, joint_idx index) {
25 assert(anima); 25 assert(anima);
26 assert(index < GFX_MAX_NUM_JOINTS); 26 assert(index < GFX_MAX_NUM_JOINTS);
27 assert(index != INDEX_NONE); 27 assert(index != INDEX_NONE);
@@ -29,22 +29,33 @@ static Joint* get_anima_joint(Anima* anima, rel_idx index) {
29 return &anima->joints[index]; 29 return &anima->joints[index];
30} 30}
31 31
32static Joint* get_anima_joint_mut(Anima* anima, joint_idx index) {
33 return (Joint*)get_anima_joint(anima, index);
34}
35
36static const Joint* get_skeleton_joint(
37 const Anima* anima, const Skeleton* skeleton, joint_idx index) {
38 assert(anima);
39 assert(skeleton);
40 return get_anima_joint(anima, skeleton->joints[index]);
41}
42
32static void set_joint_parent( 43static void set_joint_parent(
33 Anima* anima, rel_idx joint_index, rel_idx parent_index) { 44 Anima* anima, joint_idx joint_index, joint_idx parent_index) {
34 assert(anima); 45 assert(anima);
35 assert(joint_index != INDEX_NONE); 46 assert(joint_index != INDEX_NONE);
36 assert(joint_index != get_anima_root_joint_index(anima)); 47 assert(joint_index != get_anima_root_joint_index(anima));
37 assert(parent_index != INDEX_NONE); 48 assert(parent_index != INDEX_NONE);
38 49
39 Joint* parent = get_anima_joint(anima, parent_index); 50 Joint* parent = get_anima_joint_mut(anima, parent_index);
40 51
41 if (parent->child == INDEX_NONE) { 52 if (parent->child == INDEX_NONE) {
42 parent->child = joint_index; 53 parent->child = joint_index;
43 } else { 54 } else {
44 // Find the last child in the chain of children. 55 // Find the last child in the chain of children.
45 Joint* child = get_anima_joint(anima, parent->child); 56 Joint* child = get_anima_joint_mut(anima, parent->child);
46 while (child->next != INDEX_NONE) { 57 while (child->next != INDEX_NONE) {
47 child = get_anima_joint(anima, child->next); 58 child = get_anima_joint_mut(anima, child->next);
48 } 59 }
49 // Wire up this joint as the last child's sibling. 60 // Wire up this joint as the last child's sibling.
50 child->next = joint_index; 61 child->next = joint_index;
@@ -64,6 +75,7 @@ static void make_joint(Anima* anima, const JointDesc* desc, Joint* joint) {
64 joint->transform = mat4_id(); 75 joint->transform = mat4_id();
65 joint->inv_bind_matrix = desc->inv_bind_matrix; 76 joint->inv_bind_matrix = desc->inv_bind_matrix;
66 joint->joint_matrix = mat4_id(); 77 joint->joint_matrix = mat4_id();
78 joint->box = desc->box;
67} 79}
68 80
69static Skeleton* make_skeleton(const SkeletonDesc* desc) { 81static Skeleton* make_skeleton(const SkeletonDesc* desc) {
@@ -88,6 +100,7 @@ static Animation* make_animation(const AnimationDesc* desc) {
88 animation->num_channels = desc->num_channels; 100 animation->num_channels = desc->num_channels;
89 R start_time = 0; 101 R start_time = 0;
90 R end_time = 0; 102 R end_time = 0;
103
91 for (size_t c = 0; c < desc->num_channels; ++c) { 104 for (size_t c = 0; c < desc->num_channels; ++c) {
92 const ChannelDesc* channel_desc = &desc->channels[c]; 105 const ChannelDesc* channel_desc = &desc->channels[c];
93 Channel* channel = &animation->channels[c]; 106 Channel* channel = &animation->channels[c];
@@ -110,6 +123,7 @@ static Animation* make_animation(const AnimationDesc* desc) {
110 end_time = keyframe->time > end_time ? keyframe->time : end_time; 123 end_time = keyframe->time > end_time ? keyframe->time : end_time;
111 } 124 }
112 } 125 }
126
113 // LOGD("Animation start/end: %f / %f", start_time, end_time); 127 // LOGD("Animation start/end: %f / %f", start_time, end_time);
114 animation->duration = end_time - start_time; 128 animation->duration = end_time - start_time;
115 assert(animation->duration >= 0); 129 assert(animation->duration >= 0);
@@ -122,7 +136,7 @@ Anima* gfx_make_anima(const AnimaDesc* desc) {
122 assert(desc->num_joints <= GFX_MAX_NUM_JOINTS); 136 assert(desc->num_joints <= GFX_MAX_NUM_JOINTS);
123 // All joints should have a parent except for the root. 137 // All joints should have a parent except for the root.
124 for (size_t i = 0; i < desc->num_joints - 1; ++i) { 138 for (size_t i = 0; i < desc->num_joints - 1; ++i) {
125 const rel_idx parent = desc->joints[i].parent; 139 const joint_idx parent = desc->joints[i].parent;
126 assert(parent != INDEX_NONE); 140 assert(parent != INDEX_NONE);
127 assert(parent < desc->num_joints); 141 assert(parent < desc->num_joints);
128 } 142 }
@@ -134,10 +148,7 @@ Anima* gfx_make_anima(const AnimaDesc* desc) {
134 // Wire the skeletons in the same order they are given in the descriptor. 148 // Wire the skeletons in the same order they are given in the descriptor.
135 Skeleton* last_skeleton = 0; 149 Skeleton* last_skeleton = 0;
136 for (size_t i = 0; i < desc->num_skeletons; ++i) { 150 for (size_t i = 0; i < desc->num_skeletons; ++i) {
137 Skeleton* skeleton = make_skeleton(&desc->skeletons[i]); 151 Skeleton* skeleton = make_skeleton(&desc->skeletons[i]);
138 // TODO: Here and everywhere else, I think it would simplify the code
139 // greatly to make mem_alloc_xyz() fail if the allocation fails. At that
140 // point the user should just bump their memory limits.
141 const skeleton_idx skeleton_index = mem_get_skeleton_index(skeleton); 152 const skeleton_idx skeleton_index = mem_get_skeleton_index(skeleton);
142 if (last_skeleton == 0) { 153 if (last_skeleton == 0) {
143 anima->skeleton = skeleton_index; 154 anima->skeleton = skeleton_index;
@@ -166,7 +177,7 @@ Anima* gfx_make_anima(const AnimaDesc* desc) {
166 // Child and sibling pointers must be initialized before wiring up the 177 // Child and sibling pointers must be initialized before wiring up the
167 // hierarchy. 178 // hierarchy.
168 for (size_t i = 0; i < desc->num_joints; ++i) { 179 for (size_t i = 0; i < desc->num_joints; ++i) {
169 Joint* joint = get_anima_joint(anima, i); 180 Joint* joint = get_anima_joint_mut(anima, i);
170 make_joint(anima, &desc->joints[i], joint); 181 make_joint(anima, &desc->joints[i], joint);
171 } 182 }
172 // Wire up joints to their parents. -1 to skip the root. 183 // Wire up joints to their parents. -1 to skip the root.
@@ -339,7 +350,7 @@ static void animate_channel(Anima* anima, const Channel* channel, R t) {
339 // work. 350 // work.
340 t = t > channel->keyframes[next].time ? channel->keyframes[next].time : t; 351 t = t > channel->keyframes[next].time ? channel->keyframes[next].time : t;
341 352
342 Joint* target = get_anima_joint(anima, channel->target); 353 Joint* target = get_anima_joint_mut(anima, channel->target);
343 354
344 switch (channel->type) { 355 switch (channel->type) {
345 case RotationChannel: { 356 case RotationChannel: {
@@ -380,7 +391,7 @@ static void compute_joint_matrices_rec(
380 391
381 // Recursively compute the joint matrices for this joint's siblings. 392 // Recursively compute the joint matrices for this joint's siblings.
382 if (joint->next != INDEX_NONE) { 393 if (joint->next != INDEX_NONE) {
383 Joint* sibling = get_anima_joint(anima, joint->next); 394 Joint* sibling = get_anima_joint_mut(anima, joint->next);
384 395
385 compute_joint_matrices_rec( 396 compute_joint_matrices_rec(
386 anima, sibling, parent_global_joint_transform, 397 anima, sibling, parent_global_joint_transform,
@@ -389,7 +400,7 @@ static void compute_joint_matrices_rec(
389 400
390 // Recursively compute the joint matrices for this joint's children. 401 // Recursively compute the joint matrices for this joint's children.
391 if (joint->child != INDEX_NONE) { 402 if (joint->child != INDEX_NONE) {
392 Joint* child = get_anima_joint(anima, joint->child); 403 Joint* child = get_anima_joint_mut(anima, joint->child);
393 404
394 compute_joint_matrices_rec( 405 compute_joint_matrices_rec(
395 anima, child, &global_joint_transform, root_inv_global_transform); 406 anima, child, &global_joint_transform, root_inv_global_transform);
@@ -431,16 +442,14 @@ void gfx_update_animation(Anima* anima, R t) {
431 442
432 // Compute joint matrices after having transformed the skeletons. 443 // Compute joint matrices after having transformed the skeletons.
433 // 444 //
434 // Skeletons are not guaranteed to have a common parent, but are generally a 445 // The anima's parent node is the common ancestor of all skeletons, and its
435 // set of disjoint trees (glTF). The anima's parent node, however, is 446 // transform maps the skeletons from object space to world space. This is the
436 // guaranteed to be the common ancestor of all skeletons. 447 // transform used as the "global transform" in the joint matrix equations.
437 // 448 //
438 // Joint matrix calculation therefore begins by descending from the anima's 449 // Joint matrix calculation begins by descending from the anima's root joint,
439 // node. This node's immediate children may not be joints, however, so we need 450 // which we have constructed to be the common root of all skeletons.
440 // to gracefully handle them and proceed recursively.
441 // 451 //
442 // Lack of a common parent aside, the procedure touches every joint exactly 452 // This procedure touches every joint exactly once.
443 // once (and potentially other non-joint intermediate nodes).
444 SceneNode* root_node = mem_get_node(anima->parent); 453 SceneNode* root_node = mem_get_node(anima->parent);
445 // LOGD("Root: %u, child: %u", anima->parent.val, root->child.val); 454 // LOGD("Root: %u, child: %u", anima->parent.val, root->child.val);
446 const mat4 root_global_transform = gfx_get_node_global_transform(root_node); 455 const mat4 root_global_transform = gfx_get_node_global_transform(root_node);
@@ -464,3 +473,52 @@ const Skeleton* gfx_get_anima_skeleton(const Anima* anima, size_t i) {
464 473
465 return skeleton; 474 return skeleton;
466} 475}
476
477size_t gfx_get_skeleton_num_joints(const Skeleton* skeleton) {
478 assert(skeleton);
479 return skeleton->num_joints;
480}
481
482bool gfx_joint_has_box(
483 const Anima* anima, const Skeleton* skeleton, size_t joint_index) {
484 assert(anima);
485 assert(skeleton);
486 assert(joint_index < skeleton->num_joints);
487
488 const Joint* joint = get_skeleton_joint(anima, skeleton, joint_index);
489 return !aabb3_is_empty(joint->box);
490}
491
492Box gfx_get_joint_box(
493 const Anima* anima, const Skeleton* skeleton, size_t joint_index) {
494 assert(anima);
495 assert(skeleton);
496
497 const Joint* joint = get_skeleton_joint(anima, skeleton, joint_index);
498
499 // Transform the box to anima space.
500 // Note that joint matrices do not usually have a translation since joints
501 // mostly just rotate with respect to their parent.
502 const vec3 pmin = joint->box.min;
503 const vec3 pmax = joint->box.max;
504 return (Box){
505 .vertices = {
506 mat4_mul_vec3(
507 joint->joint_matrix, vec3_make(pmin.x, pmin.y, pmax.z), 1),
508 mat4_mul_vec3(
509 joint->joint_matrix, vec3_make(pmax.x, pmin.y, pmax.z), 1),
510 mat4_mul_vec3(
511 joint->joint_matrix, vec3_make(pmax.x, pmax.y, pmax.z), 1),
512 mat4_mul_vec3(
513 joint->joint_matrix, vec3_make(pmin.x, pmax.y, pmax.z), 1),
514 mat4_mul_vec3(
515 joint->joint_matrix, vec3_make(pmin.x, pmin.y, pmin.z), 1),
516 mat4_mul_vec3(
517 joint->joint_matrix, vec3_make(pmax.x, pmin.y, pmin.z), 1),
518 mat4_mul_vec3(
519 joint->joint_matrix, vec3_make(pmax.x, pmax.y, pmin.z), 1),
520 mat4_mul_vec3(
521 joint->joint_matrix, vec3_make(pmin.x, pmax.y, pmin.z), 1),
522 }
523 };
524}