Ejemplo n.º 1
0
        private static T GetAnimBoneFrames <T>(TranslateTimeline spineTranslate) where  T : SerAnimBoneFramesContainer, new()
        {
            var frames = new SerAnimBoneFrame[spineTranslate.FrameCount];

            for (int i = 0; i < spineTranslate.FrameCount; i++)
            {
                frames[i] = new SerAnimBoneFrame()
                {
                    Time  = spineTranslate.Frames[3 * i + 0],
                    X     = spineTranslate.Frames[3 * i + 1],
                    Y     = spineTranslate.Frames[3 * i + 2],
                    Curve = spineTranslate.RawCurve
                            .Where(s => s.Key == i)
                            .Select(s => s.Value)
                            .FirstOrDefault(),
                    IsStepped = spineTranslate.IsStepped
                                .Where(s => s.Key == i)
                                .Select(s => s.Value)
                                .FirstOrDefault()
                };
            }
            return(new T()
            {
                Frames = frames
            });
        }
            static TranslateTimeline GetFillerTimeline(TranslateTimeline timeline, SkeletonData skeletonData)
            {
                var t = new TranslateTimeline(1, 0, timeline.BoneIndex);

                t.SetFrame(0, 0, 0, 0);
                return(t);
            }
Ejemplo n.º 3
0
        public RootMotionInfo GetAnimationRootMotionInfo(Animation animation, float currentTime)
        {
            RootMotionInfo rootMotion = new RootMotionInfo();
            float          duration   = animation.Duration;
            float          mid        = duration * 0.5f;

            rootMotion.timeIsPastMid = currentTime > mid;
            TranslateTimeline timeline = animation.FindTranslateTimelineForBone(rootMotionBoneIndex);

            if (timeline != null)
            {
                rootMotion.start   = timeline.Evaluate(0);
                rootMotion.current = timeline.Evaluate(currentTime);
                rootMotion.mid     = timeline.Evaluate(mid);
                rootMotion.end     = timeline.Evaluate(duration);
                return(rootMotion);
            }
            TranslateXTimeline xTimeline = animation.FindTimelineForBone <TranslateXTimeline>(rootMotionBoneIndex);
            TranslateYTimeline yTimeline = animation.FindTimelineForBone <TranslateYTimeline>(rootMotionBoneIndex);

            if (xTimeline != null || yTimeline != null)
            {
                rootMotion.start   = TimelineExtensions.Evaluate(xTimeline, yTimeline, 0);
                rootMotion.current = TimelineExtensions.Evaluate(xTimeline, yTimeline, currentTime);
                rootMotion.mid     = TimelineExtensions.Evaluate(xTimeline, yTimeline, mid);
                rootMotion.end     = TimelineExtensions.Evaluate(xTimeline, yTimeline, duration);
                return(rootMotion);
            }
            return(rootMotion);
        }
Ejemplo n.º 4
0
    void HandleStart(TrackEntry trackEntry)
    {
        track = trackEntry;

        //int trackIndex = trackEntry.TrackIndex;

        //0번 트랙 아니면 리턴
        if (track.TrackIndex != 0)
        {
            return;
        }

        Spine.Animation anim = trackEntry.Animation;


        //루트본애니 걸린거 찾기
        transTimeline = null;
        foreach (Timeline t in anim.Timelines)
        {
            if (t.GetType() != typeof(TranslateTimeline))
            {
                continue;
            }

            TranslateTimeline tt = (TranslateTimeline)t;
            if (tt.boneIndex == rootBoneIndex)
            {
                transTimeline = tt;
                lastTime      = 0;
                lastPos       = GetXYAtTime(transTimeline, 0);
                fullDelta     = GetXYAtTime(transTimeline, trackEntry.animation.Duration) - lastPos;
                break;
            }
        }
    }
Ejemplo n.º 5
0
    Vector2 GetXYAtTime(TranslateTimeline timeline, float time)
    {
        const int ENTRIES = 3;
        const int PREV_TIME = -3, PREV_X = -2, PREV_Y = -1;
        const int X = 1, Y = 2;

        float x, y;

        float[] frames = timeline.Frames;
        if (time < frames[0])
        {
            return(new Vector2(0, 0));
        }

        if (time >= frames[frames.Length - ENTRIES])
        {
            x = frames[frames.Length + PREV_X];
            y = frames[frames.Length + PREV_Y];
            return(new Vector2(x, y));
        }

        //보간
        int   frame     = Spine.Animation.BinarySearch(frames, time, ENTRIES);
        float prevX     = frames[frame + PREV_X];
        float prevY     = frames[frame + PREV_Y];
        float frameTime = frames[frame];
        float percent   = timeline.GetCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));

        x = prevX + (frames[frame + X] - prevX) * percent;
        y = prevY + (frames[frame + Y] - prevY) * percent;
        return(new Vector2(x, y));
    }
Ejemplo n.º 6
0
        private static TranslateTimeline GetFillerTimeline(TranslateTimeline timeline, SkeletonData skeletonData)
        {
            TranslateTimeline timeline2 = new TranslateTimeline(1)
            {
                boneIndex = timeline.boneIndex
            };

            timeline2.SetFrame(0, 0f, 0f, 0f);
            return(timeline2);
        }
Ejemplo n.º 7
0
        Vector2 GetTrackMovementDelta(TrackEntry track, TranslateTimeline timeline,
                                      Animation animation, TrackEntry next)
        {
            float   start        = track.animationLast;
            float   end          = track.AnimationTime;
            Vector2 currentDelta = GetTimelineMovementDelta(start, end, timeline, animation);

            ApplyMixAlphaToDelta(ref currentDelta, next, track);
            return(currentDelta);
        }
Ejemplo n.º 8
0
    void HandleEnd(TrackEntry trackEntry)
    {
        int trackIndex = trackEntry.TrackIndex;

        if (trackIndex != 0)
        {
            return;
        }

        ApplyRootMotion(skeletonAnimation);

        track         = null;
        transTimeline = null;
    }
        private void PopulateAnimationTranslationScaleTimeline(TranslateTimeline translateScaleTimeline,
		                                                       JArray jsonTimelineList, int boneIndex, float timelineScale)
        {
            translateScaleTimeline.BoneIndex = boneIndex;

            int keyframeIndex = 0;
            foreach (JToken jsonTimeline in jsonTimelineList)
            {
                var time = (float) jsonTimeline["time"];
                var x = Read<float>(jsonTimeline, "x", 0);
                var y = Read<float>(jsonTimeline, "y", 0);
                translateScaleTimeline.SetKeyframe(keyframeIndex, time, x*timelineScale, y*timelineScale);
                ReadAnimationCurve(translateScaleTimeline, keyframeIndex, jsonTimeline);
                keyframeIndex++;
            }
        }
Ejemplo n.º 10
0
        /// <summary>Evaluates the resulting value of a TranslateTimeline at a given time.
        /// SkeletonData can be accessed from Skeleton.Data or from SkeletonDataAsset.GetSkeletonData.
        /// If no SkeletonData is given, values are computed relative to setup pose instead of local-absolute.</summary>
        public static Vector2 Evaluate(this TranslateTimeline timeline, float time, SkeletonData skeletonData = null)
        {
            const int PREV_TIME = -3, PREV_X = -2, PREV_Y = -1;
            const int X = 1, Y = 2;

            var frames = timeline.frames;

            if (time < frames[0])
            {
                return(Vector2.zero);
            }

            float x, y;

            if (time >= frames[frames.Length - TranslateTimeline.ENTRIES])               // Time is after last frame.
            {
                x = frames[frames.Length + PREV_X];
                y = frames[frames.Length + PREV_Y];
            }
            else
            {
                // Interpolate between the previous frame and the current frame.
                int frame = Animation.BinarySearch(frames, time, TranslateTimeline.ENTRIES);
                x = frames[frame + PREV_X];
                y = frames[frame + PREV_Y];
                float frameTime = frames[frame];
                float percent   = timeline.GetCurvePercent(frame / TranslateTimeline.ENTRIES - 1,
                                                           1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));

                x += (frames[frame + X] - x) * percent;
                y += (frames[frame + Y] - y) * percent;
            }

            Vector2 xy = new Vector2(x, y);

            if (skeletonData == null)
            {
                return(xy);
            }
            else
            {
                var boneData = skeletonData.bones.Items[timeline.boneIndex];
                return(xy + new Vector2(boneData.x, boneData.y));
            }
        }
Ejemplo n.º 11
0
        public Vector2 GetAnimationRootMotion(float startTime, float endTime,
                                              Animation animation)
        {
            TranslateTimeline timeline = animation.FindTranslateTimelineForBone(rootMotionBoneIndex);

            if (timeline != null)
            {
                return(GetTimelineMovementDelta(startTime, endTime, timeline, animation));
            }
            TranslateXTimeline xTimeline = animation.FindTimelineForBone <TranslateXTimeline>(rootMotionBoneIndex);
            TranslateYTimeline yTimeline = animation.FindTimelineForBone <TranslateYTimeline>(rootMotionBoneIndex);

            if (xTimeline != null || yTimeline != null)
            {
                return(GetTimelineMovementDelta(startTime, endTime, xTimeline, yTimeline, animation));
            }
            return(Vector2.zero);
        }
                /// <summary>Evaluates the resulting value of a TranslateTimeline at a given time.
                /// SkeletonData can be accessed from Skeleton.Data or from SkeletonDataAsset.GetSkeletonData.
                /// If no SkeletonData is given, values are computed relative to setup pose instead of local-absolute.</summary>
                public static Vector2 Evaluate(this TranslateTimeline tt, float time, SkeletonData skeletonData = null)
                {
                    const int PREV_TIME = -3, PREV_X = -2, PREV_Y = -1;
                    const int X = 1, Y = 2;

                    var frames = tt.Frames;

                    if (time < frames[0])
                    {
                        return(Vector2.zero);
                    }

                    float x, y;

                    if (time >= frames[frames.Length - TranslateTimeline.ENTRIES])
                    {                     // Time is after last frame.
                        x = frames[frames.Length + PREV_X];
                        y = frames[frames.Length + PREV_Y];
                    }
                    else
                    {
                        int frame = Animation.BinarySearch(frames, time, TranslateTimeline.ENTRIES);
                        x = frames[frame + PREV_X];
                        y = frames[frame + PREV_Y];
                        float frameTime = frames[frame];
                        float percent   = tt.GetCurvePercent(frame / TranslateTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));

                        x += (frames[frame + X] - x) * percent;
                        y += (frames[frame + Y] - y) * percent;
                    }

                    Vector2 o = new Vector2(x, y);

                    if (skeletonData == null)
                    {
                        return(o);
                    }
                    else
                    {
                        var boneData = skeletonData.Bones.Items[tt.BoneIndex];
                        return(o + new Vector2(boneData.X, boneData.Y));
                    }
                }
Ejemplo n.º 13
0
        Vector2 GetTimelineMovementDelta(float startTime, float endTime,
                                         TranslateTimeline timeline, Animation animation)
        {
            Vector2 currentDelta;

            if (startTime > endTime)             // Looped
            {
                currentDelta = (timeline.Evaluate(animation.Duration) - timeline.Evaluate(startTime))
                               + (timeline.Evaluate(endTime) - timeline.Evaluate(0));
            }
            else if (startTime != endTime)             // Non-looped
            {
                currentDelta = timeline.Evaluate(endTime) - timeline.Evaluate(startTime);
            }
            else
            {
                currentDelta = Vector2.zero;
            }
            return(currentDelta);
        }
Ejemplo n.º 14
0
        /// <summary>Evaluates the resulting value of a TranslateTimeline at a given time.
        /// SkeletonData can be accessed from Skeleton.Data or from SkeletonDataAsset.GetSkeletonData.
        /// If no SkeletonData is given, values are returned as difference to setup pose
        /// instead of absolute values.</summary>
        public static Vector2 Evaluate(this TranslateTimeline timeline, float time, SkeletonData skeletonData = null)
        {
            if (time < timeline.Frames[0])
            {
                return(Vector2.zero);
            }

            float x, y;

            timeline.GetCurveValue(out x, out y, time);

            if (skeletonData == null)
            {
                return(new Vector2(x, y));
            }
            else
            {
                BoneData boneData = skeletonData.Bones.Items[timeline.BoneIndex];
                return(new Vector2(boneData.X + x, boneData.Y + y));
            }
        }
Ejemplo n.º 15
0
		static void ParseTranslateTimeline (Skeleton skeleton, TranslateTimeline timeline, AnimationClip clip) {
			var boneData = skeleton.Data.Bones.Items[timeline.BoneIndex];
			var bone = skeleton.Bones.Items[timeline.BoneIndex];

			AnimationCurve xCurve = new AnimationCurve();
			AnimationCurve yCurve = new AnimationCurve();
			AnimationCurve zCurve = new AnimationCurve();

			float endTime = timeline.Frames[(timeline.FrameCount * 3) - 3];

			float currentTime = timeline.Frames[0];

			List<Keyframe> xKeys = new List<Keyframe>();
			List<Keyframe> yKeys = new List<Keyframe>();

			xKeys.Add(new Keyframe(timeline.Frames[0], timeline.Frames[1] + boneData.X, 0, 0));
			yKeys.Add(new Keyframe(timeline.Frames[0], timeline.Frames[2] + boneData.Y, 0, 0));

			int listIndex = 1;
			int frameIndex = 1;
			int f = 3;
			float[] frames = timeline.Frames;
			skeleton.SetToSetupPose();
			float lastTime = 0;
			while (currentTime < endTime) {
				int pIndex = listIndex - 1;

				float curveType = timeline.GetCurveType(frameIndex - 1);
				if (curveType == 0) {
					//linear
					Keyframe px = xKeys[pIndex];
					Keyframe py = yKeys[pIndex];

					float time = frames[f];
					float x = frames[f + 1] + boneData.X;
					float y = frames[f + 2] + boneData.Y;

					float xOut = (x - px.value) / (time - px.time);
					float yOut = (y - py.value) / (time - py.time);

					px.outTangent = xOut;
					py.outTangent = yOut;

					xKeys.Add(new Keyframe(time, x, xOut, 0));
					yKeys.Add(new Keyframe(time, y, yOut, 0));

					xKeys[pIndex] = px;
					yKeys[pIndex] = py;

					currentTime = time;

					timeline.Apply(skeleton, lastTime, currentTime, null, 1, MixBlend.Setup, MixDirection.In);

					lastTime = time;
					listIndex++;
				} else if (curveType == 1) {
					//stepped
					Keyframe px = xKeys[pIndex];
					Keyframe py = yKeys[pIndex];

					float time = frames[f];
					float x = frames[f + 1] + boneData.X;
					float y = frames[f + 2] + boneData.Y;

					float xOut = float.PositiveInfinity;
					float yOut = float.PositiveInfinity;

					px.outTangent = xOut;
					py.outTangent = yOut;

					xKeys.Add(new Keyframe(time, x, xOut, 0));
					yKeys.Add(new Keyframe(time, y, yOut, 0));

					xKeys[pIndex] = px;
					yKeys[pIndex] = py;

					currentTime = time;

					timeline.Apply(skeleton, lastTime, currentTime, null, 1, MixBlend.Setup, MixDirection.In);

					lastTime = time;
					listIndex++;
				} else if (curveType == 2) {

					//bezier
					Keyframe px = xKeys[pIndex];
					Keyframe py = yKeys[pIndex];

					float time = frames[f];

					int steps = Mathf.FloorToInt((time - px.time) / BakeIncrement);

					for (int i = 1; i <= steps; i++) {
						currentTime += BakeIncrement;
						if (i == steps)
							currentTime = time;

						timeline.Apply(skeleton, lastTime, currentTime, null, 1, MixBlend.Setup, MixDirection.In);

						px = xKeys[listIndex - 1];
						py = yKeys[listIndex - 1];

						float xOut = (bone.X - px.value) / (currentTime - px.time);
						float yOut = (bone.Y - py.value) / (currentTime - py.time);

						px.outTangent = xOut;
						py.outTangent = yOut;

						xKeys.Add(new Keyframe(currentTime, bone.X, xOut, 0));
						yKeys.Add(new Keyframe(currentTime, bone.Y, yOut, 0));

						xKeys[listIndex - 1] = px;
						yKeys[listIndex - 1] = py;

						listIndex++;
						lastTime = currentTime;
					}
				}

				frameIndex++;
				f += 3;
			}

			xCurve = EnsureCurveKeyCount(new AnimationCurve(xKeys.ToArray()));
			yCurve = EnsureCurveKeyCount(new AnimationCurve(yKeys.ToArray()));



			string path = GetPath(boneData);
			const string propertyName = "localPosition";

			clip.SetCurve(path, typeof(Transform), propertyName + ".x", xCurve);
			clip.SetCurve(path, typeof(Transform), propertyName + ".y", yCurve);
			clip.SetCurve(path, typeof(Transform), propertyName + ".z", zCurve);
		}
Ejemplo n.º 16
0
    void readAnimation(string name, SkeletonData skeletonData)
    {
        List <Timeline> timelines = new List <Timeline>();
        float           scale     = 1;
        float           duration  = 0;

        //Slot timelines
        for (int i = 0, n = ReadInt(); i < n; i++)
        {
            int slotIndex = ReadInt();
            for (int ii = 0, nn = ReadInt(); ii < nn; ii++)
            {
                int timelineType = Read();
                int frameCount   = ReadInt();
                switch (timelineType)
                {
                case TIMELINE_COLOR:
                {
                    ColorTimeline timeline = new ColorTimeline(frameCount);
                    timeline.slotIndex = slotIndex;
                    for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
                    {
                        float time = ReadFloat();
                        m_tempColor = ReadColor();                          //Color

                        timeline.setFrame(frameIndex, time, m_tempColor.r, m_tempColor.g, m_tempColor.b, m_tempColor.a);
                        if (frameIndex < frameCount - 1)
                        {
                            readCurve(frameIndex, timeline);
                        }
                    }
                    timelines.Add(timeline);
                    duration = Mathf.Max(duration, timeline.Frames[frameCount * 5 - 5]);
                    break;
                }

                case TIMELINE_ATTACHMENT:
                {
                    AttachmentTimeline timeline = new AttachmentTimeline(frameCount);
                    timeline.slotIndex = slotIndex;
                    for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
                    {
                        timeline.setFrame(frameIndex, ReadFloat(), ReadString());
                    }
                    timelines.Add(timeline);
                    duration = Mathf.Max(duration, timeline.Frames[frameCount - 1]);
                    break;
                }
                }
            }
        }

        //Bone timelines
        for (int i = 0, n = ReadInt(); i < n; i++)
        {
            int boneIndex = ReadInt();
            for (int ii = 0, nn = ReadInt(); ii < nn; ii++)
            {
                int timelineType = Read();
                int frameCount   = ReadInt();
                switch (timelineType)
                {
                case TIMELINE_ROTATE: {
                    RotateTimeline timeline = new RotateTimeline(frameCount);
                    timeline.boneIndex = boneIndex;
                    for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
                    {
                        timeline.SetFrame(frameIndex, ReadFloat(), ReadFloat());
                        if (frameIndex < frameCount - 1)
                        {
                            readCurve(frameIndex, timeline);
                        }
                    }
                    timelines.Add(timeline);
                    duration = Mathf.Max(duration, timeline.Frames[frameCount * 2 - 2]);
                    break;
                }

                case TIMELINE_TRANSLATE:
                case TIMELINE_SCALE:
                {
                    TranslateTimeline timeline;
                    float             timelineScale = 1;
                    if (timelineType == TIMELINE_SCALE)
                    {
                        timeline = new ScaleTimeline(frameCount);
                    }
                    else
                    {
                        timeline      = new TranslateTimeline(frameCount);
                        timelineScale = scale;
                    }
                    timeline.boneIndex = boneIndex;
                    for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
                    {
                        timeline.SetFrame(frameIndex, ReadFloat(), ReadFloat() * timelineScale, ReadFloat()
                                          * timelineScale);
                        if (frameIndex < frameCount - 1)
                        {
                            readCurve(frameIndex, timeline);
                        }
                    }
                    timelines.Add(timeline);
                    duration = Mathf.Max(duration, timeline.Frames[frameCount * 3 - 3]);
                    break;
                }
                }
            }
        }

        //FFD timelines
        for (int i = 0, n = ReadInt(); i < n; i++)
        {
            Skin skin = skeletonData.skins[ReadInt() + 1];
            for (int ii = 0, nn = ReadInt(); ii < nn; ii++)
            {
                int slotIndex = ReadInt();
                for (int iii = 0, nnn = ReadInt(); iii < nnn; iii++)
                {
                    Attachment  attachment = skin.GetAttachment(slotIndex, ReadString());
                    int         frameCount = ReadInt();
                    FFDTimeline timeline   = new FFDTimeline(frameCount);
                    timeline.slotIndex  = slotIndex;
                    timeline.attachment = attachment;
                    for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
                    {
                        float time = ReadFloat();

                        float[] vertices;
                        int     vertexCount;
                        if (attachment.GetType() == typeof(MeshAttachment))
                        {
                            vertexCount = ((MeshAttachment)attachment).vertices.Length;
                        }
                        else
                        {
                            vertexCount = ((SkinnedMeshAttachment)attachment).weights.Length / 3 * 2;
                        }

                        int end = ReadInt();
                        if (end == 0)
                        {
                            if (attachment.GetType() == typeof(MeshAttachment))
                            {
                                vertices = ((MeshAttachment)attachment).vertices;
                            }
                            else
                            {
                                vertices = new float[vertexCount];
                            }
                        }
                        else
                        {
                            vertices = new float[vertexCount];
                            int start = ReadInt();
                            end += start;
                            if (scale == 1)
                            {
                                for (int v = start; v < end; v++)
                                {
                                    vertices[v] = ReadFloat();
                                }
                            }
                            else
                            {
                                for (int v = start; v < end; v++)
                                {
                                    vertices[v] = ReadFloat() * scale;
                                }
                            }
                            if (attachment.GetType() == typeof(MeshAttachment))
                            {
                                float[] meshVertices = ((MeshAttachment)attachment).vertices;
                                for (int v = 0, vn = vertices.Length; v < vn; v++)
                                {
                                    vertices[v] += meshVertices[v];
                                }
                            }
                        }
                        timeline.setFrame(frameIndex, time, vertices);
                        if (frameIndex < frameCount - 1)
                        {
                            readCurve(frameIndex, timeline);
                        }
                    }
                    timelines.Add(timeline);
                    duration = Mathf.Max(duration, timeline.Frames[frameCount - 1]);
                }
            }
        }

        //Draw order timeline
        int drawOrderCount = ReadInt();

        if (drawOrderCount > 0)
        {
            DrawOrderTimeline timeline = new DrawOrderTimeline(drawOrderCount);
            int slotCount = skeletonData.slots.Count;
            for (int i = 0; i < drawOrderCount; i++)
            {
                int   offsetCount = ReadInt();
                int[] drawOrder   = new int[slotCount];
                for (int ii = slotCount - 1; ii >= 0; ii--)
                {
                    drawOrder[ii] = -1;
                }
                int[] unchanged = new int[slotCount - offsetCount];
                int   originalIndex = 0, unchangedIndex = 0;
                for (int ii = 0; ii < offsetCount; ii++)
                {
                    int slotIndex = ReadInt();
                    // Collect unchanged items.
                    while (originalIndex != slotIndex)
                    {
                        unchanged[unchangedIndex++] = originalIndex++;
                    }
                    // Set changed items.
                    drawOrder[originalIndex + ReadInt()] = originalIndex++;
                }
                // Collect remaining unchanged items.
                while (originalIndex < slotCount)
                {
                    unchanged[unchangedIndex++] = originalIndex++;
                }
                // Fill in unchanged items.
                for (int ii = slotCount - 1; ii >= 0; ii--)
                {
                    if (drawOrder[ii] == -1)
                    {
                        drawOrder[ii] = unchanged[--unchangedIndex];
                    }
                }
                timeline.setFrame(i, ReadFloat(), drawOrder);
            }
            timelines.Add(timeline);
            duration = Mathf.Max(duration, timeline.Frames[drawOrderCount - 1]);
        }

        //Event timeline
        int eventCount = ReadInt();

        if (eventCount > 0)
        {
            EventTimeline timeline = new EventTimeline(eventCount);
            for (int i = 0; i < eventCount; i++)
            {
                float       time      = ReadFloat();
                EventData   eventData = skeletonData.events[ReadInt()];
                Spine.Event event1    = new Spine.Event(eventData);
                event1.Int    = ReadInt(false);
                event1.Float  = ReadFloat();
                event1.String = ReadBoolean() ? ReadString() : eventData.String;
                timeline.setFrame(i, time, event1);
            }
            timelines.Add(timeline);
            duration = Mathf.Max(duration, timeline.Frames[eventCount - 1]);
        }

        timelines.TrimExcess();
        skeletonData.AddAnimation(new Spine.Animation(name, timelines, duration));
    }
Ejemplo n.º 17
0
        private void ReadAnimation(String name, Stream input, SkeletonData skeletonData)
        {
            var   timelines = new ExposedList <Timeline>();
            float scale     = Scale;
            float duration  = 0;

            // Slot timelines.
            for (int i = 0, n = ReadVarint(input, true); i < n; i++)
            {
                int slotIndex = ReadVarint(input, true);
                for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++)
                {
                    int timelineType = input.ReadByte();
                    int frameCount   = ReadVarint(input, true);
                    switch (timelineType)
                    {
                    case SLOT_ATTACHMENT: {
                        AttachmentTimeline timeline = new AttachmentTimeline(frameCount);
                        timeline.slotIndex = slotIndex;
                        for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
                        {
                            timeline.SetFrame(frameIndex, ReadFloat(input), ReadString(input));
                        }
                        timelines.Add(timeline);
                        duration = Math.Max(duration, timeline.frames[frameCount - 1]);
                        break;
                    }

                    case SLOT_COLOR: {
                        ColorTimeline timeline = new ColorTimeline(frameCount);
                        timeline.slotIndex = slotIndex;
                        for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
                        {
                            float time  = ReadFloat(input);
                            int   color = ReadInt(input);
                            float r     = ((color & 0xff000000) >> 24) / 255f;
                            float g     = ((color & 0x00ff0000) >> 16) / 255f;
                            float b     = ((color & 0x0000ff00) >> 8) / 255f;
                            float a     = ((color & 0x000000ff)) / 255f;
                            timeline.SetFrame(frameIndex, time, r, g, b, a);
                            if (frameIndex < frameCount - 1)
                            {
                                ReadCurve(input, frameIndex, timeline);
                            }
                        }
                        timelines.Add(timeline);
                        duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * ColorTimeline.ENTRIES]);
                        break;
                    }

                    case SLOT_TWO_COLOR: {
                        TwoColorTimeline timeline = new TwoColorTimeline(frameCount);
                        timeline.slotIndex = slotIndex;
                        for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
                        {
                            float time   = ReadFloat(input);
                            int   color  = ReadInt(input);
                            float r      = ((color & 0xff000000) >> 24) / 255f;
                            float g      = ((color & 0x00ff0000) >> 16) / 255f;
                            float b      = ((color & 0x0000ff00) >> 8) / 255f;
                            float a      = ((color & 0x000000ff)) / 255f;
                            int   color2 = ReadInt(input);                                   // 0x00rrggbb
                            float r2     = ((color2 & 0x00ff0000) >> 16) / 255f;
                            float g2     = ((color2 & 0x0000ff00) >> 8) / 255f;
                            float b2     = ((color2 & 0x000000ff)) / 255f;

                            timeline.SetFrame(frameIndex, time, r, g, b, a, r2, g2, b2);
                            if (frameIndex < frameCount - 1)
                            {
                                ReadCurve(input, frameIndex, timeline);
                            }
                        }
                        timelines.Add(timeline);
                        duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * TwoColorTimeline.ENTRIES]);
                        break;
                    }
                    }
                }
            }

            // Bone timelines.
            for (int i = 0, n = ReadVarint(input, true); i < n; i++)
            {
                int boneIndex = ReadVarint(input, true);
                for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++)
                {
                    int timelineType = input.ReadByte();
                    int frameCount   = ReadVarint(input, true);
                    switch (timelineType)
                    {
                    case BONE_ROTATE: {
                        RotateTimeline timeline = new RotateTimeline(frameCount);
                        timeline.boneIndex = boneIndex;
                        for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
                        {
                            timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input));
                            if (frameIndex < frameCount - 1)
                            {
                                ReadCurve(input, frameIndex, timeline);
                            }
                        }
                        timelines.Add(timeline);
                        duration = Math.Max(duration, timeline.frames[(frameCount - 1) * RotateTimeline.ENTRIES]);
                        break;
                    }

                    case BONE_TRANSLATE:
                    case BONE_SCALE:
                    case BONE_SHEAR: {
                        TranslateTimeline timeline;
                        float             timelineScale = 1;
                        if (timelineType == BONE_SCALE)
                        {
                            timeline = new ScaleTimeline(frameCount);
                        }
                        else if (timelineType == BONE_SHEAR)
                        {
                            timeline = new ShearTimeline(frameCount);
                        }
                        else
                        {
                            timeline      = new TranslateTimeline(frameCount);
                            timelineScale = scale;
                        }
                        timeline.boneIndex = boneIndex;
                        for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
                        {
                            timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input) * timelineScale, ReadFloat(input)
                                              * timelineScale);
                            if (frameIndex < frameCount - 1)
                            {
                                ReadCurve(input, frameIndex, timeline);
                            }
                        }
                        timelines.Add(timeline);
                        duration = Math.Max(duration, timeline.frames[(frameCount - 1) * TranslateTimeline.ENTRIES]);
                        break;
                    }
                    }
                }
            }

            // IK timelines.
            for (int i = 0, n = ReadVarint(input, true); i < n; i++)
            {
                int index      = ReadVarint(input, true);
                int frameCount = ReadVarint(input, true);
                IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount)
                {
                    ikConstraintIndex = index
                };
                for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
                {
                    timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input), ReadSByte(input), ReadBoolean(input), ReadBoolean(input));
                    if (frameIndex < frameCount - 1)
                    {
                        ReadCurve(input, frameIndex, timeline);
                    }
                }
                timelines.Add(timeline);
                duration = Math.Max(duration, timeline.frames[(frameCount - 1) * IkConstraintTimeline.ENTRIES]);
            }

            // Transform constraint timelines.
            for (int i = 0, n = ReadVarint(input, true); i < n; i++)
            {
                int index      = ReadVarint(input, true);
                int frameCount = ReadVarint(input, true);
                TransformConstraintTimeline timeline = new TransformConstraintTimeline(frameCount);
                timeline.transformConstraintIndex = index;
                for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
                {
                    timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input), ReadFloat(input), ReadFloat(input), ReadFloat(input));
                    if (frameIndex < frameCount - 1)
                    {
                        ReadCurve(input, frameIndex, timeline);
                    }
                }
                timelines.Add(timeline);
                duration = Math.Max(duration, timeline.frames[(frameCount - 1) * TransformConstraintTimeline.ENTRIES]);
            }

            // Path constraint timelines.
            for (int i = 0, n = ReadVarint(input, true); i < n; i++)
            {
                int index = ReadVarint(input, true);
                PathConstraintData data = skeletonData.pathConstraints.Items[index];
                for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++)
                {
                    int timelineType = ReadSByte(input);
                    int frameCount   = ReadVarint(input, true);
                    switch (timelineType)
                    {
                    case PATH_POSITION:
                    case PATH_SPACING: {
                        PathConstraintPositionTimeline timeline;
                        float timelineScale = 1;
                        if (timelineType == PATH_SPACING)
                        {
                            timeline = new PathConstraintSpacingTimeline(frameCount);
                            if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed)
                            {
                                timelineScale = scale;
                            }
                        }
                        else
                        {
                            timeline = new PathConstraintPositionTimeline(frameCount);
                            if (data.positionMode == PositionMode.Fixed)
                            {
                                timelineScale = scale;
                            }
                        }
                        timeline.pathConstraintIndex = index;
                        for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
                        {
                            timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input) * timelineScale);
                            if (frameIndex < frameCount - 1)
                            {
                                ReadCurve(input, frameIndex, timeline);
                            }
                        }
                        timelines.Add(timeline);
                        duration = Math.Max(duration, timeline.frames[(frameCount - 1) * PathConstraintPositionTimeline.ENTRIES]);
                        break;
                    }

                    case PATH_MIX: {
                        PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(frameCount);
                        timeline.pathConstraintIndex = index;
                        for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
                        {
                            timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input), ReadFloat(input));
                            if (frameIndex < frameCount - 1)
                            {
                                ReadCurve(input, frameIndex, timeline);
                            }
                        }
                        timelines.Add(timeline);
                        duration = Math.Max(duration, timeline.frames[(frameCount - 1) * PathConstraintMixTimeline.ENTRIES]);
                        break;
                    }
                    }
                }
            }

            // Deform timelines.
            for (int i = 0, n = ReadVarint(input, true); i < n; i++)
            {
                Skin skin = skeletonData.skins.Items[ReadVarint(input, true)];
                for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++)
                {
                    int slotIndex = ReadVarint(input, true);
                    for (int iii = 0, nnn = ReadVarint(input, true); iii < nnn; iii++)
                    {
                        VertexAttachment attachment = (VertexAttachment)skin.GetAttachment(slotIndex, ReadString(input));
                        bool             weighted   = attachment.bones != null;
                        float[]          vertices   = attachment.vertices;
                        int deformLength            = weighted ? vertices.Length / 3 * 2 : vertices.Length;

                        int            frameCount = ReadVarint(input, true);
                        DeformTimeline timeline   = new DeformTimeline(frameCount);
                        timeline.slotIndex  = slotIndex;
                        timeline.attachment = attachment;

                        for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
                        {
                            float   time = ReadFloat(input);
                            float[] deform;
                            int     end = ReadVarint(input, true);
                            if (end == 0)
                            {
                                deform = weighted ? new float[deformLength] : vertices;
                            }
                            else
                            {
                                deform = new float[deformLength];
                                int start = ReadVarint(input, true);
                                end += start;
                                if (scale == 1)
                                {
                                    for (int v = start; v < end; v++)
                                    {
                                        deform[v] = ReadFloat(input);
                                    }
                                }
                                else
                                {
                                    for (int v = start; v < end; v++)
                                    {
                                        deform[v] = ReadFloat(input) * scale;
                                    }
                                }
                                if (!weighted)
                                {
                                    for (int v = 0, vn = deform.Length; v < vn; v++)
                                    {
                                        deform[v] += vertices[v];
                                    }
                                }
                            }

                            timeline.SetFrame(frameIndex, time, deform);
                            if (frameIndex < frameCount - 1)
                            {
                                ReadCurve(input, frameIndex, timeline);
                            }
                        }
                        timelines.Add(timeline);
                        duration = Math.Max(duration, timeline.frames[frameCount - 1]);
                    }
                }
            }

            // Draw order timeline.
            int drawOrderCount = ReadVarint(input, true);

            if (drawOrderCount > 0)
            {
                DrawOrderTimeline timeline = new DrawOrderTimeline(drawOrderCount);
                int slotCount = skeletonData.slots.Count;
                for (int i = 0; i < drawOrderCount; i++)
                {
                    float time        = ReadFloat(input);
                    int   offsetCount = ReadVarint(input, true);
                    int[] drawOrder   = new int[slotCount];
                    for (int ii = slotCount - 1; ii >= 0; ii--)
                    {
                        drawOrder[ii] = -1;
                    }
                    int[] unchanged = new int[slotCount - offsetCount];
                    int   originalIndex = 0, unchangedIndex = 0;
                    for (int ii = 0; ii < offsetCount; ii++)
                    {
                        int slotIndex = ReadVarint(input, true);
                        // Collect unchanged items.
                        while (originalIndex != slotIndex)
                        {
                            unchanged[unchangedIndex++] = originalIndex++;
                        }
                        // Set changed items.
                        drawOrder[originalIndex + ReadVarint(input, true)] = originalIndex++;
                    }
                    // Collect remaining unchanged items.
                    while (originalIndex < slotCount)
                    {
                        unchanged[unchangedIndex++] = originalIndex++;
                    }
                    // Fill in unchanged items.
                    for (int ii = slotCount - 1; ii >= 0; ii--)
                    {
                        if (drawOrder[ii] == -1)
                        {
                            drawOrder[ii] = unchanged[--unchangedIndex];
                        }
                    }
                    timeline.SetFrame(i, time, drawOrder);
                }
                timelines.Add(timeline);
                duration = Math.Max(duration, timeline.frames[drawOrderCount - 1]);
            }

            // Event timeline.
            int eventCount = ReadVarint(input, true);

            if (eventCount > 0)
            {
                EventTimeline timeline = new EventTimeline(eventCount);
                for (int i = 0; i < eventCount; i++)
                {
                    float     time      = ReadFloat(input);
                    EventData eventData = skeletonData.events.Items[ReadVarint(input, true)];
                    Event     e         = new Event(time, eventData)
                    {
                        Int    = ReadVarint(input, false),
                        Float  = ReadFloat(input),
                        String = ReadBoolean(input) ? ReadString(input) : eventData.String
                    };
                    if (e.data.AudioPath != null)
                    {
                        e.volume  = ReadFloat(input);
                        e.balance = ReadFloat(input);
                    }
                    timeline.SetFrame(i, e);
                }
                timelines.Add(timeline);
                duration = Math.Max(duration, timeline.frames[eventCount - 1]);
            }

            timelines.TrimExcess();
            skeletonData.animations.Add(new Animation(name, timelines, duration));
        }
Ejemplo n.º 18
0
        private void ReadAnimation(Dictionary <String, Object> map, String name, SkeletonData skeletonData)
        {
            var   scale     = this.Scale;
            var   timelines = new ExposedList <Timeline>();
            float duration  = 0;

            // Slot timelines.
            if (map.ContainsKey("slots"))
            {
                foreach (KeyValuePair <String, Object> entry in (Dictionary <String, Object>)map["slots"])
                {
                    String slotName    = entry.Key;
                    int    slotIndex   = skeletonData.FindSlotIndex(slotName);
                    var    timelineMap = (Dictionary <String, Object>)entry.Value;
                    foreach (KeyValuePair <String, Object> timelineEntry in timelineMap)
                    {
                        var values       = (List <Object>)timelineEntry.Value;
                        var timelineName = (String)timelineEntry.Key;
                        if (timelineName == "color")
                        {
                            var timeline = new ColorTimeline(values.Count);
                            timeline.slotIndex = slotIndex;

                            int frameIndex = 0;
                            foreach (Dictionary <String, Object> valueMap in values)
                            {
                                float  time = (float)valueMap["time"];
                                String c    = (String)valueMap["color"];
                                timeline.SetFrame(frameIndex, time, ToColor(c, 0), ToColor(c, 1), ToColor(c, 2), ToColor(c, 3));
                                ReadCurve(valueMap, timeline, frameIndex);
                                frameIndex++;
                            }
                            timelines.Add(timeline);
                            duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * ColorTimeline.ENTRIES]);
                        }
                        else if (timelineName == "attachment")
                        {
                            var timeline = new AttachmentTimeline(values.Count);
                            timeline.slotIndex = slotIndex;

                            int frameIndex = 0;
                            foreach (Dictionary <String, Object> valueMap in values)
                            {
                                float time = (float)valueMap["time"];
                                timeline.SetFrame(frameIndex++, time, (String)valueMap["name"]);
                            }
                            timelines.Add(timeline);
                            duration = Math.Max(duration, timeline.frames[timeline.FrameCount - 1]);
                        }
                        else
                        {
                            throw new Exception("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")");
                        }
                    }
                }
            }

            // Bone timelines.
            if (map.ContainsKey("bones"))
            {
                foreach (KeyValuePair <String, Object> entry in (Dictionary <String, Object>)map["bones"])
                {
                    String boneName  = entry.Key;
                    int    boneIndex = skeletonData.FindBoneIndex(boneName);
                    if (boneIndex == -1)
                    {
                        throw new Exception("Bone not found: " + boneName);
                    }
                    var timelineMap = (Dictionary <String, Object>)entry.Value;
                    foreach (KeyValuePair <String, Object> timelineEntry in timelineMap)
                    {
                        var values       = (List <Object>)timelineEntry.Value;
                        var timelineName = (String)timelineEntry.Key;
                        if (timelineName == "rotate")
                        {
                            var timeline = new RotateTimeline(values.Count);
                            timeline.boneIndex = boneIndex;

                            int frameIndex = 0;
                            foreach (Dictionary <String, Object> valueMap in values)
                            {
                                timeline.SetFrame(frameIndex, (float)valueMap["time"], (float)valueMap["angle"]);
                                ReadCurve(valueMap, timeline, frameIndex);
                                frameIndex++;
                            }
                            timelines.Add(timeline);
                            duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * RotateTimeline.ENTRIES]);
                        }
                        else if (timelineName == "translate" || timelineName == "scale" || timelineName == "shear")
                        {
                            TranslateTimeline timeline;
                            float             timelineScale = 1;
                            if (timelineName == "scale")
                            {
                                timeline = new ScaleTimeline(values.Count);
                            }
                            else if (timelineName == "shear")
                            {
                                timeline = new ShearTimeline(values.Count);
                            }
                            else
                            {
                                timeline      = new TranslateTimeline(values.Count);
                                timelineScale = scale;
                            }
                            timeline.boneIndex = boneIndex;

                            int frameIndex = 0;
                            foreach (Dictionary <String, Object> valueMap in values)
                            {
                                float time = (float)valueMap["time"];
                                float x    = GetFloat(valueMap, "x", 0);
                                float y    = GetFloat(valueMap, "y", 0);
                                timeline.SetFrame(frameIndex, time, x * timelineScale, y * timelineScale);
                                ReadCurve(valueMap, timeline, frameIndex);
                                frameIndex++;
                            }
                            timelines.Add(timeline);
                            duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * TranslateTimeline.ENTRIES]);
                        }
                        else
                        {
                            throw new Exception("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")");
                        }
                    }
                }
            }

            // IK constraint timelines.
            if (map.ContainsKey("ik"))
            {
                foreach (KeyValuePair <String, Object> constraintMap in (Dictionary <String, Object>)map["ik"])
                {
                    IkConstraintData constraint = skeletonData.FindIkConstraint(constraintMap.Key);
                    var values   = (List <Object>)constraintMap.Value;
                    var timeline = new IkConstraintTimeline(values.Count);
                    timeline.ikConstraintIndex = skeletonData.ikConstraints.IndexOf(constraint);
                    int frameIndex = 0;
                    foreach (Dictionary <String, Object> valueMap in values)
                    {
                        float time         = (float)valueMap["time"];
                        float mix          = GetFloat(valueMap, "mix", 1);
                        bool  bendPositive = GetBoolean(valueMap, "bendPositive", true);
                        timeline.SetFrame(frameIndex, time, mix, bendPositive ? 1 : -1);
                        ReadCurve(valueMap, timeline, frameIndex);
                        frameIndex++;
                    }
                    timelines.Add(timeline);
                    duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * IkConstraintTimeline.ENTRIES]);
                }
            }

            // Transform constraint timelines.
            if (map.ContainsKey("transform"))
            {
                foreach (KeyValuePair <String, Object> constraintMap in (Dictionary <String, Object>)map["transform"])
                {
                    TransformConstraintData constraint = skeletonData.FindTransformConstraint(constraintMap.Key);
                    var values   = (List <Object>)constraintMap.Value;
                    var timeline = new TransformConstraintTimeline(values.Count);
                    timeline.transformConstraintIndex = skeletonData.transformConstraints.IndexOf(constraint);
                    int frameIndex = 0;
                    foreach (Dictionary <String, Object> valueMap in values)
                    {
                        float time         = (float)valueMap["time"];
                        float rotateMix    = GetFloat(valueMap, "rotateMix", 1);
                        float translateMix = GetFloat(valueMap, "translateMix", 1);
                        float scaleMix     = GetFloat(valueMap, "scaleMix", 1);
                        float shearMix     = GetFloat(valueMap, "shearMix", 1);
                        timeline.SetFrame(frameIndex, time, rotateMix, translateMix, scaleMix, shearMix);
                        ReadCurve(valueMap, timeline, frameIndex);
                        frameIndex++;
                    }
                    timelines.Add(timeline);
                    duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * TransformConstraintTimeline.ENTRIES]);
                }
            }

            // Path constraint timelines.
            if (map.ContainsKey("paths"))
            {
                foreach (KeyValuePair <String, Object> constraintMap in (Dictionary <String, Object>)map["paths"])
                {
                    int index = skeletonData.FindPathConstraintIndex(constraintMap.Key);
                    if (index == -1)
                    {
                        throw new Exception("Path constraint not found: " + constraintMap.Key);
                    }
                    PathConstraintData data = skeletonData.pathConstraints.Items[index];
                    var timelineMap         = (Dictionary <String, Object>)constraintMap.Value;
                    foreach (KeyValuePair <String, Object> timelineEntry in timelineMap)
                    {
                        var values       = (List <Object>)timelineEntry.Value;
                        var timelineName = (String)timelineEntry.Key;
                        if (timelineName == "position" || timelineName == "spacing")
                        {
                            PathConstraintPositionTimeline timeline;
                            float timelineScale = 1;
                            if (timelineName == "spacing")
                            {
                                timeline = new PathConstraintSpacingTimeline(values.Count);
                                if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed)
                                {
                                    timelineScale = scale;
                                }
                            }
                            else
                            {
                                timeline = new PathConstraintPositionTimeline(values.Count);
                                if (data.positionMode == PositionMode.Fixed)
                                {
                                    timelineScale = scale;
                                }
                            }
                            timeline.pathConstraintIndex = index;
                            int frameIndex = 0;
                            foreach (Dictionary <String, Object> valueMap in values)
                            {
                                timeline.SetFrame(frameIndex, (float)valueMap["time"], GetFloat(valueMap, timelineName, 0) * timelineScale);
                                ReadCurve(valueMap, timeline, frameIndex);
                                frameIndex++;
                            }
                            timelines.Add(timeline);
                            duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * PathConstraintPositionTimeline.ENTRIES]);
                        }
                        else if (timelineName == "mix")
                        {
                            PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(values.Count);
                            timeline.pathConstraintIndex = index;
                            int frameIndex = 0;
                            foreach (Dictionary <String, Object> valueMap in values)
                            {
                                timeline.SetFrame(frameIndex, (float)valueMap["time"], GetFloat(valueMap, "rotateMix", 1), GetFloat(valueMap, "translateMix", 1));
                                ReadCurve(valueMap, timeline, frameIndex);
                                frameIndex++;
                            }
                            timelines.Add(timeline);
                            duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * PathConstraintMixTimeline.ENTRIES]);
                        }
                    }
                }
            }

            // Deform timelines.
            if (map.ContainsKey("deform"))
            {
                foreach (KeyValuePair <String, Object> deformMap in (Dictionary <String, Object>)map["deform"])
                {
                    Skin skin = skeletonData.FindSkin(deformMap.Key);
                    foreach (KeyValuePair <String, Object> slotMap in (Dictionary <String, Object>)deformMap.Value)
                    {
                        int slotIndex = skeletonData.FindSlotIndex(slotMap.Key);
                        if (slotIndex == -1)
                        {
                            throw new Exception("Slot not found: " + slotMap.Key);
                        }
                        foreach (KeyValuePair <String, Object> timelineMap in (Dictionary <String, Object>)slotMap.Value)
                        {
                            var values = (List <Object>)timelineMap.Value;
                            VertexAttachment attachment = (VertexAttachment)skin.GetAttachment(slotIndex, timelineMap.Key);
                            if (attachment == null)
                            {
                                throw new Exception("Deform attachment not found: " + timelineMap.Key);
                            }
                            bool    weighted     = attachment.bones != null;
                            float[] vertices     = attachment.vertices;
                            int     deformLength = weighted ? vertices.Length / 3 * 2 : vertices.Length;

                            var timeline = new DeformTimeline(values.Count);
                            timeline.slotIndex  = slotIndex;
                            timeline.attachment = attachment;

                            int frameIndex = 0;
                            foreach (Dictionary <String, Object> valueMap in values)
                            {
                                float[] deform;
                                if (!valueMap.ContainsKey("vertices"))
                                {
                                    deform = weighted ? new float[deformLength] : vertices;
                                }
                                else
                                {
                                    deform = new float[deformLength];
                                    int     start         = GetInt(valueMap, "offset", 0);
                                    float[] verticesValue = GetFloatArray(valueMap, "vertices", 1);
                                    Array.Copy(verticesValue, 0, deform, start, verticesValue.Length);
                                    if (scale != 1)
                                    {
                                        for (int i = start, n = i + verticesValue.Length; i < n; i++)
                                        {
                                            deform[i] *= scale;
                                        }
                                    }

                                    if (!weighted)
                                    {
                                        for (int i = 0; i < deformLength; i++)
                                        {
                                            deform[i] += vertices[i];
                                        }
                                    }
                                }

                                timeline.SetFrame(frameIndex, (float)valueMap["time"], deform);
                                ReadCurve(valueMap, timeline, frameIndex);
                                frameIndex++;
                            }
                            timelines.Add(timeline);
                            duration = Math.Max(duration, timeline.frames[timeline.FrameCount - 1]);
                        }
                    }
                }
            }

            // Draw order timeline.
            if (map.ContainsKey("drawOrder") || map.ContainsKey("draworder"))
            {
                var values     = (List <Object>)map[map.ContainsKey("drawOrder") ? "drawOrder" : "draworder"];
                var timeline   = new DrawOrderTimeline(values.Count);
                int slotCount  = skeletonData.slots.Count;
                int frameIndex = 0;
                foreach (Dictionary <String, Object> drawOrderMap in values)
                {
                    int[] drawOrder = null;
                    if (drawOrderMap.ContainsKey("offsets"))
                    {
                        drawOrder = new int[slotCount];
                        for (int i = slotCount - 1; i >= 0; i--)
                        {
                            drawOrder[i] = -1;
                        }
                        var   offsets = (List <Object>)drawOrderMap["offsets"];
                        int[] unchanged = new int[slotCount - offsets.Count];
                        int   originalIndex = 0, unchangedIndex = 0;
                        foreach (Dictionary <String, Object> offsetMap in offsets)
                        {
                            int slotIndex = skeletonData.FindSlotIndex((String)offsetMap["slot"]);
                            if (slotIndex == -1)
                            {
                                throw new Exception("Slot not found: " + offsetMap["slot"]);
                            }
                            // Collect unchanged items.
                            while (originalIndex != slotIndex)
                            {
                                unchanged[unchangedIndex++] = originalIndex++;
                            }
                            // Set changed items.
                            int index = originalIndex + (int)(float)offsetMap["offset"];
                            drawOrder[index] = originalIndex++;
                        }
                        // Collect remaining unchanged items.
                        while (originalIndex < slotCount)
                        {
                            unchanged[unchangedIndex++] = originalIndex++;
                        }
                        // Fill in unchanged items.
                        for (int i = slotCount - 1; i >= 0; i--)
                        {
                            if (drawOrder[i] == -1)
                            {
                                drawOrder[i] = unchanged[--unchangedIndex];
                            }
                        }
                    }
                    timeline.SetFrame(frameIndex++, (float)drawOrderMap["time"], drawOrder);
                }
                timelines.Add(timeline);
                duration = Math.Max(duration, timeline.frames[timeline.FrameCount - 1]);
            }

            // Event timeline.
            if (map.ContainsKey("events"))
            {
                var eventsMap  = (List <Object>)map["events"];
                var timeline   = new EventTimeline(eventsMap.Count);
                int frameIndex = 0;
                foreach (Dictionary <String, Object> eventMap in eventsMap)
                {
                    EventData eventData = skeletonData.FindEvent((String)eventMap["name"]);
                    if (eventData == null)
                    {
                        throw new Exception("Event not found: " + eventMap["name"]);
                    }
                    var e = new Event((float)eventMap["time"], eventData);
                    e.Int    = GetInt(eventMap, "int", eventData.Int);
                    e.Float  = GetFloat(eventMap, "float", eventData.Float);
                    e.String = GetString(eventMap, "string", eventData.String);
                    timeline.SetFrame(frameIndex++, e);
                }
                timelines.Add(timeline);
                duration = Math.Max(duration, timeline.frames[timeline.FrameCount - 1]);
            }

            timelines.TrimExcess();
            skeletonData.animations.Add(new Animation(name, timelines, duration));
        }
        private ITimeline ReadAnimationTranslationTimeline(JArray jsonTimelineList, int boneIndex, float scale)
        {
            var translateTimeline = new TranslateTimeline(jsonTimelineList.Count);

            PopulateAnimationTranslationScaleTimeline(translateTimeline, jsonTimelineList, boneIndex, scale);

            return translateTimeline;
        }