libanim
view src/anim.c @ 63:091dd6e6be59
added README file
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 17 Apr 2014 07:51:18 +0300 |
parents | 09e267e7ed4a |
children | b52f3e23e06f 60a46a122b0f |
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;
79 free(node->name);
81 for(i=0; i<ANM_NUM_TRACKS; i++) {
82 anm_destroy_animation(node->animations + i);
83 }
84 dynarr_free(node->animations);
86 /* destroy thread-specific cache */
87 pthread_key_delete(node->cache_key);
89 while(node->cache_list) {
90 struct mat_cache *tmp = node->cache_list;
91 node->cache_list = tmp->next;
92 free(tmp);
93 }
94 }
96 void anm_destroy_node_tree(struct anm_node *tree)
97 {
98 struct anm_node *c, *tmp;
100 if(!tree) return;
102 c = tree->child;
103 while(c) {
104 tmp = c;
105 c = c->next;
107 anm_destroy_node_tree(tmp);
108 }
109 anm_destroy_node(tree);
110 }
112 struct anm_node *anm_create_node(void)
113 {
114 struct anm_node *n;
116 if((n = malloc(sizeof *n))) {
117 if(anm_init_node(n) == -1) {
118 free(n);
119 return 0;
120 }
121 }
122 return n;
123 }
125 void anm_free_node(struct anm_node *node)
126 {
127 anm_destroy_node(node);
128 free(node);
129 }
131 void anm_free_node_tree(struct anm_node *tree)
132 {
133 struct anm_node *c, *tmp;
135 if(!tree) return;
137 c = tree->child;
138 while(c) {
139 tmp = c;
140 c = c->next;
142 anm_free_node_tree(tmp);
143 }
145 anm_free_node(tree);
146 }
148 int anm_set_node_name(struct anm_node *node, const char *name)
149 {
150 char *str;
152 if(!(str = malloc(strlen(name) + 1))) {
153 return -1;
154 }
155 strcpy(str, name);
156 free(node->name);
157 node->name = str;
158 return 0;
159 }
161 const char *anm_get_node_name(struct anm_node *node)
162 {
163 return node->name ? node->name : "";
164 }
166 void anm_link_node(struct anm_node *p, struct anm_node *c)
167 {
168 c->next = p->child;
169 p->child = c;
171 c->parent = p;
172 invalidate_cache(c);
173 }
175 int anm_unlink_node(struct anm_node *p, struct anm_node *c)
176 {
177 struct anm_node *iter;
179 if(p->child == c) {
180 p->child = c->next;
181 c->next = 0;
182 invalidate_cache(c);
183 return 0;
184 }
186 iter = p->child;
187 while(iter->next) {
188 if(iter->next == c) {
189 iter->next = c->next;
190 c->next = 0;
191 invalidate_cache(c);
192 return 0;
193 }
194 }
195 return -1;
196 }
198 void anm_set_pivot(struct anm_node *node, vec3_t piv)
199 {
200 node->pivot = piv;
201 }
203 vec3_t anm_get_pivot(struct anm_node *node)
204 {
205 return node->pivot;
206 }
209 /* animation management */
211 int anm_use_node_animation(struct anm_node *node, int aidx)
212 {
213 if(aidx == node->cur_anim[0] && node->cur_anim[1] == -1) {
214 return 0; /* no change, no invalidation */
215 }
217 if(aidx < 0 || aidx >= anm_get_animation_count(node)) {
218 return -1;
219 }
221 node->cur_anim[0] = aidx;
222 node->cur_anim[1] = -1;
223 node->cur_mix = 0;
224 node->blend_dur = -1;
226 invalidate_cache(node);
227 return 0;
228 }
230 int anm_use_node_animations(struct anm_node *node, int aidx, int bidx, float t)
231 {
232 int num_anim;
234 if(node->cur_anim[0] == aidx && node->cur_anim[1] == bidx &&
235 fabs(t - node->cur_mix) < 1e-6) {
236 return 0; /* no change, no invalidation */
237 }
239 num_anim = anm_get_animation_count(node);
240 if(aidx < 0 || aidx >= num_anim) {
241 return anm_use_animation(node, bidx);
242 }
243 if(bidx < 0 || bidx >= num_anim) {
244 return anm_use_animation(node, aidx);
245 }
246 node->cur_anim[0] = aidx;
247 node->cur_anim[1] = bidx;
248 node->cur_mix = t;
250 invalidate_cache(node);
251 return 0;
252 }
254 int anm_use_animation(struct anm_node *node, int aidx)
255 {
256 struct anm_node *child;
258 if(anm_use_node_animation(node, aidx) == -1) {
259 return -1;
260 }
262 child = node->child;
263 while(child) {
264 if(anm_use_animation(child, aidx) == -1) {
265 return -1;
266 }
267 child = child->next;
268 }
269 return 0;
270 }
272 int anm_use_animations(struct anm_node *node, int aidx, int bidx, float t)
273 {
274 struct anm_node *child;
276 if(anm_use_node_animations(node, aidx, bidx, t) == -1) {
277 return -1;
278 }
280 child = node->child;
281 while(child) {
282 if(anm_use_animations(child, aidx, bidx, t) == -1) {
283 return -1;
284 }
285 child = child->next;
286 }
287 return 0;
289 }
291 void anm_set_node_animation_offset(struct anm_node *node, anm_time_t offs, int which)
292 {
293 if(which < 0 || which >= 2) {
294 return;
295 }
296 node->cur_anim_offset[which] = offs;
297 }
299 anm_time_t anm_get_animation_offset(const struct anm_node *node, int which)
300 {
301 if(which < 0 || which >= 2) {
302 return 0;
303 }
304 return node->cur_anim_offset[which];
305 }
307 void anm_set_animation_offset(struct anm_node *node, anm_time_t offs, int which)
308 {
309 struct anm_node *c = node->child;
310 while(c) {
311 anm_set_animation_offset(c, offs, which);
312 c = c->next;
313 }
315 anm_set_node_animation_offset(node, offs, which);
316 }
318 int anm_get_active_animation_index(const struct anm_node *node, int which)
319 {
320 if(which < 0 || which >= 2) return -1;
321 return node->cur_anim[which];
322 }
324 struct anm_animation *anm_get_active_animation(const struct anm_node *node, int which)
325 {
326 int idx = anm_get_active_animation_index(node, which);
327 if(idx < 0 || idx >= anm_get_animation_count(node)) {
328 return 0;
329 }
330 return node->animations + idx;
331 }
333 float anm_get_active_animation_mix(const struct anm_node *node)
334 {
335 return node->cur_mix;
336 }
338 int anm_get_animation_count(const struct anm_node *node)
339 {
340 return dynarr_size(node->animations);
341 }
343 int anm_add_node_animation(struct anm_node *node)
344 {
345 struct anm_animation newanim;
346 anm_init_animation(&newanim);
348 node->animations = dynarr_push(node->animations, &newanim);
349 return 0;
350 }
352 int anm_remove_node_animation(struct anm_node *node, int idx)
353 {
354 fprintf(stderr, "anm_remove_animation: unimplemented!");
355 abort();
356 return 0;
357 }
359 int anm_add_animation(struct anm_node *node)
360 {
361 struct anm_node *child;
363 if(anm_add_node_animation(node) == -1) {
364 return -1;
365 }
367 child = node->child;
368 while(child) {
369 if(anm_add_animation(child)) {
370 return -1;
371 }
372 child = child->next;
373 }
374 return 0;
375 }
377 int anm_remove_animation(struct anm_node *node, int idx)
378 {
379 struct anm_node *child;
381 if(anm_remove_node_animation(node, idx) == -1) {
382 return -1;
383 }
385 child = node->child;
386 while(child) {
387 if(anm_remove_animation(child, idx) == -1) {
388 return -1;
389 }
390 child = child->next;
391 }
392 return 0;
393 }
395 struct anm_animation *anm_get_animation(struct anm_node *node, int idx)
396 {
397 if(idx < 0 || idx > anm_get_animation_count(node)) {
398 return 0;
399 }
400 return node->animations + idx;
401 }
403 struct anm_animation *anm_get_animation_by_name(struct anm_node *node, const char *name)
404 {
405 return anm_get_animation(node, anm_find_animation(node, name));
406 }
408 int anm_find_animation(struct anm_node *node, const char *name)
409 {
410 int i, count = anm_get_animation_count(node);
411 for(i=0; i<count; i++) {
412 if(strcmp(node->animations[i].name, name) == 0) {
413 return i;
414 }
415 }
416 return -1;
417 }
419 /* all the rest act on the current animation(s) */
421 void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in)
422 {
423 int i;
424 struct anm_animation *anim = anm_get_active_animation(node, 0);
425 if(!anim) return;
427 for(i=0; i<ANM_NUM_TRACKS; i++) {
428 anm_set_track_interpolator(anim->tracks + i, in);
429 }
430 invalidate_cache(node);
431 }
433 void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex)
434 {
435 int i;
436 struct anm_animation *anim = anm_get_active_animation(node, 0);
437 if(!anim) return;
439 for(i=0; i<ANM_NUM_TRACKS; i++) {
440 anm_set_track_extrapolator(anim->tracks + i, ex);
441 }
442 invalidate_cache(node);
443 }
445 void anm_set_node_active_animation_name(struct anm_node *node, const char *name)
446 {
447 struct anm_animation *anim = anm_get_active_animation(node, 0);
448 if(!anim) return;
450 anm_set_animation_name(anim, name);
451 }
453 void anm_set_active_animation_name(struct anm_node *node, const char *name)
454 {
455 struct anm_node *child;
457 anm_set_node_active_animation_name(node, name);
459 child = node->child;
460 while(child) {
461 anm_set_active_animation_name(child, name);
462 child = child->next;
463 }
464 }
466 const char *anm_get_active_animation_name(struct anm_node *node)
467 {
468 struct anm_animation *anim = anm_get_active_animation(node, 0);
469 if(anim) {
470 return anim->name;
471 }
472 return 0;
473 }
475 /* ---- high level animation blending ---- */
476 void anm_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur)
477 {
478 struct anm_node *c = node->child;
480 if(anmidx == node->cur_anim[0]) {
481 return;
482 }
484 while(c) {
485 anm_transition(c, anmidx, start, dur);
486 c = c->next;
487 }
489 anm_node_transition(node, anmidx, start, dur);
490 }
492 void anm_node_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur)
493 {
494 if(anmidx == node->cur_anim[0]) {
495 return;
496 }
498 node->cur_anim[1] = anmidx;
499 node->cur_anim_offset[1] = start;
500 node->blend_dur = dur;
501 }
504 #define BLEND_START_TM node->cur_anim_offset[1]
506 static anm_time_t animation_time(struct anm_node *node, anm_time_t tm, int which)
507 {
508 float t;
510 if(node->blend_dur >= 0) {
511 /* we're in transition... */
512 t = (float)(tm - BLEND_START_TM) / (float)node->blend_dur;
513 if(t < 0.0) t = 0.0;
515 node->cur_mix = t;
517 if(t > 1.0) {
518 /* switch completely over to the target animation and stop blending */
519 anm_use_node_animation(node, node->cur_anim[1]);
520 node->cur_anim_offset[0] = node->cur_anim_offset[1];
521 }
522 }
524 return tm - node->cur_anim_offset[which];
525 }
528 void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm)
529 {
530 struct anm_animation *anim = anm_get_active_animation(node, 0);
531 if(!anim) return;
533 anm_set_value(anim->tracks + ANM_TRACK_POS_X, tm, pos.x);
534 anm_set_value(anim->tracks + ANM_TRACK_POS_Y, tm, pos.y);
535 anm_set_value(anim->tracks + ANM_TRACK_POS_Z, tm, pos.z);
536 invalidate_cache(node);
537 }
540 vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm)
541 {
542 vec3_t v;
543 anm_time_t tm0 = animation_time(node, tm, 0);
544 struct anm_animation *anim0 = anm_get_active_animation(node, 0);
545 struct anm_animation *anim1 = anm_get_active_animation(node, 1);
547 if(!anim0) {
548 return v3_cons(0, 0, 0);
549 }
551 v.x = anm_get_value(anim0->tracks + ANM_TRACK_POS_X, tm0);
552 v.y = anm_get_value(anim0->tracks + ANM_TRACK_POS_Y, tm0);
553 v.z = anm_get_value(anim0->tracks + ANM_TRACK_POS_Z, tm0);
555 if(anim1) {
556 vec3_t v1;
557 anm_time_t tm1 = animation_time(node, tm, 1);
558 v1.x = anm_get_value(anim1->tracks + ANM_TRACK_POS_X, tm1);
559 v1.y = anm_get_value(anim1->tracks + ANM_TRACK_POS_Y, tm1);
560 v1.z = anm_get_value(anim1->tracks + ANM_TRACK_POS_Z, tm1);
562 v.x = v.x + (v1.x - v.x) * node->cur_mix;
563 v.y = v.y + (v1.y - v.y) * node->cur_mix;
564 v.z = v.z + (v1.z - v.z) * node->cur_mix;
565 }
567 return v;
568 }
570 void anm_set_rotation(struct anm_node *node, quat_t rot, anm_time_t tm)
571 {
572 struct anm_animation *anim = anm_get_active_animation(node, 0);
573 if(!anim) return;
575 anm_set_value(anim->tracks + ANM_TRACK_ROT_X, tm, rot.x);
576 anm_set_value(anim->tracks + ANM_TRACK_ROT_Y, tm, rot.y);
577 anm_set_value(anim->tracks + ANM_TRACK_ROT_Z, tm, rot.z);
578 anm_set_value(anim->tracks + ANM_TRACK_ROT_W, tm, rot.w);
579 invalidate_cache(node);
580 }
582 static quat_t get_node_rotation(struct anm_node *node, anm_time_t tm, struct anm_animation *anim)
583 {
584 #ifndef ROT_USE_SLERP
585 quat_t q;
586 q.x = anm_get_value(anim->tracks + ANM_TRACK_ROT_X, tm);
587 q.y = anm_get_value(anim->tracks + ANM_TRACK_ROT_Y, tm);
588 q.z = anm_get_value(anim->tracks + ANM_TRACK_ROT_Z, tm);
589 q.w = anm_get_value(anim->tracks + ANM_TRACK_ROT_W, tm);
590 return q;
591 #else
592 int idx0, idx1, last_idx;
593 anm_time_t tstart, tend;
594 float t, dt;
595 struct anm_track *track_x, *track_y, *track_z, *track_w;
596 quat_t q, q1, q2;
598 track_x = anim->tracks + ANM_TRACK_ROT_X;
599 track_y = anim->tracks + ANM_TRACK_ROT_Y;
600 track_z = anim->tracks + ANM_TRACK_ROT_Z;
601 track_w = anim->tracks + ANM_TRACK_ROT_W;
603 if(!track_x->count) {
604 q.x = track_x->def_val;
605 q.y = track_y->def_val;
606 q.z = track_z->def_val;
607 q.w = track_w->def_val;
608 return q;
609 }
611 last_idx = track_x->count - 1;
613 tstart = track_x->keys[0].time;
614 tend = track_x->keys[last_idx].time;
616 if(tstart == tend) {
617 q.x = track_x->keys[0].val;
618 q.y = track_y->keys[0].val;
619 q.z = track_z->keys[0].val;
620 q.w = track_w->keys[0].val;
621 return q;
622 }
624 tm = anm_remap_time(track_x, tm, tstart, tend);
626 idx0 = anm_get_key_interval(track_x, tm);
627 assert(idx0 >= 0 && idx0 < track_x->count);
628 idx1 = idx0 + 1;
630 if(idx0 == last_idx) {
631 q.x = track_x->keys[idx0].val;
632 q.y = track_y->keys[idx0].val;
633 q.z = track_z->keys[idx0].val;
634 q.w = track_w->keys[idx0].val;
635 return q;
636 }
638 dt = (float)(track_x->keys[idx1].time - track_x->keys[idx0].time);
639 t = (float)(tm - track_x->keys[idx0].time) / dt;
641 q1.x = track_x->keys[idx0].val;
642 q1.y = track_y->keys[idx0].val;
643 q1.z = track_z->keys[idx0].val;
644 q1.w = track_w->keys[idx0].val;
646 q2.x = track_x->keys[idx1].val;
647 q2.y = track_y->keys[idx1].val;
648 q2.z = track_z->keys[idx1].val;
649 q2.w = track_w->keys[idx1].val;
651 /*q1 = quat_normalize(q1);
652 q2 = quat_normalize(q2);*/
654 return quat_slerp(q1, q2, t);
655 #endif
656 }
658 quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm)
659 {
660 quat_t q;
661 anm_time_t tm0 = animation_time(node, tm, 0);
662 struct anm_animation *anim0 = anm_get_active_animation(node, 0);
663 struct anm_animation *anim1 = anm_get_active_animation(node, 1);
665 if(!anim0) {
666 return quat_identity();
667 }
669 q = get_node_rotation(node, tm0, anim0);
671 if(anim1) {
672 anm_time_t tm1 = animation_time(node, tm, 1);
673 quat_t q1 = get_node_rotation(node, tm1, anim1);
675 q = quat_slerp(q, q1, node->cur_mix);
676 }
677 return q;
678 }
680 void anm_set_scaling(struct anm_node *node, vec3_t scl, anm_time_t tm)
681 {
682 struct anm_animation *anim = anm_get_active_animation(node, 0);
683 if(!anim) return;
685 anm_set_value(anim->tracks + ANM_TRACK_SCL_X, tm, scl.x);
686 anm_set_value(anim->tracks + ANM_TRACK_SCL_Y, tm, scl.y);
687 anm_set_value(anim->tracks + ANM_TRACK_SCL_Z, tm, scl.z);
688 invalidate_cache(node);
689 }
691 vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm)
692 {
693 vec3_t v;
694 anm_time_t tm0 = animation_time(node, tm, 0);
695 struct anm_animation *anim0 = anm_get_active_animation(node, 0);
696 struct anm_animation *anim1 = anm_get_active_animation(node, 1);
698 if(!anim0) {
699 return v3_cons(1, 1, 1);
700 }
702 v.x = anm_get_value(anim0->tracks + ANM_TRACK_SCL_X, tm0);
703 v.y = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Y, tm0);
704 v.z = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Z, tm0);
706 if(anim1) {
707 vec3_t v1;
708 anm_time_t tm1 = animation_time(node, tm, 1);
709 v1.x = anm_get_value(anim1->tracks + ANM_TRACK_SCL_X, tm1);
710 v1.y = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Y, tm1);
711 v1.z = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Z, tm1);
713 v.x = v.x + (v1.x - v.x) * node->cur_mix;
714 v.y = v.y + (v1.y - v.y) * node->cur_mix;
715 v.z = v.z + (v1.z - v.z) * node->cur_mix;
716 }
718 return v;
719 }
722 vec3_t anm_get_position(struct anm_node *node, anm_time_t tm)
723 {
724 mat4_t xform;
725 vec3_t pos = {0.0, 0.0, 0.0};
727 if(!node->parent) {
728 return anm_get_node_position(node, tm);
729 }
731 anm_get_matrix(node, xform, tm);
732 return v3_transform(pos, xform);
733 }
735 quat_t anm_get_rotation(struct anm_node *node, anm_time_t tm)
736 {
737 quat_t rot, prot;
738 rot = anm_get_node_rotation(node, tm);
740 if(!node->parent) {
741 return rot;
742 }
744 prot = anm_get_rotation(node->parent, tm);
745 return quat_mul(prot, rot);
746 }
748 vec3_t anm_get_scaling(struct anm_node *node, anm_time_t tm)
749 {
750 vec3_t s, ps;
751 s = anm_get_node_scaling(node, tm);
753 if(!node->parent) {
754 return s;
755 }
757 ps = anm_get_scaling(node->parent, tm);
758 return v3_mul(s, ps);
759 }
761 void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
762 {
763 int i;
764 mat4_t rmat;
765 vec3_t pos, scale;
766 quat_t rot;
768 pos = anm_get_node_position(node, tm);
769 rot = anm_get_node_rotation(node, tm);
770 scale = anm_get_node_scaling(node, tm);
772 m4_set_translation(mat, node->pivot.x, node->pivot.y, node->pivot.z);
774 quat_to_mat4(rmat, rot);
775 for(i=0; i<3; i++) {
776 mat[i][0] = rmat[i][0];
777 mat[i][1] = rmat[i][1];
778 mat[i][2] = rmat[i][2];
779 }
780 /* this loop is equivalent to: m4_mult(mat, mat, rmat); */
782 mat[0][0] *= scale.x; mat[0][1] *= scale.y; mat[0][2] *= scale.z; mat[0][3] += pos.x;
783 mat[1][0] *= scale.x; mat[1][1] *= scale.y; mat[1][2] *= scale.z; mat[1][3] += pos.y;
784 mat[2][0] *= scale.x; mat[2][1] *= scale.y; mat[2][2] *= scale.z; mat[2][3] += pos.z;
786 m4_translate(mat, -node->pivot.x, -node->pivot.y, -node->pivot.z);
788 /* that's basically: pivot * rotation * translation * scaling * -pivot */
789 }
791 void anm_get_node_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
792 {
793 mat4_t tmp;
794 anm_get_node_matrix(node, tmp, tm);
795 m4_inverse(mat, tmp);
796 }
798 void anm_eval_node(struct anm_node *node, anm_time_t tm)
799 {
800 anm_get_node_matrix(node, node->matrix, tm);
801 }
803 void anm_eval(struct anm_node *node, anm_time_t tm)
804 {
805 struct anm_node *c;
807 anm_eval_node(node, tm);
809 if(node->parent) {
810 /* due to post-order traversal, the parent matrix is already evaluated */
811 m4_mult(node->matrix, node->parent->matrix, node->matrix);
812 }
814 /* recersively evaluate all children */
815 c = node->child;
816 while(c) {
817 anm_eval(c, tm);
818 c = c->next;
819 }
820 }
822 void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
823 {
824 struct mat_cache *cache = pthread_getspecific(node->cache_key);
825 if(!cache) {
826 cache = malloc(sizeof *cache);
827 assert(cache);
829 pthread_mutex_lock(&node->cache_list_lock);
830 cache->next = node->cache_list;
831 node->cache_list = cache;
832 pthread_mutex_unlock(&node->cache_list_lock);
834 cache->time = ANM_TIME_INVAL;
835 cache->inv_time = ANM_TIME_INVAL;
836 pthread_setspecific(node->cache_key, cache);
837 }
839 if(cache->time != tm) {
840 anm_get_node_matrix(node, cache->matrix, tm);
842 if(node->parent) {
843 mat4_t parent_mat;
845 anm_get_matrix(node->parent, parent_mat, tm);
846 m4_mult(cache->matrix, parent_mat, cache->matrix);
847 }
848 cache->time = tm;
849 }
850 m4_copy(mat, cache->matrix);
851 }
853 void anm_get_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
854 {
855 struct mat_cache *cache = pthread_getspecific(node->cache_key);
856 if(!cache) {
857 cache = malloc(sizeof *cache);
858 assert(cache);
860 pthread_mutex_lock(&node->cache_list_lock);
861 cache->next = node->cache_list;
862 node->cache_list = cache;
863 pthread_mutex_unlock(&node->cache_list_lock);
865 cache->inv_time = ANM_TIME_INVAL;
866 cache->inv_time = ANM_TIME_INVAL;
867 pthread_setspecific(node->cache_key, cache);
868 }
870 if(cache->inv_time != tm) {
871 anm_get_matrix(node, mat, tm);
872 m4_inverse(cache->inv_matrix, mat);
873 cache->inv_time = tm;
874 }
875 m4_copy(mat, cache->inv_matrix);
876 }
878 anm_time_t anm_get_start_time(struct anm_node *node)
879 {
880 int i, j;
881 struct anm_node *c;
882 anm_time_t res = LONG_MAX;
884 for(j=0; j<2; j++) {
885 struct anm_animation *anim = anm_get_active_animation(node, j);
886 if(!anim) break;
888 for(i=0; i<ANM_NUM_TRACKS; i++) {
889 if(anim->tracks[i].count) {
890 anm_time_t tm = anim->tracks[i].keys[0].time;
891 if(tm < res) {
892 res = tm;
893 }
894 }
895 }
896 }
898 c = node->child;
899 while(c) {
900 anm_time_t tm = anm_get_start_time(c);
901 if(tm < res) {
902 res = tm;
903 }
904 c = c->next;
905 }
906 return res;
907 }
909 anm_time_t anm_get_end_time(struct anm_node *node)
910 {
911 int i, j;
912 struct anm_node *c;
913 anm_time_t res = LONG_MIN;
915 for(j=0; j<2; j++) {
916 struct anm_animation *anim = anm_get_active_animation(node, j);
917 if(!anim) break;
919 for(i=0; i<ANM_NUM_TRACKS; i++) {
920 if(anim->tracks[i].count) {
921 anm_time_t tm = anim->tracks[i].keys[anim->tracks[i].count - 1].time;
922 if(tm > res) {
923 res = tm;
924 }
925 }
926 }
927 }
929 c = node->child;
930 while(c) {
931 anm_time_t tm = anm_get_end_time(c);
932 if(tm > res) {
933 res = tm;
934 }
935 c = c->next;
936 }
937 return res;
938 }
940 static void invalidate_cache(struct anm_node *node)
941 {
942 struct mat_cache *cache = pthread_getspecific(node->cache_key);
943 if(cache) {
944 cache->time = cache->inv_time = ANM_TIME_INVAL;
945 }
946 }