2 libanim - hierarchical keyframe animation library
3 Copyright (C) 2012-2018 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published
7 by the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "cgmath/cgmath.h"
29 static void invalidate_cache(struct anm_node *node);
31 int anm_init_animation(struct anm_animation *anim)
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 */
42 for(i=0; i<ANM_NUM_TRACKS; i++) {
43 if(anm_init_track(anim->tracks + i) == -1) {
45 anm_destroy_track(anim->tracks + i);
48 anm_set_track_default(anim->tracks + i, defaults[i]);
53 void anm_destroy_animation(struct anm_animation *anim)
56 for(i=0; i<ANM_NUM_TRACKS; i++) {
57 anm_destroy_track(anim->tracks + i);
62 void anm_set_animation_name(struct anm_animation *anim, const char *name)
64 char *newname = malloc(strlen(name) + 1);
67 strcpy(newname, name);
73 /* ---- node implementation ----- */
75 int anm_init_node(struct anm_node *node)
77 memset(node, 0, sizeof *node);
79 node->cur_anim[1] = -1;
81 if(!(node->animations = dynarr_alloc(1, sizeof *node->animations))) {
84 if(anm_init_animation(node->animations) == -1) {
85 dynarr_free(node->animations);
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);
98 void anm_destroy_node(struct anm_node *node)
103 num_anim = anm_get_animation_count(node);
104 for(i=0; i<num_anim; i++) {
105 anm_destroy_animation(node->animations + i);
107 dynarr_free(node->animations);
109 #ifdef ANIM_THREAD_SAFE
110 /* destroy thread-specific cache */
111 pthread_key_delete(node->cache_key);
113 while(node->cache_list) {
114 struct mat_cache *tmp = node->cache_list;
115 node->cache_list = tmp->next;
121 void anm_destroy_node_tree(struct anm_node *tree)
123 struct anm_node *c, *tmp;
132 anm_destroy_node_tree(tmp);
134 anm_destroy_node(tree);
137 struct anm_node *anm_create_node(void)
141 if((n = malloc(sizeof *n))) {
142 if(anm_init_node(n) == -1) {
150 void anm_free_node(struct anm_node *node)
152 anm_destroy_node(node);
156 void anm_free_node_tree(struct anm_node *tree)
158 struct anm_node *c, *tmp;
167 anm_free_node_tree(tmp);
173 int anm_set_node_name(struct anm_node *node, const char *name)
177 if(!(str = malloc(strlen(name) + 1))) {
186 const char *anm_get_node_name(struct anm_node *node)
188 return node->name ? node->name : "";
191 void anm_link_node(struct anm_node *p, struct anm_node *c)
200 int anm_unlink_node(struct anm_node *p, struct anm_node *c)
202 struct anm_node *iter;
213 if(iter->next == c) {
214 iter->next = c->next;
223 void anm_set_pivot(struct anm_node *node, float x, float y, float z)
230 void anm_get_pivot(struct anm_node *node, float *x, float *y, float *z)
238 /* animation management */
240 int anm_use_node_animation(struct anm_node *node, int aidx)
242 if(aidx == node->cur_anim[0] && node->cur_anim[1] == -1) {
243 return 0; /* no change, no invalidation */
246 if(aidx < 0 || aidx >= anm_get_animation_count(node)) {
250 node->cur_anim[0] = aidx;
251 node->cur_anim[1] = -1;
253 node->blend_dur = -1;
255 invalidate_cache(node);
259 int anm_use_node_animations(struct anm_node *node, int aidx, int bidx, float t)
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 */
268 num_anim = anm_get_animation_count(node);
269 if(aidx < 0 || aidx >= num_anim) {
270 return anm_use_animation(node, bidx);
272 if(bidx < 0 || bidx >= num_anim) {
273 return anm_use_animation(node, aidx);
275 node->cur_anim[0] = aidx;
276 node->cur_anim[1] = bidx;
279 invalidate_cache(node);
283 int anm_use_animation(struct anm_node *node, int aidx)
285 struct anm_node *child;
287 if(anm_use_node_animation(node, aidx) == -1) {
293 if(anm_use_animation(child, aidx) == -1) {
301 int anm_use_animations(struct anm_node *node, int aidx, int bidx, float t)
303 struct anm_node *child;
305 if(anm_use_node_animations(node, aidx, bidx, t) == -1) {
311 if(anm_use_animations(child, aidx, bidx, t) == -1) {
320 void anm_set_node_animation_offset(struct anm_node *node, anm_time_t offs, int which)
322 if(which < 0 || which >= 2) {
325 node->cur_anim_offset[which] = offs;
328 anm_time_t anm_get_animation_offset(const struct anm_node *node, int which)
330 if(which < 0 || which >= 2) {
333 return node->cur_anim_offset[which];
336 void anm_set_animation_offset(struct anm_node *node, anm_time_t offs, int which)
338 struct anm_node *c = node->child;
340 anm_set_animation_offset(c, offs, which);
344 anm_set_node_animation_offset(node, offs, which);
347 int anm_get_active_animation_index(const struct anm_node *node, int which)
349 if(which < 0 || which >= 2) return -1;
350 return node->cur_anim[which];
353 struct anm_animation *anm_get_active_animation(const struct anm_node *node, int which)
355 int idx = anm_get_active_animation_index(node, which);
356 if(idx < 0 || idx >= anm_get_animation_count(node)) {
359 return node->animations + idx;
362 float anm_get_active_animation_mix(const struct anm_node *node)
364 return node->cur_mix;
367 int anm_get_animation_count(const struct anm_node *node)
369 return dynarr_size(node->animations);
372 int anm_add_node_animation(struct anm_node *node)
374 struct anm_animation newanim;
375 anm_init_animation(&newanim);
377 node->animations = dynarr_push(node->animations, &newanim);
381 int anm_remove_node_animation(struct anm_node *node, int idx)
383 fprintf(stderr, "anm_remove_animation: unimplemented!");
388 int anm_add_animation(struct anm_node *node)
390 struct anm_node *child;
392 if(anm_add_node_animation(node) == -1) {
398 if(anm_add_animation(child)) {
406 int anm_remove_animation(struct anm_node *node, int idx)
408 struct anm_node *child;
410 if(anm_remove_node_animation(node, idx) == -1) {
416 if(anm_remove_animation(child, idx) == -1) {
424 struct anm_animation *anm_get_animation(struct anm_node *node, int idx)
426 if(idx < 0 || idx > anm_get_animation_count(node)) {
429 return node->animations + idx;
432 struct anm_animation *anm_get_animation_by_name(struct anm_node *node, const char *name)
434 return anm_get_animation(node, anm_find_animation(node, name));
437 int anm_find_animation(struct anm_node *node, const char *name)
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) {
448 /* all the rest act on the current animation(s) */
450 void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in)
453 struct anm_animation *anim = anm_get_active_animation(node, 0);
456 for(i=0; i<ANM_NUM_TRACKS; i++) {
457 anm_set_track_interpolator(anim->tracks + i, in);
459 invalidate_cache(node);
462 void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex)
465 struct anm_animation *anim = anm_get_active_animation(node, 0);
468 for(i=0; i<ANM_NUM_TRACKS; i++) {
469 anm_set_track_extrapolator(anim->tracks + i, ex);
471 invalidate_cache(node);
474 void anm_set_node_active_animation_name(struct anm_node *node, const char *name)
476 struct anm_animation *anim = anm_get_active_animation(node, 0);
479 anm_set_animation_name(anim, name);
482 void anm_set_active_animation_name(struct anm_node *node, const char *name)
484 struct anm_node *child;
486 anm_set_node_active_animation_name(node, name);
490 anm_set_active_animation_name(child, name);
495 const char *anm_get_active_animation_name(struct anm_node *node)
497 struct anm_animation *anim = anm_get_active_animation(node, 0);
504 /* ---- high level animation blending ---- */
505 void anm_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur)
507 struct anm_node *c = node->child;
509 if(anmidx == node->cur_anim[0]) {
514 anm_transition(c, anmidx, start, dur);
518 anm_node_transition(node, anmidx, start, dur);
521 void anm_node_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur)
523 if(anmidx == node->cur_anim[0]) {
527 node->cur_anim[1] = anmidx;
528 node->cur_anim_offset[1] = start;
529 node->blend_dur = dur;
533 #define BLEND_START_TM node->cur_anim_offset[1]
535 static anm_time_t animation_time(struct anm_node *node, anm_time_t tm, int which)
539 if(node->blend_dur >= 0) {
540 /* we're in transition... */
541 t = (float)(tm - BLEND_START_TM) / (float)node->blend_dur;
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];
553 return tm - node->cur_anim_offset[which];
557 void anm_set_position(struct anm_node *node, const float *pos, anm_time_t tm)
559 anm_set_position3f(node, pos[0], pos[1], pos[2], tm);
562 void anm_set_position3f(struct anm_node *node, float x, float y, float z, anm_time_t tm)
564 struct anm_animation *anim = anm_get_active_animation(node, 0);
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);
573 void anm_get_node_position(struct anm_node *node, float *pos, anm_time_t tm)
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);
580 pos[0] = pos[1] = pos[2] = 0.0f;
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);
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);
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;
600 void anm_set_rotation(struct anm_node *node, const float *qrot, anm_time_t tm)
602 anm_set_rotation4f(node, qrot[0], qrot[1], qrot[2], qrot[3], tm);
605 void anm_set_rotation4f(struct anm_node *node, float x, float y, float z, float w, anm_time_t tm)
607 struct anm_animation *anim = anm_get_active_animation(node, 0);
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);
617 void anm_set_rotation_axis(struct anm_node *node, float angle, float x, float y, float z, anm_time_t tm)
621 cgm_qrotation(&q, angle, x, y, z);
622 anm_set_rotation(node, (float*)&q, tm);
625 static void get_node_rotation(cgm_quat *qres, struct anm_node *node, anm_time_t tm, struct anm_animation *anim)
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);
633 int idx0, idx1, last_idx;
634 anm_time_t tstart, tend;
636 struct anm_track *track_x, *track_y, *track_z, *track_w;
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;
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;
652 last_idx = track_x->count - 1;
654 tstart = track_x->keys[0].time;
655 tend = track_x->keys[last_idx].time;
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;
665 tm = anm_remap_time(track_x, tm, tstart, tend);
667 idx0 = anm_get_key_interval(track_x, tm);
668 assert(idx0 >= 0 && idx0 < track_x->count);
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;
679 dt = (float)(track_x->keys[idx1].time - track_x->keys[idx0].time);
680 t = (float)(tm - track_x->keys[idx0].time) / dt;
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;
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;
692 cgm_qslerp(qres, &q1, &q2, t);
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)
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);
704 qrot[0] = qrot[1] = qrot[2] = 0.0f;
712 anm_time_t tm1 = animation_time(node, tm, 1);
714 get_node_rotation(&q0, node, tm0, anim0);
715 get_node_rotation(&q1, node, tm1, anim1);
717 cgm_qslerp((cgm_quat*)qrot, &q0, &q1, node->cur_mix);
719 get_node_rotation((cgm_quat*)qrot, node, tm0, anim0);
723 void anm_set_scaling(struct anm_node *node, const float *scale, anm_time_t tm)
725 anm_set_scaling3f(node, scale[0], scale[1], scale[2], tm);
728 void anm_set_scaling3f(struct anm_node *node, float x, float y, float z, anm_time_t tm)
730 struct anm_animation *anim = anm_get_active_animation(node, 0);
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);
739 void anm_get_node_scaling(struct anm_node *node, float *scale, anm_time_t tm)
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);
746 scale[0] = scale[1] = scale[2] = 1.0f;
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);
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);
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;
766 void anm_get_position(struct anm_node *node, float *pos, anm_time_t tm)
769 anm_get_node_position(node, pos, tm);
772 anm_get_matrix(node, xform, tm);
773 cgm_mget_translation(xform, (cgm_vec3*)pos);
777 void anm_get_rotation(struct anm_node *node, float *qrot, anm_time_t tm)
780 anm_get_node_rotation(node, qrot, tm);
783 anm_get_node_rotation(node, &rot.x, tm);
784 anm_get_rotation(node->parent, qrot, tm);
785 cgm_qmul((cgm_quat*)qrot, &rot);
789 void anm_get_scaling(struct anm_node *node, float *scale, anm_time_t tm)
791 anm_get_node_scaling(node, scale, tm);
794 anm_get_scaling(node->parent, &ps.x, tm);
795 cgm_vmul((cgm_vec3*)scale, &ps);
799 void anm_get_node_matrix(struct anm_node *node, float *mat, anm_time_t tm)
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);
810 cgm_mtranslation(mat, node->pivot[0], node->pivot[1], node->pivot[2]);
811 cgm_mrotation_quat(rmat, &rot);
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];
822 mat[4 + i] = rmat[4 + i];
823 mat[8 + i] = rmat[8 + i];
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;
830 cgm_mpretranslate(mat, -node->pivot[0], -node->pivot[1], -node->pivot[2]);
832 /* that's basically: pivot * rotation * translation * scaling * -pivot */
835 void anm_get_node_inv_matrix(struct anm_node *node, float *mat, anm_time_t tm)
837 anm_get_node_matrix(node, mat, tm);
841 void anm_eval_node(struct anm_node *node, anm_time_t tm)
843 anm_get_node_matrix(node, node->matrix, tm);
846 void anm_eval(struct anm_node *node, anm_time_t tm)
850 anm_eval_node(node, tm);
853 /* due to post-order traversal, the parent matrix is already evaluated */
854 cgm_mmul(node->matrix, node->parent->matrix);
857 /* recersively evaluate all children */
865 float *anm_get_matrix(struct anm_node *node, float *mat, anm_time_t tm)
867 #ifdef ANIM_THREAD_SAFE
868 struct mat_cache *cache = pthread_getspecific(node->cache_key);
870 cache = malloc(sizeof *cache);
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);
878 cache->time = ANM_TIME_INVAL;
879 cache->inv_time = ANM_TIME_INVAL;
880 pthread_setspecific(node->cache_key, cache);
883 struct mat_cache *cache = &node->cache;
886 if(cache->time != tm) {
887 anm_get_node_matrix(node, cache->matrix, tm);
890 float parent_mat[16];
892 anm_get_matrix(node->parent, parent_mat, tm);
893 cgm_mmul(cache->matrix, parent_mat);
899 cgm_mcopy(mat, cache->matrix);
901 return cache->matrix;
904 float *anm_get_inv_matrix(struct anm_node *node, float *mat, anm_time_t tm)
906 #ifdef ANIM_THREAD_SAFE
907 struct mat_cache *cache = pthread_getspecific(node->cache_key);
909 cache = malloc(sizeof *cache);
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);
917 cache->inv_time = ANM_TIME_INVAL;
918 cache->inv_time = ANM_TIME_INVAL;
919 pthread_setspecific(node->cache_key, cache);
922 struct mat_cache *cache = &node->cache;
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;
932 cgm_mcopy(mat, cache->inv_matrix);
934 return cache->inv_matrix;
937 anm_time_t anm_get_start_time(struct anm_node *node)
941 anm_time_t res = LONG_MAX;
944 struct anm_animation *anim = anm_get_active_animation(node, j);
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;
959 anm_time_t tm = anm_get_start_time(c);
968 anm_time_t anm_get_end_time(struct anm_node *node)
972 anm_time_t res = LONG_MIN;
975 struct anm_animation *anim = anm_get_active_animation(node, j);
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;
990 anm_time_t tm = anm_get_end_time(c);
999 static void invalidate_cache(struct anm_node *node)
1003 #ifdef ANIM_THREAD_SAFE
1004 struct mat_cache *cache = pthread_getspecific(node->cache_key);
1006 cache->time = cache->inv_time = ANM_TIME_INVAL;
1009 node->cache.time = node->cache.inv_time = ANM_TIME_INVAL;
1014 invalidate_cache(c);