📄 mpeg4_animators.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / Scene Graph sub-project * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <gpac/internal/scenegraph_dev.h>/*MPEG4 tags (for internal nodes)*/#include <gpac/nodes_mpeg4.h>/*from interpolators.c*/Fixed GetInterpolateFraction(Fixed key1, Fixed key2, Fixed fraction);Fixed Interpolate(Fixed keyValue1, Fixed keyValue2, Fixed fraction);enum{ ANIM_LINE, ANIM_QUADRATIC, ANIM_CUBIC, ANIM_NURBS, /*NOT SUPPORTED*/ ANIM_SPLINE};enum{ ANIM_DEFAULT, ANIM_DISCRETE, ANIM_LINEAR, /*NOT SUPPORTED ON SPLINES*/ ANIM_PACED, ANIM_VELOCITY};/* Bisection algorithm to find u=a*t^3+b*t^2+c*t+d */Fixed do_bisection(Fixed t, SFVec2f a, SFVec2f b, SFVec2f c, SFVec2f d){ Fixed left, right, usearch, tsearch, limit; left = 0; right = FIX_ONE; limit = FIX_ONE/1000; do { usearch = (left+right)/2; tsearch = gf_mulfix(usearch, c.x + gf_mulfix(usearch, b.x + gf_mulfix(usearch, a.x))) + d.x; if (t < tsearch + limit) right = usearch; else left = usearch; } while ((t > tsearch + limit) || (t<tsearch - limit)); return gf_mulfix(usearch, c.y + gf_mulfix(usearch, b.y + gf_mulfix(usearch , a.y))) + d.y;}typedef struct{ Fixed *knots, *weights, *n, *left, *right; u32 nknots, nweights, npoints; u32 p; u32 type; Bool valid;} anim_nurbs;static Fixed cubic_knots[] = {0,0,0,0,FIX_ONE,FIX_ONE,FIX_ONE,FIX_ONE};static Fixed quadratic_knots[] = {0,0,0,FIX_ONE,FIX_ONE,FIX_ONE};static void anurbs_reset(anim_nurbs *nurbs){ if (nurbs->n) free(nurbs->n); if (nurbs->left) free(nurbs->left); if (nurbs->right) free(nurbs->right); nurbs->n = nurbs->left = nurbs->right = NULL;}static void anurbs_init(anim_nurbs *nurbs, u32 type, u32 nCtrl, u32 nKnots, Fixed *knots, u32 nWeight, Fixed *weights){ memset(nurbs, 0, sizeof(anim_nurbs)); nurbs->type = type; switch (type) { case ANIM_CUBIC: nurbs->npoints = 4; nurbs->nknots = 8; nurbs->knots = cubic_knots; break; case ANIM_QUADRATIC: nurbs->npoints = 3; nurbs->nknots = 6; nurbs->knots = quadratic_knots; break; default: nurbs->npoints = nCtrl; nurbs->knots = knots; nurbs->nknots = nKnots; nurbs->weights = weights; nurbs->nweights = nWeight; break; } nurbs->p = nurbs->nknots - nurbs->npoints - 1; if ((nurbs->p<=0) || (nurbs->p >= nurbs->nknots -1) || ((nurbs->nweights>0) && (nurbs->npoints != nurbs->nweights)) ) { nurbs->valid = 0; } else { nurbs->valid = 1; }}static void anurbs_basis(anim_nurbs *nurbs, s32 span, Fixed t){ u32 i, j; Fixed saved, temp; if (!nurbs->n) { nurbs->n = (Fixed*)malloc(sizeof(Fixed) * (nurbs->p+1)); nurbs->left = (Fixed*)malloc(sizeof(Fixed) * (nurbs->p+1)); nurbs->right = (Fixed*)malloc(sizeof(Fixed) * (nurbs->p+1)); } nurbs->n[0] = FIX_ONE; for(i=1; i<=nurbs->p; i++) { nurbs->left[i] = t - nurbs->knots[span+1-i]; nurbs->right[i] = nurbs->knots[span+i]-t; saved = 0; for(j=0; j<i; j++) { temp = gf_divfix(nurbs->n[j], nurbs->right[j+1] + nurbs->left[i-j]); nurbs->n[j] = saved + gf_mulfix(nurbs->right[j+1], temp); saved = gf_mulfix(nurbs->left[i-j], temp); } nurbs->n[i]=saved; }}static s32 anurbs_find_span(anim_nurbs *nurbs, Fixed u){#if 0 s32 span; if (u == nurbs->knots[nurbs->npoints]) return nurbs->npoints - 1; for (span = (s32) nurbs->p; span < (s32) nurbs->nknots - (s32) nurbs->p; span++) { if (u<nurbs->knots[span]) break; } span--; return span;#else s32 low, high, mid; if (u == nurbs->knots[nurbs->npoints]) return nurbs->npoints - 1; low = nurbs->p; high = nurbs->npoints; mid = (low + high)/2; while (u < nurbs->knots[mid] || u >= nurbs->knots[mid+1]) { if (u < nurbs->knots[mid]) high = mid; else low = mid; mid = (low + high)/2; } return (mid); #endif}static SFVec3f anurbs_get_vec3f(anim_nurbs *nurbs, s32 span, SFVec3f *pts){ SFVec3f res, tmp; Fixed w, wi; u32 i; tmp.x = tmp.y = tmp.z = 0; res = tmp; w=0; for(i=0; i<=nurbs->p;i++) { tmp = pts[span - nurbs->p + i]; if (nurbs->nweights>0) { wi = nurbs->weights[span - nurbs->p + i]; tmp = gf_vec_scale(tmp, wi); w += gf_mulfix(nurbs->n[i], wi); } res.x += gf_mulfix(nurbs->n[i], tmp.x); res.y += gf_mulfix(nurbs->n[i], tmp.y); res.z += gf_mulfix(nurbs->n[i], tmp.z); } if (nurbs->nweights>0) { if (w) { w = gf_invfix(w); res = gf_vec_scale(res, w); } } return res;}static SFVec2f anurbs_get_vec2f(anim_nurbs *nurbs, s32 span, SFVec2f *pts){ SFVec2f res, tmp; Fixed w, wi; u32 i; tmp.x = tmp.y = 0; res = tmp; w=0; for(i=0; i<=nurbs->p;i++) { tmp = pts[span - nurbs->p + i]; if (nurbs->nweights>0) { wi = nurbs->weights[span - nurbs->p + i]; tmp.x = gf_mulfix(tmp.x, wi); tmp.y = gf_mulfix(tmp.y, wi); w += gf_mulfix(nurbs->n[i], wi); } res.x += gf_mulfix(nurbs->n[i], tmp.x); res.y += gf_mulfix(nurbs->n[i], tmp.y); } if (nurbs->nweights>0) { if (w) { w = gf_invfix(w); res.x = gf_mulfix(res.x, w); res.y = gf_mulfix(res.y, w); } } return res;}static Fixed anurbs_get_float(anim_nurbs *nurbs, s32 span, Fixed *vals){ Fixed res, tmp; Fixed w, wi; u32 i; res = tmp = 0; w=0; for(i=0; i<=nurbs->p;i++) { tmp = vals[span - nurbs->p + i]; if (nurbs->nweights>0) { wi = nurbs->weights[span - nurbs->p + i]; tmp = gf_mulfix(tmp, wi); w += gf_mulfix(nurbs->n[i], wi); } res += gf_mulfix(nurbs->n[i], tmp); } if (nurbs->nweights>0) res = gf_divfix(res, w); return res;}typedef struct{ Bool is_dirty; u32 anim_type; /*for paced anim*/ Fixed length; /*for spline anim*/ SFVec2f a, b, c, d; /*nurbs path*/ anim_nurbs anurbs;} AnimatorStack;static void Anim_Destroy(GF_Node *node, void *rs, Bool is_destroy){ if (is_destroy) { AnimatorStack *stack = (AnimatorStack *)gf_node_get_private(node); anurbs_reset(&stack->anurbs); free(stack); }}static void Animator_Update(AnimatorStack *stack, u32 keyValueType, u32 nCtrl, MFVec2f *keySpline, u32 nWeight, Fixed *weights){ if (stack->anim_type==ANIM_SPLINE) { stack->a.x = (keySpline->vals[0].x - keySpline->vals[1].x)*3 + FIX_ONE; stack->a.y = (keySpline->vals[0].y - keySpline->vals[1].y)*3 + FIX_ONE; stack->b.x = (keySpline->vals[1].x - 2*keySpline->vals[0].x)*3; stack->b.y = (keySpline->vals[1].y - 2*keySpline->vals[0].y)*3; stack->c.x = keySpline->vals[0].x*3; stack->c.y = keySpline->vals[0].y*3; stack->d.x = stack->d.y = 0; } anurbs_reset(&stack->anurbs); switch (keyValueType) { case ANIM_CUBIC: anurbs_init(&stack->anurbs, ANIM_CUBIC, 0, 0, NULL, 0, NULL); break; case ANIM_QUADRATIC: anurbs_init(&stack->anurbs, ANIM_QUADRATIC, 0, 0, NULL, 0, NULL); break; case ANIM_NURBS: anurbs_init(&stack->anurbs, ANIM_NURBS, nCtrl, keySpline->count, (Fixed *) &keySpline->vals[0].x, nWeight, weights); break; }}static Bool anim_check_frac(Fixed frac, SFVec2f *fromTo){ if (frac<0) return 0; if (frac>FIX_ONE) return 0; if (fromTo->x > fromTo->y) return 0; /*not active*/ if (frac<fromTo->x) return 0; if (frac>fromTo->y) return 0; return 1;}static void PA_Update(M_PositionAnimator *pa, AnimatorStack *stack){ u32 i; GF_Vec d; stack->is_dirty = 0; stack->anim_type = pa->keyType; /*if empty key and default anim switch to linear*/ if (!pa->key.count && !stack->anim_type) stack->anim_type = ANIM_LINEAR; if (stack->anim_type == ANIM_PACED) { stack->length = 0; for (i=0; i<pa->keyValue.count-1; i++) { d.x = pa->keyValue.vals[i+1].x - pa->keyValue.vals[i].x; d.y = pa->keyValue.vals[i+1].y - pa->keyValue.vals[i].y; d.z = pa->keyValue.vals[i+1].z - pa->keyValue.vals[i].z; stack->length += gf_vec_len(d); } } Animator_Update(stack, pa->keyValueType, pa->keyValue.count, &pa->keySpline, pa->weight.count, pa->weight.vals);}static void PA_SetFraction(GF_Node *node){ Fixed frac; u32 nbKeys, nbVals, i; GF_Vec d; Fixed len, dlen, dist; M_PositionAnimator *pa = (M_PositionAnimator *)node; AnimatorStack *stack = (AnimatorStack *)gf_node_get_private(node); frac = pa->set_fraction; if (!anim_check_frac(frac, &pa->fromTo)) return; if (stack->is_dirty) PA_Update(pa, stack); nbKeys = pa->key.count; nbVals = pa->keyValue.count; i=0; switch (pa->keyValueType) { /*linear interpolate*/ case ANIM_LINE: /*compute frac and segment start index*/ switch (stack->anim_type) { case ANIM_DEFAULT: if (nbKeys != nbVals) return; if (frac<pa->key.vals[0]) { i=0; frac = 0; } else if (frac>pa->key.vals[nbKeys-1]) { i=nbVals-2; frac = FIX_ONE; } else { for (i=0; i<nbKeys-1; i++) { if ((frac>=pa->key.vals[i]) && (frac<pa->key.vals[i+1])) break; } frac = GetInterpolateFraction(pa->key.vals[i], pa->key.vals[i+1], frac); } break; case ANIM_DISCRETE: i = FIX2INT(gf_floor(frac*nbVals)); frac = 0; break; case ANIM_LINEAR: i = FIX2INT(gf_floor(frac*(nbVals-1))); frac = (frac - INT2FIX(i) / (nbVals-1) ) * (nbVals-1); break; case ANIM_PACED: /*at cst speed, this is the length done*/ dist = gf_mulfix(frac, stack->length); /*then figure out in which seg we are*/ len = 0; dlen = 0; for (i=0; i<nbVals-1; i++) { d.x = pa->keyValue.vals[i+1].x - pa->keyValue.vals[i].x; d.y = pa->keyValue.vals[i+1].y - pa->keyValue.vals[i].y; d.z = pa->keyValue.vals[i+1].z - pa->keyValue.vals[i].z; dlen = gf_vec_len(d); if (len+dlen>dist) break; len += dlen; } /*that's our fraction inside the seg*/ frac = gf_divfix(dist-len, dlen); break; case ANIM_SPLINE:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -