Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2012
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / Scene Graph sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 :
27 : #include <gpac/internal/scenegraph_dev.h>
28 : /*MPEG4 tags (for internal nodes)*/
29 : #include <gpac/nodes_mpeg4.h>
30 :
31 :
32 : #ifndef GPAC_DISABLE_VRML
33 :
34 : static Fixed Interpolate(Fixed keyValue1, Fixed keyValue2, Fixed fraction)
35 : {
36 300 : return gf_mulfix(keyValue2 - keyValue1, fraction) + keyValue1;
37 : }
38 :
39 : static Fixed GetInterpolateFraction(Fixed key1, Fixed key2, Fixed fraction)
40 : {
41 148 : Fixed keyDiff = key2 - key1;
42 : assert((fraction >= key1) && (fraction <= key2));
43 148 : if (ABS(keyDiff) < FIX_EPSILON) return 0;
44 148 : return gf_divfix(fraction - key1, keyDiff);
45 : }
46 :
47 : enum
48 : {
49 : ANIM_LINE,
50 : ANIM_QUADRATIC,
51 : ANIM_CUBIC,
52 : ANIM_NURBS,
53 : /*NOT SUPPORTED*/
54 : ANIM_SPLINE
55 : };
56 :
57 : enum
58 : {
59 : ANIM_DEFAULT,
60 : ANIM_DISCRETE,
61 : ANIM_LINEAR,
62 : /*NOT SUPPORTED ON SPLINES*/
63 : ANIM_PACED,
64 : ANIM_VELOCITY
65 : };
66 :
67 :
68 : /* Bisection algorithm to find u=a*t^3+b*t^2+c*t+d */
69 300 : Fixed do_bisection(Fixed t, SFVec2f a, SFVec2f b, SFVec2f c, SFVec2f d)
70 : {
71 : Fixed left, right, usearch, tsearch, limit;
72 : left = 0;
73 : right = FIX_ONE;
74 : limit = FIX_ONE/1000;
75 :
76 : do {
77 2460 : usearch = (left+right)/2;
78 2460 : tsearch = gf_mulfix(usearch, c.x + gf_mulfix(usearch, b.x + gf_mulfix(usearch, a.x))) + d.x;
79 2460 : if (t < tsearch + limit) right = usearch;
80 : else left = usearch;
81 2460 : } while ((t > tsearch + limit) || (t<tsearch - limit));
82 300 : return gf_mulfix(usearch, c.y + gf_mulfix(usearch, b.y + gf_mulfix(usearch , a.y))) + d.y;
83 : }
84 :
85 :
86 :
87 : typedef struct
88 : {
89 : Fixed *knots, *weights, *n, *left, *right;
90 : u32 nknots, nweights, npoints;
91 : u32 p;
92 : u32 type;
93 : Bool valid;
94 : } anim_nurbs;
95 :
96 : static Fixed cubic_knots[] = {0,0,0,0,FIX_ONE,FIX_ONE,FIX_ONE,FIX_ONE};
97 : static Fixed quadratic_knots[] = {0,0,0,FIX_ONE,FIX_ONE,FIX_ONE};
98 :
99 8 : static void anurbs_reset(anim_nurbs *nurbs)
100 : {
101 8 : if (nurbs->n) gf_free(nurbs->n);
102 8 : if (nurbs->left) gf_free(nurbs->left);
103 8 : if (nurbs->right) gf_free(nurbs->right);
104 8 : nurbs->n = nurbs->left = nurbs->right = NULL;
105 8 : }
106 :
107 3 : static void anurbs_init(anim_nurbs *nurbs, u32 type, u32 nCtrl, u32 nKnots, Fixed *knots, u32 nWeight, Fixed *weights)
108 : {
109 : memset(nurbs, 0, sizeof(anim_nurbs));
110 3 : nurbs->type = type;
111 3 : switch (type) {
112 1 : case ANIM_CUBIC:
113 1 : nurbs->npoints = 4;
114 1 : nurbs->nknots = 8;
115 1 : nurbs->knots = cubic_knots;
116 1 : break;
117 2 : case ANIM_QUADRATIC:
118 2 : nurbs->npoints = 3;
119 2 : nurbs->nknots = 6;
120 2 : nurbs->knots = quadratic_knots;
121 2 : break;
122 0 : default:
123 0 : nurbs->npoints = nCtrl;
124 0 : nurbs->knots = knots;
125 0 : nurbs->nknots = nKnots;
126 0 : nurbs->weights = weights;
127 0 : nurbs->nweights = nWeight;
128 0 : break;
129 : }
130 3 : nurbs->p = nurbs->nknots - nurbs->npoints - 1;
131 3 : if ((nurbs->p<=0) || (nurbs->p >= nurbs->nknots -1)
132 3 : || ((nurbs->nweights>0) && (nurbs->npoints != nurbs->nweights)) ) {
133 0 : nurbs->valid = 0;
134 : } else {
135 3 : nurbs->valid = 1;
136 : }
137 3 : }
138 :
139 450 : static void anurbs_basis(anim_nurbs *nurbs, s32 span, Fixed t)
140 : {
141 : u32 i, j;
142 : Fixed saved, temp;
143 450 : if (!nurbs->n) {
144 3 : nurbs->n = (Fixed*)gf_malloc(sizeof(Fixed) * (nurbs->p+1));
145 3 : nurbs->left = (Fixed*)gf_malloc(sizeof(Fixed) * (nurbs->p+1));
146 3 : nurbs->right = (Fixed*)gf_malloc(sizeof(Fixed) * (nurbs->p+1));
147 : }
148 450 : nurbs->n[0] = FIX_ONE;
149 :
150 1500 : for(i=1; i<=nurbs->p; i++) {
151 1050 : nurbs->left[i] = t - nurbs->knots[span+1-i];
152 1050 : nurbs->right[i] = nurbs->knots[span+i]-t;
153 : saved = 0;
154 :
155 3900 : for(j=0; j<i; j++) {
156 1800 : temp = gf_divfix(nurbs->n[j], nurbs->right[j+1] + nurbs->left[i-j]);
157 1800 : nurbs->n[j] = saved + gf_mulfix(nurbs->right[j+1], temp);
158 1800 : saved = gf_mulfix(nurbs->left[i-j], temp);
159 : }
160 1050 : nurbs->n[i]=saved;
161 : }
162 450 : }
163 :
164 450 : static s32 anurbs_find_span(anim_nurbs *nurbs, Fixed u)
165 : {
166 : #if 0
167 : s32 span;
168 : if (u == nurbs->knots[nurbs->npoints]) return nurbs->npoints - 1;
169 : for (span = (s32) nurbs->p; span < (s32) nurbs->nknots - (s32) nurbs->p; span++) {
170 : if (u<nurbs->knots[span]) break;
171 : }
172 : span--;
173 : return span;
174 : #else
175 : s32 low, high, mid;
176 450 : if (u == nurbs->knots[nurbs->npoints]) return nurbs->npoints - 1;
177 450 : low = nurbs->p;
178 450 : high = nurbs->npoints;
179 450 : mid = (low + high)/2;
180 :
181 900 : while (u < nurbs->knots[mid] || u >= nurbs->knots[mid+1]) {
182 0 : if (u < nurbs->knots[mid]) high = mid;
183 : else low = mid;
184 0 : mid = (low + high)/2;
185 : }
186 : return (mid);
187 :
188 : #endif
189 : }
190 :
191 150 : static SFVec3f anurbs_get_vec3f(anim_nurbs *nurbs, s32 span, SFVec3f *pts)
192 : {
193 : SFVec3f res, tmp;
194 : Fixed w, wi;
195 : u32 i;
196 : tmp.x = tmp.y = tmp.z = 0;
197 : res = tmp;
198 : w=0;
199 600 : for(i=0; i<=nurbs->p; i++) {
200 450 : tmp = pts[span - nurbs->p + i];
201 450 : if (nurbs->nweights>0) {
202 0 : wi = nurbs->weights[span - nurbs->p + i];
203 0 : tmp = gf_vec_scale(tmp, wi);
204 0 : w += gf_mulfix(nurbs->n[i], wi);
205 : }
206 450 : res.x += gf_mulfix(nurbs->n[i], tmp.x);
207 450 : res.y += gf_mulfix(nurbs->n[i], tmp.y);
208 450 : res.z += gf_mulfix(nurbs->n[i], tmp.z);
209 : }
210 150 : if (nurbs->nweights>0) {
211 0 : if (w) {
212 0 : w = gf_invfix(w);
213 0 : res = gf_vec_scale(res, w);
214 : }
215 : }
216 150 : return res;
217 : }
218 :
219 150 : static SFVec2f anurbs_get_vec2f(anim_nurbs *nurbs, s32 span, SFVec2f *pts)
220 : {
221 : SFVec2f res, tmp;
222 : Fixed w, wi;
223 : u32 i;
224 : tmp.x = tmp.y = 0;
225 : res = tmp;
226 : w=0;
227 600 : for(i=0; i<=nurbs->p; i++) {
228 450 : tmp = pts[span - nurbs->p + i];
229 450 : if (nurbs->nweights>0) {
230 0 : wi = nurbs->weights[span - nurbs->p + i];
231 0 : tmp.x = gf_mulfix(tmp.x, wi);
232 0 : tmp.y = gf_mulfix(tmp.y, wi);
233 0 : w += gf_mulfix(nurbs->n[i], wi);
234 : }
235 450 : res.x += gf_mulfix(nurbs->n[i], tmp.x);
236 450 : res.y += gf_mulfix(nurbs->n[i], tmp.y);
237 : }
238 150 : if (nurbs->nweights>0) {
239 0 : if (w) {
240 0 : w = gf_invfix(w);
241 0 : res.x = gf_mulfix(res.x, w);
242 0 : res.y = gf_mulfix(res.y, w);
243 : }
244 : }
245 150 : return res;
246 : }
247 :
248 150 : static Fixed anurbs_get_float(anim_nurbs *nurbs, s32 span, Fixed *vals)
249 : {
250 : Fixed res;
251 : Fixed w, wi;
252 : u32 i;
253 : res = 0;
254 : w=0;
255 750 : for(i=0; i<=nurbs->p; i++) {
256 600 : Fixed tmp = vals[span - nurbs->p + i];
257 600 : if (nurbs->nweights>0) {
258 0 : wi = nurbs->weights[span - nurbs->p + i];
259 0 : tmp = gf_mulfix(tmp, wi);
260 0 : w += gf_mulfix(nurbs->n[i], wi);
261 : }
262 600 : res += gf_mulfix(nurbs->n[i], tmp);
263 : }
264 150 : if (nurbs->nweights>0) res = gf_divfix(res, w);
265 150 : return res;
266 : }
267 :
268 : typedef struct
269 : {
270 : Bool is_dirty;
271 : u32 anim_type;
272 : /*for paced anim*/
273 : Fixed length;
274 : /*for spline anim*/
275 : SFVec2f a, b, c, d;
276 : /*nurbs path*/
277 : anim_nurbs anurbs;
278 : } AnimatorStack;
279 :
280 952 : static void Anim_Destroy(GF_Node *node, void *rs, Bool is_destroy)
281 : {
282 952 : if (is_destroy) {
283 4 : AnimatorStack *stack = (AnimatorStack *)gf_node_get_private(node);
284 4 : anurbs_reset(&stack->anurbs);
285 4 : gf_free(stack);
286 : }
287 952 : }
288 :
289 4 : static void Animator_Update(AnimatorStack *stack, u32 keyValueType, u32 nCtrl, MFVec2f *keySpline, u32 nWeight, Fixed *weights)
290 : {
291 4 : if (stack->anim_type==ANIM_SPLINE) {
292 2 : stack->a.x = (keySpline->vals[0].x - keySpline->vals[1].x)*3 + FIX_ONE;
293 2 : stack->a.y = (keySpline->vals[0].y - keySpline->vals[1].y)*3 + FIX_ONE;
294 2 : stack->b.x = (keySpline->vals[1].x - 2*keySpline->vals[0].x)*3;
295 2 : stack->b.y = (keySpline->vals[1].y - 2*keySpline->vals[0].y)*3;
296 2 : stack->c.x = keySpline->vals[0].x*3;
297 2 : stack->c.y = keySpline->vals[0].y*3;
298 2 : stack->d.x = stack->d.y = 0;
299 : }
300 4 : anurbs_reset(&stack->anurbs);
301 4 : switch (keyValueType) {
302 1 : case ANIM_CUBIC:
303 1 : anurbs_init(&stack->anurbs, ANIM_CUBIC, 0, 0, NULL, 0, NULL);
304 1 : break;
305 2 : case ANIM_QUADRATIC:
306 2 : anurbs_init(&stack->anurbs, ANIM_QUADRATIC, 0, 0, NULL, 0, NULL);
307 2 : break;
308 0 : case ANIM_NURBS:
309 0 : anurbs_init(&stack->anurbs, ANIM_NURBS, nCtrl, keySpline->count, (Fixed *) &keySpline->vals[0].x, nWeight, weights);
310 0 : break;
311 : }
312 4 : }
313 :
314 :
315 : static Bool anim_check_frac(Fixed frac, SFVec2f *fromTo)
316 : {
317 600 : if (frac<0) return 0;
318 600 : if (frac>FIX_ONE) return 0;
319 600 : if (fromTo->x > fromTo->y) return 0;
320 : /*not active*/
321 600 : if (frac<fromTo->x) return 0;
322 600 : if (frac>fromTo->y) return 0;
323 : return 1;
324 : }
325 :
326 1 : static void PA_Update(M_PositionAnimator *pa, AnimatorStack *stack)
327 : {
328 : u32 i;
329 : GF_Vec d;
330 1 : stack->is_dirty = 0;
331 1 : stack->anim_type = pa->keyType;
332 : /*if empty key and default anim switch to linear*/
333 1 : if (!pa->key.count && !stack->anim_type) stack->anim_type = ANIM_LINEAR;
334 :
335 1 : if (stack->anim_type == ANIM_PACED) {
336 0 : stack->length = 0;
337 0 : for (i=0; i<pa->keyValue.count-1; i++) {
338 0 : d.x = pa->keyValue.vals[i+1].x - pa->keyValue.vals[i].x;
339 0 : d.y = pa->keyValue.vals[i+1].y - pa->keyValue.vals[i].y;
340 0 : d.z = pa->keyValue.vals[i+1].z - pa->keyValue.vals[i].z;
341 0 : stack->length += gf_vec_len(d);
342 : }
343 : }
344 1 : Animator_Update(stack, pa->keyValueType, pa->keyValue.count, &pa->keySpline, pa->weight.count, pa->weight.vals);
345 1 : }
346 150 : static void PA_SetFraction(GF_Node *node, GF_Route *route)
347 : {
348 : Fixed frac;
349 : u32 nbKeys, nbVals, i;
350 : GF_Vec d;
351 : Fixed len, dlen, dist;
352 : M_PositionAnimator *pa = (M_PositionAnimator *)node;
353 150 : AnimatorStack *stack = (AnimatorStack *)gf_node_get_private(node);
354 :
355 150 : frac = pa->set_fraction;
356 0 : if (!anim_check_frac(frac, &pa->fromTo)) return;
357 :
358 150 : if (stack->is_dirty) PA_Update(pa, stack);
359 :
360 150 : nbKeys = pa->key.count;
361 150 : nbVals = pa->keyValue.count;
362 :
363 150 : switch (pa->keyValueType) {
364 : /*linear interpolate*/
365 0 : case ANIM_LINE:
366 : /*compute frac and segment start index*/
367 0 : switch (stack->anim_type) {
368 0 : case ANIM_DEFAULT:
369 0 : if (nbKeys != nbVals) return;
370 0 : if (frac<pa->key.vals[0]) {
371 : i=0;
372 : frac = 0;
373 : }
374 0 : else if (frac>pa->key.vals[nbKeys-1]) {
375 0 : i=nbVals-2;
376 : frac = FIX_ONE;
377 : }
378 : else {
379 0 : for (i=0; i<nbKeys-1; i++) {
380 0 : if ((frac>=pa->key.vals[i]) && (frac<pa->key.vals[i+1])) break;
381 : }
382 0 : frac = GetInterpolateFraction(pa->key.vals[i], pa->key.vals[i+1], frac);
383 : }
384 : break;
385 0 : case ANIM_DISCRETE:
386 0 : i = FIX2INT(gf_floor(frac*nbVals));
387 : frac = 0;
388 0 : break;
389 0 : case ANIM_LINEAR:
390 0 : i = FIX2INT(gf_floor(frac*(nbVals-1)));
391 0 : frac = (frac - INT2FIX(i) / (nbVals-1) ) * (nbVals-1);
392 0 : break;
393 0 : case ANIM_PACED:
394 : /*at cst speed, this is the length done*/
395 0 : dist = gf_mulfix(frac, stack->length);
396 : /*then figure out in which seg we are*/
397 : len = 0;
398 : dlen = 0;
399 0 : for (i=0; i<nbVals-1; i++) {
400 0 : d.x = pa->keyValue.vals[i+1].x - pa->keyValue.vals[i].x;
401 0 : d.y = pa->keyValue.vals[i+1].y - pa->keyValue.vals[i].y;
402 0 : d.z = pa->keyValue.vals[i+1].z - pa->keyValue.vals[i].z;
403 0 : dlen = gf_vec_len(d);
404 0 : if (len+dlen>dist) break;
405 : len += dlen;
406 : }
407 : /*that's our fraction inside the seg*/
408 0 : frac = gf_divfix(dist-len, dlen);
409 : break;
410 0 : case ANIM_SPLINE:
411 0 : frac = do_bisection(frac, stack->a, stack->b, stack->c, stack->d);
412 0 : i = FIX2INT(gf_floor(frac*(nbVals-1)));
413 0 : frac = (frac - INT2FIX(i) / (nbVals-1) ) * (nbVals-1);
414 0 : break;
415 : default:
416 : return;
417 : }
418 : /*interpolate*/
419 0 : pa->value_changed.x = Interpolate(pa->keyValue.vals[i].x, pa->keyValue.vals[i+1].x, frac);
420 0 : pa->value_changed.y = Interpolate(pa->keyValue.vals[i].y, pa->keyValue.vals[i+1].y, frac);
421 0 : pa->value_changed.z = Interpolate(pa->keyValue.vals[i].z, pa->keyValue.vals[i+1].z, frac);
422 0 : break;
423 : /*bezier interpolate*/
424 150 : case ANIM_QUADRATIC:
425 : case ANIM_CUBIC:
426 : case ANIM_NURBS:
427 150 : if (!stack->anurbs.valid) return;
428 : /*compute frac*/
429 150 : switch (stack->anim_type) {
430 0 : case ANIM_DISCRETE:
431 0 : i = FIX2INT(gf_floor(frac*nbVals));
432 0 : frac = INT2FIX(i) / nbVals;
433 0 : break;
434 0 : case ANIM_LINEAR:
435 0 : i = FIX2INT(gf_floor(frac*(nbVals-1)));
436 0 : frac = (frac - INT2FIX(i) / (nbVals-1) ) * (nbVals-1);
437 0 : break;
438 150 : case ANIM_VELOCITY:
439 150 : frac = do_bisection(frac, stack->a, stack->b, stack->c, stack->d);
440 150 : break;
441 : /*nothing to do for this one here*/
442 : case ANIM_DEFAULT:
443 : /*not supported - use frac as is*/
444 : case ANIM_PACED:
445 : default:
446 : break;
447 : }
448 : /*evaluate*/
449 150 : i = anurbs_find_span(&stack->anurbs, frac);
450 150 : anurbs_basis(&stack->anurbs, i, frac);
451 150 : pa->value_changed = anurbs_get_vec3f(&stack->anurbs, i, pa->keyValue.vals);
452 150 : break;
453 : /*not supported*/
454 : case ANIM_SPLINE:
455 : default:
456 : return;
457 : }
458 :
459 150 : pa->value_changed.x += pa->offset.x;
460 150 : pa->value_changed.y += pa->offset.y;
461 150 : pa->value_changed.z += pa->offset.z;
462 150 : gf_node_event_out(node, 12/*"value_changed"*/);
463 : }
464 :
465 149 : void PA_Modified(GF_Node *node, GF_FieldInfo *field)
466 : {
467 149 : AnimatorStack *stack = (AnimatorStack *)gf_node_get_private(node);
468 : M_PositionAnimator *pa = (M_PositionAnimator *)node;
469 :
470 149 : if ( /*all fields impacting cached path len / nurbs*/
471 149 : (field->far_ptr == &pa->keyValue)
472 149 : || (field->far_ptr == &pa->keyValueType)
473 149 : || (field->far_ptr == &pa->key)
474 149 : || (field->far_ptr == &pa->keyType)
475 149 : || (field->far_ptr == &pa->keySpline)
476 149 : || (field->far_ptr == &pa->weight)
477 : )
478 0 : stack->is_dirty = 1;
479 149 : }
480 1 : void PA_Init(GF_Node *n)
481 : {
482 : M_PositionAnimator *sa = (M_PositionAnimator*)n;
483 : AnimatorStack *stack;
484 1 : GF_SAFEALLOC(stack, AnimatorStack);
485 1 : if (!stack) {
486 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to allocate position animator stack\n"));
487 : return;
488 : }
489 1 : stack->is_dirty = 1;
490 1 : gf_node_set_private(n, stack);
491 1 : gf_node_set_callback_function(n, Anim_Destroy);
492 1 : sa->on_set_fraction = PA_SetFraction;
493 : }
494 :
495 2 : static void PA2D_Update(M_PositionAnimator2D *pa, AnimatorStack *stack)
496 : {
497 : u32 i;
498 : Fixed dx, dy;
499 2 : stack->is_dirty = 0;
500 2 : stack->anim_type = pa->keyType;
501 : /*if empty key and default anim switch to linear*/
502 2 : if (!pa->key.count && !stack->anim_type) stack->anim_type = ANIM_LINEAR;
503 :
504 2 : if (stack->anim_type == ANIM_PACED) {
505 0 : stack->length = 0;
506 0 : for (i=0; i<pa->keyValue.count-1; i++) {
507 0 : dx = pa->keyValue.vals[i+1].x - pa->keyValue.vals[i].x;
508 0 : dy = pa->keyValue.vals[i+1].y - pa->keyValue.vals[i].y;
509 0 : stack->length += gf_sqrt(gf_mulfix(dx, dx) + gf_mulfix(dy, dy));
510 : }
511 : }
512 2 : Animator_Update(stack, pa->keyValueType, pa->keyValue.count, &pa->keySpline, pa->weight.count, pa->weight.vals);
513 2 : }
514 300 : static void PA2D_SetFraction(GF_Node *node, GF_Route *route)
515 : {
516 : Fixed frac;
517 : u32 nbKeys, nbVals, i;
518 : Fixed dx, dy;
519 : Fixed len, dlen, dist;
520 : M_PositionAnimator2D *pa = (M_PositionAnimator2D *)node;
521 300 : AnimatorStack *stack = (AnimatorStack *)gf_node_get_private(node);
522 :
523 300 : frac = pa->set_fraction;
524 : if (!anim_check_frac(frac, &pa->fromTo)) return;
525 :
526 300 : if (stack->is_dirty) PA2D_Update(pa, stack);
527 :
528 300 : nbKeys = pa->key.count;
529 300 : nbVals = pa->keyValue.count;
530 :
531 300 : switch (pa->keyValueType) {
532 : /*linear interpolate*/
533 150 : case ANIM_LINE:
534 : /*compute frac and segment start index*/
535 150 : switch (stack->anim_type) {
536 150 : case ANIM_DEFAULT:
537 150 : if (nbKeys != nbVals) return;
538 150 : if (frac<=pa->key.vals[0]) {
539 : i=0;
540 : frac = 0;
541 : }
542 149 : else if (frac>=pa->key.vals[nbKeys-1]) {
543 1 : i=nbVals-2;
544 : frac=FIX_ONE;
545 : }
546 : else {
547 90 : for (i=0; i<nbKeys-1; i++) {
548 238 : if ((frac>=pa->key.vals[i]) && (frac<pa->key.vals[i+1])) break;
549 : }
550 148 : frac = GetInterpolateFraction(pa->key.vals[i], pa->key.vals[i+1], frac);
551 : }
552 : break;
553 0 : case ANIM_DISCRETE:
554 0 : i = FIX2INT(gf_floor(frac*nbVals));
555 : frac = 0;
556 0 : break;
557 0 : case ANIM_LINEAR:
558 0 : i = FIX2INT(gf_floor(frac*(nbVals-1)));
559 0 : frac = (frac - INT2FIX(i)/ (nbVals-1) ) * (nbVals-1);
560 0 : break;
561 0 : case ANIM_PACED:
562 : /*at cst speed, this is the length done*/
563 0 : dist = gf_mulfix(frac, stack->length);
564 : /*then figure out in which seg we are*/
565 : len = 0;
566 : dlen = 0;
567 0 : for (i=0; i<nbVals-1; i++) {
568 0 : dx = pa->keyValue.vals[i+1].x - pa->keyValue.vals[i].x;
569 0 : dy = pa->keyValue.vals[i+1].y - pa->keyValue.vals[i].y;
570 0 : dlen = gf_sqrt(gf_mulfix(dx,dx) + gf_mulfix(dy,dy));
571 0 : if (len+dlen>dist) break;
572 : len += dlen;
573 : }
574 : /*that's our fraction inside the seg*/
575 0 : frac = gf_divfix(dist-len, dlen);
576 : break;
577 0 : case ANIM_SPLINE:
578 0 : frac = do_bisection(frac, stack->a, stack->b, stack->c, stack->d);
579 0 : i = FIX2INT(gf_floor(frac * (nbVals-1)));
580 0 : frac = (frac - INT2FIX(i) / (nbVals-1) ) * (nbVals-1);
581 0 : break;
582 : default:
583 : return;
584 : }
585 : /*interpolate*/
586 300 : pa->value_changed.x = Interpolate(pa->keyValue.vals[i].x, pa->keyValue.vals[i+1].x, frac);
587 300 : pa->value_changed.y = Interpolate(pa->keyValue.vals[i].y, pa->keyValue.vals[i+1].y, frac);
588 150 : break;
589 : /*bezier interpolate*/
590 150 : case ANIM_QUADRATIC:
591 : case ANIM_CUBIC:
592 : case ANIM_NURBS:
593 150 : if (!stack->anurbs.valid) return;
594 : /*compute frac*/
595 150 : switch (stack->anim_type) {
596 0 : case ANIM_DISCRETE:
597 0 : i = FIX2INT(gf_floor(frac*nbVals));
598 0 : frac = INT2FIX(i) / nbVals;
599 0 : break;
600 0 : case ANIM_LINEAR:
601 0 : i = FIX2INT(gf_floor(frac*(nbVals-1)));
602 0 : frac = (frac - INT2FIX(i) / (nbVals-1) ) * (nbVals-1);
603 0 : break;
604 150 : case ANIM_VELOCITY:
605 150 : frac = do_bisection(frac, stack->a, stack->b, stack->c, stack->d);
606 150 : break;
607 : /*nothing to do for this one here*/
608 : case ANIM_DEFAULT:
609 : /*not supported - use frac as is*/
610 : case ANIM_PACED:
611 : default:
612 : break;
613 : }
614 : /*evaluate*/
615 150 : i = anurbs_find_span(&stack->anurbs, frac);
616 150 : anurbs_basis(&stack->anurbs, i, frac);
617 150 : pa->value_changed = anurbs_get_vec2f(&stack->anurbs, i, pa->keyValue.vals);
618 150 : break;
619 : /*not supported*/
620 : case ANIM_SPLINE:
621 : default:
622 : return;
623 : }
624 :
625 300 : pa->value_changed.x += pa->offset.x;
626 300 : pa->value_changed.y += pa->offset.y;
627 300 : gf_node_event_out(node, 12/*"value_changed"*/);
628 : }
629 :
630 298 : void PA2D_Modified(GF_Node *node, GF_FieldInfo *field)
631 : {
632 298 : AnimatorStack *stack = (AnimatorStack *)gf_node_get_private(node);
633 : M_PositionAnimator2D *pa = (M_PositionAnimator2D *)node;
634 :
635 298 : if ( /*all fields impacting cached path len / nurbs*/
636 298 : (field->far_ptr == &pa->keyValue)
637 298 : || (field->far_ptr == &pa->keyValueType)
638 298 : || (field->far_ptr == &pa->key)
639 298 : || (field->far_ptr == &pa->keyType)
640 298 : || (field->far_ptr == &pa->keySpline)
641 298 : || (field->far_ptr == &pa->weight)
642 : )
643 0 : stack->is_dirty = 1;
644 298 : }
645 2 : void PA2D_Init(GF_Node *n)
646 : {
647 : M_PositionAnimator2D *sa = (M_PositionAnimator2D *)n;
648 : AnimatorStack *stack;
649 2 : GF_SAFEALLOC(stack, AnimatorStack);
650 2 : if (!stack) {
651 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to allocate position animator 2D stack\n"));
652 : return;
653 : }
654 2 : stack->is_dirty = 1;
655 2 : gf_node_set_private(n, stack);
656 2 : gf_node_set_callback_function(n, Anim_Destroy);
657 2 : sa->on_set_fraction = PA2D_SetFraction;
658 : }
659 :
660 1 : static void SA_Update(M_ScalarAnimator *sa, AnimatorStack *stack)
661 : {
662 : u32 i;
663 : Fixed len;
664 1 : stack->is_dirty = 0;
665 1 : stack->anim_type = sa->keyType;
666 : /*if empty key and default anim switch to linear*/
667 1 : if (!sa->key.count && !stack->anim_type) stack->anim_type = ANIM_LINEAR;
668 :
669 1 : if (stack->anim_type == ANIM_PACED) {
670 0 : stack->length = 0;
671 0 : for (i=0; i<sa->keyValue.count-1; i++) {
672 0 : len = sa->keyValue.vals[i+1] - sa->keyValue.vals[i];
673 0 : stack->length += ABS(len);
674 : }
675 : }
676 1 : Animator_Update(stack, sa->keyValueType, sa->keyValue.count, &sa->keySpline, sa->weight.count, sa->weight.vals);
677 1 : }
678 :
679 150 : void SA_SetFraction(GF_Node *node, GF_Route *route)
680 : {
681 : Fixed frac;
682 : u32 nbKeys, nbVals, i;
683 : Fixed len, dlen, dist;
684 : M_ScalarAnimator *sa = (M_ScalarAnimator *)node;
685 150 : AnimatorStack *stack = (AnimatorStack *)gf_node_get_private(node);
686 :
687 150 : frac = sa->set_fraction;
688 : if (!anim_check_frac(frac, &sa->fromTo)) return;
689 :
690 150 : if (stack->is_dirty) SA_Update(sa, stack);
691 :
692 150 : nbKeys = sa->key.count;
693 150 : nbVals = sa->keyValue.count;
694 :
695 : i = 0;
696 150 : switch (sa->keyValueType) {
697 : /*linear interpolate*/
698 0 : case ANIM_LINE:
699 : /*compute frac & segment start index*/
700 0 : switch (stack->anim_type) {
701 0 : case ANIM_DEFAULT:
702 0 : if (nbKeys != nbVals) return;
703 0 : if (frac<sa->key.vals[0]) {
704 : i=0;
705 : frac = 0;
706 : }
707 0 : else if (frac>sa->key.vals[nbKeys-1]) {
708 0 : i=nbVals-2;
709 : frac=FIX_ONE;
710 : }
711 : else {
712 0 : for (i=0; i<nbKeys-1; i++) {
713 0 : if ((frac>=sa->key.vals[i]) && (frac<sa->key.vals[i+1])) break;
714 : }
715 0 : frac = GetInterpolateFraction(sa->key.vals[i], sa->key.vals[i+1], frac);
716 : }
717 : break;
718 0 : case ANIM_DISCRETE:
719 0 : i = FIX2INT(gf_floor(frac*nbVals));
720 : frac = 0;
721 0 : break;
722 0 : case ANIM_LINEAR:
723 0 : i = FIX2INT(gf_floor(frac*(nbVals-1)));
724 0 : frac = (frac - INT2FIX(i)/ (nbVals-1) ) * (nbVals-1);
725 0 : break;
726 0 : case ANIM_PACED:
727 : /*at cst speed, this is the length done*/
728 0 : dist = gf_mulfix(frac, stack->length);
729 : /*then figure out in which seg we are*/
730 : len = 0;
731 : dlen = 0;
732 0 : for (i=0; i<nbVals-1; i++) {
733 0 : dlen = sa->keyValue.vals[i+1] - sa->keyValue.vals[i];
734 0 : if (dlen<0) dlen *= -1;
735 0 : if (len+dlen>dist) break;
736 : len += dlen;
737 : }
738 : /*that's our fraction inside the seg*/
739 0 : frac = gf_divfix(dist-len, dlen);
740 : break;
741 0 : case ANIM_SPLINE:
742 0 : frac = do_bisection(frac, stack->a, stack->b, stack->c, stack->d);
743 0 : i = FIX2INT(gf_floor(frac*(nbVals-1)));
744 0 : frac = (frac - INT2FIX(i) / (nbVals-1) ) * (nbVals-1);
745 0 : break;
746 : }
747 : /*interpolate*/
748 0 : sa->value_changed = Interpolate(sa->keyValue.vals[i], sa->keyValue.vals[i+1], frac);
749 0 : break;
750 : /*bezier interpolate*/
751 150 : case ANIM_QUADRATIC:
752 : case ANIM_CUBIC:
753 : case ANIM_NURBS:
754 150 : if (!stack->anurbs.valid) return;
755 : /*compute frac*/
756 150 : switch (stack->anim_type) {
757 0 : case ANIM_DISCRETE:
758 0 : i = FIX2INT(gf_floor(frac*nbVals));
759 0 : frac = INT2FIX(i) / nbVals;
760 0 : break;
761 150 : case ANIM_LINEAR:
762 150 : i = FIX2INT(gf_floor(frac*(nbVals-1)));
763 150 : frac = (frac - INT2FIX(i) / (nbVals-1) ) * (nbVals-1);
764 150 : break;
765 0 : case ANIM_VELOCITY:
766 0 : frac = do_bisection(frac, stack->a, stack->b, stack->c, stack->d);
767 0 : break;
768 : /*nothing to do for this one here*/
769 : case ANIM_DEFAULT:
770 : /*not supported - use frac as is*/
771 : case ANIM_PACED:
772 : default:
773 : break;
774 : }
775 : /*evaluate nurbs*/
776 150 : i = anurbs_find_span(&stack->anurbs, frac);
777 150 : anurbs_basis(&stack->anurbs, i, frac);
778 150 : sa->value_changed = anurbs_get_float(&stack->anurbs, i, sa->keyValue.vals);
779 150 : break;
780 : /*not supported*/
781 : case ANIM_SPLINE:
782 : default:
783 : return;
784 : }
785 :
786 150 : sa->value_changed += sa->offset;
787 150 : gf_node_event_out(node, 10/*"value_changed"*/);
788 : }
789 :
790 149 : void SA_Modified(GF_Node *node, GF_FieldInfo *field)
791 : {
792 149 : AnimatorStack *stack = (AnimatorStack *)gf_node_get_private(node);
793 : M_ScalarAnimator *sa = (M_ScalarAnimator *)node;
794 :
795 149 : if ( /*all fields impacting cached path len / nurbs*/
796 149 : (field->far_ptr == &sa->keyValue)
797 149 : || (field->far_ptr == &sa->keyValueType)
798 149 : || (field->far_ptr == &sa->key)
799 149 : || (field->far_ptr == &sa->keyType)
800 149 : || (field->far_ptr == &sa->keySpline)
801 149 : || (field->far_ptr == &sa->weight)
802 : )
803 0 : stack->is_dirty = 1;
804 149 : }
805 :
806 1 : void SA_Init(GF_Node *n)
807 : {
808 : M_ScalarAnimator *sa = (M_ScalarAnimator *)n;
809 : AnimatorStack *stack;
810 1 : GF_SAFEALLOC(stack, AnimatorStack);
811 1 : if (!stack) {
812 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to allocate scalar animator stack\n"));
813 : return;
814 : }
815 1 : stack->is_dirty = 1;
816 1 : gf_node_set_private(n, stack);
817 1 : gf_node_set_callback_function(n, Anim_Destroy);
818 1 : sa->on_set_fraction = SA_SetFraction;
819 : }
820 :
821 :
822 : #endif /*GPAC_DISABLE_VRML*/
|