libanim

annotate src/anim.c @ 23:203c11299586

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