libanim

annotate src/anim.c @ 22:9758004136f8

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