libanim
changeset 24:09e267e7ed4a
implemented high-level animation blending interface
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 30 Dec 2013 15:20:31 +0200 |
parents | 203c11299586 |
children | ebead35c9eb1 |
files | example/test.c src/anim.c src/anim.h |
diffstat | 3 files changed, 141 insertions(+), 47 deletions(-) [+] |
line diff
1.1 --- a/example/test.c Fri Dec 27 11:29:42 2013 +0200 1.2 +++ b/example/test.c Mon Dec 30 15:20:31 2013 +0200 1.3 @@ -23,7 +23,7 @@ 1.4 {{0, -2.1, 0}, {0, 1, 0}, {0.8, 2, 0.8}, {1, 0.5, 0.5}}, /* left-lower leg */ 1.5 {{0, -2.1, 0}, {0, 1, 0}, {0.8, 2, 0.8}, {0.5, 1, 0.5}}, /* right-lower leg */ 1.6 1.7 - {{0, 2.6, 0}, {0, -0.5, 0}, {1.2, 1.2, 1.2},{0, 1, 1}}, /* head */ 1.8 + {{0, 2.6, 0}, {0, -0.5, 0}, {1.2, 1.2, 1.2},{0, 1, 1}}, /* head */ 1.9 1.10 {{-1.3, 0.4, 0}, {0, 1, 0}, {0.8, 2, 0.8}, {0, 0, 1}}, /* left-upper arm */ 1.11 {{1.3, 0.4, 0}, {0, 1, 0}, {0.8, 2, 0.8}, {1, 1, 0}}, /* right-upper arm */ 1.12 @@ -253,29 +253,6 @@ 1.13 glRotatef(cam_phi, 1, 0, 0); 1.14 glRotatef(cam_theta, 0, 1, 0); 1.15 1.16 - /* animation blending if we're in transition */ 1.17 - if(cur_anim != next_anim) { 1.18 - float t = (msec - trans_start_tm) / 1500.0; 1.19 - 1.20 - struct anm_animation *from, *to; 1.21 - from = anm_get_animation(root, cur_anim); 1.22 - to = anm_get_animation(root, next_anim); 1.23 - 1.24 - if(t >= 1.0) { 1.25 - t = 1.0; 1.26 - cur_anim = next_anim; 1.27 - anm_use_animation(root, cur_anim); 1.28 - } else { 1.29 - anm_use_animations(root, cur_anim, next_anim, t); 1.30 - } 1.31 - 1.32 - printf("transitioning from \"%s\" to \"%s\": %.2f \r", from->name, to->name, t); 1.33 - if(cur_anim == next_anim) { 1.34 - putchar('\n'); 1.35 - } 1.36 - fflush(stdout); 1.37 - } 1.38 - 1.39 /* first render a character with bottom-up lazy matrix calculation */ 1.40 glPushMatrix(); 1.41 glTranslatef(-2.5, 0, 0); 1.42 @@ -358,8 +335,10 @@ 1.43 exit(0); 1.44 1.45 case ' ': 1.46 + cur_anim = anm_get_active_animation_index(root, 0); 1.47 next_anim = (cur_anim + 1) % 2; 1.48 trans_start_tm = glutGet(GLUT_ELAPSED_TIME); 1.49 + anm_transition(root, next_anim, trans_start_tm, 1500); 1.50 break; 1.51 } 1.52 }
2.1 --- a/src/anim.c Fri Dec 27 11:29:42 2013 +0200 2.2 +++ b/src/anim.c Mon Dec 30 15:20:31 2013 +0200 2.3 @@ -57,7 +57,6 @@ 2.4 memset(node, 0, sizeof *node); 2.5 2.6 node->cur_anim[1] = -1; 2.7 - node->cur_mix = 0; 2.8 2.9 if(!(node->animations = dynarr_alloc(1, sizeof *node->animations))) { 2.10 return -1; 2.11 @@ -222,6 +221,7 @@ 2.12 node->cur_anim[0] = aidx; 2.13 node->cur_anim[1] = -1; 2.14 node->cur_mix = 0; 2.15 + node->blend_dur = -1; 2.16 2.17 invalidate_cache(node); 2.18 return 0; 2.19 @@ -288,13 +288,40 @@ 2.20 2.21 } 2.22 2.23 -int anm_get_active_animation_index(struct anm_node *node, int which) 2.24 +void anm_set_node_animation_offset(struct anm_node *node, anm_time_t offs, int which) 2.25 +{ 2.26 + if(which < 0 || which >= 2) { 2.27 + return; 2.28 + } 2.29 + node->cur_anim_offset[which] = offs; 2.30 +} 2.31 + 2.32 +anm_time_t anm_get_animation_offset(const struct anm_node *node, int which) 2.33 +{ 2.34 + if(which < 0 || which >= 2) { 2.35 + return 0; 2.36 + } 2.37 + return node->cur_anim_offset[which]; 2.38 +} 2.39 + 2.40 +void anm_set_animation_offset(struct anm_node *node, anm_time_t offs, int which) 2.41 +{ 2.42 + struct anm_node *c = node->child; 2.43 + while(c) { 2.44 + anm_set_animation_offset(c, offs, which); 2.45 + c = c->next; 2.46 + } 2.47 + 2.48 + anm_set_node_animation_offset(node, offs, which); 2.49 +} 2.50 + 2.51 +int anm_get_active_animation_index(const struct anm_node *node, int which) 2.52 { 2.53 if(which < 0 || which >= 2) return -1; 2.54 return node->cur_anim[which]; 2.55 } 2.56 2.57 -struct anm_animation *anm_get_active_animation(struct anm_node *node, int which) 2.58 +struct anm_animation *anm_get_active_animation(const struct anm_node *node, int which) 2.59 { 2.60 int idx = anm_get_active_animation_index(node, which); 2.61 if(idx < 0 || idx >= anm_get_animation_count(node)) { 2.62 @@ -303,12 +330,12 @@ 2.63 return node->animations + idx; 2.64 } 2.65 2.66 -float anm_get_active_animation_mix(struct anm_node *node) 2.67 +float anm_get_active_animation_mix(const struct anm_node *node) 2.68 { 2.69 return node->cur_mix; 2.70 } 2.71 2.72 -int anm_get_animation_count(struct anm_node *node) 2.73 +int anm_get_animation_count(const struct anm_node *node) 2.74 { 2.75 return dynarr_size(node->animations); 2.76 } 2.77 @@ -445,6 +472,50 @@ 2.78 return 0; 2.79 } 2.80 2.81 +/* ---- high level animation blending ---- */ 2.82 +void anm_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur) 2.83 +{ 2.84 + struct anm_node *c = node->child; 2.85 + while(c) { 2.86 + anm_transition(c, anmidx, start, dur); 2.87 + c = c->next; 2.88 + } 2.89 + 2.90 + anm_node_transition(node, anmidx, start, dur); 2.91 +} 2.92 + 2.93 +void anm_node_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur) 2.94 +{ 2.95 + node->cur_anim[1] = anmidx; 2.96 + node->cur_anim_offset[1] = start; 2.97 + node->blend_dur = dur; 2.98 +} 2.99 + 2.100 + 2.101 +#define BLEND_START_TM node->cur_anim_offset[1] 2.102 + 2.103 +static anm_time_t animation_time(struct anm_node *node, anm_time_t tm, int which) 2.104 +{ 2.105 + float t; 2.106 + 2.107 + if(node->blend_dur >= 0) { 2.108 + /* we're in transition... */ 2.109 + t = (float)(tm - BLEND_START_TM) / (float)node->blend_dur; 2.110 + if(t < 0.0) t = 0.0; 2.111 + 2.112 + node->cur_mix = t; 2.113 + 2.114 + if(t > 1.0) { 2.115 + /* switch completely over to the target animation and stop blending */ 2.116 + anm_use_node_animation(node, node->cur_anim[1]); 2.117 + node->cur_anim_offset[0] = node->cur_anim_offset[1]; 2.118 + } 2.119 + } 2.120 + 2.121 + return tm - node->cur_anim_offset[which]; 2.122 +} 2.123 + 2.124 + 2.125 void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm) 2.126 { 2.127 struct anm_animation *anim = anm_get_active_animation(node, 0); 2.128 @@ -456,9 +527,11 @@ 2.129 invalidate_cache(node); 2.130 } 2.131 2.132 + 2.133 vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm) 2.134 { 2.135 vec3_t v; 2.136 + anm_time_t tm0 = animation_time(node, tm, 0); 2.137 struct anm_animation *anim0 = anm_get_active_animation(node, 0); 2.138 struct anm_animation *anim1 = anm_get_active_animation(node, 1); 2.139 2.140 @@ -466,15 +539,16 @@ 2.141 return v3_cons(0, 0, 0); 2.142 } 2.143 2.144 - v.x = anm_get_value(anim0->tracks + ANM_TRACK_POS_X, tm); 2.145 - v.y = anm_get_value(anim0->tracks + ANM_TRACK_POS_Y, tm); 2.146 - v.z = anm_get_value(anim0->tracks + ANM_TRACK_POS_Z, tm); 2.147 + v.x = anm_get_value(anim0->tracks + ANM_TRACK_POS_X, tm0); 2.148 + v.y = anm_get_value(anim0->tracks + ANM_TRACK_POS_Y, tm0); 2.149 + v.z = anm_get_value(anim0->tracks + ANM_TRACK_POS_Z, tm0); 2.150 2.151 if(anim1) { 2.152 vec3_t v1; 2.153 - v1.x = anm_get_value(anim1->tracks + ANM_TRACK_POS_X, tm); 2.154 - v1.y = anm_get_value(anim1->tracks + ANM_TRACK_POS_Y, tm); 2.155 - v1.z = anm_get_value(anim1->tracks + ANM_TRACK_POS_Z, tm); 2.156 + anm_time_t tm1 = animation_time(node, tm, 1); 2.157 + v1.x = anm_get_value(anim1->tracks + ANM_TRACK_POS_X, tm1); 2.158 + v1.y = anm_get_value(anim1->tracks + ANM_TRACK_POS_Y, tm1); 2.159 + v1.z = anm_get_value(anim1->tracks + ANM_TRACK_POS_Z, tm1); 2.160 2.161 v.x = v.x + (v1.x - v.x) * node->cur_mix; 2.162 v.y = v.y + (v1.y - v.y) * node->cur_mix; 2.163 @@ -575,6 +649,7 @@ 2.164 quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm) 2.165 { 2.166 quat_t q; 2.167 + anm_time_t tm0 = animation_time(node, tm, 0); 2.168 struct anm_animation *anim0 = anm_get_active_animation(node, 0); 2.169 struct anm_animation *anim1 = anm_get_active_animation(node, 1); 2.170 2.171 @@ -582,10 +657,11 @@ 2.172 return quat_identity(); 2.173 } 2.174 2.175 - q = get_node_rotation(node, tm, anim0); 2.176 + q = get_node_rotation(node, tm0, anim0); 2.177 2.178 if(anim1) { 2.179 - quat_t q1 = get_node_rotation(node, tm, anim1); 2.180 + anm_time_t tm1 = animation_time(node, tm, 1); 2.181 + quat_t q1 = get_node_rotation(node, tm1, anim1); 2.182 2.183 q = quat_slerp(q, q1, node->cur_mix); 2.184 } 2.185 @@ -606,6 +682,7 @@ 2.186 vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm) 2.187 { 2.188 vec3_t v; 2.189 + anm_time_t tm0 = animation_time(node, tm, 0); 2.190 struct anm_animation *anim0 = anm_get_active_animation(node, 0); 2.191 struct anm_animation *anim1 = anm_get_active_animation(node, 1); 2.192 2.193 @@ -613,15 +690,16 @@ 2.194 return v3_cons(1, 1, 1); 2.195 } 2.196 2.197 - v.x = anm_get_value(anim0->tracks + ANM_TRACK_SCL_X, tm); 2.198 - v.y = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Y, tm); 2.199 - v.z = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Z, tm); 2.200 + v.x = anm_get_value(anim0->tracks + ANM_TRACK_SCL_X, tm0); 2.201 + v.y = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Y, tm0); 2.202 + v.z = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Z, tm0); 2.203 2.204 if(anim1) { 2.205 vec3_t v1; 2.206 - v1.x = anm_get_value(anim1->tracks + ANM_TRACK_SCL_X, tm); 2.207 - v1.y = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Y, tm); 2.208 - v1.z = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Z, tm); 2.209 + anm_time_t tm1 = animation_time(node, tm, 1); 2.210 + v1.x = anm_get_value(anim1->tracks + ANM_TRACK_SCL_X, tm1); 2.211 + v1.y = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Y, tm1); 2.212 + v1.z = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Z, tm1); 2.213 2.214 v.x = v.x + (v1.x - v.x) * node->cur_mix; 2.215 v.y = v.y + (v1.y - v.y) * node->cur_mix;
3.1 --- a/src/anim.h Fri Dec 27 11:29:42 2013 +0200 3.2 +++ b/src/anim.h Mon Dec 30 15:20:31 2013 +0200 3.3 @@ -36,8 +36,12 @@ 3.4 char *name; 3.5 3.6 int cur_anim[2]; 3.7 + anm_time_t cur_anim_offset[2]; 3.8 float cur_mix; 3.9 3.10 + /* high-level animation blending transition duration */ 3.11 + anm_time_t blend_dur; 3.12 + 3.13 struct anm_animation *animations; 3.14 vec3_t pivot; 3.15 3.16 @@ -68,6 +72,8 @@ 3.17 void anm_set_animation_name(struct anm_animation *anim, const char *name); 3.18 3.19 3.20 +/* ---- node/hierarchy management ---- */ 3.21 + 3.22 /* node constructor and destructor */ 3.23 int anm_init_node(struct anm_node *node); 3.24 void anm_destroy_node(struct anm_node *node); 3.25 @@ -95,6 +101,8 @@ 3.26 void anm_set_pivot(struct anm_node *node, vec3_t pivot); 3.27 vec3_t anm_get_pivot(struct anm_node *node); 3.28 3.29 +/* ---- multiple animations and animation blending ---- */ 3.30 + 3.31 /* set active animation(s) */ 3.32 int anm_use_node_animation(struct anm_node *node, int aidx); 3.33 int anm_use_node_animations(struct anm_node *node, int aidx, int bidx, float t); 3.34 @@ -102,13 +110,19 @@ 3.35 int anm_use_animation(struct anm_node *node, int aidx); 3.36 int anm_use_animations(struct anm_node *node, int aidx, int bidx, float t); 3.37 3.38 +/* set/get current animation offset(s) */ 3.39 +void anm_set_node_animation_offset(struct anm_node *node, anm_time_t offs, int which); 3.40 +anm_time_t anm_get_animation_offset(const struct anm_node *node, int which); 3.41 +/* recursive variant */ 3.42 +void anm_set_animation_offset(struct anm_node *node, anm_time_t offs, int which); 3.43 + 3.44 /* returns the requested current animation index, which can be 0 or 1 */ 3.45 -int anm_get_active_animation_index(struct anm_node *node, int which); 3.46 +int anm_get_active_animation_index(const struct anm_node *node, int which); 3.47 /* returns the requested current animation, which can be 0 or 1 */ 3.48 -struct anm_animation *anm_get_active_animation(struct anm_node *node, int which); 3.49 -float anm_get_active_animation_mix(struct anm_node *node); 3.50 +struct anm_animation *anm_get_active_animation(const struct anm_node *node, int which); 3.51 +float anm_get_active_animation_mix(const struct anm_node *node); 3.52 3.53 -int anm_get_animation_count(struct anm_node *node); 3.54 +int anm_get_animation_count(const struct anm_node *node); 3.55 3.56 /* add/remove an animation to the specified node */ 3.57 int anm_add_node_animation(struct anm_node *node); 3.58 @@ -136,6 +150,26 @@ 3.59 /* get the name of the currently active animation of this node */ 3.60 const char *anm_get_active_animation_name(struct anm_node *node); 3.61 3.62 + 3.63 +/* ---- high level animation blending interface ---- */ 3.64 +/* XXX this convenience interface assumes monotonically increasing time values 3.65 + * in all subsequent calls to anm_get_* and anm_eval_* functions. 3.66 + * 3.67 + * anmidx: index of the animation to transition to 3.68 + * start: when to start the transition 3.69 + * dur: transition duration 3.70 + * 3.71 + * sets up a transition from the current animation (cur_anim[0]) to another animation. 3.72 + * at time start + dur, the transition will be completed, cur_anim[0] will be the new 3.73 + * animation and cur_anim_offset[0] will be equal to start. 3.74 + */ 3.75 +void anm_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur); 3.76 +/* non-recursive variant, acts on a single node (you probably DON'T want to use this) */ 3.77 +void anm_node_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur); 3.78 + 3.79 + 3.80 +/* ---- keyframes / PRS interpolation ---- */ 3.81 + 3.82 void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm); 3.83 vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm); 3.84 3.85 @@ -154,6 +188,9 @@ 3.86 anm_time_t anm_get_start_time(struct anm_node *node); 3.87 anm_time_t anm_get_end_time(struct anm_node *node); 3.88 3.89 + 3.90 +/* ---- transformation matrices ---- */ 3.91 + 3.92 /* these calculate the matrix and inverse matrix of this node alone */ 3.93 void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm); 3.94 void anm_get_node_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm);