Updated IK constraints.

This commit is contained in:
NathanSweet 2014-08-30 11:18:24 +02:00
parent 059cc69a31
commit ed55a831d7
3 changed files with 70 additions and 30 deletions

View File

@ -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<Event> 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];
}
}
}

View File

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

View File

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