goat3d

annotate libs/anim/anim.c @ 43:1dcbe87b6a5d

ops, screwed up the GOAT3DAPI define
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 05 Dec 2013 18:49:19 +0200
parents
children 0ecb788a87f7
rev   line source
nuclear@27 1 #include <stdlib.h>
nuclear@27 2 #include <limits.h>
nuclear@27 3 #include <assert.h>
nuclear@27 4 #include "anim.h"
nuclear@27 5 #include "dynarr.h"
nuclear@27 6
nuclear@27 7 #define ROT_USE_SLERP
nuclear@27 8
nuclear@27 9 static void invalidate_cache(struct anm_node *node);
nuclear@27 10
nuclear@27 11 int anm_init_node(struct anm_node *node)
nuclear@27 12 {
nuclear@27 13 int i, j;
nuclear@27 14 static const float defaults[] = {
nuclear@27 15 0.0f, 0.0f, 0.0f, /* default position */
nuclear@27 16 0.0f, 0.0f, 0.0f, 1.0f, /* default rotation quat */
nuclear@27 17 1.0f, 1.0f, 1.0f /* default scale factor */
nuclear@27 18 };
nuclear@27 19
nuclear@27 20 memset(node, 0, sizeof *node);
nuclear@27 21
nuclear@27 22 for(i=0; i<ANM_NUM_TRACKS; i++) {
nuclear@27 23 if(anm_init_track(node->tracks + i) == -1) {
nuclear@27 24 for(j=0; j<i; j++) {
nuclear@27 25 anm_destroy_track(node->tracks + i);
nuclear@27 26 }
nuclear@27 27 }
nuclear@27 28 anm_set_track_default(node->tracks + i, defaults[i]);
nuclear@27 29 }
nuclear@27 30
nuclear@27 31 node->cache.time = ANM_TIME_INVAL;
nuclear@27 32 node->cache.inv_time = ANM_TIME_INVAL;
nuclear@27 33 return 0;
nuclear@27 34 }
nuclear@27 35
nuclear@27 36 void anm_destroy_node(struct anm_node *node)
nuclear@27 37 {
nuclear@27 38 int i;
nuclear@27 39 free(node->name);
nuclear@27 40
nuclear@27 41 for(i=0; i<ANM_NUM_TRACKS; i++) {
nuclear@27 42 anm_destroy_track(node->tracks + i);
nuclear@27 43 }
nuclear@27 44 }
nuclear@27 45
nuclear@27 46 void anm_destroy_node_tree(struct anm_node *tree)
nuclear@27 47 {
nuclear@27 48 struct anm_node *c, *tmp;
nuclear@27 49
nuclear@27 50 if(!tree) return;
nuclear@27 51
nuclear@27 52 c = tree->child;
nuclear@27 53 while(c) {
nuclear@27 54 tmp = c;
nuclear@27 55 c = c->next;
nuclear@27 56
nuclear@27 57 anm_destroy_node_tree(tmp);
nuclear@27 58 }
nuclear@27 59 anm_destroy_node(tree);
nuclear@27 60 }
nuclear@27 61
nuclear@27 62 struct anm_node *anm_create_node(void)
nuclear@27 63 {
nuclear@27 64 struct anm_node *n;
nuclear@27 65
nuclear@27 66 if((n = malloc(sizeof *n))) {
nuclear@27 67 if(anm_init_node(n) == -1) {
nuclear@27 68 free(n);
nuclear@27 69 return 0;
nuclear@27 70 }
nuclear@27 71 }
nuclear@27 72 return n;
nuclear@27 73 }
nuclear@27 74
nuclear@27 75 void anm_free_node(struct anm_node *node)
nuclear@27 76 {
nuclear@27 77 anm_destroy_node(node);
nuclear@27 78 free(node);
nuclear@27 79 }
nuclear@27 80
nuclear@27 81 void anm_free_node_tree(struct anm_node *tree)
nuclear@27 82 {
nuclear@27 83 struct anm_node *c, *tmp;
nuclear@27 84
nuclear@27 85 if(!tree) return;
nuclear@27 86
nuclear@27 87 c = tree->child;
nuclear@27 88 while(c) {
nuclear@27 89 tmp = c;
nuclear@27 90 c = c->next;
nuclear@27 91
nuclear@27 92 anm_free_node_tree(tmp);
nuclear@27 93 }
nuclear@27 94
nuclear@27 95 anm_free_node(tree);
nuclear@27 96 }
nuclear@27 97
nuclear@27 98 int anm_set_node_name(struct anm_node *node, const char *name)
nuclear@27 99 {
nuclear@27 100 char *str;
nuclear@27 101
nuclear@27 102 if(!(str = malloc(strlen(name) + 1))) {
nuclear@27 103 return -1;
nuclear@27 104 }
nuclear@27 105 strcpy(str, name);
nuclear@27 106 free(node->name);
nuclear@27 107 node->name = str;
nuclear@27 108 return 0;
nuclear@27 109 }
nuclear@27 110
nuclear@27 111 const char *anm_get_node_name(struct anm_node *node)
nuclear@27 112 {
nuclear@27 113 return node->name ? node->name : "";
nuclear@27 114 }
nuclear@27 115
nuclear@27 116 void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in)
nuclear@27 117 {
nuclear@27 118 int i;
nuclear@27 119
nuclear@27 120 for(i=0; i<ANM_NUM_TRACKS; i++) {
nuclear@27 121 anm_set_track_interpolator(node->tracks + i, in);
nuclear@27 122 }
nuclear@27 123 invalidate_cache(node);
nuclear@27 124 }
nuclear@27 125
nuclear@27 126 void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex)
nuclear@27 127 {
nuclear@27 128 int i;
nuclear@27 129
nuclear@27 130 for(i=0; i<ANM_NUM_TRACKS; i++) {
nuclear@27 131 anm_set_track_extrapolator(node->tracks + i, ex);
nuclear@27 132 }
nuclear@27 133 invalidate_cache(node);
nuclear@27 134 }
nuclear@27 135
nuclear@27 136 void anm_link_node(struct anm_node *p, struct anm_node *c)
nuclear@27 137 {
nuclear@27 138 c->next = p->child;
nuclear@27 139 p->child = c;
nuclear@27 140
nuclear@27 141 c->parent = p;
nuclear@27 142 invalidate_cache(c);
nuclear@27 143 }
nuclear@27 144
nuclear@27 145 int anm_unlink_node(struct anm_node *p, struct anm_node *c)
nuclear@27 146 {
nuclear@27 147 struct anm_node *iter;
nuclear@27 148
nuclear@27 149 if(p->child == c) {
nuclear@27 150 p->child = c->next;
nuclear@27 151 c->next = 0;
nuclear@27 152 invalidate_cache(c);
nuclear@27 153 return 0;
nuclear@27 154 }
nuclear@27 155
nuclear@27 156 iter = p->child;
nuclear@27 157 while(iter->next) {
nuclear@27 158 if(iter->next == c) {
nuclear@27 159 iter->next = c->next;
nuclear@27 160 c->next = 0;
nuclear@27 161 invalidate_cache(c);
nuclear@27 162 return 0;
nuclear@27 163 }
nuclear@27 164 }
nuclear@27 165 return -1;
nuclear@27 166 }
nuclear@27 167
nuclear@27 168 void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm)
nuclear@27 169 {
nuclear@27 170 anm_set_value(node->tracks + ANM_TRACK_POS_X, tm, pos.x);
nuclear@27 171 anm_set_value(node->tracks + ANM_TRACK_POS_Y, tm, pos.y);
nuclear@27 172 anm_set_value(node->tracks + ANM_TRACK_POS_Z, tm, pos.z);
nuclear@27 173 invalidate_cache(node);
nuclear@27 174 }
nuclear@27 175
nuclear@27 176 vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm)
nuclear@27 177 {
nuclear@27 178 vec3_t v;
nuclear@27 179 v.x = anm_get_value(node->tracks + ANM_TRACK_POS_X, tm);
nuclear@27 180 v.y = anm_get_value(node->tracks + ANM_TRACK_POS_Y, tm);
nuclear@27 181 v.z = anm_get_value(node->tracks + ANM_TRACK_POS_Z, tm);
nuclear@27 182 return v;
nuclear@27 183 }
nuclear@27 184
nuclear@27 185 void anm_set_rotation(struct anm_node *node, quat_t rot, anm_time_t tm)
nuclear@27 186 {
nuclear@27 187 anm_set_value(node->tracks + ANM_TRACK_ROT_X, tm, rot.x);
nuclear@27 188 anm_set_value(node->tracks + ANM_TRACK_ROT_Y, tm, rot.y);
nuclear@27 189 anm_set_value(node->tracks + ANM_TRACK_ROT_Z, tm, rot.z);
nuclear@27 190 anm_set_value(node->tracks + ANM_TRACK_ROT_W, tm, rot.w);
nuclear@27 191 invalidate_cache(node);
nuclear@27 192 }
nuclear@27 193
nuclear@27 194 quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm)
nuclear@27 195 {
nuclear@27 196 #ifndef ROT_USE_SLERP
nuclear@27 197 quat_t q;
nuclear@27 198 q.x = anm_get_value(node->tracks + ANM_TRACK_ROT_X, tm);
nuclear@27 199 q.y = anm_get_value(node->tracks + ANM_TRACK_ROT_Y, tm);
nuclear@27 200 q.z = anm_get_value(node->tracks + ANM_TRACK_ROT_Z, tm);
nuclear@27 201 q.w = anm_get_value(node->tracks + ANM_TRACK_ROT_W, tm);
nuclear@27 202 return q;
nuclear@27 203 #else
nuclear@27 204 int idx0, idx1, last_idx;
nuclear@27 205 anm_time_t tstart, tend;
nuclear@27 206 float t, dt;
nuclear@27 207 struct anm_track *track_x, *track_y, *track_z, *track_w;
nuclear@27 208 quat_t q, q1, q2;
nuclear@27 209
nuclear@27 210 track_x = node->tracks + ANM_TRACK_ROT_X;
nuclear@27 211 track_y = node->tracks + ANM_TRACK_ROT_Y;
nuclear@27 212 track_z = node->tracks + ANM_TRACK_ROT_Z;
nuclear@27 213 track_w = node->tracks + ANM_TRACK_ROT_W;
nuclear@27 214
nuclear@27 215 if(!track_x->count) {
nuclear@27 216 q.x = track_x->def_val;
nuclear@27 217 q.y = track_y->def_val;
nuclear@27 218 q.z = track_z->def_val;
nuclear@27 219 q.w = track_w->def_val;
nuclear@27 220 return q;
nuclear@27 221 }
nuclear@27 222
nuclear@27 223 last_idx = track_x->count - 1;
nuclear@27 224
nuclear@27 225 tstart = track_x->keys[0].time;
nuclear@27 226 tend = track_x->keys[last_idx].time;
nuclear@27 227
nuclear@27 228 if(tstart == tend) {
nuclear@27 229 q.x = track_x->keys[0].val;
nuclear@27 230 q.y = track_y->keys[0].val;
nuclear@27 231 q.z = track_z->keys[0].val;
nuclear@27 232 q.w = track_w->keys[0].val;
nuclear@27 233 return q;
nuclear@27 234 }
nuclear@27 235
nuclear@27 236 tm = anm_remap_time(track_x, tm, tstart, tend);
nuclear@27 237
nuclear@27 238 idx0 = anm_get_key_interval(track_x, tm);
nuclear@27 239 assert(idx0 >= 0 && idx0 < track_x->count);
nuclear@27 240 idx1 = idx0 + 1;
nuclear@27 241
nuclear@27 242 if(idx0 == last_idx) {
nuclear@27 243 q.x = track_x->keys[idx0].val;
nuclear@27 244 q.y = track_y->keys[idx0].val;
nuclear@27 245 q.z = track_z->keys[idx0].val;
nuclear@27 246 q.w = track_w->keys[idx0].val;
nuclear@27 247 return q;
nuclear@27 248 }
nuclear@27 249
nuclear@27 250 dt = (float)(track_x->keys[idx1].time - track_x->keys[idx0].time);
nuclear@27 251 t = (float)(tm - track_x->keys[idx0].time) / dt;
nuclear@27 252
nuclear@27 253 q1.x = track_x->keys[idx0].val;
nuclear@27 254 q1.y = track_y->keys[idx0].val;
nuclear@27 255 q1.z = track_z->keys[idx0].val;
nuclear@27 256 q1.w = track_w->keys[idx0].val;
nuclear@27 257
nuclear@27 258 q2.x = track_x->keys[idx1].val;
nuclear@27 259 q2.y = track_y->keys[idx1].val;
nuclear@27 260 q2.z = track_z->keys[idx1].val;
nuclear@27 261 q2.w = track_w->keys[idx1].val;
nuclear@27 262
nuclear@27 263 /*q1 = quat_normalize(q1);
nuclear@27 264 q2 = quat_normalize(q2);*/
nuclear@27 265
nuclear@27 266 return quat_slerp(q1, q2, t);
nuclear@27 267 #endif
nuclear@27 268 }
nuclear@27 269
nuclear@27 270 void anm_set_scaling(struct anm_node *node, vec3_t scl, anm_time_t tm)
nuclear@27 271 {
nuclear@27 272 anm_set_value(node->tracks + ANM_TRACK_SCL_X, tm, scl.x);
nuclear@27 273 anm_set_value(node->tracks + ANM_TRACK_SCL_Y, tm, scl.y);
nuclear@27 274 anm_set_value(node->tracks + ANM_TRACK_SCL_Z, tm, scl.z);
nuclear@27 275 invalidate_cache(node);
nuclear@27 276 }
nuclear@27 277
nuclear@27 278 vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm)
nuclear@27 279 {
nuclear@27 280 vec3_t v;
nuclear@27 281 v.x = anm_get_value(node->tracks + ANM_TRACK_SCL_X, tm);
nuclear@27 282 v.y = anm_get_value(node->tracks + ANM_TRACK_SCL_Y, tm);
nuclear@27 283 v.z = anm_get_value(node->tracks + ANM_TRACK_SCL_Z, tm);
nuclear@27 284 return v;
nuclear@27 285 }
nuclear@27 286
nuclear@27 287
nuclear@27 288 vec3_t anm_get_position(struct anm_node *node, anm_time_t tm)
nuclear@27 289 {
nuclear@27 290 mat4_t xform;
nuclear@27 291 vec3_t pos = {0.0, 0.0, 0.0};
nuclear@27 292
nuclear@27 293 if(!node->parent) {
nuclear@27 294 return anm_get_node_position(node, tm);
nuclear@27 295 }
nuclear@27 296
nuclear@27 297 anm_get_matrix(node, xform, tm);
nuclear@27 298 return v3_transform(pos, xform);
nuclear@27 299 }
nuclear@27 300
nuclear@27 301 quat_t anm_get_rotation(struct anm_node *node, anm_time_t tm)
nuclear@27 302 {
nuclear@27 303 quat_t rot, prot;
nuclear@27 304 rot = anm_get_node_rotation(node, tm);
nuclear@27 305
nuclear@27 306 if(!node->parent) {
nuclear@27 307 return rot;
nuclear@27 308 }
nuclear@27 309
nuclear@27 310 prot = anm_get_rotation(node->parent, tm);
nuclear@27 311 return quat_mul(prot, rot);
nuclear@27 312 }
nuclear@27 313
nuclear@27 314 vec3_t anm_get_scaling(struct anm_node *node, anm_time_t tm)
nuclear@27 315 {
nuclear@27 316 vec3_t s, ps;
nuclear@27 317 s = anm_get_node_scaling(node, tm);
nuclear@27 318
nuclear@27 319 if(!node->parent) {
nuclear@27 320 return s;
nuclear@27 321 }
nuclear@27 322
nuclear@27 323 ps = anm_get_scaling(node->parent, tm);
nuclear@27 324 return v3_mul(s, ps);
nuclear@27 325 }
nuclear@27 326
nuclear@27 327 void anm_set_pivot(struct anm_node *node, vec3_t piv)
nuclear@27 328 {
nuclear@27 329 node->pivot = piv;
nuclear@27 330 }
nuclear@27 331
nuclear@27 332 vec3_t anm_get_pivot(struct anm_node *node)
nuclear@27 333 {
nuclear@27 334 return node->pivot;
nuclear@27 335 }
nuclear@27 336
nuclear@27 337 void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
nuclear@27 338 {
nuclear@27 339 int i;
nuclear@27 340 mat4_t rmat;
nuclear@27 341 vec3_t pos, scale;
nuclear@27 342 quat_t rot;
nuclear@27 343
nuclear@27 344 pos = anm_get_node_position(node, tm);
nuclear@27 345 rot = anm_get_node_rotation(node, tm);
nuclear@27 346 scale = anm_get_node_scaling(node, tm);
nuclear@27 347
nuclear@27 348 m4_set_translation(mat, node->pivot.x, node->pivot.y, node->pivot.z);
nuclear@27 349
nuclear@27 350 quat_to_mat4(rmat, rot);
nuclear@27 351 for(i=0; i<3; i++) {
nuclear@27 352 mat[i][0] = rmat[i][0];
nuclear@27 353 mat[i][1] = rmat[i][1];
nuclear@27 354 mat[i][2] = rmat[i][2];
nuclear@27 355 }
nuclear@27 356 /* this loop is equivalent to: m4_mult(mat, mat, rmat); */
nuclear@27 357
nuclear@27 358 mat[0][0] *= scale.x; mat[0][1] *= scale.y; mat[0][2] *= scale.z; mat[0][3] += pos.x;
nuclear@27 359 mat[1][0] *= scale.x; mat[1][1] *= scale.y; mat[1][2] *= scale.z; mat[1][3] += pos.y;
nuclear@27 360 mat[2][0] *= scale.x; mat[2][1] *= scale.y; mat[2][2] *= scale.z; mat[2][3] += pos.z;
nuclear@27 361
nuclear@27 362 m4_translate(mat, -node->pivot.x, -node->pivot.y, -node->pivot.z);
nuclear@27 363
nuclear@27 364 /* that's basically: pivot * rotation * translation * scaling * -pivot */
nuclear@27 365 }
nuclear@27 366
nuclear@27 367 void anm_get_node_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
nuclear@27 368 {
nuclear@27 369 mat4_t tmp;
nuclear@27 370 anm_get_node_matrix(node, tmp, tm);
nuclear@27 371 m4_inverse(mat, tmp);
nuclear@27 372 }
nuclear@27 373
nuclear@27 374 void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
nuclear@27 375 {
nuclear@27 376 if(node->cache.time != tm) {
nuclear@27 377 anm_get_node_matrix(node, node->cache.matrix, tm);
nuclear@27 378
nuclear@27 379 if(node->parent) {
nuclear@27 380 mat4_t parent_mat;
nuclear@27 381
nuclear@27 382 anm_get_matrix(node->parent, parent_mat, tm);
nuclear@27 383 m4_mult(node->cache.matrix, parent_mat, node->cache.matrix);
nuclear@27 384 }
nuclear@27 385 node->cache.time = tm;
nuclear@27 386 }
nuclear@27 387 m4_copy(mat, node->cache.matrix);
nuclear@27 388 }
nuclear@27 389
nuclear@27 390 void anm_get_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
nuclear@27 391 {
nuclear@27 392 if(node->cache.inv_time != tm) {
nuclear@27 393 anm_get_matrix(node, mat, tm);
nuclear@27 394 m4_inverse(node->cache.inv_matrix, mat);
nuclear@27 395 node->cache.inv_time = tm;
nuclear@27 396 }
nuclear@27 397 m4_copy(mat, node->cache.inv_matrix);
nuclear@27 398 }
nuclear@27 399
nuclear@27 400 anm_time_t anm_get_start_time(struct anm_node *node)
nuclear@27 401 {
nuclear@27 402 int i;
nuclear@27 403 struct anm_node *c;
nuclear@27 404 anm_time_t res = LONG_MAX;
nuclear@27 405
nuclear@27 406 for(i=0; i<ANM_NUM_TRACKS; i++) {
nuclear@27 407 if(node->tracks[i].count) {
nuclear@27 408 anm_time_t tm = node->tracks[i].keys[0].time;
nuclear@27 409 if(tm < res) {
nuclear@27 410 res = tm;
nuclear@27 411 }
nuclear@27 412 }
nuclear@27 413 }
nuclear@27 414
nuclear@27 415 c = node->child;
nuclear@27 416 while(c) {
nuclear@27 417 anm_time_t tm = anm_get_start_time(c);
nuclear@27 418 if(tm < res) {
nuclear@27 419 res = tm;
nuclear@27 420 }
nuclear@27 421 c = c->next;
nuclear@27 422 }
nuclear@27 423 return res;
nuclear@27 424 }
nuclear@27 425
nuclear@27 426 anm_time_t anm_get_end_time(struct anm_node *node)
nuclear@27 427 {
nuclear@27 428 int i;
nuclear@27 429 struct anm_node *c;
nuclear@27 430 anm_time_t res = LONG_MIN;
nuclear@27 431
nuclear@27 432 for(i=0; i<ANM_NUM_TRACKS; i++) {
nuclear@27 433 if(node->tracks[i].count) {
nuclear@27 434 anm_time_t tm = node->tracks[i].keys[node->tracks[i].count - 1].time;
nuclear@27 435 if(tm > res) {
nuclear@27 436 res = tm;
nuclear@27 437 }
nuclear@27 438 }
nuclear@27 439 }
nuclear@27 440
nuclear@27 441 c = node->child;
nuclear@27 442 while(c) {
nuclear@27 443 anm_time_t tm = anm_get_end_time(c);
nuclear@27 444 if(tm > res) {
nuclear@27 445 res = tm;
nuclear@27 446 }
nuclear@27 447 c = c->next;
nuclear@27 448 }
nuclear@27 449 return res;
nuclear@27 450 }
nuclear@27 451
nuclear@27 452 static void invalidate_cache(struct anm_node *node)
nuclear@27 453 {
nuclear@27 454 node->cache.time = node->cache.inv_time = ANM_TIME_INVAL;
nuclear@27 455 }