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