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