vrshoot

view libs/anim/anim.c @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
line source
1 #include <stdlib.h>
2 #include <limits.h>
3 #include <assert.h>
4 #include "anim.h"
5 #include "dynarr.h"
7 #define ROT_USE_SLERP
9 static void invalidate_cache(struct anm_node *node);
11 int anm_init_node(struct anm_node *node)
12 {
13 int i, j;
14 static const float defaults[] = {
15 0.0f, 0.0f, 0.0f, /* default position */
16 0.0f, 0.0f, 0.0f, 1.0f, /* default rotation quat */
17 1.0f, 1.0f, 1.0f /* default scale factor */
18 };
20 memset(node, 0, sizeof *node);
22 /* initialize thread-local matrix cache */
23 pthread_key_create(&node->cache_key, 0);
24 pthread_mutex_init(&node->cache_list_lock, 0);
26 for(i=0; i<ANM_NUM_TRACKS; i++) {
27 if(anm_init_track(node->tracks + i) == -1) {
28 for(j=0; j<i; j++) {
29 anm_destroy_track(node->tracks + i);
30 }
31 }
32 anm_set_track_default(node->tracks + i, defaults[i]);
33 }
34 return 0;
35 }
37 void anm_destroy_node(struct anm_node *node)
38 {
39 int i;
40 free(node->name);
42 for(i=0; i<ANM_NUM_TRACKS; i++) {
43 anm_destroy_track(node->tracks + i);
44 }
46 /* destroy thread-specific cache */
47 pthread_key_delete(node->cache_key);
49 while(node->cache_list) {
50 struct mat_cache *tmp = node->cache_list;
51 node->cache_list = tmp->next;
52 free(tmp);
53 }
54 }
56 void anm_destroy_node_tree(struct anm_node *tree)
57 {
58 struct anm_node *c, *tmp;
60 if(!tree) return;
62 c = tree->child;
63 while(c) {
64 tmp = c;
65 c = c->next;
67 anm_destroy_node_tree(tmp);
68 }
69 anm_destroy_node(tree);
70 }
72 struct anm_node *anm_create_node(void)
73 {
74 struct anm_node *n;
76 if((n = malloc(sizeof *n))) {
77 if(anm_init_node(n) == -1) {
78 free(n);
79 return 0;
80 }
81 }
82 return n;
83 }
85 void anm_free_node(struct anm_node *node)
86 {
87 anm_destroy_node(node);
88 free(node);
89 }
91 void anm_free_node_tree(struct anm_node *tree)
92 {
93 struct anm_node *c, *tmp;
95 if(!tree) return;
97 c = tree->child;
98 while(c) {
99 tmp = c;
100 c = c->next;
102 anm_free_node_tree(tmp);
103 }
105 anm_free_node(tree);
106 }
108 int anm_set_node_name(struct anm_node *node, const char *name)
109 {
110 char *str;
112 if(!(str = malloc(strlen(name) + 1))) {
113 return -1;
114 }
115 strcpy(str, name);
116 free(node->name);
117 node->name = str;
118 return 0;
119 }
121 const char *anm_get_node_name(struct anm_node *node)
122 {
123 return node->name ? node->name : "";
124 }
126 void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in)
127 {
128 int i;
130 for(i=0; i<ANM_NUM_TRACKS; i++) {
131 anm_set_track_interpolator(node->tracks + i, in);
132 }
133 invalidate_cache(node);
134 }
136 void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex)
137 {
138 int i;
140 for(i=0; i<ANM_NUM_TRACKS; i++) {
141 anm_set_track_extrapolator(node->tracks + i, ex);
142 }
143 invalidate_cache(node);
144 }
146 void anm_link_node(struct anm_node *p, struct anm_node *c)
147 {
148 c->next = p->child;
149 p->child = c;
151 c->parent = p;
152 invalidate_cache(c);
153 }
155 int anm_unlink_node(struct anm_node *p, struct anm_node *c)
156 {
157 struct anm_node *iter;
159 if(p->child == c) {
160 p->child = c->next;
161 c->next = 0;
162 invalidate_cache(c);
163 return 0;
164 }
166 iter = p->child;
167 while(iter->next) {
168 if(iter->next == c) {
169 iter->next = c->next;
170 c->next = 0;
171 invalidate_cache(c);
172 return 0;
173 }
174 }
175 return -1;
176 }
178 void anm_clear(struct anm_node *node)
179 {
180 int i;
182 for(i=0; i<ANM_NUM_TRACKS; i++) {
183 anm_clear_track(&node->tracks[i]);
184 }
185 invalidate_cache(node);
186 }
188 void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm)
189 {
190 anm_set_value(node->tracks + ANM_TRACK_POS_X, tm, pos.x);
191 anm_set_value(node->tracks + ANM_TRACK_POS_Y, tm, pos.y);
192 anm_set_value(node->tracks + ANM_TRACK_POS_Z, tm, pos.z);
193 invalidate_cache(node);
194 }
196 vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm)
197 {
198 vec3_t v;
199 v.x = anm_get_value(node->tracks + ANM_TRACK_POS_X, tm);
200 v.y = anm_get_value(node->tracks + ANM_TRACK_POS_Y, tm);
201 v.z = anm_get_value(node->tracks + ANM_TRACK_POS_Z, tm);
202 return v;
203 }
205 void anm_set_rotation(struct anm_node *node, quat_t rot, anm_time_t tm)
206 {
207 anm_set_value(node->tracks + ANM_TRACK_ROT_X, tm, rot.x);
208 anm_set_value(node->tracks + ANM_TRACK_ROT_Y, tm, rot.y);
209 anm_set_value(node->tracks + ANM_TRACK_ROT_Z, tm, rot.z);
210 anm_set_value(node->tracks + ANM_TRACK_ROT_W, tm, rot.w);
211 invalidate_cache(node);
212 }
214 quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm)
215 {
216 #ifndef ROT_USE_SLERP
217 quat_t q;
218 q.x = anm_get_value(node->tracks + ANM_TRACK_ROT_X, tm);
219 q.y = anm_get_value(node->tracks + ANM_TRACK_ROT_Y, tm);
220 q.z = anm_get_value(node->tracks + ANM_TRACK_ROT_Z, tm);
221 q.w = anm_get_value(node->tracks + ANM_TRACK_ROT_W, tm);
222 return q;
223 #else
224 int idx0, idx1, last_idx;
225 anm_time_t tstart, tend;
226 float t, dt;
227 struct anm_track *track_x, *track_y, *track_z, *track_w;
228 quat_t q, q1, q2;
230 track_x = node->tracks + ANM_TRACK_ROT_X;
231 track_y = node->tracks + ANM_TRACK_ROT_Y;
232 track_z = node->tracks + ANM_TRACK_ROT_Z;
233 track_w = node->tracks + ANM_TRACK_ROT_W;
235 if(!track_x->count) {
236 q.x = track_x->def_val;
237 q.y = track_y->def_val;
238 q.z = track_z->def_val;
239 q.w = track_w->def_val;
240 return q;
241 }
243 last_idx = track_x->count - 1;
245 tstart = track_x->keys[0].time;
246 tend = track_x->keys[last_idx].time;
248 if(tstart == tend) {
249 q.x = track_x->keys[0].val;
250 q.y = track_y->keys[0].val;
251 q.z = track_z->keys[0].val;
252 q.w = track_w->keys[0].val;
253 return q;
254 }
256 tm = anm_remap_time(track_x, tm, tstart, tend);
258 idx0 = anm_get_key_interval(track_x, tm);
259 assert(idx0 >= 0 && idx0 < track_x->count);
260 idx1 = idx0 + 1;
262 if(idx0 == last_idx) {
263 q.x = track_x->keys[idx0].val;
264 q.y = track_y->keys[idx0].val;
265 q.z = track_z->keys[idx0].val;
266 q.w = track_w->keys[idx0].val;
267 return q;
268 }
270 dt = (float)(track_x->keys[idx1].time - track_x->keys[idx0].time);
271 t = (float)(tm - track_x->keys[idx0].time) / dt;
273 q1.x = track_x->keys[idx0].val;
274 q1.y = track_y->keys[idx0].val;
275 q1.z = track_z->keys[idx0].val;
276 q1.w = track_w->keys[idx0].val;
278 q2.x = track_x->keys[idx1].val;
279 q2.y = track_y->keys[idx1].val;
280 q2.z = track_z->keys[idx1].val;
281 q2.w = track_w->keys[idx1].val;
283 /*q1 = quat_normalize(q1);
284 q2 = quat_normalize(q2);*/
286 return quat_slerp(q1, q2, t);
287 #endif
288 }
290 void anm_set_scaling(struct anm_node *node, vec3_t scl, anm_time_t tm)
291 {
292 anm_set_value(node->tracks + ANM_TRACK_SCL_X, tm, scl.x);
293 anm_set_value(node->tracks + ANM_TRACK_SCL_Y, tm, scl.y);
294 anm_set_value(node->tracks + ANM_TRACK_SCL_Z, tm, scl.z);
295 invalidate_cache(node);
296 }
298 vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm)
299 {
300 vec3_t v;
301 v.x = anm_get_value(node->tracks + ANM_TRACK_SCL_X, tm);
302 v.y = anm_get_value(node->tracks + ANM_TRACK_SCL_Y, tm);
303 v.z = anm_get_value(node->tracks + ANM_TRACK_SCL_Z, tm);
304 return v;
305 }
308 vec3_t anm_get_position(struct anm_node *node, anm_time_t tm)
309 {
310 mat4_t xform;
311 vec3_t pos = {0.0, 0.0, 0.0};
313 if(!node->parent) {
314 return anm_get_node_position(node, tm);
315 }
317 anm_get_matrix(node, xform, tm);
318 return v3_transform(pos, xform);
319 }
321 quat_t anm_get_rotation(struct anm_node *node, anm_time_t tm)
322 {
323 quat_t rot, prot;
324 rot = anm_get_node_rotation(node, tm);
326 if(!node->parent) {
327 return rot;
328 }
330 prot = anm_get_rotation(node->parent, tm);
331 return quat_mul(prot, rot);
332 }
334 vec3_t anm_get_scaling(struct anm_node *node, anm_time_t tm)
335 {
336 vec3_t s, ps;
337 s = anm_get_node_scaling(node, tm);
339 if(!node->parent) {
340 return s;
341 }
343 ps = anm_get_scaling(node->parent, tm);
344 return v3_mul(s, ps);
345 }
347 void anm_set_pivot(struct anm_node *node, vec3_t piv)
348 {
349 node->pivot = piv;
350 }
352 vec3_t anm_get_pivot(struct anm_node *node)
353 {
354 return node->pivot;
355 }
357 void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
358 {
359 int i;
360 mat4_t rmat;
361 vec3_t pos, scale;
362 quat_t rot;
364 pos = anm_get_node_position(node, tm);
365 rot = anm_get_node_rotation(node, tm);
366 scale = anm_get_node_scaling(node, tm);
368 m4_set_translation(mat, node->pivot.x, node->pivot.y, node->pivot.z);
370 quat_to_mat4(rmat, rot);
371 for(i=0; i<3; i++) {
372 mat[i][0] = rmat[i][0];
373 mat[i][1] = rmat[i][1];
374 mat[i][2] = rmat[i][2];
375 }
376 /* this loop is equivalent to: m4_mult(mat, mat, rmat); */
378 mat[0][0] *= scale.x; mat[0][1] *= scale.y; mat[0][2] *= scale.z; mat[0][3] += pos.x;
379 mat[1][0] *= scale.x; mat[1][1] *= scale.y; mat[1][2] *= scale.z; mat[1][3] += pos.y;
380 mat[2][0] *= scale.x; mat[2][1] *= scale.y; mat[2][2] *= scale.z; mat[2][3] += pos.z;
382 m4_translate(mat, -node->pivot.x, -node->pivot.y, -node->pivot.z);
384 /* that's basically: pivot * rotation * translation * scaling * -pivot */
385 }
387 void anm_get_node_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
388 {
389 mat4_t tmp;
390 anm_get_node_matrix(node, tmp, tm);
391 m4_inverse(mat, tmp);
392 }
394 void anm_eval_node(struct anm_node *node, anm_time_t tm)
395 {
396 anm_get_node_matrix(node, node->matrix, tm);
397 }
399 void anm_eval(struct anm_node *node, anm_time_t tm)
400 {
401 struct anm_node *c;
403 anm_eval_node(node, tm);
405 if(node->parent) {
406 /* due to post-order traversal, the parent matrix is already evaluated */
407 m4_mult(node->matrix, node->parent->matrix, node->matrix);
408 }
410 /* recersively evaluate all children */
411 c = node->child;
412 while(c) {
413 anm_eval(c, tm);
414 c = c->next;
415 }
416 }
418 void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
419 {
420 struct mat_cache *cache = pthread_getspecific(node->cache_key);
421 if(!cache) {
422 cache = malloc(sizeof *cache);
423 assert(cache);
425 pthread_mutex_lock(&node->cache_list_lock);
426 cache->next = node->cache_list;
427 node->cache_list = cache;
428 pthread_mutex_unlock(&node->cache_list_lock);
430 cache->time = ANM_TIME_INVAL;
431 cache->inv_time = ANM_TIME_INVAL;
432 pthread_setspecific(node->cache_key, cache);
433 }
435 if(cache->time != tm) {
436 anm_get_node_matrix(node, cache->matrix, tm);
438 if(node->parent) {
439 mat4_t parent_mat;
441 anm_get_matrix(node->parent, parent_mat, tm);
442 m4_mult(cache->matrix, parent_mat, cache->matrix);
443 }
444 cache->time = tm;
445 }
446 m4_copy(mat, cache->matrix);
447 }
449 void anm_get_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
450 {
451 struct mat_cache *cache = pthread_getspecific(node->cache_key);
452 if(!cache) {
453 cache = malloc(sizeof *cache);
454 assert(cache);
456 pthread_mutex_lock(&node->cache_list_lock);
457 cache->next = node->cache_list;
458 node->cache_list = cache;
459 pthread_mutex_unlock(&node->cache_list_lock);
461 cache->inv_time = ANM_TIME_INVAL;
462 cache->inv_time = ANM_TIME_INVAL;
463 pthread_setspecific(node->cache_key, cache);
464 }
466 if(cache->inv_time != tm) {
467 anm_get_matrix(node, mat, tm);
468 m4_inverse(cache->inv_matrix, mat);
469 cache->inv_time = tm;
470 }
471 m4_copy(mat, cache->inv_matrix);
472 }
474 anm_time_t anm_get_start_time(struct anm_node *node)
475 {
476 int i;
477 struct anm_node *c;
478 anm_time_t res = LONG_MAX;
480 for(i=0; i<ANM_NUM_TRACKS; i++) {
481 if(node->tracks[i].count) {
482 anm_time_t tm = node->tracks[i].keys[0].time;
483 if(tm < res) {
484 res = tm;
485 }
486 }
487 }
489 c = node->child;
490 while(c) {
491 anm_time_t tm = anm_get_start_time(c);
492 if(tm < res) {
493 res = tm;
494 }
495 c = c->next;
496 }
497 return res;
498 }
500 anm_time_t anm_get_end_time(struct anm_node *node)
501 {
502 int i;
503 struct anm_node *c;
504 anm_time_t res = LONG_MIN;
506 for(i=0; i<ANM_NUM_TRACKS; i++) {
507 if(node->tracks[i].count) {
508 anm_time_t tm = node->tracks[i].keys[node->tracks[i].count - 1].time;
509 if(tm > res) {
510 res = tm;
511 }
512 }
513 }
515 c = node->child;
516 while(c) {
517 anm_time_t tm = anm_get_end_time(c);
518 if(tm > res) {
519 res = tm;
520 }
521 c = c->next;
522 }
523 return res;
524 }
526 static void invalidate_cache(struct anm_node *node)
527 {
528 struct mat_cache *cache = pthread_getspecific(node->cache_key);
529 if(cache) {
530 cache->time = cache->inv_time = ANM_TIME_INVAL;
531 }
532 }