private static SpriterSpatial[] GetBoneInfos(SpriterMainlineKey key, SpriterAnimation animation, float targetTime, SpriterSpatial parentInfo = null)
        {
            if (key.BoneRefs == null)
            {
                return(null);
            }
            SpriterSpatial[] ret = SpriterObjectPool.GetArray <SpriterSpatial>(key.BoneRefs.Length);

            for (int i = 0; i < key.BoneRefs.Length; ++i)
            {
                SpriterRef     boneRef      = key.BoneRefs[i];
                SpriterSpatial interpolated = GetBoneInfo(boneRef, animation, targetTime);

                if (boneRef.ParentId >= 0)
                {
                    ApplyParentTransform(interpolated, ret[boneRef.ParentId]);
                }
                else if (parentInfo != null)
                {
                    ApplyParentTransform(interpolated, parentInfo);
                }
                ret[i] = interpolated;
            }

            return(ret);
        }
        public static void UpdateFrameData(FrameData frameData, SpriterAnimation first, SpriterAnimation second, float targetTime, float factor)
        {
            if (first == second)
            {
                UpdateFrameData(frameData, first, targetTime);
                return;
            }

            float targetTimeSecond = targetTime / first.Length * second.Length;

            SpriterMainlineKey firstKeyA;
            SpriterMainlineKey firstKeyB;

            GetMainlineKeys(first.MainlineKeys, targetTime, out firstKeyA, out firstKeyB);

            SpriterMainlineKey secondKeyA;
            SpriterMainlineKey secondKeyB;

            GetMainlineKeys(second.MainlineKeys, targetTimeSecond, out secondKeyA, out secondKeyB);

            if (!WillItBlend(firstKeyA, secondKeyA) || !WillItBlend(firstKeyB, secondKeyB))
            {
                UpdateFrameData(frameData, first, targetTime);
                return;
            }

            float adjustedTimeFirst  = AdjustTime(firstKeyA, firstKeyB, first.Length, targetTime);
            float adjustedTimeSecond = AdjustTime(secondKeyA, secondKeyB, second.Length, targetTimeSecond);

            SpriterSpatial[] boneInfosA = GetBoneInfos(firstKeyA, first, adjustedTimeFirst);
            SpriterSpatial[] boneInfosB = GetBoneInfos(secondKeyA, second, adjustedTimeSecond);
            SpriterSpatial[] boneInfos  = null;
            if (boneInfosA != null && boneInfosB != null)
            {
                boneInfos = SpriterObjectPool.GetArray <SpriterSpatial>(boneInfosA.Length);
                for (int i = 0; i < boneInfosA.Length; ++i)
                {
                    SpriterSpatial boneA        = boneInfosA[i];
                    SpriterSpatial boneB        = boneInfosB[i];
                    SpriterSpatial interpolated = Interpolate(boneA, boneB, factor, 1);
                    interpolated.Angle = MathHelper.CloserAngleLinear(boneA.Angle, boneB.Angle, factor);
                    boneInfos[i]       = interpolated;
                }
            }

            SpriterMainlineKey baseKey          = factor < 0.5f ? firstKeyA : firstKeyB;
            SpriterAnimation   currentAnimation = factor < 0.5f ? first : second;

            for (int i = 0; i < baseKey.ObjectRefs.Length; ++i)
            {
                SpriterObjectRef objectRefFirst    = baseKey.ObjectRefs[i];
                SpriterObject    interpolatedFirst = GetObjectInfo(objectRefFirst, first, adjustedTimeFirst);

                SpriterObjectRef objectRefSecond    = secondKeyA.ObjectRefs[i];
                SpriterObject    interpolatedSecond = GetObjectInfo(objectRefSecond, second, adjustedTimeSecond);

                SpriterObject info = Interpolate(interpolatedFirst, interpolatedSecond, factor, 1);
                info.Angle  = MathHelper.CloserAngleLinear(interpolatedFirst.Angle, interpolatedSecond.Angle, factor);
                info.PivotX = MathHelper.Linear(interpolatedFirst.PivotX, interpolatedSecond.PivotX, factor);
                info.PivotY = MathHelper.Linear(interpolatedFirst.PivotY, interpolatedSecond.PivotY, factor);

                if (boneInfos != null && objectRefFirst.ParentId >= 0)
                {
                    ApplyParentTransform(info, boneInfos[objectRefFirst.ParentId]);
                }

                AddSpatialData(info, currentAnimation.Timelines[objectRefFirst.TimelineId], currentAnimation.Entity.Spriter, targetTime, frameData);

                SpriterObjectPool.ReturnObject(interpolatedFirst);
                SpriterObjectPool.ReturnObject(interpolatedSecond);
            }

            SpriterObjectPool.ReturnObject(boneInfosA);
            SpriterObjectPool.ReturnObject(boneInfosB);
            SpriterObjectPool.ReturnObject(boneInfos);
        }