libanim

view src/anim.c @ 36:6ebf9f2d1113

invalidate_cache should also invalidate children's caches recursively
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 08 Nov 2014 13:41:23 +0200
parents 70ad14ba4df2
children
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, num_anim;
96 free(node->name);
98 num_anim = anm_get_animation_count(node);
99 for(i=0; i<num_anim; i++) {
100 anm_destroy_animation(node->animations + i);
101 }
102 dynarr_free(node->animations);
104 /* destroy thread-specific cache */
105 pthread_key_delete(node->cache_key);
107 while(node->cache_list) {
108 struct mat_cache *tmp = node->cache_list;
109 node->cache_list = tmp->next;
110 free(tmp);
111 }
112 }
114 void anm_destroy_node_tree(struct anm_node *tree)
115 {
116 struct anm_node *c, *tmp;
118 if(!tree) return;
120 c = tree->child;
121 while(c) {
122 tmp = c;
123 c = c->next;
125 anm_destroy_node_tree(tmp);
126 }
127 anm_destroy_node(tree);
128 }
130 struct anm_node *anm_create_node(void)
131 {
132 struct anm_node *n;
134 if((n = malloc(sizeof *n))) {
135 if(anm_init_node(n) == -1) {
136 free(n);
137 return 0;
138 }
139 }
140 return n;
141 }
143 void anm_free_node(struct anm_node *node)
144 {
145 anm_destroy_node(node);
146 free(node);
147 }
149 void anm_free_node_tree(struct anm_node *tree)
150 {
151 struct anm_node *c, *tmp;
153 if(!tree) return;
155 c = tree->child;
156 while(c) {
157 tmp = c;
158 c = c->next;
160 anm_free_node_tree(tmp);
161 }
163 anm_free_node(tree);
164 }
166 int anm_set_node_name(struct anm_node *node, const char *name)
167 {
168 char *str;
170 if(!(str = malloc(strlen(name) + 1))) {
171 return -1;
172 }
173 strcpy(str, name);
174 free(node->name);
175 node->name = str;
176 return 0;
177 }
179 const char *anm_get_node_name(struct anm_node *node)
180 {
181 return node->name ? node->name : "";
182 }
184 void anm_link_node(struct anm_node *p, struct anm_node *c)
185 {
186 c->next = p->child;
187 p->child = c;
189 c->parent = p;
190 invalidate_cache(c);
191 }
193 int anm_unlink_node(struct anm_node *p, struct anm_node *c)
194 {
195 struct anm_node *iter;
197 if(p->child == c) {
198 p->child = c->next;
199 c->next = 0;
200 invalidate_cache(c);
201 return 0;
202 }
204 iter = p->child;
205 while(iter->next) {
206 if(iter->next == c) {
207 iter->next = c->next;
208 c->next = 0;
209 invalidate_cache(c);
210 return 0;
211 }
212 }
213 return -1;
214 }
216 void anm_set_pivot(struct anm_node *node, vec3_t piv)
217 {
218 node->pivot = piv;
219 }
221 vec3_t anm_get_pivot(struct anm_node *node)
222 {
223 return node->pivot;
224 }
227 /* animation management */
229 int anm_use_node_animation(struct anm_node *node, int aidx)
230 {
231 if(aidx == node->cur_anim[0] && node->cur_anim[1] == -1) {
232 return 0; /* no change, no invalidation */
233 }
235 if(aidx < 0 || aidx >= anm_get_animation_count(node)) {
236 return -1;
237 }
239 node->cur_anim[0] = aidx;
240 node->cur_anim[1] = -1;
241 node->cur_mix = 0;
242 node->blend_dur = -1;
244 invalidate_cache(node);
245 return 0;
246 }
248 int anm_use_node_animations(struct anm_node *node, int aidx, int bidx, float t)
249 {
250 int num_anim;
252 if(node->cur_anim[0] == aidx && node->cur_anim[1] == bidx &&
253 fabs(t - node->cur_mix) < 1e-6) {
254 return 0; /* no change, no invalidation */
255 }
257 num_anim = anm_get_animation_count(node);
258 if(aidx < 0 || aidx >= num_anim) {
259 return anm_use_animation(node, bidx);
260 }
261 if(bidx < 0 || bidx >= num_anim) {
262 return anm_use_animation(node, aidx);
263 }
264 node->cur_anim[0] = aidx;
265 node->cur_anim[1] = bidx;
266 node->cur_mix = t;
268 invalidate_cache(node);
269 return 0;
270 }
272 int anm_use_animation(struct anm_node *node, int aidx)
273 {
274 struct anm_node *child;
276 if(anm_use_node_animation(node, aidx) == -1) {
277 return -1;
278 }
280 child = node->child;
281 while(child) {
282 if(anm_use_animation(child, aidx) == -1) {
283 return -1;
284 }
285 child = child->next;
286 }
287 return 0;
288 }
290 int anm_use_animations(struct anm_node *node, int aidx, int bidx, float t)
291 {
292 struct anm_node *child;
294 if(anm_use_node_animations(node, aidx, bidx, t) == -1) {
295 return -1;
296 }
298 child = node->child;
299 while(child) {
300 if(anm_use_animations(child, aidx, bidx, t) == -1) {
301 return -1;
302 }
303 child = child->next;
304 }
305 return 0;
307 }
309 void anm_set_node_animation_offset(struct anm_node *node, anm_time_t offs, int which)
310 {
311 if(which < 0 || which >= 2) {
312 return;
313 }
314 node->cur_anim_offset[which] = offs;
315 }
317 anm_time_t anm_get_animation_offset(const struct anm_node *node, int which)
318 {
319 if(which < 0 || which >= 2) {
320 return 0;
321 }
322 return node->cur_anim_offset[which];
323 }
325 void anm_set_animation_offset(struct anm_node *node, anm_time_t offs, int which)
326 {
327 struct anm_node *c = node->child;
328 while(c) {
329 anm_set_animation_offset(c, offs, which);
330 c = c->next;
331 }
333 anm_set_node_animation_offset(node, offs, which);
334 }
336 int anm_get_active_animation_index(const struct anm_node *node, int which)
337 {
338 if(which < 0 || which >= 2) return -1;
339 return node->cur_anim[which];
340 }
342 struct anm_animation *anm_get_active_animation(const struct anm_node *node, int which)
343 {
344 int idx = anm_get_active_animation_index(node, which);
345 if(idx < 0 || idx >= anm_get_animation_count(node)) {
346 return 0;
347 }
348 return node->animations + idx;
349 }
351 float anm_get_active_animation_mix(const struct anm_node *node)
352 {
353 return node->cur_mix;
354 }
356 int anm_get_animation_count(const struct anm_node *node)
357 {
358 return dynarr_size(node->animations);
359 }
361 int anm_add_node_animation(struct anm_node *node)
362 {
363 struct anm_animation newanim;
364 anm_init_animation(&newanim);
366 node->animations = dynarr_push(node->animations, &newanim);
367 return 0;
368 }
370 int anm_remove_node_animation(struct anm_node *node, int idx)
371 {
372 fprintf(stderr, "anm_remove_animation: unimplemented!");
373 abort();
374 return 0;
375 }
377 int anm_add_animation(struct anm_node *node)
378 {
379 struct anm_node *child;
381 if(anm_add_node_animation(node) == -1) {
382 return -1;
383 }
385 child = node->child;
386 while(child) {
387 if(anm_add_animation(child)) {
388 return -1;
389 }
390 child = child->next;
391 }
392 return 0;
393 }
395 int anm_remove_animation(struct anm_node *node, int idx)
396 {
397 struct anm_node *child;
399 if(anm_remove_node_animation(node, idx) == -1) {
400 return -1;
401 }
403 child = node->child;
404 while(child) {
405 if(anm_remove_animation(child, idx) == -1) {
406 return -1;
407 }
408 child = child->next;
409 }
410 return 0;
411 }
413 struct anm_animation *anm_get_animation(struct anm_node *node, int idx)
414 {
415 if(idx < 0 || idx > anm_get_animation_count(node)) {
416 return 0;
417 }
418 return node->animations + idx;
419 }
421 struct anm_animation *anm_get_animation_by_name(struct anm_node *node, const char *name)
422 {
423 return anm_get_animation(node, anm_find_animation(node, name));
424 }
426 int anm_find_animation(struct anm_node *node, const char *name)
427 {
428 int i, count = anm_get_animation_count(node);
429 for(i=0; i<count; i++) {
430 if(strcmp(node->animations[i].name, name) == 0) {
431 return i;
432 }
433 }
434 return -1;
435 }
437 /* all the rest act on the current animation(s) */
439 void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in)
440 {
441 int i;
442 struct anm_animation *anim = anm_get_active_animation(node, 0);
443 if(!anim) return;
445 for(i=0; i<ANM_NUM_TRACKS; i++) {
446 anm_set_track_interpolator(anim->tracks + i, in);
447 }
448 invalidate_cache(node);
449 }
451 void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex)
452 {
453 int i;
454 struct anm_animation *anim = anm_get_active_animation(node, 0);
455 if(!anim) return;
457 for(i=0; i<ANM_NUM_TRACKS; i++) {
458 anm_set_track_extrapolator(anim->tracks + i, ex);
459 }
460 invalidate_cache(node);
461 }
463 void anm_set_node_active_animation_name(struct anm_node *node, const char *name)
464 {
465 struct anm_animation *anim = anm_get_active_animation(node, 0);
466 if(!anim) return;
468 anm_set_animation_name(anim, name);
469 }
471 void anm_set_active_animation_name(struct anm_node *node, const char *name)
472 {
473 struct anm_node *child;
475 anm_set_node_active_animation_name(node, name);
477 child = node->child;
478 while(child) {
479 anm_set_active_animation_name(child, name);
480 child = child->next;
481 }
482 }
484 const char *anm_get_active_animation_name(struct anm_node *node)
485 {
486 struct anm_animation *anim = anm_get_active_animation(node, 0);
487 if(anim) {
488 return anim->name;
489 }
490 return 0;
491 }
493 /* ---- high level animation blending ---- */
494 void anm_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur)
495 {
496 struct anm_node *c = node->child;
498 if(anmidx == node->cur_anim[0]) {
499 return;
500 }
502 while(c) {
503 anm_transition(c, anmidx, start, dur);
504 c = c->next;
505 }
507 anm_node_transition(node, anmidx, start, dur);
508 }
510 void anm_node_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur)
511 {
512 if(anmidx == node->cur_anim[0]) {
513 return;
514 }
516 node->cur_anim[1] = anmidx;
517 node->cur_anim_offset[1] = start;
518 node->blend_dur = dur;
519 }
522 #define BLEND_START_TM node->cur_anim_offset[1]
524 static anm_time_t animation_time(struct anm_node *node, anm_time_t tm, int which)
525 {
526 float t;
528 if(node->blend_dur >= 0) {
529 /* we're in transition... */
530 t = (float)(tm - BLEND_START_TM) / (float)node->blend_dur;
531 if(t < 0.0) t = 0.0;
533 node->cur_mix = t;
535 if(t > 1.0) {
536 /* switch completely over to the target animation and stop blending */
537 anm_use_node_animation(node, node->cur_anim[1]);
538 node->cur_anim_offset[0] = node->cur_anim_offset[1];
539 }
540 }
542 return tm - node->cur_anim_offset[which];
543 }
546 void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm)
547 {
548 struct anm_animation *anim = anm_get_active_animation(node, 0);
549 if(!anim) return;
551 anm_set_value(anim->tracks + ANM_TRACK_POS_X, tm, pos.x);
552 anm_set_value(anim->tracks + ANM_TRACK_POS_Y, tm, pos.y);
553 anm_set_value(anim->tracks + ANM_TRACK_POS_Z, tm, pos.z);
554 invalidate_cache(node);
555 }
558 vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm)
559 {
560 vec3_t v;
561 anm_time_t tm0 = animation_time(node, tm, 0);
562 struct anm_animation *anim0 = anm_get_active_animation(node, 0);
563 struct anm_animation *anim1 = anm_get_active_animation(node, 1);
565 if(!anim0) {
566 return v3_cons(0, 0, 0);
567 }
569 v.x = anm_get_value(anim0->tracks + ANM_TRACK_POS_X, tm0);
570 v.y = anm_get_value(anim0->tracks + ANM_TRACK_POS_Y, tm0);
571 v.z = anm_get_value(anim0->tracks + ANM_TRACK_POS_Z, tm0);
573 if(anim1) {
574 vec3_t v1;
575 anm_time_t tm1 = animation_time(node, tm, 1);
576 v1.x = anm_get_value(anim1->tracks + ANM_TRACK_POS_X, tm1);
577 v1.y = anm_get_value(anim1->tracks + ANM_TRACK_POS_Y, tm1);
578 v1.z = anm_get_value(anim1->tracks + ANM_TRACK_POS_Z, tm1);
580 v.x = v.x + (v1.x - v.x) * node->cur_mix;
581 v.y = v.y + (v1.y - v.y) * node->cur_mix;
582 v.z = v.z + (v1.z - v.z) * node->cur_mix;
583 }
585 return v;
586 }
588 void anm_set_rotation(struct anm_node *node, quat_t rot, anm_time_t tm)
589 {
590 struct anm_animation *anim = anm_get_active_animation(node, 0);
591 if(!anim) return;
593 anm_set_value(anim->tracks + ANM_TRACK_ROT_X, tm, rot.x);
594 anm_set_value(anim->tracks + ANM_TRACK_ROT_Y, tm, rot.y);
595 anm_set_value(anim->tracks + ANM_TRACK_ROT_Z, tm, rot.z);
596 anm_set_value(anim->tracks + ANM_TRACK_ROT_W, tm, rot.w);
597 invalidate_cache(node);
598 }
600 static quat_t get_node_rotation(struct anm_node *node, anm_time_t tm, struct anm_animation *anim)
601 {
602 #ifndef ROT_USE_SLERP
603 quat_t q;
604 q.x = anm_get_value(anim->tracks + ANM_TRACK_ROT_X, tm);
605 q.y = anm_get_value(anim->tracks + ANM_TRACK_ROT_Y, tm);
606 q.z = anm_get_value(anim->tracks + ANM_TRACK_ROT_Z, tm);
607 q.w = anm_get_value(anim->tracks + ANM_TRACK_ROT_W, tm);
608 return q;
609 #else
610 int idx0, idx1, last_idx;
611 anm_time_t tstart, tend;
612 float t, dt;
613 struct anm_track *track_x, *track_y, *track_z, *track_w;
614 quat_t q, q1, q2;
616 track_x = anim->tracks + ANM_TRACK_ROT_X;
617 track_y = anim->tracks + ANM_TRACK_ROT_Y;
618 track_z = anim->tracks + ANM_TRACK_ROT_Z;
619 track_w = anim->tracks + ANM_TRACK_ROT_W;
621 if(!track_x->count) {
622 q.x = track_x->def_val;
623 q.y = track_y->def_val;
624 q.z = track_z->def_val;
625 q.w = track_w->def_val;
626 return q;
627 }
629 last_idx = track_x->count - 1;
631 tstart = track_x->keys[0].time;
632 tend = track_x->keys[last_idx].time;
634 if(tstart == tend) {
635 q.x = track_x->keys[0].val;
636 q.y = track_y->keys[0].val;
637 q.z = track_z->keys[0].val;
638 q.w = track_w->keys[0].val;
639 return q;
640 }
642 tm = anm_remap_time(track_x, tm, tstart, tend);
644 idx0 = anm_get_key_interval(track_x, tm);
645 assert(idx0 >= 0 && idx0 < track_x->count);
646 idx1 = idx0 + 1;
648 if(idx0 == last_idx) {
649 q.x = track_x->keys[idx0].val;
650 q.y = track_y->keys[idx0].val;
651 q.z = track_z->keys[idx0].val;
652 q.w = track_w->keys[idx0].val;
653 return q;
654 }
656 dt = (float)(track_x->keys[idx1].time - track_x->keys[idx0].time);
657 t = (float)(tm - track_x->keys[idx0].time) / dt;
659 q1.x = track_x->keys[idx0].val;
660 q1.y = track_y->keys[idx0].val;
661 q1.z = track_z->keys[idx0].val;
662 q1.w = track_w->keys[idx0].val;
664 q2.x = track_x->keys[idx1].val;
665 q2.y = track_y->keys[idx1].val;
666 q2.z = track_z->keys[idx1].val;
667 q2.w = track_w->keys[idx1].val;
669 /*q1 = quat_normalize(q1);
670 q2 = quat_normalize(q2);*/
672 return quat_slerp(q1, q2, t);
673 #endif
674 }
676 quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm)
677 {
678 quat_t q;
679 anm_time_t tm0 = animation_time(node, tm, 0);
680 struct anm_animation *anim0 = anm_get_active_animation(node, 0);
681 struct anm_animation *anim1 = anm_get_active_animation(node, 1);
683 if(!anim0) {
684 return quat_identity();
685 }
687 q = get_node_rotation(node, tm0, anim0);
689 if(anim1) {
690 anm_time_t tm1 = animation_time(node, tm, 1);
691 quat_t q1 = get_node_rotation(node, tm1, anim1);
693 q = quat_slerp(q, q1, node->cur_mix);
694 }
695 return q;
696 }
698 void anm_set_scaling(struct anm_node *node, vec3_t scl, anm_time_t tm)
699 {
700 struct anm_animation *anim = anm_get_active_animation(node, 0);
701 if(!anim) return;
703 anm_set_value(anim->tracks + ANM_TRACK_SCL_X, tm, scl.x);
704 anm_set_value(anim->tracks + ANM_TRACK_SCL_Y, tm, scl.y);
705 anm_set_value(anim->tracks + ANM_TRACK_SCL_Z, tm, scl.z);
706 invalidate_cache(node);
707 }
709 vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm)
710 {
711 vec3_t v;
712 anm_time_t tm0 = animation_time(node, tm, 0);
713 struct anm_animation *anim0 = anm_get_active_animation(node, 0);
714 struct anm_animation *anim1 = anm_get_active_animation(node, 1);
716 if(!anim0) {
717 return v3_cons(1, 1, 1);
718 }
720 v.x = anm_get_value(anim0->tracks + ANM_TRACK_SCL_X, tm0);
721 v.y = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Y, tm0);
722 v.z = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Z, tm0);
724 if(anim1) {
725 vec3_t v1;
726 anm_time_t tm1 = animation_time(node, tm, 1);
727 v1.x = anm_get_value(anim1->tracks + ANM_TRACK_SCL_X, tm1);
728 v1.y = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Y, tm1);
729 v1.z = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Z, tm1);
731 v.x = v.x + (v1.x - v.x) * node->cur_mix;
732 v.y = v.y + (v1.y - v.y) * node->cur_mix;
733 v.z = v.z + (v1.z - v.z) * node->cur_mix;
734 }
736 return v;
737 }
740 vec3_t anm_get_position(struct anm_node *node, anm_time_t tm)
741 {
742 mat4_t xform;
743 vec3_t pos = {0.0, 0.0, 0.0};
745 if(!node->parent) {
746 return anm_get_node_position(node, tm);
747 }
749 anm_get_matrix(node, xform, tm);
750 return v3_transform(pos, xform);
751 }
753 quat_t anm_get_rotation(struct anm_node *node, anm_time_t tm)
754 {
755 quat_t rot, prot;
756 rot = anm_get_node_rotation(node, tm);
758 if(!node->parent) {
759 return rot;
760 }
762 prot = anm_get_rotation(node->parent, tm);
763 return quat_mul(prot, rot);
764 }
766 vec3_t anm_get_scaling(struct anm_node *node, anm_time_t tm)
767 {
768 vec3_t s, ps;
769 s = anm_get_node_scaling(node, tm);
771 if(!node->parent) {
772 return s;
773 }
775 ps = anm_get_scaling(node->parent, tm);
776 return v3_mul(s, ps);
777 }
779 void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
780 {
781 int i;
782 mat4_t rmat;
783 vec3_t pos, scale;
784 quat_t rot;
786 pos = anm_get_node_position(node, tm);
787 rot = anm_get_node_rotation(node, tm);
788 scale = anm_get_node_scaling(node, tm);
790 m4_set_translation(mat, node->pivot.x, node->pivot.y, node->pivot.z);
792 quat_to_mat4(rmat, rot);
793 for(i=0; i<3; i++) {
794 mat[i][0] = rmat[i][0];
795 mat[i][1] = rmat[i][1];
796 mat[i][2] = rmat[i][2];
797 }
798 /* this loop is equivalent to: m4_mult(mat, mat, rmat); */
800 mat[0][0] *= scale.x; mat[0][1] *= scale.y; mat[0][2] *= scale.z; mat[0][3] += pos.x;
801 mat[1][0] *= scale.x; mat[1][1] *= scale.y; mat[1][2] *= scale.z; mat[1][3] += pos.y;
802 mat[2][0] *= scale.x; mat[2][1] *= scale.y; mat[2][2] *= scale.z; mat[2][3] += pos.z;
804 m4_translate(mat, -node->pivot.x, -node->pivot.y, -node->pivot.z);
806 /* that's basically: pivot * rotation * translation * scaling * -pivot */
807 }
809 void anm_get_node_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
810 {
811 mat4_t tmp;
812 anm_get_node_matrix(node, tmp, tm);
813 m4_inverse(mat, tmp);
814 }
816 void anm_eval_node(struct anm_node *node, anm_time_t tm)
817 {
818 anm_get_node_matrix(node, node->matrix, tm);
819 }
821 void anm_eval(struct anm_node *node, anm_time_t tm)
822 {
823 struct anm_node *c;
825 anm_eval_node(node, tm);
827 if(node->parent) {
828 /* due to post-order traversal, the parent matrix is already evaluated */
829 m4_mult(node->matrix, node->parent->matrix, node->matrix);
830 }
832 /* recersively evaluate all children */
833 c = node->child;
834 while(c) {
835 anm_eval(c, tm);
836 c = c->next;
837 }
838 }
840 void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
841 {
842 struct mat_cache *cache = pthread_getspecific(node->cache_key);
843 if(!cache) {
844 cache = malloc(sizeof *cache);
845 assert(cache);
847 pthread_mutex_lock(&node->cache_list_lock);
848 cache->next = node->cache_list;
849 node->cache_list = cache;
850 pthread_mutex_unlock(&node->cache_list_lock);
852 cache->time = ANM_TIME_INVAL;
853 cache->inv_time = ANM_TIME_INVAL;
854 pthread_setspecific(node->cache_key, cache);
855 }
857 if(cache->time != tm) {
858 anm_get_node_matrix(node, cache->matrix, tm);
860 if(node->parent) {
861 mat4_t parent_mat;
863 anm_get_matrix(node->parent, parent_mat, tm);
864 m4_mult(cache->matrix, parent_mat, cache->matrix);
865 }
866 cache->time = tm;
867 }
868 m4_copy(mat, cache->matrix);
869 }
871 void anm_get_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
872 {
873 struct mat_cache *cache = pthread_getspecific(node->cache_key);
874 if(!cache) {
875 cache = malloc(sizeof *cache);
876 assert(cache);
878 pthread_mutex_lock(&node->cache_list_lock);
879 cache->next = node->cache_list;
880 node->cache_list = cache;
881 pthread_mutex_unlock(&node->cache_list_lock);
883 cache->inv_time = ANM_TIME_INVAL;
884 cache->inv_time = ANM_TIME_INVAL;
885 pthread_setspecific(node->cache_key, cache);
886 }
888 if(cache->inv_time != tm) {
889 anm_get_matrix(node, mat, tm);
890 m4_inverse(cache->inv_matrix, mat);
891 cache->inv_time = tm;
892 }
893 m4_copy(mat, cache->inv_matrix);
894 }
896 anm_time_t anm_get_start_time(struct anm_node *node)
897 {
898 int i, j;
899 struct anm_node *c;
900 anm_time_t res = LONG_MAX;
902 for(j=0; j<2; j++) {
903 struct anm_animation *anim = anm_get_active_animation(node, j);
904 if(!anim) break;
906 for(i=0; i<ANM_NUM_TRACKS; i++) {
907 if(anim->tracks[i].count) {
908 anm_time_t tm = anim->tracks[i].keys[0].time;
909 if(tm < res) {
910 res = tm;
911 }
912 }
913 }
914 }
916 c = node->child;
917 while(c) {
918 anm_time_t tm = anm_get_start_time(c);
919 if(tm < res) {
920 res = tm;
921 }
922 c = c->next;
923 }
924 return res;
925 }
927 anm_time_t anm_get_end_time(struct anm_node *node)
928 {
929 int i, j;
930 struct anm_node *c;
931 anm_time_t res = LONG_MIN;
933 for(j=0; j<2; j++) {
934 struct anm_animation *anim = anm_get_active_animation(node, j);
935 if(!anim) break;
937 for(i=0; i<ANM_NUM_TRACKS; i++) {
938 if(anim->tracks[i].count) {
939 anm_time_t tm = anim->tracks[i].keys[anim->tracks[i].count - 1].time;
940 if(tm > res) {
941 res = tm;
942 }
943 }
944 }
945 }
947 c = node->child;
948 while(c) {
949 anm_time_t tm = anm_get_end_time(c);
950 if(tm > res) {
951 res = tm;
952 }
953 c = c->next;
954 }
955 return res;
956 }
958 static void invalidate_cache(struct anm_node *node)
959 {
960 struct anm_node *c;
961 struct mat_cache *cache = pthread_getspecific(node->cache_key);
962 if(cache) {
963 cache->time = cache->inv_time = ANM_TIME_INVAL;
964 }
966 c = node->child;
967 while(c) {
968 invalidate_cache(c);
969 c = c->next;
970 }
971 }