rev |
line source |
nuclear@1
|
1 #include <stdlib.h>
|
nuclear@0
|
2 #include <limits.h>
|
nuclear@0
|
3 #include <assert.h>
|
nuclear@0
|
4 #include "anim.h"
|
nuclear@0
|
5 #include "dynarr.h"
|
nuclear@0
|
6
|
nuclear@7
|
7 #define ROT_USE_SLERP
|
nuclear@7
|
8
|
nuclear@0
|
9 static void invalidate_cache(struct anm_node *node);
|
nuclear@0
|
10
|
nuclear@21
|
11 int anm_init_animation(struct anm_animation *anim)
|
nuclear@0
|
12 {
|
nuclear@0
|
13 int i, j;
|
nuclear@0
|
14 static const float defaults[] = {
|
nuclear@0
|
15 0.0f, 0.0f, 0.0f, /* default position */
|
nuclear@0
|
16 0.0f, 0.0f, 0.0f, 1.0f, /* default rotation quat */
|
nuclear@0
|
17 1.0f, 1.0f, 1.0f /* default scale factor */
|
nuclear@0
|
18 };
|
nuclear@0
|
19
|
nuclear@21
|
20 anim->name = 0;
|
nuclear@21
|
21
|
nuclear@21
|
22 for(i=0; i<ANM_NUM_TRACKS; i++) {
|
nuclear@21
|
23 if(anm_init_track(anim->tracks + i) == -1) {
|
nuclear@21
|
24 for(j=0; j<i; j++) {
|
nuclear@21
|
25 anm_destroy_track(anim->tracks + i);
|
nuclear@21
|
26 }
|
nuclear@21
|
27 }
|
nuclear@21
|
28 anm_set_track_default(anim->tracks + i, defaults[i]);
|
nuclear@21
|
29 }
|
nuclear@21
|
30 return 0;
|
nuclear@21
|
31 }
|
nuclear@21
|
32
|
nuclear@21
|
33 void anm_destroy_animation(struct anm_animation *anim)
|
nuclear@21
|
34 {
|
nuclear@21
|
35 int i;
|
nuclear@21
|
36 for(i=0; i<ANM_NUM_TRACKS; i++) {
|
nuclear@21
|
37 anm_destroy_track(anim->tracks + i);
|
nuclear@21
|
38 }
|
nuclear@21
|
39 free(anim->name);
|
nuclear@21
|
40 }
|
nuclear@21
|
41
|
nuclear@22
|
42 void anm_set_animation_name(struct anm_animation *anim, const char *name)
|
nuclear@22
|
43 {
|
nuclear@22
|
44 char *newname = malloc(strlen(name) + 1);
|
nuclear@22
|
45 if(!newname) return;
|
nuclear@22
|
46
|
nuclear@22
|
47 free(anim->name);
|
nuclear@22
|
48 anim->name = newname;
|
nuclear@22
|
49 }
|
nuclear@22
|
50
|
nuclear@21
|
51 /* ---- node implementation ----- */
|
nuclear@21
|
52
|
nuclear@21
|
53 int anm_init_node(struct anm_node *node)
|
nuclear@21
|
54 {
|
nuclear@0
|
55 memset(node, 0, sizeof *node);
|
nuclear@0
|
56
|
nuclear@21
|
57 node->cur_anim[1] = -1;
|
nuclear@21
|
58 node->cur_mix = 0;
|
nuclear@21
|
59
|
nuclear@21
|
60 if(!(node->animations = dynarr_alloc(1, sizeof *node->animations))) {
|
nuclear@21
|
61 return -1;
|
nuclear@21
|
62 }
|
nuclear@21
|
63 if(anm_init_animation(node->animations) == -1) {
|
nuclear@21
|
64 dynarr_free(node->animations);
|
nuclear@21
|
65 return -1;
|
nuclear@21
|
66 }
|
nuclear@21
|
67
|
nuclear@0
|
68 /* initialize thread-local matrix cache */
|
nuclear@0
|
69 pthread_key_create(&node->cache_key, 0);
|
nuclear@10
|
70 pthread_mutex_init(&node->cache_list_lock, 0);
|
nuclear@0
|
71
|
nuclear@0
|
72 return 0;
|
nuclear@0
|
73 }
|
nuclear@0
|
74
|
nuclear@0
|
75 void anm_destroy_node(struct anm_node *node)
|
nuclear@0
|
76 {
|
nuclear@0
|
77 int i;
|
nuclear@0
|
78 free(node->name);
|
nuclear@0
|
79
|
nuclear@0
|
80 for(i=0; i<ANM_NUM_TRACKS; i++) {
|
nuclear@21
|
81 anm_destroy_animation(node->animations + i);
|
nuclear@0
|
82 }
|
nuclear@21
|
83 dynarr_free(node->animations);
|
nuclear@0
|
84
|
nuclear@0
|
85 /* destroy thread-specific cache */
|
nuclear@0
|
86 pthread_key_delete(node->cache_key);
|
nuclear@0
|
87
|
nuclear@0
|
88 while(node->cache_list) {
|
nuclear@0
|
89 struct mat_cache *tmp = node->cache_list;
|
nuclear@0
|
90 node->cache_list = tmp->next;
|
nuclear@0
|
91 free(tmp);
|
nuclear@0
|
92 }
|
nuclear@0
|
93 }
|
nuclear@0
|
94
|
nuclear@0
|
95 void anm_destroy_node_tree(struct anm_node *tree)
|
nuclear@0
|
96 {
|
nuclear@0
|
97 struct anm_node *c, *tmp;
|
nuclear@0
|
98
|
nuclear@0
|
99 if(!tree) return;
|
nuclear@0
|
100
|
nuclear@0
|
101 c = tree->child;
|
nuclear@0
|
102 while(c) {
|
nuclear@0
|
103 tmp = c;
|
nuclear@0
|
104 c = c->next;
|
nuclear@0
|
105
|
nuclear@0
|
106 anm_destroy_node_tree(tmp);
|
nuclear@0
|
107 }
|
nuclear@0
|
108 anm_destroy_node(tree);
|
nuclear@0
|
109 }
|
nuclear@0
|
110
|
nuclear@0
|
111 struct anm_node *anm_create_node(void)
|
nuclear@0
|
112 {
|
nuclear@0
|
113 struct anm_node *n;
|
nuclear@0
|
114
|
nuclear@0
|
115 if((n = malloc(sizeof *n))) {
|
nuclear@0
|
116 if(anm_init_node(n) == -1) {
|
nuclear@0
|
117 free(n);
|
nuclear@0
|
118 return 0;
|
nuclear@0
|
119 }
|
nuclear@0
|
120 }
|
nuclear@0
|
121 return n;
|
nuclear@0
|
122 }
|
nuclear@0
|
123
|
nuclear@0
|
124 void anm_free_node(struct anm_node *node)
|
nuclear@0
|
125 {
|
nuclear@0
|
126 anm_destroy_node(node);
|
nuclear@0
|
127 free(node);
|
nuclear@0
|
128 }
|
nuclear@0
|
129
|
nuclear@0
|
130 void anm_free_node_tree(struct anm_node *tree)
|
nuclear@0
|
131 {
|
nuclear@0
|
132 struct anm_node *c, *tmp;
|
nuclear@0
|
133
|
nuclear@0
|
134 if(!tree) return;
|
nuclear@0
|
135
|
nuclear@0
|
136 c = tree->child;
|
nuclear@0
|
137 while(c) {
|
nuclear@0
|
138 tmp = c;
|
nuclear@0
|
139 c = c->next;
|
nuclear@0
|
140
|
nuclear@0
|
141 anm_free_node_tree(tmp);
|
nuclear@0
|
142 }
|
nuclear@0
|
143
|
nuclear@0
|
144 anm_free_node(tree);
|
nuclear@0
|
145 }
|
nuclear@0
|
146
|
nuclear@0
|
147 int anm_set_node_name(struct anm_node *node, const char *name)
|
nuclear@0
|
148 {
|
nuclear@0
|
149 char *str;
|
nuclear@0
|
150
|
nuclear@0
|
151 if(!(str = malloc(strlen(name) + 1))) {
|
nuclear@0
|
152 return -1;
|
nuclear@0
|
153 }
|
nuclear@0
|
154 strcpy(str, name);
|
nuclear@0
|
155 free(node->name);
|
nuclear@0
|
156 node->name = str;
|
nuclear@0
|
157 return 0;
|
nuclear@0
|
158 }
|
nuclear@0
|
159
|
nuclear@0
|
160 const char *anm_get_node_name(struct anm_node *node)
|
nuclear@0
|
161 {
|
nuclear@0
|
162 return node->name ? node->name : "";
|
nuclear@0
|
163 }
|
nuclear@0
|
164
|
nuclear@0
|
165 void anm_link_node(struct anm_node *p, struct anm_node *c)
|
nuclear@0
|
166 {
|
nuclear@0
|
167 c->next = p->child;
|
nuclear@0
|
168 p->child = c;
|
nuclear@0
|
169
|
nuclear@0
|
170 c->parent = p;
|
nuclear@0
|
171 invalidate_cache(c);
|
nuclear@0
|
172 }
|
nuclear@0
|
173
|
nuclear@0
|
174 int anm_unlink_node(struct anm_node *p, struct anm_node *c)
|
nuclear@0
|
175 {
|
nuclear@0
|
176 struct anm_node *iter;
|
nuclear@0
|
177
|
nuclear@0
|
178 if(p->child == c) {
|
nuclear@0
|
179 p->child = c->next;
|
nuclear@0
|
180 c->next = 0;
|
nuclear@0
|
181 invalidate_cache(c);
|
nuclear@0
|
182 return 0;
|
nuclear@0
|
183 }
|
nuclear@0
|
184
|
nuclear@0
|
185 iter = p->child;
|
nuclear@0
|
186 while(iter->next) {
|
nuclear@0
|
187 if(iter->next == c) {
|
nuclear@0
|
188 iter->next = c->next;
|
nuclear@0
|
189 c->next = 0;
|
nuclear@0
|
190 invalidate_cache(c);
|
nuclear@0
|
191 return 0;
|
nuclear@0
|
192 }
|
nuclear@0
|
193 }
|
nuclear@0
|
194 return -1;
|
nuclear@0
|
195 }
|
nuclear@0
|
196
|
nuclear@21
|
197 void anm_set_pivot(struct anm_node *node, vec3_t piv)
|
nuclear@21
|
198 {
|
nuclear@21
|
199 node->pivot = piv;
|
nuclear@21
|
200 }
|
nuclear@21
|
201
|
nuclear@21
|
202 vec3_t anm_get_pivot(struct anm_node *node)
|
nuclear@21
|
203 {
|
nuclear@21
|
204 return node->pivot;
|
nuclear@21
|
205 }
|
nuclear@21
|
206
|
nuclear@21
|
207
|
nuclear@21
|
208 /* animation management */
|
nuclear@21
|
209
|
nuclear@21
|
210 int anm_use_node_animation(struct anm_node *node, int aidx)
|
nuclear@21
|
211 {
|
nuclear@21
|
212 if(aidx == node->cur_anim[0] && node->cur_anim[1] == -1) {
|
nuclear@21
|
213 return 0; /* no change, no invalidation */
|
nuclear@21
|
214 }
|
nuclear@21
|
215
|
nuclear@21
|
216 if(aidx < 0 || aidx >= anm_get_animation_count(node)) {
|
nuclear@21
|
217 return -1;
|
nuclear@21
|
218 }
|
nuclear@21
|
219
|
nuclear@21
|
220 node->cur_anim[0] = aidx;
|
nuclear@21
|
221 node->cur_anim[1] = -1;
|
nuclear@21
|
222 node->cur_mix = 0;
|
nuclear@21
|
223
|
nuclear@21
|
224 invalidate_cache(node);
|
nuclear@21
|
225 return 0;
|
nuclear@21
|
226 }
|
nuclear@21
|
227
|
nuclear@21
|
228 int anm_use_node_animations(struct anm_node *node, int aidx, int bidx, float t)
|
nuclear@21
|
229 {
|
nuclear@21
|
230 int num_anim;
|
nuclear@21
|
231
|
nuclear@21
|
232 if(node->cur_anim[0] == aidx && node->cur_anim[1] == bidx &&
|
nuclear@21
|
233 fabs(t - node->cur_mix) < 1e-6) {
|
nuclear@21
|
234 return 0; /* no change, no invalidation */
|
nuclear@21
|
235 }
|
nuclear@21
|
236
|
nuclear@21
|
237 num_anim = anm_get_animation_count(node);
|
nuclear@21
|
238 if(aidx < 0 || aidx >= num_anim) {
|
nuclear@21
|
239 return anm_use_animation(node, bidx);
|
nuclear@21
|
240 }
|
nuclear@21
|
241 if(bidx < 0 || bidx >= num_anim) {
|
nuclear@21
|
242 return anm_use_animation(node, aidx);
|
nuclear@21
|
243 }
|
nuclear@21
|
244 node->cur_anim[0] = aidx;
|
nuclear@21
|
245 node->cur_anim[1] = bidx;
|
nuclear@21
|
246 node->cur_mix = t;
|
nuclear@21
|
247
|
nuclear@21
|
248 invalidate_cache(node);
|
nuclear@21
|
249 return 0;
|
nuclear@21
|
250 }
|
nuclear@21
|
251
|
nuclear@21
|
252 int anm_use_animation(struct anm_node *node, int aidx)
|
nuclear@21
|
253 {
|
nuclear@21
|
254 struct anm_node *child;
|
nuclear@21
|
255
|
nuclear@21
|
256 if(anm_use_node_animation(node, aidx) == -1) {
|
nuclear@21
|
257 return -1;
|
nuclear@21
|
258 }
|
nuclear@21
|
259
|
nuclear@21
|
260 child = node->child;
|
nuclear@21
|
261 while(child) {
|
nuclear@21
|
262 if(anm_use_animation(child, aidx) == -1) {
|
nuclear@21
|
263 return -1;
|
nuclear@21
|
264 }
|
nuclear@21
|
265 child = child->next;
|
nuclear@21
|
266 }
|
nuclear@21
|
267 return 0;
|
nuclear@21
|
268 }
|
nuclear@21
|
269
|
nuclear@21
|
270 int anm_use_animations(struct anm_node *node, int aidx, int bidx, float t)
|
nuclear@21
|
271 {
|
nuclear@21
|
272 struct anm_node *child;
|
nuclear@21
|
273
|
nuclear@21
|
274 if(anm_use_node_animations(node, aidx, bidx, t) == -1) {
|
nuclear@21
|
275 return -1;
|
nuclear@21
|
276 }
|
nuclear@21
|
277
|
nuclear@21
|
278 child = node->child;
|
nuclear@21
|
279 while(child) {
|
nuclear@21
|
280 if(anm_use_animations(child, aidx, bidx, t) == -1) {
|
nuclear@21
|
281 return -1;
|
nuclear@21
|
282 }
|
nuclear@21
|
283 child = child->next;
|
nuclear@21
|
284 }
|
nuclear@21
|
285 return 0;
|
nuclear@21
|
286
|
nuclear@21
|
287 }
|
nuclear@21
|
288
|
nuclear@21
|
289 int anm_get_active_animation_index(struct anm_node *node, int which)
|
nuclear@21
|
290 {
|
nuclear@21
|
291 if(which < 0 || which >= 2) return -1;
|
nuclear@21
|
292 return node->cur_anim[which];
|
nuclear@21
|
293 }
|
nuclear@21
|
294
|
nuclear@21
|
295 struct anm_animation *anm_get_active_animation(struct anm_node *node, int which)
|
nuclear@21
|
296 {
|
nuclear@21
|
297 int idx = anm_get_active_animation_index(node, which);
|
nuclear@21
|
298 if(idx < 0 || idx >= anm_get_animation_count(node)) {
|
nuclear@21
|
299 return 0;
|
nuclear@21
|
300 }
|
nuclear@21
|
301 return node->animations + idx;
|
nuclear@21
|
302 }
|
nuclear@21
|
303
|
nuclear@21
|
304 float anm_get_active_animation_mix(struct anm_node *node)
|
nuclear@21
|
305 {
|
nuclear@21
|
306 return node->cur_mix;
|
nuclear@21
|
307 }
|
nuclear@21
|
308
|
nuclear@21
|
309 int anm_get_animation_count(struct anm_node *node)
|
nuclear@21
|
310 {
|
nuclear@21
|
311 return dynarr_size(node->animations);
|
nuclear@21
|
312 }
|
nuclear@21
|
313
|
nuclear@21
|
314 int anm_add_node_animation(struct anm_node *node)
|
nuclear@21
|
315 {
|
nuclear@21
|
316 struct anm_animation newanim;
|
nuclear@21
|
317 anm_init_animation(&newanim);
|
nuclear@21
|
318
|
nuclear@21
|
319 node->animations = dynarr_push(node->animations, &newanim);
|
nuclear@21
|
320 return 0;
|
nuclear@21
|
321 }
|
nuclear@21
|
322
|
nuclear@21
|
323 int anm_remove_node_animation(struct anm_node *node, int idx)
|
nuclear@21
|
324 {
|
nuclear@21
|
325 fprintf(stderr, "anm_remove_animation: unimplemented!");
|
nuclear@21
|
326 abort();
|
nuclear@21
|
327 return 0;
|
nuclear@21
|
328 }
|
nuclear@21
|
329
|
nuclear@21
|
330 int anm_add_animation(struct anm_node *node)
|
nuclear@21
|
331 {
|
nuclear@21
|
332 struct anm_node *child;
|
nuclear@21
|
333
|
nuclear@21
|
334 if(anm_add_node_animation(node) == -1) {
|
nuclear@21
|
335 return -1;
|
nuclear@21
|
336 }
|
nuclear@21
|
337
|
nuclear@21
|
338 child = node->child;
|
nuclear@21
|
339 while(child) {
|
nuclear@21
|
340 if(anm_add_animation(child)) {
|
nuclear@21
|
341 return -1;
|
nuclear@21
|
342 }
|
nuclear@21
|
343 child = child->next;
|
nuclear@21
|
344 }
|
nuclear@21
|
345 return 0;
|
nuclear@21
|
346 }
|
nuclear@21
|
347
|
nuclear@21
|
348 int anm_remove_animation(struct anm_node *node, int idx)
|
nuclear@21
|
349 {
|
nuclear@21
|
350 struct anm_node *child;
|
nuclear@21
|
351
|
nuclear@21
|
352 if(anm_remove_node_animation(node, idx) == -1) {
|
nuclear@21
|
353 return -1;
|
nuclear@21
|
354 }
|
nuclear@21
|
355
|
nuclear@21
|
356 child = node->child;
|
nuclear@21
|
357 while(child) {
|
nuclear@21
|
358 if(anm_remove_animation(child, idx) == -1) {
|
nuclear@21
|
359 return -1;
|
nuclear@21
|
360 }
|
nuclear@21
|
361 child = child->next;
|
nuclear@21
|
362 }
|
nuclear@21
|
363 return 0;
|
nuclear@21
|
364 }
|
nuclear@21
|
365
|
nuclear@21
|
366 struct anm_animation *anm_get_animation(struct anm_node *node, int idx)
|
nuclear@21
|
367 {
|
nuclear@21
|
368 if(idx < 0 || idx > anm_get_animation_count(node)) {
|
nuclear@21
|
369 return 0;
|
nuclear@21
|
370 }
|
nuclear@21
|
371 return node->animations + idx;
|
nuclear@21
|
372 }
|
nuclear@21
|
373
|
nuclear@21
|
374 struct anm_animation *anm_get_animation_by_name(struct anm_node *node, const char *name)
|
nuclear@21
|
375 {
|
nuclear@21
|
376 return anm_get_animation(node, anm_find_animation(node, name));
|
nuclear@21
|
377 }
|
nuclear@21
|
378
|
nuclear@21
|
379 int anm_find_animation(struct anm_node *node, const char *name)
|
nuclear@21
|
380 {
|
nuclear@21
|
381 int i, count = anm_get_animation_count(node);
|
nuclear@21
|
382 for(i=0; i<count; i++) {
|
nuclear@21
|
383 if(strcmp(node->animations[i].name, name) == 0) {
|
nuclear@21
|
384 return i;
|
nuclear@21
|
385 }
|
nuclear@21
|
386 }
|
nuclear@21
|
387 return -1;
|
nuclear@21
|
388 }
|
nuclear@21
|
389
|
nuclear@21
|
390 /* all the rest act on the current animation(s) */
|
nuclear@21
|
391
|
nuclear@21
|
392 void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in)
|
nuclear@21
|
393 {
|
nuclear@21
|
394 int i;
|
nuclear@21
|
395 struct anm_animation *anim = anm_get_active_animation(node, 0);
|
nuclear@21
|
396 if(!anim) return;
|
nuclear@21
|
397
|
nuclear@21
|
398 for(i=0; i<ANM_NUM_TRACKS; i++) {
|
nuclear@21
|
399 anm_set_track_interpolator(anim->tracks + i, in);
|
nuclear@21
|
400 }
|
nuclear@21
|
401 invalidate_cache(node);
|
nuclear@21
|
402 }
|
nuclear@21
|
403
|
nuclear@21
|
404 void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex)
|
nuclear@21
|
405 {
|
nuclear@21
|
406 int i;
|
nuclear@21
|
407 struct anm_animation *anim = anm_get_active_animation(node, 0);
|
nuclear@21
|
408 if(!anim) return;
|
nuclear@21
|
409
|
nuclear@21
|
410 for(i=0; i<ANM_NUM_TRACKS; i++) {
|
nuclear@21
|
411 anm_set_track_extrapolator(anim->tracks + i, ex);
|
nuclear@21
|
412 }
|
nuclear@21
|
413 invalidate_cache(node);
|
nuclear@21
|
414 }
|
nuclear@21
|
415
|
nuclear@0
|
416 void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm)
|
nuclear@0
|
417 {
|
nuclear@21
|
418 struct anm_animation *anim = anm_get_active_animation(node, 0);
|
nuclear@21
|
419 if(!anim) return;
|
nuclear@21
|
420
|
nuclear@21
|
421 anm_set_value(anim->tracks + ANM_TRACK_POS_X, tm, pos.x);
|
nuclear@21
|
422 anm_set_value(anim->tracks + ANM_TRACK_POS_Y, tm, pos.y);
|
nuclear@21
|
423 anm_set_value(anim->tracks + ANM_TRACK_POS_Z, tm, pos.z);
|
nuclear@0
|
424 invalidate_cache(node);
|
nuclear@0
|
425 }
|
nuclear@0
|
426
|
nuclear@0
|
427 vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm)
|
nuclear@0
|
428 {
|
nuclear@0
|
429 vec3_t v;
|
nuclear@21
|
430 struct anm_animation *anim0 = anm_get_active_animation(node, 0);
|
nuclear@21
|
431 struct anm_animation *anim1 = anm_get_active_animation(node, 1);
|
nuclear@21
|
432
|
nuclear@21
|
433 if(!anim0) {
|
nuclear@21
|
434 return v3_cons(0, 0, 0);
|
nuclear@21
|
435 }
|
nuclear@21
|
436
|
nuclear@21
|
437 v.x = anm_get_value(anim0->tracks + ANM_TRACK_POS_X, tm);
|
nuclear@21
|
438 v.y = anm_get_value(anim0->tracks + ANM_TRACK_POS_Y, tm);
|
nuclear@21
|
439 v.z = anm_get_value(anim0->tracks + ANM_TRACK_POS_Z, tm);
|
nuclear@21
|
440
|
nuclear@21
|
441 if(anim1) {
|
nuclear@21
|
442 vec3_t v1;
|
nuclear@21
|
443 v1.x = anm_get_value(anim1->tracks + ANM_TRACK_POS_X, tm);
|
nuclear@21
|
444 v1.y = anm_get_value(anim1->tracks + ANM_TRACK_POS_Y, tm);
|
nuclear@21
|
445 v1.z = anm_get_value(anim1->tracks + ANM_TRACK_POS_Z, tm);
|
nuclear@21
|
446
|
nuclear@21
|
447 v.x = v.x + (v1.x - v.x) * node->cur_mix;
|
nuclear@21
|
448 v.y = v.y + (v1.y - v.y) * node->cur_mix;
|
nuclear@21
|
449 v.z = v.z + (v1.z - v.z) * node->cur_mix;
|
nuclear@21
|
450 }
|
nuclear@21
|
451
|
nuclear@0
|
452 return v;
|
nuclear@0
|
453 }
|
nuclear@0
|
454
|
nuclear@0
|
455 void anm_set_rotation(struct anm_node *node, quat_t rot, anm_time_t tm)
|
nuclear@0
|
456 {
|
nuclear@21
|
457 struct anm_animation *anim = anm_get_active_animation(node, 0);
|
nuclear@21
|
458 if(!anim) return;
|
nuclear@21
|
459
|
nuclear@21
|
460 anm_set_value(anim->tracks + ANM_TRACK_ROT_X, tm, rot.x);
|
nuclear@21
|
461 anm_set_value(anim->tracks + ANM_TRACK_ROT_Y, tm, rot.y);
|
nuclear@21
|
462 anm_set_value(anim->tracks + ANM_TRACK_ROT_Z, tm, rot.z);
|
nuclear@21
|
463 anm_set_value(anim->tracks + ANM_TRACK_ROT_W, tm, rot.w);
|
nuclear@0
|
464 invalidate_cache(node);
|
nuclear@0
|
465 }
|
nuclear@0
|
466
|
nuclear@21
|
467 static quat_t get_node_rotation(struct anm_node *node, anm_time_t tm, struct anm_animation *anim)
|
nuclear@0
|
468 {
|
nuclear@7
|
469 #ifndef ROT_USE_SLERP
|
nuclear@7
|
470 quat_t q;
|
nuclear@21
|
471 q.x = anm_get_value(anim->tracks + ANM_TRACK_ROT_X, tm);
|
nuclear@21
|
472 q.y = anm_get_value(anim->tracks + ANM_TRACK_ROT_Y, tm);
|
nuclear@21
|
473 q.z = anm_get_value(anim->tracks + ANM_TRACK_ROT_Z, tm);
|
nuclear@21
|
474 q.w = anm_get_value(anim->tracks + ANM_TRACK_ROT_W, tm);
|
nuclear@7
|
475 return q;
|
nuclear@7
|
476 #else
|
nuclear@0
|
477 int idx0, idx1, last_idx;
|
nuclear@0
|
478 anm_time_t tstart, tend;
|
nuclear@0
|
479 float t, dt;
|
nuclear@0
|
480 struct anm_track *track_x, *track_y, *track_z, *track_w;
|
nuclear@0
|
481 quat_t q, q1, q2;
|
nuclear@0
|
482
|
nuclear@21
|
483 track_x = anim->tracks + ANM_TRACK_ROT_X;
|
nuclear@21
|
484 track_y = anim->tracks + ANM_TRACK_ROT_Y;
|
nuclear@21
|
485 track_z = anim->tracks + ANM_TRACK_ROT_Z;
|
nuclear@21
|
486 track_w = anim->tracks + ANM_TRACK_ROT_W;
|
nuclear@0
|
487
|
nuclear@0
|
488 if(!track_x->count) {
|
nuclear@0
|
489 q.x = track_x->def_val;
|
nuclear@0
|
490 q.y = track_y->def_val;
|
nuclear@0
|
491 q.z = track_z->def_val;
|
nuclear@0
|
492 q.w = track_w->def_val;
|
nuclear@0
|
493 return q;
|
nuclear@0
|
494 }
|
nuclear@0
|
495
|
nuclear@0
|
496 last_idx = track_x->count - 1;
|
nuclear@0
|
497
|
nuclear@0
|
498 tstart = track_x->keys[0].time;
|
nuclear@0
|
499 tend = track_x->keys[last_idx].time;
|
nuclear@6
|
500
|
nuclear@6
|
501 if(tstart == tend) {
|
nuclear@6
|
502 q.x = track_x->keys[0].val;
|
nuclear@6
|
503 q.y = track_y->keys[0].val;
|
nuclear@6
|
504 q.z = track_z->keys[0].val;
|
nuclear@6
|
505 q.w = track_w->keys[0].val;
|
nuclear@6
|
506 return q;
|
nuclear@6
|
507 }
|
nuclear@6
|
508
|
nuclear@0
|
509 tm = anm_remap_time(track_x, tm, tstart, tend);
|
nuclear@0
|
510
|
nuclear@0
|
511 idx0 = anm_get_key_interval(track_x, tm);
|
nuclear@0
|
512 assert(idx0 >= 0 && idx0 < track_x->count);
|
nuclear@0
|
513 idx1 = idx0 + 1;
|
nuclear@0
|
514
|
nuclear@6
|
515 if(idx0 == last_idx) {
|
nuclear@6
|
516 q.x = track_x->keys[idx0].val;
|
nuclear@6
|
517 q.y = track_y->keys[idx0].val;
|
nuclear@6
|
518 q.z = track_z->keys[idx0].val;
|
nuclear@6
|
519 q.w = track_w->keys[idx0].val;
|
nuclear@6
|
520 return q;
|
nuclear@6
|
521 }
|
nuclear@6
|
522
|
nuclear@0
|
523 dt = (float)(track_x->keys[idx1].time - track_x->keys[idx0].time);
|
nuclear@0
|
524 t = (float)(tm - track_x->keys[idx0].time) / dt;
|
nuclear@0
|
525
|
nuclear@0
|
526 q1.x = track_x->keys[idx0].val;
|
nuclear@0
|
527 q1.y = track_y->keys[idx0].val;
|
nuclear@0
|
528 q1.z = track_z->keys[idx0].val;
|
nuclear@0
|
529 q1.w = track_w->keys[idx0].val;
|
nuclear@0
|
530
|
nuclear@0
|
531 q2.x = track_x->keys[idx1].val;
|
nuclear@0
|
532 q2.y = track_y->keys[idx1].val;
|
nuclear@0
|
533 q2.z = track_z->keys[idx1].val;
|
nuclear@0
|
534 q2.w = track_w->keys[idx1].val;
|
nuclear@0
|
535
|
nuclear@9
|
536 /*q1 = quat_normalize(q1);
|
nuclear@9
|
537 q2 = quat_normalize(q2);*/
|
nuclear@9
|
538
|
nuclear@0
|
539 return quat_slerp(q1, q2, t);
|
nuclear@7
|
540 #endif
|
nuclear@0
|
541 }
|
nuclear@0
|
542
|
nuclear@21
|
543 quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm)
|
nuclear@21
|
544 {
|
nuclear@21
|
545 quat_t q;
|
nuclear@21
|
546 struct anm_animation *anim0 = anm_get_active_animation(node, 0);
|
nuclear@21
|
547 struct anm_animation *anim1 = anm_get_active_animation(node, 1);
|
nuclear@21
|
548
|
nuclear@21
|
549 if(!anim0) {
|
nuclear@21
|
550 return quat_identity();
|
nuclear@21
|
551 }
|
nuclear@21
|
552
|
nuclear@21
|
553 q = get_node_rotation(node, tm, anim0);
|
nuclear@21
|
554
|
nuclear@21
|
555 if(anim1) {
|
nuclear@21
|
556 quat_t q1 = get_node_rotation(node, tm, anim1);
|
nuclear@21
|
557
|
nuclear@21
|
558 q = quat_slerp(q, q1, node->cur_mix);
|
nuclear@21
|
559 }
|
nuclear@21
|
560 return q;
|
nuclear@21
|
561 }
|
nuclear@21
|
562
|
nuclear@0
|
563 void anm_set_scaling(struct anm_node *node, vec3_t scl, anm_time_t tm)
|
nuclear@0
|
564 {
|
nuclear@21
|
565 struct anm_animation *anim = anm_get_active_animation(node, 0);
|
nuclear@21
|
566 if(!anim) return;
|
nuclear@21
|
567
|
nuclear@21
|
568 anm_set_value(anim->tracks + ANM_TRACK_SCL_X, tm, scl.x);
|
nuclear@21
|
569 anm_set_value(anim->tracks + ANM_TRACK_SCL_Y, tm, scl.y);
|
nuclear@21
|
570 anm_set_value(anim->tracks + ANM_TRACK_SCL_Z, tm, scl.z);
|
nuclear@0
|
571 invalidate_cache(node);
|
nuclear@0
|
572 }
|
nuclear@0
|
573
|
nuclear@0
|
574 vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm)
|
nuclear@0
|
575 {
|
nuclear@0
|
576 vec3_t v;
|
nuclear@21
|
577 struct anm_animation *anim0 = anm_get_active_animation(node, 0);
|
nuclear@21
|
578 struct anm_animation *anim1 = anm_get_active_animation(node, 1);
|
nuclear@21
|
579
|
nuclear@21
|
580 if(!anim0) {
|
nuclear@21
|
581 return v3_cons(1, 1, 1);
|
nuclear@21
|
582 }
|
nuclear@21
|
583
|
nuclear@21
|
584 v.x = anm_get_value(anim0->tracks + ANM_TRACK_SCL_X, tm);
|
nuclear@21
|
585 v.y = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Y, tm);
|
nuclear@21
|
586 v.z = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Z, tm);
|
nuclear@21
|
587
|
nuclear@21
|
588 if(anim1) {
|
nuclear@21
|
589 vec3_t v1;
|
nuclear@21
|
590 v1.x = anm_get_value(anim1->tracks + ANM_TRACK_SCL_X, tm);
|
nuclear@21
|
591 v1.y = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Y, tm);
|
nuclear@21
|
592 v1.z = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Z, tm);
|
nuclear@21
|
593
|
nuclear@21
|
594 v.x = v.x + (v1.x - v.x) * node->cur_mix;
|
nuclear@21
|
595 v.y = v.y + (v1.y - v.y) * node->cur_mix;
|
nuclear@21
|
596 v.z = v.z + (v1.z - v.z) * node->cur_mix;
|
nuclear@21
|
597 }
|
nuclear@21
|
598
|
nuclear@0
|
599 return v;
|
nuclear@0
|
600 }
|
nuclear@0
|
601
|
nuclear@0
|
602
|
nuclear@0
|
603 vec3_t anm_get_position(struct anm_node *node, anm_time_t tm)
|
nuclear@0
|
604 {
|
nuclear@0
|
605 mat4_t xform;
|
nuclear@0
|
606 vec3_t pos = {0.0, 0.0, 0.0};
|
nuclear@0
|
607
|
nuclear@0
|
608 if(!node->parent) {
|
nuclear@0
|
609 return anm_get_node_position(node, tm);
|
nuclear@0
|
610 }
|
nuclear@0
|
611
|
nuclear@0
|
612 anm_get_matrix(node, xform, tm);
|
nuclear@0
|
613 return v3_transform(pos, xform);
|
nuclear@0
|
614 }
|
nuclear@0
|
615
|
nuclear@0
|
616 quat_t anm_get_rotation(struct anm_node *node, anm_time_t tm)
|
nuclear@0
|
617 {
|
nuclear@0
|
618 quat_t rot, prot;
|
nuclear@0
|
619 rot = anm_get_node_rotation(node, tm);
|
nuclear@0
|
620
|
nuclear@0
|
621 if(!node->parent) {
|
nuclear@0
|
622 return rot;
|
nuclear@0
|
623 }
|
nuclear@0
|
624
|
nuclear@0
|
625 prot = anm_get_rotation(node->parent, tm);
|
nuclear@0
|
626 return quat_mul(prot, rot);
|
nuclear@0
|
627 }
|
nuclear@0
|
628
|
nuclear@0
|
629 vec3_t anm_get_scaling(struct anm_node *node, anm_time_t tm)
|
nuclear@0
|
630 {
|
nuclear@0
|
631 vec3_t s, ps;
|
nuclear@0
|
632 s = anm_get_node_scaling(node, tm);
|
nuclear@0
|
633
|
nuclear@0
|
634 if(!node->parent) {
|
nuclear@0
|
635 return s;
|
nuclear@0
|
636 }
|
nuclear@0
|
637
|
nuclear@0
|
638 ps = anm_get_scaling(node->parent, tm);
|
nuclear@0
|
639 return v3_mul(s, ps);
|
nuclear@0
|
640 }
|
nuclear@0
|
641
|
nuclear@5
|
642 void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
|
nuclear@5
|
643 {
|
nuclear@9
|
644 int i;
|
nuclear@9
|
645 mat4_t rmat;
|
nuclear@5
|
646 vec3_t pos, scale;
|
nuclear@5
|
647 quat_t rot;
|
nuclear@5
|
648
|
nuclear@5
|
649 pos = anm_get_node_position(node, tm);
|
nuclear@5
|
650 rot = anm_get_node_rotation(node, tm);
|
nuclear@5
|
651 scale = anm_get_node_scaling(node, tm);
|
nuclear@5
|
652
|
nuclear@9
|
653 m4_set_translation(mat, node->pivot.x, node->pivot.y, node->pivot.z);
|
nuclear@5
|
654
|
nuclear@5
|
655 quat_to_mat4(rmat, rot);
|
nuclear@9
|
656 for(i=0; i<3; i++) {
|
nuclear@9
|
657 mat[i][0] = rmat[i][0];
|
nuclear@9
|
658 mat[i][1] = rmat[i][1];
|
nuclear@9
|
659 mat[i][2] = rmat[i][2];
|
nuclear@9
|
660 }
|
nuclear@9
|
661 /* this loop is equivalent to: m4_mult(mat, mat, rmat); */
|
nuclear@5
|
662
|
nuclear@9
|
663 mat[0][0] *= scale.x; mat[0][1] *= scale.y; mat[0][2] *= scale.z; mat[0][3] += pos.x;
|
nuclear@9
|
664 mat[1][0] *= scale.x; mat[1][1] *= scale.y; mat[1][2] *= scale.z; mat[1][3] += pos.y;
|
nuclear@9
|
665 mat[2][0] *= scale.x; mat[2][1] *= scale.y; mat[2][2] *= scale.z; mat[2][3] += pos.z;
|
nuclear@9
|
666
|
nuclear@9
|
667 m4_translate(mat, -node->pivot.x, -node->pivot.y, -node->pivot.z);
|
nuclear@9
|
668
|
nuclear@9
|
669 /* that's basically: pivot * rotation * translation * scaling * -pivot */
|
nuclear@5
|
670 }
|
nuclear@5
|
671
|
nuclear@5
|
672 void anm_get_node_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
|
nuclear@5
|
673 {
|
nuclear@5
|
674 mat4_t tmp;
|
nuclear@5
|
675 anm_get_node_matrix(node, tmp, tm);
|
nuclear@5
|
676 m4_inverse(mat, tmp);
|
nuclear@5
|
677 }
|
nuclear@5
|
678
|
nuclear@20
|
679 void anm_eval_node(struct anm_node *node, anm_time_t tm)
|
nuclear@20
|
680 {
|
nuclear@20
|
681 anm_get_node_matrix(node, node->matrix, tm);
|
nuclear@20
|
682 }
|
nuclear@20
|
683
|
nuclear@20
|
684 void anm_eval(struct anm_node *node, anm_time_t tm)
|
nuclear@20
|
685 {
|
nuclear@20
|
686 struct anm_node *c;
|
nuclear@20
|
687
|
nuclear@20
|
688 anm_eval_node(node, tm);
|
nuclear@20
|
689
|
nuclear@20
|
690 if(node->parent) {
|
nuclear@20
|
691 /* due to post-order traversal, the parent matrix is already evaluated */
|
nuclear@20
|
692 m4_mult(node->matrix, node->parent->matrix, node->matrix);
|
nuclear@20
|
693 }
|
nuclear@20
|
694
|
nuclear@20
|
695 /* recersively evaluate all children */
|
nuclear@20
|
696 c = node->child;
|
nuclear@20
|
697 while(c) {
|
nuclear@20
|
698 anm_eval(c, tm);
|
nuclear@20
|
699 c = c->next;
|
nuclear@20
|
700 }
|
nuclear@20
|
701 }
|
nuclear@20
|
702
|
nuclear@0
|
703 void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
|
nuclear@0
|
704 {
|
nuclear@0
|
705 struct mat_cache *cache = pthread_getspecific(node->cache_key);
|
nuclear@0
|
706 if(!cache) {
|
nuclear@0
|
707 cache = malloc(sizeof *cache);
|
nuclear@0
|
708 assert(cache);
|
nuclear@0
|
709
|
nuclear@0
|
710 pthread_mutex_lock(&node->cache_list_lock);
|
nuclear@0
|
711 cache->next = node->cache_list;
|
nuclear@0
|
712 node->cache_list = cache;
|
nuclear@0
|
713 pthread_mutex_unlock(&node->cache_list_lock);
|
nuclear@0
|
714
|
nuclear@0
|
715 cache->time = ANM_TIME_INVAL;
|
nuclear@2
|
716 cache->inv_time = ANM_TIME_INVAL;
|
nuclear@0
|
717 pthread_setspecific(node->cache_key, cache);
|
nuclear@0
|
718 }
|
nuclear@0
|
719
|
nuclear@0
|
720 if(cache->time != tm) {
|
nuclear@5
|
721 anm_get_node_matrix(node, cache->matrix, tm);
|
nuclear@0
|
722
|
nuclear@0
|
723 if(node->parent) {
|
nuclear@0
|
724 mat4_t parent_mat;
|
nuclear@0
|
725
|
nuclear@4
|
726 anm_get_matrix(node->parent, parent_mat, tm);
|
nuclear@0
|
727 m4_mult(cache->matrix, parent_mat, cache->matrix);
|
nuclear@0
|
728 }
|
nuclear@0
|
729 cache->time = tm;
|
nuclear@0
|
730 }
|
nuclear@0
|
731 m4_copy(mat, cache->matrix);
|
nuclear@0
|
732 }
|
nuclear@0
|
733
|
nuclear@0
|
734 void anm_get_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
|
nuclear@0
|
735 {
|
nuclear@0
|
736 struct mat_cache *cache = pthread_getspecific(node->cache_key);
|
nuclear@0
|
737 if(!cache) {
|
nuclear@0
|
738 cache = malloc(sizeof *cache);
|
nuclear@0
|
739 assert(cache);
|
nuclear@0
|
740
|
nuclear@0
|
741 pthread_mutex_lock(&node->cache_list_lock);
|
nuclear@0
|
742 cache->next = node->cache_list;
|
nuclear@0
|
743 node->cache_list = cache;
|
nuclear@0
|
744 pthread_mutex_unlock(&node->cache_list_lock);
|
nuclear@0
|
745
|
nuclear@0
|
746 cache->inv_time = ANM_TIME_INVAL;
|
nuclear@2
|
747 cache->inv_time = ANM_TIME_INVAL;
|
nuclear@0
|
748 pthread_setspecific(node->cache_key, cache);
|
nuclear@0
|
749 }
|
nuclear@0
|
750
|
nuclear@0
|
751 if(cache->inv_time != tm) {
|
nuclear@0
|
752 anm_get_matrix(node, mat, tm);
|
nuclear@0
|
753 m4_inverse(cache->inv_matrix, mat);
|
nuclear@0
|
754 cache->inv_time = tm;
|
nuclear@0
|
755 }
|
nuclear@0
|
756 m4_copy(mat, cache->inv_matrix);
|
nuclear@0
|
757 }
|
nuclear@0
|
758
|
nuclear@0
|
759 anm_time_t anm_get_start_time(struct anm_node *node)
|
nuclear@0
|
760 {
|
nuclear@21
|
761 int i, j;
|
nuclear@0
|
762 struct anm_node *c;
|
nuclear@0
|
763 anm_time_t res = LONG_MAX;
|
nuclear@0
|
764
|
nuclear@21
|
765 for(j=0; j<2; j++) {
|
nuclear@21
|
766 struct anm_animation *anim = anm_get_active_animation(node, j);
|
nuclear@21
|
767 if(!anim) break;
|
nuclear@21
|
768
|
nuclear@21
|
769 for(i=0; i<ANM_NUM_TRACKS; i++) {
|
nuclear@21
|
770 if(anim->tracks[i].count) {
|
nuclear@21
|
771 anm_time_t tm = anim->tracks[i].keys[0].time;
|
nuclear@21
|
772 if(tm < res) {
|
nuclear@21
|
773 res = tm;
|
nuclear@21
|
774 }
|
nuclear@0
|
775 }
|
nuclear@0
|
776 }
|
nuclear@0
|
777 }
|
nuclear@0
|
778
|
nuclear@0
|
779 c = node->child;
|
nuclear@0
|
780 while(c) {
|
nuclear@0
|
781 anm_time_t tm = anm_get_start_time(c);
|
nuclear@0
|
782 if(tm < res) {
|
nuclear@0
|
783 res = tm;
|
nuclear@0
|
784 }
|
nuclear@0
|
785 c = c->next;
|
nuclear@0
|
786 }
|
nuclear@0
|
787 return res;
|
nuclear@0
|
788 }
|
nuclear@0
|
789
|
nuclear@0
|
790 anm_time_t anm_get_end_time(struct anm_node *node)
|
nuclear@0
|
791 {
|
nuclear@21
|
792 int i, j;
|
nuclear@0
|
793 struct anm_node *c;
|
nuclear@0
|
794 anm_time_t res = LONG_MIN;
|
nuclear@0
|
795
|
nuclear@21
|
796 for(j=0; j<2; j++) {
|
nuclear@21
|
797 struct anm_animation *anim = anm_get_active_animation(node, j);
|
nuclear@21
|
798 if(!anim) break;
|
nuclear@21
|
799
|
nuclear@21
|
800 for(i=0; i<ANM_NUM_TRACKS; i++) {
|
nuclear@21
|
801 if(anim->tracks[i].count) {
|
nuclear@21
|
802 anm_time_t tm = anim->tracks[i].keys[anim->tracks[i].count - 1].time;
|
nuclear@21
|
803 if(tm > res) {
|
nuclear@21
|
804 res = tm;
|
nuclear@21
|
805 }
|
nuclear@0
|
806 }
|
nuclear@0
|
807 }
|
nuclear@0
|
808 }
|
nuclear@0
|
809
|
nuclear@0
|
810 c = node->child;
|
nuclear@0
|
811 while(c) {
|
nuclear@0
|
812 anm_time_t tm = anm_get_end_time(c);
|
nuclear@0
|
813 if(tm > res) {
|
nuclear@0
|
814 res = tm;
|
nuclear@0
|
815 }
|
nuclear@0
|
816 c = c->next;
|
nuclear@0
|
817 }
|
nuclear@0
|
818 return res;
|
nuclear@0
|
819 }
|
nuclear@0
|
820
|
nuclear@0
|
821 static void invalidate_cache(struct anm_node *node)
|
nuclear@0
|
822 {
|
nuclear@0
|
823 struct mat_cache *cache = pthread_getspecific(node->cache_key);
|
nuclear@0
|
824 if(cache) {
|
nuclear@13
|
825 cache->time = cache->inv_time = ANM_TIME_INVAL;
|
nuclear@0
|
826 }
|
nuclear@0
|
827 }
|