goat3d

view libs/anim/anim.c @ 29:3d669155709d

- switched the unix build to use the internal vmath/anim as well - fixed a memory corruption issue which was caused by including the system-wide installed version of the anim.h header file - started the ass2goat assimp->goat3d converter
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 29 Sep 2013 21:53:03 +0300
parents
children 0ecb788a87f7
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 for(i=0; i<ANM_NUM_TRACKS; i++) {
23 if(anm_init_track(node->tracks + i) == -1) {
24 for(j=0; j<i; j++) {
25 anm_destroy_track(node->tracks + i);
26 }
27 }
28 anm_set_track_default(node->tracks + i, defaults[i]);
29 }
31 node->cache.time = ANM_TIME_INVAL;
32 node->cache.inv_time = ANM_TIME_INVAL;
33 return 0;
34 }
36 void anm_destroy_node(struct anm_node *node)
37 {
38 int i;
39 free(node->name);
41 for(i=0; i<ANM_NUM_TRACKS; i++) {
42 anm_destroy_track(node->tracks + i);
43 }
44 }
46 void anm_destroy_node_tree(struct anm_node *tree)
47 {
48 struct anm_node *c, *tmp;
50 if(!tree) return;
52 c = tree->child;
53 while(c) {
54 tmp = c;
55 c = c->next;
57 anm_destroy_node_tree(tmp);
58 }
59 anm_destroy_node(tree);
60 }
62 struct anm_node *anm_create_node(void)
63 {
64 struct anm_node *n;
66 if((n = malloc(sizeof *n))) {
67 if(anm_init_node(n) == -1) {
68 free(n);
69 return 0;
70 }
71 }
72 return n;
73 }
75 void anm_free_node(struct anm_node *node)
76 {
77 anm_destroy_node(node);
78 free(node);
79 }
81 void anm_free_node_tree(struct anm_node *tree)
82 {
83 struct anm_node *c, *tmp;
85 if(!tree) return;
87 c = tree->child;
88 while(c) {
89 tmp = c;
90 c = c->next;
92 anm_free_node_tree(tmp);
93 }
95 anm_free_node(tree);
96 }
98 int anm_set_node_name(struct anm_node *node, const char *name)
99 {
100 char *str;
102 if(!(str = malloc(strlen(name) + 1))) {
103 return -1;
104 }
105 strcpy(str, name);
106 free(node->name);
107 node->name = str;
108 return 0;
109 }
111 const char *anm_get_node_name(struct anm_node *node)
112 {
113 return node->name ? node->name : "";
114 }
116 void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in)
117 {
118 int i;
120 for(i=0; i<ANM_NUM_TRACKS; i++) {
121 anm_set_track_interpolator(node->tracks + i, in);
122 }
123 invalidate_cache(node);
124 }
126 void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex)
127 {
128 int i;
130 for(i=0; i<ANM_NUM_TRACKS; i++) {
131 anm_set_track_extrapolator(node->tracks + i, ex);
132 }
133 invalidate_cache(node);
134 }
136 void anm_link_node(struct anm_node *p, struct anm_node *c)
137 {
138 c->next = p->child;
139 p->child = c;
141 c->parent = p;
142 invalidate_cache(c);
143 }
145 int anm_unlink_node(struct anm_node *p, struct anm_node *c)
146 {
147 struct anm_node *iter;
149 if(p->child == c) {
150 p->child = c->next;
151 c->next = 0;
152 invalidate_cache(c);
153 return 0;
154 }
156 iter = p->child;
157 while(iter->next) {
158 if(iter->next == c) {
159 iter->next = c->next;
160 c->next = 0;
161 invalidate_cache(c);
162 return 0;
163 }
164 }
165 return -1;
166 }
168 void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm)
169 {
170 anm_set_value(node->tracks + ANM_TRACK_POS_X, tm, pos.x);
171 anm_set_value(node->tracks + ANM_TRACK_POS_Y, tm, pos.y);
172 anm_set_value(node->tracks + ANM_TRACK_POS_Z, tm, pos.z);
173 invalidate_cache(node);
174 }
176 vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm)
177 {
178 vec3_t v;
179 v.x = anm_get_value(node->tracks + ANM_TRACK_POS_X, tm);
180 v.y = anm_get_value(node->tracks + ANM_TRACK_POS_Y, tm);
181 v.z = anm_get_value(node->tracks + ANM_TRACK_POS_Z, tm);
182 return v;
183 }
185 void anm_set_rotation(struct anm_node *node, quat_t rot, anm_time_t tm)
186 {
187 anm_set_value(node->tracks + ANM_TRACK_ROT_X, tm, rot.x);
188 anm_set_value(node->tracks + ANM_TRACK_ROT_Y, tm, rot.y);
189 anm_set_value(node->tracks + ANM_TRACK_ROT_Z, tm, rot.z);
190 anm_set_value(node->tracks + ANM_TRACK_ROT_W, tm, rot.w);
191 invalidate_cache(node);
192 }
194 quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm)
195 {
196 #ifndef ROT_USE_SLERP
197 quat_t q;
198 q.x = anm_get_value(node->tracks + ANM_TRACK_ROT_X, tm);
199 q.y = anm_get_value(node->tracks + ANM_TRACK_ROT_Y, tm);
200 q.z = anm_get_value(node->tracks + ANM_TRACK_ROT_Z, tm);
201 q.w = anm_get_value(node->tracks + ANM_TRACK_ROT_W, tm);
202 return q;
203 #else
204 int idx0, idx1, last_idx;
205 anm_time_t tstart, tend;
206 float t, dt;
207 struct anm_track *track_x, *track_y, *track_z, *track_w;
208 quat_t q, q1, q2;
210 track_x = node->tracks + ANM_TRACK_ROT_X;
211 track_y = node->tracks + ANM_TRACK_ROT_Y;
212 track_z = node->tracks + ANM_TRACK_ROT_Z;
213 track_w = node->tracks + ANM_TRACK_ROT_W;
215 if(!track_x->count) {
216 q.x = track_x->def_val;
217 q.y = track_y->def_val;
218 q.z = track_z->def_val;
219 q.w = track_w->def_val;
220 return q;
221 }
223 last_idx = track_x->count - 1;
225 tstart = track_x->keys[0].time;
226 tend = track_x->keys[last_idx].time;
228 if(tstart == tend) {
229 q.x = track_x->keys[0].val;
230 q.y = track_y->keys[0].val;
231 q.z = track_z->keys[0].val;
232 q.w = track_w->keys[0].val;
233 return q;
234 }
236 tm = anm_remap_time(track_x, tm, tstart, tend);
238 idx0 = anm_get_key_interval(track_x, tm);
239 assert(idx0 >= 0 && idx0 < track_x->count);
240 idx1 = idx0 + 1;
242 if(idx0 == last_idx) {
243 q.x = track_x->keys[idx0].val;
244 q.y = track_y->keys[idx0].val;
245 q.z = track_z->keys[idx0].val;
246 q.w = track_w->keys[idx0].val;
247 return q;
248 }
250 dt = (float)(track_x->keys[idx1].time - track_x->keys[idx0].time);
251 t = (float)(tm - track_x->keys[idx0].time) / dt;
253 q1.x = track_x->keys[idx0].val;
254 q1.y = track_y->keys[idx0].val;
255 q1.z = track_z->keys[idx0].val;
256 q1.w = track_w->keys[idx0].val;
258 q2.x = track_x->keys[idx1].val;
259 q2.y = track_y->keys[idx1].val;
260 q2.z = track_z->keys[idx1].val;
261 q2.w = track_w->keys[idx1].val;
263 /*q1 = quat_normalize(q1);
264 q2 = quat_normalize(q2);*/
266 return quat_slerp(q1, q2, t);
267 #endif
268 }
270 void anm_set_scaling(struct anm_node *node, vec3_t scl, anm_time_t tm)
271 {
272 anm_set_value(node->tracks + ANM_TRACK_SCL_X, tm, scl.x);
273 anm_set_value(node->tracks + ANM_TRACK_SCL_Y, tm, scl.y);
274 anm_set_value(node->tracks + ANM_TRACK_SCL_Z, tm, scl.z);
275 invalidate_cache(node);
276 }
278 vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm)
279 {
280 vec3_t v;
281 v.x = anm_get_value(node->tracks + ANM_TRACK_SCL_X, tm);
282 v.y = anm_get_value(node->tracks + ANM_TRACK_SCL_Y, tm);
283 v.z = anm_get_value(node->tracks + ANM_TRACK_SCL_Z, tm);
284 return v;
285 }
288 vec3_t anm_get_position(struct anm_node *node, anm_time_t tm)
289 {
290 mat4_t xform;
291 vec3_t pos = {0.0, 0.0, 0.0};
293 if(!node->parent) {
294 return anm_get_node_position(node, tm);
295 }
297 anm_get_matrix(node, xform, tm);
298 return v3_transform(pos, xform);
299 }
301 quat_t anm_get_rotation(struct anm_node *node, anm_time_t tm)
302 {
303 quat_t rot, prot;
304 rot = anm_get_node_rotation(node, tm);
306 if(!node->parent) {
307 return rot;
308 }
310 prot = anm_get_rotation(node->parent, tm);
311 return quat_mul(prot, rot);
312 }
314 vec3_t anm_get_scaling(struct anm_node *node, anm_time_t tm)
315 {
316 vec3_t s, ps;
317 s = anm_get_node_scaling(node, tm);
319 if(!node->parent) {
320 return s;
321 }
323 ps = anm_get_scaling(node->parent, tm);
324 return v3_mul(s, ps);
325 }
327 void anm_set_pivot(struct anm_node *node, vec3_t piv)
328 {
329 node->pivot = piv;
330 }
332 vec3_t anm_get_pivot(struct anm_node *node)
333 {
334 return node->pivot;
335 }
337 void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
338 {
339 int i;
340 mat4_t rmat;
341 vec3_t pos, scale;
342 quat_t rot;
344 pos = anm_get_node_position(node, tm);
345 rot = anm_get_node_rotation(node, tm);
346 scale = anm_get_node_scaling(node, tm);
348 m4_set_translation(mat, node->pivot.x, node->pivot.y, node->pivot.z);
350 quat_to_mat4(rmat, rot);
351 for(i=0; i<3; i++) {
352 mat[i][0] = rmat[i][0];
353 mat[i][1] = rmat[i][1];
354 mat[i][2] = rmat[i][2];
355 }
356 /* this loop is equivalent to: m4_mult(mat, mat, rmat); */
358 mat[0][0] *= scale.x; mat[0][1] *= scale.y; mat[0][2] *= scale.z; mat[0][3] += pos.x;
359 mat[1][0] *= scale.x; mat[1][1] *= scale.y; mat[1][2] *= scale.z; mat[1][3] += pos.y;
360 mat[2][0] *= scale.x; mat[2][1] *= scale.y; mat[2][2] *= scale.z; mat[2][3] += pos.z;
362 m4_translate(mat, -node->pivot.x, -node->pivot.y, -node->pivot.z);
364 /* that's basically: pivot * rotation * translation * scaling * -pivot */
365 }
367 void anm_get_node_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
368 {
369 mat4_t tmp;
370 anm_get_node_matrix(node, tmp, tm);
371 m4_inverse(mat, tmp);
372 }
374 void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
375 {
376 if(node->cache.time != tm) {
377 anm_get_node_matrix(node, node->cache.matrix, tm);
379 if(node->parent) {
380 mat4_t parent_mat;
382 anm_get_matrix(node->parent, parent_mat, tm);
383 m4_mult(node->cache.matrix, parent_mat, node->cache.matrix);
384 }
385 node->cache.time = tm;
386 }
387 m4_copy(mat, node->cache.matrix);
388 }
390 void anm_get_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
391 {
392 if(node->cache.inv_time != tm) {
393 anm_get_matrix(node, mat, tm);
394 m4_inverse(node->cache.inv_matrix, mat);
395 node->cache.inv_time = tm;
396 }
397 m4_copy(mat, node->cache.inv_matrix);
398 }
400 anm_time_t anm_get_start_time(struct anm_node *node)
401 {
402 int i;
403 struct anm_node *c;
404 anm_time_t res = LONG_MAX;
406 for(i=0; i<ANM_NUM_TRACKS; i++) {
407 if(node->tracks[i].count) {
408 anm_time_t tm = node->tracks[i].keys[0].time;
409 if(tm < res) {
410 res = tm;
411 }
412 }
413 }
415 c = node->child;
416 while(c) {
417 anm_time_t tm = anm_get_start_time(c);
418 if(tm < res) {
419 res = tm;
420 }
421 c = c->next;
422 }
423 return res;
424 }
426 anm_time_t anm_get_end_time(struct anm_node *node)
427 {
428 int i;
429 struct anm_node *c;
430 anm_time_t res = LONG_MIN;
432 for(i=0; i<ANM_NUM_TRACKS; i++) {
433 if(node->tracks[i].count) {
434 anm_time_t tm = node->tracks[i].keys[node->tracks[i].count - 1].time;
435 if(tm > res) {
436 res = tm;
437 }
438 }
439 }
441 c = node->child;
442 while(c) {
443 anm_time_t tm = anm_get_end_time(c);
444 if(tm > res) {
445 res = tm;
446 }
447 c = c->next;
448 }
449 return res;
450 }
452 static void invalidate_cache(struct anm_node *node)
453 {
454 node->cache.time = node->cache.inv_time = ANM_TIME_INVAL;
455 }