dungeon_crawler

annotate prototype/anim/anim.c @ 80:a373b36ffc17

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