backport builds
[dosdemo] / libs / anim / src / anim.c
1 /*
2 libanim - hierarchical keyframe animation library
3 Copyright (C) 2012-2018 John Tsiombikas <nuclear@member.fsf.org>
4
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.
9
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.
14
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 <stdio.h>
19 #include <stdlib.h>
20 #include <limits.h>
21 #include <assert.h>
22 #include "anim.h"
23 #include "dynarr.h"
24
25 #include "cgmath/cgmath.h"
26
27 #define ROT_USE_SLERP
28
29 static void invalidate_cache(struct anm_node *node);
30
31 int anm_init_animation(struct anm_animation *anim)
32 {
33         int i, j;
34         static const float defaults[] = {
35                 0.0f, 0.0f, 0.0f,               /* default position */
36                 0.0f, 0.0f, 0.0f, 1.0f, /* default rotation quat */
37                 1.0f, 1.0f, 1.0f                /* default scale factor */
38         };
39
40         anim->name = 0;
41
42         for(i=0; i<ANM_NUM_TRACKS; i++) {
43                 if(anm_init_track(anim->tracks + i) == -1) {
44                         for(j=0; j<i; j++) {
45                                 anm_destroy_track(anim->tracks + i);
46                         }
47                 }
48                 anm_set_track_default(anim->tracks + i, defaults[i]);
49         }
50         return 0;
51 }
52
53 void anm_destroy_animation(struct anm_animation *anim)
54 {
55         int i;
56         for(i=0; i<ANM_NUM_TRACKS; i++) {
57                 anm_destroy_track(anim->tracks + i);
58         }
59         free(anim->name);
60 }
61
62 void anm_set_animation_name(struct anm_animation *anim, const char *name)
63 {
64         char *newname = malloc(strlen(name) + 1);
65         if(!newname) return;
66
67         strcpy(newname, name);
68
69         free(anim->name);
70         anim->name = newname;
71 }
72
73 /* ---- node implementation ----- */
74
75 int anm_init_node(struct anm_node *node)
76 {
77         memset(node, 0, sizeof *node);
78
79         node->cur_anim[1] = -1;
80
81         if(!(node->animations = dynarr_alloc(1, sizeof *node->animations))) {
82                 return -1;
83         }
84         if(anm_init_animation(node->animations) == -1) {
85                 dynarr_free(node->animations);
86                 return -1;
87         }
88
89 #ifdef ANIM_THREAD_SAFE
90         /* initialize thread-local matrix cache */
91         pthread_key_create(&node->cache_key, 0);
92         pthread_mutex_init(&node->cache_list_lock, 0);
93 #endif
94
95         return 0;
96 }
97
98 void anm_destroy_node(struct anm_node *node)
99 {
100         int i, num_anim;
101         free(node->name);
102
103         num_anim = anm_get_animation_count(node);
104         for(i=0; i<num_anim; i++) {
105                 anm_destroy_animation(node->animations + i);
106         }
107         dynarr_free(node->animations);
108
109 #ifdef ANIM_THREAD_SAFE
110         /* destroy thread-specific cache */
111         pthread_key_delete(node->cache_key);
112
113         while(node->cache_list) {
114                 struct mat_cache *tmp = node->cache_list;
115                 node->cache_list = tmp->next;
116                 free(tmp);
117         }
118 #endif
119 }
120
121 void anm_destroy_node_tree(struct anm_node *tree)
122 {
123         struct anm_node *c, *tmp;
124
125         if(!tree) return;
126
127         c = tree->child;
128         while(c) {
129                 tmp = c;
130                 c = c->next;
131
132                 anm_destroy_node_tree(tmp);
133         }
134         anm_destroy_node(tree);
135 }
136
137 struct anm_node *anm_create_node(void)
138 {
139         struct anm_node *n;
140
141         if((n = malloc(sizeof *n))) {
142                 if(anm_init_node(n) == -1) {
143                         free(n);
144                         return 0;
145                 }
146         }
147         return n;
148 }
149
150 void anm_free_node(struct anm_node *node)
151 {
152         anm_destroy_node(node);
153         free(node);
154 }
155
156 void anm_free_node_tree(struct anm_node *tree)
157 {
158         struct anm_node *c, *tmp;
159
160         if(!tree) return;
161
162         c = tree->child;
163         while(c) {
164                 tmp = c;
165                 c = c->next;
166
167                 anm_free_node_tree(tmp);
168         }
169
170         anm_free_node(tree);
171 }
172
173 int anm_set_node_name(struct anm_node *node, const char *name)
174 {
175         char *str;
176
177         if(!(str = malloc(strlen(name) + 1))) {
178                 return -1;
179         }
180         strcpy(str, name);
181         free(node->name);
182         node->name = str;
183         return 0;
184 }
185
186 const char *anm_get_node_name(struct anm_node *node)
187 {
188         return node->name ? node->name : "";
189 }
190
191 void anm_link_node(struct anm_node *p, struct anm_node *c)
192 {
193         c->next = p->child;
194         p->child = c;
195
196         c->parent = p;
197         invalidate_cache(c);
198 }
199
200 int anm_unlink_node(struct anm_node *p, struct anm_node *c)
201 {
202         struct anm_node *iter;
203
204         if(p->child == c) {
205                 p->child = c->next;
206                 c->next = 0;
207                 invalidate_cache(c);
208                 return 0;
209         }
210
211         iter = p->child;
212         while(iter->next) {
213                 if(iter->next == c) {
214                         iter->next = c->next;
215                         c->next = 0;
216                         invalidate_cache(c);
217                         return 0;
218                 }
219         }
220         return -1;
221 }
222
223 void anm_set_pivot(struct anm_node *node, float x, float y, float z)
224 {
225         node->pivot[0] = x;
226         node->pivot[1] = y;
227         node->pivot[2] = z;
228 }
229
230 void anm_get_pivot(struct anm_node *node, float *x, float *y, float *z)
231 {
232         *x = node->pivot[0];
233         *y = node->pivot[1];
234         *z = node->pivot[2];
235 }
236
237
238 /* animation management */
239
240 int anm_use_node_animation(struct anm_node *node, int aidx)
241 {
242         if(aidx == node->cur_anim[0] && node->cur_anim[1] == -1) {
243                 return 0;       /* no change, no invalidation */
244         }
245
246         if(aidx < 0 || aidx >= anm_get_animation_count(node)) {
247                 return -1;
248         }
249
250         node->cur_anim[0] = aidx;
251         node->cur_anim[1] = -1;
252         node->cur_mix = 0;
253         node->blend_dur = -1;
254
255         invalidate_cache(node);
256         return 0;
257 }
258
259 int anm_use_node_animations(struct anm_node *node, int aidx, int bidx, float t)
260 {
261         int num_anim;
262
263         if(node->cur_anim[0] == aidx && node->cur_anim[1] == bidx &&
264                         fabs(t - node->cur_mix) < 1e-6) {
265                 return 0;       /* no change, no invalidation */
266         }
267
268         num_anim = anm_get_animation_count(node);
269         if(aidx < 0 || aidx >= num_anim) {
270                 return anm_use_animation(node, bidx);
271         }
272         if(bidx < 0 || bidx >= num_anim) {
273                 return anm_use_animation(node, aidx);
274         }
275         node->cur_anim[0] = aidx;
276         node->cur_anim[1] = bidx;
277         node->cur_mix = t;
278
279         invalidate_cache(node);
280         return 0;
281 }
282
283 int anm_use_animation(struct anm_node *node, int aidx)
284 {
285         struct anm_node *child;
286
287         if(anm_use_node_animation(node, aidx) == -1) {
288                 return -1;
289         }
290
291         child = node->child;
292         while(child) {
293                 if(anm_use_animation(child, aidx) == -1) {
294                         return -1;
295                 }
296                 child = child->next;
297         }
298         return 0;
299 }
300
301 int anm_use_animations(struct anm_node *node, int aidx, int bidx, float t)
302 {
303         struct anm_node *child;
304
305         if(anm_use_node_animations(node, aidx, bidx, t) == -1) {
306                 return -1;
307         }
308
309         child = node->child;
310         while(child) {
311                 if(anm_use_animations(child, aidx, bidx, t) == -1) {
312                         return -1;
313                 }
314                 child = child->next;
315         }
316         return 0;
317
318 }
319
320 void anm_set_node_animation_offset(struct anm_node *node, anm_time_t offs, int which)
321 {
322         if(which < 0 || which >= 2) {
323                 return;
324         }
325         node->cur_anim_offset[which] = offs;
326 }
327
328 anm_time_t anm_get_animation_offset(const struct anm_node *node, int which)
329 {
330         if(which < 0 || which >= 2) {
331                 return 0;
332         }
333         return node->cur_anim_offset[which];
334 }
335
336 void anm_set_animation_offset(struct anm_node *node, anm_time_t offs, int which)
337 {
338         struct anm_node *c = node->child;
339         while(c) {
340                 anm_set_animation_offset(c, offs, which);
341                 c = c->next;
342         }
343
344         anm_set_node_animation_offset(node, offs, which);
345 }
346
347 int anm_get_active_animation_index(const struct anm_node *node, int which)
348 {
349         if(which < 0 || which >= 2) return -1;
350         return node->cur_anim[which];
351 }
352
353 struct anm_animation *anm_get_active_animation(const struct anm_node *node, int which)
354 {
355         int idx = anm_get_active_animation_index(node, which);
356         if(idx < 0 || idx >= anm_get_animation_count(node)) {
357                 return 0;
358         }
359         return node->animations + idx;
360 }
361
362 float anm_get_active_animation_mix(const struct anm_node *node)
363 {
364         return node->cur_mix;
365 }
366
367 int anm_get_animation_count(const struct anm_node *node)
368 {
369         return dynarr_size(node->animations);
370 }
371
372 int anm_add_node_animation(struct anm_node *node)
373 {
374         struct anm_animation newanim;
375         anm_init_animation(&newanim);
376
377         node->animations = dynarr_push(node->animations, &newanim);
378         return 0;
379 }
380
381 int anm_remove_node_animation(struct anm_node *node, int idx)
382 {
383         fprintf(stderr, "anm_remove_animation: unimplemented!");
384         abort();
385         return 0;
386 }
387
388 int anm_add_animation(struct anm_node *node)
389 {
390         struct anm_node *child;
391
392         if(anm_add_node_animation(node) == -1) {
393                 return -1;
394         }
395
396         child = node->child;
397         while(child) {
398                 if(anm_add_animation(child)) {
399                         return -1;
400                 }
401                 child = child->next;
402         }
403         return 0;
404 }
405
406 int anm_remove_animation(struct anm_node *node, int idx)
407 {
408         struct anm_node *child;
409
410         if(anm_remove_node_animation(node, idx) == -1) {
411                 return -1;
412         }
413
414         child = node->child;
415         while(child) {
416                 if(anm_remove_animation(child, idx) == -1) {
417                         return -1;
418                 }
419                 child = child->next;
420         }
421         return 0;
422 }
423
424 struct anm_animation *anm_get_animation(struct anm_node *node, int idx)
425 {
426         if(idx < 0 || idx > anm_get_animation_count(node)) {
427                 return 0;
428         }
429         return node->animations + idx;
430 }
431
432 struct anm_animation *anm_get_animation_by_name(struct anm_node *node, const char *name)
433 {
434         return anm_get_animation(node, anm_find_animation(node, name));
435 }
436
437 int anm_find_animation(struct anm_node *node, const char *name)
438 {
439         int i, count = anm_get_animation_count(node);
440         for(i=0; i<count; i++) {
441                 if(strcmp(node->animations[i].name, name) == 0) {
442                         return i;
443                 }
444         }
445         return -1;
446 }
447
448 /* all the rest act on the current animation(s) */
449
450 void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in)
451 {
452         int i;
453         struct anm_animation *anim = anm_get_active_animation(node, 0);
454         if(!anim) return;
455
456         for(i=0; i<ANM_NUM_TRACKS; i++) {
457                 anm_set_track_interpolator(anim->tracks + i, in);
458         }
459         invalidate_cache(node);
460 }
461
462 void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex)
463 {
464         int i;
465         struct anm_animation *anim = anm_get_active_animation(node, 0);
466         if(!anim) return;
467
468         for(i=0; i<ANM_NUM_TRACKS; i++) {
469                 anm_set_track_extrapolator(anim->tracks + i, ex);
470         }
471         invalidate_cache(node);
472 }
473
474 void anm_set_node_active_animation_name(struct anm_node *node, const char *name)
475 {
476         struct anm_animation *anim = anm_get_active_animation(node, 0);
477         if(!anim) return;
478
479         anm_set_animation_name(anim, name);
480 }
481
482 void anm_set_active_animation_name(struct anm_node *node, const char *name)
483 {
484         struct anm_node *child;
485
486         anm_set_node_active_animation_name(node, name);
487
488         child = node->child;
489         while(child) {
490                 anm_set_active_animation_name(child, name);
491                 child = child->next;
492         }
493 }
494
495 const char *anm_get_active_animation_name(struct anm_node *node)
496 {
497         struct anm_animation *anim = anm_get_active_animation(node, 0);
498         if(anim) {
499                 return anim->name;
500         }
501         return 0;
502 }
503
504 /* ---- high level animation blending ---- */
505 void anm_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur)
506 {
507         struct anm_node *c = node->child;
508
509         if(anmidx == node->cur_anim[0]) {
510                 return;
511         }
512
513         while(c) {
514                 anm_transition(c, anmidx, start, dur);
515                 c = c->next;
516         }
517
518         anm_node_transition(node, anmidx, start, dur);
519 }
520
521 void anm_node_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur)
522 {
523         if(anmidx == node->cur_anim[0]) {
524                 return;
525         }
526
527         node->cur_anim[1] = anmidx;
528         node->cur_anim_offset[1] = start;
529         node->blend_dur = dur;
530 }
531
532
533 #define BLEND_START_TM  node->cur_anim_offset[1]
534
535 static anm_time_t animation_time(struct anm_node *node, anm_time_t tm, int which)
536 {
537         float t;
538
539         if(node->blend_dur >= 0) {
540                 /* we're in transition... */
541                 t = (float)(tm - BLEND_START_TM) / (float)node->blend_dur;
542                 if(t < 0.0) t = 0.0;
543
544                 node->cur_mix = t;
545
546                 if(t > 1.0) {
547                         /* switch completely over to the target animation and stop blending */
548                         anm_use_node_animation(node, node->cur_anim[1]);
549                         node->cur_anim_offset[0] = node->cur_anim_offset[1];
550                 }
551         }
552
553         return tm - node->cur_anim_offset[which];
554 }
555
556
557 void anm_set_position(struct anm_node *node, const float *pos, anm_time_t tm)
558 {
559         anm_set_position3f(node, pos[0], pos[1], pos[2], tm);
560 }
561
562 void anm_set_position3f(struct anm_node *node, float x, float y, float z, anm_time_t tm)
563 {
564         struct anm_animation *anim = anm_get_active_animation(node, 0);
565         if(!anim) return;
566
567         anm_set_value(anim->tracks + ANM_TRACK_POS_X, tm, x);
568         anm_set_value(anim->tracks + ANM_TRACK_POS_Y, tm, y);
569         anm_set_value(anim->tracks + ANM_TRACK_POS_Z, tm, z);
570         invalidate_cache(node);
571 }
572
573 void anm_get_node_position(struct anm_node *node, float *pos, anm_time_t tm)
574 {
575         anm_time_t tm0 = animation_time(node, tm, 0);
576         struct anm_animation *anim0 = anm_get_active_animation(node, 0);
577         struct anm_animation *anim1 = anm_get_active_animation(node, 1);
578
579         if(!anim0) {
580                 pos[0] = pos[1] = pos[2] = 0.0f;
581                 return;
582         }
583
584         pos[0] = anm_get_value(anim0->tracks + ANM_TRACK_POS_X, tm0);
585         pos[1] = anm_get_value(anim0->tracks + ANM_TRACK_POS_Y, tm0);
586         pos[2] = anm_get_value(anim0->tracks + ANM_TRACK_POS_Z, tm0);
587
588         if(anim1) {
589                 anm_time_t tm1 = animation_time(node, tm, 1);
590                 float x1 = anm_get_value(anim1->tracks + ANM_TRACK_POS_X, tm1);
591                 float y1 = anm_get_value(anim1->tracks + ANM_TRACK_POS_Y, tm1);
592                 float z1 = anm_get_value(anim1->tracks + ANM_TRACK_POS_Z, tm1);
593
594                 pos[0] = pos[0] + (x1 - pos[0]) * node->cur_mix;
595                 pos[1] = pos[1] + (y1 - pos[1]) * node->cur_mix;
596                 pos[2] = pos[2] + (z1 - pos[2]) * node->cur_mix;
597         }
598 }
599
600 void anm_set_rotation(struct anm_node *node, const float *qrot, anm_time_t tm)
601 {
602         anm_set_rotation4f(node, qrot[0], qrot[1], qrot[2], qrot[3], tm);
603 }
604
605 void anm_set_rotation4f(struct anm_node *node, float x, float y, float z, float w, anm_time_t tm)
606 {
607         struct anm_animation *anim = anm_get_active_animation(node, 0);
608         if(!anim) return;
609
610         anm_set_value(anim->tracks + ANM_TRACK_ROT_X, tm, x);
611         anm_set_value(anim->tracks + ANM_TRACK_ROT_Y, tm, y);
612         anm_set_value(anim->tracks + ANM_TRACK_ROT_Z, tm, z);
613         anm_set_value(anim->tracks + ANM_TRACK_ROT_W, tm, w);
614         invalidate_cache(node);
615 }
616
617 void anm_set_rotation_axis(struct anm_node *node, float angle, float x, float y, float z, anm_time_t tm)
618 {
619         cgm_quat q;
620
621         cgm_qrotation(&q, angle, x, y, z);
622         anm_set_rotation(node, (float*)&q, tm);
623 }
624
625 static void get_node_rotation(cgm_quat *qres, struct anm_node *node, anm_time_t tm, struct anm_animation *anim)
626 {
627 #ifndef ROT_USE_SLERP
628         qres->x = anm_get_value(anim->tracks + ANM_TRACK_ROT_X, tm);
629         qres->y = anm_get_value(anim->tracks + ANM_TRACK_ROT_Y, tm);
630         qres->z = anm_get_value(anim->tracks + ANM_TRACK_ROT_Z, tm);
631         qres->w = anm_get_value(anim->tracks + ANM_TRACK_ROT_W, tm);
632 #else
633         int idx0, idx1, last_idx;
634         anm_time_t tstart, tend;
635         float t, dt;
636         struct anm_track *track_x, *track_y, *track_z, *track_w;
637         cgm_quat q1, q2;
638
639         track_x = anim->tracks + ANM_TRACK_ROT_X;
640         track_y = anim->tracks + ANM_TRACK_ROT_Y;
641         track_z = anim->tracks + ANM_TRACK_ROT_Z;
642         track_w = anim->tracks + ANM_TRACK_ROT_W;
643
644         if(!track_x->count) {
645                 qres->x = track_x->def_val;
646                 qres->y = track_y->def_val;
647                 qres->z = track_z->def_val;
648                 qres->w = track_w->def_val;
649                 return;
650         }
651
652         last_idx = track_x->count - 1;
653
654         tstart = track_x->keys[0].time;
655         tend = track_x->keys[last_idx].time;
656
657         if(tstart == tend) {
658                 qres->x = track_x->keys[0].val;
659                 qres->y = track_y->keys[0].val;
660                 qres->z = track_z->keys[0].val;
661                 qres->w = track_w->keys[0].val;
662                 return;
663         }
664
665         tm = anm_remap_time(track_x, tm, tstart, tend);
666
667         idx0 = anm_get_key_interval(track_x, tm);
668         assert(idx0 >= 0 && idx0 < track_x->count);
669         idx1 = idx0 + 1;
670
671         if(idx0 == last_idx) {
672                 qres->x = track_x->keys[idx0].val;
673                 qres->y = track_y->keys[idx0].val;
674                 qres->z = track_z->keys[idx0].val;
675                 qres->w = track_w->keys[idx0].val;
676                 return;
677         }
678
679         dt = (float)(track_x->keys[idx1].time - track_x->keys[idx0].time);
680         t = (float)(tm - track_x->keys[idx0].time) / dt;
681
682         q1.x = track_x->keys[idx0].val;
683         q1.y = track_y->keys[idx0].val;
684         q1.z = track_z->keys[idx0].val;
685         q1.w = track_w->keys[idx0].val;
686
687         q2.x = track_x->keys[idx1].val;
688         q2.y = track_y->keys[idx1].val;
689         q2.z = track_z->keys[idx1].val;
690         q2.w = track_w->keys[idx1].val;
691
692         cgm_qslerp(qres, &q1, &q2, t);
693 #endif
694 }
695
696 //get_node_rotation(cgm_quat *qres, struct anm_node *node, anm_time_t tm, struct anm_animation *anim)
697 void anm_get_node_rotation(struct anm_node *node, float *qrot, anm_time_t tm)
698 {
699         anm_time_t tm0 = animation_time(node, tm, 0);
700         struct anm_animation *anim0 = anm_get_active_animation(node, 0);
701         struct anm_animation *anim1 = anm_get_active_animation(node, 1);
702
703         if(!anim0) {
704                 qrot[0] = qrot[1] = qrot[2] = 0.0f;
705                 qrot[3] = 1.0f;
706                 return;
707         }
708
709
710         if(anim1) {
711                 cgm_quat q0, q1;
712                 anm_time_t tm1 = animation_time(node, tm, 1);
713
714                 get_node_rotation(&q0, node, tm0, anim0);
715                 get_node_rotation(&q1, node, tm1, anim1);
716
717                 cgm_qslerp((cgm_quat*)qrot, &q0, &q1, node->cur_mix);
718         } else {
719                 get_node_rotation((cgm_quat*)qrot, node, tm0, anim0);
720         }
721 }
722
723 void anm_set_scaling(struct anm_node *node, const float *scale, anm_time_t tm)
724 {
725         anm_set_scaling3f(node, scale[0], scale[1], scale[2], tm);
726 }
727
728 void anm_set_scaling3f(struct anm_node *node, float x, float y, float z, anm_time_t tm)
729 {
730         struct anm_animation *anim = anm_get_active_animation(node, 0);
731         if(!anim) return;
732
733         anm_set_value(anim->tracks + ANM_TRACK_SCL_X, tm, x);
734         anm_set_value(anim->tracks + ANM_TRACK_SCL_Y, tm, y);
735         anm_set_value(anim->tracks + ANM_TRACK_SCL_Z, tm, z);
736         invalidate_cache(node);
737 }
738
739 void anm_get_node_scaling(struct anm_node *node, float *scale, anm_time_t tm)
740 {
741         anm_time_t tm0 = animation_time(node, tm, 0);
742         struct anm_animation *anim0 = anm_get_active_animation(node, 0);
743         struct anm_animation *anim1 = anm_get_active_animation(node, 1);
744
745         if(!anim0) {
746                 scale[0] = scale[1] = scale[2] = 1.0f;
747                 return;
748         }
749
750         scale[0] = anm_get_value(anim0->tracks + ANM_TRACK_SCL_X, tm0);
751         scale[1] = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Y, tm0);
752         scale[2] = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Z, tm0);
753
754         if(anim1) {
755                 anm_time_t tm1 = animation_time(node, tm, 1);
756                 float x1 = anm_get_value(anim1->tracks + ANM_TRACK_SCL_X, tm1);
757                 float y1 = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Y, tm1);
758                 float z1 = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Z, tm1);
759
760                 scale[0] = scale[0] + (x1 - scale[0]) * node->cur_mix;
761                 scale[1] = scale[1] + (y1 - scale[1]) * node->cur_mix;
762                 scale[2] = scale[2] + (z1 - scale[2]) * node->cur_mix;
763         }
764 }
765
766 void anm_get_position(struct anm_node *node, float *pos, anm_time_t tm)
767 {
768         if(!node->parent) {
769                 anm_get_node_position(node, pos, tm);
770         } else {
771                 float xform[16];
772                 anm_get_matrix(node, xform, tm);
773                 cgm_mget_translation(xform, (cgm_vec3*)pos);
774         }
775 }
776
777 void anm_get_rotation(struct anm_node *node, float *qrot, anm_time_t tm)
778 {
779         if(!node->parent) {
780                 anm_get_node_rotation(node, qrot, tm);
781         } else {
782                 cgm_quat rot;
783                 anm_get_node_rotation(node, &rot.x, tm);
784                 anm_get_rotation(node->parent, qrot, tm);
785                 cgm_qmul((cgm_quat*)qrot, &rot);
786         }
787 }
788
789 void anm_get_scaling(struct anm_node *node, float *scale, anm_time_t tm)
790 {
791         anm_get_node_scaling(node, scale, tm);
792         if(node->parent) {
793                 cgm_vec3 ps;
794                 anm_get_scaling(node->parent, &ps.x, tm);
795                 cgm_vmul((cgm_vec3*)scale, &ps);
796         }
797 }
798
799 void anm_get_node_matrix(struct anm_node *node, float *mat, anm_time_t tm)
800 {
801         int i;
802         float rmat[16];
803         cgm_vec3 pos, scale;
804         cgm_quat rot;
805
806         anm_get_node_position(node, &pos.x, tm);
807         anm_get_node_rotation(node, &rot.x, tm);
808         anm_get_node_scaling(node, &scale.x, tm);
809
810         cgm_mtranslation(mat, node->pivot[0], node->pivot[1], node->pivot[2]);
811         cgm_mrotation_quat(rmat, &rot);
812
813         /*
814         for(i=0; i<3; i++) {
815                 mat[i * 4] = rmat[i * 4];
816                 mat[i * 4 + 1] = rmat[i * 4 + 1];
817                 mat[i * 4 + 2] = rmat[i * 4 + 2];
818         }
819         */
820         for(i=0; i<3; i++) {
821                 mat[i] = rmat[i];
822                 mat[4 + i] = rmat[4 + i];
823                 mat[8 + i] = rmat[8 + i];
824         }
825
826         mat[0] *= scale.x; mat[4] *= scale.y; mat[8] *= scale.z; mat[12] += pos.x;
827         mat[1] *= scale.x; mat[5] *= scale.y; mat[9] *= scale.z; mat[13] += pos.y;
828         mat[2] *= scale.x; mat[6] *= scale.y; mat[10] *= scale.z; mat[14] += pos.z;
829
830         cgm_mpretranslate(mat, -node->pivot[0], -node->pivot[1], -node->pivot[2]);
831
832         /* that's basically: pivot * rotation * translation * scaling * -pivot */
833 }
834
835 void anm_get_node_inv_matrix(struct anm_node *node, float *mat, anm_time_t tm)
836 {
837         anm_get_node_matrix(node, mat, tm);
838         cgm_minverse(mat);
839 }
840
841 void anm_eval_node(struct anm_node *node, anm_time_t tm)
842 {
843         anm_get_node_matrix(node, node->matrix, tm);
844 }
845
846 void anm_eval(struct anm_node *node, anm_time_t tm)
847 {
848         struct anm_node *c;
849
850         anm_eval_node(node, tm);
851
852         if(node->parent) {
853                 /* due to post-order traversal, the parent matrix is already evaluated */
854                 cgm_mmul(node->matrix, node->parent->matrix);
855         }
856
857         /* recersively evaluate all children */
858         c = node->child;
859         while(c) {
860                 anm_eval(c, tm);
861                 c = c->next;
862         }
863 }
864
865 float *anm_get_matrix(struct anm_node *node, float *mat, anm_time_t tm)
866 {
867 #ifdef ANIM_THREAD_SAFE
868         struct mat_cache *cache = pthread_getspecific(node->cache_key);
869         if(!cache) {
870                 cache = malloc(sizeof *cache);
871                 assert(cache);
872
873                 pthread_mutex_lock(&node->cache_list_lock);
874                 cache->next = node->cache_list;
875                 node->cache_list = cache;
876                 pthread_mutex_unlock(&node->cache_list_lock);
877
878                 cache->time = ANM_TIME_INVAL;
879                 cache->inv_time = ANM_TIME_INVAL;
880                 pthread_setspecific(node->cache_key, cache);
881         }
882 #else
883         struct mat_cache *cache = &node->cache;
884 #endif
885
886         if(cache->time != tm) {
887                 anm_get_node_matrix(node, cache->matrix, tm);
888
889                 if(node->parent) {
890                         float parent_mat[16];
891
892                         anm_get_matrix(node->parent, parent_mat, tm);
893                         cgm_mmul(cache->matrix, parent_mat);
894                 }
895                 cache->time = tm;
896         }
897
898         if(mat) {
899                 cgm_mcopy(mat, cache->matrix);
900         }
901         return cache->matrix;
902 }
903
904 float *anm_get_inv_matrix(struct anm_node *node, float *mat, anm_time_t tm)
905 {
906 #ifdef ANIM_THREAD_SAFE
907         struct mat_cache *cache = pthread_getspecific(node->cache_key);
908         if(!cache) {
909                 cache = malloc(sizeof *cache);
910                 assert(cache);
911
912                 pthread_mutex_lock(&node->cache_list_lock);
913                 cache->next = node->cache_list;
914                 node->cache_list = cache;
915                 pthread_mutex_unlock(&node->cache_list_lock);
916
917                 cache->inv_time = ANM_TIME_INVAL;
918                 cache->inv_time = ANM_TIME_INVAL;
919                 pthread_setspecific(node->cache_key, cache);
920         }
921 #else
922         struct mat_cache *cache = &node->cache;
923 #endif
924
925         if(cache->inv_time != tm) {
926                 anm_get_matrix(node, cache->inv_matrix, tm);
927                 cgm_minverse(cache->inv_matrix);
928                 cache->inv_time = tm;
929         }
930
931         if(mat) {
932                 cgm_mcopy(mat, cache->inv_matrix);
933         }
934         return cache->inv_matrix;
935 }
936
937 anm_time_t anm_get_start_time(struct anm_node *node)
938 {
939         int i, j;
940         struct anm_node *c;
941         anm_time_t res = LONG_MAX;
942
943         for(j=0; j<2; j++) {
944                 struct anm_animation *anim = anm_get_active_animation(node, j);
945                 if(!anim) break;
946
947                 for(i=0; i<ANM_NUM_TRACKS; i++) {
948                         if(anim->tracks[i].count) {
949                                 anm_time_t tm = anim->tracks[i].keys[0].time;
950                                 if(tm < res) {
951                                         res = tm;
952                                 }
953                         }
954                 }
955         }
956
957         c = node->child;
958         while(c) {
959                 anm_time_t tm = anm_get_start_time(c);
960                 if(tm < res) {
961                         res = tm;
962                 }
963                 c = c->next;
964         }
965         return res;
966 }
967
968 anm_time_t anm_get_end_time(struct anm_node *node)
969 {
970         int i, j;
971         struct anm_node *c;
972         anm_time_t res = LONG_MIN;
973
974         for(j=0; j<2; j++) {
975                 struct anm_animation *anim = anm_get_active_animation(node, j);
976                 if(!anim) break;
977
978                 for(i=0; i<ANM_NUM_TRACKS; i++) {
979                         if(anim->tracks[i].count) {
980                                 anm_time_t tm = anim->tracks[i].keys[anim->tracks[i].count - 1].time;
981                                 if(tm > res) {
982                                         res = tm;
983                                 }
984                         }
985                 }
986         }
987
988         c = node->child;
989         while(c) {
990                 anm_time_t tm = anm_get_end_time(c);
991                 if(tm > res) {
992                         res = tm;
993                 }
994                 c = c->next;
995         }
996         return res;
997 }
998
999 static void invalidate_cache(struct anm_node *node)
1000 {
1001         struct anm_node *c;
1002
1003 #ifdef ANIM_THREAD_SAFE
1004         struct mat_cache *cache = pthread_getspecific(node->cache_key);
1005         if(cache) {
1006            cache->time = cache->inv_time = ANM_TIME_INVAL;
1007         }
1008 #else
1009         node->cache.time = node->cache.inv_time = ANM_TIME_INVAL;
1010 #endif
1011
1012         c = node->child;
1013         while(c) {
1014                 invalidate_cache(c);
1015                 c = c->next;
1016         }
1017 }