goat3d
changeset 52:cb5414f406eb
merged
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Fri, 17 Jan 2014 18:27:47 +0200 |
parents | fa5c52ea9d59 0be413ac2e0a |
children | 6d514398a728 |
files | src/goat3d.cc src/goat3d_readxml.cc src/goat3d_write.cc |
diffstat | 10 files changed, 729 insertions(+), 110 deletions(-) [+] |
line diff
1.1 --- a/Makefile Fri Jan 17 18:16:09 2014 +0200 1.2 +++ b/Makefile Fri Jan 17 18:27:47 2014 +0200 1.3 @@ -37,7 +37,7 @@ 1.4 CC = clang 1.5 CXX = clang++ 1.6 CXXFLAGS = -pedantic -Wall $(dbg) $(opt) $(pic) $(extinc) 1.7 -LDFLAGS = $(extlibs) 1.8 +LDFLAGS = $(extlibs) -lpthread 1.9 1.10 .PHONY: all 1.11 all: $(lib_so) $(lib_a) 1.12 @@ -48,15 +48,19 @@ 1.13 $(lib_a): $(obj) $(extlibs) 1.14 $(AR) rcs $@ $(obj) $(extlibs) 1.15 1.16 +.PHONY: $(openctm) 1.17 $(openctm): 1.18 $(MAKE) -C libs/openctm 1.19 1.20 +.PHONY: $(tinyxml2) 1.21 $(tinyxml2): 1.22 $(MAKE) -C libs/tinyxml2 1.23 1.24 +.PHONY: $(vmath) 1.25 $(vmath): 1.26 $(MAKE) -C libs/vmath 1.27 1.28 +.PHONY: $(anim) 1.29 $(anim): 1.30 $(MAKE) -C libs/anim 1.31
2.1 --- a/libs/anim/anim.c Fri Jan 17 18:16:09 2014 +0200 2.2 +++ b/libs/anim/anim.c Fri Jan 17 18:27:47 2014 +0200 2.3 @@ -8,7 +8,7 @@ 2.4 2.5 static void invalidate_cache(struct anm_node *node); 2.6 2.7 -int anm_init_node(struct anm_node *node) 2.8 +int anm_init_animation(struct anm_animation *anim) 2.9 { 2.10 int i, j; 2.11 static const float defaults[] = { 2.12 @@ -17,19 +17,59 @@ 2.13 1.0f, 1.0f, 1.0f /* default scale factor */ 2.14 }; 2.15 2.16 + anim->name = 0; 2.17 + 2.18 + for(i=0; i<ANM_NUM_TRACKS; i++) { 2.19 + if(anm_init_track(anim->tracks + i) == -1) { 2.20 + for(j=0; j<i; j++) { 2.21 + anm_destroy_track(anim->tracks + i); 2.22 + } 2.23 + } 2.24 + anm_set_track_default(anim->tracks + i, defaults[i]); 2.25 + } 2.26 + return 0; 2.27 +} 2.28 + 2.29 +void anm_destroy_animation(struct anm_animation *anim) 2.30 +{ 2.31 + int i; 2.32 + for(i=0; i<ANM_NUM_TRACKS; i++) { 2.33 + anm_destroy_track(anim->tracks + i); 2.34 + } 2.35 + free(anim->name); 2.36 +} 2.37 + 2.38 +void anm_set_animation_name(struct anm_animation *anim, const char *name) 2.39 +{ 2.40 + char *newname = malloc(strlen(name) + 1); 2.41 + if(!newname) return; 2.42 + 2.43 + strcpy(newname, name); 2.44 + 2.45 + free(anim->name); 2.46 + anim->name = newname; 2.47 +} 2.48 + 2.49 +/* ---- node implementation ----- */ 2.50 + 2.51 +int anm_init_node(struct anm_node *node) 2.52 +{ 2.53 memset(node, 0, sizeof *node); 2.54 2.55 - for(i=0; i<ANM_NUM_TRACKS; i++) { 2.56 - if(anm_init_track(node->tracks + i) == -1) { 2.57 - for(j=0; j<i; j++) { 2.58 - anm_destroy_track(node->tracks + i); 2.59 - } 2.60 - } 2.61 - anm_set_track_default(node->tracks + i, defaults[i]); 2.62 + node->cur_anim[1] = -1; 2.63 + 2.64 + if(!(node->animations = dynarr_alloc(1, sizeof *node->animations))) { 2.65 + return -1; 2.66 + } 2.67 + if(anm_init_animation(node->animations) == -1) { 2.68 + dynarr_free(node->animations); 2.69 + return -1; 2.70 } 2.71 2.72 - node->cache.time = ANM_TIME_INVAL; 2.73 - node->cache.inv_time = ANM_TIME_INVAL; 2.74 + /* initialize thread-local matrix cache */ 2.75 + pthread_key_create(&node->cache_key, 0); 2.76 + pthread_mutex_init(&node->cache_list_lock, 0); 2.77 + 2.78 return 0; 2.79 } 2.80 2.81 @@ -39,7 +79,17 @@ 2.82 free(node->name); 2.83 2.84 for(i=0; i<ANM_NUM_TRACKS; i++) { 2.85 - anm_destroy_track(node->tracks + i); 2.86 + anm_destroy_animation(node->animations + i); 2.87 + } 2.88 + dynarr_free(node->animations); 2.89 + 2.90 + /* destroy thread-specific cache */ 2.91 + pthread_key_delete(node->cache_key); 2.92 + 2.93 + while(node->cache_list) { 2.94 + struct mat_cache *tmp = node->cache_list; 2.95 + node->cache_list = tmp->next; 2.96 + free(tmp); 2.97 } 2.98 } 2.99 2.100 @@ -113,26 +163,6 @@ 2.101 return node->name ? node->name : ""; 2.102 } 2.103 2.104 -void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in) 2.105 -{ 2.106 - int i; 2.107 - 2.108 - for(i=0; i<ANM_NUM_TRACKS; i++) { 2.109 - anm_set_track_interpolator(node->tracks + i, in); 2.110 - } 2.111 - invalidate_cache(node); 2.112 -} 2.113 - 2.114 -void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex) 2.115 -{ 2.116 - int i; 2.117 - 2.118 - for(i=0; i<ANM_NUM_TRACKS; i++) { 2.119 - anm_set_track_extrapolator(node->tracks + i, ex); 2.120 - } 2.121 - invalidate_cache(node); 2.122 -} 2.123 - 2.124 void anm_link_node(struct anm_node *p, struct anm_node *c) 2.125 { 2.126 c->next = p->child; 2.127 @@ -165,40 +195,398 @@ 2.128 return -1; 2.129 } 2.130 2.131 +void anm_set_pivot(struct anm_node *node, vec3_t piv) 2.132 +{ 2.133 + node->pivot = piv; 2.134 +} 2.135 + 2.136 +vec3_t anm_get_pivot(struct anm_node *node) 2.137 +{ 2.138 + return node->pivot; 2.139 +} 2.140 + 2.141 + 2.142 +/* animation management */ 2.143 + 2.144 +int anm_use_node_animation(struct anm_node *node, int aidx) 2.145 +{ 2.146 + if(aidx == node->cur_anim[0] && node->cur_anim[1] == -1) { 2.147 + return 0; /* no change, no invalidation */ 2.148 + } 2.149 + 2.150 + if(aidx < 0 || aidx >= anm_get_animation_count(node)) { 2.151 + return -1; 2.152 + } 2.153 + 2.154 + node->cur_anim[0] = aidx; 2.155 + node->cur_anim[1] = -1; 2.156 + node->cur_mix = 0; 2.157 + node->blend_dur = -1; 2.158 + 2.159 + invalidate_cache(node); 2.160 + return 0; 2.161 +} 2.162 + 2.163 +int anm_use_node_animations(struct anm_node *node, int aidx, int bidx, float t) 2.164 +{ 2.165 + int num_anim; 2.166 + 2.167 + if(node->cur_anim[0] == aidx && node->cur_anim[1] == bidx && 2.168 + fabs(t - node->cur_mix) < 1e-6) { 2.169 + return 0; /* no change, no invalidation */ 2.170 + } 2.171 + 2.172 + num_anim = anm_get_animation_count(node); 2.173 + if(aidx < 0 || aidx >= num_anim) { 2.174 + return anm_use_animation(node, bidx); 2.175 + } 2.176 + if(bidx < 0 || bidx >= num_anim) { 2.177 + return anm_use_animation(node, aidx); 2.178 + } 2.179 + node->cur_anim[0] = aidx; 2.180 + node->cur_anim[1] = bidx; 2.181 + node->cur_mix = t; 2.182 + 2.183 + invalidate_cache(node); 2.184 + return 0; 2.185 +} 2.186 + 2.187 +int anm_use_animation(struct anm_node *node, int aidx) 2.188 +{ 2.189 + struct anm_node *child; 2.190 + 2.191 + if(anm_use_node_animation(node, aidx) == -1) { 2.192 + return -1; 2.193 + } 2.194 + 2.195 + child = node->child; 2.196 + while(child) { 2.197 + if(anm_use_animation(child, aidx) == -1) { 2.198 + return -1; 2.199 + } 2.200 + child = child->next; 2.201 + } 2.202 + return 0; 2.203 +} 2.204 + 2.205 +int anm_use_animations(struct anm_node *node, int aidx, int bidx, float t) 2.206 +{ 2.207 + struct anm_node *child; 2.208 + 2.209 + if(anm_use_node_animations(node, aidx, bidx, t) == -1) { 2.210 + return -1; 2.211 + } 2.212 + 2.213 + child = node->child; 2.214 + while(child) { 2.215 + if(anm_use_animations(child, aidx, bidx, t) == -1) { 2.216 + return -1; 2.217 + } 2.218 + child = child->next; 2.219 + } 2.220 + return 0; 2.221 + 2.222 +} 2.223 + 2.224 +void anm_set_node_animation_offset(struct anm_node *node, anm_time_t offs, int which) 2.225 +{ 2.226 + if(which < 0 || which >= 2) { 2.227 + return; 2.228 + } 2.229 + node->cur_anim_offset[which] = offs; 2.230 +} 2.231 + 2.232 +anm_time_t anm_get_animation_offset(const struct anm_node *node, int which) 2.233 +{ 2.234 + if(which < 0 || which >= 2) { 2.235 + return 0; 2.236 + } 2.237 + return node->cur_anim_offset[which]; 2.238 +} 2.239 + 2.240 +void anm_set_animation_offset(struct anm_node *node, anm_time_t offs, int which) 2.241 +{ 2.242 + struct anm_node *c = node->child; 2.243 + while(c) { 2.244 + anm_set_animation_offset(c, offs, which); 2.245 + c = c->next; 2.246 + } 2.247 + 2.248 + anm_set_node_animation_offset(node, offs, which); 2.249 +} 2.250 + 2.251 +int anm_get_active_animation_index(const struct anm_node *node, int which) 2.252 +{ 2.253 + if(which < 0 || which >= 2) return -1; 2.254 + return node->cur_anim[which]; 2.255 +} 2.256 + 2.257 +struct anm_animation *anm_get_active_animation(const struct anm_node *node, int which) 2.258 +{ 2.259 + int idx = anm_get_active_animation_index(node, which); 2.260 + if(idx < 0 || idx >= anm_get_animation_count(node)) { 2.261 + return 0; 2.262 + } 2.263 + return node->animations + idx; 2.264 +} 2.265 + 2.266 +float anm_get_active_animation_mix(const struct anm_node *node) 2.267 +{ 2.268 + return node->cur_mix; 2.269 +} 2.270 + 2.271 +int anm_get_animation_count(const struct anm_node *node) 2.272 +{ 2.273 + return dynarr_size(node->animations); 2.274 +} 2.275 + 2.276 +int anm_add_node_animation(struct anm_node *node) 2.277 +{ 2.278 + struct anm_animation newanim; 2.279 + anm_init_animation(&newanim); 2.280 + 2.281 + node->animations = dynarr_push(node->animations, &newanim); 2.282 + return 0; 2.283 +} 2.284 + 2.285 +int anm_remove_node_animation(struct anm_node *node, int idx) 2.286 +{ 2.287 + fprintf(stderr, "anm_remove_animation: unimplemented!"); 2.288 + abort(); 2.289 + return 0; 2.290 +} 2.291 + 2.292 +int anm_add_animation(struct anm_node *node) 2.293 +{ 2.294 + struct anm_node *child; 2.295 + 2.296 + if(anm_add_node_animation(node) == -1) { 2.297 + return -1; 2.298 + } 2.299 + 2.300 + child = node->child; 2.301 + while(child) { 2.302 + if(anm_add_animation(child)) { 2.303 + return -1; 2.304 + } 2.305 + child = child->next; 2.306 + } 2.307 + return 0; 2.308 +} 2.309 + 2.310 +int anm_remove_animation(struct anm_node *node, int idx) 2.311 +{ 2.312 + struct anm_node *child; 2.313 + 2.314 + if(anm_remove_node_animation(node, idx) == -1) { 2.315 + return -1; 2.316 + } 2.317 + 2.318 + child = node->child; 2.319 + while(child) { 2.320 + if(anm_remove_animation(child, idx) == -1) { 2.321 + return -1; 2.322 + } 2.323 + child = child->next; 2.324 + } 2.325 + return 0; 2.326 +} 2.327 + 2.328 +struct anm_animation *anm_get_animation(struct anm_node *node, int idx) 2.329 +{ 2.330 + if(idx < 0 || idx > anm_get_animation_count(node)) { 2.331 + return 0; 2.332 + } 2.333 + return node->animations + idx; 2.334 +} 2.335 + 2.336 +struct anm_animation *anm_get_animation_by_name(struct anm_node *node, const char *name) 2.337 +{ 2.338 + return anm_get_animation(node, anm_find_animation(node, name)); 2.339 +} 2.340 + 2.341 +int anm_find_animation(struct anm_node *node, const char *name) 2.342 +{ 2.343 + int i, count = anm_get_animation_count(node); 2.344 + for(i=0; i<count; i++) { 2.345 + if(strcmp(node->animations[i].name, name) == 0) { 2.346 + return i; 2.347 + } 2.348 + } 2.349 + return -1; 2.350 +} 2.351 + 2.352 +/* all the rest act on the current animation(s) */ 2.353 + 2.354 +void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in) 2.355 +{ 2.356 + int i; 2.357 + struct anm_animation *anim = anm_get_active_animation(node, 0); 2.358 + if(!anim) return; 2.359 + 2.360 + for(i=0; i<ANM_NUM_TRACKS; i++) { 2.361 + anm_set_track_interpolator(anim->tracks + i, in); 2.362 + } 2.363 + invalidate_cache(node); 2.364 +} 2.365 + 2.366 +void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex) 2.367 +{ 2.368 + int i; 2.369 + struct anm_animation *anim = anm_get_active_animation(node, 0); 2.370 + if(!anim) return; 2.371 + 2.372 + for(i=0; i<ANM_NUM_TRACKS; i++) { 2.373 + anm_set_track_extrapolator(anim->tracks + i, ex); 2.374 + } 2.375 + invalidate_cache(node); 2.376 +} 2.377 + 2.378 +void anm_set_node_active_animation_name(struct anm_node *node, const char *name) 2.379 +{ 2.380 + struct anm_animation *anim = anm_get_active_animation(node, 0); 2.381 + if(!anim) return; 2.382 + 2.383 + anm_set_animation_name(anim, name); 2.384 +} 2.385 + 2.386 +void anm_set_active_animation_name(struct anm_node *node, const char *name) 2.387 +{ 2.388 + struct anm_node *child; 2.389 + 2.390 + anm_set_node_active_animation_name(node, name); 2.391 + 2.392 + child = node->child; 2.393 + while(child) { 2.394 + anm_set_active_animation_name(child, name); 2.395 + child = child->next; 2.396 + } 2.397 +} 2.398 + 2.399 +const char *anm_get_active_animation_name(struct anm_node *node) 2.400 +{ 2.401 + struct anm_animation *anim = anm_get_active_animation(node, 0); 2.402 + if(anim) { 2.403 + return anim->name; 2.404 + } 2.405 + return 0; 2.406 +} 2.407 + 2.408 +/* ---- high level animation blending ---- */ 2.409 +void anm_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur) 2.410 +{ 2.411 + struct anm_node *c = node->child; 2.412 + 2.413 + if(anmidx == node->cur_anim[0]) { 2.414 + return; 2.415 + } 2.416 + 2.417 + while(c) { 2.418 + anm_transition(c, anmidx, start, dur); 2.419 + c = c->next; 2.420 + } 2.421 + 2.422 + anm_node_transition(node, anmidx, start, dur); 2.423 +} 2.424 + 2.425 +void anm_node_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur) 2.426 +{ 2.427 + if(anmidx == node->cur_anim[0]) { 2.428 + return; 2.429 + } 2.430 + 2.431 + node->cur_anim[1] = anmidx; 2.432 + node->cur_anim_offset[1] = start; 2.433 + node->blend_dur = dur; 2.434 +} 2.435 + 2.436 + 2.437 +#define BLEND_START_TM node->cur_anim_offset[1] 2.438 + 2.439 +static anm_time_t animation_time(struct anm_node *node, anm_time_t tm, int which) 2.440 +{ 2.441 + float t; 2.442 + 2.443 + if(node->blend_dur >= 0) { 2.444 + /* we're in transition... */ 2.445 + t = (float)(tm - BLEND_START_TM) / (float)node->blend_dur; 2.446 + if(t < 0.0) t = 0.0; 2.447 + 2.448 + node->cur_mix = t; 2.449 + 2.450 + if(t > 1.0) { 2.451 + /* switch completely over to the target animation and stop blending */ 2.452 + anm_use_node_animation(node, node->cur_anim[1]); 2.453 + node->cur_anim_offset[0] = node->cur_anim_offset[1]; 2.454 + } 2.455 + } 2.456 + 2.457 + return tm - node->cur_anim_offset[which]; 2.458 +} 2.459 + 2.460 + 2.461 void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm) 2.462 { 2.463 - anm_set_value(node->tracks + ANM_TRACK_POS_X, tm, pos.x); 2.464 - anm_set_value(node->tracks + ANM_TRACK_POS_Y, tm, pos.y); 2.465 - anm_set_value(node->tracks + ANM_TRACK_POS_Z, tm, pos.z); 2.466 + struct anm_animation *anim = anm_get_active_animation(node, 0); 2.467 + if(!anim) return; 2.468 + 2.469 + anm_set_value(anim->tracks + ANM_TRACK_POS_X, tm, pos.x); 2.470 + anm_set_value(anim->tracks + ANM_TRACK_POS_Y, tm, pos.y); 2.471 + anm_set_value(anim->tracks + ANM_TRACK_POS_Z, tm, pos.z); 2.472 invalidate_cache(node); 2.473 } 2.474 2.475 + 2.476 vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm) 2.477 { 2.478 vec3_t v; 2.479 - v.x = anm_get_value(node->tracks + ANM_TRACK_POS_X, tm); 2.480 - v.y = anm_get_value(node->tracks + ANM_TRACK_POS_Y, tm); 2.481 - v.z = anm_get_value(node->tracks + ANM_TRACK_POS_Z, tm); 2.482 + anm_time_t tm0 = animation_time(node, tm, 0); 2.483 + struct anm_animation *anim0 = anm_get_active_animation(node, 0); 2.484 + struct anm_animation *anim1 = anm_get_active_animation(node, 1); 2.485 + 2.486 + if(!anim0) { 2.487 + return v3_cons(0, 0, 0); 2.488 + } 2.489 + 2.490 + v.x = anm_get_value(anim0->tracks + ANM_TRACK_POS_X, tm0); 2.491 + v.y = anm_get_value(anim0->tracks + ANM_TRACK_POS_Y, tm0); 2.492 + v.z = anm_get_value(anim0->tracks + ANM_TRACK_POS_Z, tm0); 2.493 + 2.494 + if(anim1) { 2.495 + vec3_t v1; 2.496 + anm_time_t tm1 = animation_time(node, tm, 1); 2.497 + v1.x = anm_get_value(anim1->tracks + ANM_TRACK_POS_X, tm1); 2.498 + v1.y = anm_get_value(anim1->tracks + ANM_TRACK_POS_Y, tm1); 2.499 + v1.z = anm_get_value(anim1->tracks + ANM_TRACK_POS_Z, tm1); 2.500 + 2.501 + v.x = v.x + (v1.x - v.x) * node->cur_mix; 2.502 + v.y = v.y + (v1.y - v.y) * node->cur_mix; 2.503 + v.z = v.z + (v1.z - v.z) * node->cur_mix; 2.504 + } 2.505 + 2.506 return v; 2.507 } 2.508 2.509 void anm_set_rotation(struct anm_node *node, quat_t rot, anm_time_t tm) 2.510 { 2.511 - anm_set_value(node->tracks + ANM_TRACK_ROT_X, tm, rot.x); 2.512 - anm_set_value(node->tracks + ANM_TRACK_ROT_Y, tm, rot.y); 2.513 - anm_set_value(node->tracks + ANM_TRACK_ROT_Z, tm, rot.z); 2.514 - anm_set_value(node->tracks + ANM_TRACK_ROT_W, tm, rot.w); 2.515 + struct anm_animation *anim = anm_get_active_animation(node, 0); 2.516 + if(!anim) return; 2.517 + 2.518 + anm_set_value(anim->tracks + ANM_TRACK_ROT_X, tm, rot.x); 2.519 + anm_set_value(anim->tracks + ANM_TRACK_ROT_Y, tm, rot.y); 2.520 + anm_set_value(anim->tracks + ANM_TRACK_ROT_Z, tm, rot.z); 2.521 + anm_set_value(anim->tracks + ANM_TRACK_ROT_W, tm, rot.w); 2.522 invalidate_cache(node); 2.523 } 2.524 2.525 -quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm) 2.526 +static quat_t get_node_rotation(struct anm_node *node, anm_time_t tm, struct anm_animation *anim) 2.527 { 2.528 #ifndef ROT_USE_SLERP 2.529 quat_t q; 2.530 - q.x = anm_get_value(node->tracks + ANM_TRACK_ROT_X, tm); 2.531 - q.y = anm_get_value(node->tracks + ANM_TRACK_ROT_Y, tm); 2.532 - q.z = anm_get_value(node->tracks + ANM_TRACK_ROT_Z, tm); 2.533 - q.w = anm_get_value(node->tracks + ANM_TRACK_ROT_W, tm); 2.534 + q.x = anm_get_value(anim->tracks + ANM_TRACK_ROT_X, tm); 2.535 + q.y = anm_get_value(anim->tracks + ANM_TRACK_ROT_Y, tm); 2.536 + q.z = anm_get_value(anim->tracks + ANM_TRACK_ROT_Z, tm); 2.537 + q.w = anm_get_value(anim->tracks + ANM_TRACK_ROT_W, tm); 2.538 return q; 2.539 #else 2.540 int idx0, idx1, last_idx; 2.541 @@ -207,10 +595,10 @@ 2.542 struct anm_track *track_x, *track_y, *track_z, *track_w; 2.543 quat_t q, q1, q2; 2.544 2.545 - track_x = node->tracks + ANM_TRACK_ROT_X; 2.546 - track_y = node->tracks + ANM_TRACK_ROT_Y; 2.547 - track_z = node->tracks + ANM_TRACK_ROT_Z; 2.548 - track_w = node->tracks + ANM_TRACK_ROT_W; 2.549 + track_x = anim->tracks + ANM_TRACK_ROT_X; 2.550 + track_y = anim->tracks + ANM_TRACK_ROT_Y; 2.551 + track_z = anim->tracks + ANM_TRACK_ROT_Z; 2.552 + track_w = anim->tracks + ANM_TRACK_ROT_W; 2.553 2.554 if(!track_x->count) { 2.555 q.x = track_x->def_val; 2.556 @@ -267,20 +655,66 @@ 2.557 #endif 2.558 } 2.559 2.560 +quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm) 2.561 +{ 2.562 + quat_t q; 2.563 + anm_time_t tm0 = animation_time(node, tm, 0); 2.564 + struct anm_animation *anim0 = anm_get_active_animation(node, 0); 2.565 + struct anm_animation *anim1 = anm_get_active_animation(node, 1); 2.566 + 2.567 + if(!anim0) { 2.568 + return quat_identity(); 2.569 + } 2.570 + 2.571 + q = get_node_rotation(node, tm0, anim0); 2.572 + 2.573 + if(anim1) { 2.574 + anm_time_t tm1 = animation_time(node, tm, 1); 2.575 + quat_t q1 = get_node_rotation(node, tm1, anim1); 2.576 + 2.577 + q = quat_slerp(q, q1, node->cur_mix); 2.578 + } 2.579 + return q; 2.580 +} 2.581 + 2.582 void anm_set_scaling(struct anm_node *node, vec3_t scl, anm_time_t tm) 2.583 { 2.584 - anm_set_value(node->tracks + ANM_TRACK_SCL_X, tm, scl.x); 2.585 - anm_set_value(node->tracks + ANM_TRACK_SCL_Y, tm, scl.y); 2.586 - anm_set_value(node->tracks + ANM_TRACK_SCL_Z, tm, scl.z); 2.587 + struct anm_animation *anim = anm_get_active_animation(node, 0); 2.588 + if(!anim) return; 2.589 + 2.590 + anm_set_value(anim->tracks + ANM_TRACK_SCL_X, tm, scl.x); 2.591 + anm_set_value(anim->tracks + ANM_TRACK_SCL_Y, tm, scl.y); 2.592 + anm_set_value(anim->tracks + ANM_TRACK_SCL_Z, tm, scl.z); 2.593 invalidate_cache(node); 2.594 } 2.595 2.596 vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm) 2.597 { 2.598 vec3_t v; 2.599 - v.x = anm_get_value(node->tracks + ANM_TRACK_SCL_X, tm); 2.600 - v.y = anm_get_value(node->tracks + ANM_TRACK_SCL_Y, tm); 2.601 - v.z = anm_get_value(node->tracks + ANM_TRACK_SCL_Z, tm); 2.602 + anm_time_t tm0 = animation_time(node, tm, 0); 2.603 + struct anm_animation *anim0 = anm_get_active_animation(node, 0); 2.604 + struct anm_animation *anim1 = anm_get_active_animation(node, 1); 2.605 + 2.606 + if(!anim0) { 2.607 + return v3_cons(1, 1, 1); 2.608 + } 2.609 + 2.610 + v.x = anm_get_value(anim0->tracks + ANM_TRACK_SCL_X, tm0); 2.611 + v.y = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Y, tm0); 2.612 + v.z = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Z, tm0); 2.613 + 2.614 + if(anim1) { 2.615 + vec3_t v1; 2.616 + anm_time_t tm1 = animation_time(node, tm, 1); 2.617 + v1.x = anm_get_value(anim1->tracks + ANM_TRACK_SCL_X, tm1); 2.618 + v1.y = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Y, tm1); 2.619 + v1.z = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Z, tm1); 2.620 + 2.621 + v.x = v.x + (v1.x - v.x) * node->cur_mix; 2.622 + v.y = v.y + (v1.y - v.y) * node->cur_mix; 2.623 + v.z = v.z + (v1.z - v.z) * node->cur_mix; 2.624 + } 2.625 + 2.626 return v; 2.627 } 2.628 2.629 @@ -324,16 +758,6 @@ 2.630 return v3_mul(s, ps); 2.631 } 2.632 2.633 -void anm_set_pivot(struct anm_node *node, vec3_t piv) 2.634 -{ 2.635 - node->pivot = piv; 2.636 -} 2.637 - 2.638 -vec3_t anm_get_pivot(struct anm_node *node) 2.639 -{ 2.640 - return node->pivot; 2.641 -} 2.642 - 2.643 void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm) 2.644 { 2.645 int i; 2.646 @@ -371,43 +795,102 @@ 2.647 m4_inverse(mat, tmp); 2.648 } 2.649 2.650 +void anm_eval_node(struct anm_node *node, anm_time_t tm) 2.651 +{ 2.652 + anm_get_node_matrix(node, node->matrix, tm); 2.653 +} 2.654 + 2.655 +void anm_eval(struct anm_node *node, anm_time_t tm) 2.656 +{ 2.657 + struct anm_node *c; 2.658 + 2.659 + anm_eval_node(node, tm); 2.660 + 2.661 + if(node->parent) { 2.662 + /* due to post-order traversal, the parent matrix is already evaluated */ 2.663 + m4_mult(node->matrix, node->parent->matrix, node->matrix); 2.664 + } 2.665 + 2.666 + /* recersively evaluate all children */ 2.667 + c = node->child; 2.668 + while(c) { 2.669 + anm_eval(c, tm); 2.670 + c = c->next; 2.671 + } 2.672 +} 2.673 + 2.674 void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm) 2.675 { 2.676 - if(node->cache.time != tm) { 2.677 - anm_get_node_matrix(node, node->cache.matrix, tm); 2.678 + struct mat_cache *cache = pthread_getspecific(node->cache_key); 2.679 + if(!cache) { 2.680 + cache = malloc(sizeof *cache); 2.681 + assert(cache); 2.682 + 2.683 + pthread_mutex_lock(&node->cache_list_lock); 2.684 + cache->next = node->cache_list; 2.685 + node->cache_list = cache; 2.686 + pthread_mutex_unlock(&node->cache_list_lock); 2.687 + 2.688 + cache->time = ANM_TIME_INVAL; 2.689 + cache->inv_time = ANM_TIME_INVAL; 2.690 + pthread_setspecific(node->cache_key, cache); 2.691 + } 2.692 + 2.693 + if(cache->time != tm) { 2.694 + anm_get_node_matrix(node, cache->matrix, tm); 2.695 2.696 if(node->parent) { 2.697 mat4_t parent_mat; 2.698 2.699 anm_get_matrix(node->parent, parent_mat, tm); 2.700 - m4_mult(node->cache.matrix, parent_mat, node->cache.matrix); 2.701 + m4_mult(cache->matrix, parent_mat, cache->matrix); 2.702 } 2.703 - node->cache.time = tm; 2.704 + cache->time = tm; 2.705 } 2.706 - m4_copy(mat, node->cache.matrix); 2.707 + m4_copy(mat, cache->matrix); 2.708 } 2.709 2.710 void anm_get_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm) 2.711 { 2.712 - if(node->cache.inv_time != tm) { 2.713 + struct mat_cache *cache = pthread_getspecific(node->cache_key); 2.714 + if(!cache) { 2.715 + cache = malloc(sizeof *cache); 2.716 + assert(cache); 2.717 + 2.718 + pthread_mutex_lock(&node->cache_list_lock); 2.719 + cache->next = node->cache_list; 2.720 + node->cache_list = cache; 2.721 + pthread_mutex_unlock(&node->cache_list_lock); 2.722 + 2.723 + cache->inv_time = ANM_TIME_INVAL; 2.724 + cache->inv_time = ANM_TIME_INVAL; 2.725 + pthread_setspecific(node->cache_key, cache); 2.726 + } 2.727 + 2.728 + if(cache->inv_time != tm) { 2.729 anm_get_matrix(node, mat, tm); 2.730 - m4_inverse(node->cache.inv_matrix, mat); 2.731 - node->cache.inv_time = tm; 2.732 + m4_inverse(cache->inv_matrix, mat); 2.733 + cache->inv_time = tm; 2.734 } 2.735 - m4_copy(mat, node->cache.inv_matrix); 2.736 + m4_copy(mat, cache->inv_matrix); 2.737 } 2.738 2.739 anm_time_t anm_get_start_time(struct anm_node *node) 2.740 { 2.741 - int i; 2.742 + int i, j; 2.743 struct anm_node *c; 2.744 anm_time_t res = LONG_MAX; 2.745 2.746 - for(i=0; i<ANM_NUM_TRACKS; i++) { 2.747 - if(node->tracks[i].count) { 2.748 - anm_time_t tm = node->tracks[i].keys[0].time; 2.749 - if(tm < res) { 2.750 - res = tm; 2.751 + for(j=0; j<2; j++) { 2.752 + struct anm_animation *anim = anm_get_active_animation(node, j); 2.753 + if(!anim) break; 2.754 + 2.755 + for(i=0; i<ANM_NUM_TRACKS; i++) { 2.756 + if(anim->tracks[i].count) { 2.757 + anm_time_t tm = anim->tracks[i].keys[0].time; 2.758 + if(tm < res) { 2.759 + res = tm; 2.760 + } 2.761 } 2.762 } 2.763 } 2.764 @@ -425,15 +908,20 @@ 2.765 2.766 anm_time_t anm_get_end_time(struct anm_node *node) 2.767 { 2.768 - int i; 2.769 + int i, j; 2.770 struct anm_node *c; 2.771 anm_time_t res = LONG_MIN; 2.772 2.773 - for(i=0; i<ANM_NUM_TRACKS; i++) { 2.774 - if(node->tracks[i].count) { 2.775 - anm_time_t tm = node->tracks[i].keys[node->tracks[i].count - 1].time; 2.776 - if(tm > res) { 2.777 - res = tm; 2.778 + for(j=0; j<2; j++) { 2.779 + struct anm_animation *anim = anm_get_active_animation(node, j); 2.780 + if(!anim) break; 2.781 + 2.782 + for(i=0; i<ANM_NUM_TRACKS; i++) { 2.783 + if(anim->tracks[i].count) { 2.784 + anm_time_t tm = anim->tracks[i].keys[anim->tracks[i].count - 1].time; 2.785 + if(tm > res) { 2.786 + res = tm; 2.787 + } 2.788 } 2.789 } 2.790 } 2.791 @@ -451,5 +939,8 @@ 2.792 2.793 static void invalidate_cache(struct anm_node *node) 2.794 { 2.795 - node->cache.time = node->cache.inv_time = ANM_TIME_INVAL; 2.796 + struct mat_cache *cache = pthread_getspecific(node->cache_key); 2.797 + if(cache) { 2.798 + cache->time = cache->inv_time = ANM_TIME_INVAL; 2.799 + } 2.800 }
3.1 --- a/libs/anim/anim.h Fri Jan 17 18:16:09 2014 +0200 3.2 +++ b/libs/anim/anim.h Fri Jan 17 18:27:47 2014 +0200 3.3 @@ -3,6 +3,8 @@ 3.4 3.5 #include "config.h" 3.6 3.7 +#include <pthread.h> 3.8 + 3.9 #include <vmath/vector.h> 3.10 #include <vmath/quat.h> 3.11 #include <vmath/matrix.h> 3.12 @@ -25,17 +27,35 @@ 3.13 ANM_NUM_TRACKS 3.14 }; 3.15 3.16 +struct anm_animation { 3.17 + char *name; 3.18 + struct anm_track tracks[ANM_NUM_TRACKS]; 3.19 +}; 3.20 + 3.21 struct anm_node { 3.22 char *name; 3.23 3.24 - struct anm_track tracks[ANM_NUM_TRACKS]; 3.25 + int cur_anim[2]; 3.26 + anm_time_t cur_anim_offset[2]; 3.27 + float cur_mix; 3.28 + 3.29 + /* high-level animation blending transition duration */ 3.30 + anm_time_t blend_dur; 3.31 + 3.32 + struct anm_animation *animations; 3.33 vec3_t pivot; 3.34 3.35 /* matrix cache */ 3.36 struct mat_cache { 3.37 mat4_t matrix, inv_matrix; 3.38 anm_time_t time, inv_time; 3.39 - } cache; 3.40 + struct mat_cache *next; 3.41 + } *cache_list; 3.42 + pthread_key_t cache_key; 3.43 + pthread_mutex_t cache_list_lock; 3.44 + 3.45 + /* matrix calculated by anm_eval functions (no locking, meant as a pre-pass) */ 3.46 + mat4_t matrix; 3.47 3.48 struct anm_node *parent; 3.49 struct anm_node *child; 3.50 @@ -46,6 +66,14 @@ 3.51 extern "C" { 3.52 #endif 3.53 3.54 +int anm_init_animation(struct anm_animation *anim); 3.55 +void anm_destroy_animation(struct anm_animation *anim); 3.56 + 3.57 +void anm_set_animation_name(struct anm_animation *anim, const char *name); 3.58 + 3.59 + 3.60 +/* ---- node/hierarchy management ---- */ 3.61 + 3.62 /* node constructor and destructor */ 3.63 int anm_init_node(struct anm_node *node); 3.64 void anm_destroy_node(struct anm_node *node); 3.65 @@ -66,13 +94,82 @@ 3.66 int anm_set_node_name(struct anm_node *node, const char *name); 3.67 const char *anm_get_node_name(struct anm_node *node); 3.68 3.69 -void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in); 3.70 -void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex); 3.71 - 3.72 /* link and unlink nodes with parent/child relations */ 3.73 void anm_link_node(struct anm_node *parent, struct anm_node *child); 3.74 int anm_unlink_node(struct anm_node *parent, struct anm_node *child); 3.75 3.76 +void anm_set_pivot(struct anm_node *node, vec3_t pivot); 3.77 +vec3_t anm_get_pivot(struct anm_node *node); 3.78 + 3.79 +/* ---- multiple animations and animation blending ---- */ 3.80 + 3.81 +/* set active animation(s) */ 3.82 +int anm_use_node_animation(struct anm_node *node, int aidx); 3.83 +int anm_use_node_animations(struct anm_node *node, int aidx, int bidx, float t); 3.84 +/* recursive variants */ 3.85 +int anm_use_animation(struct anm_node *node, int aidx); 3.86 +int anm_use_animations(struct anm_node *node, int aidx, int bidx, float t); 3.87 + 3.88 +/* set/get current animation offset(s) */ 3.89 +void anm_set_node_animation_offset(struct anm_node *node, anm_time_t offs, int which); 3.90 +anm_time_t anm_get_animation_offset(const struct anm_node *node, int which); 3.91 +/* recursive variant */ 3.92 +void anm_set_animation_offset(struct anm_node *node, anm_time_t offs, int which); 3.93 + 3.94 +/* returns the requested current animation index, which can be 0 or 1 */ 3.95 +int anm_get_active_animation_index(const struct anm_node *node, int which); 3.96 +/* returns the requested current animation, which can be 0 or 1 */ 3.97 +struct anm_animation *anm_get_active_animation(const struct anm_node *node, int which); 3.98 +float anm_get_active_animation_mix(const struct anm_node *node); 3.99 + 3.100 +int anm_get_animation_count(const struct anm_node *node); 3.101 + 3.102 +/* add/remove an animation to the specified node */ 3.103 +int anm_add_node_animation(struct anm_node *node); 3.104 +int anm_remove_node_animation(struct anm_node *node, int idx); 3.105 + 3.106 +/* add/remove an animation to the specified node and all it's descendants */ 3.107 +int anm_add_animation(struct anm_node *node); 3.108 +int anm_remove_animation(struct anm_node *node, int idx); 3.109 + 3.110 +struct anm_animation *anm_get_animation(struct anm_node *node, int idx); 3.111 +struct anm_animation *anm_get_animation_by_name(struct anm_node *node, const char *name); 3.112 + 3.113 +int anm_find_animation(struct anm_node *node, const char *name); 3.114 + 3.115 +/* set the interpolator for the (first) currently active animation */ 3.116 +void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in); 3.117 +/* set the extrapolator for the (first) currently active animation */ 3.118 +void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex); 3.119 + 3.120 +/* set the name of the currently active animation of this node only */ 3.121 +void anm_set_node_active_animation_name(struct anm_node *node, const char *name); 3.122 +/* recursively set the name of the currently active animation for this node 3.123 + * and all it's descendants */ 3.124 +void anm_set_active_animation_name(struct anm_node *node, const char *name); 3.125 +/* get the name of the currently active animation of this node */ 3.126 +const char *anm_get_active_animation_name(struct anm_node *node); 3.127 + 3.128 + 3.129 +/* ---- high level animation blending interface ---- */ 3.130 +/* XXX this convenience interface assumes monotonically increasing time values 3.131 + * in all subsequent calls to anm_get_* and anm_eval_* functions. 3.132 + * 3.133 + * anmidx: index of the animation to transition to 3.134 + * start: when to start the transition 3.135 + * dur: transition duration 3.136 + * 3.137 + * sets up a transition from the current animation (cur_anim[0]) to another animation. 3.138 + * at time start + dur, the transition will be completed, cur_anim[0] will be the new 3.139 + * animation and cur_anim_offset[0] will be equal to start. 3.140 + */ 3.141 +void anm_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur); 3.142 +/* non-recursive variant, acts on a single node (you probably DON'T want to use this) */ 3.143 +void anm_node_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur); 3.144 + 3.145 + 3.146 +/* ---- keyframes / PRS interpolation ---- */ 3.147 + 3.148 void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm); 3.149 vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm); 3.150 3.151 @@ -87,13 +184,27 @@ 3.152 quat_t anm_get_rotation(struct anm_node *node, anm_time_t tm); 3.153 vec3_t anm_get_scaling(struct anm_node *node, anm_time_t tm); 3.154 3.155 -void anm_set_pivot(struct anm_node *node, vec3_t pivot); 3.156 -vec3_t anm_get_pivot(struct anm_node *node); 3.157 +/* those return the start and end times of the whole tree */ 3.158 +anm_time_t anm_get_start_time(struct anm_node *node); 3.159 +anm_time_t anm_get_end_time(struct anm_node *node); 3.160 + 3.161 + 3.162 +/* ---- transformation matrices ---- */ 3.163 3.164 /* these calculate the matrix and inverse matrix of this node alone */ 3.165 void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm); 3.166 void anm_get_node_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm); 3.167 3.168 +/* ---- top-down matrix calculation interface ---- */ 3.169 + 3.170 +/* calculate and set the matrix of this node */ 3.171 +void anm_eval_node(struct anm_node *node, anm_time_t tm); 3.172 +/* calculate and set the matrix of this node and all its children recursively */ 3.173 +void anm_eval(struct anm_node *node, anm_time_t tm); 3.174 + 3.175 + 3.176 +/* ---- bottom-up lazy matrix calculation interface ---- */ 3.177 + 3.178 /* These calculate the matrix and inverse matrix of this node taking hierarchy 3.179 * into account. The results are cached in thread-specific storage and returned 3.180 * if there's no change in time or tracks from the last query... 3.181 @@ -101,10 +212,6 @@ 3.182 void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm); 3.183 void anm_get_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm); 3.184 3.185 -/* those return the start and end times of the whole tree */ 3.186 -anm_time_t anm_get_start_time(struct anm_node *node); 3.187 -anm_time_t anm_get_end_time(struct anm_node *node); 3.188 - 3.189 #ifdef __cplusplus 3.190 } 3.191 #endif
4.1 --- a/libs/anim/dynarr.h Fri Jan 17 18:16:09 2014 +0200 4.2 +++ b/libs/anim/dynarr.h Fri Jan 17 18:27:47 2014 +0200 4.3 @@ -1,8 +1,6 @@ 4.4 #ifndef DYNARR_H_ 4.5 #define DYNARR_H_ 4.6 4.7 -#include "config.h" 4.8 - 4.9 void *dynarr_alloc(int elem, int szelem); 4.10 void dynarr_free(void *da); 4.11 void *dynarr_resize(void *da, int elem);
5.1 --- a/libs/anim/track.c Fri Jan 17 18:16:09 2014 +0200 5.2 +++ b/libs/anim/track.c Fri Jan 17 18:27:47 2014 +0200 5.3 @@ -69,7 +69,7 @@ 5.4 free(track); 5.5 } 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 free(dest->name); 5.11 if(dest->keys) {
6.1 --- a/libs/anim/track.h Fri Jan 17 18:16:09 2014 +0200 6.2 +++ b/libs/anim/track.h Fri Jan 17 18:27:47 2014 +0200 6.3 @@ -59,7 +59,7 @@ 6.4 /* copies track src to dest 6.5 * XXX: dest must have been initialized first 6.6 */ 6.7 -void anm_copy_track(struct anm_track *dest, struct anm_track *src); 6.8 +void anm_copy_track(struct anm_track *dest, const struct anm_track *src); 6.9 6.10 int anm_set_track_name(struct anm_track *track, const char *name); 6.11 const char *anm_get_track_name(struct anm_track *track);
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/src/goat3d_read.cc Fri Jan 17 18:27:47 2014 +0200 7.3 @@ -0,0 +1,13 @@ 7.4 +#include "goat3d_impl.h" 7.5 + 7.6 +using namespace g3dimpl; 7.7 + 7.8 +bool Scene::load(goat3d_io *io) 7.9 +{ 7.10 + return false; 7.11 +} 7.12 + 7.13 +bool Scene::load_anim(goat3d_io *io) 7.14 +{ 7.15 + return false; 7.16 +}
8.1 --- a/src/goat3d_readxml.cc Fri Jan 17 18:16:09 2014 +0200 8.2 +++ b/src/goat3d_readxml.cc Fri Jan 17 18:27:47 2014 +0200 8.3 @@ -110,6 +110,12 @@ 8.4 return true; 8.5 } 8.6 8.7 +bool Scene::load_anim_xml(goat3d_io *io) 8.8 +{ 8.9 + return false; 8.10 +} 8.11 + 8.12 + 8.13 static Material *read_material(Scene *scn, XMLElement *xml_mtl) 8.14 { 8.15 Material *mtl = new Material;
9.1 --- a/src/goat3d_write.cc Fri Jan 17 18:16:09 2014 +0200 9.2 +++ b/src/goat3d_write.cc Fri Jan 17 18:27:47 2014 +0200 9.3 @@ -225,3 +225,8 @@ 9.4 return size; 9.5 } 9.6 #endif 9.7 + 9.8 +bool Scene::save_anim(const XFormNode *node, goat3d_io *io) const 9.9 +{ 9.10 + return false; 9.11 +}
10.1 --- a/src/scene.cc Fri Jan 17 18:16:09 2014 +0200 10.2 +++ b/src/scene.cc Fri Jan 17 18:27:47 2014 +0200 10.3 @@ -204,12 +204,7 @@ 10.4 return (int)nodes.size(); 10.5 } 10.6 10.7 - 10.8 -bool Scene::load(goat3d_io *io) 10.9 -{ 10.10 - return false; 10.11 -} 10.12 - 10.13 +// Scene::load is defined in goat3d_read.cc 10.14 // Scene::loadxml is defined in goat3d_readxml.cc 10.15 // Scene::save is defined in goat3d_write.cc 10.16 // Scene::savexml is defined in goat3d_writexml.cc