goat3d
changeset 49:0ecb788a87f7
merged changes from libanim
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 16 Jan 2014 19:13:45 +0200 |
parents | 9ef9de80649c |
children | 0be413ac2e0a |
files | libs/anim/anim.c libs/anim/anim.h libs/anim/dynarr.h libs/anim/track.c libs/anim/track.h |
diffstat | 5 files changed, 699 insertions(+), 103 deletions(-) [+] |
line diff
1.1 --- a/libs/anim/anim.c Sun Dec 29 06:01:59 2013 +0200 1.2 +++ b/libs/anim/anim.c Thu Jan 16 19:13:45 2014 +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,19 +17,59 @@ 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 +void anm_set_animation_name(struct anm_animation *anim, const char *name) 1.39 +{ 1.40 + char *newname = malloc(strlen(name) + 1); 1.41 + if(!newname) return; 1.42 + 1.43 + strcpy(newname, name); 1.44 + 1.45 + free(anim->name); 1.46 + anim->name = newname; 1.47 +} 1.48 + 1.49 +/* ---- node implementation ----- */ 1.50 + 1.51 +int anm_init_node(struct anm_node *node) 1.52 +{ 1.53 memset(node, 0, sizeof *node); 1.54 1.55 - for(i=0; i<ANM_NUM_TRACKS; i++) { 1.56 - if(anm_init_track(node->tracks + i) == -1) { 1.57 - for(j=0; j<i; j++) { 1.58 - anm_destroy_track(node->tracks + i); 1.59 - } 1.60 - } 1.61 - anm_set_track_default(node->tracks + i, defaults[i]); 1.62 + node->cur_anim[1] = -1; 1.63 + 1.64 + if(!(node->animations = dynarr_alloc(1, sizeof *node->animations))) { 1.65 + return -1; 1.66 + } 1.67 + if(anm_init_animation(node->animations) == -1) { 1.68 + dynarr_free(node->animations); 1.69 + return -1; 1.70 } 1.71 1.72 - node->cache.time = ANM_TIME_INVAL; 1.73 - node->cache.inv_time = ANM_TIME_INVAL; 1.74 + /* initialize thread-local matrix cache */ 1.75 + pthread_key_create(&node->cache_key, 0); 1.76 + pthread_mutex_init(&node->cache_list_lock, 0); 1.77 + 1.78 return 0; 1.79 } 1.80 1.81 @@ -39,7 +79,17 @@ 1.82 free(node->name); 1.83 1.84 for(i=0; i<ANM_NUM_TRACKS; i++) { 1.85 - anm_destroy_track(node->tracks + i); 1.86 + anm_destroy_animation(node->animations + i); 1.87 + } 1.88 + dynarr_free(node->animations); 1.89 + 1.90 + /* destroy thread-specific cache */ 1.91 + pthread_key_delete(node->cache_key); 1.92 + 1.93 + while(node->cache_list) { 1.94 + struct mat_cache *tmp = node->cache_list; 1.95 + node->cache_list = tmp->next; 1.96 + free(tmp); 1.97 } 1.98 } 1.99 1.100 @@ -113,26 +163,6 @@ 1.101 return node->name ? node->name : ""; 1.102 } 1.103 1.104 -void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in) 1.105 -{ 1.106 - int i; 1.107 - 1.108 - for(i=0; i<ANM_NUM_TRACKS; i++) { 1.109 - anm_set_track_interpolator(node->tracks + i, in); 1.110 - } 1.111 - invalidate_cache(node); 1.112 -} 1.113 - 1.114 -void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex) 1.115 -{ 1.116 - int i; 1.117 - 1.118 - for(i=0; i<ANM_NUM_TRACKS; i++) { 1.119 - anm_set_track_extrapolator(node->tracks + i, ex); 1.120 - } 1.121 - invalidate_cache(node); 1.122 -} 1.123 - 1.124 void anm_link_node(struct anm_node *p, struct anm_node *c) 1.125 { 1.126 c->next = p->child; 1.127 @@ -165,40 +195,398 @@ 1.128 return -1; 1.129 } 1.130 1.131 +void anm_set_pivot(struct anm_node *node, vec3_t piv) 1.132 +{ 1.133 + node->pivot = piv; 1.134 +} 1.135 + 1.136 +vec3_t anm_get_pivot(struct anm_node *node) 1.137 +{ 1.138 + return node->pivot; 1.139 +} 1.140 + 1.141 + 1.142 +/* animation management */ 1.143 + 1.144 +int anm_use_node_animation(struct anm_node *node, int aidx) 1.145 +{ 1.146 + if(aidx == node->cur_anim[0] && node->cur_anim[1] == -1) { 1.147 + return 0; /* no change, no invalidation */ 1.148 + } 1.149 + 1.150 + if(aidx < 0 || aidx >= anm_get_animation_count(node)) { 1.151 + return -1; 1.152 + } 1.153 + 1.154 + node->cur_anim[0] = aidx; 1.155 + node->cur_anim[1] = -1; 1.156 + node->cur_mix = 0; 1.157 + node->blend_dur = -1; 1.158 + 1.159 + invalidate_cache(node); 1.160 + return 0; 1.161 +} 1.162 + 1.163 +int anm_use_node_animations(struct anm_node *node, int aidx, int bidx, float t) 1.164 +{ 1.165 + int num_anim; 1.166 + 1.167 + if(node->cur_anim[0] == aidx && node->cur_anim[1] == bidx && 1.168 + fabs(t - node->cur_mix) < 1e-6) { 1.169 + return 0; /* no change, no invalidation */ 1.170 + } 1.171 + 1.172 + num_anim = anm_get_animation_count(node); 1.173 + if(aidx < 0 || aidx >= num_anim) { 1.174 + return anm_use_animation(node, bidx); 1.175 + } 1.176 + if(bidx < 0 || bidx >= num_anim) { 1.177 + return anm_use_animation(node, aidx); 1.178 + } 1.179 + node->cur_anim[0] = aidx; 1.180 + node->cur_anim[1] = bidx; 1.181 + node->cur_mix = t; 1.182 + 1.183 + invalidate_cache(node); 1.184 + return 0; 1.185 +} 1.186 + 1.187 +int anm_use_animation(struct anm_node *node, int aidx) 1.188 +{ 1.189 + struct anm_node *child; 1.190 + 1.191 + if(anm_use_node_animation(node, aidx) == -1) { 1.192 + return -1; 1.193 + } 1.194 + 1.195 + child = node->child; 1.196 + while(child) { 1.197 + if(anm_use_animation(child, aidx) == -1) { 1.198 + return -1; 1.199 + } 1.200 + child = child->next; 1.201 + } 1.202 + return 0; 1.203 +} 1.204 + 1.205 +int anm_use_animations(struct anm_node *node, int aidx, int bidx, float t) 1.206 +{ 1.207 + struct anm_node *child; 1.208 + 1.209 + if(anm_use_node_animations(node, aidx, bidx, t) == -1) { 1.210 + return -1; 1.211 + } 1.212 + 1.213 + child = node->child; 1.214 + while(child) { 1.215 + if(anm_use_animations(child, aidx, bidx, t) == -1) { 1.216 + return -1; 1.217 + } 1.218 + child = child->next; 1.219 + } 1.220 + return 0; 1.221 + 1.222 +} 1.223 + 1.224 +void anm_set_node_animation_offset(struct anm_node *node, anm_time_t offs, int which) 1.225 +{ 1.226 + if(which < 0 || which >= 2) { 1.227 + return; 1.228 + } 1.229 + node->cur_anim_offset[which] = offs; 1.230 +} 1.231 + 1.232 +anm_time_t anm_get_animation_offset(const struct anm_node *node, int which) 1.233 +{ 1.234 + if(which < 0 || which >= 2) { 1.235 + return 0; 1.236 + } 1.237 + return node->cur_anim_offset[which]; 1.238 +} 1.239 + 1.240 +void anm_set_animation_offset(struct anm_node *node, anm_time_t offs, int which) 1.241 +{ 1.242 + struct anm_node *c = node->child; 1.243 + while(c) { 1.244 + anm_set_animation_offset(c, offs, which); 1.245 + c = c->next; 1.246 + } 1.247 + 1.248 + anm_set_node_animation_offset(node, offs, which); 1.249 +} 1.250 + 1.251 +int anm_get_active_animation_index(const struct anm_node *node, int which) 1.252 +{ 1.253 + if(which < 0 || which >= 2) return -1; 1.254 + return node->cur_anim[which]; 1.255 +} 1.256 + 1.257 +struct anm_animation *anm_get_active_animation(const struct anm_node *node, int which) 1.258 +{ 1.259 + int idx = anm_get_active_animation_index(node, which); 1.260 + if(idx < 0 || idx >= anm_get_animation_count(node)) { 1.261 + return 0; 1.262 + } 1.263 + return node->animations + idx; 1.264 +} 1.265 + 1.266 +float anm_get_active_animation_mix(const struct anm_node *node) 1.267 +{ 1.268 + return node->cur_mix; 1.269 +} 1.270 + 1.271 +int anm_get_animation_count(const struct anm_node *node) 1.272 +{ 1.273 + return dynarr_size(node->animations); 1.274 +} 1.275 + 1.276 +int anm_add_node_animation(struct anm_node *node) 1.277 +{ 1.278 + struct anm_animation newanim; 1.279 + anm_init_animation(&newanim); 1.280 + 1.281 + node->animations = dynarr_push(node->animations, &newanim); 1.282 + return 0; 1.283 +} 1.284 + 1.285 +int anm_remove_node_animation(struct anm_node *node, int idx) 1.286 +{ 1.287 + fprintf(stderr, "anm_remove_animation: unimplemented!"); 1.288 + abort(); 1.289 + return 0; 1.290 +} 1.291 + 1.292 +int anm_add_animation(struct anm_node *node) 1.293 +{ 1.294 + struct anm_node *child; 1.295 + 1.296 + if(anm_add_node_animation(node) == -1) { 1.297 + return -1; 1.298 + } 1.299 + 1.300 + child = node->child; 1.301 + while(child) { 1.302 + if(anm_add_animation(child)) { 1.303 + return -1; 1.304 + } 1.305 + child = child->next; 1.306 + } 1.307 + return 0; 1.308 +} 1.309 + 1.310 +int anm_remove_animation(struct anm_node *node, int idx) 1.311 +{ 1.312 + struct anm_node *child; 1.313 + 1.314 + if(anm_remove_node_animation(node, idx) == -1) { 1.315 + return -1; 1.316 + } 1.317 + 1.318 + child = node->child; 1.319 + while(child) { 1.320 + if(anm_remove_animation(child, idx) == -1) { 1.321 + return -1; 1.322 + } 1.323 + child = child->next; 1.324 + } 1.325 + return 0; 1.326 +} 1.327 + 1.328 +struct anm_animation *anm_get_animation(struct anm_node *node, int idx) 1.329 +{ 1.330 + if(idx < 0 || idx > anm_get_animation_count(node)) { 1.331 + return 0; 1.332 + } 1.333 + return node->animations + idx; 1.334 +} 1.335 + 1.336 +struct anm_animation *anm_get_animation_by_name(struct anm_node *node, const char *name) 1.337 +{ 1.338 + return anm_get_animation(node, anm_find_animation(node, name)); 1.339 +} 1.340 + 1.341 +int anm_find_animation(struct anm_node *node, const char *name) 1.342 +{ 1.343 + int i, count = anm_get_animation_count(node); 1.344 + for(i=0; i<count; i++) { 1.345 + if(strcmp(node->animations[i].name, name) == 0) { 1.346 + return i; 1.347 + } 1.348 + } 1.349 + return -1; 1.350 +} 1.351 + 1.352 +/* all the rest act on the current animation(s) */ 1.353 + 1.354 +void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in) 1.355 +{ 1.356 + int i; 1.357 + struct anm_animation *anim = anm_get_active_animation(node, 0); 1.358 + if(!anim) return; 1.359 + 1.360 + for(i=0; i<ANM_NUM_TRACKS; i++) { 1.361 + anm_set_track_interpolator(anim->tracks + i, in); 1.362 + } 1.363 + invalidate_cache(node); 1.364 +} 1.365 + 1.366 +void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex) 1.367 +{ 1.368 + int i; 1.369 + struct anm_animation *anim = anm_get_active_animation(node, 0); 1.370 + if(!anim) return; 1.371 + 1.372 + for(i=0; i<ANM_NUM_TRACKS; i++) { 1.373 + anm_set_track_extrapolator(anim->tracks + i, ex); 1.374 + } 1.375 + invalidate_cache(node); 1.376 +} 1.377 + 1.378 +void anm_set_node_active_animation_name(struct anm_node *node, const char *name) 1.379 +{ 1.380 + struct anm_animation *anim = anm_get_active_animation(node, 0); 1.381 + if(!anim) return; 1.382 + 1.383 + anm_set_animation_name(anim, name); 1.384 +} 1.385 + 1.386 +void anm_set_active_animation_name(struct anm_node *node, const char *name) 1.387 +{ 1.388 + struct anm_node *child; 1.389 + 1.390 + anm_set_node_active_animation_name(node, name); 1.391 + 1.392 + child = node->child; 1.393 + while(child) { 1.394 + anm_set_active_animation_name(child, name); 1.395 + child = child->next; 1.396 + } 1.397 +} 1.398 + 1.399 +const char *anm_get_active_animation_name(struct anm_node *node) 1.400 +{ 1.401 + struct anm_animation *anim = anm_get_active_animation(node, 0); 1.402 + if(anim) { 1.403 + return anim->name; 1.404 + } 1.405 + return 0; 1.406 +} 1.407 + 1.408 +/* ---- high level animation blending ---- */ 1.409 +void anm_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur) 1.410 +{ 1.411 + struct anm_node *c = node->child; 1.412 + 1.413 + if(anmidx == node->cur_anim[0]) { 1.414 + return; 1.415 + } 1.416 + 1.417 + while(c) { 1.418 + anm_transition(c, anmidx, start, dur); 1.419 + c = c->next; 1.420 + } 1.421 + 1.422 + anm_node_transition(node, anmidx, start, dur); 1.423 +} 1.424 + 1.425 +void anm_node_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur) 1.426 +{ 1.427 + if(anmidx == node->cur_anim[0]) { 1.428 + return; 1.429 + } 1.430 + 1.431 + node->cur_anim[1] = anmidx; 1.432 + node->cur_anim_offset[1] = start; 1.433 + node->blend_dur = dur; 1.434 +} 1.435 + 1.436 + 1.437 +#define BLEND_START_TM node->cur_anim_offset[1] 1.438 + 1.439 +static anm_time_t animation_time(struct anm_node *node, anm_time_t tm, int which) 1.440 +{ 1.441 + float t; 1.442 + 1.443 + if(node->blend_dur >= 0) { 1.444 + /* we're in transition... */ 1.445 + t = (float)(tm - BLEND_START_TM) / (float)node->blend_dur; 1.446 + if(t < 0.0) t = 0.0; 1.447 + 1.448 + node->cur_mix = t; 1.449 + 1.450 + if(t > 1.0) { 1.451 + /* switch completely over to the target animation and stop blending */ 1.452 + anm_use_node_animation(node, node->cur_anim[1]); 1.453 + node->cur_anim_offset[0] = node->cur_anim_offset[1]; 1.454 + } 1.455 + } 1.456 + 1.457 + return tm - node->cur_anim_offset[which]; 1.458 +} 1.459 + 1.460 + 1.461 void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm) 1.462 { 1.463 - anm_set_value(node->tracks + ANM_TRACK_POS_X, tm, pos.x); 1.464 - anm_set_value(node->tracks + ANM_TRACK_POS_Y, tm, pos.y); 1.465 - anm_set_value(node->tracks + ANM_TRACK_POS_Z, tm, pos.z); 1.466 + struct anm_animation *anim = anm_get_active_animation(node, 0); 1.467 + if(!anim) return; 1.468 + 1.469 + anm_set_value(anim->tracks + ANM_TRACK_POS_X, tm, pos.x); 1.470 + anm_set_value(anim->tracks + ANM_TRACK_POS_Y, tm, pos.y); 1.471 + anm_set_value(anim->tracks + ANM_TRACK_POS_Z, tm, pos.z); 1.472 invalidate_cache(node); 1.473 } 1.474 1.475 + 1.476 vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm) 1.477 { 1.478 vec3_t v; 1.479 - v.x = anm_get_value(node->tracks + ANM_TRACK_POS_X, tm); 1.480 - v.y = anm_get_value(node->tracks + ANM_TRACK_POS_Y, tm); 1.481 - v.z = anm_get_value(node->tracks + ANM_TRACK_POS_Z, tm); 1.482 + anm_time_t tm0 = animation_time(node, tm, 0); 1.483 + struct anm_animation *anim0 = anm_get_active_animation(node, 0); 1.484 + struct anm_animation *anim1 = anm_get_active_animation(node, 1); 1.485 + 1.486 + if(!anim0) { 1.487 + return v3_cons(0, 0, 0); 1.488 + } 1.489 + 1.490 + v.x = anm_get_value(anim0->tracks + ANM_TRACK_POS_X, tm0); 1.491 + v.y = anm_get_value(anim0->tracks + ANM_TRACK_POS_Y, tm0); 1.492 + v.z = anm_get_value(anim0->tracks + ANM_TRACK_POS_Z, tm0); 1.493 + 1.494 + if(anim1) { 1.495 + vec3_t v1; 1.496 + anm_time_t tm1 = animation_time(node, tm, 1); 1.497 + v1.x = anm_get_value(anim1->tracks + ANM_TRACK_POS_X, tm1); 1.498 + v1.y = anm_get_value(anim1->tracks + ANM_TRACK_POS_Y, tm1); 1.499 + v1.z = anm_get_value(anim1->tracks + ANM_TRACK_POS_Z, tm1); 1.500 + 1.501 + v.x = v.x + (v1.x - v.x) * node->cur_mix; 1.502 + v.y = v.y + (v1.y - v.y) * node->cur_mix; 1.503 + v.z = v.z + (v1.z - v.z) * node->cur_mix; 1.504 + } 1.505 + 1.506 return v; 1.507 } 1.508 1.509 void anm_set_rotation(struct anm_node *node, quat_t rot, anm_time_t tm) 1.510 { 1.511 - anm_set_value(node->tracks + ANM_TRACK_ROT_X, tm, rot.x); 1.512 - anm_set_value(node->tracks + ANM_TRACK_ROT_Y, tm, rot.y); 1.513 - anm_set_value(node->tracks + ANM_TRACK_ROT_Z, tm, rot.z); 1.514 - anm_set_value(node->tracks + ANM_TRACK_ROT_W, tm, rot.w); 1.515 + struct anm_animation *anim = anm_get_active_animation(node, 0); 1.516 + if(!anim) return; 1.517 + 1.518 + anm_set_value(anim->tracks + ANM_TRACK_ROT_X, tm, rot.x); 1.519 + anm_set_value(anim->tracks + ANM_TRACK_ROT_Y, tm, rot.y); 1.520 + anm_set_value(anim->tracks + ANM_TRACK_ROT_Z, tm, rot.z); 1.521 + anm_set_value(anim->tracks + ANM_TRACK_ROT_W, tm, rot.w); 1.522 invalidate_cache(node); 1.523 } 1.524 1.525 -quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm) 1.526 +static quat_t get_node_rotation(struct anm_node *node, anm_time_t tm, struct anm_animation *anim) 1.527 { 1.528 #ifndef ROT_USE_SLERP 1.529 quat_t q; 1.530 - q.x = anm_get_value(node->tracks + ANM_TRACK_ROT_X, tm); 1.531 - q.y = anm_get_value(node->tracks + ANM_TRACK_ROT_Y, tm); 1.532 - q.z = anm_get_value(node->tracks + ANM_TRACK_ROT_Z, tm); 1.533 - q.w = anm_get_value(node->tracks + ANM_TRACK_ROT_W, tm); 1.534 + q.x = anm_get_value(anim->tracks + ANM_TRACK_ROT_X, tm); 1.535 + q.y = anm_get_value(anim->tracks + ANM_TRACK_ROT_Y, tm); 1.536 + q.z = anm_get_value(anim->tracks + ANM_TRACK_ROT_Z, tm); 1.537 + q.w = anm_get_value(anim->tracks + ANM_TRACK_ROT_W, tm); 1.538 return q; 1.539 #else 1.540 int idx0, idx1, last_idx; 1.541 @@ -207,10 +595,10 @@ 1.542 struct anm_track *track_x, *track_y, *track_z, *track_w; 1.543 quat_t q, q1, q2; 1.544 1.545 - track_x = node->tracks + ANM_TRACK_ROT_X; 1.546 - track_y = node->tracks + ANM_TRACK_ROT_Y; 1.547 - track_z = node->tracks + ANM_TRACK_ROT_Z; 1.548 - track_w = node->tracks + ANM_TRACK_ROT_W; 1.549 + track_x = anim->tracks + ANM_TRACK_ROT_X; 1.550 + track_y = anim->tracks + ANM_TRACK_ROT_Y; 1.551 + track_z = anim->tracks + ANM_TRACK_ROT_Z; 1.552 + track_w = anim->tracks + ANM_TRACK_ROT_W; 1.553 1.554 if(!track_x->count) { 1.555 q.x = track_x->def_val; 1.556 @@ -267,20 +655,66 @@ 1.557 #endif 1.558 } 1.559 1.560 +quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm) 1.561 +{ 1.562 + quat_t q; 1.563 + anm_time_t tm0 = animation_time(node, tm, 0); 1.564 + struct anm_animation *anim0 = anm_get_active_animation(node, 0); 1.565 + struct anm_animation *anim1 = anm_get_active_animation(node, 1); 1.566 + 1.567 + if(!anim0) { 1.568 + return quat_identity(); 1.569 + } 1.570 + 1.571 + q = get_node_rotation(node, tm0, anim0); 1.572 + 1.573 + if(anim1) { 1.574 + anm_time_t tm1 = animation_time(node, tm, 1); 1.575 + quat_t q1 = get_node_rotation(node, tm1, anim1); 1.576 + 1.577 + q = quat_slerp(q, q1, node->cur_mix); 1.578 + } 1.579 + return q; 1.580 +} 1.581 + 1.582 void anm_set_scaling(struct anm_node *node, vec3_t scl, anm_time_t tm) 1.583 { 1.584 - anm_set_value(node->tracks + ANM_TRACK_SCL_X, tm, scl.x); 1.585 - anm_set_value(node->tracks + ANM_TRACK_SCL_Y, tm, scl.y); 1.586 - anm_set_value(node->tracks + ANM_TRACK_SCL_Z, tm, scl.z); 1.587 + struct anm_animation *anim = anm_get_active_animation(node, 0); 1.588 + if(!anim) return; 1.589 + 1.590 + anm_set_value(anim->tracks + ANM_TRACK_SCL_X, tm, scl.x); 1.591 + anm_set_value(anim->tracks + ANM_TRACK_SCL_Y, tm, scl.y); 1.592 + anm_set_value(anim->tracks + ANM_TRACK_SCL_Z, tm, scl.z); 1.593 invalidate_cache(node); 1.594 } 1.595 1.596 vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm) 1.597 { 1.598 vec3_t v; 1.599 - v.x = anm_get_value(node->tracks + ANM_TRACK_SCL_X, tm); 1.600 - v.y = anm_get_value(node->tracks + ANM_TRACK_SCL_Y, tm); 1.601 - v.z = anm_get_value(node->tracks + ANM_TRACK_SCL_Z, tm); 1.602 + anm_time_t tm0 = animation_time(node, tm, 0); 1.603 + struct anm_animation *anim0 = anm_get_active_animation(node, 0); 1.604 + struct anm_animation *anim1 = anm_get_active_animation(node, 1); 1.605 + 1.606 + if(!anim0) { 1.607 + return v3_cons(1, 1, 1); 1.608 + } 1.609 + 1.610 + v.x = anm_get_value(anim0->tracks + ANM_TRACK_SCL_X, tm0); 1.611 + v.y = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Y, tm0); 1.612 + v.z = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Z, tm0); 1.613 + 1.614 + if(anim1) { 1.615 + vec3_t v1; 1.616 + anm_time_t tm1 = animation_time(node, tm, 1); 1.617 + v1.x = anm_get_value(anim1->tracks + ANM_TRACK_SCL_X, tm1); 1.618 + v1.y = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Y, tm1); 1.619 + v1.z = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Z, tm1); 1.620 + 1.621 + v.x = v.x + (v1.x - v.x) * node->cur_mix; 1.622 + v.y = v.y + (v1.y - v.y) * node->cur_mix; 1.623 + v.z = v.z + (v1.z - v.z) * node->cur_mix; 1.624 + } 1.625 + 1.626 return v; 1.627 } 1.628 1.629 @@ -324,16 +758,6 @@ 1.630 return v3_mul(s, ps); 1.631 } 1.632 1.633 -void anm_set_pivot(struct anm_node *node, vec3_t piv) 1.634 -{ 1.635 - node->pivot = piv; 1.636 -} 1.637 - 1.638 -vec3_t anm_get_pivot(struct anm_node *node) 1.639 -{ 1.640 - return node->pivot; 1.641 -} 1.642 - 1.643 void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm) 1.644 { 1.645 int i; 1.646 @@ -371,43 +795,102 @@ 1.647 m4_inverse(mat, tmp); 1.648 } 1.649 1.650 +void anm_eval_node(struct anm_node *node, anm_time_t tm) 1.651 +{ 1.652 + anm_get_node_matrix(node, node->matrix, tm); 1.653 +} 1.654 + 1.655 +void anm_eval(struct anm_node *node, anm_time_t tm) 1.656 +{ 1.657 + struct anm_node *c; 1.658 + 1.659 + anm_eval_node(node, tm); 1.660 + 1.661 + if(node->parent) { 1.662 + /* due to post-order traversal, the parent matrix is already evaluated */ 1.663 + m4_mult(node->matrix, node->parent->matrix, node->matrix); 1.664 + } 1.665 + 1.666 + /* recersively evaluate all children */ 1.667 + c = node->child; 1.668 + while(c) { 1.669 + anm_eval(c, tm); 1.670 + c = c->next; 1.671 + } 1.672 +} 1.673 + 1.674 void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm) 1.675 { 1.676 - if(node->cache.time != tm) { 1.677 - anm_get_node_matrix(node, node->cache.matrix, tm); 1.678 + struct mat_cache *cache = pthread_getspecific(node->cache_key); 1.679 + if(!cache) { 1.680 + cache = malloc(sizeof *cache); 1.681 + assert(cache); 1.682 + 1.683 + pthread_mutex_lock(&node->cache_list_lock); 1.684 + cache->next = node->cache_list; 1.685 + node->cache_list = cache; 1.686 + pthread_mutex_unlock(&node->cache_list_lock); 1.687 + 1.688 + cache->time = ANM_TIME_INVAL; 1.689 + cache->inv_time = ANM_TIME_INVAL; 1.690 + pthread_setspecific(node->cache_key, cache); 1.691 + } 1.692 + 1.693 + if(cache->time != tm) { 1.694 + anm_get_node_matrix(node, cache->matrix, tm); 1.695 1.696 if(node->parent) { 1.697 mat4_t parent_mat; 1.698 1.699 anm_get_matrix(node->parent, parent_mat, tm); 1.700 - m4_mult(node->cache.matrix, parent_mat, node->cache.matrix); 1.701 + m4_mult(cache->matrix, parent_mat, cache->matrix); 1.702 } 1.703 - node->cache.time = tm; 1.704 + cache->time = tm; 1.705 } 1.706 - m4_copy(mat, node->cache.matrix); 1.707 + m4_copy(mat, cache->matrix); 1.708 } 1.709 1.710 void anm_get_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm) 1.711 { 1.712 - if(node->cache.inv_time != tm) { 1.713 + struct mat_cache *cache = pthread_getspecific(node->cache_key); 1.714 + if(!cache) { 1.715 + cache = malloc(sizeof *cache); 1.716 + assert(cache); 1.717 + 1.718 + pthread_mutex_lock(&node->cache_list_lock); 1.719 + cache->next = node->cache_list; 1.720 + node->cache_list = cache; 1.721 + pthread_mutex_unlock(&node->cache_list_lock); 1.722 + 1.723 + cache->inv_time = ANM_TIME_INVAL; 1.724 + cache->inv_time = ANM_TIME_INVAL; 1.725 + pthread_setspecific(node->cache_key, cache); 1.726 + } 1.727 + 1.728 + if(cache->inv_time != tm) { 1.729 anm_get_matrix(node, mat, tm); 1.730 - m4_inverse(node->cache.inv_matrix, mat); 1.731 - node->cache.inv_time = tm; 1.732 + m4_inverse(cache->inv_matrix, mat); 1.733 + cache->inv_time = tm; 1.734 } 1.735 - m4_copy(mat, node->cache.inv_matrix); 1.736 + m4_copy(mat, cache->inv_matrix); 1.737 } 1.738 1.739 anm_time_t anm_get_start_time(struct anm_node *node) 1.740 { 1.741 - int i; 1.742 + int i, j; 1.743 struct anm_node *c; 1.744 anm_time_t res = LONG_MAX; 1.745 1.746 - for(i=0; i<ANM_NUM_TRACKS; i++) { 1.747 - if(node->tracks[i].count) { 1.748 - anm_time_t tm = node->tracks[i].keys[0].time; 1.749 - if(tm < res) { 1.750 - res = tm; 1.751 + for(j=0; j<2; j++) { 1.752 + struct anm_animation *anim = anm_get_active_animation(node, j); 1.753 + if(!anim) break; 1.754 + 1.755 + for(i=0; i<ANM_NUM_TRACKS; i++) { 1.756 + if(anim->tracks[i].count) { 1.757 + anm_time_t tm = anim->tracks[i].keys[0].time; 1.758 + if(tm < res) { 1.759 + res = tm; 1.760 + } 1.761 } 1.762 } 1.763 } 1.764 @@ -425,15 +908,20 @@ 1.765 1.766 anm_time_t anm_get_end_time(struct anm_node *node) 1.767 { 1.768 - int i; 1.769 + int i, j; 1.770 struct anm_node *c; 1.771 anm_time_t res = LONG_MIN; 1.772 1.773 - for(i=0; i<ANM_NUM_TRACKS; i++) { 1.774 - if(node->tracks[i].count) { 1.775 - anm_time_t tm = node->tracks[i].keys[node->tracks[i].count - 1].time; 1.776 - if(tm > res) { 1.777 - res = tm; 1.778 + for(j=0; j<2; j++) { 1.779 + struct anm_animation *anim = anm_get_active_animation(node, j); 1.780 + if(!anim) break; 1.781 + 1.782 + for(i=0; i<ANM_NUM_TRACKS; i++) { 1.783 + if(anim->tracks[i].count) { 1.784 + anm_time_t tm = anim->tracks[i].keys[anim->tracks[i].count - 1].time; 1.785 + if(tm > res) { 1.786 + res = tm; 1.787 + } 1.788 } 1.789 } 1.790 } 1.791 @@ -451,5 +939,8 @@ 1.792 1.793 static void invalidate_cache(struct anm_node *node) 1.794 { 1.795 - node->cache.time = node->cache.inv_time = ANM_TIME_INVAL; 1.796 + struct mat_cache *cache = pthread_getspecific(node->cache_key); 1.797 + if(cache) { 1.798 + cache->time = cache->inv_time = ANM_TIME_INVAL; 1.799 + } 1.800 }
2.1 --- a/libs/anim/anim.h Sun Dec 29 06:01:59 2013 +0200 2.2 +++ b/libs/anim/anim.h Thu Jan 16 19:13:45 2014 +0200 2.3 @@ -3,6 +3,8 @@ 2.4 2.5 #include "config.h" 2.6 2.7 +#include <pthread.h> 2.8 + 2.9 #include <vmath/vector.h> 2.10 #include <vmath/quat.h> 2.11 #include <vmath/matrix.h> 2.12 @@ -25,17 +27,35 @@ 2.13 ANM_NUM_TRACKS 2.14 }; 2.15 2.16 +struct anm_animation { 2.17 + char *name; 2.18 + struct anm_track tracks[ANM_NUM_TRACKS]; 2.19 +}; 2.20 + 2.21 struct anm_node { 2.22 char *name; 2.23 2.24 - struct anm_track tracks[ANM_NUM_TRACKS]; 2.25 + int cur_anim[2]; 2.26 + anm_time_t cur_anim_offset[2]; 2.27 + float cur_mix; 2.28 + 2.29 + /* high-level animation blending transition duration */ 2.30 + anm_time_t blend_dur; 2.31 + 2.32 + struct anm_animation *animations; 2.33 vec3_t pivot; 2.34 2.35 /* matrix cache */ 2.36 struct mat_cache { 2.37 mat4_t matrix, inv_matrix; 2.38 anm_time_t time, inv_time; 2.39 - } cache; 2.40 + struct mat_cache *next; 2.41 + } *cache_list; 2.42 + pthread_key_t cache_key; 2.43 + pthread_mutex_t cache_list_lock; 2.44 + 2.45 + /* matrix calculated by anm_eval functions (no locking, meant as a pre-pass) */ 2.46 + mat4_t matrix; 2.47 2.48 struct anm_node *parent; 2.49 struct anm_node *child; 2.50 @@ -46,6 +66,14 @@ 2.51 extern "C" { 2.52 #endif 2.53 2.54 +int anm_init_animation(struct anm_animation *anim); 2.55 +void anm_destroy_animation(struct anm_animation *anim); 2.56 + 2.57 +void anm_set_animation_name(struct anm_animation *anim, const char *name); 2.58 + 2.59 + 2.60 +/* ---- node/hierarchy management ---- */ 2.61 + 2.62 /* node constructor and destructor */ 2.63 int anm_init_node(struct anm_node *node); 2.64 void anm_destroy_node(struct anm_node *node); 2.65 @@ -66,13 +94,82 @@ 2.66 int anm_set_node_name(struct anm_node *node, const char *name); 2.67 const char *anm_get_node_name(struct anm_node *node); 2.68 2.69 -void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in); 2.70 -void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex); 2.71 - 2.72 /* link and unlink nodes with parent/child relations */ 2.73 void anm_link_node(struct anm_node *parent, struct anm_node *child); 2.74 int anm_unlink_node(struct anm_node *parent, struct anm_node *child); 2.75 2.76 +void anm_set_pivot(struct anm_node *node, vec3_t pivot); 2.77 +vec3_t anm_get_pivot(struct anm_node *node); 2.78 + 2.79 +/* ---- multiple animations and animation blending ---- */ 2.80 + 2.81 +/* set active animation(s) */ 2.82 +int anm_use_node_animation(struct anm_node *node, int aidx); 2.83 +int anm_use_node_animations(struct anm_node *node, int aidx, int bidx, float t); 2.84 +/* recursive variants */ 2.85 +int anm_use_animation(struct anm_node *node, int aidx); 2.86 +int anm_use_animations(struct anm_node *node, int aidx, int bidx, float t); 2.87 + 2.88 +/* set/get current animation offset(s) */ 2.89 +void anm_set_node_animation_offset(struct anm_node *node, anm_time_t offs, int which); 2.90 +anm_time_t anm_get_animation_offset(const struct anm_node *node, int which); 2.91 +/* recursive variant */ 2.92 +void anm_set_animation_offset(struct anm_node *node, anm_time_t offs, int which); 2.93 + 2.94 +/* returns the requested current animation index, which can be 0 or 1 */ 2.95 +int anm_get_active_animation_index(const struct anm_node *node, int which); 2.96 +/* returns the requested current animation, which can be 0 or 1 */ 2.97 +struct anm_animation *anm_get_active_animation(const struct anm_node *node, int which); 2.98 +float anm_get_active_animation_mix(const struct anm_node *node); 2.99 + 2.100 +int anm_get_animation_count(const struct anm_node *node); 2.101 + 2.102 +/* add/remove an animation to the specified node */ 2.103 +int anm_add_node_animation(struct anm_node *node); 2.104 +int anm_remove_node_animation(struct anm_node *node, int idx); 2.105 + 2.106 +/* add/remove an animation to the specified node and all it's descendants */ 2.107 +int anm_add_animation(struct anm_node *node); 2.108 +int anm_remove_animation(struct anm_node *node, int idx); 2.109 + 2.110 +struct anm_animation *anm_get_animation(struct anm_node *node, int idx); 2.111 +struct anm_animation *anm_get_animation_by_name(struct anm_node *node, const char *name); 2.112 + 2.113 +int anm_find_animation(struct anm_node *node, const char *name); 2.114 + 2.115 +/* set the interpolator for the (first) currently active animation */ 2.116 +void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in); 2.117 +/* set the extrapolator for the (first) currently active animation */ 2.118 +void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex); 2.119 + 2.120 +/* set the name of the currently active animation of this node only */ 2.121 +void anm_set_node_active_animation_name(struct anm_node *node, const char *name); 2.122 +/* recursively set the name of the currently active animation for this node 2.123 + * and all it's descendants */ 2.124 +void anm_set_active_animation_name(struct anm_node *node, const char *name); 2.125 +/* get the name of the currently active animation of this node */ 2.126 +const char *anm_get_active_animation_name(struct anm_node *node); 2.127 + 2.128 + 2.129 +/* ---- high level animation blending interface ---- */ 2.130 +/* XXX this convenience interface assumes monotonically increasing time values 2.131 + * in all subsequent calls to anm_get_* and anm_eval_* functions. 2.132 + * 2.133 + * anmidx: index of the animation to transition to 2.134 + * start: when to start the transition 2.135 + * dur: transition duration 2.136 + * 2.137 + * sets up a transition from the current animation (cur_anim[0]) to another animation. 2.138 + * at time start + dur, the transition will be completed, cur_anim[0] will be the new 2.139 + * animation and cur_anim_offset[0] will be equal to start. 2.140 + */ 2.141 +void anm_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur); 2.142 +/* non-recursive variant, acts on a single node (you probably DON'T want to use this) */ 2.143 +void anm_node_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur); 2.144 + 2.145 + 2.146 +/* ---- keyframes / PRS interpolation ---- */ 2.147 + 2.148 void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm); 2.149 vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm); 2.150 2.151 @@ -87,13 +184,27 @@ 2.152 quat_t anm_get_rotation(struct anm_node *node, anm_time_t tm); 2.153 vec3_t anm_get_scaling(struct anm_node *node, anm_time_t tm); 2.154 2.155 -void anm_set_pivot(struct anm_node *node, vec3_t pivot); 2.156 -vec3_t anm_get_pivot(struct anm_node *node); 2.157 +/* those return the start and end times of the whole tree */ 2.158 +anm_time_t anm_get_start_time(struct anm_node *node); 2.159 +anm_time_t anm_get_end_time(struct anm_node *node); 2.160 + 2.161 + 2.162 +/* ---- transformation matrices ---- */ 2.163 2.164 /* these calculate the matrix and inverse matrix of this node alone */ 2.165 void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm); 2.166 void anm_get_node_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm); 2.167 2.168 +/* ---- top-down matrix calculation interface ---- */ 2.169 + 2.170 +/* calculate and set the matrix of this node */ 2.171 +void anm_eval_node(struct anm_node *node, anm_time_t tm); 2.172 +/* calculate and set the matrix of this node and all its children recursively */ 2.173 +void anm_eval(struct anm_node *node, anm_time_t tm); 2.174 + 2.175 + 2.176 +/* ---- bottom-up lazy matrix calculation interface ---- */ 2.177 + 2.178 /* These calculate the matrix and inverse matrix of this node taking hierarchy 2.179 * into account. The results are cached in thread-specific storage and returned 2.180 * if there's no change in time or tracks from the last query... 2.181 @@ -101,10 +212,6 @@ 2.182 void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm); 2.183 void anm_get_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm); 2.184 2.185 -/* those return the start and end times of the whole tree */ 2.186 -anm_time_t anm_get_start_time(struct anm_node *node); 2.187 -anm_time_t anm_get_end_time(struct anm_node *node); 2.188 - 2.189 #ifdef __cplusplus 2.190 } 2.191 #endif
3.1 --- a/libs/anim/dynarr.h Sun Dec 29 06:01:59 2013 +0200 3.2 +++ b/libs/anim/dynarr.h Thu Jan 16 19:13:45 2014 +0200 3.3 @@ -1,8 +1,6 @@ 3.4 #ifndef DYNARR_H_ 3.5 #define DYNARR_H_ 3.6 3.7 -#include "config.h" 3.8 - 3.9 void *dynarr_alloc(int elem, int szelem); 3.10 void dynarr_free(void *da); 3.11 void *dynarr_resize(void *da, int elem);
4.1 --- a/libs/anim/track.c Sun Dec 29 06:01:59 2013 +0200 4.2 +++ b/libs/anim/track.c Thu Jan 16 19:13:45 2014 +0200 4.3 @@ -69,7 +69,7 @@ 4.4 free(track); 4.5 } 4.6 4.7 -void anm_copy_track(struct anm_track *dest, struct anm_track *src) 4.8 +void anm_copy_track(struct anm_track *dest, const struct anm_track *src) 4.9 { 4.10 free(dest->name); 4.11 if(dest->keys) {
5.1 --- a/libs/anim/track.h Sun Dec 29 06:01:59 2013 +0200 5.2 +++ b/libs/anim/track.h Thu Jan 16 19:13:45 2014 +0200 5.3 @@ -59,7 +59,7 @@ 5.4 /* copies track src to dest 5.5 * XXX: dest must have been initialized first 5.6 */ 5.7 -void anm_copy_track(struct anm_track *dest, struct anm_track *src); 5.8 +void anm_copy_track(struct anm_track *dest, const struct anm_track *src); 5.9 5.10 int anm_set_track_name(struct anm_track *track, const char *name); 5.11 const char *anm_get_track_name(struct anm_track *track);