aboutsummaryrefslogtreecommitdiff
path: root/src/animation.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/animation.c')
-rw-r--r--src/animation.c517
1 files changed, 517 insertions, 0 deletions
diff --git a/src/animation.c b/src/animation.c
new file mode 100644
index 0000000..c52df73
--- /dev/null
+++ b/src/animation.c
@@ -0,0 +1,517 @@
1#include "animation_impl.h"
2
3#include "memory.h"
4
5#include <string.h>
6
7// #include <log/log.h> // Debugging.
8
9static const R PLAYBACK_UNINITIALIZED = -1;
10
11static joint_idx get_anima_root_joint_index(Anima* anima) {
12 assert(anima);
13 assert(anima->num_joints > 0);
14 assert(anima->num_joints < GFX_MAX_NUM_JOINTS);
15 return anima->num_joints - 1;
16}
17
18static Joint* get_anima_root_joint(Anima* anima) {
19 assert(anima);
20 return &anima->joints[get_anima_root_joint_index(anima)];
21}
22
23static const Joint* get_anima_joint(const Anima* anima, joint_idx index) {
24 assert(anima);
25 assert(index < GFX_MAX_NUM_JOINTS);
26 assert(index != INDEX_NONE);
27 assert(index < anima->num_joints);
28 return &anima->joints[index];
29}
30
31static Joint* get_anima_joint_mut(Anima* anima, joint_idx index) {
32 return (Joint*)get_anima_joint(anima, index);
33}
34
35static const Joint* get_skeleton_joint(
36 const Anima* anima, const Skeleton* skeleton, joint_idx index) {
37 assert(anima);
38 assert(skeleton);
39 return get_anima_joint(anima, skeleton->joints[index]);
40}
41
42static void set_joint_parent(
43 Anima* anima, joint_idx joint_index, joint_idx parent_index) {
44 assert(anima);
45 assert(joint_index != INDEX_NONE);
46 assert(joint_index != get_anima_root_joint_index(anima));
47 assert(parent_index != INDEX_NONE);
48
49 Joint* parent = get_anima_joint_mut(anima, parent_index);
50
51 if (parent->child == INDEX_NONE) {
52 parent->child = joint_index;
53 } else {
54 // Find the last child in the chain of children.
55 Joint* child = get_anima_joint_mut(anima, parent->child);
56 while (child->next != INDEX_NONE) {
57 child = get_anima_joint_mut(anima, child->next);
58 }
59 // Wire up this joint as the last child's sibling.
60 child->next = joint_index;
61 }
62}
63
64static void make_joint(Anima* anima, const JointDesc* desc, Joint* joint) {
65 assert(anima);
66 assert(desc);
67 assert(joint);
68
69 // The joint matrix needs to be initialized so that meshes look right even if
70 // no animation is played. Initializing joint matrices to the identity makes
71 // meshes appear in their bind pose.
72 joint->child = INDEX_NONE;
73 joint->next = INDEX_NONE;
74 joint->transform = mat4_id();
75 joint->inv_bind_matrix = desc->inv_bind_matrix;
76 joint->joint_matrix = mat4_id();
77 joint->box = desc->box;
78}
79
80static Skeleton* make_skeleton(const SkeletonDesc* desc) {
81 assert(desc);
82 assert(desc->num_joints <= GFX_MAX_NUM_JOINTS);
83
84 Skeleton* skeleton = mem_alloc_skeleton();
85 skeleton->num_joints = desc->num_joints;
86 memcpy(
87 skeleton->joints, desc->joints,
88 desc->num_joints * sizeof(skeleton->joints[0]));
89 return skeleton;
90}
91
92static Animation* make_animation(const AnimationDesc* desc) {
93 assert(desc);
94 assert(desc->num_channels < GFX_MAX_NUM_CHANNELS);
95
96 Animation* animation = mem_alloc_animation();
97 animation->name = desc->name;
98 animation->duration = 0;
99 animation->num_channels = desc->num_channels;
100 R start_time = 0;
101 R end_time = 0;
102
103 for (size_t c = 0; c < desc->num_channels; ++c) {
104 const ChannelDesc* channel_desc = &desc->channels[c];
105 Channel* channel = &animation->channels[c];
106
107 channel->target = channel_desc->target;
108 channel->type = channel_desc->type;
109 channel->interpolation = channel_desc->interpolation;
110 channel->num_keyframes = channel_desc->num_keyframes;
111 assert(channel_desc->num_keyframes < GFX_MAX_NUM_KEYFRAMES);
112
113 for (size_t k = 0; k < channel_desc->num_keyframes; ++k) {
114 const KeyframeDesc* keyframe_desc = &channel_desc->keyframes[k];
115 Keyframe* keyframe = &channel->keyframes[k];
116
117 keyframe->time = keyframe_desc->time;
118 keyframe->translation = keyframe_desc->translation;
119 keyframe->rotation = keyframe_desc->rotation;
120
121 start_time = keyframe->time < start_time ? keyframe->time : start_time;
122 end_time = keyframe->time > end_time ? keyframe->time : end_time;
123 }
124 }
125
126 // LOGD("Animation start/end: %f / %f", start_time, end_time);
127 animation->duration = end_time - start_time;
128 assert(animation->duration >= 0);
129 return animation;
130}
131
132Anima* gfx_make_anima(const AnimaDesc* desc) {
133 assert(desc);
134 assert(desc->num_joints > 0);
135 assert(desc->num_joints <= GFX_MAX_NUM_JOINTS);
136 // All joints should have a parent except for the root.
137 for (size_t i = 0; i < desc->num_joints - 1; ++i) {
138 const joint_idx parent = desc->joints[i].parent;
139 assert(parent != INDEX_NONE);
140 assert(parent < desc->num_joints);
141 }
142 // The root should have no parent.
143 assert(desc->joints[desc->num_joints - 1].parent == INDEX_NONE);
144
145 Anima* anima = mem_alloc_anima();
146
147 // Wire the skeletons in the same order they are given in the descriptor.
148 Skeleton* last_skeleton = 0;
149 for (size_t i = 0; i < desc->num_skeletons; ++i) {
150 Skeleton* skeleton = make_skeleton(&desc->skeletons[i]);
151 const skeleton_idx skeleton_index = mem_get_skeleton_index(skeleton);
152 if (last_skeleton == 0) {
153 anima->skeleton = skeleton_index;
154 } else {
155 last_skeleton->next = skeleton_index;
156 }
157 last_skeleton = skeleton;
158 }
159
160 // Wire the animations in the same order they are given in the descriptor.
161 Animation* last_animation = 0;
162 for (size_t i = 0; i < desc->num_animations; ++i) {
163 Animation* animation = make_animation(&desc->animations[i]);
164 const animation_idx animation_index = mem_get_animation_index(animation);
165 if (last_animation == 0) {
166 anima->animation = animation_index;
167 } else {
168 last_animation->next = animation_index;
169 }
170 last_animation = animation;
171 }
172
173 // Create joints.
174 anima->num_joints = desc->num_joints;
175 // Initialize all joints.
176 // Child and sibling pointers must be initialized before wiring up the
177 // hierarchy.
178 for (size_t i = 0; i < desc->num_joints; ++i) {
179 Joint* joint = get_anima_joint_mut(anima, i);
180 make_joint(anima, &desc->joints[i], joint);
181 }
182 // Wire up joints to their parents. -1 to skip the root.
183 for (size_t i = 0; i < desc->num_joints - 1; ++i) {
184 set_joint_parent(anima, i, desc->joints[i].parent);
185 }
186
187 return anima;
188}
189
190void gfx_destroy_anima(Anima** anima) {
191 assert(anima);
192
193 if (*anima) {
194 for (skeleton_idx i = (*anima)->skeleton; i.val != 0;) {
195 Skeleton* skeleton = mem_get_skeleton(i);
196 i = skeleton->next;
197 mem_free_skeleton(&skeleton);
198 }
199
200 for (animation_idx i = (*anima)->animation; i.val != 0;) {
201 Animation* animation = mem_get_animation(i);
202 i = animation->next;
203 mem_free_animation(&animation);
204 }
205
206 mem_free_anima(anima);
207 }
208}
209
210static Animation* find_animation(animation_idx index, const char* name) {
211 assert(name);
212
213 while (index.val != 0) {
214 Animation* animation = mem_get_animation(index);
215 if (sstring_eq_cstr(animation->name, name)) {
216 // LOGD(
217 // "Found animation at index %u, %s - %s", index.val,
218 // sstring_cstr(&animation->name), name);
219 // LOGD("Animation has duration %f", animation->duration);
220 return animation;
221 }
222 index = animation->next;
223 }
224
225 return 0;
226}
227
228bool gfx_play_animation(Anima* anima, const AnimationPlaySettings* settings) {
229 assert(anima);
230 assert(settings);
231
232 // TODO: Should we animate at t=0 here to kickstart the animation? Otherwise
233 // the client is forced to call gfx_update_animation() to do this.
234 Animation* animation = find_animation(anima->animation, settings->name);
235 if (!animation) {
236 return false;
237 }
238 // Playback initialized on first call to update().
239 AnimationState* state = &anima->state;
240 state->start_time = PLAYBACK_UNINITIALIZED;
241 state->animation = mem_get_animation_index(animation);
242 state->loop = settings->loop;
243 return true;
244}
245
246static void gfx_set_joint_position(Joint* joint, vec3 position) {
247 assert(joint);
248 mat4_set_v3(&joint->transform, position);
249}
250
251static void gfx_set_joint_rotation(Joint* joint, quat rotation) {
252 assert(joint);
253 mat4_set_3x3(&joint->transform, mat4_from_quat(rotation));
254}
255
256static void find_keyframes(const Channel* channel, R t, int* prev, int* next) {
257 assert(channel);
258 assert(prev);
259 assert(next);
260
261 *prev = -1;
262 *next = 0;
263 while (((*next + 1) < (int)channel->num_keyframes) &&
264 (t >= channel->keyframes[*next + 1].time)) {
265 (*prev)++;
266 (*next)++;
267 }
268}
269
270static R normalize_time(R a, R b, R t) {
271 assert(a <= t);
272 assert(t <= b);
273 return (t - a) / (b - a);
274}
275
276static quat interpolate_rotation(
277 const Channel* channel, int prev, int next, R t) {
278 assert(channel);
279
280 if (next == 0) {
281 // Animation has not started at this point in time yet.
282 return channel->keyframes[next].rotation;
283 } else {
284 switch (channel->interpolation) {
285 case StepInterpolation:
286 return channel->keyframes[prev].rotation;
287 case LinearInterpolation: {
288 const R normalized_t = normalize_time(
289 channel->keyframes[prev].time, channel->keyframes[next].time, t);
290 return qnormalize(qslerp(
291 channel->keyframes[prev].rotation, channel->keyframes[next].rotation,
292 normalized_t));
293 break;
294 }
295 case CubicSplineInterpolation:
296 assert(false); // TODO
297 return qmake(0, 0, 0, 0);
298 default:
299 assert(false);
300 return qmake(0, 0, 0, 0);
301 }
302 }
303}
304
305static vec3 interpolate_translation(
306 const Channel* channel, int prev, int next, R t) {
307 assert(channel);
308
309 if (next == 0) {
310 // Animation has not started at this point in time yet.
311 return channel->keyframes[next].translation;
312 } else {
313 switch (channel->interpolation) {
314 case StepInterpolation:
315 return channel->keyframes[prev].translation;
316 case LinearInterpolation: {
317 const R normalized_t = normalize_time(
318 channel->keyframes[prev].time, channel->keyframes[next].time, t);
319 return vec3_lerp(
320 channel->keyframes[prev].translation,
321 channel->keyframes[next].translation, normalized_t);
322 break;
323 }
324 case CubicSplineInterpolation:
325 assert(false); // TODO
326 return vec3_make(0, 0, 0);
327 default:
328 assert(false);
329 return vec3_make(0, 0, 0);
330 }
331 }
332}
333
334static void animate_channel(Anima* anima, const Channel* channel, R t) {
335 assert(anima);
336 assert(channel);
337 assert(channel->target < anima->num_joints);
338
339 int prev, next;
340 find_keyframes(channel, t, &prev, &next);
341
342 // Note that not all channels extend to the duration of an animation; some
343 // channels may stop animating their targets earlier. Clamp the animation time
344 // to the channel's end keyframe to make the rest of the math (normalize_time)
345 // work.
346 t = t > channel->keyframes[next].time ? channel->keyframes[next].time : t;
347
348 Joint* target = get_anima_joint_mut(anima, channel->target);
349
350 switch (channel->type) {
351 case RotationChannel: {
352 const quat rotation = interpolate_rotation(channel, prev, next, t);
353 gfx_set_joint_rotation(target, rotation);
354 break;
355 }
356 case TranslationChannel: {
357 const vec3 translation = interpolate_translation(channel, prev, next, t);
358 gfx_set_joint_position(target, translation);
359 break;
360 }
361 // Not yet supported.
362 case ScaleChannel:
363 case WeightsChannel:
364 default:
365 // TODO: Add back the assertion or add support for scaling.
366 // assert(false);
367 break;
368 }
369}
370
371static void compute_joint_matrices_rec(
372 Anima* anima, Joint* joint, const mat4* parent_global_joint_transform,
373 const mat4* root_inv_global_transform) {
374 assert(anima);
375 assert(joint);
376 assert(parent_global_joint_transform);
377 assert(root_inv_global_transform);
378
379 const mat4 global_joint_transform =
380 mat4_mul(*parent_global_joint_transform, joint->transform);
381
382 // Compute this joint's matrix.
383 joint->joint_matrix = mat4_mul(
384 *root_inv_global_transform,
385 mat4_mul(global_joint_transform, joint->inv_bind_matrix));
386
387 // Recursively compute the joint matrices for this joint's siblings.
388 if (joint->next != INDEX_NONE) {
389 Joint* sibling = get_anima_joint_mut(anima, joint->next);
390
391 compute_joint_matrices_rec(
392 anima, sibling, parent_global_joint_transform,
393 root_inv_global_transform);
394 }
395
396 // Recursively compute the joint matrices for this joint's children.
397 if (joint->child != INDEX_NONE) {
398 Joint* child = get_anima_joint_mut(anima, joint->child);
399
400 compute_joint_matrices_rec(
401 anima, child, &global_joint_transform, root_inv_global_transform);
402 }
403}
404
405void gfx_update_animation(Anima* anima, R t) {
406 assert(anima);
407
408 AnimationState* state = &anima->state;
409 if (state->animation.val == 0) {
410 return; // No active animation.
411 }
412 const Animation* animation = mem_get_animation(state->animation);
413 assert(animation);
414
415 // On a call to play(), the start time is set to -1 to signal that the
416 // animation playback has not yet been initialized.
417 if (state->start_time == PLAYBACK_UNINITIALIZED) {
418 state->start_time = t;
419 }
420 // Locate the current time point inside the animation's timeline.
421 assert(t >= state->start_time);
422 assert(animation->duration >= 0.0);
423 const R local_time = t - state->start_time;
424 const R animation_time = state->loop
425 ? rmod(local_time, animation->duration)
426 : clamp(local_time, 0.0, animation->duration);
427
428 // LOGD(
429 // "animation_time = %f, animation duration: %f", animation_time,
430 // animation->duration);
431
432 // Play through the animation to transform skeleton nodes.
433 for (size_t i = 0; i < animation->num_channels; ++i) {
434 const Channel* channel = &animation->channels[i];
435 animate_channel(anima, channel, animation_time);
436 }
437
438 // Compute joint matrices after having transformed the skeletons.
439 //
440 // The anima's parent node is the common ancestor of all skeletons, and its
441 // transform maps the skeletons from object space to world space. This is the
442 // transform used as the "global transform" in the joint matrix equations.
443 //
444 // Joint matrix calculation begins by descending from the anima's root joint,
445 // which we have constructed to be the common root of all skeletons.
446 //
447 // This procedure touches every joint exactly once.
448 const mat4 root_global_transform = mat4_id();
449 const mat4 root_inv_global_transform = mat4_id();
450
451 Joint* root_joint = get_anima_root_joint(anima);
452 compute_joint_matrices_rec(
453 anima, root_joint, &root_global_transform, &root_inv_global_transform);
454}
455
456const Skeleton* gfx_get_anima_skeleton(const Anima* anima, size_t i) {
457 assert(anima);
458
459 skeleton_idx skeleton_index = anima->skeleton;
460 const Skeleton* skeleton = mem_get_skeleton(skeleton_index);
461
462 for (size_t j = 1; j < i; ++j) {
463 skeleton_index = skeleton->next;
464 mem_get_skeleton(skeleton_index);
465 }
466
467 return skeleton;
468}
469
470size_t gfx_get_skeleton_num_joints(const Skeleton* skeleton) {
471 assert(skeleton);
472 return skeleton->num_joints;
473}
474
475bool gfx_joint_has_box(
476 const Anima* anima, const Skeleton* skeleton, size_t joint_index) {
477 assert(anima);
478 assert(skeleton);
479 assert(joint_index < skeleton->num_joints);
480
481 const Joint* joint = get_skeleton_joint(anima, skeleton, joint_index);
482 return !aabb3_is_empty(joint->box);
483}
484
485Box gfx_get_joint_box(
486 const Anima* anima, const Skeleton* skeleton, size_t joint_index) {
487 assert(anima);
488 assert(skeleton);
489
490 const Joint* joint = get_skeleton_joint(anima, skeleton, joint_index);
491
492 // Transform the box to anima space.
493 // Note that joint matrices do not usually have a translation since joints
494 // mostly just rotate with respect to their parent.
495 const vec3 pmin = joint->box.min;
496 const vec3 pmax = joint->box.max;
497 return (Box){
498 .vertices = {
499 mat4_mul_vec3(
500 joint->joint_matrix, vec3_make(pmin.x, pmin.y, pmax.z), 1),
501 mat4_mul_vec3(
502 joint->joint_matrix, vec3_make(pmax.x, pmin.y, pmax.z), 1),
503 mat4_mul_vec3(
504 joint->joint_matrix, vec3_make(pmax.x, pmax.y, pmax.z), 1),
505 mat4_mul_vec3(
506 joint->joint_matrix, vec3_make(pmin.x, pmax.y, pmax.z), 1),
507 mat4_mul_vec3(
508 joint->joint_matrix, vec3_make(pmin.x, pmin.y, pmin.z), 1),
509 mat4_mul_vec3(
510 joint->joint_matrix, vec3_make(pmax.x, pmin.y, pmin.z), 1),
511 mat4_mul_vec3(
512 joint->joint_matrix, vec3_make(pmax.x, pmax.y, pmin.z), 1),
513 mat4_mul_vec3(
514 joint->joint_matrix, vec3_make(pmin.x, pmax.y, pmin.z), 1),
515 }
516 };
517}