LCOV - code coverage report
Current view: top level - scenegraph - mpeg4_animators.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 254 415 61.2 %
Date: 2021-04-29 23:48:07 Functions: 22 22 100.0 %

          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*/

Generated by: LCOV version 1.13