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)); }