📄 smil_anim.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Authors: Cyril Concolato - Jean Le Feuvre * Copyright (c)2004-200X ENST - All rights reserved * * This file is part of GPAC / SVG 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>#include <gpac/nodes_svg_sa.h>#include <gpac/nodes_svg_sani.h>#include <gpac/nodes_svg_da.h>#define DO_OPTIMIZATION_TESTS 1/************************************************************************************** * Each GF_Node holds the (SVG/SMIL) animation elements which target itself in a list * * The following are the generic functions to manipulate this list: * * - add a new animation to the list, * * - get an animation from the list, * * - remove an animation from the list, * * - count the animations in the list, * * - delete the list * **************************************************************************************/GF_Err gf_node_animation_add(GF_Node *node, void *animation){ if (!node || !animation) return GF_BAD_PARAM; if (!node->sgprivate->interact) GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext); if (!node->sgprivate->interact->animations) node->sgprivate->interact->animations = gf_list_new(); return gf_list_add(node->sgprivate->interact->animations, animation);}GF_Err gf_node_animation_del(GF_Node *node){ if (!node || !node->sgprivate->interact || !node->sgprivate->interact->animations) return GF_BAD_PARAM; gf_list_del(node->sgprivate->interact->animations); node->sgprivate->interact->animations = NULL; return GF_OK;}u32 gf_node_animation_count(GF_Node *node){ if (!node || !node->sgprivate->interact|| !node->sgprivate->interact->animations) return 0; return gf_list_count(node->sgprivate->interact->animations);}void *gf_node_animation_get(GF_Node *node, u32 i){ if (!node || !node->sgprivate->interact || !node->sgprivate->interact->animations) return 0; return gf_list_get(node->sgprivate->interact->animations, i);}GF_Err gf_node_animation_rem(GF_Node *node, u32 i){ if (!node || !node->sgprivate->interact || !node->sgprivate->interact->animations) return GF_OK; return gf_list_rem(node->sgprivate->interact->animations, i);}/************************************************************************************** * End of Generic GF_Node animations list * **************************************************************************************//************************************************************************************** * Helping functions for animation * **************************************************************************************//* Sets the pointer to the attribute value with the pointer to the value which passed (if unspecified) */void gf_svg_attributes_resolve_unspecified(GF_FieldInfo *in, GF_FieldInfo *p, GF_FieldInfo *t){ if (in->fieldType == 0) { if (p->fieldType == SVG_Transform_datatype) { /* if the input value is not specified, and the presentation value is of type Transform, then we should use the default identity transform instead of the presentation value */ *in = *t; } else { *in = *p; } }}/* Replaces the pointer to the attribute value with the pointer to the value which is inherited (if inherited) */void gf_svg_attributes_resolve_inherit(GF_FieldInfo *in, GF_FieldInfo *prop){ if (gf_svg_is_inherit(in)) *in = *prop;}/* Replaces the pointer to the attribute value with the pointer to the value of the color attribute (if the current value is set to currentColor) */void gf_svg_attributes_resolve_currentColor(GF_FieldInfo *in, GF_FieldInfo *current_color){ if ((in->fieldType == SVG_Paint_datatype) && gf_svg_is_current_color(in)) { *in = *current_color; } }/************************************************************************************** * The main function doing evaluation of the animation is: gf_smil_anim_evaluate * * Depending on the timing status of the animation it calls: * * - gf_smil_anim_animate * * - gf_smil_anim_animate_with_fraction * * - gf_smil_anim_freeze * * - gf_smil_anim_remove * * * * The gf_smil_anim_animate consists in * * - interpolating using gf_smil_anim_compute_interpolation_value * * - accumulating using gf_smil_anim_apply_accumulate * * - applying additive behavior * * * * Depending on the animation attributes, one of the following functions is called * * by the function gf_smil_anim_compute_interpolation_value * * - gf_smil_anim_set * * - gf_smil_anim_animate_using_values * * - gf_smil_anim_animate_from_to * * - gf_smil_anim_animate_from_by * * - gf_smil_anim_animate_using_path * * * * In most animation methods, the important step in the animation is to resolve * * the inherit and currentColor values to perform further interpolation, i.e. calls: * * gf_svg_attributes_resolve_currentColor(&info, &rai->owner->current_color_value); * * gf_svg_attributes_resolve_inherit(&info, &rai->owner->parent_presentation_value); * * * **************************************************************************************/static void gf_smil_anim_set(SMIL_Anim_RTI *rai){ GF_FieldInfo to_info; SMILAnimationAttributesPointers *animp = rai->animp; if (!animp) return; if (!animp->to || !animp->to->type) return; if (rai->set_done && !rai->owner->presentation_value_changed) { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Animation] Time %f - Animation %s - set animation done - nothing to do\n", gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_name((GF_Node *)rai->anim_elt))); return; } GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Animation] Time %f - Animation %s - applying set animation\n", gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_name((GF_Node *)rai->anim_elt))); to_info.fieldType = animp->to->type; to_info.far_ptr = animp->to->value; /* we do not need to resolve currentColor values or inherit values here, because no further interpolation is required for the animation and because inheritance is applied after animations in SVG_Render_base. */ gf_svg_attributes_copy(&rai->interpolated_value, &to_info, 0); rai->interpolated_value_changed = 1; rai->set_done = 1;}static void gf_smil_anim_animate_using_values(SMIL_Anim_RTI *rai, Fixed normalized_simple_time){ SMILAnimationAttributesPointers *animp = rai->animp; GF_List *values = NULL; GF_FieldInfo value_info, value_info_next; u32 keyValueIndex; u32 nbValues; Fixed interval_duration; Fixed interpolation_coefficient; u32 real_calcMode; u32 tag = gf_node_get_tag(rai->anim_elt); if (!animp) return; values = animp->values->values; memset(&value_info, 0, sizeof(GF_FieldInfo)); value_info.fieldType = animp->values->type; value_info_next = value_info; real_calcMode = (gf_svg_attribute_is_interpolatable(animp->values->type)? (animp->calcMode ? *animp->calcMode : SMIL_CALCMODE_LINEAR): SMIL_CALCMODE_DISCRETE ); nbValues = gf_list_count(values); if (nbValues == 1) { if (rai->previous_key_index != 0) { value_info.far_ptr = gf_list_get(values, 0); /* no further interpolation needed therefore no need to resolve inherit and currentColor */ gf_svg_attributes_copy(&rai->interpolated_value, &value_info, 0); rai->previous_key_index = 0; rai->interpolated_value_changed = 1; GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Animation] Time %f - Animation %s - Using values[0] as interpolation value\n", gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_name((GF_Node *)rai->anim_elt))); } return; } /* Computing new key value index and interpolation coefficient */ if (animp->keyTimes && gf_list_count(*animp->keyTimes)) { u32 keyTimeIndex; Fixed keyTimeBefore = 0, keyTimeAfter=0; u32 keyTimesCount = gf_list_count(*animp->keyTimes); for (keyTimeIndex = rai->previous_keytime_index; keyTimeIndex<keyTimesCount; keyTimeIndex++) { Fixed *tm1, *t = (Fixed *)gf_list_get(*animp->keyTimes, keyTimeIndex); if (normalized_simple_time < *t) { rai->previous_keytime_index = keyTimeIndex; tm1 = (Fixed *) gf_list_get(*animp->keyTimes, keyTimeIndex-1); if (tm1) keyTimeBefore = *tm1; else keyTimeBefore = 0; keyTimeAfter = *t; break; } } keyTimeIndex--; keyValueIndex = keyTimeIndex; interval_duration = keyTimeAfter - keyTimeBefore; if (interval_duration) interpolation_coefficient = gf_divfix(normalized_simple_time - keyTimeBefore, interval_duration); else interpolation_coefficient = 1; GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Animation] Time %f - Animation %s - Using Key Times: index %d, interval duration %.2f, coeff: %.2f\n", keyTimeIndex, interval_duration, interpolation_coefficient)); } else { if (real_calcMode == SMIL_CALCMODE_DISCRETE) { Fixed tmp = normalized_simple_time*nbValues; if (normalized_simple_time == FIX_ONE) { keyValueIndex = nbValues-1; } else { keyValueIndex = FIX2INT(gf_floor(tmp)); } interpolation_coefficient = tmp - INT2FIX(keyValueIndex); } else { Fixed tmp = normalized_simple_time*(nbValues-1); if (normalized_simple_time == FIX_ONE) { keyValueIndex = nbValues-2; } else { keyValueIndex = FIX2INT(gf_floor(tmp)); } interpolation_coefficient = tmp - INT2FIX(keyValueIndex); } //GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Animation] Time %f - Animation %s - No KeyTimes: key index %d, coeff: %.2f\n", keyValueIndex, FIX2FLT(interpolation_coefficient))); } switch (tag) {#ifdef GPAC_ENABLE_SVG_SA_BASE#ifdef GPAC_ENABLE_SVG_SA case TAG_SVG_SA_animateMotion:#endif#ifdef GPAC_ENABLE_SVG_SANI case TAG_SVG_SANI_animateMotion:#endif { SVG_SA_animateMotionElement *am = (SVG_SA_animateMotionElement *)rai->anim_elt; if (gf_list_count(am->keyPoints)) { interpolation_coefficient = *(Fixed *)gf_list_get(am->keyPoints, keyValueIndex); keyValueIndex = 0; GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Animation] Time %f - Animation %s - Using Key Points: key Value Index %d, coeff: %.2f\n", keyValueIndex, interpolation_coefficient)); } } break;#endif case TAG_SVG_animateMotion: { SVGTimedAnimBaseElement *am = (SVGTimedAnimBaseElement *)rai->anim_elt; if (am->animp->keyPoints && gf_list_count(*am->animp->keyPoints)) { interpolation_coefficient = *(Fixed *)gf_list_get(*am->animp->keyPoints, keyValueIndex); keyValueIndex = 0; GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Animation] Time %f - Animation %s - Using Key Points: key Value Index %d, coeff: %.2f\n", keyValueIndex, interpolation_coefficient)); } } break; default: break; }#if DO_OPTIMIZATION_TESTS if (rai->previous_key_index == (s32)keyValueIndex && rai->previous_coef == interpolation_coefficient) return;#endif rai->previous_key_index = keyValueIndex; rai->previous_coef = interpolation_coefficient; rai->interpolated_value_changed = 1; switch (real_calcMode) { case SMIL_CALCMODE_DISCRETE: GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Animation] Time %f - Animation %s - applying discrete animation using values (key value index: %d)\n", gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_name((GF_Node *)rai->anim_elt), keyValueIndex)); value_info.far_ptr = gf_list_get(values, keyValueIndex); /* no further interpolation needed therefore no need to resolve inherit and currentColor */ gf_svg_attributes_copy(&rai->interpolated_value, &value_info, 0); break; case SMIL_CALCMODE_PACED: /* TODO: at the moment assume it is linear */ case SMIL_CALCMODE_SPLINE: /* TODO: at the moment assume it is linear */ case SMIL_CALCMODE_LINEAR: if (keyValueIndex == nbValues - 1) { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Animation] Time %f - Animation %s - applying linear animation using values (setting last key value: %d)\n", gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_name((GF_Node *)rai->anim_elt), keyValueIndex)); value_info.far_ptr = gf_list_get(values, nbValues - 1); /* no further interpolation needed therefore no need to resolve inherit and currentColor */ gf_svg_attributes_copy(&rai->interpolated_value, &value_info, 0); } else { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Animation] Time %f - Animation %s - applying linear animation using values (key value indices: %d, %d / coeff: %f)\n", gf_node_get_scene_time((GF_Node*)rai->anim_elt), gf_node_get_name((GF_Node *)rai->anim_elt), keyValueIndex, keyValueIndex+1, interpolation_coefficient)); value_info.far_ptr = gf_list_get(values, keyValueIndex); if (rai->owner->is_property && gf_svg_attribute_is_interpolatable(animp->values->type)) { gf_svg_attributes_resolve_currentColor(&value_info, &rai->owner->current_color_value); gf_svg_attributes_resolve_inherit(&value_info, &rai->owner->parent_presentation_value); } value_info_next.far_ptr = gf_list_get(values, keyValueIndex+1); if (rai->owner->is_property && gf_svg_attribute_is_interpolatable(animp->values->type)) { gf_svg_attributes_resolve_currentColor(&value_info_next, &rai->owner->current_color_value); gf_svg_attributes_resolve_inherit(&value_info_next, &rai->owner->parent_presentation_value); } gf_svg_attributes_interpolate(&value_info, &value_info_next, &rai->interpolated_value, interpolation_coefficient, 1); } break; }}static void gf_smil_anim_animate_from_to(SMIL_Anim_RTI *rai, Fixed normalized_simple_time){ GF_FieldInfo from_info, to_info; SMILAnimationAttributesPointers *animp = rai->animp; if (!animp) return; if (rai->previous_coef == normalized_simple_time) return; rai->previous_coef = normalized_simple_time; if (animp->from) { from_info.fieldType = animp->from->type; from_info.far_ptr = animp->from->value; } else { from_info.fieldType = 0; } if (rai->is_first_anim) gf_svg_attributes_resolve_unspecified(&from_info, &rai->owner->specified_value, &rai->default_transform_value); else gf_svg_attributes_resolve_unspecified(&from_info, &rai->owner->presentation_value, &rai->default_transform_value); if (rai->owner->is_property && gf_svg_attribute_is_interpolatable(from_info.fieldType)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -