コード例 #1
0
        private void InitializeImplicitKeyframes(bool recycleLastFrames = false)
        {
            for (var ti = 0; ti < Data.Tracks.Length; ti++)
            {
                var track = Data.Tracks[ti];

                // if looping, set implicit start exactly at the last frame of the previous loop
                if (recycleLastFrames && track.Relative == true)
                {
                    var temp = ImplicitStartKeyframes[ti].Value;
                    ImplicitStartKeyframes[ti].Value = ResolvedRelativeKeyframes[ti][track.Keyframes.Length - 1].Value;
                    ResolvedRelativeKeyframes[ti][track.Keyframes.Length - 1].Value = temp;
                }
                // only snapshot start state if we need it
                else if (track.Keyframes[0].Time > 0 || track.Relative == true)
                {
                    // generate keyframe
                    if (ImplicitStartKeyframes[ti] == null)
                    {
                        ImplicitStartKeyframes[ti] = new Keyframe()
                        {
                            Time  = 0f,
                            Value = TokenPool.Lease(TargetPath.TypeOfPath[track.TargetPath.Path])
                        };
                    }

                    // get a patch of the target type, traverse patch for the targeted field
                    JToken json = ImplicitStartKeyframes[ti].Value;
                    if (!GetPatchAtPath(track.TargetPath, out IPatchable patch) || !patch.ReadFromPath(track.TargetPath, ref json, 0))
                    {
                        continue;
                    }
                }

                // resolve all relative keyframes now
                if (track.Relative == true)
                {
                    for (var ki = 0; ki < track.Keyframes.Length; ki++)
                    {
                        var keyframe = track.Keyframes[ki];
                        if (ResolvedRelativeKeyframes[ti][ki] == null)
                        {
                            ResolvedRelativeKeyframes[ti][ki] = new Keyframe()
                            {
                                Time   = keyframe.Time,
                                Value  = TokenPool.Lease(keyframe.Value),
                                Easing = keyframe.Easing
                            };
                        }

                        Interpolations.ResolveRelativeValue(
                            ImplicitStartKeyframes[ti].Value,
                            keyframe.Value,
                            ref ResolvedRelativeKeyframes[ti][ki].Value);
                    }
                }
            }
        }
コード例 #2
0
        internal override void Update(long serverTime)
        {
            if (Data == null)
            {
                // only way for Data to be unset is if it's unloaded
                if (DataSet)
                {
                    manager.DeregisterAnimation(this);
                }
                return;
            }

            // normalize time to animation length based on wrap settings
            float currentTime;

            if (Weight > 0 && Speed != 0)
            {
                // normal operation
                currentTime  = (serverTime - BasisTime) * Speed / 1000;
                LastWeight   = Weight;
                StopUpdating = false;
            }
            else if (!StopUpdating)
            {
                // supposed to stop, but run one last update
                currentTime  = Time;
                StopUpdating = true;
            }
            else
            {
                // don't update
                return;
            }

            currentTime = ApplyWrapMode(currentTime);

            // process tracks
            for (var ti = 0; ti < Data.Tracks.Length; ti++)
            {
                Track track = Data.Tracks[ti];
                bool  usesPrevFrameValue = false, usesNextFrameValue = false;

                (Keyframe prevFrame, Keyframe nextFrame) = GetActiveKeyframes(ti, currentTime);

                // either no keyframes, or time out of range
                if (prevFrame == null)
                {
                    continue;
                }

                float linearT = (currentTime - prevFrame.Time) / (nextFrame.Time - prevFrame.Time);

                // get realtime value for trailing frame
                JToken prevFrameValue = prevFrame.Value;
                if (prevFrame.ValuePath != null)
                {
                    if (GetPatchAtPath(prevFrame.ValuePath, out IPatchable patch))
                    {
                        prevFrameValue = TokenPool.Lease(TargetPath.TypeOfPath[prevFrame.ValuePath.Path]);
                        if (patch.ReadFromPath(prevFrame.ValuePath, ref prevFrameValue, 0))
                        {
                            usesPrevFrameValue = true;
                        }
                        else
                        {
                            TokenPool.Return(prevFrameValue);
                            continue;
                        }
                    }
                    else
                    {
                        continue;
                    }
                }

                // get realtime value for leading frame (same as above)
                JToken nextFrameValue = nextFrame.Value;
                if (nextFrame.ValuePath != null)
                {
                    if (GetPatchAtPath(nextFrame.ValuePath, out IPatchable patch))
                    {
                        nextFrameValue = TokenPool.Lease(TargetPath.TypeOfPath[nextFrame.ValuePath.Path]);
                        if (patch.ReadFromPath(nextFrame.ValuePath, ref nextFrameValue, 0))
                        {
                            usesNextFrameValue = true;
                        }
                        else
                        {
                            TokenPool.Return(nextFrameValue);
                            continue;
                        }
                    }
                    else
                    {
                        continue;
                    }
                }

                // compute new value for targeted field
                JToken outputToken = TokenPool.Lease(prevFrameValue);
                Interpolations.Interpolate(prevFrameValue, nextFrameValue, linearT, ref outputToken, nextFrame.Bezier ?? track.Bezier ?? LinearEasing);
                if (usesPrevFrameValue)
                {
                    TokenPool.Return(prevFrameValue);
                }
                if (usesNextFrameValue)
                {
                    TokenPool.Return(nextFrameValue);
                }

                // mix computed value with the result of any other anims targeting the same property
                AnimationManager.AnimBlend blendData = manager.AnimBlends.GetOrCreate(
                    ResolvedTargetPaths[ti],
                    () => new AnimationManager.AnimBlend(ResolvedTargetPaths[ti]));

                blendData.FinalUpdate = blendData.FinalUpdate || StopUpdating;
                if (blendData.TotalWeight == 0)
                {
                    blendData.TotalWeight = LastWeight;
                    if (blendData.CurrentValue == null)
                    {
                        blendData.CurrentValue = outputToken.DeepClone();
                    }
                    else
                    {
                        JToken temp = blendData.CurrentValue;
                        blendData.CurrentValue = outputToken;
                        TokenPool.Return(temp);
                    }
                }
                else
                {
                    blendData.TotalWeight += LastWeight;
                    JToken temp = TokenPool.Lease(outputToken);
                    Interpolations.Interpolate(outputToken, blendData.CurrentValue, LastWeight / blendData.TotalWeight, ref temp, LinearEasing);

                    TokenPool.Return(blendData.CurrentValue);
                    blendData.CurrentValue = temp;
                }
            }
        }