libanim
diff src/anim.c @ 58:fe017bde08bc
implemented multiple animations per node, and blending between two animations
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Fri, 27 Dec 2013 06:28:43 +0200 |
parents | 3c2428cb38f7 |
children | 9758004136f8 |
line diff
1.1 --- a/src/anim.c Mon Dec 09 04:06:30 2013 +0200 1.2 +++ b/src/anim.c Fri Dec 27 06:28:43 2013 +0200 1.3 @@ -8,7 +8,7 @@ 1.4 1.5 static void invalidate_cache(struct anm_node *node); 1.6 1.7 -int anm_init_node(struct anm_node *node) 1.8 +int anm_init_animation(struct anm_animation *anim) 1.9 { 1.10 int i, j; 1.11 static const float defaults[] = { 1.12 @@ -17,20 +17,49 @@ 1.13 1.0f, 1.0f, 1.0f /* default scale factor */ 1.14 }; 1.15 1.16 + anim->name = 0; 1.17 + 1.18 + for(i=0; i<ANM_NUM_TRACKS; i++) { 1.19 + if(anm_init_track(anim->tracks + i) == -1) { 1.20 + for(j=0; j<i; j++) { 1.21 + anm_destroy_track(anim->tracks + i); 1.22 + } 1.23 + } 1.24 + anm_set_track_default(anim->tracks + i, defaults[i]); 1.25 + } 1.26 + return 0; 1.27 +} 1.28 + 1.29 +void anm_destroy_animation(struct anm_animation *anim) 1.30 +{ 1.31 + int i; 1.32 + for(i=0; i<ANM_NUM_TRACKS; i++) { 1.33 + anm_destroy_track(anim->tracks + i); 1.34 + } 1.35 + free(anim->name); 1.36 +} 1.37 + 1.38 +/* ---- node implementation ----- */ 1.39 + 1.40 +int anm_init_node(struct anm_node *node) 1.41 +{ 1.42 memset(node, 0, sizeof *node); 1.43 1.44 + node->cur_anim[1] = -1; 1.45 + node->cur_mix = 0; 1.46 + 1.47 + if(!(node->animations = dynarr_alloc(1, sizeof *node->animations))) { 1.48 + return -1; 1.49 + } 1.50 + if(anm_init_animation(node->animations) == -1) { 1.51 + dynarr_free(node->animations); 1.52 + return -1; 1.53 + } 1.54 + 1.55 /* initialize thread-local matrix cache */ 1.56 pthread_key_create(&node->cache_key, 0); 1.57 pthread_mutex_init(&node->cache_list_lock, 0); 1.58 1.59 - for(i=0; i<ANM_NUM_TRACKS; i++) { 1.60 - if(anm_init_track(node->tracks + i) == -1) { 1.61 - for(j=0; j<i; j++) { 1.62 - anm_destroy_track(node->tracks + i); 1.63 - } 1.64 - } 1.65 - anm_set_track_default(node->tracks + i, defaults[i]); 1.66 - } 1.67 return 0; 1.68 } 1.69 1.70 @@ -40,8 +69,9 @@ 1.71 free(node->name); 1.72 1.73 for(i=0; i<ANM_NUM_TRACKS; i++) { 1.74 - anm_destroy_track(node->tracks + i); 1.75 + anm_destroy_animation(node->animations + i); 1.76 } 1.77 + dynarr_free(node->animations); 1.78 1.79 /* destroy thread-specific cache */ 1.80 pthread_key_delete(node->cache_key); 1.81 @@ -123,26 +153,6 @@ 1.82 return node->name ? node->name : ""; 1.83 } 1.84 1.85 -void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in) 1.86 -{ 1.87 - int i; 1.88 - 1.89 - for(i=0; i<ANM_NUM_TRACKS; i++) { 1.90 - anm_set_track_interpolator(node->tracks + i, in); 1.91 - } 1.92 - invalidate_cache(node); 1.93 -} 1.94 - 1.95 -void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex) 1.96 -{ 1.97 - int i; 1.98 - 1.99 - for(i=0; i<ANM_NUM_TRACKS; i++) { 1.100 - anm_set_track_extrapolator(node->tracks + i, ex); 1.101 - } 1.102 - invalidate_cache(node); 1.103 -} 1.104 - 1.105 void anm_link_node(struct anm_node *p, struct anm_node *c) 1.106 { 1.107 c->next = p->child; 1.108 @@ -175,40 +185,284 @@ 1.109 return -1; 1.110 } 1.111 1.112 +void anm_set_pivot(struct anm_node *node, vec3_t piv) 1.113 +{ 1.114 + node->pivot = piv; 1.115 +} 1.116 + 1.117 +vec3_t anm_get_pivot(struct anm_node *node) 1.118 +{ 1.119 + return node->pivot; 1.120 +} 1.121 + 1.122 + 1.123 +/* animation management */ 1.124 + 1.125 +int anm_use_node_animation(struct anm_node *node, int aidx) 1.126 +{ 1.127 + if(aidx == node->cur_anim[0] && node->cur_anim[1] == -1) { 1.128 + return 0; /* no change, no invalidation */ 1.129 + } 1.130 + 1.131 + if(aidx < 0 || aidx >= anm_get_animation_count(node)) { 1.132 + return -1; 1.133 + } 1.134 + 1.135 + node->cur_anim[0] = aidx; 1.136 + node->cur_anim[1] = -1; 1.137 + node->cur_mix = 0; 1.138 + 1.139 + invalidate_cache(node); 1.140 + return 0; 1.141 +} 1.142 + 1.143 +int anm_use_node_animations(struct anm_node *node, int aidx, int bidx, float t) 1.144 +{ 1.145 + int num_anim; 1.146 + 1.147 + if(node->cur_anim[0] == aidx && node->cur_anim[1] == bidx && 1.148 + fabs(t - node->cur_mix) < 1e-6) { 1.149 + return 0; /* no change, no invalidation */ 1.150 + } 1.151 + 1.152 + num_anim = anm_get_animation_count(node); 1.153 + if(aidx < 0 || aidx >= num_anim) { 1.154 + return anm_use_animation(node, bidx); 1.155 + } 1.156 + if(bidx < 0 || bidx >= num_anim) { 1.157 + return anm_use_animation(node, aidx); 1.158 + } 1.159 + node->cur_anim[0] = aidx; 1.160 + node->cur_anim[1] = bidx; 1.161 + node->cur_mix = t; 1.162 + 1.163 + invalidate_cache(node); 1.164 + return 0; 1.165 +} 1.166 + 1.167 +int anm_use_animation(struct anm_node *node, int aidx) 1.168 +{ 1.169 + struct anm_node *child; 1.170 + 1.171 + if(anm_use_node_animation(node, aidx) == -1) { 1.172 + return -1; 1.173 + } 1.174 + 1.175 + child = node->child; 1.176 + while(child) { 1.177 + if(anm_use_animation(child, aidx) == -1) { 1.178 + return -1; 1.179 + } 1.180 + child = child->next; 1.181 + } 1.182 + return 0; 1.183 +} 1.184 + 1.185 +int anm_use_animations(struct anm_node *node, int aidx, int bidx, float t) 1.186 +{ 1.187 + struct anm_node *child; 1.188 + 1.189 + if(anm_use_node_animations(node, aidx, bidx, t) == -1) { 1.190 + return -1; 1.191 + } 1.192 + 1.193 + child = node->child; 1.194 + while(child) { 1.195 + if(anm_use_animations(child, aidx, bidx, t) == -1) { 1.196 + return -1; 1.197 + } 1.198 + child = child->next; 1.199 + } 1.200 + return 0; 1.201 + 1.202 +} 1.203 + 1.204 +int anm_get_active_animation_index(struct anm_node *node, int which) 1.205 +{ 1.206 + if(which < 0 || which >= 2) return -1; 1.207 + return node->cur_anim[which]; 1.208 +} 1.209 + 1.210 +struct anm_animation *anm_get_active_animation(struct anm_node *node, int which) 1.211 +{ 1.212 + int idx = anm_get_active_animation_index(node, which); 1.213 + if(idx < 0 || idx >= anm_get_animation_count(node)) { 1.214 + return 0; 1.215 + } 1.216 + return node->animations + idx; 1.217 +} 1.218 + 1.219 +float anm_get_active_animation_mix(struct anm_node *node) 1.220 +{ 1.221 + return node->cur_mix; 1.222 +} 1.223 + 1.224 +int anm_get_animation_count(struct anm_node *node) 1.225 +{ 1.226 + return dynarr_size(node->animations); 1.227 +} 1.228 + 1.229 +int anm_add_node_animation(struct anm_node *node) 1.230 +{ 1.231 + struct anm_animation newanim; 1.232 + anm_init_animation(&newanim); 1.233 + 1.234 + node->animations = dynarr_push(node->animations, &newanim); 1.235 + return 0; 1.236 +} 1.237 + 1.238 +int anm_remove_node_animation(struct anm_node *node, int idx) 1.239 +{ 1.240 + fprintf(stderr, "anm_remove_animation: unimplemented!"); 1.241 + abort(); 1.242 + return 0; 1.243 +} 1.244 + 1.245 +int anm_add_animation(struct anm_node *node) 1.246 +{ 1.247 + struct anm_node *child; 1.248 + 1.249 + if(anm_add_node_animation(node) == -1) { 1.250 + return -1; 1.251 + } 1.252 + 1.253 + child = node->child; 1.254 + while(child) { 1.255 + if(anm_add_animation(child)) { 1.256 + return -1; 1.257 + } 1.258 + child = child->next; 1.259 + } 1.260 + return 0; 1.261 +} 1.262 + 1.263 +int anm_remove_animation(struct anm_node *node, int idx) 1.264 +{ 1.265 + struct anm_node *child; 1.266 + 1.267 + if(anm_remove_node_animation(node, idx) == -1) { 1.268 + return -1; 1.269 + } 1.270 + 1.271 + child = node->child; 1.272 + while(child) { 1.273 + if(anm_remove_animation(child, idx) == -1) { 1.274 + return -1; 1.275 + } 1.276 + child = child->next; 1.277 + } 1.278 + return 0; 1.279 +} 1.280 + 1.281 +struct anm_animation *anm_get_animation(struct anm_node *node, int idx) 1.282 +{ 1.283 + if(idx < 0 || idx > anm_get_animation_count(node)) { 1.284 + return 0; 1.285 + } 1.286 + return node->animations + idx; 1.287 +} 1.288 + 1.289 +struct anm_animation *anm_get_animation_by_name(struct anm_node *node, const char *name) 1.290 +{ 1.291 + return anm_get_animation(node, anm_find_animation(node, name)); 1.292 +} 1.293 + 1.294 +int anm_find_animation(struct anm_node *node, const char *name) 1.295 +{ 1.296 + int i, count = anm_get_animation_count(node); 1.297 + for(i=0; i<count; i++) { 1.298 + if(strcmp(node->animations[i].name, name) == 0) { 1.299 + return i; 1.300 + } 1.301 + } 1.302 + return -1; 1.303 +} 1.304 + 1.305 +/* all the rest act on the current animation(s) */ 1.306 + 1.307 +void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in) 1.308 +{ 1.309 + int i; 1.310 + struct anm_animation *anim = anm_get_active_animation(node, 0); 1.311 + if(!anim) return; 1.312 + 1.313 + for(i=0; i<ANM_NUM_TRACKS; i++) { 1.314 + anm_set_track_interpolator(anim->tracks + i, in); 1.315 + } 1.316 + invalidate_cache(node); 1.317 +} 1.318 + 1.319 +void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex) 1.320 +{ 1.321 + int i; 1.322 + struct anm_animation *anim = anm_get_active_animation(node, 0); 1.323 + if(!anim) return; 1.324 + 1.325 + for(i=0; i<ANM_NUM_TRACKS; i++) { 1.326 + anm_set_track_extrapolator(anim->tracks + i, ex); 1.327 + } 1.328 + invalidate_cache(node); 1.329 +} 1.330 + 1.331 void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm) 1.332 { 1.333 - anm_set_value(node->tracks + ANM_TRACK_POS_X, tm, pos.x); 1.334 - anm_set_value(node->tracks + ANM_TRACK_POS_Y, tm, pos.y); 1.335 - anm_set_value(node->tracks + ANM_TRACK_POS_Z, tm, pos.z); 1.336 + struct anm_animation *anim = anm_get_active_animation(node, 0); 1.337 + if(!anim) return; 1.338 + 1.339 + anm_set_value(anim->tracks + ANM_TRACK_POS_X, tm, pos.x); 1.340 + anm_set_value(anim->tracks + ANM_TRACK_POS_Y, tm, pos.y); 1.341 + anm_set_value(anim->tracks + ANM_TRACK_POS_Z, tm, pos.z); 1.342 invalidate_cache(node); 1.343 } 1.344 1.345 vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm) 1.346 { 1.347 vec3_t v; 1.348 - v.x = anm_get_value(node->tracks + ANM_TRACK_POS_X, tm); 1.349 - v.y = anm_get_value(node->tracks + ANM_TRACK_POS_Y, tm); 1.350 - v.z = anm_get_value(node->tracks + ANM_TRACK_POS_Z, tm); 1.351 + struct anm_animation *anim0 = anm_get_active_animation(node, 0); 1.352 + struct anm_animation *anim1 = anm_get_active_animation(node, 1); 1.353 + 1.354 + if(!anim0) { 1.355 + return v3_cons(0, 0, 0); 1.356 + } 1.357 + 1.358 + v.x = anm_get_value(anim0->tracks + ANM_TRACK_POS_X, tm); 1.359 + v.y = anm_get_value(anim0->tracks + ANM_TRACK_POS_Y, tm); 1.360 + v.z = anm_get_value(anim0->tracks + ANM_TRACK_POS_Z, tm); 1.361 + 1.362 + if(anim1) { 1.363 + vec3_t v1; 1.364 + v1.x = anm_get_value(anim1->tracks + ANM_TRACK_POS_X, tm); 1.365 + v1.y = anm_get_value(anim1->tracks + ANM_TRACK_POS_Y, tm); 1.366 + v1.z = anm_get_value(anim1->tracks + ANM_TRACK_POS_Z, tm); 1.367 + 1.368 + v.x = v.x + (v1.x - v.x) * node->cur_mix; 1.369 + v.y = v.y + (v1.y - v.y) * node->cur_mix; 1.370 + v.z = v.z + (v1.z - v.z) * node->cur_mix; 1.371 + } 1.372 + 1.373 return v; 1.374 } 1.375 1.376 void anm_set_rotation(struct anm_node *node, quat_t rot, anm_time_t tm) 1.377 { 1.378 - anm_set_value(node->tracks + ANM_TRACK_ROT_X, tm, rot.x); 1.379 - anm_set_value(node->tracks + ANM_TRACK_ROT_Y, tm, rot.y); 1.380 - anm_set_value(node->tracks + ANM_TRACK_ROT_Z, tm, rot.z); 1.381 - anm_set_value(node->tracks + ANM_TRACK_ROT_W, tm, rot.w); 1.382 + struct anm_animation *anim = anm_get_active_animation(node, 0); 1.383 + if(!anim) return; 1.384 + 1.385 + anm_set_value(anim->tracks + ANM_TRACK_ROT_X, tm, rot.x); 1.386 + anm_set_value(anim->tracks + ANM_TRACK_ROT_Y, tm, rot.y); 1.387 + anm_set_value(anim->tracks + ANM_TRACK_ROT_Z, tm, rot.z); 1.388 + anm_set_value(anim->tracks + ANM_TRACK_ROT_W, tm, rot.w); 1.389 invalidate_cache(node); 1.390 } 1.391 1.392 -quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm) 1.393 +static quat_t get_node_rotation(struct anm_node *node, anm_time_t tm, struct anm_animation *anim) 1.394 { 1.395 #ifndef ROT_USE_SLERP 1.396 quat_t q; 1.397 - q.x = anm_get_value(node->tracks + ANM_TRACK_ROT_X, tm); 1.398 - q.y = anm_get_value(node->tracks + ANM_TRACK_ROT_Y, tm); 1.399 - q.z = anm_get_value(node->tracks + ANM_TRACK_ROT_Z, tm); 1.400 - q.w = anm_get_value(node->tracks + ANM_TRACK_ROT_W, tm); 1.401 + q.x = anm_get_value(anim->tracks + ANM_TRACK_ROT_X, tm); 1.402 + q.y = anm_get_value(anim->tracks + ANM_TRACK_ROT_Y, tm); 1.403 + q.z = anm_get_value(anim->tracks + ANM_TRACK_ROT_Z, tm); 1.404 + q.w = anm_get_value(anim->tracks + ANM_TRACK_ROT_W, tm); 1.405 return q; 1.406 #else 1.407 int idx0, idx1, last_idx; 1.408 @@ -217,10 +471,10 @@ 1.409 struct anm_track *track_x, *track_y, *track_z, *track_w; 1.410 quat_t q, q1, q2; 1.411 1.412 - track_x = node->tracks + ANM_TRACK_ROT_X; 1.413 - track_y = node->tracks + ANM_TRACK_ROT_Y; 1.414 - track_z = node->tracks + ANM_TRACK_ROT_Z; 1.415 - track_w = node->tracks + ANM_TRACK_ROT_W; 1.416 + track_x = anim->tracks + ANM_TRACK_ROT_X; 1.417 + track_y = anim->tracks + ANM_TRACK_ROT_Y; 1.418 + track_z = anim->tracks + ANM_TRACK_ROT_Z; 1.419 + track_w = anim->tracks + ANM_TRACK_ROT_W; 1.420 1.421 if(!track_x->count) { 1.422 q.x = track_x->def_val; 1.423 @@ -277,20 +531,62 @@ 1.424 #endif 1.425 } 1.426 1.427 +quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm) 1.428 +{ 1.429 + quat_t q; 1.430 + struct anm_animation *anim0 = anm_get_active_animation(node, 0); 1.431 + struct anm_animation *anim1 = anm_get_active_animation(node, 1); 1.432 + 1.433 + if(!anim0) { 1.434 + return quat_identity(); 1.435 + } 1.436 + 1.437 + q = get_node_rotation(node, tm, anim0); 1.438 + 1.439 + if(anim1) { 1.440 + quat_t q1 = get_node_rotation(node, tm, anim1); 1.441 + 1.442 + q = quat_slerp(q, q1, node->cur_mix); 1.443 + } 1.444 + return q; 1.445 +} 1.446 + 1.447 void anm_set_scaling(struct anm_node *node, vec3_t scl, anm_time_t tm) 1.448 { 1.449 - anm_set_value(node->tracks + ANM_TRACK_SCL_X, tm, scl.x); 1.450 - anm_set_value(node->tracks + ANM_TRACK_SCL_Y, tm, scl.y); 1.451 - anm_set_value(node->tracks + ANM_TRACK_SCL_Z, tm, scl.z); 1.452 + struct anm_animation *anim = anm_get_active_animation(node, 0); 1.453 + if(!anim) return; 1.454 + 1.455 + anm_set_value(anim->tracks + ANM_TRACK_SCL_X, tm, scl.x); 1.456 + anm_set_value(anim->tracks + ANM_TRACK_SCL_Y, tm, scl.y); 1.457 + anm_set_value(anim->tracks + ANM_TRACK_SCL_Z, tm, scl.z); 1.458 invalidate_cache(node); 1.459 } 1.460 1.461 vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm) 1.462 { 1.463 vec3_t v; 1.464 - v.x = anm_get_value(node->tracks + ANM_TRACK_SCL_X, tm); 1.465 - v.y = anm_get_value(node->tracks + ANM_TRACK_SCL_Y, tm); 1.466 - v.z = anm_get_value(node->tracks + ANM_TRACK_SCL_Z, tm); 1.467 + struct anm_animation *anim0 = anm_get_active_animation(node, 0); 1.468 + struct anm_animation *anim1 = anm_get_active_animation(node, 1); 1.469 + 1.470 + if(!anim0) { 1.471 + return v3_cons(1, 1, 1); 1.472 + } 1.473 + 1.474 + v.x = anm_get_value(anim0->tracks + ANM_TRACK_SCL_X, tm); 1.475 + v.y = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Y, tm); 1.476 + v.z = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Z, tm); 1.477 + 1.478 + if(anim1) { 1.479 + vec3_t v1; 1.480 + v1.x = anm_get_value(anim1->tracks + ANM_TRACK_SCL_X, tm); 1.481 + v1.y = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Y, tm); 1.482 + v1.z = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Z, tm); 1.483 + 1.484 + v.x = v.x + (v1.x - v.x) * node->cur_mix; 1.485 + v.y = v.y + (v1.y - v.y) * node->cur_mix; 1.486 + v.z = v.z + (v1.z - v.z) * node->cur_mix; 1.487 + } 1.488 + 1.489 return v; 1.490 } 1.491 1.492 @@ -334,16 +630,6 @@ 1.493 return v3_mul(s, ps); 1.494 } 1.495 1.496 -void anm_set_pivot(struct anm_node *node, vec3_t piv) 1.497 -{ 1.498 - node->pivot = piv; 1.499 -} 1.500 - 1.501 -vec3_t anm_get_pivot(struct anm_node *node) 1.502 -{ 1.503 - return node->pivot; 1.504 -} 1.505 - 1.506 void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm) 1.507 { 1.508 int i; 1.509 @@ -463,15 +749,20 @@ 1.510 1.511 anm_time_t anm_get_start_time(struct anm_node *node) 1.512 { 1.513 - int i; 1.514 + int i, j; 1.515 struct anm_node *c; 1.516 anm_time_t res = LONG_MAX; 1.517 1.518 - for(i=0; i<ANM_NUM_TRACKS; i++) { 1.519 - if(node->tracks[i].count) { 1.520 - anm_time_t tm = node->tracks[i].keys[0].time; 1.521 - if(tm < res) { 1.522 - res = tm; 1.523 + for(j=0; j<2; j++) { 1.524 + struct anm_animation *anim = anm_get_active_animation(node, j); 1.525 + if(!anim) break; 1.526 + 1.527 + for(i=0; i<ANM_NUM_TRACKS; i++) { 1.528 + if(anim->tracks[i].count) { 1.529 + anm_time_t tm = anim->tracks[i].keys[0].time; 1.530 + if(tm < res) { 1.531 + res = tm; 1.532 + } 1.533 } 1.534 } 1.535 } 1.536 @@ -489,15 +780,20 @@ 1.537 1.538 anm_time_t anm_get_end_time(struct anm_node *node) 1.539 { 1.540 - int i; 1.541 + int i, j; 1.542 struct anm_node *c; 1.543 anm_time_t res = LONG_MIN; 1.544 1.545 - for(i=0; i<ANM_NUM_TRACKS; i++) { 1.546 - if(node->tracks[i].count) { 1.547 - anm_time_t tm = node->tracks[i].keys[node->tracks[i].count - 1].time; 1.548 - if(tm > res) { 1.549 - res = tm; 1.550 + for(j=0; j<2; j++) { 1.551 + struct anm_animation *anim = anm_get_active_animation(node, j); 1.552 + if(!anim) break; 1.553 + 1.554 + for(i=0; i<ANM_NUM_TRACKS; i++) { 1.555 + if(anim->tracks[i].count) { 1.556 + anm_time_t tm = anim->tracks[i].keys[anim->tracks[i].count - 1].time; 1.557 + if(tm > res) { 1.558 + res = tm; 1.559 + } 1.560 } 1.561 } 1.562 }