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
Interpolate(Fixed keyValue1,Fixed keyValue2,Fixed fraction)34 static Fixed Interpolate(Fixed keyValue1, Fixed keyValue2, Fixed fraction)
35 {
36 return gf_mulfix(keyValue2 - keyValue1, fraction) + keyValue1;
37 }
38
GetInterpolateFraction(Fixed key1,Fixed key2,Fixed fraction)39 static Fixed GetInterpolateFraction(Fixed key1, Fixed key2, Fixed fraction)
40 {
41 Fixed keyDiff = key2 - key1;
42 assert((fraction >= key1) && (fraction <= key2));
43 if (ABS(keyDiff) < FIX_EPSILON) return 0;
44 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 */
do_bisection(Fixed t,SFVec2f a,SFVec2f b,SFVec2f c,SFVec2f d)69 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 usearch = (left+right)/2;
78 tsearch = gf_mulfix(usearch, c.x + gf_mulfix(usearch, b.x + gf_mulfix(usearch, a.x))) + d.x;
79 if (t < tsearch + limit) right = usearch;
80 else left = usearch;
81 } while ((t > tsearch + limit) || (t<tsearch - limit));
82 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
anurbs_reset(anim_nurbs * nurbs)99 static void anurbs_reset(anim_nurbs *nurbs)
100 {
101 if (nurbs->n) gf_free(nurbs->n);
102 if (nurbs->left) gf_free(nurbs->left);
103 if (nurbs->right) gf_free(nurbs->right);
104 nurbs->n = nurbs->left = nurbs->right = NULL;
105 }
106
anurbs_init(anim_nurbs * nurbs,u32 type,u32 nCtrl,u32 nKnots,Fixed * knots,u32 nWeight,Fixed * weights)107 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 nurbs->type = type;
111 switch (type) {
112 case ANIM_CUBIC:
113 nurbs->npoints = 4;
114 nurbs->nknots = 8;
115 nurbs->knots = cubic_knots;
116 break;
117 case ANIM_QUADRATIC:
118 nurbs->npoints = 3;
119 nurbs->nknots = 6;
120 nurbs->knots = quadratic_knots;
121 break;
122 default:
123 nurbs->npoints = nCtrl;
124 nurbs->knots = knots;
125 nurbs->nknots = nKnots;
126 nurbs->weights = weights;
127 nurbs->nweights = nWeight;
128 break;
129 }
130 nurbs->p = nurbs->nknots - nurbs->npoints - 1;
131 if ((nurbs->p<=0) || (nurbs->p >= nurbs->nknots -1)
132 || ((nurbs->nweights>0) && (nurbs->npoints != nurbs->nweights)) ) {
133 nurbs->valid = 0;
134 } else {
135 nurbs->valid = 1;
136 }
137 }
138
anurbs_basis(anim_nurbs * nurbs,s32 span,Fixed t)139 static void anurbs_basis(anim_nurbs *nurbs, s32 span, Fixed t)
140 {
141 u32 i, j;
142 Fixed saved, temp;
143 if (!nurbs->n) {
144 nurbs->n = (Fixed*)gf_malloc(sizeof(Fixed) * (nurbs->p+1));
145 nurbs->left = (Fixed*)gf_malloc(sizeof(Fixed) * (nurbs->p+1));
146 nurbs->right = (Fixed*)gf_malloc(sizeof(Fixed) * (nurbs->p+1));
147 }
148 nurbs->n[0] = FIX_ONE;
149
150 for(i=1; i<=nurbs->p; i++) {
151 nurbs->left[i] = t - nurbs->knots[span+1-i];
152 nurbs->right[i] = nurbs->knots[span+i]-t;
153 saved = 0;
154
155 for(j=0; j<i; j++) {
156 temp = gf_divfix(nurbs->n[j], nurbs->right[j+1] + nurbs->left[i-j]);
157 nurbs->n[j] = saved + gf_mulfix(nurbs->right[j+1], temp);
158 saved = gf_mulfix(nurbs->left[i-j], temp);
159 }
160 nurbs->n[i]=saved;
161 }
162 }
163
anurbs_find_span(anim_nurbs * nurbs,Fixed u)164 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 if (u == nurbs->knots[nurbs->npoints]) return nurbs->npoints - 1;
177 low = nurbs->p;
178 high = nurbs->npoints;
179 mid = (low + high)/2;
180
181 while (u < nurbs->knots[mid] || u >= nurbs->knots[mid+1]) {
182 if (u < nurbs->knots[mid]) high = mid;
183 else low = mid;
184 mid = (low + high)/2;
185 }
186 return (mid);
187
188 #endif
189 }
190
anurbs_get_vec3f(anim_nurbs * nurbs,s32 span,SFVec3f * pts)191 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 for(i=0; i<=nurbs->p; i++) {
200 tmp = pts[span - nurbs->p + i];
201 if (nurbs->nweights>0) {
202 wi = nurbs->weights[span - nurbs->p + i];
203 tmp = gf_vec_scale(tmp, wi);
204 w += gf_mulfix(nurbs->n[i], wi);
205 }
206 res.x += gf_mulfix(nurbs->n[i], tmp.x);
207 res.y += gf_mulfix(nurbs->n[i], tmp.y);
208 res.z += gf_mulfix(nurbs->n[i], tmp.z);
209 }
210 if (nurbs->nweights>0) {
211 if (w) {
212 w = gf_invfix(w);
213 res = gf_vec_scale(res, w);
214 }
215 }
216 return res;
217 }
218
anurbs_get_vec2f(anim_nurbs * nurbs,s32 span,SFVec2f * pts)219 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 for(i=0; i<=nurbs->p; i++) {
228 tmp = pts[span - nurbs->p + i];
229 if (nurbs->nweights>0) {
230 wi = nurbs->weights[span - nurbs->p + i];
231 tmp.x = gf_mulfix(tmp.x, wi);
232 tmp.y = gf_mulfix(tmp.y, wi);
233 w += gf_mulfix(nurbs->n[i], wi);
234 }
235 res.x += gf_mulfix(nurbs->n[i], tmp.x);
236 res.y += gf_mulfix(nurbs->n[i], tmp.y);
237 }
238 if (nurbs->nweights>0) {
239 if (w) {
240 w = gf_invfix(w);
241 res.x = gf_mulfix(res.x, w);
242 res.y = gf_mulfix(res.y, w);
243 }
244 }
245 return res;
246 }
247
anurbs_get_float(anim_nurbs * nurbs,s32 span,Fixed * vals)248 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 for(i=0; i<=nurbs->p; i++) {
256 Fixed tmp = vals[span - nurbs->p + i];
257 if (nurbs->nweights>0) {
258 wi = nurbs->weights[span - nurbs->p + i];
259 tmp = gf_mulfix(tmp, wi);
260 w += gf_mulfix(nurbs->n[i], wi);
261 }
262 res += gf_mulfix(nurbs->n[i], tmp);
263 }
264 if (nurbs->nweights>0) res = gf_divfix(res, w);
265 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
Anim_Destroy(GF_Node * node,void * rs,Bool is_destroy)280 static void Anim_Destroy(GF_Node *node, void *rs, Bool is_destroy)
281 {
282 if (is_destroy) {
283 AnimatorStack *stack = (AnimatorStack *)gf_node_get_private(node);
284 anurbs_reset(&stack->anurbs);
285 gf_free(stack);
286 }
287 }
288
Animator_Update(AnimatorStack * stack,u32 keyValueType,u32 nCtrl,MFVec2f * keySpline,u32 nWeight,Fixed * weights)289 static void Animator_Update(AnimatorStack *stack, u32 keyValueType, u32 nCtrl, MFVec2f *keySpline, u32 nWeight, Fixed *weights)
290 {
291 if (stack->anim_type==ANIM_SPLINE) {
292 stack->a.x = (keySpline->vals[0].x - keySpline->vals[1].x)*3 + FIX_ONE;
293 stack->a.y = (keySpline->vals[0].y - keySpline->vals[1].y)*3 + FIX_ONE;
294 stack->b.x = (keySpline->vals[1].x - 2*keySpline->vals[0].x)*3;
295 stack->b.y = (keySpline->vals[1].y - 2*keySpline->vals[0].y)*3;
296 stack->c.x = keySpline->vals[0].x*3;
297 stack->c.y = keySpline->vals[0].y*3;
298 stack->d.x = stack->d.y = 0;
299 }
300 anurbs_reset(&stack->anurbs);
301 switch (keyValueType) {
302 case ANIM_CUBIC:
303 anurbs_init(&stack->anurbs, ANIM_CUBIC, 0, 0, NULL, 0, NULL);
304 break;
305 case ANIM_QUADRATIC:
306 anurbs_init(&stack->anurbs, ANIM_QUADRATIC, 0, 0, NULL, 0, NULL);
307 break;
308 case ANIM_NURBS:
309 anurbs_init(&stack->anurbs, ANIM_NURBS, nCtrl, keySpline->count, (Fixed *) &keySpline->vals[0].x, nWeight, weights);
310 break;
311 }
312 }
313
314
anim_check_frac(Fixed frac,SFVec2f * fromTo)315 static Bool anim_check_frac(Fixed frac, SFVec2f *fromTo)
316 {
317 if (frac<0) return 0;
318 if (frac>FIX_ONE) return 0;
319 if (fromTo->x > fromTo->y) return 0;
320 /*not active*/
321 if (frac<fromTo->x) return 0;
322 if (frac>fromTo->y) return 0;
323 return 1;
324 }
325
PA_Update(M_PositionAnimator * pa,AnimatorStack * stack)326 static void PA_Update(M_PositionAnimator *pa, AnimatorStack *stack)
327 {
328 u32 i;
329 GF_Vec d;
330 stack->is_dirty = 0;
331 stack->anim_type = pa->keyType;
332 /*if empty key and default anim switch to linear*/
333 if (!pa->key.count && !stack->anim_type) stack->anim_type = ANIM_LINEAR;
334
335 if (stack->anim_type == ANIM_PACED) {
336 stack->length = 0;
337 for (i=0; i<pa->keyValue.count-1; i++) {
338 d.x = pa->keyValue.vals[i+1].x - pa->keyValue.vals[i].x;
339 d.y = pa->keyValue.vals[i+1].y - pa->keyValue.vals[i].y;
340 d.z = pa->keyValue.vals[i+1].z - pa->keyValue.vals[i].z;
341 stack->length += gf_vec_len(d);
342 }
343 }
344 Animator_Update(stack, pa->keyValueType, pa->keyValue.count, &pa->keySpline, pa->weight.count, pa->weight.vals);
345 }
PA_SetFraction(GF_Node * node,GF_Route * route)346 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 AnimatorStack *stack = (AnimatorStack *)gf_node_get_private(node);
354
355 frac = pa->set_fraction;
356 if (!anim_check_frac(frac, &pa->fromTo)) return;
357
358 if (stack->is_dirty) PA_Update(pa, stack);
359
360 nbKeys = pa->key.count;
361 nbVals = pa->keyValue.count;
362
363 switch (pa->keyValueType) {
364 /*linear interpolate*/
365 case ANIM_LINE:
366 /*compute frac and segment start index*/
367 switch (stack->anim_type) {
368 case ANIM_DEFAULT:
369 if (nbKeys != nbVals) return;
370 if (frac<pa->key.vals[0]) {
371 i=0;
372 frac = 0;
373 }
374 else if (frac>pa->key.vals[nbKeys-1]) {
375 i=nbVals-2;
376 frac = FIX_ONE;
377 }
378 else {
379 for (i=0; i<nbKeys-1; i++) {
380 if ((frac>=pa->key.vals[i]) && (frac<pa->key.vals[i+1])) break;
381 }
382 frac = GetInterpolateFraction(pa->key.vals[i], pa->key.vals[i+1], frac);
383 }
384 break;
385 case ANIM_DISCRETE:
386 i = FIX2INT(gf_floor(frac*nbVals));
387 frac = 0;
388 break;
389 case ANIM_LINEAR:
390 i = FIX2INT(gf_floor(frac*(nbVals-1)));
391 frac = (frac - INT2FIX(i) / (nbVals-1) ) * (nbVals-1);
392 break;
393 case ANIM_PACED:
394 /*at cst speed, this is the length done*/
395 dist = gf_mulfix(frac, stack->length);
396 /*then figure out in which seg we are*/
397 len = 0;
398 dlen = 0;
399 for (i=0; i<nbVals-1; i++) {
400 d.x = pa->keyValue.vals[i+1].x - pa->keyValue.vals[i].x;
401 d.y = pa->keyValue.vals[i+1].y - pa->keyValue.vals[i].y;
402 d.z = pa->keyValue.vals[i+1].z - pa->keyValue.vals[i].z;
403 dlen = gf_vec_len(d);
404 if (len+dlen>dist) break;
405 len += dlen;
406 }
407 /*that's our fraction inside the seg*/
408 frac = gf_divfix(dist-len, dlen);
409 break;
410 case ANIM_SPLINE:
411 frac = do_bisection(frac, stack->a, stack->b, stack->c, stack->d);
412 i = FIX2INT(gf_floor(frac*(nbVals-1)));
413 frac = (frac - INT2FIX(i) / (nbVals-1) ) * (nbVals-1);
414 break;
415 default:
416 return;
417 }
418 /*interpolate*/
419 pa->value_changed.x = Interpolate(pa->keyValue.vals[i].x, pa->keyValue.vals[i+1].x, frac);
420 pa->value_changed.y = Interpolate(pa->keyValue.vals[i].y, pa->keyValue.vals[i+1].y, frac);
421 pa->value_changed.z = Interpolate(pa->keyValue.vals[i].z, pa->keyValue.vals[i+1].z, frac);
422 break;
423 /*bezier interpolate*/
424 case ANIM_QUADRATIC:
425 case ANIM_CUBIC:
426 case ANIM_NURBS:
427 if (!stack->anurbs.valid) return;
428 /*compute frac*/
429 switch (stack->anim_type) {
430 case ANIM_DISCRETE:
431 i = FIX2INT(gf_floor(frac*nbVals));
432 frac = INT2FIX(i) / nbVals;
433 break;
434 case ANIM_LINEAR:
435 i = FIX2INT(gf_floor(frac*(nbVals-1)));
436 frac = (frac - INT2FIX(i) / (nbVals-1) ) * (nbVals-1);
437 break;
438 case ANIM_VELOCITY:
439 frac = do_bisection(frac, stack->a, stack->b, stack->c, stack->d);
440 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 i = anurbs_find_span(&stack->anurbs, frac);
450 anurbs_basis(&stack->anurbs, i, frac);
451 pa->value_changed = anurbs_get_vec3f(&stack->anurbs, i, pa->keyValue.vals);
452 break;
453 /*not supported*/
454 case ANIM_SPLINE:
455 default:
456 return;
457 }
458
459 pa->value_changed.x += pa->offset.x;
460 pa->value_changed.y += pa->offset.y;
461 pa->value_changed.z += pa->offset.z;
462 gf_node_event_out(node, 12/*"value_changed"*/);
463 }
464
PA_Modified(GF_Node * node,GF_FieldInfo * field)465 void PA_Modified(GF_Node *node, GF_FieldInfo *field)
466 {
467 AnimatorStack *stack = (AnimatorStack *)gf_node_get_private(node);
468 M_PositionAnimator *pa = (M_PositionAnimator *)node;
469
470 if ( /*all fields impacting cached path len / nurbs*/
471 (field->far_ptr == &pa->keyValue)
472 || (field->far_ptr == &pa->keyValueType)
473 || (field->far_ptr == &pa->key)
474 || (field->far_ptr == &pa->keyType)
475 || (field->far_ptr == &pa->keySpline)
476 || (field->far_ptr == &pa->weight)
477 )
478 stack->is_dirty = 1;
479 }
PA_Init(GF_Node * n)480 void PA_Init(GF_Node *n)
481 {
482 M_PositionAnimator *sa = (M_PositionAnimator*)n;
483 AnimatorStack *stack;
484 GF_SAFEALLOC(stack, AnimatorStack);
485 if (!stack) {
486 GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to allocate position animator stack\n"));
487 return;
488 }
489 stack->is_dirty = 1;
490 gf_node_set_private(n, stack);
491 gf_node_set_callback_function(n, Anim_Destroy);
492 sa->on_set_fraction = PA_SetFraction;
493 }
494
PA2D_Update(M_PositionAnimator2D * pa,AnimatorStack * stack)495 static void PA2D_Update(M_PositionAnimator2D *pa, AnimatorStack *stack)
496 {
497 u32 i;
498 Fixed dx, dy;
499 stack->is_dirty = 0;
500 stack->anim_type = pa->keyType;
501 /*if empty key and default anim switch to linear*/
502 if (!pa->key.count && !stack->anim_type) stack->anim_type = ANIM_LINEAR;
503
504 if (stack->anim_type == ANIM_PACED) {
505 stack->length = 0;
506 for (i=0; i<pa->keyValue.count-1; i++) {
507 dx = pa->keyValue.vals[i+1].x - pa->keyValue.vals[i].x;
508 dy = pa->keyValue.vals[i+1].y - pa->keyValue.vals[i].y;
509 stack->length += gf_sqrt(gf_mulfix(dx, dx) + gf_mulfix(dy, dy));
510 }
511 }
512 Animator_Update(stack, pa->keyValueType, pa->keyValue.count, &pa->keySpline, pa->weight.count, pa->weight.vals);
513 }
PA2D_SetFraction(GF_Node * node,GF_Route * route)514 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 AnimatorStack *stack = (AnimatorStack *)gf_node_get_private(node);
522
523 frac = pa->set_fraction;
524 if (!anim_check_frac(frac, &pa->fromTo)) return;
525
526 if (stack->is_dirty) PA2D_Update(pa, stack);
527
528 nbKeys = pa->key.count;
529 nbVals = pa->keyValue.count;
530
531 switch (pa->keyValueType) {
532 /*linear interpolate*/
533 case ANIM_LINE:
534 /*compute frac and segment start index*/
535 switch (stack->anim_type) {
536 case ANIM_DEFAULT:
537 if (nbKeys != nbVals) return;
538 if (frac<=pa->key.vals[0]) {
539 i=0;
540 frac = 0;
541 }
542 else if (frac>=pa->key.vals[nbKeys-1]) {
543 i=nbVals-2;
544 frac=FIX_ONE;
545 }
546 else {
547 for (i=0; i<nbKeys-1; i++) {
548 if ((frac>=pa->key.vals[i]) && (frac<pa->key.vals[i+1])) break;
549 }
550 frac = GetInterpolateFraction(pa->key.vals[i], pa->key.vals[i+1], frac);
551 }
552 break;
553 case ANIM_DISCRETE:
554 i = FIX2INT(gf_floor(frac*nbVals));
555 frac = 0;
556 break;
557 case ANIM_LINEAR:
558 i = FIX2INT(gf_floor(frac*(nbVals-1)));
559 frac = (frac - INT2FIX(i)/ (nbVals-1) ) * (nbVals-1);
560 break;
561 case ANIM_PACED:
562 /*at cst speed, this is the length done*/
563 dist = gf_mulfix(frac, stack->length);
564 /*then figure out in which seg we are*/
565 len = 0;
566 dlen = 0;
567 for (i=0; i<nbVals-1; i++) {
568 dx = pa->keyValue.vals[i+1].x - pa->keyValue.vals[i].x;
569 dy = pa->keyValue.vals[i+1].y - pa->keyValue.vals[i].y;
570 dlen = gf_sqrt(gf_mulfix(dx,dx) + gf_mulfix(dy,dy));
571 if (len+dlen>dist) break;
572 len += dlen;
573 }
574 /*that's our fraction inside the seg*/
575 frac = gf_divfix(dist-len, dlen);
576 break;
577 case ANIM_SPLINE:
578 frac = do_bisection(frac, stack->a, stack->b, stack->c, stack->d);
579 i = FIX2INT(gf_floor(frac * (nbVals-1)));
580 frac = (frac - INT2FIX(i) / (nbVals-1) ) * (nbVals-1);
581 break;
582 default:
583 return;
584 }
585 /*interpolate*/
586 pa->value_changed.x = Interpolate(pa->keyValue.vals[i].x, pa->keyValue.vals[i+1].x, frac);
587 pa->value_changed.y = Interpolate(pa->keyValue.vals[i].y, pa->keyValue.vals[i+1].y, frac);
588 break;
589 /*bezier interpolate*/
590 case ANIM_QUADRATIC:
591 case ANIM_CUBIC:
592 case ANIM_NURBS:
593 if (!stack->anurbs.valid) return;
594 /*compute frac*/
595 switch (stack->anim_type) {
596 case ANIM_DISCRETE:
597 i = FIX2INT(gf_floor(frac*nbVals));
598 frac = INT2FIX(i) / nbVals;
599 break;
600 case ANIM_LINEAR:
601 i = FIX2INT(gf_floor(frac*(nbVals-1)));
602 frac = (frac - INT2FIX(i) / (nbVals-1) ) * (nbVals-1);
603 break;
604 case ANIM_VELOCITY:
605 frac = do_bisection(frac, stack->a, stack->b, stack->c, stack->d);
606 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 i = anurbs_find_span(&stack->anurbs, frac);
616 anurbs_basis(&stack->anurbs, i, frac);
617 pa->value_changed = anurbs_get_vec2f(&stack->anurbs, i, pa->keyValue.vals);
618 break;
619 /*not supported*/
620 case ANIM_SPLINE:
621 default:
622 return;
623 }
624
625 pa->value_changed.x += pa->offset.x;
626 pa->value_changed.y += pa->offset.y;
627 gf_node_event_out(node, 12/*"value_changed"*/);
628 }
629
PA2D_Modified(GF_Node * node,GF_FieldInfo * field)630 void PA2D_Modified(GF_Node *node, GF_FieldInfo *field)
631 {
632 AnimatorStack *stack = (AnimatorStack *)gf_node_get_private(node);
633 M_PositionAnimator2D *pa = (M_PositionAnimator2D *)node;
634
635 if ( /*all fields impacting cached path len / nurbs*/
636 (field->far_ptr == &pa->keyValue)
637 || (field->far_ptr == &pa->keyValueType)
638 || (field->far_ptr == &pa->key)
639 || (field->far_ptr == &pa->keyType)
640 || (field->far_ptr == &pa->keySpline)
641 || (field->far_ptr == &pa->weight)
642 )
643 stack->is_dirty = 1;
644 }
PA2D_Init(GF_Node * n)645 void PA2D_Init(GF_Node *n)
646 {
647 M_PositionAnimator2D *sa = (M_PositionAnimator2D *)n;
648 AnimatorStack *stack;
649 GF_SAFEALLOC(stack, AnimatorStack);
650 if (!stack) {
651 GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to allocate position animator 2D stack\n"));
652 return;
653 }
654 stack->is_dirty = 1;
655 gf_node_set_private(n, stack);
656 gf_node_set_callback_function(n, Anim_Destroy);
657 sa->on_set_fraction = PA2D_SetFraction;
658 }
659
SA_Update(M_ScalarAnimator * sa,AnimatorStack * stack)660 static void SA_Update(M_ScalarAnimator *sa, AnimatorStack *stack)
661 {
662 u32 i;
663 Fixed len;
664 stack->is_dirty = 0;
665 stack->anim_type = sa->keyType;
666 /*if empty key and default anim switch to linear*/
667 if (!sa->key.count && !stack->anim_type) stack->anim_type = ANIM_LINEAR;
668
669 if (stack->anim_type == ANIM_PACED) {
670 stack->length = 0;
671 for (i=0; i<sa->keyValue.count-1; i++) {
672 len = sa->keyValue.vals[i+1] - sa->keyValue.vals[i];
673 stack->length += ABS(len);
674 }
675 }
676 Animator_Update(stack, sa->keyValueType, sa->keyValue.count, &sa->keySpline, sa->weight.count, sa->weight.vals);
677 }
678
SA_SetFraction(GF_Node * node,GF_Route * route)679 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 AnimatorStack *stack = (AnimatorStack *)gf_node_get_private(node);
686
687 frac = sa->set_fraction;
688 if (!anim_check_frac(frac, &sa->fromTo)) return;
689
690 if (stack->is_dirty) SA_Update(sa, stack);
691
692 nbKeys = sa->key.count;
693 nbVals = sa->keyValue.count;
694
695 i = 0;
696 switch (sa->keyValueType) {
697 /*linear interpolate*/
698 case ANIM_LINE:
699 /*compute frac & segment start index*/
700 switch (stack->anim_type) {
701 case ANIM_DEFAULT:
702 if (nbKeys != nbVals) return;
703 if (frac<sa->key.vals[0]) {
704 i=0;
705 frac = 0;
706 }
707 else if (frac>sa->key.vals[nbKeys-1]) {
708 i=nbVals-2;
709 frac=FIX_ONE;
710 }
711 else {
712 for (i=0; i<nbKeys-1; i++) {
713 if ((frac>=sa->key.vals[i]) && (frac<sa->key.vals[i+1])) break;
714 }
715 frac = GetInterpolateFraction(sa->key.vals[i], sa->key.vals[i+1], frac);
716 }
717 break;
718 case ANIM_DISCRETE:
719 i = FIX2INT(gf_floor(frac*nbVals));
720 frac = 0;
721 break;
722 case ANIM_LINEAR:
723 i = FIX2INT(gf_floor(frac*(nbVals-1)));
724 frac = (frac - INT2FIX(i)/ (nbVals-1) ) * (nbVals-1);
725 break;
726 case ANIM_PACED:
727 /*at cst speed, this is the length done*/
728 dist = gf_mulfix(frac, stack->length);
729 /*then figure out in which seg we are*/
730 len = 0;
731 dlen = 0;
732 for (i=0; i<nbVals-1; i++) {
733 dlen = sa->keyValue.vals[i+1] - sa->keyValue.vals[i];
734 if (dlen<0) dlen *= -1;
735 if (len+dlen>dist) break;
736 len += dlen;
737 }
738 /*that's our fraction inside the seg*/
739 frac = gf_divfix(dist-len, dlen);
740 break;
741 case ANIM_SPLINE:
742 frac = do_bisection(frac, stack->a, stack->b, stack->c, stack->d);
743 i = FIX2INT(gf_floor(frac*(nbVals-1)));
744 frac = (frac - INT2FIX(i) / (nbVals-1) ) * (nbVals-1);
745 break;
746 }
747 /*interpolate*/
748 sa->value_changed = Interpolate(sa->keyValue.vals[i], sa->keyValue.vals[i+1], frac);
749 break;
750 /*bezier interpolate*/
751 case ANIM_QUADRATIC:
752 case ANIM_CUBIC:
753 case ANIM_NURBS:
754 if (!stack->anurbs.valid) return;
755 /*compute frac*/
756 switch (stack->anim_type) {
757 case ANIM_DISCRETE:
758 i = FIX2INT(gf_floor(frac*nbVals));
759 frac = INT2FIX(i) / nbVals;
760 break;
761 case ANIM_LINEAR:
762 i = FIX2INT(gf_floor(frac*(nbVals-1)));
763 frac = (frac - INT2FIX(i) / (nbVals-1) ) * (nbVals-1);
764 break;
765 case ANIM_VELOCITY:
766 frac = do_bisection(frac, stack->a, stack->b, stack->c, stack->d);
767 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 i = anurbs_find_span(&stack->anurbs, frac);
777 anurbs_basis(&stack->anurbs, i, frac);
778 sa->value_changed = anurbs_get_float(&stack->anurbs, i, sa->keyValue.vals);
779 break;
780 /*not supported*/
781 case ANIM_SPLINE:
782 default:
783 return;
784 }
785
786 sa->value_changed += sa->offset;
787 gf_node_event_out(node, 10/*"value_changed"*/);
788 }
789
SA_Modified(GF_Node * node,GF_FieldInfo * field)790 void SA_Modified(GF_Node *node, GF_FieldInfo *field)
791 {
792 AnimatorStack *stack = (AnimatorStack *)gf_node_get_private(node);
793 M_ScalarAnimator *sa = (M_ScalarAnimator *)node;
794
795 if ( /*all fields impacting cached path len / nurbs*/
796 (field->far_ptr == &sa->keyValue)
797 || (field->far_ptr == &sa->keyValueType)
798 || (field->far_ptr == &sa->key)
799 || (field->far_ptr == &sa->keyType)
800 || (field->far_ptr == &sa->keySpline)
801 || (field->far_ptr == &sa->weight)
802 )
803 stack->is_dirty = 1;
804 }
805
SA_Init(GF_Node * n)806 void SA_Init(GF_Node *n)
807 {
808 M_ScalarAnimator *sa = (M_ScalarAnimator *)n;
809 AnimatorStack *stack;
810 GF_SAFEALLOC(stack, AnimatorStack);
811 if (!stack) {
812 GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to allocate scalar animator stack\n"));
813 return;
814 }
815 stack->is_dirty = 1;
816 gf_node_set_private(n, stack);
817 gf_node_set_callback_function(n, Anim_Destroy);
818 sa->on_set_fraction = SA_SetFraction;
819 }
820
821
822 #endif /*GPAC_DISABLE_VRML*/
823