libanim

view src/anim.c @ 64:73a26dc37e43

copyright headers and license text files
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 17 Apr 2014 07:57:52 +0300
parents ebead35c9eb1
children 70ad14ba4df2
line source
1 /*
2 libanim - hierarchical keyframe animation library
3 Copyright (C) 2012-2014 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published
7 by the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include <stdlib.h>
19 #include <limits.h>
20 #include <assert.h>
21 #include "anim.h"
22 #include "dynarr.h"
24 #define ROT_USE_SLERP
26 static void invalidate_cache(struct anm_node *node);
28 int anm_init_animation(struct anm_animation *anim)
29 {
30 int i, j;
31 static const float defaults[] = {
32 0.0f, 0.0f, 0.0f, /* default position */
33 0.0f, 0.0f, 0.0f, 1.0f, /* default rotation quat */
34 1.0f, 1.0f, 1.0f /* default scale factor */
35 };
37 anim->name = 0;
39 for(i=0; i<ANM_NUM_TRACKS; i++) {
40 if(anm_init_track(anim->tracks + i) == -1) {
41 for(j=0; j<i; j++) {
42 anm_destroy_track(anim->tracks + i);
43 }
44 }
45 anm_set_track_default(anim->tracks + i, defaults[i]);
46 }
47 return 0;
48 }
50 void anm_destroy_animation(struct anm_animation *anim)
51 {
52 int i;
53 for(i=0; i<ANM_NUM_TRACKS; i++) {
54 anm_destroy_track(anim->tracks + i);
55 }
56 free(anim->name);
57 }
59 void anm_set_animation_name(struct anm_animation *anim, const char *name)
60 {
61 char *newname = malloc(strlen(name) + 1);
62 if(!newname) return;
64 strcpy(newname, name);
66 free(anim->name);
67 anim->name = newname;
68 }
70 /* ---- node implementation ----- */
72 int anm_init_node(struct anm_node *node)
73 {
74 memset(node, 0, sizeof *node);
76 node->cur_anim[1] = -1;
78 if(!(node->animations = dynarr_alloc(1, sizeof *node->animations))) {
79 return -1;
80 }
81 if(anm_init_animation(node->animations) == -1) {
82 dynarr_free(node->animations);
83 return -1;
84 }
86 /* initialize thread-local matrix cache */
87 pthread_key_create(&node->cache_key, 0);
88 pthread_mutex_init(&node->cache_list_lock, 0);
90 return 0;
91 }
93 void anm_destroy_node(struct anm_node *node)
94 {
95 int i;
96 free(node->name);
98 for(i=0; i<ANM_NUM_TRACKS; i++) {
99 anm_destroy_animation(node->animations + i);
100 }
101 dynarr_free(node->animations);
103 /* destroy thread-specific cache */
104 pthread_key_delete(node->cache_key);
106 while(node->cache_list) {
107 struct mat_cache *tmp = node->cache_list;
108 node->cache_list = tmp->next;
109 free(tmp);
110 }
111 }
113 void anm_destroy_node_tree(struct anm_node *tree)
114 {
115 struct anm_node *c, *tmp;
117 if(!tree) return;
119 c = tree->child;
120 while(c) {
121 tmp = c;
122 c = c->next;
124 anm_destroy_node_tree(tmp);
125 }
126 anm_destroy_node(tree);
127 }
129 struct anm_node *anm_create_node(void)
130 {
131 struct anm_node *n;
133 if((n = malloc(sizeof *n))) {
134 if(anm_init_node(n) == -1) {
135 free(n);
136 return 0;
137 }
138 }
139 return n;
140 }
142 void anm_free_node(struct anm_node *node)
143 {
144 anm_destroy_node(node);
145 free(node);
146 }
148 void anm_free_node_tree(struct anm_node *tree)
149 {
150 struct anm_node *c, *tmp;
152 if(!tree) return;
154 c = tree->child;
155 while(c) {
156 tmp = c;
157 c = c->next;
159 anm_free_node_tree(tmp);
160 }
162 anm_free_node(tree);
163 }
165 int anm_set_node_name(struct anm_node *node, const char *name)
166 {
167 char *str;
169 if(!(str = malloc(strlen(name) + 1))) {
170 return -1;
171 }
172 strcpy(str, name);
173 free(node->name);
174 node->name = str;
175 return 0;
176 }
178 const char *anm_get_node_name(struct anm_node *node)
179 {
180 return node->name ? node->name : "";
181 }
183 void anm_link_node(struct anm_node *p, struct anm_node *c)
184 {
185 c->next = p->child;
186 p->child = c;
188 c->parent = p;
189 invalidate_cache(c);
190 }
192 int anm_unlink_node(struct anm_node *p, struct anm_node *c)
193 {
194 struct anm_node *iter;
196 if(p->child == c) {
197 p->child = c->next;
198 c->next = 0;
199 invalidate_cache(c);
200 return 0;
201 }
203 iter = p->child;
204 while(iter->next) {
205 if(iter->next == c) {
206 iter->next = c->next;
207 c->next = 0;
208 invalidate_cache(c);
209 return 0;
210 }
211 }
212 return -1;
213 }
215 void anm_set_pivot(struct anm_node *node, vec3_t piv)
216 {
217 node->pivot = piv;
218 }
220 vec3_t anm_get_pivot(struct anm_node *node)
221 {
222 return node->pivot;
223 }
226 /* animation management */
228 int anm_use_node_animation(struct anm_node *node, int aidx)
229 {
230 if(aidx == node->cur_anim[0] && node->cur_anim[1] == -1) {
231 return 0; /* no change, no invalidation */
232 }
234 if(aidx < 0 || aidx >= anm_get_animation_count(node)) {
235 return -1;
236 }
238 node->cur_anim[0] = aidx;
239 node->cur_anim[1] = -1;
240 node->cur_mix = 0;
241 node->blend_dur = -1;
243 invalidate_cache(node);
244 return 0;
245 }
247 int anm_use_node_animations(struct anm_node *node, int aidx, int bidx, float t)
248 {
249 int num_anim;
251 if(node->cur_anim[0] == aidx && node->cur_anim[1] == bidx &&
252 fabs(t - node->cur_mix) < 1e-6) {
253 return 0; /* no change, no invalidation */
254 }
256 num_anim = anm_get_animation_count(node);
257 if(aidx < 0 || aidx >= num_anim) {
258 return anm_use_animation(node, bidx);
259 }
260 if(bidx < 0 || bidx >= num_anim) {
261 return anm_use_animation(node, aidx);
262 }
263 node->cur_anim[0] = aidx;
264 node->cur_anim[1] = bidx;
265 node->cur_mix = t;
267 invalidate_cache(node);
268 return 0;
269 }
271 int anm_use_animation(struct anm_node *node, int aidx)
272 {
273 struct anm_node *child;
275 if(anm_use_node_animation(node, aidx) == -1) {
276 return -1;
277 }
279 child = node->child;
280 while(child) {
281 if(anm_use_animation(child, aidx) == -1) {
282 return -1;
283 }
284 child = child->next;
285 }
286 return 0;
287 }
289 int anm_use_animations(struct anm_node *node, int aidx, int bidx, float t)
290 {
291 struct anm_node *child;
293 if(anm_use_node_animations(node, aidx, bidx, t) == -1) {
294 return -1;
295 }
297 child = node->child;
298 while(child) {
299 if(anm_use_animations(child, aidx, bidx, t) == -1) {
300 return -1;
301 }
302 child = child->next;
303 }
304 return 0;
306 }
308 void anm_set_node_animation_offset(struct anm_node *node, anm_time_t offs, int which)
309 {
310 if(which < 0 || which >= 2) {
311 return;
312 }
313 node->cur_anim_offset[which] = offs;
314 }
316 anm_time_t anm_get_animation_offset(const struct anm_node *node, int which)
317 {
318 if(which < 0 || which >= 2) {
319 return 0;
320 }
321 return node->cur_anim_offset[which];
322 }
324 void anm_set_animation_offset(struct anm_node *node, anm_time_t offs, int which)
325 {
326 struct anm_node *c = node->child;
327 while(c) {
328 anm_set_animation_offset(c, offs, which);
329 c = c->next;
330 }
332 anm_set_node_animation_offset(node, offs, which);
333 }
335 int anm_get_active_animation_index(const struct anm_node *node, int which)
336 {
337 if(which < 0 || which >= 2) return -1;
338 return node->cur_anim[which];
339 }
341 struct anm_animation *anm_get_active_animation(const struct anm_node *node, int which)
342 {
343 int idx = anm_get_active_animation_index(node, which);
344 if(idx < 0 || idx >= anm_get_animation_count(node)) {
345 return 0;
346 }
347 return node->animations + idx;
348 }
350 float anm_get_active_animation_mix(const struct anm_node *node)
351 {
352 return node->cur_mix;
353 }
355 int anm_get_animation_count(const struct anm_node *node)
356 {
357 return dynarr_size(node->animations);
358 }
360 int anm_add_node_animation(struct anm_node *node)
361 {
362 struct anm_animation newanim;
363 anm_init_animation(&newanim);
365 node->animations = dynarr_push(node->animations, &newanim);
366 return 0;
367 }
369 int anm_remove_node_animation(struct anm_node *node, int idx)
370 {
371 fprintf(stderr, "anm_remove_animation: unimplemented!");
372 abort();
373 return 0;
374 }
376 int anm_add_animation(struct anm_node *node)
377 {
378 struct anm_node *child;
380 if(anm_add_node_animation(node) == -1) {
381 return -1;
382 }
384 child = node->child;
385 while(child) {
386 if(anm_add_animation(child)) {
387 return -1;
388 }
389 child = child->next;
390 }
391 return 0;
392 }
394 int anm_remove_animation(struct anm_node *node, int idx)
395 {
396 struct anm_node *child;
398 if(anm_remove_node_animation(node, idx) == -1) {
399 return -1;
400 }
402 child = node->child;
403 while(child) {
404 if(anm_remove_animation(child, idx) == -1) {
405 return -1;
406 }
407 child = child->next;
408 }
409 return 0;
410 }
412 struct anm_animation *anm_get_animation(struct anm_node *node, int idx)
413 {
414 if(idx < 0 || idx > anm_get_animation_count(node)) {
415 return 0;
416 }
417 return node->animations + idx;
418 }
420 struct anm_animation *anm_get_animation_by_name(struct anm_node *node, const char *name)
421 {
422 return anm_get_animation(node, anm_find_animation(node, name));
423 }
425 int anm_find_animation(struct anm_node *node, const char *name)
426 {
427 int i, count = anm_get_animation_count(node);
428 for(i=0; i<count; i++) {
429 if(strcmp(node->animations[i].name, name) == 0) {
430 return i;
431 }
432 }
433 return -1;
434 }
436 /* all the rest act on the current animation(s) */
438 void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in)
439 {
440 int i;
441 struct anm_animation *anim = anm_get_active_animation(node, 0);
442 if(!anim) return;
444 for(i=0; i<ANM_NUM_TRACKS; i++) {
445 anm_set_track_interpolator(anim->tracks + i, in);
446 }
447 invalidate_cache(node);
448 }
450 void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex)
451 {
452 int i;
453 struct anm_animation *anim = anm_get_active_animation(node, 0);
454 if(!anim) return;
456 for(i=0; i<ANM_NUM_TRACKS; i++) {
457 anm_set_track_extrapolator(anim->tracks + i, ex);
458 }
459 invalidate_cache(node);
460 }
462 void anm_set_node_active_animation_name(struct anm_node *node, const char *name)
463 {
464 struct anm_animation *anim = anm_get_active_animation(node, 0);
465 if(!anim) return;
467 anm_set_animation_name(anim, name);
468 }
470 void anm_set_active_animation_name(struct anm_node *node, const char *name)
471 {
472 struct anm_node *child;
474 anm_set_node_active_animation_name(node, name);
476 child = node->child;
477 while(child) {
478 anm_set_active_animation_name(child, name);
479 child = child->next;
480 }
481 }
483 const char *anm_get_active_animation_name(struct anm_node *node)
484 {
485 struct anm_animation *anim = anm_get_active_animation(node, 0);
486 if(anim) {
487 return anim->name;
488 }
489 return 0;
490 }
492 /* ---- high level animation blending ---- */
493 void anm_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur)
494 {
495 struct anm_node *c = node->child;
497 if(anmidx == node->cur_anim[0]) {
498 return;
499 }
501 while(c) {
502 anm_transition(c, anmidx, start, dur);
503 c = c->next;
504 }
506 anm_node_transition(node, anmidx, start, dur);
507 }
509 void anm_node_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur)
510 {
511 if(anmidx == node->cur_anim[0]) {
512 return;
513 }
515 node->cur_anim[1] = anmidx;
516 node->cur_anim_offset[1] = start;
517 node->blend_dur = dur;
518 }
521 #define BLEND_START_TM node->cur_anim_offset[1]
523 static anm_time_t animation_time(struct anm_node *node, anm_time_t tm, int which)
524 {
525 float t;
527 if(node->blend_dur >= 0) {
528 /* we're in transition... */
529 t = (float)(tm - BLEND_START_TM) / (float)node->blend_dur;
530 if(t < 0.0) t = 0.0;
532 node->cur_mix = t;
534 if(t > 1.0) {
535 /* switch completely over to the target animation and stop blending */
536 anm_use_node_animation(node, node->cur_anim[1]);
537 node->cur_anim_offset[0] = node->cur_anim_offset[1];
538 }
539 }
541 return tm - node->cur_anim_offset[which];
542 }
545 void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm)
546 {
547 struct anm_animation *anim = anm_get_active_animation(node, 0);
548 if(!anim) return;
550 anm_set_value(anim->tracks + ANM_TRACK_POS_X, tm, pos.x);
551 anm_set_value(anim->tracks + ANM_TRACK_POS_Y, tm, pos.y);
552 anm_set_value(anim->tracks + ANM_TRACK_POS_Z, tm, pos.z);
553 invalidate_cache(node);
554 }
557 vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm)
558 {
559 vec3_t v;
560 anm_time_t tm0 = animation_time(node, tm, 0);
561 struct anm_animation *anim0 = anm_get_active_animation(node, 0);
562 struct anm_animation *anim1 = anm_get_active_animation(node, 1);
564 if(!anim0) {
565 return v3_cons(0, 0, 0);
566 }
568 v.x = anm_get_value(anim0->tracks + ANM_TRACK_POS_X, tm0);
569 v.y = anm_get_value(anim0->tracks + ANM_TRACK_POS_Y, tm0);
570 v.z = anm_get_value(anim0->tracks + ANM_TRACK_POS_Z, tm0);
572 if(anim1) {
573 vec3_t v1;
574 anm_time_t tm1 = animation_time(node, tm, 1);
575 v1.x = anm_get_value(anim1->tracks + ANM_TRACK_POS_X, tm1);
576 v1.y = anm_get_value(anim1->tracks + ANM_TRACK_POS_Y, tm1);
577 v1.z = anm_get_value(anim1->tracks + ANM_TRACK_POS_Z, tm1);
579 v.x = v.x + (v1.x - v.x) * node->cur_mix;
580 v.y = v.y + (v1.y - v.y) * node->cur_mix;
581 v.z = v.z + (v1.z - v.z) * node->cur_mix;
582 }
584 return v;
585 }
587 void anm_set_rotation(struct anm_node *node, quat_t rot, anm_time_t tm)
588 {
589 struct anm_animation *anim = anm_get_active_animation(node, 0);
590 if(!anim) return;
592 anm_set_value(anim->tracks + ANM_TRACK_ROT_X, tm, rot.x);
593 anm_set_value(anim->tracks + ANM_TRACK_ROT_Y, tm, rot.y);
594 anm_set_value(anim->tracks + ANM_TRACK_ROT_Z, tm, rot.z);
595 anm_set_value(anim->tracks + ANM_TRACK_ROT_W, tm, rot.w);
596 invalidate_cache(node);
597 }
599 static quat_t get_node_rotation(struct anm_node *node, anm_time_t tm, struct anm_animation *anim)
600 {
601 #ifndef ROT_USE_SLERP
602 quat_t q;
603 q.x = anm_get_value(anim->tracks + ANM_TRACK_ROT_X, tm);
604 q.y = anm_get_value(anim->tracks + ANM_TRACK_ROT_Y, tm);
605 q.z = anm_get_value(anim->tracks + ANM_TRACK_ROT_Z, tm);
606 q.w = anm_get_value(anim->tracks + ANM_TRACK_ROT_W, tm);
607 return q;
608 #else
609 int idx0, idx1, last_idx;
610 anm_time_t tstart, tend;
611 float t, dt;
612 struct anm_track *track_x, *track_y, *track_z, *track_w;
613 quat_t q, q1, q2;
615 track_x = anim->tracks + ANM_TRACK_ROT_X;
616 track_y = anim->tracks + ANM_TRACK_ROT_Y;
617 track_z = anim->tracks + ANM_TRACK_ROT_Z;
618 track_w = anim->tracks + ANM_TRACK_ROT_W;
620 if(!track_x->count) {
621 q.x = track_x->def_val;
622 q.y = track_y->def_val;
623 q.z = track_z->def_val;
624 q.w = track_w->def_val;
625 return q;
626 }
628 last_idx = track_x->count - 1;
630 tstart = track_x->keys[0].time;
631 tend = track_x->keys[last_idx].time;
633 if(tstart == tend) {
634 q.x = track_x->keys[0].val;
635 q.y = track_y->keys[0].val;
636 q.z = track_z->keys[0].val;
637 q.w = track_w->keys[0].val;
638 return q;
639 }
641 tm = anm_remap_time(track_x, tm, tstart, tend);
643 idx0 = anm_get_key_interval(track_x, tm);
644 assert(idx0 >= 0 && idx0 < track_x->count);
645 idx1 = idx0 + 1;
647 if(idx0 == last_idx) {
648 q.x = track_x->keys[idx0].val;
649 q.y = track_y->keys[idx0].val;
650 q.z = track_z->keys[idx0].val;
651 q.w = track_w->keys[idx0].val;
652 return q;
653 }
655 dt = (float)(track_x->keys[idx1].time - track_x->keys[idx0].time);
656 t = (float)(tm - track_x->keys[idx0].time) / dt;
658 q1.x = track_x->keys[idx0].val;
659 q1.y = track_y->keys[idx0].val;
660 q1.z = track_z->keys[idx0].val;
661 q1.w = track_w->keys[idx0].val;
663 q2.x = track_x->keys[idx1].val;
664 q2.y = track_y->keys[idx1].val;
665 q2.z = track_z->keys[idx1].val;
666 q2.w = track_w->keys[idx1].val;
668 /*q1 = quat_normalize(q1);
669 q2 = quat_normalize(q2);*/
671 return quat_slerp(q1, q2, t);
672 #endif
673 }
675 quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm)
676 {
677 quat_t q;
678 anm_time_t tm0 = animation_time(node, tm, 0);
679 struct anm_animation *anim0 = anm_get_active_animation(node, 0);
680 struct anm_animation *anim1 = anm_get_active_animation(node, 1);
682 if(!anim0) {
683 return quat_identity();
684 }
686 q = get_node_rotation(node, tm0, anim0);
688 if(anim1) {
689 anm_time_t tm1 = animation_time(node, tm, 1);
690 quat_t q1 = get_node_rotation(node, tm1, anim1);
692 q = quat_slerp(q, q1, node->cur_mix);
693 }
694 return q;
695 }
697 void anm_set_scaling(struct anm_node *node, vec3_t scl, anm_time_t tm)
698 {
699 struct anm_animation *anim = anm_get_active_animation(node, 0);
700 if(!anim) return;
702 anm_set_value(anim->tracks + ANM_TRACK_SCL_X, tm, scl.x);
703 anm_set_value(anim->tracks + ANM_TRACK_SCL_Y, tm, scl.y);
704 anm_set_value(anim->tracks + ANM_TRACK_SCL_Z, tm, scl.z);
705 invalidate_cache(node);
706 }
708 vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm)
709 {
710 vec3_t v;
711 anm_time_t tm0 = animation_time(node, tm, 0);
712 struct anm_animation *anim0 = anm_get_active_animation(node, 0);
713 struct anm_animation *anim1 = anm_get_active_animation(node, 1);
715 if(!anim0) {
716 return v3_cons(1, 1, 1);
717 }
719 v.x = anm_get_value(anim0->tracks + ANM_TRACK_SCL_X, tm0);
720 v.y = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Y, tm0);
721 v.z = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Z, tm0);
723 if(anim1) {
724 vec3_t v1;
725 anm_time_t tm1 = animation_time(node, tm, 1);
726 v1.x = anm_get_value(anim1->tracks + ANM_TRACK_SCL_X, tm1);
727 v1.y = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Y, tm1);
728 v1.z = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Z, tm1);
730 v.x = v.x + (v1.x - v.x) * node->cur_mix;
731 v.y = v.y + (v1.y - v.y) * node->cur_mix;
732 v.z = v.z + (v1.z - v.z) * node->cur_mix;
733 }
735 return v;
736 }
739 vec3_t anm_get_position(struct anm_node *node, anm_time_t tm)
740 {
741 mat4_t xform;
742 vec3_t pos = {0.0, 0.0, 0.0};
744 if(!node->parent) {
745 return anm_get_node_position(node, tm);
746 }
748 anm_get_matrix(node, xform, tm);
749 return v3_transform(pos, xform);
750 }
752 quat_t anm_get_rotation(struct anm_node *node, anm_time_t tm)
753 {
754 quat_t rot, prot;
755 rot = anm_get_node_rotation(node, tm);
757 if(!node->parent) {
758 return rot;
759 }
761 prot = anm_get_rotation(node->parent, tm);
762 return quat_mul(prot, rot);
763 }
765 vec3_t anm_get_scaling(struct anm_node *node, anm_time_t tm)
766 {
767 vec3_t s, ps;
768 s = anm_get_node_scaling(node, tm);
770 if(!node->parent) {
771 return s;
772 }
774 ps = anm_get_scaling(node->parent, tm);
775 return v3_mul(s, ps);
776 }
778 void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
779 {
780 int i;
781 mat4_t rmat;
782 vec3_t pos, scale;
783 quat_t rot;
785 pos = anm_get_node_position(node, tm);
786 rot = anm_get_node_rotation(node, tm);
787 scale = anm_get_node_scaling(node, tm);
789 m4_set_translation(mat, node->pivot.x, node->pivot.y, node->pivot.z);
791 quat_to_mat4(rmat, rot);
792 for(i=0; i<3; i++) {
793 mat[i][0] = rmat[i][0];
794 mat[i][1] = rmat[i][1];
795 mat[i][2] = rmat[i][2];
796 }
797 /* this loop is equivalent to: m4_mult(mat, mat, rmat); */
799 mat[0][0] *= scale.x; mat[0][1] *= scale.y; mat[0][2] *= scale.z; mat[0][3] += pos.x;
800 mat[1][0] *= scale.x; mat[1][1] *= scale.y; mat[1][2] *= scale.z; mat[1][3] += pos.y;
801 mat[2][0] *= scale.x; mat[2][1] *= scale.y; mat[2][2] *= scale.z; mat[2][3] += pos.z;
803 m4_translate(mat, -node->pivot.x, -node->pivot.y, -node->pivot.z);
805 /* that's basically: pivot * rotation * translation * scaling * -pivot */
806 }
808 void anm_get_node_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
809 {
810 mat4_t tmp;
811 anm_get_node_matrix(node, tmp, tm);
812 m4_inverse(mat, tmp);
813 }
815 void anm_eval_node(struct anm_node *node, anm_time_t tm)
816 {
817 anm_get_node_matrix(node, node->matrix, tm);
818 }
820 void anm_eval(struct anm_node *node, anm_time_t tm)
821 {
822 struct anm_node *c;
824 anm_eval_node(node, tm);
826 if(node->parent) {
827 /* due to post-order traversal, the parent matrix is already evaluated */
828 m4_mult(node->matrix, node->parent->matrix, node->matrix);
829 }
831 /* recersively evaluate all children */
832 c = node->child;
833 while(c) {
834 anm_eval(c, tm);
835 c = c->next;
836 }
837 }
839 void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
840 {
841 struct mat_cache *cache = pthread_getspecific(node->cache_key);
842 if(!cache) {
843 cache = malloc(sizeof *cache);
844 assert(cache);
846 pthread_mutex_lock(&node->cache_list_lock);
847 cache->next = node->cache_list;
848 node->cache_list = cache;
849 pthread_mutex_unlock(&node->cache_list_lock);
851 cache->time = ANM_TIME_INVAL;
852 cache->inv_time = ANM_TIME_INVAL;
853 pthread_setspecific(node->cache_key, cache);
854 }
856 if(cache->time != tm) {
857 anm_get_node_matrix(node, cache->matrix, tm);
859 if(node->parent) {
860 mat4_t parent_mat;
862 anm_get_matrix(node->parent, parent_mat, tm);
863 m4_mult(cache->matrix, parent_mat, cache->matrix);
864 }
865 cache->time = tm;
866 }
867 m4_copy(mat, cache->matrix);
868 }
870 void anm_get_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
871 {
872 struct mat_cache *cache = pthread_getspecific(node->cache_key);
873 if(!cache) {
874 cache = malloc(sizeof *cache);
875 assert(cache);
877 pthread_mutex_lock(&node->cache_list_lock);
878 cache->next = node->cache_list;
879 node->cache_list = cache;
880 pthread_mutex_unlock(&node->cache_list_lock);
882 cache->inv_time = ANM_TIME_INVAL;
883 cache->inv_time = ANM_TIME_INVAL;
884 pthread_setspecific(node->cache_key, cache);
885 }
887 if(cache->inv_time != tm) {
888 anm_get_matrix(node, mat, tm);
889 m4_inverse(cache->inv_matrix, mat);
890 cache->inv_time = tm;
891 }
892 m4_copy(mat, cache->inv_matrix);
893 }
895 anm_time_t anm_get_start_time(struct anm_node *node)
896 {
897 int i, j;
898 struct anm_node *c;
899 anm_time_t res = LONG_MAX;
901 for(j=0; j<2; j++) {
902 struct anm_animation *anim = anm_get_active_animation(node, j);
903 if(!anim) break;
905 for(i=0; i<ANM_NUM_TRACKS; i++) {
906 if(anim->tracks[i].count) {
907 anm_time_t tm = anim->tracks[i].keys[0].time;
908 if(tm < res) {
909 res = tm;
910 }
911 }
912 }
913 }
915 c = node->child;
916 while(c) {
917 anm_time_t tm = anm_get_start_time(c);
918 if(tm < res) {
919 res = tm;
920 }
921 c = c->next;
922 }
923 return res;
924 }
926 anm_time_t anm_get_end_time(struct anm_node *node)
927 {
928 int i, j;
929 struct anm_node *c;
930 anm_time_t res = LONG_MIN;
932 for(j=0; j<2; j++) {
933 struct anm_animation *anim = anm_get_active_animation(node, j);
934 if(!anim) break;
936 for(i=0; i<ANM_NUM_TRACKS; i++) {
937 if(anim->tracks[i].count) {
938 anm_time_t tm = anim->tracks[i].keys[anim->tracks[i].count - 1].time;
939 if(tm > res) {
940 res = tm;
941 }
942 }
943 }
944 }
946 c = node->child;
947 while(c) {
948 anm_time_t tm = anm_get_end_time(c);
949 if(tm > res) {
950 res = tm;
951 }
952 c = c->next;
953 }
954 return res;
955 }
957 static void invalidate_cache(struct anm_node *node)
958 {
959 struct mat_cache *cache = pthread_getspecific(node->cache_key);
960 if(cache) {
961 cache->time = cache->inv_time = ANM_TIME_INVAL;
962 }
963 }