diff options
Diffstat (limited to 'gfx/src/scene')
-rw-r--r-- | gfx/src/scene/animation.c | 104 | ||||
-rw-r--r-- | gfx/src/scene/animation_impl.h | 15 | ||||
-rw-r--r-- | gfx/src/scene/object.c | 5 | ||||
-rw-r--r-- | gfx/src/scene/object_impl.h | 4 | ||||
-rw-r--r-- | gfx/src/scene/types.h | 1 |
5 files changed, 96 insertions, 33 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 | } | ||
diff --git a/gfx/src/scene/animation_impl.h b/gfx/src/scene/animation_impl.h index 7265858..4408158 100644 --- a/gfx/src/scene/animation_impl.h +++ b/gfx/src/scene/animation_impl.h | |||
@@ -24,18 +24,19 @@ typedef struct Buffer Buffer; | |||
24 | /// Joints are mutable and store the transform and joint matrices that result | 24 | /// Joints are mutable and store the transform and joint matrices that result |
25 | /// from animation, aside from the inverse bind matrix. | 25 | /// from animation, aside from the inverse bind matrix. |
26 | typedef struct Joint { | 26 | typedef struct Joint { |
27 | rel_idx child; /// First child Joint; index into Anima's joints. | 27 | joint_idx child; /// First child Joint; index into Anima's joints. |
28 | rel_idx next; /// Next sibling Joint; index into Anima's joints. | 28 | joint_idx next; /// Next sibling Joint; index into Anima's joints. |
29 | mat4 transform; /// Local transform relative to parent. | 29 | mat4 transform; /// Local transform relative to parent. |
30 | mat4 inv_bind_matrix; /// Transforms the mesh into the joint's local space. | 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). | 31 | mat4 joint_matrix; /// inv(global) * global joint transform * inv(bind). |
32 | aabb3 box; /// Bounding box of vertices affected by joint. | ||
32 | } Joint; | 33 | } Joint; |
33 | 34 | ||
34 | /// Animation skeleton. | 35 | /// Animation skeleton. |
35 | typedef struct Skeleton { | 36 | typedef struct Skeleton { |
36 | skeleton_idx next; | 37 | skeleton_idx next; |
37 | size_t num_joints; | 38 | size_t num_joints; |
38 | rel_idx joints[GFX_MAX_NUM_JOINTS]; /// Indices into Anima's joints array. | 39 | joint_idx joints[GFX_MAX_NUM_JOINTS]; /// Indices into Anima's joints array. |
39 | } Skeleton; | 40 | } Skeleton; |
40 | 41 | ||
41 | /// A keyframe of animation. | 42 | /// A keyframe of animation. |
@@ -49,7 +50,7 @@ typedef struct Keyframe { | |||
49 | 50 | ||
50 | /// Animation channel. | 51 | /// Animation channel. |
51 | typedef struct Channel { | 52 | typedef struct Channel { |
52 | rel_idx target; /// Index into Anima's joints array. | 53 | joint_idx target; /// Index into Anima's joints array. |
53 | ChannelType type; | 54 | ChannelType type; |
54 | AnimationInterpolation interpolation; | 55 | AnimationInterpolation interpolation; |
55 | size_t num_keyframes; | 56 | size_t num_keyframes; |
diff --git a/gfx/src/scene/object.c b/gfx/src/scene/object.c index 9291feb..406c81f 100644 --- a/gfx/src/scene/object.c +++ b/gfx/src/scene/object.c | |||
@@ -72,6 +72,11 @@ void gfx_set_object_skeleton(SceneObject* object, const Skeleton* skeleton) { | |||
72 | object->skeleton = mem_get_skeleton_index(skeleton); | 72 | object->skeleton = mem_get_skeleton_index(skeleton); |
73 | } | 73 | } |
74 | 74 | ||
75 | const Skeleton* gfx_get_object_skeleton(const SceneObject* object) { | ||
76 | assert(object); | ||
77 | return (object->skeleton.val == 0) ? 0 : mem_get_skeleton(object->skeleton); | ||
78 | } | ||
79 | |||
75 | aabb3 gfx_get_object_aabb(const SceneObject* object) { | 80 | aabb3 gfx_get_object_aabb(const SceneObject* object) { |
76 | assert(object); | 81 | assert(object); |
77 | return object->box; | 82 | return object->box; |
diff --git a/gfx/src/scene/object_impl.h b/gfx/src/scene/object_impl.h index 91e1427..88f8e31 100644 --- a/gfx/src/scene/object_impl.h +++ b/gfx/src/scene/object_impl.h | |||
@@ -20,7 +20,7 @@ typedef struct MeshLink { | |||
20 | /// of Meshes, and the Meshes are re-used. | 20 | /// of Meshes, and the Meshes are re-used. |
21 | typedef struct SceneObject { | 21 | typedef struct SceneObject { |
22 | mesh_link_idx mesh_link; /// First MeshLink in the list. | 22 | mesh_link_idx mesh_link; /// First MeshLink in the list. |
23 | skeleton_idx skeleton; | 23 | skeleton_idx skeleton; /// 0 for static objects. |
24 | node_idx parent; /// Parent SceneNode. | 24 | node_idx parent; /// Parent SceneNode. |
25 | aabb3 box; | 25 | aabb3 box; |
26 | } SceneObject; | 26 | } SceneObject; |
diff --git a/gfx/src/scene/types.h b/gfx/src/scene/types.h index 9752bcf..d0ffc41 100644 --- a/gfx/src/scene/types.h +++ b/gfx/src/scene/types.h | |||
@@ -13,7 +13,6 @@ typedef uint16_t gfx_idx; | |||
13 | DEF_STRONG_INDEX(anima, gfx_idx) | 13 | DEF_STRONG_INDEX(anima, gfx_idx) |
14 | DEF_STRONG_INDEX(animation, gfx_idx) | 14 | DEF_STRONG_INDEX(animation, gfx_idx) |
15 | DEF_STRONG_INDEX(camera, gfx_idx) | 15 | DEF_STRONG_INDEX(camera, gfx_idx) |
16 | DEF_STRONG_INDEX(joint, gfx_idx) | ||
17 | DEF_STRONG_INDEX(light, gfx_idx) | 16 | DEF_STRONG_INDEX(light, gfx_idx) |
18 | DEF_STRONG_INDEX(material, gfx_idx) | 17 | DEF_STRONG_INDEX(material, gfx_idx) |
19 | DEF_STRONG_INDEX(mesh, gfx_idx) | 18 | DEF_STRONG_INDEX(mesh, gfx_idx) |