Added path constraint spacing, spacing mode, rotate mode.

This commit is contained in:
NathanSweet 2016-06-06 11:30:50 +02:00
parent b3fdaca019
commit 5cfa647ce2
6 changed files with 171 additions and 108 deletions

View File

@ -866,10 +866,11 @@ public class Animation {
} }
} }
// BOZO! - Separate into multiple timelines.
static public class PathConstraintTimeline extends CurveTimeline { static public class PathConstraintTimeline extends CurveTimeline {
static public final int ENTRIES = 5; static public final int ENTRIES = 5;
static private final int PREV_TIME = -5, PREV_POSITION = -4, PREV_ROTATE = -3, PREV_TRANSLATE = -2, PREV_SCALE = -1; static private final int PREV_TIME = -5, PREV_POSITION = -4, PREV_ROTATE = -3, PREV_TRANSLATE = -2;
static private final int POSITION = 1, ROTATE = 2, TRANSLATE = 3, SCALE = 4; static private final int POSITION = 1, ROTATE = 2, TRANSLATE = 3;
int pathConstraintIndex; int pathConstraintIndex;
@ -894,13 +895,12 @@ public class Animation {
} }
/** Sets the time, position, and mixes of the specified keyframe. */ /** Sets the time, position, and mixes of the specified keyframe. */
public void setFrame (int frameIndex, float time, float position, float rotateMix, float translateMix, float scaleMix) { public void setFrame (int frameIndex, float time, float position, float rotateMix, float translateMix) {
frameIndex *= ENTRIES; frameIndex *= ENTRIES;
frames[frameIndex] = time; frames[frameIndex] = time;
frames[frameIndex + POSITION] = position; frames[frameIndex + POSITION] = position;
frames[frameIndex + ROTATE] = rotateMix; frames[frameIndex + ROTATE] = rotateMix;
frames[frameIndex + TRANSLATE] = translateMix; frames[frameIndex + TRANSLATE] = translateMix;
frames[frameIndex + SCALE] = scaleMix;
} }
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha) { public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha) {
@ -914,7 +914,6 @@ public class Animation {
constraint.position += (frames[i + PREV_POSITION] - constraint.position) * alpha; constraint.position += (frames[i + PREV_POSITION] - constraint.position) * alpha;
constraint.rotateMix += (frames[i + PREV_ROTATE] - constraint.rotateMix) * alpha; constraint.rotateMix += (frames[i + PREV_ROTATE] - constraint.rotateMix) * alpha;
constraint.translateMix += (frames[i + PREV_TRANSLATE] - constraint.translateMix) * alpha; constraint.translateMix += (frames[i + PREV_TRANSLATE] - constraint.translateMix) * alpha;
constraint.scaleMix += (frames[i + PREV_SCALE] - constraint.scaleMix) * alpha;
return; return;
} }
@ -923,7 +922,6 @@ public class Animation {
float position = frames[frame + PREV_POSITION]; float position = frames[frame + PREV_POSITION];
float rotate = frames[frame + PREV_ROTATE]; float rotate = frames[frame + PREV_ROTATE];
float translate = frames[frame + PREV_TRANSLATE]; float translate = frames[frame + PREV_TRANSLATE];
float scale = frames[frame + PREV_SCALE];
float frameTime = frames[frame]; float frameTime = frames[frame];
float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
@ -931,7 +929,6 @@ public class Animation {
constraint.rotateMix += (rotate + (frames[frame + ROTATE] - rotate) * percent - constraint.rotateMix) * alpha; constraint.rotateMix += (rotate + (frames[frame + ROTATE] - rotate) * percent - constraint.rotateMix) * alpha;
constraint.translateMix += (translate + (frames[frame + TRANSLATE] - translate) * percent - constraint.translateMix) constraint.translateMix += (translate + (frames[frame + TRANSLATE] - translate) * percent - constraint.translateMix)
* alpha; * alpha;
constraint.scaleMix += (scale + (frames[frame + SCALE] - scale) * percent - constraint.scaleMix) * alpha;
} }
} }
} }

View File

@ -16,18 +16,18 @@ public class PathConstraint implements Updatable {
final PathConstraintData data; final PathConstraintData data;
final Array<Bone> bones; final Array<Bone> bones;
Slot target; Slot target;
float position, rotateMix, translateMix, scaleMix; float position, spacing, rotateMix, translateMix;
final FloatArray spacing = new FloatArray(), positions = new FloatArray(), temp = new FloatArray(); final FloatArray spaces = new FloatArray(), positions = new FloatArray(), temp = new FloatArray();
public PathConstraint (PathConstraintData data, Skeleton skeleton) { public PathConstraint (PathConstraintData data, Skeleton skeleton) {
if (data == null) throw new IllegalArgumentException("data cannot be null."); if (data == null) throw new IllegalArgumentException("data cannot be null.");
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
this.data = data; this.data = data;
position = data.position; position = data.position;
spacing = data.spacing;
rotateMix = data.rotateMix; rotateMix = data.rotateMix;
translateMix = data.translateMix; translateMix = data.translateMix;
scaleMix = data.scaleMix;
bones = new Array(data.bones.size); bones = new Array(data.bones.size);
for (BoneData boneData : data.bones) for (BoneData boneData : data.bones)
bones.add(skeleton.findBone(boneData.name)); bones.add(skeleton.findBone(boneData.name));
@ -44,9 +44,9 @@ public class PathConstraint implements Updatable {
bones.add(skeleton.bones.get(bone.data.index)); bones.add(skeleton.bones.get(bone.data.index));
target = skeleton.slots.get(constraint.target.data.index); target = skeleton.slots.get(constraint.target.data.index);
position = constraint.position; position = constraint.position;
spacing = constraint.spacing;
rotateMix = constraint.rotateMix; rotateMix = constraint.rotateMix;
translateMix = constraint.translateMix; translateMix = constraint.translateMix;
scaleMix = constraint.scaleMix;
} }
public void apply () { public void apply () {
@ -57,19 +57,21 @@ public class PathConstraint implements Updatable {
Attachment attachment = target.getAttachment(); Attachment attachment = target.getAttachment();
if (!(attachment instanceof PathAttachment)) return; if (!(attachment instanceof PathAttachment)) return;
float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix; float rotateMix = this.rotateMix, translateMix = this.translateMix;
boolean translate = translateMix > 0, rotate = rotateMix > 0, scale = scaleMix > 0; RotateMode rotateMode = data.rotateMode;
if (!translate && !rotate && !scale) return; SpacingMode spacingMode = data.spacingMode;
boolean translate = translateMix > 0, rotate = rotateMix > 0;
if (!translate && !rotate) return;
PathAttachment path = (PathAttachment)attachment; PathAttachment path = (PathAttachment)attachment;
FloatArray spacing = this.spacing; FloatArray spacesArray = this.spaces;
spacing.clear(); spacesArray.clear();
spacing.add(0); spacesArray.add(0);
Array<Bone> bones = this.bones; Array<Bone> bones = this.bones;
int boneCount = bones.size; int boneCount = bones.size;
if (boneCount == 1) { if (boneCount == 1) {
float[] positions = computeWorldPositions(path, rotate); float[] positions = computeWorldPositions(path, rotate, spacingMode == SpacingMode.percent);
Bone bone = bones.first(); Bone bone = bones.first();
bone.worldX += (positions[0] - bone.worldX) * translateMix; bone.worldX += (positions[0] - bone.worldX) * translateMix;
bone.worldY += (positions[1] - bone.worldY) * translateMix; bone.worldY += (positions[1] - bone.worldY) * translateMix;
@ -89,42 +91,59 @@ public class PathConstraint implements Updatable {
return; return;
} }
for (int i = 0; i < boneCount; i++) { float[] spaces;
Bone bone = bones.get(i); float spacing = this.spacing;
float length = bone.data.length, x = length * bone.a, y = length * bone.c; boolean scale = rotateMode == RotateMode.chainScale, lengthMode = spacingMode == SpacingMode.length;
spacing.add((float)Math.sqrt(x * x + y * y)); if (!scale || lengthMode) {
spaces = spacesArray.setSize(1 + boneCount * 2);
for (int i = 0; i < boneCount;) {
Bone bone = bones.get(i++);
float length = bone.data.length, x = length * bone.a, y = length * bone.c;
length = (float)Math.sqrt(x * x + y * y);
spaces[i] = lengthMode ? Math.max(0, length + spacing) : spacing;
spaces[i + boneCount] = length;
}
} else {
spaces = spacesArray.setSize(1 + boneCount);
for (int i = 1; i <= boneCount; i++)
spaces[i] = spacing;
} }
float[] positions = computeWorldPositions(path, false);
boolean tangents = rotateMode == RotateMode.tangent;
float[] positions = computeWorldPositions(path, tangents, spacingMode == SpacingMode.percent);
float boneX = positions[0], boneY = positions[1], offsetRotation = data.offsetRotation; float boneX = positions[0], boneY = positions[1], offsetRotation = data.offsetRotation;
for (int i = 0, p = 2; i < boneCount; i++, p += 2) { boolean tip = rotateMode == RotateMode.chain && offsetRotation == 0;
Bone bone = bones.get(i); for (int i = 0, p = 3; i < boneCount; p += 3) {
Bone bone = bones.get(i++);
bone.worldX += (boneX - bone.worldX) * translateMix; bone.worldX += (boneX - bone.worldX) * translateMix;
bone.worldY += (boneY - bone.worldY) * translateMix; bone.worldY += (boneY - bone.worldY) * translateMix;
float x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY; float x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY;
if (scale) { if (scale) {
float space = spacing.get(i + 1); float space = spaces[i + boneCount];
if (space != 0) { if (space != 0) {
float s = ((float)Math.sqrt(dx * dx + dy * dy) / space - 1) * scaleMix + 1; float s = ((float)Math.sqrt(dx * dx + dy * dy) / space - 1) * rotateMix + 1;
bone.a *= s; bone.a *= s;
bone.c *= s; bone.c *= s;
} }
} }
if (!rotate) { boneX = x;
boneX = x; boneY = y;
boneY = y; if (rotate) {
} else { float a = bone.a, b = bone.b, c = bone.c, d = bone.d, r, cos, sin;
float a = bone.a, b = bone.b, c = bone.c, d = bone.d; if (tangents)
float r = atan2(dy, dx) - atan2(c, a) + offsetRotation * degRad, cos, sin; r = positions[p - 1];
if (offsetRotation != 0) { else if (spaces[i] == 0)
boneX = x; r = positions[p + 2];
boneY = y; else
} else { // Mix between on path and at tip. r = atan2(dy, dx);
r -= atan2(c, a) - offsetRotation * degRad;
if (tip) {
cos = cos(r); cos = cos(r);
sin = sin(r); sin = sin(r);
float length = bone.data.length; float length = bone.data.length;
boneX = x + (length * (cos * a - sin * c) - dx) * rotateMix; boneX += (length * (cos * a - sin * c) - dx) * rotateMix;
boneY = y + (length * (sin * a + cos * c) - dy) * rotateMix; boneY += (length * (sin * a + cos * c) - dy) * rotateMix;
} }
if (r > PI) if (r > PI)
r -= PI2; r -= PI2;
@ -141,45 +160,46 @@ public class PathConstraint implements Updatable {
} }
} }
private float[] computeWorldPositions (PathAttachment path, boolean tangents) { private float[] computeWorldPositions (PathAttachment path, boolean tangents, boolean percentSpacing) {
Slot target = this.target; Slot target = this.target;
float position = this.position; float position = this.position;
int spacingCount = spacing.size; int verticesLength = path.getWorldVerticesLength(), curves = verticesLength / 6, lastCurve = NONE;
float[] spacing = this.spacing.items; int spacesCount = spaces.size;
FloatArray positions = this.positions; float[] spaces = this.spaces.items, out = this.positions.setSize(spacesCount * 3), temp;
positions.clear();
boolean closed = path.getClosed(); boolean closed = path.getClosed();
int verticesLength = path.getWorldVerticesLength(), curves = verticesLength / 6;
float[] temp;
int lastCurve = NONE;
// New.
if (!path.getConstantSpeed()) { if (!path.getConstantSpeed()) {
if (!closed) curves--;
float[] curveLengths = path.getCurveLengths().items;
float pathLength = path.getTotalLength(); float pathLength = path.getTotalLength();
position *= pathLength; position *= pathLength;
if (percentSpacing) {
for (int i = 0; i < spacesCount; i++)
spaces[i] *= pathLength;
}
curves--;
float[] curveLengths = path.getCurveLengths().items;
temp = this.temp.setSize(8); temp = this.temp.setSize(8);
for (int i = 0, curve = 0; i < spacingCount; i++) { for (int i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) {
position += spacing[i]; float space = spaces[i];
position += space;
float p = position; float p = position;
if (closed) { if (closed) {
p %= 1; p %= pathLength;
if (p < 0) p += 1; if (p < 0) p += pathLength;
curve = 0;
} else if (p < 0) { } else if (p < 0) {
if (lastCurve != BEFORE) { if (lastCurve != BEFORE) {
lastCurve = BEFORE; lastCurve = BEFORE;
path.computeWorldVertices(target, 2, 4, temp, 0); path.computeWorldVertices(target, 2, 4, temp, 0);
} }
addBeforePosition(p, temp, 0, positions, tangents); addBeforePosition(p, temp, 0, out, o);
continue; continue;
} else if (p > pathLength) { } else if (p > pathLength) {
if (lastCurve != AFTER) { if (lastCurve != AFTER) {
lastCurve = AFTER; lastCurve = AFTER;
path.computeWorldVertices(target, verticesLength - 6, 4, temp, 0); path.computeWorldVertices(target, verticesLength - 6, 4, temp, 0);
} }
addAfterPosition(p - pathLength, temp, 0, positions, tangents); addAfterPosition(p - pathLength, temp, 0, out, o);
continue; continue;
} }
@ -198,15 +218,16 @@ public class PathConstraint implements Updatable {
if (curve != lastCurve) { if (curve != lastCurve) {
lastCurve = curve; lastCurve = curve;
if (closed && curve == curves - 1) { if (closed && curve == curves) {
path.computeWorldVertices(target, verticesLength - 4, 4, temp, 0); path.computeWorldVertices(target, verticesLength - 4, 4, temp, 0);
path.computeWorldVertices(target, 0, 4, temp, 4); path.computeWorldVertices(target, 0, 4, temp, 4);
} else } else
path.computeWorldVertices(target, curve * 6 + 2, 8, temp, 0); path.computeWorldVertices(target, curve * 6 + 2, 8, temp, 0);
} }
addCurvePosition(p, temp[0], temp[1], temp[2], temp[3], temp[4], temp[5], temp[6], temp[7], positions, tangents); addCurvePosition(p, temp[0], temp[1], temp[2], temp[3], temp[4], temp[5], temp[6], temp[7], out, o,
tangents || (space == 0 && i > 0));
} }
return positions.items; return out;
} }
// World vertices, verticesStart to verticesStart + verticesLength - 1. // World vertices, verticesStart to verticesStart + verticesLength - 1.
@ -261,20 +282,26 @@ public class PathConstraint implements Updatable {
y1 = y2; y1 = y2;
} }
position *= pathLength; position *= pathLength;
if (percentSpacing) {
for (int i = 0; i < spacesCount; i++)
spaces[i] *= pathLength;
}
float curveLength = 0; float curveLength = 0;
for (int i = 0, curve = 10, segment = 0; i < spacingCount; i++) { for (int i = 0, o = 0, curve = 10, segment = 0; i < spacesCount; i++, o += 3) {
position += spacing[i]; float space = spaces[i];
position += space;
float p = position; float p = position;
if (closed) { if (closed) {
p %= pathLength; p %= pathLength;
if (p < 0) p += pathLength; if (p < 0) p += pathLength;
curve = 10;
} else if (p < 0) { } else if (p < 0) {
addBeforePosition(p, temp, verticesStart, positions, tangents); addBeforePosition(p, temp, verticesStart, out, o);
continue; continue;
} else if (p > pathLength) { } else if (p > pathLength) {
addAfterPosition(p - pathLength, temp, verticesStart + verticesLength - 4, positions, tangents); addAfterPosition(p - pathLength, temp, verticesStart + verticesLength - 4, out, o);
continue; continue;
} }
@ -346,35 +373,35 @@ public class PathConstraint implements Updatable {
break; break;
} }
addCurvePosition(p, x1, y1, cx1, cy1, cx2, cy2, x2, y2, positions, tangents); addCurvePosition(p, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || (space == 0 && i > 0));
} }
return positions.items; return out;
} }
private void addBeforePosition (float p, float[] temp, int i, FloatArray out, boolean tangents) { private void addBeforePosition (float p, float[] temp, int i, float[] out, int o) {
float x1 = temp[i], y1 = temp[i + 1], dx = temp[i + 2] - x1, dy = temp[i + 3] - y1, r = atan2(dy, dx); float x1 = temp[i], y1 = temp[i + 1], dx = temp[i + 2] - x1, dy = temp[i + 3] - y1, r = atan2(dy, dx);
out.add(x1 + p * cos(r)); out[o] = x1 + p * cos(r);
out.add(y1 + p * sin(r)); out[o + 1] = y1 + p * sin(r);
if (tangents) out.add(r + PI); out[o + 2] = r;
} }
private void addAfterPosition (float p, float[] temp, int i, FloatArray out, boolean tangents) { private void addAfterPosition (float p, float[] temp, int i, float[] out, int o) {
float x1 = temp[i + 2], y1 = temp[i + 3], dx = x1 - temp[i], dy = y1 - temp[i + 1], r = atan2(dy, dx); float x1 = temp[i + 2], y1 = temp[i + 3], dx = x1 - temp[i], dy = y1 - temp[i + 1], r = atan2(dy, dx);
out.add(x1 + p * cos(r)); out[o] = x1 + p * cos(r);
out.add(y1 + p * sin(r)); out[o + 1] = y1 + p * sin(r);
if (tangents) out.add(r + PI); out[o + 2] = r;
} }
private void addCurvePosition (float p, float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2, private void addCurvePosition (float p, float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2,
FloatArray out, boolean tangents) { float[] out, int o, boolean tangents) {
if (p == 0) p = 0.0001f; if (p == 0) p = 0.0001f;
float tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u; float tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u;
float ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p; float ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p;
float x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt; float x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt;
out.add(x); out[o] = x;
out.add(y); out[o + 1] = y;
if (tangents) out.add(atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt))); if (tangents) out[o + 2] = atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt));
} }
public float getPosition () { public float getPosition () {
@ -385,6 +412,14 @@ public class PathConstraint implements Updatable {
this.position = position; this.position = position;
} }
public float getSpacing () {
return spacing;
}
public void setSpacing (float spacing) {
this.spacing = spacing;
}
public float getRotateMix () { public float getRotateMix () {
return rotateMix; return rotateMix;
} }
@ -401,14 +436,6 @@ public class PathConstraint implements Updatable {
this.translateMix = translateMix; this.translateMix = translateMix;
} }
public float getScaleMix () {
return scaleMix;
}
public void setScaleMix (float scaleMix) {
this.scaleMix = scaleMix;
}
public Array<Bone> getBones () { public Array<Bone> getBones () {
return bones; return bones;
} }
@ -428,4 +455,16 @@ public class PathConstraint implements Updatable {
public String toString () { public String toString () {
return data.name; return data.name;
} }
static public enum RotateMode {
tangent, chain, chainScale;
static public final RotateMode[] values = RotateMode.values();
}
static public enum SpacingMode {
length, fixed, percent;
static public final SpacingMode[] values = SpacingMode.values();
}
} }

View File

@ -2,13 +2,17 @@
package com.esotericsoftware.spine; package com.esotericsoftware.spine;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
import com.esotericsoftware.spine.PathConstraint.RotateMode;
import com.esotericsoftware.spine.PathConstraint.SpacingMode;
public class PathConstraintData { public class PathConstraintData {
final String name; final String name;
final Array<BoneData> bones = new Array(); final Array<BoneData> bones = new Array();
SlotData target; SlotData target;
float position, rotateMix, translateMix, scaleMix; SpacingMode spacingMode;
RotateMode rotateMode;
float offsetRotation; float offsetRotation;
float position, spacing, rotateMix, translateMix;
public PathConstraintData (String name) { public PathConstraintData (String name) {
if (name == null) throw new IllegalArgumentException("name cannot be null."); if (name == null) throw new IllegalArgumentException("name cannot be null.");
@ -27,6 +31,30 @@ public class PathConstraintData {
this.target = target; this.target = target;
} }
public SpacingMode getSpacingMode () {
return spacingMode;
}
public void setSpacingMode (SpacingMode spacingMode) {
this.spacingMode = spacingMode;
}
public RotateMode getRotateMode () {
return rotateMode;
}
public void setRotateMode (RotateMode rotateMode) {
this.rotateMode = rotateMode;
}
public float getOffsetRotation () {
return offsetRotation;
}
public void setOffsetRotation (float offsetRotation) {
this.offsetRotation = offsetRotation;
}
public float getPosition () { public float getPosition () {
return position; return position;
} }
@ -35,6 +63,14 @@ public class PathConstraintData {
this.position = position; this.position = position;
} }
public float getSpacing () {
return spacing;
}
public void setSpacing (float spacing) {
this.spacing = spacing;
}
public float getRotateMix () { public float getRotateMix () {
return rotateMix; return rotateMix;
} }
@ -51,22 +87,6 @@ public class PathConstraintData {
this.translateMix = translateMix; this.translateMix = translateMix;
} }
public float getScaleMix () {
return scaleMix;
}
public void setScaleMix (float scaleMix) {
this.scaleMix = scaleMix;
}
public float getOffsetRotation () {
return offsetRotation;
}
public void setOffsetRotation (float offsetRotation) {
this.offsetRotation = offsetRotation;
}
public String getName () { public String getName () {
return name; return name;
} }

View File

@ -294,9 +294,9 @@ public class Skeleton {
PathConstraint constraint = pathConstraints.get(i); PathConstraint constraint = pathConstraints.get(i);
PathConstraintData data = constraint.data; PathConstraintData data = constraint.data;
constraint.position = data.position; constraint.position = data.position;
constraint.spacing = data.spacing;
constraint.rotateMix = data.rotateMix; constraint.rotateMix = data.rotateMix;
constraint.translateMix = data.translateMix; constraint.translateMix = data.translateMix;
constraint.scaleMix = data.scaleMix;
} }
} }

View File

@ -55,6 +55,8 @@ import com.esotericsoftware.spine.Animation.ShearTimeline;
import com.esotericsoftware.spine.Animation.Timeline; import com.esotericsoftware.spine.Animation.Timeline;
import com.esotericsoftware.spine.Animation.TransformConstraintTimeline; import com.esotericsoftware.spine.Animation.TransformConstraintTimeline;
import com.esotericsoftware.spine.Animation.TranslateTimeline; import com.esotericsoftware.spine.Animation.TranslateTimeline;
import com.esotericsoftware.spine.PathConstraint.RotateMode;
import com.esotericsoftware.spine.PathConstraint.SpacingMode;
import com.esotericsoftware.spine.SkeletonJson.LinkedMesh; import com.esotericsoftware.spine.SkeletonJson.LinkedMesh;
import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader; import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
import com.esotericsoftware.spine.attachments.Attachment; import com.esotericsoftware.spine.attachments.Attachment;
@ -216,9 +218,11 @@ public class SkeletonBinary {
data.target = skeletonData.slots.get(input.readInt(true)); data.target = skeletonData.slots.get(input.readInt(true));
data.offsetRotation = input.readFloat(); data.offsetRotation = input.readFloat();
data.position = input.readFloat(); data.position = input.readFloat();
data.spacing = input.readFloat();
data.spacingMode = SpacingMode.values[input.readInt(true)];
data.rotateMode = RotateMode.values[input.readInt(true)];
data.rotateMix = input.readFloat(); data.rotateMix = input.readFloat();
data.translateMix = input.readFloat(); data.translateMix = input.readFloat();
data.scaleMix = input.readFloat();
skeletonData.pathConstraints.add(data); skeletonData.pathConstraints.add(data);
} }
@ -590,8 +594,7 @@ public class SkeletonBinary {
PathConstraintTimeline timeline = new PathConstraintTimeline(frameCount); PathConstraintTimeline timeline = new PathConstraintTimeline(frameCount);
timeline.pathConstraintIndex = index; timeline.pathConstraintIndex = index;
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) {
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat(), timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat());
input.readFloat());
if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline);
} }
timelines.add(timeline); timelines.add(timeline);

View File

@ -54,6 +54,8 @@ import com.esotericsoftware.spine.Animation.ShearTimeline;
import com.esotericsoftware.spine.Animation.Timeline; import com.esotericsoftware.spine.Animation.Timeline;
import com.esotericsoftware.spine.Animation.TransformConstraintTimeline; import com.esotericsoftware.spine.Animation.TransformConstraintTimeline;
import com.esotericsoftware.spine.Animation.TranslateTimeline; import com.esotericsoftware.spine.Animation.TranslateTimeline;
import com.esotericsoftware.spine.PathConstraint.RotateMode;
import com.esotericsoftware.spine.PathConstraint.SpacingMode;
import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader; import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
import com.esotericsoftware.spine.attachments.Attachment; import com.esotericsoftware.spine.attachments.Attachment;
import com.esotericsoftware.spine.attachments.AttachmentLoader; import com.esotericsoftware.spine.attachments.AttachmentLoader;
@ -198,9 +200,11 @@ public class SkeletonJson {
data.offsetRotation = constraintMap.getFloat("rotation", 0); data.offsetRotation = constraintMap.getFloat("rotation", 0);
data.position = constraintMap.getFloat("position", 0); data.position = constraintMap.getFloat("position", 0);
data.spacing = constraintMap.getFloat("spacing", 0);
data.spacingMode = SpacingMode.valueOf(constraintMap.getString("spacingMode", "length"));
data.rotateMode = RotateMode.valueOf(constraintMap.getString("rotateMode", "tangent"));
data.rotateMix = constraintMap.getFloat("rotateMix", 1); data.rotateMix = constraintMap.getFloat("rotateMix", 1);
data.translateMix = constraintMap.getFloat("translateMix", 1); data.translateMix = constraintMap.getFloat("translateMix", 1);
data.scaleMix = constraintMap.getFloat("scaleMix", 1);
skeletonData.pathConstraints.add(data); skeletonData.pathConstraints.add(data);
} }
@ -509,7 +513,7 @@ public class SkeletonJson {
int frameIndex = 0; int frameIndex = 0;
for (JsonValue valueMap = constraintMap.child; valueMap != null; valueMap = valueMap.next) { for (JsonValue valueMap = constraintMap.child; valueMap != null; valueMap = valueMap.next) {
timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat("scaleMix", 1), timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat("scaleMix", 1),
valueMap.getFloat("rotateMix", 1), valueMap.getFloat("translateMix", 1), valueMap.getFloat("scaleMix", 1)); valueMap.getFloat("rotateMix", 1), valueMap.getFloat("translateMix", 1));
readCurve(valueMap, timeline, frameIndex); readCurve(valueMap, timeline, frameIndex);
frameIndex++; frameIndex++;
} }