private static void ProcessAnimation(AnimationClip clip, MouthModel mouthModel, Transform animationRoot, Transform jawRoot) { var bindings = AnimationUtility.GetCurveBindings(clip); var uBinding = bindings.FirstOrDefault(binding => binding.propertyName == "material._MainTex_mouth_ST.z"); var vBinding = bindings.FirstOrDefault(binding => binding.propertyName == "material._MainTex_mouth_ST.w"); if (uBinding.path == null || vBinding.path == null) { Debug.LogWarning("Couldn't find animation binding for clip " + clip.name); return; } var uCurve = AnimationUtility.GetEditorCurve(clip, uBinding); var vCurve = AnimationUtility.GetEditorCurve(clip, vBinding); var snapshotsAtPath = new Dictionary<string, AnimationSnapshotData>(); for (int i = 0; i < uCurve.keys.Length; i++) { // We can assume that that the curves for the U and V value have the same keyframes Vector2 uvValue = new Vector2(uCurve.keys[i].value, vCurve.keys[i].value); mouthModel.CurrentPoseIndex = RtdxTextureToMouthType.ContainsKey(uvValue) ? RtdxTextureToMouthType[uvValue] : 0; TraverseRig(jawRoot, snapshotsAtPath, GetRelativePath(jawRoot, animationRoot), uCurve.keys[i].time); } foreach (var snapshot in snapshotsAtPath) { snapshot.Value.ApplyToClip(clip); clip.EnsureQuaternionContinuity(); } AnimationHelpers.SetAnimationTangentsToConstant(clip); }
private void Update() { if (onlyInEditor) { #if !UNITY_EDITOR return; #endif } if (readyForNextStep) { readyForNextStep = false; AnimationHelpers.Play(this, path[index], () => { AsyncHelpers.DoAfterTime(this, waitTime, () => { if (index == path.Count - 1 && loop) { index = 0; readyForNextStep = true; } else if (index < path.Count - 1) { index++; readyForNextStep = true; } }); }); } }
private void ApplyLastKeyFrame(object sender, EventArgs e) { if (!_cancelledAnimation) { DoubleKeyFrame lastKeyFrame = _keyFrames[_resolvedKeyFrames.GetNextKeyFrameIndex(_keyFrames.Count - 1)]; AnimationHelpers.ApplyValue(_propertyContainer, _targetProperty, lastKeyFrame.Value, _parameters.IsVisualStateChange); } }
private static bool ValidateFromToOrByValue(object value) { CornerRadius?nullable = (CornerRadius?)value; if (nullable.HasValue) { return(AnimationHelpers.IsValidAnimationValueCornerRadius(nullable.Value)); } return(true); }
private Action OnAnimationCompleted(IterationParameters parameters, bool isLastLoop, object value, DependencyObject target, PropertyPath propertyPath, Guid callBackGuid) { return(() => { if (isLastLoop && _animationID == callBackGuid) { AnimationHelpers.ApplyValue(target, propertyPath, value, parameters.IsVisualStateChange); } OnIterationCompleted(parameters); }); }
private Action OnAnimationCompleted(IterationParameters parameters, bool isLastLoop, DependencyObject target, PropertyPath propertyPath) { return(() => { if (isLastLoop) { AnimationHelpers.ApplyInstantAnimation(target, propertyPath, To.Value, parameters.IsVisualStateChange); } OnIterationCompleted(parameters); }); }
private void OnAnimationCompleted(IterationParameters parameters, bool isLastLoop, object value, DependencyObject target, PropertyPath propertyPath) { if (!this._isUnapplied) { if (isLastLoop) { AnimationHelpers.ApplyValue(target, propertyPath, value, parameters.IsVisualStateChange); } OnIterationCompleted(parameters); } }
static void StartAnimation(DependencyObject target, CSSEquivalent cssEquivalent, double?from, object to, Duration Duration, EasingFunctionBase easingFunction, string visualStateGroupName, Action callbackForWhenfinished = null) { if (cssEquivalent.Name != null && cssEquivalent.Name.Count != 0) { UIElement uiElement = cssEquivalent.UIElement ?? (target as UIElement); // If no UIElement is specified, we assume that the property is intended to be applied to the instance on which the PropertyChanged has occurred. bool hasTemplate = (uiElement is Control) && ((Control)uiElement).HasTemplate; if (!hasTemplate || cssEquivalent.ApplyAlsoWhenThereIsAControlTemplate) { if (cssEquivalent.DomElement == null && uiElement != null) { cssEquivalent.DomElement = uiElement.INTERNAL_OuterDomElement; // Default value } if (cssEquivalent.DomElement != null) { if (cssEquivalent.Value == null) { cssEquivalent.Value = (finalInstance, value) => { return(value ?? ""); }; // Default value } object cssValue = cssEquivalent.Value(target, to); object newObj = CSHTML5.Interop.ExecuteJavaScriptAsync(@"new Object()"); if (from == null) { foreach (string csspropertyName in cssEquivalent.Name) { CSHTML5.Interop.ExecuteJavaScriptAsync(@" $0[$1] = $2;", newObj, csspropertyName, cssValue); } } else { foreach (string csspropertyName in cssEquivalent.Name) { CSHTML5.Interop.ExecuteJavaScriptAsync(@" $0[$1] = [$2, $3];", newObj, csspropertyName, cssValue, from); } } AnimationHelpers.CallVelocity(cssEquivalent.DomElement, Duration, easingFunction, visualStateGroupName, callbackForWhenfinished, newObj); } } } else { throw new InvalidOperationException("Please set the Name property of the CSSEquivalent class."); } }
private Action OnKeyFrameCompleted(IterationParameters parameters, bool isLastLoop, object value, DependencyObject target, PropertyPath propertyPath, Guid callBackGuid) { return(() => { if (_animationID == callBackGuid) { AnimationHelpers.ApplyValue(target, propertyPath, value, parameters.IsVisualStateChange); _appliedKeyFramesCount++; if (!CheckTimeLineEndAndRaiseCompletedEvent(_parameters)) { ApplyKeyFrame(GetNextKeyFrame(), isLastLoop); } } }); }
/// <summary> /// Export the animation clip meta data and spit to xml /// </summary> private Dictionary <String, AnimationData> PrepareAnimations(Dictionary <string, AnimationClip> animationClips, SkinningData skinningData, ContentProcessorContext context) { Dictionary <String, AnimationData> animationMap = new Dictionary <String, AnimationData>(); String sourceDir = SourceDirFromContext(context); String assetName = Path.GetFileNameWithoutExtension(context.OutputFilename); AnimationGroupType groupType = AnimationGroupType.Base; ChannelBlendOperation blendOp = ChannelBlendOperation.Exclusive; TimeSpan blendIn = TimeSpan.FromSeconds(0.3571); TimeSpan blendOut = TimeSpan.FromSeconds(0.3571); float[] defaultWeights = new float[skinningData.BindPose.Count]; for (int i = 0; i < defaultWeights.Length; defaultWeights[i] = 1.0f, ++i) { ; } //DebugNow(); foreach (var keyValue in animationClips) { String name = keyValue.Key; AnimationClip clip = keyValue.Value; String xmlFile = Path.Combine(sourceDir, assetName + "_" + name + ".xml"); AnimationData animData = AnimationHelpers.DeserializeAnimationData(xmlFile); if (animData == null || animData.NumBones != skinningData.BindPose.Count) { animData = new Core.Animation.AnimationData(name, Scale, clip, skinningData.BindPose.Count, skinningData.BoneMap, defaultWeights, groupType, blendOp, blendIn, blendOut); AnimationHelpers.SerializeAnimationData(animData, xmlFile); } // Overrides, not stored in Xml right now animData.BoneMap = (Dictionary <String, Int32>)skinningData.BoneMap; animData.AnimationClip = clip; animationMap.Add(animData.Name, animData); } return(animationMap); }
private void ApplyKeyFrame(ObjectKeyFrame keyFrame) { object value = keyFrame.Value; if (value is string && _propDp.PropertyType != typeof(string)) { if (_propDp.PropertyType.IsEnum) { value = Enum.Parse(_propDp.PropertyType, (string)value); } else { value = DotNetForHtml5.Core.TypeFromStringConverters.ConvertFromInvariantString(_propDp.PropertyType, (string)value); } } object castedValue = DynamicCast(value, _propDp.PropertyType); AnimationHelpers.ApplyValue(_propertyContainer, _targetProperty, castedValue, _parameters.IsVisualStateChange); }
private static UnityEngine.AnimationClip ProcessClip(AssetStudio.AnimationClip animationClip, string savePath, string bundleName, string materialAttributeName, CoordinateAttributeSet attributeSet, UnityEngine.SkinnedMeshRenderer[] skinnedMeshRenderers) { var uCurve = new UnityEngine.AnimationCurve(); var vCurve = new UnityEngine.AnimationCurve(); var clip = animationClip.m_MuscleClip.m_Clip; var streamedFrames = clip.m_StreamedClip.ReadData(); var clipBindingConstant = animationClip.m_ClipBindingConstant; for (int frameIndex = 1; frameIndex < streamedFrames.Count - 1; frameIndex++) { StreamedClip.StreamedCurveKey uCoordKey = null, vCoordKey = null; foreach (var key in streamedFrames[frameIndex].keyList) { var binding = clipBindingConstant.FindBinding(key.index); if (binding.attribute == attributeSet.UAttribute) { uCoordKey = key; } else if (binding.attribute == attributeSet.VAttribute) { vCoordKey = key; } } if (uCoordKey == null || vCoordKey == null) { continue; } // Round to 0.25 steps since the input UVs might not match perfectly var roundedUv = new Vector2(Mathf.Round(uCoordKey.value * 4) / 4, Mathf.Round(vCoordKey.value * 4) / 4); var value = RtdxTextureTo2x4Mappings[roundedUv]; uCurve.AddKey(streamedFrames[frameIndex].time, value.x); vCurve.AddKey(streamedFrames[frameIndex].time, value.y); } var newClip = new UnityEngine.AnimationClip { frameRate = animationClip.m_SampleRate }; foreach (var skinnedMeshRenderer in skinnedMeshRenderers) { AnimationUtility.SetEditorCurve(newClip, new EditorCurveBinding { path = skinnedMeshRenderer.gameObject.name, type = typeof(UnityEngine.SkinnedMeshRenderer), propertyName = $"material.{materialAttributeName}.z" }, uCurve); AnimationUtility.SetEditorCurve(newClip, new EditorCurveBinding { path = skinnedMeshRenderer.gameObject.name, type = typeof(UnityEngine.SkinnedMeshRenderer), propertyName = $"material.{materialAttributeName}.w" }, vCurve); } // We need to use this stupid workaround instead of doing it when adding the key because // apparently it glitches if the curve wasn't added to an animation AnimationHelpers.SetAnimationTangentsToConstant(newClip); string animationPath = $"{savePath}/{animationClip.m_Name}.anim"; AssetDatabase.CreateAsset(newClip, animationPath); AssetImporter.GetAtPath(animationPath).assetBundleName = bundleName; return(newClip); }
/// <summary> /// Calculates the ball animation tasks. /// </summary> /// <param name="initialWindow">The initial window.</param> /// <param name="startPosition">The start position.</param> /// <param name="initialDirection">The initial direction.</param> /// <returns>The calculated animation queue</returns> private Queue <BallAnimationTask> CalculateBallAnimationTasks(Models.Window initialWindow, Point startPosition, Vector initialDirection) { var animationQueue = new Queue <BallAnimationTask>(); var isLastAnimation = false; var currentWindow = initialWindow; var currentBallPosition = startPosition; var currentDirection = initialDirection; var stepCounter = 0; var currentTask = new BallAnimationTask { Window = currentWindow }; var previousIntersection = Intersection.None; var windowPreviouslyChanged = false; const double BallRadius = GameConfiguration.BallDiameter / 2; while (!isLastAnimation) { // Ensure an end of the animation stepCounter++; if (stepCounter == 30) { isLastAnimation = true; currentTask.IsLastAnimation = true; currentTask.IntersectsWithHole = false; } var borderPositionCorrection = new Point(); // Calculate the ignorable intersection var ignoredIntersection = Intersection.None; if (previousIntersection != Intersection.None) { if (windowPreviouslyChanged) { switch (previousIntersection) { case Intersection.TopWall: ignoredIntersection = Intersection.BottomWall; break; case Intersection.LeftWall: ignoredIntersection = Intersection.RightWall; break; case Intersection.RightWall: ignoredIntersection = Intersection.LeftWall; break; case Intersection.BottomWall: ignoredIntersection = Intersection.TopWall; break; } } else { ignoredIntersection = previousIntersection; } } var currentIntersection = Intersection.None; Point? intersectionPosition = null; Models.Window neighbourWindow = null; // Generate a point outside of the window var intersectionTestPoint = currentBallPosition + (currentDirection * 1000); // Check for hole intersection if (currentWindow.Holes != null) { foreach (var hole in currentWindow.Holes) { Point?firstIntersection; Point?secondIntersection; var intersection = CalculationHelpers.CalculateLineSphereIntersection( hole.CenterPosition, hole.Radius, currentBallPosition, intersectionTestPoint, out firstIntersection, out secondIntersection); if (intersection > 0 && firstIntersection != null) { currentIntersection = Intersection.Hole; // This hole intersection is only relevant, if the distance between this intersection and the ball is the shortest if (intersectionPosition == null || currentBallPosition.DistanceTo((Point)firstIntersection) < currentBallPosition.DistanceTo((Point)intersectionPosition)) { intersectionPosition = firstIntersection; } } } } // Check for top wall hit if (intersectionPosition == null && ignoredIntersection != Intersection.TopWall) { intersectionPosition = CalculationHelpers.GetLineIntersection( currentBallPosition, intersectionTestPoint, new Point(0, 0), new Point(GameConfiguration.GameWindowWidth, 0)); if (intersectionPosition != null) { previousIntersection = currentIntersection = Intersection.TopWall; var upperWindow = this.CurrentGame.Map.Windows.FirstOrDefault(w => w.X == currentWindow.X && w.Y == currentWindow.Y - 1); if (upperWindow != null) { neighbourWindow = upperWindow; } else { borderPositionCorrection.Y += BallRadius; } } } if (intersectionPosition == null && ignoredIntersection != Intersection.LeftWall) { // Check for left wall hit intersectionPosition = CalculationHelpers.GetLineIntersection( currentBallPosition, intersectionTestPoint, new Point(0, 0), new Point(0, GameConfiguration.GameWindowWidth)); if (intersectionPosition != null) { previousIntersection = currentIntersection = Intersection.LeftWall; var leftWindow = this.CurrentGame.Map.Windows.FirstOrDefault(w => w.X == currentWindow.X - 1 && w.Y == currentWindow.Y); if (leftWindow != null) { neighbourWindow = leftWindow; } else { borderPositionCorrection.X += BallRadius; } } } if (intersectionPosition == null && ignoredIntersection != Intersection.RightWall) { // Check for right wall hit intersectionPosition = CalculationHelpers.GetLineIntersection( currentBallPosition, intersectionTestPoint, new Point(GameConfiguration.GameWindowWidth, 0), new Point(GameConfiguration.GameWindowWidth, GameConfiguration.GameWindowWidth)); if (intersectionPosition != null) { previousIntersection = currentIntersection = Intersection.RightWall; var rightWindow = this.CurrentGame.Map.Windows.FirstOrDefault(w => w.X == currentWindow.X + 1 && w.Y == currentWindow.Y); if (rightWindow != null) { neighbourWindow = rightWindow; } else { borderPositionCorrection.X -= BallRadius; } } } if (intersectionPosition == null && ignoredIntersection != Intersection.BottomWall) { // Check for bottom wall hit intersectionPosition = CalculationHelpers.GetLineIntersection( currentBallPosition, intersectionTestPoint, new Point(0, GameConfiguration.GameWindowWidth), new Point(GameConfiguration.GameWindowWidth, GameConfiguration.GameWindowWidth)); if (intersectionPosition != null) { previousIntersection = currentIntersection = Intersection.BottomWall; var bottomWindow = this.CurrentGame.Map.Windows.FirstOrDefault(w => w.X == currentWindow.X && w.Y == currentWindow.Y + 1); if (bottomWindow != null) { neighbourWindow = bottomWindow; } else { borderPositionCorrection.Y -= BallRadius; } } } if (currentIntersection != Intersection.None && intersectionPosition != null) { var newPosition = (Point)intersectionPosition; // Apply correction newPosition.X += borderPositionCorrection.X; newPosition.Y += borderPositionCorrection.Y; currentTask.Steps.Add(AnimationHelpers.GetPointAnimation(currentBallPosition, newPosition)); // If the ball intersects a hole, end the calculation after this step if (currentIntersection == Intersection.Hole) { currentTask.IsLastAnimation = true; currentTask.IntersectsWithHole = true; animationQueue.Enqueue(currentTask); return(animationQueue); } currentBallPosition = newPosition; // Ball will leave the window if (neighbourWindow != null) { animationQueue.Enqueue(currentTask); currentWindow = neighbourWindow; currentTask = new BallAnimationTask { Window = currentWindow }; windowPreviouslyChanged = true; // Set new initial position for the next window switch (currentIntersection) { case Intersection.TopWall: currentBallPosition.Y = GameConfiguration.GameWindowWidth; break; case Intersection.LeftWall: currentBallPosition.X = GameConfiguration.GameWindowWidth; break; case Intersection.RightWall: currentBallPosition.X = 0; break; case Intersection.BottomWall: currentBallPosition.Y = 0; break; } } else { // Change ball direction within the current window if (currentIntersection == Intersection.TopWall || currentIntersection == Intersection.BottomWall) { currentDirection.Y *= -1; } else { currentDirection.X *= -1; } windowPreviouslyChanged = false; } } } // Add the last animation task to the queue because we had no wall hit (timeout) if (currentTask.Steps.Count > 0) { animationQueue.Enqueue(currentTask); } return(animationQueue); }
// todo: find a way to not have to do this. private void SetInitialAnimationValue(bool isVisualStateChange) { object initialAnimationValue = _propertyContainer.GetValue(_propDp); AnimationHelpers.ApplyValue(_propertyContainer, _targetProperty, initialAnimationValue, isVisualStateChange); }
private void UnApply(bool isVisualStateChange) { AnimationHelpers.ApplyValue(_propertyContainer, _targetProperty, DependencyProperty.UnsetValue, isVisualStateChange); //_targetProperty.INTERNAL_PropertySetAnimationValue(_propertyContainer, INTERNAL_NoValue.NoValue); }
static bool TryStartAnimation(DependencyObject target, CSSEquivalent cssEquivalent, Color?from, object to, Duration Duration, EasingFunctionBase easingFunction, string visualStateGroupName, Action callbackForWhenfinished = null) { if (cssEquivalent.Name != null && cssEquivalent.Name.Count != 0) { UIElement uiElement = cssEquivalent.UIElement ?? (target as UIElement); // If no UIElement is specified, we assume that the property is intended to be applied to the instance on which the PropertyChanged has occurred. bool hasTemplate = (uiElement is Control) && ((Control)uiElement).HasTemplate; if (!hasTemplate || cssEquivalent.ApplyAlsoWhenThereIsAControlTemplate) { if (cssEquivalent.DomElement == null && uiElement != null) { cssEquivalent.DomElement = uiElement.INTERNAL_OuterDomElement; // Default value } if (cssEquivalent.DomElement != null) { if (cssEquivalent.Value == null) { cssEquivalent.Value = (finalInstance, value) => { if (value == null) { return(""); } else { Dictionary <string, object> valuesDict = new Dictionary <string, object>(); foreach (string name in cssEquivalent.Name) { if (!name.EndsWith("Alpha")) { valuesDict.Add(name, ((Color)value).INTERNAL_ToHtmlStringForVelocity()); } else { valuesDict.Add(name, ((double)((Color)value).A) / 255); } } return(valuesDict); } //return value ?? ""; }; // Default value } object cssValue = cssEquivalent.Value(target, to); //INTERNAL_HtmlDomManager.SetDomElementStyleProperty(cssEquivalent.DomElement, cssEquivalent.Name, cssValue); object newObj = CSHTML5.Interop.ExecuteJavaScriptAsync(@"new Object()"); if (AnimationHelpers.IsValueNull(from)) //todo: when using Bridge, I guess we would want to directly use "from == null" since it worked in the first place (I think). { if (!(cssValue is Dictionary <string, object>)) { foreach (string csspropertyName in cssEquivalent.Name) { //todo: check the note below once the clone will work properly (a value set through velocity is not set in c#, which makes the clone take the former value). //Note: the test below is to avoid setting Background because Velocity cannot handle it, // which makes the element go transparent (no color) before then changing color with backgroundColor. // Therefore, we no longer go in the animation from the previous color to the new one but from no color to the new one if (csspropertyName != "background") //todo: when we will be able to use velocity for linearGradientBrush, we will need another solution here. { CSHTML5.Interop.ExecuteJavaScriptAsync(@"$0[$1] = $2;", newObj, csspropertyName, cssValue); } } } else { Dictionary <string, object> cssValueAsDictionary = (Dictionary <string, object>)cssValue; foreach (string csspropertyName in cssEquivalent.Name) { //todo: check the note below once the clone will work properly (a value set through velocity is not set in c#, which makes the clone take the former value). //Note: the test below is to avoid setting Background because Velocity cannot handle it, // which makes the element go transparent (no color) before then changing color with backgroundColor. // Therefore, we no longer go in the animation from the previous color to the new one but from no color to the new one if (csspropertyName != "background") //todo: when we will be able to use velocity for linearGradientBrush, we will need another solution here. { CSHTML5.Interop.ExecuteJavaScriptAsync(@"$0[$1] = $2;", newObj, csspropertyName, cssValueAsDictionary[csspropertyName]); } } } } else { object fromCssValue = cssEquivalent.Value(target, from); foreach (string csspropertyName in cssEquivalent.Name) { //todo: check the note below once the clone will work properly (a value set through velocity is not set in c#, which makes the clone take the former value). //Note: the test below is to avoid setting Background because Velocity cannot handle it, // which makes the element go transparent (no color) before then changing color with backgroundColor. // Therefore, we no longer go in the animation from the previous color to the new one but from no color to the new one if (csspropertyName != "background") //todo: when we will be able to use velocity for linearGradientBrush, we will need another solution here. { object currentCssValue = cssValue; if (cssValue is Dictionary <string, object> ) { currentCssValue = ((Dictionary <string, object>)cssValue)[csspropertyName]; } object currentFromCssValue = fromCssValue; if (fromCssValue is Dictionary <string, object> ) { currentFromCssValue = ((Dictionary <string, object>)fromCssValue)[csspropertyName]; } CSHTML5.Interop.ExecuteJavaScriptAsync(@"$0[$1] = [$2, $3];", newObj, csspropertyName, currentCssValue, currentFromCssValue); } } } AnimationHelpers.CallVelocity(cssEquivalent.DomElement, Duration, easingFunction, visualStateGroupName, callbackForWhenfinished, newObj); return(true); } } return(false); } else { throw new InvalidOperationException("Please set the Name property of the CSSEquivalent class."); } }
/// <summary> /// Calculates a value that represents the current value of the property being animated, as determined by the <see cref="T:System.Windows.Media.Animation.ThicknessAnimation"/>. /// </summary> /// /// <returns> /// The calculated value of the property, as determined by the current animation. /// </returns> /// <param name="defaultOriginValue">The suggested origin value, used if the animation does not have its own explicitly set start value.</param><param name="defaultDestinationValue">The suggested destination value, used if the animation does not have its own explicitly set end value.</param><param name="animationClock">An <see cref="T:System.Windows.Media.Animation.AnimationClock"/> that generates the <see cref="P:System.Windows.Media.Animation.Clock.CurrentTime"/> or <see cref="P:System.Windows.Media.Animation.Clock.CurrentProgress"/> used by the animation.</param> protected override CornerRadius GetCurrentValueCore(CornerRadius defaultOriginValue, CornerRadius defaultDestinationValue, AnimationClock animationClock) { if (!this._isAnimationFunctionValid) { this.ValidateAnimationFunction(); } double num1 = animationClock.CurrentProgress.Value; IEasingFunction easingFunction = this.EasingFunction; if (easingFunction != null) { num1 = easingFunction.Ease(num1); } var from = new CornerRadius(); var to = new CornerRadius(); var thickness1 = new CornerRadius(); var thickness2 = new CornerRadius(); bool flag1 = false; bool flag2 = false; switch (this._AnimationMode) { case AnimationMode.Automatic: from = defaultOriginValue; to = defaultDestinationValue; flag1 = true; flag2 = true; break; case AnimationMode.From: from = this._keyValues[0]; to = defaultDestinationValue; flag2 = true; break; case AnimationMode.To: from = defaultOriginValue; to = this._keyValues[0]; flag1 = true; break; case AnimationMode.By: to = this._keyValues[0]; thickness2 = defaultOriginValue; flag1 = true; break; case AnimationMode.FromTo: from = this._keyValues[0]; to = this._keyValues[1]; if (this.IsAdditive) { thickness2 = defaultOriginValue; flag1 = true; break; } break; case AnimationMode.FromBy: from = this._keyValues[0]; to = AnimationHelpers.AddCornerRadius(this._keyValues[0], this._keyValues[1]); if (this.IsAdditive) { thickness2 = defaultOriginValue; flag1 = true; break; } break; } if (flag1 && !AnimationHelpers.IsValidAnimationValueCornerRadius(defaultOriginValue)) { throw new InvalidOperationException("Animation_Invalid_DefaultValue"); } if (flag2 && !AnimationHelpers.IsValidAnimationValueCornerRadius(defaultDestinationValue)) { throw new InvalidOperationException("Animation_Invalid_DefaultValue"); } if (this.IsCumulative) { int? currentIteration = animationClock.CurrentIteration; int num2 = 1; double factor = (double)(currentIteration.HasValue ? new int?(currentIteration.GetValueOrDefault() - num2) : new int?()).Value; if (factor > 0.0) { thickness1 = AnimationHelpers.ScaleCornerRadius(AnimationHelpers.SubtractCornerRadius(to, from), factor); } } return(AnimationHelpers.AddCornerRadius(thickness2, AnimationHelpers.AddCornerRadius(thickness1, AnimationHelpers.InterpolateCornerRadius(from, to, num1)))); }
private void ApplyLastKeyFrame(object sender, EventArgs e) { DoubleKeyFrame lastKeyFrame = _keyFrames[_resolvedKeyFrames.GetNextKeyFrameIndex(_keyFrames.Count - 1)]; AnimationHelpers.ApplyInstantAnimation(_target, _targetProperty, lastKeyFrame.Value, _parameters.IsVisualStateChange); }