diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java
index 70bc5a541..2b7289986 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java
@@ -2312,8 +2312,12 @@ public class Animation {
}
}
- /** Changes a transform constraint's {@link PathConstraint#getMixRotate()} and {@link PathConstraint#getMixTranslate()}. */
- static public class PathConstraintMixTimeline extends CurveTimeline2 {
+ /** Changes a transform constraint's {@link PathConstraint#getMixRotate()}, {@link PathConstraint#getMixX()}, and
+ * {@link PathConstraint#getMixY()}. */
+ static public class PathConstraintMixTimeline extends CurveTimeline {
+ static public final int ENTRIES = 4;
+ static private final int ROTATE = 1, X = 2, Y = 3;
+
final int pathConstraintIndex;
public PathConstraintMixTimeline (int frameCount, int bezierCount, int pathConstraintIndex) {
@@ -2321,12 +2325,27 @@ public class Animation {
this.pathConstraintIndex = pathConstraintIndex;
}
+ public int getFrameEntries () {
+ return ENTRIES;
+ }
+
/** The index of the path constraint slot in {@link Skeleton#getPathConstraints()} that will be changed when this timeline
* is applied. */
public int getPathConstraintIndex () {
return pathConstraintIndex;
}
+ /** Sets the time and color for the specified frame.
+ * @param frame Between 0 and frameCount, inclusive.
+ * @param time The frame time in seconds. */
+ public void setFrame (int frame, float time, float mixRotate, float mixX, float mixY) {
+ frame <<= 2;
+ frames[frame] = time;
+ frames[frame + ROTATE] = mixRotate;
+ frames[frame + X] = mixX;
+ frames[frame + Y] = mixY;
+ }
+
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array events, float alpha, MixBlend blend,
MixDirection direction) {
@@ -2338,41 +2357,50 @@ public class Animation {
switch (blend) {
case setup:
constraint.mixRotate = constraint.data.mixRotate;
- constraint.mixTranslate = constraint.data.mixTranslate;
+ constraint.mixX = constraint.data.mixX;
+ constraint.mixY = constraint.data.mixY;
return;
case first:
constraint.mixRotate += (constraint.data.mixRotate - constraint.mixRotate) * alpha;
- constraint.mixTranslate += (constraint.data.mixTranslate - constraint.mixTranslate) * alpha;
+ constraint.mixX += (constraint.data.mixX - constraint.mixX) * alpha;
+ constraint.mixY += (constraint.data.mixY - constraint.mixY) * alpha;
}
return;
}
- float rotate, translate;
- int i = search(frames, time, ENTRIES), curveType = (int)curves[i / ENTRIES];
+ float rotate, x, y;
+ int i = search(frames, time, ENTRIES), curveType = (int)curves[i >> 2];
switch (curveType) {
case LINEAR:
float before = frames[i];
- rotate = frames[i + VALUE1];
- translate = frames[i + VALUE2];
+ rotate = frames[i + ROTATE];
+ x = frames[i + X];
+ y = frames[i + Y];
float t = (time - before) / (frames[i + ENTRIES] - before);
- rotate += (frames[i + ENTRIES + VALUE1] - rotate) * t;
- translate += (frames[i + ENTRIES + VALUE2] - translate) * t;
+ rotate += (frames[i + ENTRIES + ROTATE] - rotate) * t;
+ x += (frames[i + ENTRIES + X] - x) * t;
+ y += (frames[i + ENTRIES + Y] - y) * t;
break;
case STEPPED:
- rotate = frames[i + VALUE1];
- translate = frames[i + VALUE2];
+ rotate = frames[i + ROTATE];
+ x = frames[i + X];
+ y = frames[i + Y];
break;
default:
- rotate = getBezierValue(time, i, VALUE1, curveType - BEZIER);
- translate = getBezierValue(time, i, VALUE2, curveType + BEZIER_SIZE - BEZIER);
+ rotate = getBezierValue(time, i, ROTATE, curveType - BEZIER);
+ x = getBezierValue(time, i, X, curveType + BEZIER_SIZE - BEZIER);
+ y = getBezierValue(time, i, Y, curveType + BEZIER_SIZE * 2 - BEZIER);
}
if (blend == setup) {
- constraint.mixRotate = constraint.data.mixRotate + (rotate - constraint.data.mixRotate) * alpha;
- constraint.mixTranslate = constraint.data.mixTranslate + (translate - constraint.data.mixTranslate) * alpha;
+ PathConstraintData data = constraint.data;
+ constraint.mixRotate = data.mixRotate + (rotate - data.mixRotate) * alpha;
+ constraint.mixX = data.mixX + (x - data.mixX) * alpha;
+ constraint.mixY = data.mixY + (y - data.mixY) * alpha;
} else {
constraint.mixRotate += (rotate - constraint.mixRotate) * alpha;
- constraint.mixTranslate += (translate - constraint.mixTranslate) * alpha;
+ constraint.mixX += (x - constraint.mixX) * alpha;
+ constraint.mixY += (y - constraint.mixY) * alpha;
}
}
}
diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java
index b5cb5eab8..23f27d74a 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java
@@ -50,7 +50,7 @@ public class PathConstraint implements Updatable {
final PathConstraintData data;
final Array bones;
Slot target;
- float position, spacing, mixRotate, mixTranslate;
+ float position, spacing, mixRotate, mixX, mixY;
boolean active;
@@ -69,7 +69,8 @@ public class PathConstraint implements Updatable {
position = data.position;
spacing = data.spacing;
mixRotate = data.mixRotate;
- mixTranslate = data.mixTranslate;
+ mixX = data.mixX;
+ mixY = data.mixY;
}
/** Copy constructor. */
@@ -84,7 +85,8 @@ public class PathConstraint implements Updatable {
position = constraint.position;
spacing = constraint.spacing;
mixRotate = constraint.mixRotate;
- mixTranslate = constraint.mixTranslate;
+ mixX = constraint.mixX;
+ mixY = constraint.mixY;
}
/** Applies the constraint to the constrained bones. */
@@ -92,9 +94,8 @@ public class PathConstraint implements Updatable {
Attachment attachment = target.attachment;
if (!(attachment instanceof PathAttachment)) return;
- float mixRotate = this.mixRotate, mixTranslate = this.mixTranslate;
- boolean translate = mixTranslate > 0, rotate = mixRotate > 0;
- if (!translate && !rotate) return;
+ float mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY;
+ if (mixRotate == 0 && mixX == 0 && mixY == 0) return;
PathConstraintData data = this.data;
boolean percentSpacing = data.spacingMode == SpacingMode.percent;
@@ -145,8 +146,8 @@ public class PathConstraint implements Updatable {
}
for (int i = 0, p = 3; i < boneCount; i++, p += 3) {
Bone bone = (Bone)bones[i];
- bone.worldX += (boneX - bone.worldX) * mixTranslate;
- bone.worldY += (boneY - bone.worldY) * mixTranslate;
+ bone.worldX += (boneX - bone.worldX) * mixX;
+ bone.worldY += (boneY - bone.worldY) * mixY;
float x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY;
if (scale) {
float length = lengths[i];
@@ -158,7 +159,7 @@ public class PathConstraint implements Updatable {
}
boneX = x;
boneY = y;
- if (rotate) {
+ if (mixRotate > 0) {
float a = bone.a, b = bone.b, c = bone.c, d = bone.d, r, cos, sin;
if (tangents)
r = positions[p - 1];
@@ -473,13 +474,22 @@ public class PathConstraint implements Updatable {
this.mixRotate = mixRotate;
}
- /** A percentage (0-1) that controls the mix between the constrained and unconstrained translation. */
- public float getMixTranslate () {
- return mixTranslate;
+ /** A percentage (0-1) that controls the mix between the constrained and unconstrained translation X. */
+ public float getMixX () {
+ return mixX;
}
- public void setMixTranslate (float mixTranslate) {
- this.mixTranslate = mixTranslate;
+ public void setMixX (float mixX) {
+ this.mixX = mixX;
+ }
+
+ /** A percentage (0-1) that controls the mix between the constrained and unconstrained translation Y. */
+ public float getMixY () {
+ return mixY;
+ }
+
+ public void setMixY (float mixY) {
+ this.mixY = mixY;
}
/** The bones that will be modified by this path constraint. */
diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintData.java
index 54e6e5a5c..a24bd4087 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintData.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintData.java
@@ -41,7 +41,7 @@ public class PathConstraintData extends ConstraintData {
SpacingMode spacingMode;
RotateMode rotateMode;
float offsetRotation;
- float position, spacing, mixRotate, mixTranslate;
+ float position, spacing, mixRotate, mixX, mixY;
public PathConstraintData (String name) {
super(name);
@@ -128,13 +128,22 @@ public class PathConstraintData extends ConstraintData {
this.mixRotate = mixRotate;
}
- /** A percentage (0-1) that controls the mix between the constrained and unconstrained translation. */
- public float getMixTranslate () {
- return mixTranslate;
+ /** A percentage (0-1) that controls the mix between the constrained and unconstrained translation X. */
+ public float getMixX () {
+ return mixX;
}
- public void setMixTranslate (float mixTranslate) {
- this.mixTranslate = mixTranslate;
+ public void setMixX (float mixX) {
+ this.mixX = mixX;
+ }
+
+ /** A percentage (0-1) that controls the mix between the constrained and unconstrained translation Y. */
+ public float getMixY () {
+ return mixY;
+ }
+
+ public void setMixY (float mixY) {
+ this.mixY = mixY;
}
/** Controls how the first bone is positioned along the path.
diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java
index 12240d101..5aa107e9c 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java
@@ -420,7 +420,8 @@ public class Skeleton {
constraint.position = data.position;
constraint.spacing = data.spacing;
constraint.mixRotate = data.mixRotate;
- constraint.mixTranslate = data.mixTranslate;
+ constraint.mixX = data.mixX;
+ constraint.mixY = data.mixY;
}
}
diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java
index df2b246ab..3decfe576 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java
@@ -267,7 +267,8 @@ public class SkeletonBinary extends SkeletonLoader {
data.spacing = input.readFloat();
if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) data.spacing *= scale;
data.mixRotate = input.readFloat();
- data.mixTranslate = input.readFloat();
+ data.mixX = input.readFloat();
+ data.mixY = input.readFloat();
o[i] = data;
}
@@ -859,8 +860,29 @@ public class SkeletonBinary extends SkeletonLoader {
data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed ? scale : 1));
break;
case PATH_MIX:
- timelines
- .add(readTimeline(input, new PathConstraintMixTimeline(input.readInt(true), input.readInt(true), index), 1));
+ PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(input.readInt(true), input.readInt(true),
+ index);
+ float time = input.readFloat(), mixRotate = input.readFloat(), mixX = input.readFloat(), mixY = input.readFloat();
+ for (int frame = 0, bezier = 0, frameLast = nn - 1;; frame++) {
+ timeline.setFrame(frame, time, mixRotate, mixX, mixY);
+ if (frame == frameLast) break;
+ float time2 = input.readFloat(), mixRotate2 = input.readFloat(), mixX2 = input.readFloat(),
+ mixY2 = input.readFloat();
+ switch (input.readByte()) {
+ case CURVE_STEPPED:
+ timeline.setStepped(frame);
+ break;
+ case CURVE_BEZIER:
+ setBezier(input, timeline, bezier++, frame, 0, time, time2, mixRotate, mixRotate2, 1);
+ setBezier(input, timeline, bezier++, frame, 1, time, time2, mixX, mixX2, 1);
+ setBezier(input, timeline, bezier++, frame, 2, time, time2, mixY, mixY2, 1);
+ }
+ time = time2;
+ mixRotate = mixRotate2;
+ mixX = mixX2;
+ mixY = mixY2;
+ }
+ timelines.add(timeline);
}
}
}
diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java
index c37408fd8..1dcd9c41c 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java
@@ -261,7 +261,8 @@ public class SkeletonJson extends SkeletonLoader {
data.spacing = constraintMap.getFloat("spacing", 0);
if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) data.spacing *= scale;
data.mixRotate = constraintMap.getFloat("mixRotate", 1);
- data.mixTranslate = constraintMap.getFloat("mixTranslate", 1);
+ data.mixX = constraintMap.getFloat("mixX", 1);
+ data.mixY = constraintMap.getFloat("mixY", 1);
skeletonData.pathConstraints.add(data);
}
@@ -819,8 +820,33 @@ public class SkeletonJson extends SkeletonLoader {
timelines.add(readTimeline(keyMap, timeline, 0,
data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed ? scale : 1));
} else if (timelineName.equals("mix")) {
- CurveTimeline2 timeline = new PathConstraintMixTimeline(timelineMap.size, timelineMap.size << 1, index);
- timelines.add(readTimeline(keyMap, timeline, "mixRotate", "mixTranslate", 1, 1));
+ PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(timelineMap.size, timelineMap.size * 3, index);
+ float time = keyMap.getFloat("time", 0);
+ float mixRotate = keyMap.getFloat("mixRotate", 1);
+ float mixX = keyMap.getFloat("mixX", 1), mixY = keyMap.getFloat("mixY", mixX);
+ for (int frame = 0, bezier = 0;; frame++) {
+ timeline.setFrame(frame, time, mixRotate, mixX, mixY);
+ JsonValue nextMap = keyMap.next;
+ if (nextMap == null) {
+ timeline.shrink(bezier);
+ break;
+ }
+ float time2 = nextMap.getFloat("time", 0);
+ float mixRotate2 = nextMap.getFloat("mixRotate", 1);
+ float mixX2 = nextMap.getFloat("mixX", 1), mixY2 = nextMap.getFloat("mixY", mixX2);
+ JsonValue curve = keyMap.get("curve");
+ if (curve != null) {
+ bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, mixRotate, mixRotate2, 1);
+ bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, mixX, mixX2, 1);
+ bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, mixY, mixY2, 1);
+ }
+ time = time2;
+ mixRotate = mixRotate2;
+ mixX = mixX2;
+ mixY = mixY2;
+ keyMap = nextMap;
+ }
+ timelines.add(timeline);
}
}
}