diff --git a/spine-libgdx/src/com/esotericsoftware/spine/Animation.java b/spine-libgdx/src/com/esotericsoftware/spine/Animation.java index c4722891a..fd2d2561b 100644 --- a/spine-libgdx/src/com/esotericsoftware/spine/Animation.java +++ b/spine-libgdx/src/com/esotericsoftware/spine/Animation.java @@ -718,17 +718,16 @@ public class Animation { } static public class IkConstraintTimeline extends CurveTimeline { - static private final int PREV_FRAME_TIME = -2; - static private final int FRAME_VALUE = 1; + static private final int PREV_FRAME_TIME = -3; + static private final int FRAME_MIX = 1; + static private final int FRAME_BEND_DIRECTION = 2; int ikConstraintIndex; - private final float[] frames; // time, mix, ... - private final int[] bendDirections; + private final float[] frames; // time, mix, bendDirection, ... public IkConstraintTimeline (int frameCount) { super(frameCount); - frames = new float[frameCount * 2]; - bendDirections = new int[frameCount]; + frames = new float[frameCount * 3]; } public void setIkConstraintIndex (int ikConstraint) { @@ -745,10 +744,10 @@ public class Animation { /** Sets the time, mix and bend direction of the specified keyframe. */ public void setFrame (int frameIndex, float time, float mix, int bendDirection) { - bendDirections[frameIndex] = bendDirection; - frameIndex *= 2; + frameIndex *= 3; frames[frameIndex] = time; frames[frameIndex + 1] = mix; + frames[frameIndex + 2] = bendDirection; } public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { @@ -757,22 +756,22 @@ public class Animation { IkConstraint ikConstraint = skeleton.ikConstraints.get(ikConstraintIndex); - if (time >= frames[frames.length - 2]) { // Time is after last frame. - ikConstraint.mix += (frames[frames.length - 1] - ikConstraint.mix) * alpha; - ikConstraint.bendDirection = bendDirections[bendDirections.length - 1]; + if (time >= frames[frames.length - 3]) { // Time is after last frame. + ikConstraint.mix += (frames[frames.length - 2] - ikConstraint.mix) * alpha; + ikConstraint.bendDirection = (int)frames[frames.length - 1]; return; } // Interpolate between the previous frame and the current frame. - int frameIndex = binarySearch(frames, time, 2); - float prevFrameValue = frames[frameIndex - 1]; + int frameIndex = binarySearch(frames, time, 3); + float prevFrameMix = frames[frameIndex - 2]; float frameTime = frames[frameIndex]; float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frameIndex + PREV_FRAME_TIME] - frameTime), 0, 1); - percent = getCurvePercent((frameIndex >> 1) - 1, percent); + percent = getCurvePercent(frameIndex / 3 - 1, percent); - float mix = prevFrameValue + (frames[frameIndex + FRAME_VALUE] - prevFrameValue) * percent; + float mix = prevFrameMix + (frames[frameIndex + FRAME_MIX] - prevFrameMix) * percent; ikConstraint.mix += (mix - ikConstraint.mix) * alpha; - ikConstraint.bendDirection = bendDirections[(frameIndex - 2) >> 1]; + ikConstraint.bendDirection = (int)frames[frameIndex + FRAME_BEND_DIRECTION]; } } } diff --git a/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java b/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java index cb6ac9588..3885df343 100644 --- a/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java +++ b/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java @@ -30,12 +30,23 @@ package com.esotericsoftware.spine; +import java.io.IOException; + +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.DataInput; +import com.badlogic.gdx.utils.FloatArray; +import com.badlogic.gdx.utils.IntArray; +import com.badlogic.gdx.utils.SerializationException; import com.esotericsoftware.spine.Animation.AttachmentTimeline; import com.esotericsoftware.spine.Animation.ColorTimeline; import com.esotericsoftware.spine.Animation.CurveTimeline; import com.esotericsoftware.spine.Animation.DrawOrderTimeline; import com.esotericsoftware.spine.Animation.EventTimeline; import com.esotericsoftware.spine.Animation.FfdTimeline; +import com.esotericsoftware.spine.Animation.IkConstraintTimeline; import com.esotericsoftware.spine.Animation.RotateTimeline; import com.esotericsoftware.spine.Animation.ScaleTimeline; import com.esotericsoftware.spine.Animation.Timeline; @@ -49,17 +60,6 @@ import com.esotericsoftware.spine.attachments.MeshAttachment; import com.esotericsoftware.spine.attachments.RegionAttachment; import com.esotericsoftware.spine.attachments.SkinnedMeshAttachment; -import com.badlogic.gdx.files.FileHandle; -import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.DataInput; -import com.badlogic.gdx.utils.FloatArray; -import com.badlogic.gdx.utils.IntArray; -import com.badlogic.gdx.utils.SerializationException; - -import java.io.IOException; - public class SkeletonBinary { static public final int TIMELINE_SCALE = 0; static public final int TIMELINE_ROTATE = 1; @@ -129,7 +129,18 @@ public class SkeletonBinary { boneData.inheritScale = input.readBoolean(); boneData.inheritRotation = input.readBoolean(); if (nonessential) Color.rgba8888ToColor(boneData.getColor(), input.readInt()); - skeletonData.getBones().add(boneData); + skeletonData.bones.add(boneData); + } + + // IK constraints. + for (int i = 0, n = input.readInt(true); i < n; i++) { + IkConstraintData ikConstraint = new IkConstraintData(input.readString()); + for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) + ikConstraint.bones.add(skeletonData.bones.get(input.readInt(true))); + ikConstraint.target = skeletonData.bones.get(input.readInt(true)); + ikConstraint.mix = input.readFloat(); + ikConstraint.bendDirection = input.readByte(); + skeletonData.ikConstraints.add(ikConstraint); } // Slots. @@ -396,6 +407,20 @@ public class SkeletonBinary { } } + // IK timelines. + for (int i = 0, n = input.readInt(true); i < n; i++) { + IkConstraintData ikConstraint = skeletonData.findIkConstraint(input.readString()); + int frameCount = input.readInt(true); + IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount); + timeline.setIkConstraintIndex(skeletonData.getIkConstraints().indexOf(ikConstraint, true)); + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readByte()); + if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[frameCount * 3 - 3]); + } + // FFD timelines. for (int i = 0, n = input.readInt(true); i < n; i++) { Skin skin = skeletonData.getSkins().get(input.readInt(true) + 1); diff --git a/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java b/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java index f61203b32..b26cfffff 100644 --- a/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java +++ b/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java @@ -36,6 +36,7 @@ import com.esotericsoftware.spine.Animation.CurveTimeline; import com.esotericsoftware.spine.Animation.DrawOrderTimeline; import com.esotericsoftware.spine.Animation.EventTimeline; import com.esotericsoftware.spine.Animation.FfdTimeline; +import com.esotericsoftware.spine.Animation.IkConstraintTimeline; import com.esotericsoftware.spine.Animation.RotateTimeline; import com.esotericsoftware.spine.Animation.ScaleTimeline; import com.esotericsoftware.spine.Animation.Timeline; @@ -48,7 +49,6 @@ import com.esotericsoftware.spine.attachments.BoundingBoxAttachment; import com.esotericsoftware.spine.attachments.MeshAttachment; import com.esotericsoftware.spine.attachments.RegionAttachment; import com.esotericsoftware.spine.attachments.SkinnedMeshAttachment; - import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.TextureAtlas; @@ -123,7 +123,7 @@ public class SkeletonJson { skeletonData.getBones().add(boneData); } - // IK. + // IK constraints. for (JsonValue ikMap = root.getChild("ik"); ikMap != null; ikMap = ikMap.next) { IkConstraintData ikConstraintData = new IkConstraintData(ikMap.getString("name")); @@ -381,6 +381,22 @@ public class SkeletonJson { } } + // IK timelines. + for (JsonValue ikMap = map.getChild("ik"); ikMap != null; ikMap = ikMap.next) { + IkConstraintData ikConstraint = skeletonData.findIkConstraint(ikMap.name); + IkConstraintTimeline timeline = new IkConstraintTimeline(ikMap.size); + timeline.setIkConstraintIndex(skeletonData.getIkConstraints().indexOf(ikConstraint, true)); + int frameIndex = 0; + for (JsonValue valueMap = ikMap.child; valueMap != null; valueMap = valueMap.next) { + timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat("mix"), + valueMap.getBoolean("bendPositive") ? 1 : -1); + readCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() * 3 - 3]); + } + // FFD timelines. for (JsonValue ffdMap = map.getChild("ffd"); ffdMap != null; ffdMap = ffdMap.next) { Skin skin = skeletonData.findSkin(ffdMap.name);