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