added libanim, and moved gph-cmath into libs/cgmath
[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         cgm_vec3 axis;
621
622         cgm_vcons(&axis, x, y, z);
623         cgm_qrotation(&q, &axis, angle);
624
625         anm_set_rotation(node, (float*)&q, tm);
626 }
627
628 static void get_node_rotation(cgm_quat *qres, struct anm_node *node, anm_time_t tm, struct anm_animation *anim)
629 {
630 #ifndef ROT_USE_SLERP
631         qres->x = anm_get_value(anim->tracks + ANM_TRACK_ROT_X, tm);
632         qres->y = anm_get_value(anim->tracks + ANM_TRACK_ROT_Y, tm);
633         qres->z = anm_get_value(anim->tracks + ANM_TRACK_ROT_Z, tm);
634         qres->w = anm_get_value(anim->tracks + ANM_TRACK_ROT_W, tm);
635 #else
636         int idx0, idx1, last_idx;
637         anm_time_t tstart, tend;
638         float t, dt;
639         struct anm_track *track_x, *track_y, *track_z, *track_w;
640         cgm_quat q1, q2;
641
642         track_x = anim->tracks + ANM_TRACK_ROT_X;
643         track_y = anim->tracks + ANM_TRACK_ROT_Y;
644         track_z = anim->tracks + ANM_TRACK_ROT_Z;
645         track_w = anim->tracks + ANM_TRACK_ROT_W;
646
647         if(!track_x->count) {
648                 qres->x = track_x->def_val;
649                 qres->y = track_y->def_val;
650                 qres->z = track_z->def_val;
651                 qres->w = track_w->def_val;
652                 return;
653         }
654
655         last_idx = track_x->count - 1;
656
657         tstart = track_x->keys[0].time;
658         tend = track_x->keys[last_idx].time;
659
660         if(tstart == tend) {
661                 qres->x = track_x->keys[0].val;
662                 qres->y = track_y->keys[0].val;
663                 qres->z = track_z->keys[0].val;
664                 qres->w = track_w->keys[0].val;
665                 return;
666         }
667
668         tm = anm_remap_time(track_x, tm, tstart, tend);
669
670         idx0 = anm_get_key_interval(track_x, tm);
671         assert(idx0 >= 0 && idx0 < track_x->count);
672         idx1 = idx0 + 1;
673
674         if(idx0 == last_idx) {
675                 qres->x = track_x->keys[idx0].val;
676                 qres->y = track_y->keys[idx0].val;
677                 qres->z = track_z->keys[idx0].val;
678                 qres->w = track_w->keys[idx0].val;
679                 return;
680         }
681
682         dt = (float)(track_x->keys[idx1].time - track_x->keys[idx0].time);
683         t = (float)(tm - track_x->keys[idx0].time) / dt;
684
685         q1.x = track_x->keys[idx0].val;
686         q1.y = track_y->keys[idx0].val;
687         q1.z = track_z->keys[idx0].val;
688         q1.w = track_w->keys[idx0].val;
689
690         q2.x = track_x->keys[idx1].val;
691         q2.y = track_y->keys[idx1].val;
692         q2.z = track_z->keys[idx1].val;
693         q2.w = track_w->keys[idx1].val;
694
695         cgm_qslerp(qres, &q1, &q2, t);
696 #endif
697 }
698
699 //get_node_rotation(cgm_quat *qres, struct anm_node *node, anm_time_t tm, struct anm_animation *anim)
700 void anm_get_node_rotation(struct anm_node *node, float *qrot, anm_time_t tm)
701 {
702         anm_time_t tm0 = animation_time(node, tm, 0);
703         struct anm_animation *anim0 = anm_get_active_animation(node, 0);
704         struct anm_animation *anim1 = anm_get_active_animation(node, 1);
705
706         if(!anim0) {
707                 qrot[0] = qrot[1] = qrot[2] = 0.0f;
708                 qrot[3] = 1.0f;
709                 return;
710         }
711
712
713         if(anim1) {
714                 cgm_quat q0, q1;
715                 anm_time_t tm1 = animation_time(node, tm, 1);
716
717                 get_node_rotation(&q0, node, tm0, anim0);
718                 get_node_rotation(&q1, node, tm1, anim1);
719
720                 cgm_qslerp((cgm_quat*)qrot, &q0, &q1, node->cur_mix);
721         } else {
722                 get_node_rotation((cgm_quat*)qrot, node, tm0, anim0);
723         }
724 }
725
726 void anm_set_scaling(struct anm_node *node, const float *scale, anm_time_t tm)
727 {
728         anm_set_scaling3f(node, scale[0], scale[1], scale[2], tm);
729 }
730
731 void anm_set_scaling3f(struct anm_node *node, float x, float y, float z, anm_time_t tm)
732 {
733         struct anm_animation *anim = anm_get_active_animation(node, 0);
734         if(!anim) return;
735
736         anm_set_value(anim->tracks + ANM_TRACK_SCL_X, tm, x);
737         anm_set_value(anim->tracks + ANM_TRACK_SCL_Y, tm, y);
738         anm_set_value(anim->tracks + ANM_TRACK_SCL_Z, tm, z);
739         invalidate_cache(node);
740 }
741
742 void anm_get_node_scaling(struct anm_node *node, float *scale, anm_time_t tm)
743 {
744         anm_time_t tm0 = animation_time(node, tm, 0);
745         struct anm_animation *anim0 = anm_get_active_animation(node, 0);
746         struct anm_animation *anim1 = anm_get_active_animation(node, 1);
747
748         if(!anim0) {
749                 scale[0] = scale[1] = scale[2] = 1.0f;
750                 return;
751         }
752
753         scale[0] = anm_get_value(anim0->tracks + ANM_TRACK_SCL_X, tm0);
754         scale[1] = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Y, tm0);
755         scale[2] = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Z, tm0);
756
757         if(anim1) {
758                 anm_time_t tm1 = animation_time(node, tm, 1);
759                 float x1 = anm_get_value(anim1->tracks + ANM_TRACK_SCL_X, tm1);
760                 float y1 = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Y, tm1);
761                 float z1 = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Z, tm1);
762
763                 scale[0] = scale[0] + (x1 - scale[0]) * node->cur_mix;
764                 scale[1] = scale[1] + (y1 - scale[1]) * node->cur_mix;
765                 scale[2] = scale[2] + (z1 - scale[2]) * node->cur_mix;
766         }
767 }
768
769 void anm_get_position(struct anm_node *node, float *pos, anm_time_t tm)
770 {
771         if(!node->parent) {
772                 anm_get_node_position(node, pos, tm);
773         } else {
774                 float xform[16];
775                 anm_get_matrix(node, xform, tm);
776                 cgm_mget_translation(xform, (cgm_vec3*)pos);
777         }
778 }
779
780 void anm_get_rotation(struct anm_node *node, float *qrot, anm_time_t tm)
781 {
782         if(!node->parent) {
783                 anm_get_node_rotation(node, qrot, tm);
784         } else {
785                 cgm_quat rot;
786                 anm_get_node_rotation(node, &rot.x, tm);
787                 anm_get_rotation(node->parent, qrot, tm);
788                 cgm_qmul((cgm_quat*)qrot, &rot);
789         }
790 }
791
792 void anm_get_scaling(struct anm_node *node, float *scale, anm_time_t tm)
793 {
794         anm_get_node_scaling(node, scale, tm);
795         if(node->parent) {
796                 cgm_vec3 ps;
797                 anm_get_scaling(node->parent, &ps.x, tm);
798                 cgm_vmul((cgm_vec3*)scale, &ps);
799         }
800 }
801
802 void anm_get_node_matrix(struct anm_node *node, float *mat, anm_time_t tm)
803 {
804         int i;
805         float rmat[16];
806         cgm_vec3 pos, scale;
807         cgm_quat rot;
808
809         anm_get_node_position(node, &pos.x, tm);
810         anm_get_node_rotation(node, &rot.x, tm);
811         anm_get_node_scaling(node, &scale.x, tm);
812
813         cgm_mtranslation(mat, node->pivot[0], node->pivot[1], node->pivot[2]);
814         cgm_mrotation_quat(rmat, &rot);
815
816         /*
817         for(i=0; i<3; i++) {
818                 mat[i * 4] = rmat[i * 4];
819                 mat[i * 4 + 1] = rmat[i * 4 + 1];
820                 mat[i * 4 + 2] = rmat[i * 4 + 2];
821         }
822         */
823         for(i=0; i<3; i++) {
824                 mat[i] = rmat[i];
825                 mat[4 + i] = rmat[4 + i];
826                 mat[8 + i] = rmat[8 + i];
827         }
828
829         mat[0] *= scale.x; mat[4] *= scale.y; mat[8] *= scale.z; mat[12] += pos.x;
830         mat[1] *= scale.x; mat[5] *= scale.y; mat[9] *= scale.z; mat[13] += pos.y;
831         mat[2] *= scale.x; mat[6] *= scale.y; mat[10] *= scale.z; mat[14] += pos.z;
832
833         cgm_mpretranslate(mat, -node->pivot[0], -node->pivot[1], -node->pivot[2]);
834
835         /* that's basically: pivot * rotation * translation * scaling * -pivot */
836 }
837
838 void anm_get_node_inv_matrix(struct anm_node *node, float *mat, anm_time_t tm)
839 {
840         anm_get_node_matrix(node, mat, tm);
841         cgm_minverse(mat);
842 }
843
844 void anm_eval_node(struct anm_node *node, anm_time_t tm)
845 {
846         anm_get_node_matrix(node, node->matrix, tm);
847 }
848
849 void anm_eval(struct anm_node *node, anm_time_t tm)
850 {
851         struct anm_node *c;
852
853         anm_eval_node(node, tm);
854
855         if(node->parent) {
856                 /* due to post-order traversal, the parent matrix is already evaluated */
857                 cgm_mmul(node->matrix, node->parent->matrix);
858         }
859
860         /* recersively evaluate all children */
861         c = node->child;
862         while(c) {
863                 anm_eval(c, tm);
864                 c = c->next;
865         }
866 }
867
868 float *anm_get_matrix(struct anm_node *node, float *mat, anm_time_t tm)
869 {
870 #ifdef ANIM_THREAD_SAFE
871         struct mat_cache *cache = pthread_getspecific(node->cache_key);
872         if(!cache) {
873                 cache = malloc(sizeof *cache);
874                 assert(cache);
875
876                 pthread_mutex_lock(&node->cache_list_lock);
877                 cache->next = node->cache_list;
878                 node->cache_list = cache;
879                 pthread_mutex_unlock(&node->cache_list_lock);
880
881                 cache->time = ANM_TIME_INVAL;
882                 cache->inv_time = ANM_TIME_INVAL;
883                 pthread_setspecific(node->cache_key, cache);
884         }
885 #else
886         struct mat_cache *cache = &node->cache;
887 #endif
888
889         if(cache->time != tm) {
890                 anm_get_node_matrix(node, cache->matrix, tm);
891
892                 if(node->parent) {
893                         float parent_mat[16];
894
895                         anm_get_matrix(node->parent, parent_mat, tm);
896                         cgm_mmul(cache->matrix, parent_mat);
897                 }
898                 cache->time = tm;
899         }
900
901         if(mat) {
902                 cgm_mcopy(mat, cache->matrix);
903         }
904         return cache->matrix;
905 }
906
907 float *anm_get_inv_matrix(struct anm_node *node, float *mat, anm_time_t tm)
908 {
909 #ifdef ANIM_THREAD_SAFE
910         struct mat_cache *cache = pthread_getspecific(node->cache_key);
911         if(!cache) {
912                 cache = malloc(sizeof *cache);
913                 assert(cache);
914
915                 pthread_mutex_lock(&node->cache_list_lock);
916                 cache->next = node->cache_list;
917                 node->cache_list = cache;
918                 pthread_mutex_unlock(&node->cache_list_lock);
919
920                 cache->inv_time = ANM_TIME_INVAL;
921                 cache->inv_time = ANM_TIME_INVAL;
922                 pthread_setspecific(node->cache_key, cache);
923         }
924 #else
925         struct mat_cache *cache = &node->cache;
926 #endif
927
928         if(cache->inv_time != tm) {
929                 anm_get_matrix(node, cache->inv_matrix, tm);
930                 cgm_minverse(cache->inv_matrix);
931                 cache->inv_time = tm;
932         }
933
934         if(mat) {
935                 cgm_mcopy(mat, cache->inv_matrix);
936         }
937         return cache->inv_matrix;
938 }
939
940 anm_time_t anm_get_start_time(struct anm_node *node)
941 {
942         int i, j;
943         struct anm_node *c;
944         anm_time_t res = LONG_MAX;
945
946         for(j=0; j<2; j++) {
947                 struct anm_animation *anim = anm_get_active_animation(node, j);
948                 if(!anim) break;
949
950                 for(i=0; i<ANM_NUM_TRACKS; i++) {
951                         if(anim->tracks[i].count) {
952                                 anm_time_t tm = anim->tracks[i].keys[0].time;
953                                 if(tm < res) {
954                                         res = tm;
955                                 }
956                         }
957                 }
958         }
959
960         c = node->child;
961         while(c) {
962                 anm_time_t tm = anm_get_start_time(c);
963                 if(tm < res) {
964                         res = tm;
965                 }
966                 c = c->next;
967         }
968         return res;
969 }
970
971 anm_time_t anm_get_end_time(struct anm_node *node)
972 {
973         int i, j;
974         struct anm_node *c;
975         anm_time_t res = LONG_MIN;
976
977         for(j=0; j<2; j++) {
978                 struct anm_animation *anim = anm_get_active_animation(node, j);
979                 if(!anim) break;
980
981                 for(i=0; i<ANM_NUM_TRACKS; i++) {
982                         if(anim->tracks[i].count) {
983                                 anm_time_t tm = anim->tracks[i].keys[anim->tracks[i].count - 1].time;
984                                 if(tm > res) {
985                                         res = tm;
986                                 }
987                         }
988                 }
989         }
990
991         c = node->child;
992         while(c) {
993                 anm_time_t tm = anm_get_end_time(c);
994                 if(tm > res) {
995                         res = tm;
996                 }
997                 c = c->next;
998         }
999         return res;
1000 }
1001
1002 static void invalidate_cache(struct anm_node *node)
1003 {
1004         struct anm_node *c;
1005
1006 #ifdef ANIM_THREAD_SAFE
1007         struct mat_cache *cache = pthread_getspecific(node->cache_key);
1008         if(cache) {
1009            cache->time = cache->inv_time = ANM_TIME_INVAL;
1010         }
1011 #else
1012         node->cache.time = node->cache.inv_time = ANM_TIME_INVAL;
1013 #endif
1014
1015         c = node->child;
1016         while(c) {
1017                 invalidate_cache(c);
1018                 c = c->next;
1019         }
1020 }