diff options
Diffstat (limited to 'gfx/src/scene/animation.c')
-rw-r--r-- | gfx/src/scene/animation.c | 104 |
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 | ||
10 | static const R PLAYBACK_UNINITIALIZED = -1; | 10 | static const R PLAYBACK_UNINITIALIZED = -1; |
11 | 11 | ||
12 | static rel_idx get_anima_root_joint_index(Anima* anima) { | 12 | static 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 | ||
24 | static Joint* get_anima_joint(Anima* anima, rel_idx index) { | 24 | static 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 | ||
32 | static Joint* get_anima_joint_mut(Anima* anima, joint_idx index) { | ||
33 | return (Joint*)get_anima_joint(anima, index); | ||
34 | } | ||
35 | |||
36 | static 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 | |||
32 | static void set_joint_parent( | 43 | static 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 | ||
69 | static Skeleton* make_skeleton(const SkeletonDesc* desc) { | 81 | static 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 | |||
477 | size_t gfx_get_skeleton_num_joints(const Skeleton* skeleton) { | ||
478 | assert(skeleton); | ||
479 | return skeleton->num_joints; | ||
480 | } | ||
481 | |||
482 | bool 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 | |||
492 | Box 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 | } | ||