goat3d

annotate libs/anim/anim.c @ 56:ca549434dc95

fixed a crashing bug in anm_destroy_node introduced when I added the multiple animations per node
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 23 Jan 2014 02:50:54 +0200
parents 0ecb788a87f7
children
rev   line source
nuclear@27 1 #include <stdlib.h>
nuclear@27 2 #include <limits.h>
nuclear@27 3 #include <assert.h>
nuclear@27 4 #include "anim.h"
nuclear@27 5 #include "dynarr.h"
nuclear@27 6
nuclear@27 7 #define ROT_USE_SLERP
nuclear@27 8
nuclear@27 9 static void invalidate_cache(struct anm_node *node);
nuclear@27 10
nuclear@49 11 int anm_init_animation(struct anm_animation *anim)
nuclear@27 12 {
nuclear@27 13 int i, j;
nuclear@27 14 static const float defaults[] = {
nuclear@27 15 0.0f, 0.0f, 0.0f, /* default position */
nuclear@27 16 0.0f, 0.0f, 0.0f, 1.0f, /* default rotation quat */
nuclear@27 17 1.0f, 1.0f, 1.0f /* default scale factor */
nuclear@27 18 };
nuclear@27 19
nuclear@49 20 anim->name = 0;
nuclear@49 21
nuclear@49 22 for(i=0; i<ANM_NUM_TRACKS; i++) {
nuclear@49 23 if(anm_init_track(anim->tracks + i) == -1) {
nuclear@49 24 for(j=0; j<i; j++) {
nuclear@49 25 anm_destroy_track(anim->tracks + i);
nuclear@49 26 }
nuclear@49 27 }
nuclear@49 28 anm_set_track_default(anim->tracks + i, defaults[i]);
nuclear@49 29 }
nuclear@49 30 return 0;
nuclear@49 31 }
nuclear@49 32
nuclear@49 33 void anm_destroy_animation(struct anm_animation *anim)
nuclear@49 34 {
nuclear@49 35 int i;
nuclear@49 36 for(i=0; i<ANM_NUM_TRACKS; i++) {
nuclear@49 37 anm_destroy_track(anim->tracks + i);
nuclear@49 38 }
nuclear@49 39 free(anim->name);
nuclear@49 40 }
nuclear@49 41
nuclear@49 42 void anm_set_animation_name(struct anm_animation *anim, const char *name)
nuclear@49 43 {
nuclear@49 44 char *newname = malloc(strlen(name) + 1);
nuclear@49 45 if(!newname) return;
nuclear@49 46
nuclear@49 47 strcpy(newname, name);
nuclear@49 48
nuclear@49 49 free(anim->name);
nuclear@49 50 anim->name = newname;
nuclear@49 51 }
nuclear@49 52
nuclear@49 53 /* ---- node implementation ----- */
nuclear@49 54
nuclear@49 55 int anm_init_node(struct anm_node *node)
nuclear@49 56 {
nuclear@27 57 memset(node, 0, sizeof *node);
nuclear@27 58
nuclear@49 59 node->cur_anim[1] = -1;
nuclear@49 60
nuclear@49 61 if(!(node->animations = dynarr_alloc(1, sizeof *node->animations))) {
nuclear@49 62 return -1;
nuclear@49 63 }
nuclear@49 64 if(anm_init_animation(node->animations) == -1) {
nuclear@49 65 dynarr_free(node->animations);
nuclear@49 66 return -1;
nuclear@27 67 }
nuclear@27 68
nuclear@49 69 /* initialize thread-local matrix cache */
nuclear@49 70 pthread_key_create(&node->cache_key, 0);
nuclear@49 71 pthread_mutex_init(&node->cache_list_lock, 0);
nuclear@49 72
nuclear@27 73 return 0;
nuclear@27 74 }
nuclear@27 75
nuclear@27 76 void anm_destroy_node(struct anm_node *node)
nuclear@27 77 {
nuclear@56 78 int i, num_anim;
nuclear@27 79 free(node->name);
nuclear@27 80
nuclear@56 81 num_anim = anm_get_animation_count(node);
nuclear@56 82 for(i=0; i<num_anim; i++) {
nuclear@49 83 anm_destroy_animation(node->animations + i);
nuclear@49 84 }
nuclear@49 85 dynarr_free(node->animations);
nuclear@49 86
nuclear@49 87 /* destroy thread-specific cache */
nuclear@49 88 pthread_key_delete(node->cache_key);
nuclear@49 89
nuclear@49 90 while(node->cache_list) {
nuclear@49 91 struct mat_cache *tmp = node->cache_list;
nuclear@49 92 node->cache_list = tmp->next;
nuclear@49 93 free(tmp);
nuclear@27 94 }
nuclear@27 95 }
nuclear@27 96
nuclear@27 97 void anm_destroy_node_tree(struct anm_node *tree)
nuclear@27 98 {
nuclear@27 99 struct anm_node *c, *tmp;
nuclear@27 100
nuclear@27 101 if(!tree) return;
nuclear@27 102
nuclear@27 103 c = tree->child;
nuclear@27 104 while(c) {
nuclear@27 105 tmp = c;
nuclear@27 106 c = c->next;
nuclear@27 107
nuclear@27 108 anm_destroy_node_tree(tmp);
nuclear@27 109 }
nuclear@27 110 anm_destroy_node(tree);
nuclear@27 111 }
nuclear@27 112
nuclear@27 113 struct anm_node *anm_create_node(void)
nuclear@27 114 {
nuclear@27 115 struct anm_node *n;
nuclear@27 116
nuclear@27 117 if((n = malloc(sizeof *n))) {
nuclear@27 118 if(anm_init_node(n) == -1) {
nuclear@27 119 free(n);
nuclear@27 120 return 0;
nuclear@27 121 }
nuclear@27 122 }
nuclear@27 123 return n;
nuclear@27 124 }
nuclear@27 125
nuclear@27 126 void anm_free_node(struct anm_node *node)
nuclear@27 127 {
nuclear@27 128 anm_destroy_node(node);
nuclear@27 129 free(node);
nuclear@27 130 }
nuclear@27 131
nuclear@27 132 void anm_free_node_tree(struct anm_node *tree)
nuclear@27 133 {
nuclear@27 134 struct anm_node *c, *tmp;
nuclear@27 135
nuclear@27 136 if(!tree) return;
nuclear@27 137
nuclear@27 138 c = tree->child;
nuclear@27 139 while(c) {
nuclear@27 140 tmp = c;
nuclear@27 141 c = c->next;
nuclear@27 142
nuclear@27 143 anm_free_node_tree(tmp);
nuclear@27 144 }
nuclear@27 145
nuclear@27 146 anm_free_node(tree);
nuclear@27 147 }
nuclear@27 148
nuclear@27 149 int anm_set_node_name(struct anm_node *node, const char *name)
nuclear@27 150 {
nuclear@27 151 char *str;
nuclear@27 152
nuclear@27 153 if(!(str = malloc(strlen(name) + 1))) {
nuclear@27 154 return -1;
nuclear@27 155 }
nuclear@27 156 strcpy(str, name);
nuclear@27 157 free(node->name);
nuclear@27 158 node->name = str;
nuclear@27 159 return 0;
nuclear@27 160 }
nuclear@27 161
nuclear@27 162 const char *anm_get_node_name(struct anm_node *node)
nuclear@27 163 {
nuclear@27 164 return node->name ? node->name : "";
nuclear@27 165 }
nuclear@27 166
nuclear@27 167 void anm_link_node(struct anm_node *p, struct anm_node *c)
nuclear@27 168 {
nuclear@27 169 c->next = p->child;
nuclear@27 170 p->child = c;
nuclear@27 171
nuclear@27 172 c->parent = p;
nuclear@27 173 invalidate_cache(c);
nuclear@27 174 }
nuclear@27 175
nuclear@27 176 int anm_unlink_node(struct anm_node *p, struct anm_node *c)
nuclear@27 177 {
nuclear@27 178 struct anm_node *iter;
nuclear@27 179
nuclear@27 180 if(p->child == c) {
nuclear@27 181 p->child = c->next;
nuclear@27 182 c->next = 0;
nuclear@27 183 invalidate_cache(c);
nuclear@27 184 return 0;
nuclear@27 185 }
nuclear@27 186
nuclear@27 187 iter = p->child;
nuclear@27 188 while(iter->next) {
nuclear@27 189 if(iter->next == c) {
nuclear@27 190 iter->next = c->next;
nuclear@27 191 c->next = 0;
nuclear@27 192 invalidate_cache(c);
nuclear@27 193 return 0;
nuclear@27 194 }
nuclear@27 195 }
nuclear@27 196 return -1;
nuclear@27 197 }
nuclear@27 198
nuclear@49 199 void anm_set_pivot(struct anm_node *node, vec3_t piv)
nuclear@49 200 {
nuclear@49 201 node->pivot = piv;
nuclear@49 202 }
nuclear@49 203
nuclear@49 204 vec3_t anm_get_pivot(struct anm_node *node)
nuclear@49 205 {
nuclear@49 206 return node->pivot;
nuclear@49 207 }
nuclear@49 208
nuclear@49 209
nuclear@49 210 /* animation management */
nuclear@49 211
nuclear@49 212 int anm_use_node_animation(struct anm_node *node, int aidx)
nuclear@49 213 {
nuclear@49 214 if(aidx == node->cur_anim[0] && node->cur_anim[1] == -1) {
nuclear@49 215 return 0; /* no change, no invalidation */
nuclear@49 216 }
nuclear@49 217
nuclear@49 218 if(aidx < 0 || aidx >= anm_get_animation_count(node)) {
nuclear@49 219 return -1;
nuclear@49 220 }
nuclear@49 221
nuclear@49 222 node->cur_anim[0] = aidx;
nuclear@49 223 node->cur_anim[1] = -1;
nuclear@49 224 node->cur_mix = 0;
nuclear@49 225 node->blend_dur = -1;
nuclear@49 226
nuclear@49 227 invalidate_cache(node);
nuclear@49 228 return 0;
nuclear@49 229 }
nuclear@49 230
nuclear@49 231 int anm_use_node_animations(struct anm_node *node, int aidx, int bidx, float t)
nuclear@49 232 {
nuclear@49 233 int num_anim;
nuclear@49 234
nuclear@49 235 if(node->cur_anim[0] == aidx && node->cur_anim[1] == bidx &&
nuclear@49 236 fabs(t - node->cur_mix) < 1e-6) {
nuclear@49 237 return 0; /* no change, no invalidation */
nuclear@49 238 }
nuclear@49 239
nuclear@49 240 num_anim = anm_get_animation_count(node);
nuclear@49 241 if(aidx < 0 || aidx >= num_anim) {
nuclear@49 242 return anm_use_animation(node, bidx);
nuclear@49 243 }
nuclear@49 244 if(bidx < 0 || bidx >= num_anim) {
nuclear@49 245 return anm_use_animation(node, aidx);
nuclear@49 246 }
nuclear@49 247 node->cur_anim[0] = aidx;
nuclear@49 248 node->cur_anim[1] = bidx;
nuclear@49 249 node->cur_mix = t;
nuclear@49 250
nuclear@49 251 invalidate_cache(node);
nuclear@49 252 return 0;
nuclear@49 253 }
nuclear@49 254
nuclear@49 255 int anm_use_animation(struct anm_node *node, int aidx)
nuclear@49 256 {
nuclear@49 257 struct anm_node *child;
nuclear@49 258
nuclear@49 259 if(anm_use_node_animation(node, aidx) == -1) {
nuclear@49 260 return -1;
nuclear@49 261 }
nuclear@49 262
nuclear@49 263 child = node->child;
nuclear@49 264 while(child) {
nuclear@49 265 if(anm_use_animation(child, aidx) == -1) {
nuclear@49 266 return -1;
nuclear@49 267 }
nuclear@49 268 child = child->next;
nuclear@49 269 }
nuclear@49 270 return 0;
nuclear@49 271 }
nuclear@49 272
nuclear@49 273 int anm_use_animations(struct anm_node *node, int aidx, int bidx, float t)
nuclear@49 274 {
nuclear@49 275 struct anm_node *child;
nuclear@49 276
nuclear@49 277 if(anm_use_node_animations(node, aidx, bidx, t) == -1) {
nuclear@49 278 return -1;
nuclear@49 279 }
nuclear@49 280
nuclear@49 281 child = node->child;
nuclear@49 282 while(child) {
nuclear@49 283 if(anm_use_animations(child, aidx, bidx, t) == -1) {
nuclear@49 284 return -1;
nuclear@49 285 }
nuclear@49 286 child = child->next;
nuclear@49 287 }
nuclear@49 288 return 0;
nuclear@49 289
nuclear@49 290 }
nuclear@49 291
nuclear@49 292 void anm_set_node_animation_offset(struct anm_node *node, anm_time_t offs, int which)
nuclear@49 293 {
nuclear@49 294 if(which < 0 || which >= 2) {
nuclear@49 295 return;
nuclear@49 296 }
nuclear@49 297 node->cur_anim_offset[which] = offs;
nuclear@49 298 }
nuclear@49 299
nuclear@49 300 anm_time_t anm_get_animation_offset(const struct anm_node *node, int which)
nuclear@49 301 {
nuclear@49 302 if(which < 0 || which >= 2) {
nuclear@49 303 return 0;
nuclear@49 304 }
nuclear@49 305 return node->cur_anim_offset[which];
nuclear@49 306 }
nuclear@49 307
nuclear@49 308 void anm_set_animation_offset(struct anm_node *node, anm_time_t offs, int which)
nuclear@49 309 {
nuclear@49 310 struct anm_node *c = node->child;
nuclear@49 311 while(c) {
nuclear@49 312 anm_set_animation_offset(c, offs, which);
nuclear@49 313 c = c->next;
nuclear@49 314 }
nuclear@49 315
nuclear@49 316 anm_set_node_animation_offset(node, offs, which);
nuclear@49 317 }
nuclear@49 318
nuclear@49 319 int anm_get_active_animation_index(const struct anm_node *node, int which)
nuclear@49 320 {
nuclear@49 321 if(which < 0 || which >= 2) return -1;
nuclear@49 322 return node->cur_anim[which];
nuclear@49 323 }
nuclear@49 324
nuclear@49 325 struct anm_animation *anm_get_active_animation(const struct anm_node *node, int which)
nuclear@49 326 {
nuclear@49 327 int idx = anm_get_active_animation_index(node, which);
nuclear@49 328 if(idx < 0 || idx >= anm_get_animation_count(node)) {
nuclear@49 329 return 0;
nuclear@49 330 }
nuclear@49 331 return node->animations + idx;
nuclear@49 332 }
nuclear@49 333
nuclear@49 334 float anm_get_active_animation_mix(const struct anm_node *node)
nuclear@49 335 {
nuclear@49 336 return node->cur_mix;
nuclear@49 337 }
nuclear@49 338
nuclear@49 339 int anm_get_animation_count(const struct anm_node *node)
nuclear@49 340 {
nuclear@49 341 return dynarr_size(node->animations);
nuclear@49 342 }
nuclear@49 343
nuclear@49 344 int anm_add_node_animation(struct anm_node *node)
nuclear@49 345 {
nuclear@49 346 struct anm_animation newanim;
nuclear@49 347 anm_init_animation(&newanim);
nuclear@49 348
nuclear@49 349 node->animations = dynarr_push(node->animations, &newanim);
nuclear@49 350 return 0;
nuclear@49 351 }
nuclear@49 352
nuclear@49 353 int anm_remove_node_animation(struct anm_node *node, int idx)
nuclear@49 354 {
nuclear@49 355 fprintf(stderr, "anm_remove_animation: unimplemented!");
nuclear@49 356 abort();
nuclear@49 357 return 0;
nuclear@49 358 }
nuclear@49 359
nuclear@49 360 int anm_add_animation(struct anm_node *node)
nuclear@49 361 {
nuclear@49 362 struct anm_node *child;
nuclear@49 363
nuclear@49 364 if(anm_add_node_animation(node) == -1) {
nuclear@49 365 return -1;
nuclear@49 366 }
nuclear@49 367
nuclear@49 368 child = node->child;
nuclear@49 369 while(child) {
nuclear@49 370 if(anm_add_animation(child)) {
nuclear@49 371 return -1;
nuclear@49 372 }
nuclear@49 373 child = child->next;
nuclear@49 374 }
nuclear@49 375 return 0;
nuclear@49 376 }
nuclear@49 377
nuclear@49 378 int anm_remove_animation(struct anm_node *node, int idx)
nuclear@49 379 {
nuclear@49 380 struct anm_node *child;
nuclear@49 381
nuclear@49 382 if(anm_remove_node_animation(node, idx) == -1) {
nuclear@49 383 return -1;
nuclear@49 384 }
nuclear@49 385
nuclear@49 386 child = node->child;
nuclear@49 387 while(child) {
nuclear@49 388 if(anm_remove_animation(child, idx) == -1) {
nuclear@49 389 return -1;
nuclear@49 390 }
nuclear@49 391 child = child->next;
nuclear@49 392 }
nuclear@49 393 return 0;
nuclear@49 394 }
nuclear@49 395
nuclear@49 396 struct anm_animation *anm_get_animation(struct anm_node *node, int idx)
nuclear@49 397 {
nuclear@49 398 if(idx < 0 || idx > anm_get_animation_count(node)) {
nuclear@49 399 return 0;
nuclear@49 400 }
nuclear@49 401 return node->animations + idx;
nuclear@49 402 }
nuclear@49 403
nuclear@49 404 struct anm_animation *anm_get_animation_by_name(struct anm_node *node, const char *name)
nuclear@49 405 {
nuclear@49 406 return anm_get_animation(node, anm_find_animation(node, name));
nuclear@49 407 }
nuclear@49 408
nuclear@49 409 int anm_find_animation(struct anm_node *node, const char *name)
nuclear@49 410 {
nuclear@49 411 int i, count = anm_get_animation_count(node);
nuclear@49 412 for(i=0; i<count; i++) {
nuclear@49 413 if(strcmp(node->animations[i].name, name) == 0) {
nuclear@49 414 return i;
nuclear@49 415 }
nuclear@49 416 }
nuclear@49 417 return -1;
nuclear@49 418 }
nuclear@49 419
nuclear@49 420 /* all the rest act on the current animation(s) */
nuclear@49 421
nuclear@49 422 void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in)
nuclear@49 423 {
nuclear@49 424 int i;
nuclear@49 425 struct anm_animation *anim = anm_get_active_animation(node, 0);
nuclear@49 426 if(!anim) return;
nuclear@49 427
nuclear@49 428 for(i=0; i<ANM_NUM_TRACKS; i++) {
nuclear@49 429 anm_set_track_interpolator(anim->tracks + i, in);
nuclear@49 430 }
nuclear@49 431 invalidate_cache(node);
nuclear@49 432 }
nuclear@49 433
nuclear@49 434 void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex)
nuclear@49 435 {
nuclear@49 436 int i;
nuclear@49 437 struct anm_animation *anim = anm_get_active_animation(node, 0);
nuclear@49 438 if(!anim) return;
nuclear@49 439
nuclear@49 440 for(i=0; i<ANM_NUM_TRACKS; i++) {
nuclear@49 441 anm_set_track_extrapolator(anim->tracks + i, ex);
nuclear@49 442 }
nuclear@49 443 invalidate_cache(node);
nuclear@49 444 }
nuclear@49 445
nuclear@49 446 void anm_set_node_active_animation_name(struct anm_node *node, const char *name)
nuclear@49 447 {
nuclear@49 448 struct anm_animation *anim = anm_get_active_animation(node, 0);
nuclear@49 449 if(!anim) return;
nuclear@49 450
nuclear@49 451 anm_set_animation_name(anim, name);
nuclear@49 452 }
nuclear@49 453
nuclear@49 454 void anm_set_active_animation_name(struct anm_node *node, const char *name)
nuclear@49 455 {
nuclear@49 456 struct anm_node *child;
nuclear@49 457
nuclear@49 458 anm_set_node_active_animation_name(node, name);
nuclear@49 459
nuclear@49 460 child = node->child;
nuclear@49 461 while(child) {
nuclear@49 462 anm_set_active_animation_name(child, name);
nuclear@49 463 child = child->next;
nuclear@49 464 }
nuclear@49 465 }
nuclear@49 466
nuclear@49 467 const char *anm_get_active_animation_name(struct anm_node *node)
nuclear@49 468 {
nuclear@49 469 struct anm_animation *anim = anm_get_active_animation(node, 0);
nuclear@49 470 if(anim) {
nuclear@49 471 return anim->name;
nuclear@49 472 }
nuclear@49 473 return 0;
nuclear@49 474 }
nuclear@49 475
nuclear@49 476 /* ---- high level animation blending ---- */
nuclear@49 477 void anm_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur)
nuclear@49 478 {
nuclear@49 479 struct anm_node *c = node->child;
nuclear@49 480
nuclear@49 481 if(anmidx == node->cur_anim[0]) {
nuclear@49 482 return;
nuclear@49 483 }
nuclear@49 484
nuclear@49 485 while(c) {
nuclear@49 486 anm_transition(c, anmidx, start, dur);
nuclear@49 487 c = c->next;
nuclear@49 488 }
nuclear@49 489
nuclear@49 490 anm_node_transition(node, anmidx, start, dur);
nuclear@49 491 }
nuclear@49 492
nuclear@49 493 void anm_node_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur)
nuclear@49 494 {
nuclear@49 495 if(anmidx == node->cur_anim[0]) {
nuclear@49 496 return;
nuclear@49 497 }
nuclear@49 498
nuclear@49 499 node->cur_anim[1] = anmidx;
nuclear@49 500 node->cur_anim_offset[1] = start;
nuclear@49 501 node->blend_dur = dur;
nuclear@49 502 }
nuclear@49 503
nuclear@49 504
nuclear@49 505 #define BLEND_START_TM node->cur_anim_offset[1]
nuclear@49 506
nuclear@49 507 static anm_time_t animation_time(struct anm_node *node, anm_time_t tm, int which)
nuclear@49 508 {
nuclear@49 509 float t;
nuclear@49 510
nuclear@49 511 if(node->blend_dur >= 0) {
nuclear@49 512 /* we're in transition... */
nuclear@49 513 t = (float)(tm - BLEND_START_TM) / (float)node->blend_dur;
nuclear@49 514 if(t < 0.0) t = 0.0;
nuclear@49 515
nuclear@49 516 node->cur_mix = t;
nuclear@49 517
nuclear@49 518 if(t > 1.0) {
nuclear@49 519 /* switch completely over to the target animation and stop blending */
nuclear@49 520 anm_use_node_animation(node, node->cur_anim[1]);
nuclear@49 521 node->cur_anim_offset[0] = node->cur_anim_offset[1];
nuclear@49 522 }
nuclear@49 523 }
nuclear@49 524
nuclear@49 525 return tm - node->cur_anim_offset[which];
nuclear@49 526 }
nuclear@49 527
nuclear@49 528
nuclear@27 529 void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm)
nuclear@27 530 {
nuclear@49 531 struct anm_animation *anim = anm_get_active_animation(node, 0);
nuclear@49 532 if(!anim) return;
nuclear@49 533
nuclear@49 534 anm_set_value(anim->tracks + ANM_TRACK_POS_X, tm, pos.x);
nuclear@49 535 anm_set_value(anim->tracks + ANM_TRACK_POS_Y, tm, pos.y);
nuclear@49 536 anm_set_value(anim->tracks + ANM_TRACK_POS_Z, tm, pos.z);
nuclear@27 537 invalidate_cache(node);
nuclear@27 538 }
nuclear@27 539
nuclear@49 540
nuclear@27 541 vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm)
nuclear@27 542 {
nuclear@27 543 vec3_t v;
nuclear@49 544 anm_time_t tm0 = animation_time(node, tm, 0);
nuclear@49 545 struct anm_animation *anim0 = anm_get_active_animation(node, 0);
nuclear@49 546 struct anm_animation *anim1 = anm_get_active_animation(node, 1);
nuclear@49 547
nuclear@49 548 if(!anim0) {
nuclear@49 549 return v3_cons(0, 0, 0);
nuclear@49 550 }
nuclear@49 551
nuclear@49 552 v.x = anm_get_value(anim0->tracks + ANM_TRACK_POS_X, tm0);
nuclear@49 553 v.y = anm_get_value(anim0->tracks + ANM_TRACK_POS_Y, tm0);
nuclear@49 554 v.z = anm_get_value(anim0->tracks + ANM_TRACK_POS_Z, tm0);
nuclear@49 555
nuclear@49 556 if(anim1) {
nuclear@49 557 vec3_t v1;
nuclear@49 558 anm_time_t tm1 = animation_time(node, tm, 1);
nuclear@49 559 v1.x = anm_get_value(anim1->tracks + ANM_TRACK_POS_X, tm1);
nuclear@49 560 v1.y = anm_get_value(anim1->tracks + ANM_TRACK_POS_Y, tm1);
nuclear@49 561 v1.z = anm_get_value(anim1->tracks + ANM_TRACK_POS_Z, tm1);
nuclear@49 562
nuclear@49 563 v.x = v.x + (v1.x - v.x) * node->cur_mix;
nuclear@49 564 v.y = v.y + (v1.y - v.y) * node->cur_mix;
nuclear@49 565 v.z = v.z + (v1.z - v.z) * node->cur_mix;
nuclear@49 566 }
nuclear@49 567
nuclear@27 568 return v;
nuclear@27 569 }
nuclear@27 570
nuclear@27 571 void anm_set_rotation(struct anm_node *node, quat_t rot, anm_time_t tm)
nuclear@27 572 {
nuclear@49 573 struct anm_animation *anim = anm_get_active_animation(node, 0);
nuclear@49 574 if(!anim) return;
nuclear@49 575
nuclear@49 576 anm_set_value(anim->tracks + ANM_TRACK_ROT_X, tm, rot.x);
nuclear@49 577 anm_set_value(anim->tracks + ANM_TRACK_ROT_Y, tm, rot.y);
nuclear@49 578 anm_set_value(anim->tracks + ANM_TRACK_ROT_Z, tm, rot.z);
nuclear@49 579 anm_set_value(anim->tracks + ANM_TRACK_ROT_W, tm, rot.w);
nuclear@27 580 invalidate_cache(node);
nuclear@27 581 }
nuclear@27 582
nuclear@49 583 static quat_t get_node_rotation(struct anm_node *node, anm_time_t tm, struct anm_animation *anim)
nuclear@27 584 {
nuclear@27 585 #ifndef ROT_USE_SLERP
nuclear@27 586 quat_t q;
nuclear@49 587 q.x = anm_get_value(anim->tracks + ANM_TRACK_ROT_X, tm);
nuclear@49 588 q.y = anm_get_value(anim->tracks + ANM_TRACK_ROT_Y, tm);
nuclear@49 589 q.z = anm_get_value(anim->tracks + ANM_TRACK_ROT_Z, tm);
nuclear@49 590 q.w = anm_get_value(anim->tracks + ANM_TRACK_ROT_W, tm);
nuclear@27 591 return q;
nuclear@27 592 #else
nuclear@27 593 int idx0, idx1, last_idx;
nuclear@27 594 anm_time_t tstart, tend;
nuclear@27 595 float t, dt;
nuclear@27 596 struct anm_track *track_x, *track_y, *track_z, *track_w;
nuclear@27 597 quat_t q, q1, q2;
nuclear@27 598
nuclear@49 599 track_x = anim->tracks + ANM_TRACK_ROT_X;
nuclear@49 600 track_y = anim->tracks + ANM_TRACK_ROT_Y;
nuclear@49 601 track_z = anim->tracks + ANM_TRACK_ROT_Z;
nuclear@49 602 track_w = anim->tracks + ANM_TRACK_ROT_W;
nuclear@27 603
nuclear@27 604 if(!track_x->count) {
nuclear@27 605 q.x = track_x->def_val;
nuclear@27 606 q.y = track_y->def_val;
nuclear@27 607 q.z = track_z->def_val;
nuclear@27 608 q.w = track_w->def_val;
nuclear@27 609 return q;
nuclear@27 610 }
nuclear@27 611
nuclear@27 612 last_idx = track_x->count - 1;
nuclear@27 613
nuclear@27 614 tstart = track_x->keys[0].time;
nuclear@27 615 tend = track_x->keys[last_idx].time;
nuclear@27 616
nuclear@27 617 if(tstart == tend) {
nuclear@27 618 q.x = track_x->keys[0].val;
nuclear@27 619 q.y = track_y->keys[0].val;
nuclear@27 620 q.z = track_z->keys[0].val;
nuclear@27 621 q.w = track_w->keys[0].val;
nuclear@27 622 return q;
nuclear@27 623 }
nuclear@27 624
nuclear@27 625 tm = anm_remap_time(track_x, tm, tstart, tend);
nuclear@27 626
nuclear@27 627 idx0 = anm_get_key_interval(track_x, tm);
nuclear@27 628 assert(idx0 >= 0 && idx0 < track_x->count);
nuclear@27 629 idx1 = idx0 + 1;
nuclear@27 630
nuclear@27 631 if(idx0 == last_idx) {
nuclear@27 632 q.x = track_x->keys[idx0].val;
nuclear@27 633 q.y = track_y->keys[idx0].val;
nuclear@27 634 q.z = track_z->keys[idx0].val;
nuclear@27 635 q.w = track_w->keys[idx0].val;
nuclear@27 636 return q;
nuclear@27 637 }
nuclear@27 638
nuclear@27 639 dt = (float)(track_x->keys[idx1].time - track_x->keys[idx0].time);
nuclear@27 640 t = (float)(tm - track_x->keys[idx0].time) / dt;
nuclear@27 641
nuclear@27 642 q1.x = track_x->keys[idx0].val;
nuclear@27 643 q1.y = track_y->keys[idx0].val;
nuclear@27 644 q1.z = track_z->keys[idx0].val;
nuclear@27 645 q1.w = track_w->keys[idx0].val;
nuclear@27 646
nuclear@27 647 q2.x = track_x->keys[idx1].val;
nuclear@27 648 q2.y = track_y->keys[idx1].val;
nuclear@27 649 q2.z = track_z->keys[idx1].val;
nuclear@27 650 q2.w = track_w->keys[idx1].val;
nuclear@27 651
nuclear@27 652 /*q1 = quat_normalize(q1);
nuclear@27 653 q2 = quat_normalize(q2);*/
nuclear@27 654
nuclear@27 655 return quat_slerp(q1, q2, t);
nuclear@27 656 #endif
nuclear@27 657 }
nuclear@27 658
nuclear@49 659 quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm)
nuclear@49 660 {
nuclear@49 661 quat_t q;
nuclear@49 662 anm_time_t tm0 = animation_time(node, tm, 0);
nuclear@49 663 struct anm_animation *anim0 = anm_get_active_animation(node, 0);
nuclear@49 664 struct anm_animation *anim1 = anm_get_active_animation(node, 1);
nuclear@49 665
nuclear@49 666 if(!anim0) {
nuclear@49 667 return quat_identity();
nuclear@49 668 }
nuclear@49 669
nuclear@49 670 q = get_node_rotation(node, tm0, anim0);
nuclear@49 671
nuclear@49 672 if(anim1) {
nuclear@49 673 anm_time_t tm1 = animation_time(node, tm, 1);
nuclear@49 674 quat_t q1 = get_node_rotation(node, tm1, anim1);
nuclear@49 675
nuclear@49 676 q = quat_slerp(q, q1, node->cur_mix);
nuclear@49 677 }
nuclear@49 678 return q;
nuclear@49 679 }
nuclear@49 680
nuclear@27 681 void anm_set_scaling(struct anm_node *node, vec3_t scl, anm_time_t tm)
nuclear@27 682 {
nuclear@49 683 struct anm_animation *anim = anm_get_active_animation(node, 0);
nuclear@49 684 if(!anim) return;
nuclear@49 685
nuclear@49 686 anm_set_value(anim->tracks + ANM_TRACK_SCL_X, tm, scl.x);
nuclear@49 687 anm_set_value(anim->tracks + ANM_TRACK_SCL_Y, tm, scl.y);
nuclear@49 688 anm_set_value(anim->tracks + ANM_TRACK_SCL_Z, tm, scl.z);
nuclear@27 689 invalidate_cache(node);
nuclear@27 690 }
nuclear@27 691
nuclear@27 692 vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm)
nuclear@27 693 {
nuclear@27 694 vec3_t v;
nuclear@49 695 anm_time_t tm0 = animation_time(node, tm, 0);
nuclear@49 696 struct anm_animation *anim0 = anm_get_active_animation(node, 0);
nuclear@49 697 struct anm_animation *anim1 = anm_get_active_animation(node, 1);
nuclear@49 698
nuclear@49 699 if(!anim0) {
nuclear@49 700 return v3_cons(1, 1, 1);
nuclear@49 701 }
nuclear@49 702
nuclear@49 703 v.x = anm_get_value(anim0->tracks + ANM_TRACK_SCL_X, tm0);
nuclear@49 704 v.y = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Y, tm0);
nuclear@49 705 v.z = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Z, tm0);
nuclear@49 706
nuclear@49 707 if(anim1) {
nuclear@49 708 vec3_t v1;
nuclear@49 709 anm_time_t tm1 = animation_time(node, tm, 1);
nuclear@49 710 v1.x = anm_get_value(anim1->tracks + ANM_TRACK_SCL_X, tm1);
nuclear@49 711 v1.y = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Y, tm1);
nuclear@49 712 v1.z = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Z, tm1);
nuclear@49 713
nuclear@49 714 v.x = v.x + (v1.x - v.x) * node->cur_mix;
nuclear@49 715 v.y = v.y + (v1.y - v.y) * node->cur_mix;
nuclear@49 716 v.z = v.z + (v1.z - v.z) * node->cur_mix;
nuclear@49 717 }
nuclear@49 718
nuclear@27 719 return v;
nuclear@27 720 }
nuclear@27 721
nuclear@27 722
nuclear@27 723 vec3_t anm_get_position(struct anm_node *node, anm_time_t tm)
nuclear@27 724 {
nuclear@27 725 mat4_t xform;
nuclear@27 726 vec3_t pos = {0.0, 0.0, 0.0};
nuclear@27 727
nuclear@27 728 if(!node->parent) {
nuclear@27 729 return anm_get_node_position(node, tm);
nuclear@27 730 }
nuclear@27 731
nuclear@27 732 anm_get_matrix(node, xform, tm);
nuclear@27 733 return v3_transform(pos, xform);
nuclear@27 734 }
nuclear@27 735
nuclear@27 736 quat_t anm_get_rotation(struct anm_node *node, anm_time_t tm)
nuclear@27 737 {
nuclear@27 738 quat_t rot, prot;
nuclear@27 739 rot = anm_get_node_rotation(node, tm);
nuclear@27 740
nuclear@27 741 if(!node->parent) {
nuclear@27 742 return rot;
nuclear@27 743 }
nuclear@27 744
nuclear@27 745 prot = anm_get_rotation(node->parent, tm);
nuclear@27 746 return quat_mul(prot, rot);
nuclear@27 747 }
nuclear@27 748
nuclear@27 749 vec3_t anm_get_scaling(struct anm_node *node, anm_time_t tm)
nuclear@27 750 {
nuclear@27 751 vec3_t s, ps;
nuclear@27 752 s = anm_get_node_scaling(node, tm);
nuclear@27 753
nuclear@27 754 if(!node->parent) {
nuclear@27 755 return s;
nuclear@27 756 }
nuclear@27 757
nuclear@27 758 ps = anm_get_scaling(node->parent, tm);
nuclear@27 759 return v3_mul(s, ps);
nuclear@27 760 }
nuclear@27 761
nuclear@27 762 void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
nuclear@27 763 {
nuclear@27 764 int i;
nuclear@27 765 mat4_t rmat;
nuclear@27 766 vec3_t pos, scale;
nuclear@27 767 quat_t rot;
nuclear@27 768
nuclear@27 769 pos = anm_get_node_position(node, tm);
nuclear@27 770 rot = anm_get_node_rotation(node, tm);
nuclear@27 771 scale = anm_get_node_scaling(node, tm);
nuclear@27 772
nuclear@27 773 m4_set_translation(mat, node->pivot.x, node->pivot.y, node->pivot.z);
nuclear@27 774
nuclear@27 775 quat_to_mat4(rmat, rot);
nuclear@27 776 for(i=0; i<3; i++) {
nuclear@27 777 mat[i][0] = rmat[i][0];
nuclear@27 778 mat[i][1] = rmat[i][1];
nuclear@27 779 mat[i][2] = rmat[i][2];
nuclear@27 780 }
nuclear@27 781 /* this loop is equivalent to: m4_mult(mat, mat, rmat); */
nuclear@27 782
nuclear@27 783 mat[0][0] *= scale.x; mat[0][1] *= scale.y; mat[0][2] *= scale.z; mat[0][3] += pos.x;
nuclear@27 784 mat[1][0] *= scale.x; mat[1][1] *= scale.y; mat[1][2] *= scale.z; mat[1][3] += pos.y;
nuclear@27 785 mat[2][0] *= scale.x; mat[2][1] *= scale.y; mat[2][2] *= scale.z; mat[2][3] += pos.z;
nuclear@27 786
nuclear@27 787 m4_translate(mat, -node->pivot.x, -node->pivot.y, -node->pivot.z);
nuclear@27 788
nuclear@27 789 /* that's basically: pivot * rotation * translation * scaling * -pivot */
nuclear@27 790 }
nuclear@27 791
nuclear@27 792 void anm_get_node_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
nuclear@27 793 {
nuclear@27 794 mat4_t tmp;
nuclear@27 795 anm_get_node_matrix(node, tmp, tm);
nuclear@27 796 m4_inverse(mat, tmp);
nuclear@27 797 }
nuclear@27 798
nuclear@49 799 void anm_eval_node(struct anm_node *node, anm_time_t tm)
nuclear@49 800 {
nuclear@49 801 anm_get_node_matrix(node, node->matrix, tm);
nuclear@49 802 }
nuclear@49 803
nuclear@49 804 void anm_eval(struct anm_node *node, anm_time_t tm)
nuclear@49 805 {
nuclear@49 806 struct anm_node *c;
nuclear@49 807
nuclear@49 808 anm_eval_node(node, tm);
nuclear@49 809
nuclear@49 810 if(node->parent) {
nuclear@49 811 /* due to post-order traversal, the parent matrix is already evaluated */
nuclear@49 812 m4_mult(node->matrix, node->parent->matrix, node->matrix);
nuclear@49 813 }
nuclear@49 814
nuclear@49 815 /* recersively evaluate all children */
nuclear@49 816 c = node->child;
nuclear@49 817 while(c) {
nuclear@49 818 anm_eval(c, tm);
nuclear@49 819 c = c->next;
nuclear@49 820 }
nuclear@49 821 }
nuclear@49 822
nuclear@27 823 void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
nuclear@27 824 {
nuclear@49 825 struct mat_cache *cache = pthread_getspecific(node->cache_key);
nuclear@49 826 if(!cache) {
nuclear@49 827 cache = malloc(sizeof *cache);
nuclear@49 828 assert(cache);
nuclear@49 829
nuclear@49 830 pthread_mutex_lock(&node->cache_list_lock);
nuclear@49 831 cache->next = node->cache_list;
nuclear@49 832 node->cache_list = cache;
nuclear@49 833 pthread_mutex_unlock(&node->cache_list_lock);
nuclear@49 834
nuclear@49 835 cache->time = ANM_TIME_INVAL;
nuclear@49 836 cache->inv_time = ANM_TIME_INVAL;
nuclear@49 837 pthread_setspecific(node->cache_key, cache);
nuclear@49 838 }
nuclear@49 839
nuclear@49 840 if(cache->time != tm) {
nuclear@49 841 anm_get_node_matrix(node, cache->matrix, tm);
nuclear@27 842
nuclear@27 843 if(node->parent) {
nuclear@27 844 mat4_t parent_mat;
nuclear@27 845
nuclear@27 846 anm_get_matrix(node->parent, parent_mat, tm);
nuclear@49 847 m4_mult(cache->matrix, parent_mat, cache->matrix);
nuclear@27 848 }
nuclear@49 849 cache->time = tm;
nuclear@27 850 }
nuclear@49 851 m4_copy(mat, cache->matrix);
nuclear@27 852 }
nuclear@27 853
nuclear@27 854 void anm_get_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
nuclear@27 855 {
nuclear@49 856 struct mat_cache *cache = pthread_getspecific(node->cache_key);
nuclear@49 857 if(!cache) {
nuclear@49 858 cache = malloc(sizeof *cache);
nuclear@49 859 assert(cache);
nuclear@49 860
nuclear@49 861 pthread_mutex_lock(&node->cache_list_lock);
nuclear@49 862 cache->next = node->cache_list;
nuclear@49 863 node->cache_list = cache;
nuclear@49 864 pthread_mutex_unlock(&node->cache_list_lock);
nuclear@49 865
nuclear@49 866 cache->inv_time = ANM_TIME_INVAL;
nuclear@49 867 cache->inv_time = ANM_TIME_INVAL;
nuclear@49 868 pthread_setspecific(node->cache_key, cache);
nuclear@49 869 }
nuclear@49 870
nuclear@49 871 if(cache->inv_time != tm) {
nuclear@27 872 anm_get_matrix(node, mat, tm);
nuclear@49 873 m4_inverse(cache->inv_matrix, mat);
nuclear@49 874 cache->inv_time = tm;
nuclear@27 875 }
nuclear@49 876 m4_copy(mat, cache->inv_matrix);
nuclear@27 877 }
nuclear@27 878
nuclear@27 879 anm_time_t anm_get_start_time(struct anm_node *node)
nuclear@27 880 {
nuclear@49 881 int i, j;
nuclear@27 882 struct anm_node *c;
nuclear@27 883 anm_time_t res = LONG_MAX;
nuclear@27 884
nuclear@49 885 for(j=0; j<2; j++) {
nuclear@49 886 struct anm_animation *anim = anm_get_active_animation(node, j);
nuclear@49 887 if(!anim) break;
nuclear@49 888
nuclear@49 889 for(i=0; i<ANM_NUM_TRACKS; i++) {
nuclear@49 890 if(anim->tracks[i].count) {
nuclear@49 891 anm_time_t tm = anim->tracks[i].keys[0].time;
nuclear@49 892 if(tm < res) {
nuclear@49 893 res = tm;
nuclear@49 894 }
nuclear@27 895 }
nuclear@27 896 }
nuclear@27 897 }
nuclear@27 898
nuclear@27 899 c = node->child;
nuclear@27 900 while(c) {
nuclear@27 901 anm_time_t tm = anm_get_start_time(c);
nuclear@27 902 if(tm < res) {
nuclear@27 903 res = tm;
nuclear@27 904 }
nuclear@27 905 c = c->next;
nuclear@27 906 }
nuclear@27 907 return res;
nuclear@27 908 }
nuclear@27 909
nuclear@27 910 anm_time_t anm_get_end_time(struct anm_node *node)
nuclear@27 911 {
nuclear@49 912 int i, j;
nuclear@27 913 struct anm_node *c;
nuclear@27 914 anm_time_t res = LONG_MIN;
nuclear@27 915
nuclear@49 916 for(j=0; j<2; j++) {
nuclear@49 917 struct anm_animation *anim = anm_get_active_animation(node, j);
nuclear@49 918 if(!anim) break;
nuclear@49 919
nuclear@49 920 for(i=0; i<ANM_NUM_TRACKS; i++) {
nuclear@49 921 if(anim->tracks[i].count) {
nuclear@49 922 anm_time_t tm = anim->tracks[i].keys[anim->tracks[i].count - 1].time;
nuclear@49 923 if(tm > res) {
nuclear@49 924 res = tm;
nuclear@49 925 }
nuclear@27 926 }
nuclear@27 927 }
nuclear@27 928 }
nuclear@27 929
nuclear@27 930 c = node->child;
nuclear@27 931 while(c) {
nuclear@27 932 anm_time_t tm = anm_get_end_time(c);
nuclear@27 933 if(tm > res) {
nuclear@27 934 res = tm;
nuclear@27 935 }
nuclear@27 936 c = c->next;
nuclear@27 937 }
nuclear@27 938 return res;
nuclear@27 939 }
nuclear@27 940
nuclear@27 941 static void invalidate_cache(struct anm_node *node)
nuclear@27 942 {
nuclear@49 943 struct mat_cache *cache = pthread_getspecific(node->cache_key);
nuclear@49 944 if(cache) {
nuclear@49 945 cache->time = cache->inv_time = ANM_TIME_INVAL;
nuclear@49 946 }
nuclear@27 947 }