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); }
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); }
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; } } }
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)); }
private static TranslateTimeline GetFillerTimeline(TranslateTimeline timeline, SkeletonData skeletonData) { TranslateTimeline timeline2 = new TranslateTimeline(1) { boneIndex = timeline.boneIndex }; timeline2.SetFrame(0, 0f, 0f, 0f); return(timeline2); }
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); }
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++; } }
/// <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)); } }
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)); } }
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); }
/// <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)); } }
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); }
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)); }
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)); }
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; }