libanim

view src/anim.c @ 65:817a5c3a7f96

fixed a crashing bug in anm_destroy_node introduced when I added the multiple animations per node
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 23 Jan 2014 02:53:09 +0200
parents ebead35c9eb1
children 70ad14ba4df2
line source
1 #include <stdlib.h>
2 #include <limits.h>
3 #include <assert.h>
4 #include "anim.h"
5 #include "dynarr.h"
7 #define ROT_USE_SLERP
9 static void invalidate_cache(struct anm_node *node);
11 int anm_init_animation(struct anm_animation *anim)
12 {
13 int i, j;
14 static const float defaults[] = {
15 0.0f, 0.0f, 0.0f, /* default position */
16 0.0f, 0.0f, 0.0f, 1.0f, /* default rotation quat */
17 1.0f, 1.0f, 1.0f /* default scale factor */
18 };
20 anim->name = 0;
22 for(i=0; i<ANM_NUM_TRACKS; i++) {
23 if(anm_init_track(anim->tracks + i) == -1) {
24 for(j=0; j<i; j++) {
25 anm_destroy_track(anim->tracks + i);
26 }
27 }
28 anm_set_track_default(anim->tracks + i, defaults[i]);
29 }
30 return 0;
31 }
33 void anm_destroy_animation(struct anm_animation *anim)
34 {
35 int i;
36 for(i=0; i<ANM_NUM_TRACKS; i++) {
37 anm_destroy_track(anim->tracks + i);
38 }
39 free(anim->name);
40 }
42 void anm_set_animation_name(struct anm_animation *anim, const char *name)
43 {
44 char *newname = malloc(strlen(name) + 1);
45 if(!newname) return;
47 strcpy(newname, name);
49 free(anim->name);
50 anim->name = newname;
51 }
53 /* ---- node implementation ----- */
55 int anm_init_node(struct anm_node *node)
56 {
57 memset(node, 0, sizeof *node);
59 node->cur_anim[1] = -1;
61 if(!(node->animations = dynarr_alloc(1, sizeof *node->animations))) {
62 return -1;
63 }
64 if(anm_init_animation(node->animations) == -1) {
65 dynarr_free(node->animations);
66 return -1;
67 }
69 /* initialize thread-local matrix cache */
70 pthread_key_create(&node->cache_key, 0);
71 pthread_mutex_init(&node->cache_list_lock, 0);
73 return 0;
74 }
76 void anm_destroy_node(struct anm_node *node)
77 {
78 int i, num_anim;
79 free(node->name);
81 num_anim = anm_get_animation_count(node);
82 for(i=0; i<num_anim; i++) {
83 anm_destroy_animation(node->animations + i);
84 }
85 dynarr_free(node->animations);
87 /* destroy thread-specific cache */
88 pthread_key_delete(node->cache_key);
90 while(node->cache_list) {
91 struct mat_cache *tmp = node->cache_list;
92 node->cache_list = tmp->next;
93 free(tmp);
94 }
95 }
97 void anm_destroy_node_tree(struct anm_node *tree)
98 {
99 struct anm_node *c, *tmp;
101 if(!tree) return;
103 c = tree->child;
104 while(c) {
105 tmp = c;
106 c = c->next;
108 anm_destroy_node_tree(tmp);
109 }
110 anm_destroy_node(tree);
111 }
113 struct anm_node *anm_create_node(void)
114 {
115 struct anm_node *n;
117 if((n = malloc(sizeof *n))) {
118 if(anm_init_node(n) == -1) {
119 free(n);
120 return 0;
121 }
122 }
123 return n;
124 }
126 void anm_free_node(struct anm_node *node)
127 {
128 anm_destroy_node(node);
129 free(node);
130 }
132 void anm_free_node_tree(struct anm_node *tree)
133 {
134 struct anm_node *c, *tmp;
136 if(!tree) return;
138 c = tree->child;
139 while(c) {
140 tmp = c;
141 c = c->next;
143 anm_free_node_tree(tmp);
144 }
146 anm_free_node(tree);
147 }
149 int anm_set_node_name(struct anm_node *node, const char *name)
150 {
151 char *str;
153 if(!(str = malloc(strlen(name) + 1))) {
154 return -1;
155 }
156 strcpy(str, name);
157 free(node->name);
158 node->name = str;
159 return 0;
160 }
162 const char *anm_get_node_name(struct anm_node *node)
163 {
164 return node->name ? node->name : "";
165 }
167 void anm_link_node(struct anm_node *p, struct anm_node *c)
168 {
169 c->next = p->child;
170 p->child = c;
172 c->parent = p;
173 invalidate_cache(c);
174 }
176 int anm_unlink_node(struct anm_node *p, struct anm_node *c)
177 {
178 struct anm_node *iter;
180 if(p->child == c) {
181 p->child = c->next;
182 c->next = 0;
183 invalidate_cache(c);
184 return 0;
185 }
187 iter = p->child;
188 while(iter->next) {
189 if(iter->next == c) {
190 iter->next = c->next;
191 c->next = 0;
192 invalidate_cache(c);
193 return 0;
194 }
195 }
196 return -1;
197 }
199 void anm_set_pivot(struct anm_node *node, vec3_t piv)
200 {
201 node->pivot = piv;
202 }
204 vec3_t anm_get_pivot(struct anm_node *node)
205 {
206 return node->pivot;
207 }
210 /* animation management */
212 int anm_use_node_animation(struct anm_node *node, int aidx)
213 {
214 if(aidx == node->cur_anim[0] && node->cur_anim[1] == -1) {
215 return 0; /* no change, no invalidation */
216 }
218 if(aidx < 0 || aidx >= anm_get_animation_count(node)) {
219 return -1;
220 }
222 node->cur_anim[0] = aidx;
223 node->cur_anim[1] = -1;
224 node->cur_mix = 0;
225 node->blend_dur = -1;
227 invalidate_cache(node);
228 return 0;
229 }
231 int anm_use_node_animations(struct anm_node *node, int aidx, int bidx, float t)
232 {
233 int num_anim;
235 if(node->cur_anim[0] == aidx && node->cur_anim[1] == bidx &&
236 fabs(t - node->cur_mix) < 1e-6) {
237 return 0; /* no change, no invalidation */
238 }
240 num_anim = anm_get_animation_count(node);
241 if(aidx < 0 || aidx >= num_anim) {
242 return anm_use_animation(node, bidx);
243 }
244 if(bidx < 0 || bidx >= num_anim) {
245 return anm_use_animation(node, aidx);
246 }
247 node->cur_anim[0] = aidx;
248 node->cur_anim[1] = bidx;
249 node->cur_mix = t;
251 invalidate_cache(node);
252 return 0;
253 }
255 int anm_use_animation(struct anm_node *node, int aidx)
256 {
257 struct anm_node *child;
259 if(anm_use_node_animation(node, aidx) == -1) {
260 return -1;
261 }
263 child = node->child;
264 while(child) {
265 if(anm_use_animation(child, aidx) == -1) {
266 return -1;
267 }
268 child = child->next;
269 }
270 return 0;
271 }
273 int anm_use_animations(struct anm_node *node, int aidx, int bidx, float t)
274 {
275 struct anm_node *child;
277 if(anm_use_node_animations(node, aidx, bidx, t) == -1) {
278 return -1;
279 }
281 child = node->child;
282 while(child) {
283 if(anm_use_animations(child, aidx, bidx, t) == -1) {
284 return -1;
285 }
286 child = child->next;
287 }
288 return 0;
290 }
292 void anm_set_node_animation_offset(struct anm_node *node, anm_time_t offs, int which)
293 {
294 if(which < 0 || which >= 2) {
295 return;
296 }
297 node->cur_anim_offset[which] = offs;
298 }
300 anm_time_t anm_get_animation_offset(const struct anm_node *node, int which)
301 {
302 if(which < 0 || which >= 2) {
303 return 0;
304 }
305 return node->cur_anim_offset[which];
306 }
308 void anm_set_animation_offset(struct anm_node *node, anm_time_t offs, int which)
309 {
310 struct anm_node *c = node->child;
311 while(c) {
312 anm_set_animation_offset(c, offs, which);
313 c = c->next;
314 }
316 anm_set_node_animation_offset(node, offs, which);
317 }
319 int anm_get_active_animation_index(const struct anm_node *node, int which)
320 {
321 if(which < 0 || which >= 2) return -1;
322 return node->cur_anim[which];
323 }
325 struct anm_animation *anm_get_active_animation(const struct anm_node *node, int which)
326 {
327 int idx = anm_get_active_animation_index(node, which);
328 if(idx < 0 || idx >= anm_get_animation_count(node)) {
329 return 0;
330 }
331 return node->animations + idx;
332 }
334 float anm_get_active_animation_mix(const struct anm_node *node)
335 {
336 return node->cur_mix;
337 }
339 int anm_get_animation_count(const struct anm_node *node)
340 {
341 return dynarr_size(node->animations);
342 }
344 int anm_add_node_animation(struct anm_node *node)
345 {
346 struct anm_animation newanim;
347 anm_init_animation(&newanim);
349 node->animations = dynarr_push(node->animations, &newanim);
350 return 0;
351 }
353 int anm_remove_node_animation(struct anm_node *node, int idx)
354 {
355 fprintf(stderr, "anm_remove_animation: unimplemented!");
356 abort();
357 return 0;
358 }
360 int anm_add_animation(struct anm_node *node)
361 {
362 struct anm_node *child;
364 if(anm_add_node_animation(node) == -1) {
365 return -1;
366 }
368 child = node->child;
369 while(child) {
370 if(anm_add_animation(child)) {
371 return -1;
372 }
373 child = child->next;
374 }
375 return 0;
376 }
378 int anm_remove_animation(struct anm_node *node, int idx)
379 {
380 struct anm_node *child;
382 if(anm_remove_node_animation(node, idx) == -1) {
383 return -1;
384 }
386 child = node->child;
387 while(child) {
388 if(anm_remove_animation(child, idx) == -1) {
389 return -1;
390 }
391 child = child->next;
392 }
393 return 0;
394 }
396 struct anm_animation *anm_get_animation(struct anm_node *node, int idx)
397 {
398 if(idx < 0 || idx > anm_get_animation_count(node)) {
399 return 0;
400 }
401 return node->animations + idx;
402 }
404 struct anm_animation *anm_get_animation_by_name(struct anm_node *node, const char *name)
405 {
406 return anm_get_animation(node, anm_find_animation(node, name));
407 }
409 int anm_find_animation(struct anm_node *node, const char *name)
410 {
411 int i, count = anm_get_animation_count(node);
412 for(i=0; i<count; i++) {
413 if(strcmp(node->animations[i].name, name) == 0) {
414 return i;
415 }
416 }
417 return -1;
418 }
420 /* all the rest act on the current animation(s) */
422 void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in)
423 {
424 int i;
425 struct anm_animation *anim = anm_get_active_animation(node, 0);
426 if(!anim) return;
428 for(i=0; i<ANM_NUM_TRACKS; i++) {
429 anm_set_track_interpolator(anim->tracks + i, in);
430 }
431 invalidate_cache(node);
432 }
434 void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex)
435 {
436 int i;
437 struct anm_animation *anim = anm_get_active_animation(node, 0);
438 if(!anim) return;
440 for(i=0; i<ANM_NUM_TRACKS; i++) {
441 anm_set_track_extrapolator(anim->tracks + i, ex);
442 }
443 invalidate_cache(node);
444 }
446 void anm_set_node_active_animation_name(struct anm_node *node, const char *name)
447 {
448 struct anm_animation *anim = anm_get_active_animation(node, 0);
449 if(!anim) return;
451 anm_set_animation_name(anim, name);
452 }
454 void anm_set_active_animation_name(struct anm_node *node, const char *name)
455 {
456 struct anm_node *child;
458 anm_set_node_active_animation_name(node, name);
460 child = node->child;
461 while(child) {
462 anm_set_active_animation_name(child, name);
463 child = child->next;
464 }
465 }
467 const char *anm_get_active_animation_name(struct anm_node *node)
468 {
469 struct anm_animation *anim = anm_get_active_animation(node, 0);
470 if(anim) {
471 return anim->name;
472 }
473 return 0;
474 }
476 /* ---- high level animation blending ---- */
477 void anm_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur)
478 {
479 struct anm_node *c = node->child;
481 if(anmidx == node->cur_anim[0]) {
482 return;
483 }
485 while(c) {
486 anm_transition(c, anmidx, start, dur);
487 c = c->next;
488 }
490 anm_node_transition(node, anmidx, start, dur);
491 }
493 void anm_node_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur)
494 {
495 if(anmidx == node->cur_anim[0]) {
496 return;
497 }
499 node->cur_anim[1] = anmidx;
500 node->cur_anim_offset[1] = start;
501 node->blend_dur = dur;
502 }
505 #define BLEND_START_TM node->cur_anim_offset[1]
507 static anm_time_t animation_time(struct anm_node *node, anm_time_t tm, int which)
508 {
509 float t;
511 if(node->blend_dur >= 0) {
512 /* we're in transition... */
513 t = (float)(tm - BLEND_START_TM) / (float)node->blend_dur;
514 if(t < 0.0) t = 0.0;
516 node->cur_mix = t;
518 if(t > 1.0) {
519 /* switch completely over to the target animation and stop blending */
520 anm_use_node_animation(node, node->cur_anim[1]);
521 node->cur_anim_offset[0] = node->cur_anim_offset[1];
522 }
523 }
525 return tm - node->cur_anim_offset[which];
526 }
529 void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm)
530 {
531 struct anm_animation *anim = anm_get_active_animation(node, 0);
532 if(!anim) return;
534 anm_set_value(anim->tracks + ANM_TRACK_POS_X, tm, pos.x);
535 anm_set_value(anim->tracks + ANM_TRACK_POS_Y, tm, pos.y);
536 anm_set_value(anim->tracks + ANM_TRACK_POS_Z, tm, pos.z);
537 invalidate_cache(node);
538 }
541 vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm)
542 {
543 vec3_t v;
544 anm_time_t tm0 = animation_time(node, tm, 0);
545 struct anm_animation *anim0 = anm_get_active_animation(node, 0);
546 struct anm_animation *anim1 = anm_get_active_animation(node, 1);
548 if(!anim0) {
549 return v3_cons(0, 0, 0);
550 }
552 v.x = anm_get_value(anim0->tracks + ANM_TRACK_POS_X, tm0);
553 v.y = anm_get_value(anim0->tracks + ANM_TRACK_POS_Y, tm0);
554 v.z = anm_get_value(anim0->tracks + ANM_TRACK_POS_Z, tm0);
556 if(anim1) {
557 vec3_t v1;
558 anm_time_t tm1 = animation_time(node, tm, 1);
559 v1.x = anm_get_value(anim1->tracks + ANM_TRACK_POS_X, tm1);
560 v1.y = anm_get_value(anim1->tracks + ANM_TRACK_POS_Y, tm1);
561 v1.z = anm_get_value(anim1->tracks + ANM_TRACK_POS_Z, tm1);
563 v.x = v.x + (v1.x - v.x) * node->cur_mix;
564 v.y = v.y + (v1.y - v.y) * node->cur_mix;
565 v.z = v.z + (v1.z - v.z) * node->cur_mix;
566 }
568 return v;
569 }
571 void anm_set_rotation(struct anm_node *node, quat_t rot, anm_time_t tm)
572 {
573 struct anm_animation *anim = anm_get_active_animation(node, 0);
574 if(!anim) return;
576 anm_set_value(anim->tracks + ANM_TRACK_ROT_X, tm, rot.x);
577 anm_set_value(anim->tracks + ANM_TRACK_ROT_Y, tm, rot.y);
578 anm_set_value(anim->tracks + ANM_TRACK_ROT_Z, tm, rot.z);
579 anm_set_value(anim->tracks + ANM_TRACK_ROT_W, tm, rot.w);
580 invalidate_cache(node);
581 }
583 static quat_t get_node_rotation(struct anm_node *node, anm_time_t tm, struct anm_animation *anim)
584 {
585 #ifndef ROT_USE_SLERP
586 quat_t q;
587 q.x = anm_get_value(anim->tracks + ANM_TRACK_ROT_X, tm);
588 q.y = anm_get_value(anim->tracks + ANM_TRACK_ROT_Y, tm);
589 q.z = anm_get_value(anim->tracks + ANM_TRACK_ROT_Z, tm);
590 q.w = anm_get_value(anim->tracks + ANM_TRACK_ROT_W, tm);
591 return q;
592 #else
593 int idx0, idx1, last_idx;
594 anm_time_t tstart, tend;
595 float t, dt;
596 struct anm_track *track_x, *track_y, *track_z, *track_w;
597 quat_t q, q1, q2;
599 track_x = anim->tracks + ANM_TRACK_ROT_X;
600 track_y = anim->tracks + ANM_TRACK_ROT_Y;
601 track_z = anim->tracks + ANM_TRACK_ROT_Z;
602 track_w = anim->tracks + ANM_TRACK_ROT_W;
604 if(!track_x->count) {
605 q.x = track_x->def_val;
606 q.y = track_y->def_val;
607 q.z = track_z->def_val;
608 q.w = track_w->def_val;
609 return q;
610 }
612 last_idx = track_x->count - 1;
614 tstart = track_x->keys[0].time;
615 tend = track_x->keys[last_idx].time;
617 if(tstart == tend) {
618 q.x = track_x->keys[0].val;
619 q.y = track_y->keys[0].val;
620 q.z = track_z->keys[0].val;
621 q.w = track_w->keys[0].val;
622 return q;
623 }
625 tm = anm_remap_time(track_x, tm, tstart, tend);
627 idx0 = anm_get_key_interval(track_x, tm);
628 assert(idx0 >= 0 && idx0 < track_x->count);
629 idx1 = idx0 + 1;
631 if(idx0 == last_idx) {
632 q.x = track_x->keys[idx0].val;
633 q.y = track_y->keys[idx0].val;
634 q.z = track_z->keys[idx0].val;
635 q.w = track_w->keys[idx0].val;
636 return q;
637 }
639 dt = (float)(track_x->keys[idx1].time - track_x->keys[idx0].time);
640 t = (float)(tm - track_x->keys[idx0].time) / dt;
642 q1.x = track_x->keys[idx0].val;
643 q1.y = track_y->keys[idx0].val;
644 q1.z = track_z->keys[idx0].val;
645 q1.w = track_w->keys[idx0].val;
647 q2.x = track_x->keys[idx1].val;
648 q2.y = track_y->keys[idx1].val;
649 q2.z = track_z->keys[idx1].val;
650 q2.w = track_w->keys[idx1].val;
652 /*q1 = quat_normalize(q1);
653 q2 = quat_normalize(q2);*/
655 return quat_slerp(q1, q2, t);
656 #endif
657 }
659 quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm)
660 {
661 quat_t q;
662 anm_time_t tm0 = animation_time(node, tm, 0);
663 struct anm_animation *anim0 = anm_get_active_animation(node, 0);
664 struct anm_animation *anim1 = anm_get_active_animation(node, 1);
666 if(!anim0) {
667 return quat_identity();
668 }
670 q = get_node_rotation(node, tm0, anim0);
672 if(anim1) {
673 anm_time_t tm1 = animation_time(node, tm, 1);
674 quat_t q1 = get_node_rotation(node, tm1, anim1);
676 q = quat_slerp(q, q1, node->cur_mix);
677 }
678 return q;
679 }
681 void anm_set_scaling(struct anm_node *node, vec3_t scl, anm_time_t tm)
682 {
683 struct anm_animation *anim = anm_get_active_animation(node, 0);
684 if(!anim) return;
686 anm_set_value(anim->tracks + ANM_TRACK_SCL_X, tm, scl.x);
687 anm_set_value(anim->tracks + ANM_TRACK_SCL_Y, tm, scl.y);
688 anm_set_value(anim->tracks + ANM_TRACK_SCL_Z, tm, scl.z);
689 invalidate_cache(node);
690 }
692 vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm)
693 {
694 vec3_t v;
695 anm_time_t tm0 = animation_time(node, tm, 0);
696 struct anm_animation *anim0 = anm_get_active_animation(node, 0);
697 struct anm_animation *anim1 = anm_get_active_animation(node, 1);
699 if(!anim0) {
700 return v3_cons(1, 1, 1);
701 }
703 v.x = anm_get_value(anim0->tracks + ANM_TRACK_SCL_X, tm0);
704 v.y = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Y, tm0);
705 v.z = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Z, tm0);
707 if(anim1) {
708 vec3_t v1;
709 anm_time_t tm1 = animation_time(node, tm, 1);
710 v1.x = anm_get_value(anim1->tracks + ANM_TRACK_SCL_X, tm1);
711 v1.y = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Y, tm1);
712 v1.z = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Z, tm1);
714 v.x = v.x + (v1.x - v.x) * node->cur_mix;
715 v.y = v.y + (v1.y - v.y) * node->cur_mix;
716 v.z = v.z + (v1.z - v.z) * node->cur_mix;
717 }
719 return v;
720 }
723 vec3_t anm_get_position(struct anm_node *node, anm_time_t tm)
724 {
725 mat4_t xform;
726 vec3_t pos = {0.0, 0.0, 0.0};
728 if(!node->parent) {
729 return anm_get_node_position(node, tm);
730 }
732 anm_get_matrix(node, xform, tm);
733 return v3_transform(pos, xform);
734 }
736 quat_t anm_get_rotation(struct anm_node *node, anm_time_t tm)
737 {
738 quat_t rot, prot;
739 rot = anm_get_node_rotation(node, tm);
741 if(!node->parent) {
742 return rot;
743 }
745 prot = anm_get_rotation(node->parent, tm);
746 return quat_mul(prot, rot);
747 }
749 vec3_t anm_get_scaling(struct anm_node *node, anm_time_t tm)
750 {
751 vec3_t s, ps;
752 s = anm_get_node_scaling(node, tm);
754 if(!node->parent) {
755 return s;
756 }
758 ps = anm_get_scaling(node->parent, tm);
759 return v3_mul(s, ps);
760 }
762 void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
763 {
764 int i;
765 mat4_t rmat;
766 vec3_t pos, scale;
767 quat_t rot;
769 pos = anm_get_node_position(node, tm);
770 rot = anm_get_node_rotation(node, tm);
771 scale = anm_get_node_scaling(node, tm);
773 m4_set_translation(mat, node->pivot.x, node->pivot.y, node->pivot.z);
775 quat_to_mat4(rmat, rot);
776 for(i=0; i<3; i++) {
777 mat[i][0] = rmat[i][0];
778 mat[i][1] = rmat[i][1];
779 mat[i][2] = rmat[i][2];
780 }
781 /* this loop is equivalent to: m4_mult(mat, mat, rmat); */
783 mat[0][0] *= scale.x; mat[0][1] *= scale.y; mat[0][2] *= scale.z; mat[0][3] += pos.x;
784 mat[1][0] *= scale.x; mat[1][1] *= scale.y; mat[1][2] *= scale.z; mat[1][3] += pos.y;
785 mat[2][0] *= scale.x; mat[2][1] *= scale.y; mat[2][2] *= scale.z; mat[2][3] += pos.z;
787 m4_translate(mat, -node->pivot.x, -node->pivot.y, -node->pivot.z);
789 /* that's basically: pivot * rotation * translation * scaling * -pivot */
790 }
792 void anm_get_node_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
793 {
794 mat4_t tmp;
795 anm_get_node_matrix(node, tmp, tm);
796 m4_inverse(mat, tmp);
797 }
799 void anm_eval_node(struct anm_node *node, anm_time_t tm)
800 {
801 anm_get_node_matrix(node, node->matrix, tm);
802 }
804 void anm_eval(struct anm_node *node, anm_time_t tm)
805 {
806 struct anm_node *c;
808 anm_eval_node(node, tm);
810 if(node->parent) {
811 /* due to post-order traversal, the parent matrix is already evaluated */
812 m4_mult(node->matrix, node->parent->matrix, node->matrix);
813 }
815 /* recersively evaluate all children */
816 c = node->child;
817 while(c) {
818 anm_eval(c, tm);
819 c = c->next;
820 }
821 }
823 void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
824 {
825 struct mat_cache *cache = pthread_getspecific(node->cache_key);
826 if(!cache) {
827 cache = malloc(sizeof *cache);
828 assert(cache);
830 pthread_mutex_lock(&node->cache_list_lock);
831 cache->next = node->cache_list;
832 node->cache_list = cache;
833 pthread_mutex_unlock(&node->cache_list_lock);
835 cache->time = ANM_TIME_INVAL;
836 cache->inv_time = ANM_TIME_INVAL;
837 pthread_setspecific(node->cache_key, cache);
838 }
840 if(cache->time != tm) {
841 anm_get_node_matrix(node, cache->matrix, tm);
843 if(node->parent) {
844 mat4_t parent_mat;
846 anm_get_matrix(node->parent, parent_mat, tm);
847 m4_mult(cache->matrix, parent_mat, cache->matrix);
848 }
849 cache->time = tm;
850 }
851 m4_copy(mat, cache->matrix);
852 }
854 void anm_get_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
855 {
856 struct mat_cache *cache = pthread_getspecific(node->cache_key);
857 if(!cache) {
858 cache = malloc(sizeof *cache);
859 assert(cache);
861 pthread_mutex_lock(&node->cache_list_lock);
862 cache->next = node->cache_list;
863 node->cache_list = cache;
864 pthread_mutex_unlock(&node->cache_list_lock);
866 cache->inv_time = ANM_TIME_INVAL;
867 cache->inv_time = ANM_TIME_INVAL;
868 pthread_setspecific(node->cache_key, cache);
869 }
871 if(cache->inv_time != tm) {
872 anm_get_matrix(node, mat, tm);
873 m4_inverse(cache->inv_matrix, mat);
874 cache->inv_time = tm;
875 }
876 m4_copy(mat, cache->inv_matrix);
877 }
879 anm_time_t anm_get_start_time(struct anm_node *node)
880 {
881 int i, j;
882 struct anm_node *c;
883 anm_time_t res = LONG_MAX;
885 for(j=0; j<2; j++) {
886 struct anm_animation *anim = anm_get_active_animation(node, j);
887 if(!anim) break;
889 for(i=0; i<ANM_NUM_TRACKS; i++) {
890 if(anim->tracks[i].count) {
891 anm_time_t tm = anim->tracks[i].keys[0].time;
892 if(tm < res) {
893 res = tm;
894 }
895 }
896 }
897 }
899 c = node->child;
900 while(c) {
901 anm_time_t tm = anm_get_start_time(c);
902 if(tm < res) {
903 res = tm;
904 }
905 c = c->next;
906 }
907 return res;
908 }
910 anm_time_t anm_get_end_time(struct anm_node *node)
911 {
912 int i, j;
913 struct anm_node *c;
914 anm_time_t res = LONG_MIN;
916 for(j=0; j<2; j++) {
917 struct anm_animation *anim = anm_get_active_animation(node, j);
918 if(!anim) break;
920 for(i=0; i<ANM_NUM_TRACKS; i++) {
921 if(anim->tracks[i].count) {
922 anm_time_t tm = anim->tracks[i].keys[anim->tracks[i].count - 1].time;
923 if(tm > res) {
924 res = tm;
925 }
926 }
927 }
928 }
930 c = node->child;
931 while(c) {
932 anm_time_t tm = anm_get_end_time(c);
933 if(tm > res) {
934 res = tm;
935 }
936 c = c->next;
937 }
938 return res;
939 }
941 static void invalidate_cache(struct anm_node *node)
942 {
943 struct mat_cache *cache = pthread_getspecific(node->cache_key);
944 if(cache) {
945 cache->time = cache->inv_time = ANM_TIME_INVAL;
946 }
947 }