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