Use time for Bezier segments rather than percent.

Saves calculating the percent between frames for the Bezier path.
This commit is contained in:
NathanSweet 2019-10-29 10:56:22 +01:00
parent 927b9cf866
commit f165ffeb1c
3 changed files with 258 additions and 178 deletions

View File

@ -270,8 +270,7 @@ public class Animation {
float[] curves; float[] curves;
/** @param frameEntries The number of entries stored per frame. /** @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 * @param bezierCount The maximum number of frames that will use Bezier curves. See {@link #shrink(int)}.
* will allocate for <code>frameCount</code> Bezier curves (see {@link #shrink(int)}).
* @param propertyIds Unique identifiers for each property the timeline modifies. */ * @param propertyIds Unique identifiers for each property the timeline modifies. */
public CurveTimeline (int frameCount, int frameEntries, int bezierCount, String... propertyIds) { public CurveTimeline (int frameCount, int frameEntries, int bezierCount, String... propertyIds) {
super(frameCount, frameEntries, propertyIds); super(frameCount, frameEntries, propertyIds);
@ -290,9 +289,7 @@ public class Animation {
curves[frameIndex] = STEPPED; curves[frameIndex] = STEPPED;
} }
/** Sets the specified key frame to Bezier interpolation. int setBezier (int frameIndex, int bezierIndex) {
* @param frameIndex Between 0 and <code>frameCount - 1</code>. */
protected int setBezier (int frameIndex, int bezierIndex) {
int index = getFrameCount() - 1 + bezierIndex * BEZIER_SIZE; int index = getFrameCount() - 1 + bezierIndex * BEZIER_SIZE;
curves[frameIndex] = BEZIER + index; curves[frameIndex] = BEZIER + index;
return index; return index;
@ -311,7 +308,8 @@ public class Animation {
return BEZIER; return BEZIER;
} }
/** Shrinks the storage for Bezier curves, for use when <code>bezierCount</code> specified in the constructor was 0. */ /** Shrinks the storage for Bezier curves, for use when <code>bezierCount</code> specified in the constructor was larger
* than the actual number of Bezier curves. */
public void shrink (int bezierCount) { public void shrink (int bezierCount) {
int size = getFrameCount() - 1 + bezierCount * BEZIER_SIZE; int size = getFrameCount() - 1 + bezierCount * BEZIER_SIZE;
if (curves.length > 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 /** The base class for timelines that use interpolation between key frames for one or more properties using a percentage of the
* difference between values. */ * difference between values. */
static public abstract class PercentCurveTimeline extends CurveTimeline { static public abstract class PercentCurveTimeline extends CurveTimeline {
public PercentCurveTimeline (int frameCount, int frameEntries, int bezierIndex, String... propertyIds) { /** @param bezierCount The maximum number of frames that will use Bezier curves. See {@link #shrink(int)}.
super(frameCount, frameEntries, bezierIndex, propertyIds); * @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. /** Sets the specified key frame to Bezier interpolation.
* <p> * @param frameIndex Between 0 and <code>frameCount - 1</code>.
* <code>cx1</code> and <code>cx2</code> are from 0 to 1, representing the percent of time between the two key frames. * @param cx1 The time for the first Bezier handle.
* <p> * @param cy1 The percentage of the difference between the key frame's values for the first Bezier handle.
* <code>cy1</code> and <code>cy2</code> are the percent of the difference between the key frame's values. * @param cx2 The time of the second Bezier handle.
* @param frameIndex Between 0 and <code>frameCount - 1</code>. */ * @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 cx1, float cy1, float cx2, float cy2) { public void setBezier (int frameIndex, int bezierIndex, float time1, float cx1, float cy1, float cx2, float cy2,
float time2) {
int i = setBezier(frameIndex, bezierIndex); int i = setBezier(frameIndex, bezierIndex);
float[] curves = this.curves; float[] curves = this.curves;
float tmpx = cx2 * 0.03f - cx1 * 0.06f, tmpy = cy2 * 0.03f - cy1 * 0.06f; float tmpx = (time1 - cx1 * 2 + cx2) * 0.03f, tmpy = cy2 * 0.03f - cy1 * 0.06f;
float dddx = (cx1 - cx2 + 0.33333333f) * 0.018f, dddy = (cy1 - cy2 + 0.33333333f) * 0.018f; 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 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 dx = (cx1 - time1) * 0.3f + tmpx + dddx * 0.16666667f, dy = cy1 * 0.3f + tmpy + dddy * 0.16666667f;
float x = dx, y = dy; float x = time1 + dx, y = dy;
for (int n = i + BEZIER_SIZE; i < n; i += 2) { for (int n = i + BEZIER_SIZE; i < n; i += 2) {
curves[i] = x; curves[i] = x;
curves[i + 1] = y; curves[i + 1] = y;
@ -360,21 +361,19 @@ public class Animation {
public float getCurvePercent (int frameIndex, float time, float time1, float time2) { public float getCurvePercent (int frameIndex, float time, float time1, float time2) {
float[] curves = this.curves; float[] curves = this.curves;
int i = (int)curves[frameIndex]; int i = (int)curves[frameIndex];
if (i == LINEAR) return MathUtils.clamp((time - time1) / (time2 - time1), 0, 1);
if (i == STEPPED) return 0; if (i == STEPPED) return 0;
float percent = MathUtils.clamp((time - time1) / (time2 - time1), 0, 1);
if (i == LINEAR) return percent;
i -= BEZIER; i -= BEZIER;
float x = 0; if (curves[i] > time) return curves[i + 1] * (time - time1) / (curves[i] - time1);
for (int start = i, n = i + BEZIER_SIZE; i < n; i += 2) { i += 2;
x = curves[i]; for (int n = i + BEZIER_SIZE - 2; i < n; i += 2) {
if (x >= percent) { if (curves[i] >= time) {
if (i == start) return curves[i + 1] * percent / x; // First point is 0,0. float x = curves[i - 2], y = curves[i - 1];
float prevX = curves[i - 2], prevY = curves[i - 1]; return y + (curves[i + 1] - y) * (time - x) / (curves[i] - x);
return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX);
} }
} }
float y = curves[i - 1]; float x = curves[i - 2], y = curves[i - 1];
return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,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 PREV_TIME = -2, PREV_VALUE = -1;
static final int VALUE = 1; static final int VALUE = 1;
public ValueCurveTimeline (int frameCount, int bezierIndex, String... propertyIds) { /** @param bezierCount The maximum number of frames that will use Bezier curves. See {@link #shrink(int)}.
super(frameCount, 2, bezierIndex, propertyIds); * @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 () { public int getFrameCount () {
@ -401,53 +402,50 @@ public class Animation {
} }
/** Sets the specified key frame to Bezier interpolation. /** Sets the specified key frame to Bezier interpolation.
* <p> * @param frameIndex Between 0 and <code>frameCount - 1</code>.
* <code>y1</code> and <code>y2</code> are the key frame values for this and the next frame. * @param cx1 The time for the first Bezier handle.
* <p> * @param cy1 The value for the first Bezier handle.
* <code>cx1</code> and <code>cx2</code> are from 0 to 1, representing the percent of time between the two key frames. * @param cx2 The time of the second Bezier handle.
* <p> * @param cy2 The value for the second Bezier handle. */
* <code>cy1</code> and <code>cy2</code> are in the key frames' value space. public void setBezier (int frameIndex, int bezierIndex, float time1, float value1, float cx1, float cy1, float cx2,
* @param frameIndex Between 0 and <code>frameCount - 1</code>. */ float cy2, float time2, float value2) {
public void setBezier (int frameIndex, int bezierIndex, float y1, float cx1, float cy1, float cx2, float cy2, float y2) {
int i = setBezier(frameIndex, bezierIndex); int i = setBezier(frameIndex, bezierIndex);
float[] curves = this.curves; float[] curves = this.curves;
float tmpx = cx2 * 0.03f - cx1 * 0.06f, tmpy = (y1 - cy1 * 2 + cy2) * 0.03f; float tmpx = (time1 - cx1 * 2 + cx2) * 0.03f, tmpy = (value1 - cy1 * 2 + cy2) * 0.03f;
float dddfx = (cx1 - cx2 + 0.33333333f) * 0.018f, dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006f; float dddx = ((cx1 - cx2) * 3 - time1 + time2) * 0.006f, dddy = ((cy1 - cy2) * 3 - value1 + value2) * 0.006f;
float ddx = tmpx * 2 + dddfx, ddy = tmpy * 2 + dddfy; float ddx = tmpx * 2 + dddx, ddy = tmpy * 2 + dddy;
float dx = cx1 * 0.3f + tmpx + dddfx * 0.16666667f, dy = (cy1 - y1) * 0.3f + tmpy + dddfy * 0.16666667f; float dx = (cx1 - time1) * 0.3f + tmpx + dddx * 0.16666667f, dy = (cy1 - value1) * 0.3f + tmpy + dddy * 0.16666667f;
float x = dx, y = y1 + dy; float x = time1 + dx, y = value1 + dy;
for (int n = i + BEZIER_SIZE; i < n; i += 2) { for (int n = i + BEZIER_SIZE; i < n; i += 2) {
curves[i] = x; curves[i] = x;
curves[i + 1] = y; curves[i + 1] = y;
dx += ddx; dx += ddx;
dy += ddy; dy += ddy;
ddx += dddfx; ddx += dddx;
ddy += dddfy; ddy += dddy;
x += dx; x += dx;
y += dy; 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 <code>frameCount - 1</code>. */ * @param frameIndex Between 0 and <code>frameCount - 1</code>. */
public float getCurveValue (int frameIndex, float time, float time1, float value1, float time2, float value2) { public float getCurveValue (int frameIndex, float time, float time1, float value1, float time2, float value2) {
float[] curves = this.curves; float[] curves = this.curves;
int i = (int)curves[frameIndex]; 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; 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; i -= BEZIER;
float x = 0; if (curves[i] > time) return value1 + (curves[i + 1] - value1) * (time - value1) / (curves[i] - value1);
for (int start = i, n = i + BEZIER_SIZE; i < n; i += 2) { i += 2;
x = curves[i]; for (int n = i + BEZIER_SIZE - 2; i < n; i += 2) {
if (x >= percent) { if (curves[i] >= time) {
if (i == start) return value1 + (curves[i + 1] - value1) * percent / x; // First point is 0,value1. float x = curves[i - 2], y = curves[i - 1];
float prevY = curves[i - 1], prevX = curves[i - 2]; return y + (curves[i + 1] - y) * (time - x) / (curves[i] - x);
return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX);
} }
} }
float y = curves[i - 1]; float x = curves[i - 2], y = curves[i - 1];
return y + (value2 - y) * (percent - x) / (1 - x); // Last point is 1,value2. return y + (value2 - y) * (time - x) / (time2 - x);
} }
} }

View File

@ -593,24 +593,26 @@ public class SkeletonBinary {
} }
case SLOT_COLOR: { case SLOT_COLOR: {
ColorTimeline timeline = new ColorTimeline(frameCount, input.readInt(true), slotIndex); ColorTimeline timeline = new ColorTimeline(frameCount, input.readInt(true), slotIndex);
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
float time = input.readFloat(); float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
Color.rgba8888ToColor(tempColor1, input.readInt()); Color.rgba8888ToColor(tempColor1, input.readInt());
timeline.setFrame(frameIndex, time, tempColor1.r, tempColor1.g, tempColor1.b, tempColor1.a); 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); timelines.add(timeline);
break; break;
} }
case SLOT_TWO_COLOR: { case SLOT_TWO_COLOR: {
TwoColorTimeline timeline = new TwoColorTimeline(frameCount, input.readInt(true), slotIndex); TwoColorTimeline timeline = new TwoColorTimeline(frameCount, input.readInt(true), slotIndex);
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
float time = input.readFloat(); float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
Color.rgba8888ToColor(tempColor1, input.readInt()); Color.rgba8888ToColor(tempColor1, input.readInt());
Color.rgb888ToColor(tempColor2, input.readInt()); Color.rgb888ToColor(tempColor2, input.readInt());
timeline.setFrame(frameIndex, time, tempColor1.r, tempColor1.g, tempColor1.b, tempColor1.a, tempColor2.r, timeline.setFrame(frameIndex, time, tempColor1.r, tempColor1.g, tempColor1.b, tempColor1.a, tempColor2.r,
tempColor2.g, tempColor2.b); 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); timelines.add(timeline);
break; break;
@ -628,38 +630,44 @@ public class SkeletonBinary {
switch (timelineType) { switch (timelineType) {
case BONE_ROTATE: { case BONE_ROTATE: {
RotateTimeline timeline = new RotateTimeline(frameCount, input.readInt(true), boneIndex); 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++) { for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
timeline.setFrame(frameIndex, input.readFloat(), value); timeline.setFrame(frameIndex, time, value);
if (frameIndex < frameLast) if (frameIndex < frameLast) readCurve(input, timeline, frameIndex, bezierIndex, time, value,
readCurve(input, timeline, frameIndex, bezierIndex, value, value = input.readFloat()); time = input.readFloat(), value = input.readFloat());
} }
timelines.add(timeline); timelines.add(timeline);
break; break;
} }
case BONE_TRANSLATE: { case BONE_TRANSLATE: {
TranslateTimeline timeline = new TranslateTimeline(frameCount, input.readInt(true), boneIndex); TranslateTimeline timeline = new TranslateTimeline(frameCount, input.readInt(true), boneIndex);
float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) { for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * scale, input.readFloat() * scale); timeline.setFrame(frameIndex, time, input.readFloat() * scale, input.readFloat() * scale);
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); timelines.add(timeline);
break; break;
} }
case BONE_SCALE: { case BONE_SCALE: {
ScaleTimeline timeline = new ScaleTimeline(frameCount, input.readInt(true), boneIndex); ScaleTimeline timeline = new ScaleTimeline(frameCount, input.readInt(true), boneIndex);
float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) { for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat()); timeline.setFrame(frameIndex, time, input.readFloat(), input.readFloat());
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); timelines.add(timeline);
break; break;
} }
case BONE_SHEAR: { case BONE_SHEAR: {
ShearTimeline timeline = new ShearTimeline(frameCount, input.readInt(true), boneIndex); ShearTimeline timeline = new ShearTimeline(frameCount, input.readInt(true), boneIndex);
float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) { for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat()); timeline.setFrame(frameIndex, time, input.readFloat(), input.readFloat());
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); timelines.add(timeline);
break; break;
@ -673,10 +681,12 @@ public class SkeletonBinary {
int index = input.readInt(true); int index = input.readInt(true);
int frameCount = input.readInt(true), frameLast = frameCount - 1; int frameCount = input.readInt(true), frameLast = frameCount - 1;
IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount, input.readInt(true), index); IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount, input.readInt(true), index);
float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) { 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()); 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); timelines.add(timeline);
} }
@ -686,10 +696,11 @@ public class SkeletonBinary {
int index = input.readInt(true); int index = input.readInt(true);
int frameCount = input.readInt(true), frameLast = frameCount - 1; int frameCount = input.readInt(true), frameLast = frameCount - 1;
TransformConstraintTimeline timeline = new TransformConstraintTimeline(frameCount, input.readInt(true), index); TransformConstraintTimeline timeline = new TransformConstraintTimeline(frameCount, input.readInt(true), index);
float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) { for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat(), timeline.setFrame(frameIndex, time, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat());
input.readFloat()); if (frameIndex < frameLast)
if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex); bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, time = input.readFloat());
} }
timelines.add(timeline); timelines.add(timeline);
} }
@ -707,9 +718,11 @@ public class SkeletonBinary {
index); index);
float timelineScale = data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed ? scale float timelineScale = data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed ? scale
: 1; : 1;
float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) { for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * timelineScale); timeline.setFrame(frameIndex, time, input.readFloat() * timelineScale);
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); timelines.add(timeline);
break; break;
@ -718,18 +731,22 @@ public class SkeletonBinary {
PathConstraintPositionTimeline timeline = new PathConstraintPositionTimeline(frameCount, input.readInt(true), PathConstraintPositionTimeline timeline = new PathConstraintPositionTimeline(frameCount, input.readInt(true),
index); index);
float timelineScale = data.positionMode == PositionMode.fixed ? scale : 1; float timelineScale = data.positionMode == PositionMode.fixed ? scale : 1;
float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) { for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * timelineScale); timeline.setFrame(frameIndex, time, input.readFloat() * timelineScale);
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); timelines.add(timeline);
break; break;
} }
case PATH_MIX: { case PATH_MIX: {
PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(frameCount, input.readInt(true), index); PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(frameCount, input.readInt(true), index);
float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) { for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat()); timeline.setFrame(frameIndex, time, input.readFloat(), input.readFloat());
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); timelines.add(timeline);
break; break;
@ -752,8 +769,8 @@ public class SkeletonBinary {
int frameCount = input.readInt(true), frameLast = frameCount - 1; int frameCount = input.readInt(true), frameLast = frameCount - 1;
DeformTimeline timeline = new DeformTimeline(frameCount, input.readInt(true), slotIndex, attachment); DeformTimeline timeline = new DeformTimeline(frameCount, input.readInt(true), slotIndex, attachment);
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
float time = input.readFloat(); float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
float[] deform; float[] deform;
int end = input.readInt(true); int end = input.readInt(true);
if (end == 0) if (end == 0)
@ -776,7 +793,8 @@ public class SkeletonBinary {
} }
timeline.setFrame(frameIndex, time, deform); 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); timelines.add(timeline);
} }
@ -845,28 +863,29 @@ public class SkeletonBinary {
return new Animation(name, timelines, duration); return new Animation(name, timelines, duration);
} }
int readCurve (SkeletonInput input, PercentCurveTimeline timeline, int frameIndex, int bezierIndex) throws IOException { int readCurve (SkeletonInput input, PercentCurveTimeline timeline, int frameIndex, int bezierIndex, float time1, float time2)
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)
throws IOException { throws IOException {
switch (input.readByte()) { switch (input.readByte()) {
case CURVE_STEPPED: case CURVE_STEPPED:
timeline.setStepped(frameIndex); timeline.setStepped(frameIndex);
break; break;
case CURVE_BEZIER: case CURVE_BEZIER:
timeline.setBezier(frameIndex, bezierIndex++, value1, input.readFloat(), input.readFloat(), input.readFloat(), timeline.setBezier(frameIndex, bezierIndex++, time1, input.readFloat(), input.readFloat(), input.readFloat(),
input.readFloat(), value2); 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; break;
} }
return bezierIndex; return bezierIndex;

View File

@ -507,34 +507,45 @@ public class SkeletonJson {
SlotData slot = skeletonData.findSlot(slotMap.name); SlotData slot = skeletonData.findSlot(slotMap.name);
if (slot == null) throw new SerializationException("Slot not found: " + slotMap.name); if (slot == null) throw new SerializationException("Slot not found: " + slotMap.name);
for (JsonValue timelineMap = slotMap.child; timelineMap != null; timelineMap = timelineMap.next) { for (JsonValue timelineMap = slotMap.child; timelineMap != null; timelineMap = timelineMap.next) {
JsonValue valueMap = timelineMap.child;
if (valueMap == null) continue;
String timelineName = timelineMap.name; String timelineName = timelineMap.name;
int frameIndex = 0, bezierIndex = 0;
if (timelineName.equals("attachment")) { if (timelineName.equals("attachment")) {
AttachmentTimeline timeline = new AttachmentTimeline(timelineMap.size, slot.index); 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")); timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getString("name"));
timelines.add(timeline); timelines.add(timeline);
} else if (timelineName.equals("color")) { } else if (timelineName.equals("color")) {
ColorTimeline timeline = new ColorTimeline(timelineMap.size, 0, slot.index); 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")); Color color = Color.valueOf(valueMap.getString("color"));
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), color.r, color.g, color.b, color.a); timeline.setFrame(frameIndex, time, color.r, color.g, color.b, color.a);
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex); valueMap = valueMap.next;
} if (valueMap == null) {
timeline.shrink(bezierIndex); timeline.shrink(bezierIndex);
break;
}
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
timelines.add(timeline); timelines.add(timeline);
} else if (timelineName.equals("twoColor")) { } else if (timelineName.equals("twoColor")) {
TwoColorTimeline timeline = new TwoColorTimeline(timelineMap.size, 0, slot.index); 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")); 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); dark.r, dark.g, dark.b);
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex); valueMap = valueMap.next;
} if (valueMap == null) {
timeline.shrink(bezierIndex); timeline.shrink(bezierIndex);
break;
}
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
timelines.add(timeline); timelines.add(timeline);
} else } else
@ -550,49 +561,53 @@ public class SkeletonJson {
JsonValue valueMap = timelineMap.child; JsonValue valueMap = timelineMap.child;
if (valueMap == null) continue; if (valueMap == null) continue;
String timelineName = timelineMap.name; String timelineName = timelineMap.name;
int frameIndex = 0, bezierIndex = 0;
if (timelineName.equals("rotate")) { if (timelineName.equals("rotate")) {
RotateTimeline timeline = new RotateTimeline(timelineMap.size, 0, bone.index); timelines.add(readTimeline(valueMap, 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);
} else if (timelineName.equals("translate")) { } else if (timelineName.equals("translate")) {
TranslateTimeline timeline = new TranslateTimeline(timelineMap.size, 0, bone.index); 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); float x = valueMap.getFloat("x", 0), y = valueMap.getFloat("y", 0);
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), x * scale, y * scale); timeline.setFrame(frameIndex, time, x * scale, y * scale);
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex); valueMap = valueMap.next;
} if (valueMap == null) {
timeline.shrink(bezierIndex); timeline.shrink(bezierIndex);
break;
}
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
timelines.add(timeline); timelines.add(timeline);
} else if (timelineName.equals("scale")) { } else if (timelineName.equals("scale")) {
ScaleTimeline timeline = new ScaleTimeline(timelineMap.size, 0, bone.index); 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); float x = valueMap.getFloat("x", 1), y = valueMap.getFloat("y", 1);
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), x, y); timeline.setFrame(frameIndex, time, x, y);
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex); valueMap = valueMap.next;
} if (valueMap == null) {
timeline.shrink(bezierIndex); timeline.shrink(bezierIndex);
break;
}
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
timelines.add(timeline); timelines.add(timeline);
} else if (timelineName.equals("shear")) { } else if (timelineName.equals("shear")) {
ShearTimeline timeline = new ShearTimeline(timelineMap.size, 0, bone.index); 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); float x = valueMap.getFloat("x", 0), y = valueMap.getFloat("y", 0);
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), x, y); timeline.setFrame(frameIndex, time, x, y);
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex); valueMap = valueMap.next;
} if (valueMap == null) {
timeline.shrink(bezierIndex); timeline.shrink(bezierIndex);
break;
}
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
timelines.add(timeline); timelines.add(timeline);
} else } else
@ -601,33 +616,45 @@ public class SkeletonJson {
} }
// IK constraint timelines. // IK constraint timelines.
for (JsonValue constraintMap = map.getChild("ik"); constraintMap != null; constraintMap = constraintMap.next) { for (JsonValue timelineMap = map.getChild("ik"); timelineMap != null; timelineMap = timelineMap.next) {
IkConstraintData constraint = skeletonData.findIkConstraint(constraintMap.name); JsonValue valueMap = timelineMap.child;
IkConstraintTimeline timeline = new IkConstraintTimeline(constraintMap.size, 0, if (valueMap == null) continue;
IkConstraintData constraint = skeletonData.findIkConstraint(timelineMap.name);
IkConstraintTimeline timeline = new IkConstraintTimeline(timelineMap.size, 0,
skeletonData.getIkConstraints().indexOf(constraint, true)); skeletonData.getIkConstraints().indexOf(constraint, true));
int frameIndex = 0, bezierIndex = 0; float time = valueMap.getFloat("time", 0);
for (JsonValue valueMap = constraintMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) { for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) {
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat("mix", 1), timeline.setFrame(frameIndex, time, valueMap.getFloat("mix", 1), valueMap.getFloat("softness", 0) * scale,
valueMap.getFloat("softness", 0) * scale, valueMap.getBoolean("bendPositive", true) ? 1 : -1, valueMap.getBoolean("bendPositive", true) ? 1 : -1, valueMap.getBoolean("compress", false),
valueMap.getBoolean("compress", false), valueMap.getBoolean("stretch", false)); valueMap.getBoolean("stretch", false));
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex); valueMap = valueMap.next;
} if (valueMap == null) {
timeline.shrink(bezierIndex); timeline.shrink(bezierIndex);
break;
}
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
timelines.add(timeline); timelines.add(timeline);
} }
// Transform constraint timelines. // Transform constraint timelines.
for (JsonValue constraintMap = map.getChild("transform"); constraintMap != null; constraintMap = constraintMap.next) { for (JsonValue timelineMap = map.getChild("transform"); timelineMap != null; timelineMap = timelineMap.next) {
TransformConstraintData constraint = skeletonData.findTransformConstraint(constraintMap.name); JsonValue valueMap = timelineMap.child;
TransformConstraintTimeline timeline = new TransformConstraintTimeline(constraintMap.size, 0, if (valueMap == null) continue;
TransformConstraintData constraint = skeletonData.findTransformConstraint(timelineMap.name);
TransformConstraintTimeline timeline = new TransformConstraintTimeline(timelineMap.size, 0,
skeletonData.getTransformConstraints().indexOf(constraint, true)); skeletonData.getTransformConstraints().indexOf(constraint, true));
int frameIndex = 0, bezierIndex = 0; float time = valueMap.getFloat("time", 0);
for (JsonValue valueMap = constraintMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) { for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) {
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat("rotateMix", 1), timeline.setFrame(frameIndex, time, valueMap.getFloat("rotateMix", 1), valueMap.getFloat("translateMix", 1),
valueMap.getFloat("translateMix", 1), valueMap.getFloat("scaleMix", 1), valueMap.getFloat("shearMix", 1)); valueMap.getFloat("scaleMix", 1), valueMap.getFloat("shearMix", 1));
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex); valueMap = valueMap.next;
} if (valueMap == null) {
timeline.shrink(bezierIndex); timeline.shrink(bezierIndex);
break;
}
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
timelines.add(timeline); timelines.add(timeline);
} }
@ -637,37 +664,52 @@ public class SkeletonJson {
if (data == null) throw new SerializationException("Path constraint not found: " + constraintMap.name); if (data == null) throw new SerializationException("Path constraint not found: " + constraintMap.name);
int index = skeletonData.pathConstraints.indexOf(data, true); int index = skeletonData.pathConstraints.indexOf(data, true);
for (JsonValue timelineMap = constraintMap.child; timelineMap != null; timelineMap = timelineMap.next) { for (JsonValue timelineMap = constraintMap.child; timelineMap != null; timelineMap = timelineMap.next) {
JsonValue valueMap = timelineMap.child;
if (valueMap == null) continue;
String timelineName = timelineMap.name; String timelineName = timelineMap.name;
int frameIndex = 0, bezierIndex = 0;
if (timelineName.equals("position")) { if (timelineName.equals("position")) {
PathConstraintPositionTimeline timeline = new PathConstraintPositionTimeline(timelineMap.size, 0, index); PathConstraintPositionTimeline timeline = new PathConstraintPositionTimeline(timelineMap.size, 0, index);
float timelineScale = data.positionMode == PositionMode.fixed ? scale : 1; float timelineScale = data.positionMode == PositionMode.fixed ? scale : 1;
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) { float time = valueMap.getFloat("time", 0);
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat(timelineName, 0) * timelineScale); for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) {
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex); timeline.setFrame(frameIndex, time, valueMap.getFloat(timelineName, 0) * timelineScale);
} valueMap = valueMap.next;
if (valueMap == null) {
timeline.shrink(bezierIndex); timeline.shrink(bezierIndex);
break;
}
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
timelines.add(timeline); timelines.add(timeline);
} else if (timelineName.equals("spacing")) { } else if (timelineName.equals("spacing")) {
PathConstraintSpacingTimeline timeline = new PathConstraintSpacingTimeline(timelineMap.size, 0, index); PathConstraintSpacingTimeline timeline = new PathConstraintSpacingTimeline(timelineMap.size, 0, index);
float timelineScale = data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed ? scale : 1; float timelineScale = data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed ? scale : 1;
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) { float time = valueMap.getFloat("time", 0);
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat(timelineName, 0) * timelineScale); for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) {
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex); timeline.setFrame(frameIndex, time, valueMap.getFloat(timelineName, 0) * timelineScale);
} valueMap = valueMap.next;
if (valueMap == null) {
timeline.shrink(bezierIndex); timeline.shrink(bezierIndex);
break;
}
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
timelines.add(timeline); timelines.add(timeline);
} else if (timelineName.equals("mix")) { } else if (timelineName.equals("mix")) {
PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(timelineMap.size, 0, index); PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(timelineMap.size, 0, index);
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) { float time = valueMap.getFloat("time", 0);
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat("rotateMix", 1), for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) {
valueMap.getFloat("translateMix", 1)); timeline.setFrame(frameIndex, time, valueMap.getFloat("rotateMix", 1), valueMap.getFloat("translateMix", 1));
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex); valueMap = valueMap.next;
} if (valueMap == null) {
timeline.shrink(bezierIndex); timeline.shrink(bezierIndex);
break;
}
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
}
timelines.add(timeline); timelines.add(timeline);
} }
} }
@ -681,6 +723,9 @@ public class SkeletonJson {
SlotData slot = skeletonData.findSlot(slotMap.name); SlotData slot = skeletonData.findSlot(slotMap.name);
if (slot == null) throw new SerializationException("Slot not found: " + slotMap.name); if (slot == null) throw new SerializationException("Slot not found: " + slotMap.name);
for (JsonValue timelineMap = slotMap.child; timelineMap != null; timelineMap = timelineMap.next) { 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); VertexAttachment attachment = (VertexAttachment)skin.getAttachment(slot.index, timelineMap.name);
if (attachment == null) throw new SerializationException("Deform attachment not found: " + timelineMap.name); if (attachment == null) throw new SerializationException("Deform attachment not found: " + timelineMap.name);
boolean weighted = attachment.getBones() != null; boolean weighted = attachment.getBones() != null;
@ -688,8 +733,9 @@ public class SkeletonJson {
int deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; int deformLength = weighted ? vertices.length / 3 * 2 : vertices.length;
DeformTimeline timeline = new DeformTimeline(timelineMap.size, 0, slot.index, attachment); DeformTimeline timeline = new DeformTimeline(timelineMap.size, 0, slot.index, attachment);
int frameIndex = 0, bezierIndex = 0; int bezierIndex = 0;
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) { float time = valueMap.getFloat("time", 0);
for (int frameIndex = 0;; frameIndex++) {
float[] deform; float[] deform;
JsonValue verticesValue = valueMap.get("vertices"); JsonValue verticesValue = valueMap.get("vertices");
if (verticesValue == null) if (verticesValue == null)
@ -708,8 +754,10 @@ public class SkeletonJson {
} }
} }
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), deform); timeline.setFrame(frameIndex, time, deform);
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex); valueMap = valueMap.next;
if (valueMap == null) break;
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, time, time = valueMap.getFloat("time", 0));
} }
timeline.shrink(bezierIndex); timeline.shrink(bezierIndex);
timelines.add(timeline); timelines.add(timeline);
@ -782,27 +830,42 @@ public class SkeletonJson {
skeletonData.animations.add(new Animation(name, timelines, duration)); 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"); JsonValue curve = map.get("curve");
if (curve != null) { if (curve != null) {
if (curve.isString()) if (curve.isString())
timeline.setStepped(frameIndex); timeline.setStepped(frameIndex);
else { else {
timeline.setBezier(frameIndex, bezierIndex++, curve.asFloat(), map.getFloat("c2", 0), map.getFloat("c3", 1), timeline.setBezier(frameIndex, bezierIndex++, time1, curve.asFloat(), map.getFloat("c2", 0), map.getFloat("c3", 1),
map.getFloat("c4", 1)); map.getFloat("c4", 1), time2);
} }
} }
return bezierIndex; 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"); JsonValue curve = map.get("curve");
if (curve != null) { if (curve != null) {
if (curve.isString()) if (curve.isString())
timeline.setStepped(frameIndex); timeline.setStepped(frameIndex);
else { else {
timeline.setBezier(frameIndex, bezierIndex++, value1, curve.asFloat(), map.getFloat("c2", 0), map.getFloat("c3", 1), timeline.setBezier(frameIndex, bezierIndex++, time1, value1, curve.asFloat(), map.getFloat("c2", 0),
map.getFloat("c4", 1), value2); map.getFloat("c3", 1), map.getFloat("c4", 1), time2, value2);
} }
} }
return bezierIndex; return bezierIndex;