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 67c7602e5..69d218e70 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java
@@ -270,8 +270,7 @@ public class Animation {
float[] curves;
/** @param frameEntries The number of entries stored per frame.
- * @param bezierCount The number of frames that will use Bezier curves, used to reduce allocations. Pass 0 if unknown, which
- * will allocate for frameCount Bezier curves (see {@link #shrink(int)}).
+ * @param bezierCount The maximum number of frames that will use Bezier curves. See {@link #shrink(int)}.
* @param propertyIds Unique identifiers for each property the timeline modifies. */
public CurveTimeline (int frameCount, int frameEntries, int bezierCount, String... propertyIds) {
super(frameCount, frameEntries, propertyIds);
@@ -290,9 +289,7 @@ public class Animation {
curves[frameIndex] = STEPPED;
}
- /** Sets the specified key frame to Bezier interpolation.
- * @param frameIndex Between 0 and frameCount - 1. */
- protected int setBezier (int frameIndex, int bezierIndex) {
+ int setBezier (int frameIndex, int bezierIndex) {
int index = getFrameCount() - 1 + bezierIndex * BEZIER_SIZE;
curves[frameIndex] = BEZIER + index;
return index;
@@ -311,7 +308,8 @@ public class Animation {
return BEZIER;
}
- /** Shrinks the storage for Bezier curves, for use when bezierCount specified in the constructor was 0. */
+ /** Shrinks the storage for Bezier curves, for use when bezierCount specified in the constructor was larger
+ * than the actual number of Bezier curves. */
public void shrink (int bezierCount) {
int size = getFrameCount() - 1 + bezierCount * BEZIER_SIZE;
if (curves.length > size) {
@@ -325,24 +323,27 @@ public class Animation {
/** The base class for timelines that use interpolation between key frames for one or more properties using a percentage of the
* difference between values. */
static public abstract class PercentCurveTimeline extends CurveTimeline {
- public PercentCurveTimeline (int frameCount, int frameEntries, int bezierIndex, String... propertyIds) {
- super(frameCount, frameEntries, bezierIndex, propertyIds);
+ /** @param bezierCount The maximum number of frames that will use Bezier curves. See {@link #shrink(int)}.
+ * @param propertyIds Unique identifiers for each property the timeline modifies. */
+ public PercentCurveTimeline (int frameCount, int frameEntries, int bezierCount, String... propertyIds) {
+ super(frameCount, frameEntries, bezierCount, propertyIds);
}
/** Sets the specified key frame to Bezier interpolation.
- *
- * cx1 and cx2 are from 0 to 1, representing the percent of time between the two key frames.
- *
- * cy1 and cy2 are the percent of the difference between the key frame's values.
- * @param frameIndex Between 0 and frameCount - 1. */
- public void setBezier (int frameIndex, int bezierIndex, float cx1, float cy1, float cx2, float cy2) {
+ * @param frameIndex Between 0 and frameCount - 1.
+ * @param cx1 The time for the first Bezier handle.
+ * @param cy1 The percentage of the difference between the key frame's values for the first Bezier handle.
+ * @param cx2 The time of the second Bezier handle.
+ * @param cy2 The percentage of the difference between the key frame's values for the second Bezier handle. */
+ public void setBezier (int frameIndex, int bezierIndex, float time1, float cx1, float cy1, float cx2, float cy2,
+ float time2) {
int i = setBezier(frameIndex, bezierIndex);
float[] curves = this.curves;
- float tmpx = cx2 * 0.03f - cx1 * 0.06f, tmpy = cy2 * 0.03f - cy1 * 0.06f;
- float dddx = (cx1 - cx2 + 0.33333333f) * 0.018f, dddy = (cy1 - cy2 + 0.33333333f) * 0.018f;
+ float tmpx = (time1 - cx1 * 2 + cx2) * 0.03f, tmpy = cy2 * 0.03f - cy1 * 0.06f;
+ float dddx = ((cx1 - cx2) * 3 - time1 + time2) * 0.006f, dddy = (cy1 - cy2 + 0.33333333f) * 0.018f;
float ddx = tmpx * 2 + dddx, ddy = tmpy * 2 + dddy;
- float dx = cx1 * 0.3f + tmpx + dddx * 0.16666667f, dy = cy1 * 0.3f + tmpy + dddy * 0.16666667f;
- float x = dx, y = dy;
+ float dx = (cx1 - time1) * 0.3f + tmpx + dddx * 0.16666667f, dy = cy1 * 0.3f + tmpy + dddy * 0.16666667f;
+ float x = time1 + dx, y = dy;
for (int n = i + BEZIER_SIZE; i < n; i += 2) {
curves[i] = x;
curves[i + 1] = y;
@@ -360,21 +361,19 @@ public class Animation {
public float getCurvePercent (int frameIndex, float time, float time1, float time2) {
float[] curves = this.curves;
int i = (int)curves[frameIndex];
+ if (i == LINEAR) return MathUtils.clamp((time - time1) / (time2 - time1), 0, 1);
if (i == STEPPED) return 0;
- float percent = MathUtils.clamp((time - time1) / (time2 - time1), 0, 1);
- if (i == LINEAR) return percent;
i -= BEZIER;
- float x = 0;
- for (int start = i, n = i + BEZIER_SIZE; i < n; i += 2) {
- x = curves[i];
- if (x >= percent) {
- if (i == start) return curves[i + 1] * percent / x; // First point is 0,0.
- float prevX = curves[i - 2], prevY = curves[i - 1];
- return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX);
+ if (curves[i] > time) return curves[i + 1] * (time - time1) / (curves[i] - time1);
+ i += 2;
+ for (int n = i + BEZIER_SIZE - 2; i < n; i += 2) {
+ if (curves[i] >= time) {
+ float x = curves[i - 2], y = curves[i - 1];
+ return y + (curves[i + 1] - y) * (time - x) / (curves[i] - x);
}
}
- float y = curves[i - 1];
- return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1.
+ float x = curves[i - 2], y = curves[i - 1];
+ return y + (1 - y) * (time - x) / (time2 - x);
}
}
@@ -385,8 +384,10 @@ public class Animation {
static final int PREV_TIME = -2, PREV_VALUE = -1;
static final int VALUE = 1;
- public ValueCurveTimeline (int frameCount, int bezierIndex, String... propertyIds) {
- super(frameCount, 2, bezierIndex, propertyIds);
+ /** @param bezierCount The maximum number of frames that will use Bezier curves. See {@link #shrink(int)}.
+ * @param propertyIds Unique identifiers for each property the timeline modifies. */
+ public ValueCurveTimeline (int frameCount, int bezierCount, String... propertyIds) {
+ super(frameCount, 2, bezierCount, propertyIds);
}
public int getFrameCount () {
@@ -401,53 +402,50 @@ public class Animation {
}
/** Sets the specified key frame to Bezier interpolation.
- *
- * y1 and y2 are the key frame values for this and the next frame.
- *
- * cx1 and cx2 are from 0 to 1, representing the percent of time between the two key frames.
- *
- * cy1 and cy2 are in the key frames' value space.
- * @param frameIndex Between 0 and frameCount - 1. */
- public void setBezier (int frameIndex, int bezierIndex, float y1, float cx1, float cy1, float cx2, float cy2, float y2) {
+ * @param frameIndex Between 0 and frameCount - 1.
+ * @param cx1 The time for the first Bezier handle.
+ * @param cy1 The value for the first Bezier handle.
+ * @param cx2 The time of the second Bezier handle.
+ * @param cy2 The value for the second Bezier handle. */
+ public void setBezier (int frameIndex, int bezierIndex, float time1, float value1, float cx1, float cy1, float cx2,
+ float cy2, float time2, float value2) {
int i = setBezier(frameIndex, bezierIndex);
float[] curves = this.curves;
- float tmpx = cx2 * 0.03f - cx1 * 0.06f, tmpy = (y1 - cy1 * 2 + cy2) * 0.03f;
- float dddfx = (cx1 - cx2 + 0.33333333f) * 0.018f, dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006f;
- float ddx = tmpx * 2 + dddfx, ddy = tmpy * 2 + dddfy;
- float dx = cx1 * 0.3f + tmpx + dddfx * 0.16666667f, dy = (cy1 - y1) * 0.3f + tmpy + dddfy * 0.16666667f;
- float x = dx, y = y1 + dy;
+ float tmpx = (time1 - cx1 * 2 + cx2) * 0.03f, tmpy = (value1 - cy1 * 2 + cy2) * 0.03f;
+ float dddx = ((cx1 - cx2) * 3 - time1 + time2) * 0.006f, dddy = ((cy1 - cy2) * 3 - value1 + value2) * 0.006f;
+ float ddx = tmpx * 2 + dddx, ddy = tmpy * 2 + dddy;
+ float dx = (cx1 - time1) * 0.3f + tmpx + dddx * 0.16666667f, dy = (cy1 - value1) * 0.3f + tmpy + dddy * 0.16666667f;
+ float x = time1 + dx, y = value1 + dy;
for (int n = i + BEZIER_SIZE; i < n; i += 2) {
curves[i] = x;
curves[i + 1] = y;
dx += ddx;
dy += ddy;
- ddx += dddfx;
- ddy += dddfy;
+ ddx += dddx;
+ ddy += dddy;
x += dx;
y += dy;
}
}
- /** Returns the interpolated value for the specified key frame and times.
+ /** Returns the interpolated value for the specified key frame, times, and values.
* @param frameIndex Between 0 and frameCount - 1. */
public float getCurveValue (int frameIndex, float time, float time1, float value1, float time2, float value2) {
float[] curves = this.curves;
int i = (int)curves[frameIndex];
+ if (i == LINEAR) return value1 + (value2 - value1) * MathUtils.clamp((time - time1) / (time2 - time1), 0, 1);
if (i == STEPPED) return value1;
- float percent = MathUtils.clamp((time - time1) / (time2 - time1), 0, 1);
- if (i == LINEAR) return value1 + (value2 - value1) * percent;
i -= BEZIER;
- float x = 0;
- for (int start = i, n = i + BEZIER_SIZE; i < n; i += 2) {
- x = curves[i];
- if (x >= percent) {
- if (i == start) return value1 + (curves[i + 1] - value1) * percent / x; // First point is 0,value1.
- float prevY = curves[i - 1], prevX = curves[i - 2];
- return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX);
+ if (curves[i] > time) return value1 + (curves[i + 1] - value1) * (time - value1) / (curves[i] - value1);
+ i += 2;
+ for (int n = i + BEZIER_SIZE - 2; i < n; i += 2) {
+ if (curves[i] >= time) {
+ float x = curves[i - 2], y = curves[i - 1];
+ return y + (curves[i + 1] - y) * (time - x) / (curves[i] - x);
}
}
- float y = curves[i - 1];
- return y + (value2 - y) * (percent - x) / (1 - x); // Last point is 1,value2.
+ float x = curves[i - 2], y = curves[i - 1];
+ return y + (value2 - y) * (time - x) / (time2 - x);
}
}
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 e599bfcfc..06129a9e7 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java
@@ -593,24 +593,26 @@ public class SkeletonBinary {
}
case SLOT_COLOR: {
ColorTimeline timeline = new ColorTimeline(frameCount, input.readInt(true), slotIndex);
+ float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
- float time = input.readFloat();
Color.rgba8888ToColor(tempColor1, input.readInt());
timeline.setFrame(frameIndex, time, tempColor1.r, tempColor1.g, tempColor1.b, tempColor1.a);
- if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
+ if (frameIndex < frameLast)
+ bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, time = input.readFloat());
}
timelines.add(timeline);
break;
}
case SLOT_TWO_COLOR: {
TwoColorTimeline timeline = new TwoColorTimeline(frameCount, input.readInt(true), slotIndex);
+ float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
- float time = input.readFloat();
Color.rgba8888ToColor(tempColor1, input.readInt());
Color.rgb888ToColor(tempColor2, input.readInt());
timeline.setFrame(frameIndex, time, tempColor1.r, tempColor1.g, tempColor1.b, tempColor1.a, tempColor2.r,
tempColor2.g, tempColor2.b);
- if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
+ if (frameIndex < frameLast)
+ bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, time = input.readFloat());
}
timelines.add(timeline);
break;
@@ -628,38 +630,44 @@ public class SkeletonBinary {
switch (timelineType) {
case BONE_ROTATE: {
RotateTimeline timeline = new RotateTimeline(frameCount, input.readInt(true), boneIndex);
- float value = input.readFloat();
+ float time = input.readFloat(), value = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
- timeline.setFrame(frameIndex, input.readFloat(), value);
- if (frameIndex < frameLast)
- readCurve(input, timeline, frameIndex, bezierIndex, value, value = input.readFloat());
+ timeline.setFrame(frameIndex, time, value);
+ if (frameIndex < frameLast) readCurve(input, timeline, frameIndex, bezierIndex, time, value,
+ time = input.readFloat(), value = input.readFloat());
}
timelines.add(timeline);
break;
}
case BONE_TRANSLATE: {
TranslateTimeline timeline = new TranslateTimeline(frameCount, input.readInt(true), boneIndex);
+ float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
- timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * scale, input.readFloat() * scale);
- if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
+ timeline.setFrame(frameIndex, time, input.readFloat() * scale, input.readFloat() * scale);
+ if (frameIndex < frameLast)
+ bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, time = input.readFloat());
}
timelines.add(timeline);
break;
}
case BONE_SCALE: {
ScaleTimeline timeline = new ScaleTimeline(frameCount, input.readInt(true), boneIndex);
+ float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
- timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat());
- if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
+ timeline.setFrame(frameIndex, time, input.readFloat(), input.readFloat());
+ if (frameIndex < frameLast)
+ bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, time = input.readFloat());
}
timelines.add(timeline);
break;
}
case BONE_SHEAR: {
ShearTimeline timeline = new ShearTimeline(frameCount, input.readInt(true), boneIndex);
+ float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
- timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat());
- if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
+ timeline.setFrame(frameIndex, time, input.readFloat(), input.readFloat());
+ if (frameIndex < frameLast)
+ bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, time = input.readFloat());
}
timelines.add(timeline);
break;
@@ -673,10 +681,12 @@ public class SkeletonBinary {
int index = input.readInt(true);
int frameCount = input.readInt(true), frameLast = frameCount - 1;
IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount, input.readInt(true), index);
+ float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
- timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat() * scale, input.readByte(),
+ timeline.setFrame(frameIndex, time, input.readFloat(), input.readFloat() * scale, input.readByte(),
input.readBoolean(), input.readBoolean());
- if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
+ if (frameIndex < frameLast)
+ bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, time = input.readFloat());
}
timelines.add(timeline);
}
@@ -686,10 +696,11 @@ public class SkeletonBinary {
int index = input.readInt(true);
int frameCount = input.readInt(true), frameLast = frameCount - 1;
TransformConstraintTimeline timeline = new TransformConstraintTimeline(frameCount, input.readInt(true), index);
+ float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
- timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat(),
- input.readFloat());
- if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
+ timeline.setFrame(frameIndex, time, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat());
+ if (frameIndex < frameLast)
+ bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, time = input.readFloat());
}
timelines.add(timeline);
}
@@ -707,9 +718,11 @@ public class SkeletonBinary {
index);
float timelineScale = data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed ? scale
: 1;
+ float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
- timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * timelineScale);
- if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
+ timeline.setFrame(frameIndex, time, input.readFloat() * timelineScale);
+ if (frameIndex < frameLast)
+ bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, time = input.readFloat());
}
timelines.add(timeline);
break;
@@ -718,18 +731,22 @@ public class SkeletonBinary {
PathConstraintPositionTimeline timeline = new PathConstraintPositionTimeline(frameCount, input.readInt(true),
index);
float timelineScale = data.positionMode == PositionMode.fixed ? scale : 1;
+ float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
- timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * timelineScale);
- if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
+ timeline.setFrame(frameIndex, time, input.readFloat() * timelineScale);
+ if (frameIndex < frameLast)
+ bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, time = input.readFloat());
}
timelines.add(timeline);
break;
}
case PATH_MIX: {
PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(frameCount, input.readInt(true), index);
+ float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
- timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat());
- if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
+ timeline.setFrame(frameIndex, time, input.readFloat(), input.readFloat());
+ if (frameIndex < frameLast)
+ bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, time = input.readFloat());
}
timelines.add(timeline);
break;
@@ -752,8 +769,8 @@ public class SkeletonBinary {
int frameCount = input.readInt(true), frameLast = frameCount - 1;
DeformTimeline timeline = new DeformTimeline(frameCount, input.readInt(true), slotIndex, attachment);
+ float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
- float time = input.readFloat();
float[] deform;
int end = input.readInt(true);
if (end == 0)
@@ -776,7 +793,8 @@ public class SkeletonBinary {
}
timeline.setFrame(frameIndex, time, deform);
- if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
+ if (frameIndex < frameLast)
+ bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, time = input.readFloat());
}
timelines.add(timeline);
}
@@ -845,28 +863,29 @@ public class SkeletonBinary {
return new Animation(name, timelines, duration);
}
- int readCurve (SkeletonInput input, PercentCurveTimeline timeline, int frameIndex, int bezierIndex) throws IOException {
- switch (input.readByte()) {
- case CURVE_STEPPED:
- timeline.setStepped(frameIndex);
- break;
- case CURVE_BEZIER:
- timeline.setBezier(frameIndex, bezierIndex++, input.readFloat(), input.readFloat(), input.readFloat(),
- input.readFloat());
- break;
- }
- return bezierIndex;
- }
-
- int readCurve (SkeletonInput input, ValueCurveTimeline timeline, int frameIndex, int bezierIndex, float value1, float value2)
+ int readCurve (SkeletonInput input, PercentCurveTimeline timeline, int frameIndex, int bezierIndex, float time1, float time2)
throws IOException {
switch (input.readByte()) {
case CURVE_STEPPED:
timeline.setStepped(frameIndex);
break;
case CURVE_BEZIER:
- timeline.setBezier(frameIndex, bezierIndex++, value1, input.readFloat(), input.readFloat(), input.readFloat(),
- input.readFloat(), value2);
+ timeline.setBezier(frameIndex, bezierIndex++, time1, input.readFloat(), input.readFloat(), input.readFloat(),
+ input.readFloat(), time2);
+ break;
+ }
+ return bezierIndex;
+ }
+
+ int readCurve (SkeletonInput input, ValueCurveTimeline timeline, int frameIndex, int bezierIndex, float time1, float value1,
+ float time2, float value2) throws IOException {
+ switch (input.readByte()) {
+ case CURVE_STEPPED:
+ timeline.setStepped(frameIndex);
+ break;
+ case CURVE_BEZIER:
+ timeline.setBezier(frameIndex, bezierIndex++, time1, value1, input.readFloat(), input.readFloat(), input.readFloat(),
+ input.readFloat(), time2, value2);
break;
}
return bezierIndex;
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 4c6a25da6..fa176e55d 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java
@@ -507,34 +507,45 @@ public class SkeletonJson {
SlotData slot = skeletonData.findSlot(slotMap.name);
if (slot == null) throw new SerializationException("Slot not found: " + slotMap.name);
for (JsonValue timelineMap = slotMap.child; timelineMap != null; timelineMap = timelineMap.next) {
+ JsonValue valueMap = timelineMap.child;
+ if (valueMap == null) continue;
String timelineName = timelineMap.name;
- int frameIndex = 0, bezierIndex = 0;
if (timelineName.equals("attachment")) {
AttachmentTimeline timeline = new AttachmentTimeline(timelineMap.size, slot.index);
- for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++)
+ for (int frameIndex = 0; valueMap != null; valueMap = valueMap.next, frameIndex++)
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getString("name"));
timelines.add(timeline);
} else if (timelineName.equals("color")) {
ColorTimeline timeline = new ColorTimeline(timelineMap.size, 0, slot.index);
- for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) {
+ float time = timelineMap.child.getFloat("time", 0);
+ for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) {
Color color = Color.valueOf(valueMap.getString("color"));
- timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), color.r, color.g, color.b, color.a);
- bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
+ timeline.setFrame(frameIndex, time, color.r, color.g, color.b, color.a);
+ valueMap = valueMap.next;
+ if (valueMap == null) {
+ timeline.shrink(bezierIndex);
+ break;
+ }
+ bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
- timeline.shrink(bezierIndex);
timelines.add(timeline);
} else if (timelineName.equals("twoColor")) {
TwoColorTimeline timeline = new TwoColorTimeline(timelineMap.size, 0, slot.index);
- for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) {
+ float time = timelineMap.child.getFloat("time", 0);
+ for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) {
Color light = Color.valueOf(valueMap.getString("light")), dark = Color.valueOf(valueMap.getString("dark"));
- timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), light.r, light.g, light.b, light.a, //
+ timeline.setFrame(frameIndex, time, light.r, light.g, light.b, light.a, //
dark.r, dark.g, dark.b);
- bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
+ valueMap = valueMap.next;
+ if (valueMap == null) {
+ timeline.shrink(bezierIndex);
+ break;
+ }
+ bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
- timeline.shrink(bezierIndex);
timelines.add(timeline);
} else
@@ -550,49 +561,53 @@ public class SkeletonJson {
JsonValue valueMap = timelineMap.child;
if (valueMap == null) continue;
String timelineName = timelineMap.name;
- int frameIndex = 0, bezierIndex = 0;
if (timelineName.equals("rotate")) {
- RotateTimeline timeline = new RotateTimeline(timelineMap.size, 0, bone.index);
- float rotation = valueMap.getFloat("angle", 0);
- for (;; frameIndex++) {
- timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), rotation);
- valueMap = valueMap.next;
- if (valueMap == null) break;
- bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, rotation,
- rotation = valueMap.getFloat("angle", 0));
- }
- timeline.shrink(bezierIndex);
- timelines.add(timeline);
+ timelines.add(readTimeline(valueMap, new RotateTimeline(timelineMap.size, 0, bone.index)));
} else if (timelineName.equals("translate")) {
TranslateTimeline timeline = new TranslateTimeline(timelineMap.size, 0, bone.index);
- for (; valueMap != null; valueMap = valueMap.next, frameIndex++) {
+ float time = valueMap.getFloat("time", 0);
+ for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) {
float x = valueMap.getFloat("x", 0), y = valueMap.getFloat("y", 0);
- timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), x * scale, y * scale);
- bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
+ timeline.setFrame(frameIndex, time, x * scale, y * scale);
+ valueMap = valueMap.next;
+ if (valueMap == null) {
+ timeline.shrink(bezierIndex);
+ break;
+ }
+ bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
- timeline.shrink(bezierIndex);
timelines.add(timeline);
} else if (timelineName.equals("scale")) {
ScaleTimeline timeline = new ScaleTimeline(timelineMap.size, 0, bone.index);
- for (; valueMap != null; valueMap = valueMap.next, frameIndex++) {
+ float time = valueMap.getFloat("time", 0);
+ for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) {
float x = valueMap.getFloat("x", 1), y = valueMap.getFloat("y", 1);
- timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), x, y);
- bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
+ timeline.setFrame(frameIndex, time, x, y);
+ valueMap = valueMap.next;
+ if (valueMap == null) {
+ timeline.shrink(bezierIndex);
+ break;
+ }
+ bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
- timeline.shrink(bezierIndex);
timelines.add(timeline);
} else if (timelineName.equals("shear")) {
ShearTimeline timeline = new ShearTimeline(timelineMap.size, 0, bone.index);
- for (; valueMap != null; valueMap = valueMap.next, frameIndex++) {
+ float time = valueMap.getFloat("time", 0);
+ for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) {
float x = valueMap.getFloat("x", 0), y = valueMap.getFloat("y", 0);
- timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), x, y);
- bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
+ timeline.setFrame(frameIndex, time, x, y);
+ valueMap = valueMap.next;
+ if (valueMap == null) {
+ timeline.shrink(bezierIndex);
+ break;
+ }
+ bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
- timeline.shrink(bezierIndex);
timelines.add(timeline);
} else
@@ -601,33 +616,45 @@ public class SkeletonJson {
}
// IK constraint timelines.
- for (JsonValue constraintMap = map.getChild("ik"); constraintMap != null; constraintMap = constraintMap.next) {
- IkConstraintData constraint = skeletonData.findIkConstraint(constraintMap.name);
- IkConstraintTimeline timeline = new IkConstraintTimeline(constraintMap.size, 0,
+ for (JsonValue timelineMap = map.getChild("ik"); timelineMap != null; timelineMap = timelineMap.next) {
+ JsonValue valueMap = timelineMap.child;
+ if (valueMap == null) continue;
+ IkConstraintData constraint = skeletonData.findIkConstraint(timelineMap.name);
+ IkConstraintTimeline timeline = new IkConstraintTimeline(timelineMap.size, 0,
skeletonData.getIkConstraints().indexOf(constraint, true));
- int frameIndex = 0, bezierIndex = 0;
- for (JsonValue valueMap = constraintMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) {
- timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat("mix", 1),
- valueMap.getFloat("softness", 0) * scale, valueMap.getBoolean("bendPositive", true) ? 1 : -1,
- valueMap.getBoolean("compress", false), valueMap.getBoolean("stretch", false));
- bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
+ float time = valueMap.getFloat("time", 0);
+ for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) {
+ timeline.setFrame(frameIndex, time, valueMap.getFloat("mix", 1), valueMap.getFloat("softness", 0) * scale,
+ valueMap.getBoolean("bendPositive", true) ? 1 : -1, valueMap.getBoolean("compress", false),
+ valueMap.getBoolean("stretch", false));
+ valueMap = valueMap.next;
+ if (valueMap == null) {
+ timeline.shrink(bezierIndex);
+ break;
+ }
+ bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
- timeline.shrink(bezierIndex);
timelines.add(timeline);
}
// Transform constraint timelines.
- for (JsonValue constraintMap = map.getChild("transform"); constraintMap != null; constraintMap = constraintMap.next) {
- TransformConstraintData constraint = skeletonData.findTransformConstraint(constraintMap.name);
- TransformConstraintTimeline timeline = new TransformConstraintTimeline(constraintMap.size, 0,
+ for (JsonValue timelineMap = map.getChild("transform"); timelineMap != null; timelineMap = timelineMap.next) {
+ JsonValue valueMap = timelineMap.child;
+ if (valueMap == null) continue;
+ TransformConstraintData constraint = skeletonData.findTransformConstraint(timelineMap.name);
+ TransformConstraintTimeline timeline = new TransformConstraintTimeline(timelineMap.size, 0,
skeletonData.getTransformConstraints().indexOf(constraint, true));
- int frameIndex = 0, bezierIndex = 0;
- for (JsonValue valueMap = constraintMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) {
- timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat("rotateMix", 1),
- valueMap.getFloat("translateMix", 1), valueMap.getFloat("scaleMix", 1), valueMap.getFloat("shearMix", 1));
- bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
+ float time = valueMap.getFloat("time", 0);
+ for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) {
+ timeline.setFrame(frameIndex, time, valueMap.getFloat("rotateMix", 1), valueMap.getFloat("translateMix", 1),
+ valueMap.getFloat("scaleMix", 1), valueMap.getFloat("shearMix", 1));
+ valueMap = valueMap.next;
+ if (valueMap == null) {
+ timeline.shrink(bezierIndex);
+ break;
+ }
+ bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
- timeline.shrink(bezierIndex);
timelines.add(timeline);
}
@@ -637,37 +664,52 @@ public class SkeletonJson {
if (data == null) throw new SerializationException("Path constraint not found: " + constraintMap.name);
int index = skeletonData.pathConstraints.indexOf(data, true);
for (JsonValue timelineMap = constraintMap.child; timelineMap != null; timelineMap = timelineMap.next) {
+ JsonValue valueMap = timelineMap.child;
+ if (valueMap == null) continue;
String timelineName = timelineMap.name;
- int frameIndex = 0, bezierIndex = 0;
if (timelineName.equals("position")) {
PathConstraintPositionTimeline timeline = new PathConstraintPositionTimeline(timelineMap.size, 0, index);
float timelineScale = data.positionMode == PositionMode.fixed ? scale : 1;
- for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) {
- timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat(timelineName, 0) * timelineScale);
- bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
+ float time = valueMap.getFloat("time", 0);
+ for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) {
+ timeline.setFrame(frameIndex, time, valueMap.getFloat(timelineName, 0) * timelineScale);
+ valueMap = valueMap.next;
+ if (valueMap == null) {
+ timeline.shrink(bezierIndex);
+ break;
+ }
+ bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
- timeline.shrink(bezierIndex);
timelines.add(timeline);
} else if (timelineName.equals("spacing")) {
PathConstraintSpacingTimeline timeline = new PathConstraintSpacingTimeline(timelineMap.size, 0, index);
float timelineScale = data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed ? scale : 1;
- for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) {
- timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat(timelineName, 0) * timelineScale);
- bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
+ float time = valueMap.getFloat("time", 0);
+ for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) {
+ timeline.setFrame(frameIndex, time, valueMap.getFloat(timelineName, 0) * timelineScale);
+ valueMap = valueMap.next;
+ if (valueMap == null) {
+ timeline.shrink(bezierIndex);
+ break;
+ }
+ bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
- timeline.shrink(bezierIndex);
timelines.add(timeline);
} else if (timelineName.equals("mix")) {
PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(timelineMap.size, 0, index);
- for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) {
- timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat("rotateMix", 1),
- valueMap.getFloat("translateMix", 1));
- bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
+ float time = valueMap.getFloat("time", 0);
+ for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) {
+ timeline.setFrame(frameIndex, time, valueMap.getFloat("rotateMix", 1), valueMap.getFloat("translateMix", 1));
+ valueMap = valueMap.next;
+ if (valueMap == null) {
+ timeline.shrink(bezierIndex);
+ break;
+ }
+ bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
- timeline.shrink(bezierIndex);
timelines.add(timeline);
}
}
@@ -681,6 +723,9 @@ public class SkeletonJson {
SlotData slot = skeletonData.findSlot(slotMap.name);
if (slot == null) throw new SerializationException("Slot not found: " + slotMap.name);
for (JsonValue timelineMap = slotMap.child; timelineMap != null; timelineMap = timelineMap.next) {
+ JsonValue valueMap = timelineMap.child;
+ if (valueMap == null) continue;
+
VertexAttachment attachment = (VertexAttachment)skin.getAttachment(slot.index, timelineMap.name);
if (attachment == null) throw new SerializationException("Deform attachment not found: " + timelineMap.name);
boolean weighted = attachment.getBones() != null;
@@ -688,8 +733,9 @@ public class SkeletonJson {
int deformLength = weighted ? vertices.length / 3 * 2 : vertices.length;
DeformTimeline timeline = new DeformTimeline(timelineMap.size, 0, slot.index, attachment);
- int frameIndex = 0, bezierIndex = 0;
- for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) {
+ int bezierIndex = 0;
+ float time = valueMap.getFloat("time", 0);
+ for (int frameIndex = 0;; frameIndex++) {
float[] deform;
JsonValue verticesValue = valueMap.get("vertices");
if (verticesValue == null)
@@ -708,8 +754,10 @@ public class SkeletonJson {
}
}
- timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), deform);
- bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
+ timeline.setFrame(frameIndex, time, deform);
+ valueMap = valueMap.next;
+ if (valueMap == null) break;
+ bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
timeline.shrink(bezierIndex);
timelines.add(timeline);
@@ -782,27 +830,42 @@ public class SkeletonJson {
skeletonData.animations.add(new Animation(name, timelines, duration));
}
- int readCurve (JsonValue map, PercentCurveTimeline timeline, int frameIndex, int bezierIndex) {
+ private ValueCurveTimeline readTimeline (JsonValue valueMap, ValueCurveTimeline timeline) {
+ float time = valueMap.getFloat("time", 0), value = valueMap.getFloat("value", 0);
+ int bezierIndex = 0;
+ for (int frameIndex = 0;; frameIndex++) {
+ timeline.setFrame(frameIndex, time, value);
+ valueMap = valueMap.next;
+ if (valueMap == null) break;
+ bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, //
+ time, value, time = valueMap.getFloat("time", 0), value = valueMap.getFloat("value", 0));
+ }
+ timeline.shrink(bezierIndex);
+ return timeline;
+ }
+
+ int readCurve (JsonValue map, PercentCurveTimeline timeline, int frameIndex, int bezierIndex, float time1, float time2) {
JsonValue curve = map.get("curve");
if (curve != null) {
if (curve.isString())
timeline.setStepped(frameIndex);
else {
- timeline.setBezier(frameIndex, bezierIndex++, curve.asFloat(), map.getFloat("c2", 0), map.getFloat("c3", 1),
- map.getFloat("c4", 1));
+ timeline.setBezier(frameIndex, bezierIndex++, time1, curve.asFloat(), map.getFloat("c2", 0), map.getFloat("c3", 1),
+ map.getFloat("c4", 1), time2);
}
}
return bezierIndex;
}
- int readCurve (JsonValue map, ValueCurveTimeline timeline, int frameIndex, int bezierIndex, float value1, float value2) {
+ int readCurve (JsonValue map, ValueCurveTimeline timeline, int frameIndex, int bezierIndex, float time1, float value1,
+ float time2, float value2) {
JsonValue curve = map.get("curve");
if (curve != null) {
if (curve.isString())
timeline.setStepped(frameIndex);
else {
- timeline.setBezier(frameIndex, bezierIndex++, value1, curve.asFloat(), map.getFloat("c2", 0), map.getFloat("c3", 1),
- map.getFloat("c4", 1), value2);
+ timeline.setBezier(frameIndex, bezierIndex++, time1, value1, curve.asFloat(), map.getFloat("c2", 0),
+ map.getFloat("c3", 1), map.getFloat("c4", 1), time2, value2);
}
}
return bezierIndex;