libanim

annotate src/anim.c @ 33:f12663c5c907

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