Restructured timelines to have a curve per value.

EsotericSoftware/spine-editor#118
This commit is contained in:
NathanSweet 2019-11-22 22:09:03 +01:00
parent ede4ac7b45
commit 952a34bc08
3 changed files with 923 additions and 713 deletions

View File

@ -43,6 +43,9 @@ import com.badlogic.gdx.utils.SerializationException;
import com.esotericsoftware.spine.Animation.AttachmentTimeline; import com.esotericsoftware.spine.Animation.AttachmentTimeline;
import com.esotericsoftware.spine.Animation.ColorTimeline; import com.esotericsoftware.spine.Animation.ColorTimeline;
import com.esotericsoftware.spine.Animation.CurveTimeline;
import com.esotericsoftware.spine.Animation.CurveTimeline1;
import com.esotericsoftware.spine.Animation.CurveTimeline2;
import com.esotericsoftware.spine.Animation.DeformTimeline; import com.esotericsoftware.spine.Animation.DeformTimeline;
import com.esotericsoftware.spine.Animation.DrawOrderTimeline; import com.esotericsoftware.spine.Animation.DrawOrderTimeline;
import com.esotericsoftware.spine.Animation.EventTimeline; import com.esotericsoftware.spine.Animation.EventTimeline;
@ -50,8 +53,6 @@ import com.esotericsoftware.spine.Animation.IkConstraintTimeline;
import com.esotericsoftware.spine.Animation.PathConstraintMixTimeline; import com.esotericsoftware.spine.Animation.PathConstraintMixTimeline;
import com.esotericsoftware.spine.Animation.PathConstraintPositionTimeline; import com.esotericsoftware.spine.Animation.PathConstraintPositionTimeline;
import com.esotericsoftware.spine.Animation.PathConstraintSpacingTimeline; import com.esotericsoftware.spine.Animation.PathConstraintSpacingTimeline;
import com.esotericsoftware.spine.Animation.PercentCurveTimeline;
import com.esotericsoftware.spine.Animation.PercentCurveTimeline2;
import com.esotericsoftware.spine.Animation.RotateTimeline; import com.esotericsoftware.spine.Animation.RotateTimeline;
import com.esotericsoftware.spine.Animation.ScaleTimeline; import com.esotericsoftware.spine.Animation.ScaleTimeline;
import com.esotericsoftware.spine.Animation.ShearTimeline; import com.esotericsoftware.spine.Animation.ShearTimeline;
@ -59,7 +60,6 @@ import com.esotericsoftware.spine.Animation.Timeline;
import com.esotericsoftware.spine.Animation.TransformConstraintTimeline; import com.esotericsoftware.spine.Animation.TransformConstraintTimeline;
import com.esotericsoftware.spine.Animation.TranslateTimeline; import com.esotericsoftware.spine.Animation.TranslateTimeline;
import com.esotericsoftware.spine.Animation.TwoColorTimeline; import com.esotericsoftware.spine.Animation.TwoColorTimeline;
import com.esotericsoftware.spine.Animation.ValueCurveTimeline;
import com.esotericsoftware.spine.BoneData.TransformMode; import com.esotericsoftware.spine.BoneData.TransformMode;
import com.esotericsoftware.spine.PathConstraintData.PositionMode; import com.esotericsoftware.spine.PathConstraintData.PositionMode;
import com.esotericsoftware.spine.PathConstraintData.RotateMode; import com.esotericsoftware.spine.PathConstraintData.RotateMode;
@ -100,11 +100,9 @@ public class SkeletonBinary {
static public final int CURVE_STEPPED = 1; static public final int CURVE_STEPPED = 1;
static public final int CURVE_BEZIER = 2; static public final int CURVE_BEZIER = 2;
static private final Color tempColor1 = new Color(), tempColor2 = new Color();
private final AttachmentLoader attachmentLoader; private final AttachmentLoader attachmentLoader;
private float scale = 1; private float scale = 1;
private Array<LinkedMesh> linkedMeshes = new Array(); private final Array<LinkedMesh> linkedMeshes = new Array();
public SkeletonBinary (TextureAtlas atlas) { public SkeletonBinary (TextureAtlas atlas) {
attachmentLoader = new AtlasAttachmentLoader(atlas); attachmentLoader = new AtlasAttachmentLoader(atlas);
@ -585,19 +583,39 @@ public class SkeletonBinary {
switch (timelineType) { switch (timelineType) {
case SLOT_ATTACHMENT: { case SLOT_ATTACHMENT: {
AttachmentTimeline timeline = new AttachmentTimeline(frameCount, slotIndex); AttachmentTimeline timeline = new AttachmentTimeline(frameCount, slotIndex);
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) for (int frame = 0; frame < frameCount; frame++)
timeline.setFrame(frameIndex, input.readFloat(), input.readStringRef()); timeline.setFrame(frame, input.readFloat(), input.readStringRef());
timelines.add(timeline); timelines.add(timeline);
break; break;
} }
case SLOT_COLOR: { case SLOT_COLOR: {
ColorTimeline timeline = new ColorTimeline(frameCount, input.readInt(true), slotIndex); ColorTimeline timeline = new ColorTimeline(frameCount, input.readInt(true), slotIndex);
float time = input.readFloat(); float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) { int c1 = input.readInt();
Color.rgba8888ToColor(tempColor1, input.readInt()); float r = ((c1 & 0xff000000) >> 24) / 255f, g = ((c1 & 0x00ff0000) >> 16) / 255f;
timeline.setFrame(frameIndex, time, tempColor1.r, tempColor1.g, tempColor1.b, tempColor1.a); float b = ((c1 & 0x0000ff00) >> 8) / 255f, a = (c1 & 0x000000ff) / 255f;
if (frameIndex == frameLast) break; for (int frame = 0, bezier = 0;; frame++) {
bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, time = input.readFloat()); timeline.setFrame(frame, time, r, g, b, a);
if (frame == frameLast) break;
float time2 = input.readFloat();
c1 = input.readInt();
float r2 = ((c1 & 0xff000000) >> 24) / 255f, g2 = ((c1 & 0x00ff0000) >> 16) / 255f;
float b2 = ((c1 & 0x0000ff00) >> 8) / 255f, a2 = (c1 & 0x000000ff) / 255f;
switch (input.readByte()) {
case CURVE_STEPPED:
timeline.setStepped(frame);
break;
case CURVE_BEZIER:
setBezier(input, timeline, bezier++, frame, 0, time, time2, r, r2);
setBezier(input, timeline, bezier++, frame, 1, time, time2, g, g2);
setBezier(input, timeline, bezier++, frame, 2, time, time2, b, b2);
setBezier(input, timeline, bezier++, frame, 3, time, time2, a, a2);
}
time = time2;
r = r2;
g = g2;
b = b2;
a = a2;
} }
timelines.add(timeline); timelines.add(timeline);
break; break;
@ -605,13 +623,42 @@ public class SkeletonBinary {
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);
float time = input.readFloat(); float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) { int c1 = input.readInt(), c2 = input.readInt();
Color.rgba8888ToColor(tempColor1, input.readInt()); float r = ((c1 & 0xff000000) >> 24) / 255f, g = ((c1 & 0x00ff0000) >> 16) / 255f;
Color.rgb888ToColor(tempColor2, input.readInt()); float b = ((c1 & 0x0000ff00) >> 8) / 255f, a = (c1 & 0x000000ff) / 255f;
timeline.setFrame(frameIndex, time, tempColor1.r, tempColor1.g, tempColor1.b, tempColor1.a, tempColor2.r, float r2 = ((c2 & 0xff000000) >> 24) / 255f, g2 = ((c2 & 0x00ff0000) >> 16) / 255f;
tempColor2.g, tempColor2.b); float b2 = ((c2 & 0x0000ff00) >> 8) / 255f;
if (frameIndex == frameLast) break; for (int frame = 0, bezier = 0;; frame++) {
bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, time = input.readFloat()); timeline.setFrame(frame, time, r, g, b, a, r2, g2, b2);
if (frame == frameLast) break;
float time2 = input.readFloat();
c1 = input.readInt();
c2 = input.readInt();
float nr = ((c1 & 0xff000000) >> 24) / 255f, ng = ((c1 & 0x00ff0000) >> 16) / 255f;
float nb = ((c1 & 0x0000ff00) >> 8) / 255f, na = (c1 & 0x000000ff) / 255f;
float nr2 = ((c2 & 0xff000000) >> 24) / 255f, ng2 = ((c2 & 0x00ff0000) >> 16) / 255f;
float nb2 = ((c2 & 0x0000ff00) >> 8) / 255f;
switch (input.readByte()) {
case CURVE_STEPPED:
timeline.setStepped(frame);
break;
case CURVE_BEZIER:
setBezier(input, timeline, bezier++, frame, 0, time, time2, r, nr);
setBezier(input, timeline, bezier++, frame, 1, time, time2, g, ng);
setBezier(input, timeline, bezier++, frame, 2, time, time2, b, nb);
setBezier(input, timeline, bezier++, frame, 3, time, time2, a, na);
setBezier(input, timeline, bezier++, frame, 4, time, time2, r2, nr2);
setBezier(input, timeline, bezier++, frame, 5, time, time2, g2, ng2);
setBezier(input, timeline, bezier++, frame, 6, time, time2, b2, nb2);
}
time = time2;
r = nr;
g = ng;
b = nb;
a = na;
r2 = nr2;
g2 = ng2;
b2 = nb2;
} }
timelines.add(timeline); timelines.add(timeline);
break; break;
@ -625,23 +672,18 @@ public class SkeletonBinary {
int boneIndex = input.readInt(true); int boneIndex = input.readInt(true);
for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) { for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) {
switch (input.readByte()) { switch (input.readByte()) {
case BONE_ROTATE: { case BONE_ROTATE:
timelines.add(readTimeline(input, new RotateTimeline(input.readInt(true), input.readInt(true), boneIndex), 1)); timelines.add(readTimeline(input, new RotateTimeline(input.readInt(true), input.readInt(true), boneIndex), 1));
break; break;
} case BONE_TRANSLATE:
case BONE_TRANSLATE: {
timelines timelines
.add(readTimeline(input, new TranslateTimeline(input.readInt(true), input.readInt(true), boneIndex), scale)); .add(readTimeline(input, new TranslateTimeline(input.readInt(true), input.readInt(true), boneIndex), scale));
break; break;
} case BONE_SCALE:
case BONE_SCALE: {
timelines.add(readTimeline(input, new ScaleTimeline(input.readInt(true), input.readInt(true), boneIndex), 1)); timelines.add(readTimeline(input, new ScaleTimeline(input.readInt(true), input.readInt(true), boneIndex), 1));
break; break;
} case BONE_SHEAR:
case BONE_SHEAR: {
timelines.add(readTimeline(input, new ShearTimeline(input.readInt(true), input.readInt(true), boneIndex), 1)); timelines.add(readTimeline(input, new ShearTimeline(input.readInt(true), input.readInt(true), boneIndex), 1));
break;
}
} }
} }
} }
@ -650,12 +692,22 @@ public class SkeletonBinary {
for (int i = 0, n = input.readInt(true); i < n; i++) { for (int i = 0, n = input.readInt(true); i < n; i++) {
int index = input.readInt(true), frameCount = input.readInt(true), frameLast = frameCount - 1; int index = input.readInt(true), 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(); float time = input.readFloat(), mix = input.readFloat(), softness = input.readFloat() * scale;
for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) { for (int frame = 0, bezier = 0;; frame++) {
timeline.setFrame(frameIndex, time, input.readFloat(), input.readFloat() * scale, input.readByte(), timeline.setFrame(frame, time, mix, softness, input.readByte(), input.readBoolean(), input.readBoolean());
input.readBoolean(), input.readBoolean()); if (frame == frameLast) break;
if (frameIndex == frameLast) break; float time2 = input.readFloat(), mix2 = input.readFloat() * scale, softness2 = input.readFloat() * scale;
bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, time = input.readFloat()); switch (input.readByte()) {
case CURVE_STEPPED:
timeline.setStepped(frame);
break;
case CURVE_BEZIER:
setBezier(input, timeline, bezier++, frame, 0, time, time2, mix, mix2);
setBezier(input, timeline, bezier++, frame, 1, time, time2, softness, softness2);
}
time = time2;
mix = mix2;
softness = softness2;
} }
timelines.add(timeline); timelines.add(timeline);
} }
@ -664,11 +716,28 @@ public class SkeletonBinary {
for (int i = 0, n = input.readInt(true); i < n; i++) { for (int i = 0, n = input.readInt(true); i < n; i++) {
int index = input.readInt(true), frameCount = input.readInt(true), frameLast = frameCount - 1; int index = input.readInt(true), 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(); float time = input.readFloat(), rotateMix = input.readFloat(), translateMix = input.readFloat(),
for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) { scaleMix = input.readFloat(), shearMix = input.readFloat();
timeline.setFrame(frameIndex, time, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat()); for (int frame = 0, bezier = 0;; frame++) {
if (frameIndex == frameLast) break; timeline.setFrame(frame, time, rotateMix, translateMix, scaleMix, shearMix);
bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, time = input.readFloat()); if (frame == frameLast) break;
float time2 = input.readFloat(), rotateMix2 = input.readFloat(), translateMix2 = input.readFloat(),
scaleMix2 = input.readFloat(), shearMix2 = input.readFloat();
switch (input.readByte()) {
case CURVE_STEPPED:
timeline.setStepped(frame);
break;
case CURVE_BEZIER:
setBezier(input, timeline, bezier++, frame, 0, time, time2, rotateMix, rotateMix2);
setBezier(input, timeline, bezier++, frame, 1, time, time2, translateMix, translateMix2);
setBezier(input, timeline, bezier++, frame, 2, time, time2, scaleMix, scaleMix2);
setBezier(input, timeline, bezier++, frame, 3, time, time2, shearMix, shearMix2);
}
time = time2;
rotateMix = rotateMix2;
translateMix = translateMix2;
scaleMix = scaleMix2;
shearMix = shearMix2;
} }
timelines.add(timeline); timelines.add(timeline);
} }
@ -679,23 +748,19 @@ public class SkeletonBinary {
PathConstraintData data = skeletonData.pathConstraints.get(index); PathConstraintData data = skeletonData.pathConstraints.get(index);
for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) { for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) {
switch (input.readByte()) { switch (input.readByte()) {
case PATH_POSITION: { case PATH_POSITION:
timelines timelines
.add(readTimeline(input, new PathConstraintSpacingTimeline(input.readInt(true), input.readInt(true), index), .add(readTimeline(input, new PathConstraintSpacingTimeline(input.readInt(true), input.readInt(true), index),
data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed ? scale : 1)); data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed ? scale : 1));
break; break;
} case PATH_SPACING:
case PATH_SPACING: {
timelines timelines
.add(readTimeline(input, new PathConstraintPositionTimeline(input.readInt(true), input.readInt(true), index), .add(readTimeline(input, new PathConstraintPositionTimeline(input.readInt(true), input.readInt(true), index),
data.positionMode == PositionMode.fixed ? scale : 1)); data.positionMode == PositionMode.fixed ? scale : 1));
break; break;
} case PATH_MIX:
case PATH_MIX: {
timelines timelines
.add(readTimeline(input, new PathConstraintMixTimeline(input.readInt(true), input.readInt(true), index), 1)); .add(readTimeline(input, new PathConstraintMixTimeline(input.readInt(true), input.readInt(true), index), 1));
break;
}
} }
} }
} }
@ -709,13 +774,13 @@ public class SkeletonBinary {
VertexAttachment attachment = (VertexAttachment)skin.getAttachment(slotIndex, input.readStringRef()); VertexAttachment attachment = (VertexAttachment)skin.getAttachment(slotIndex, input.readStringRef());
boolean weighted = attachment.getBones() != null; boolean weighted = attachment.getBones() != null;
float[] vertices = attachment.getVertices(); float[] vertices = attachment.getVertices();
int deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; int deformLength = weighted ? (vertices.length / 3) << 1 : vertices.length;
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);
float time = input.readFloat(); float time = input.readFloat();
for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) { for (int frame = 0, bezier = 0;; frame++) {
float[] deform; float[] deform;
int end = input.readInt(true); int end = input.readInt(true);
if (end == 0) if (end == 0)
@ -736,9 +801,17 @@ public class SkeletonBinary {
deform[v] += vertices[v]; deform[v] += vertices[v];
} }
} }
timeline.setFrame(frameIndex, time, deform); timeline.setFrame(frame, time, deform);
if (frameIndex == frameLast) break; if (frame == frameLast) break;
bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, time = input.readFloat()); float time2 = input.readFloat();
switch (input.readByte()) {
case CURVE_STEPPED:
timeline.setStepped(frame);
break;
case CURVE_BEZIER:
setBezier(input, timeline, bezier++, frame, 0, time, time2, 0, 1);
}
time = time2;
} }
timelines.add(timeline); timelines.add(timeline);
} }
@ -803,53 +876,50 @@ public class SkeletonBinary {
return new Animation(name, timelines, duration); return new Animation(name, timelines, duration);
} }
private Timeline readTimeline (SkeletonInput input, ValueCurveTimeline timeline, float scale) throws IOException { private Timeline readTimeline (SkeletonInput input, CurveTimeline1 timeline, float scale) throws IOException {
float time = input.readFloat(), value = input.readFloat() * scale; float time = input.readFloat(), value = input.readFloat() * scale;
for (int frameIndex = 0, bezierIndex = 0, frameLast = timeline.getFrameCount() - 1;; frameIndex++) { for (int frame = 0, bezier = 0, frameLast = timeline.getFrameCount() - 1;; frame++) {
timeline.setFrame(frameIndex, time, value); timeline.setFrame(frame, time, value);
if (frameIndex == frameLast) break; if (frame == frameLast) break;
bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, value, time = input.readFloat(), float time2 = input.readFloat(), value2 = input.readFloat() * scale;
value = input.readFloat() * scale); switch (input.readByte()) {
case CURVE_STEPPED:
timeline.setStepped(frame);
break;
case CURVE_BEZIER:
setBezier(input, timeline, bezier++, frame, 0, time, time2, value, value2);
}
time = time2;
value = value2;
} }
return timeline; return timeline;
} }
private Timeline readTimeline (SkeletonInput input, PercentCurveTimeline2 timeline, float scale) throws IOException { private Timeline readTimeline (SkeletonInput input, CurveTimeline2 timeline, float scale) throws IOException {
float time = input.readFloat(); float time = input.readFloat(), value1 = input.readFloat() * scale, value2 = input.readFloat() * scale;
for (int frameIndex = 0, bezierIndex = 0, frameLast = timeline.getFrameCount() - 1;; frameIndex++) { for (int frame = 0, bezier = 0, frameLast = timeline.getFrameCount() - 1;; frame++) {
timeline.setFrame(frameIndex, time, input.readFloat() * scale, input.readFloat() * scale); timeline.setFrame(frame, time, value1, value2);
if (frameIndex == frameLast) break; if (frame == frameLast) break;
bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex, time, time = input.readFloat()); float time2 = input.readFloat(), nvalue1 = input.readFloat() * scale, nvalue2 = input.readFloat() * scale;
switch (input.readByte()) {
case CURVE_STEPPED:
timeline.setStepped(frame);
break;
case CURVE_BEZIER:
setBezier(input, timeline, bezier++, frame, 0, time, time2, value1, nvalue1);
setBezier(input, timeline, bezier++, frame, 1, time, time2, value2, nvalue2);
}
time = time2;
value1 = nvalue1;
value2 = nvalue2;
} }
return timeline; return timeline;
} }
int readCurve (SkeletonInput input, PercentCurveTimeline timeline, int frameIndex, int bezierIndex, float time1, float time2) void setBezier (SkeletonInput input, CurveTimeline timeline, int bezier, int frame, int value, float time1, float time2,
throws IOException { float value1, float value2) throws IOException {
switch (input.readByte()) { timeline.setBezier(bezier, frame, value, time1, value1, input.readFloat(), input.readFloat(), input.readFloat(),
case CURVE_STEPPED: input.readFloat(), time2, value2);
timeline.setStepped(frameIndex);
break;
case CURVE_BEZIER:
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;
} }
static class Vertices { static class Vertices {

View File

@ -43,6 +43,9 @@ import com.badlogic.gdx.utils.SerializationException;
import com.esotericsoftware.spine.Animation.AttachmentTimeline; import com.esotericsoftware.spine.Animation.AttachmentTimeline;
import com.esotericsoftware.spine.Animation.ColorTimeline; import com.esotericsoftware.spine.Animation.ColorTimeline;
import com.esotericsoftware.spine.Animation.CurveTimeline;
import com.esotericsoftware.spine.Animation.CurveTimeline1;
import com.esotericsoftware.spine.Animation.CurveTimeline2;
import com.esotericsoftware.spine.Animation.DeformTimeline; import com.esotericsoftware.spine.Animation.DeformTimeline;
import com.esotericsoftware.spine.Animation.DrawOrderTimeline; import com.esotericsoftware.spine.Animation.DrawOrderTimeline;
import com.esotericsoftware.spine.Animation.EventTimeline; import com.esotericsoftware.spine.Animation.EventTimeline;
@ -50,8 +53,6 @@ import com.esotericsoftware.spine.Animation.IkConstraintTimeline;
import com.esotericsoftware.spine.Animation.PathConstraintMixTimeline; import com.esotericsoftware.spine.Animation.PathConstraintMixTimeline;
import com.esotericsoftware.spine.Animation.PathConstraintPositionTimeline; import com.esotericsoftware.spine.Animation.PathConstraintPositionTimeline;
import com.esotericsoftware.spine.Animation.PathConstraintSpacingTimeline; import com.esotericsoftware.spine.Animation.PathConstraintSpacingTimeline;
import com.esotericsoftware.spine.Animation.PercentCurveTimeline;
import com.esotericsoftware.spine.Animation.PercentCurveTimeline2;
import com.esotericsoftware.spine.Animation.RotateTimeline; import com.esotericsoftware.spine.Animation.RotateTimeline;
import com.esotericsoftware.spine.Animation.ScaleTimeline; import com.esotericsoftware.spine.Animation.ScaleTimeline;
import com.esotericsoftware.spine.Animation.ShearTimeline; import com.esotericsoftware.spine.Animation.ShearTimeline;
@ -59,7 +60,6 @@ import com.esotericsoftware.spine.Animation.Timeline;
import com.esotericsoftware.spine.Animation.TransformConstraintTimeline; import com.esotericsoftware.spine.Animation.TransformConstraintTimeline;
import com.esotericsoftware.spine.Animation.TranslateTimeline; import com.esotericsoftware.spine.Animation.TranslateTimeline;
import com.esotericsoftware.spine.Animation.TwoColorTimeline; import com.esotericsoftware.spine.Animation.TwoColorTimeline;
import com.esotericsoftware.spine.Animation.ValueCurveTimeline;
import com.esotericsoftware.spine.BoneData.TransformMode; import com.esotericsoftware.spine.BoneData.TransformMode;
import com.esotericsoftware.spine.PathConstraintData.PositionMode; import com.esotericsoftware.spine.PathConstraintData.PositionMode;
import com.esotericsoftware.spine.PathConstraintData.RotateMode; import com.esotericsoftware.spine.PathConstraintData.RotateMode;
@ -84,7 +84,7 @@ import com.esotericsoftware.spine.attachments.VertexAttachment;
public class SkeletonJson { public class SkeletonJson {
private final AttachmentLoader attachmentLoader; private final AttachmentLoader attachmentLoader;
private float scale = 1; private float scale = 1;
private Array<LinkedMesh> linkedMeshes = new Array(); private final Array<LinkedMesh> linkedMeshes = new Array();
public SkeletonJson (TextureAtlas atlas) { public SkeletonJson (TextureAtlas atlas) {
attachmentLoader = new AtlasAttachmentLoader(atlas); attachmentLoader = new AtlasAttachmentLoader(atlas);
@ -415,7 +415,7 @@ public class SkeletonJson {
mesh.setRegionUVs(uvs); mesh.setRegionUVs(uvs);
mesh.updateUVs(); mesh.updateUVs();
if (map.has("hull")) mesh.setHullLength(map.require("hull").asInt() * 2); if (map.has("hull")) mesh.setHullLength(map.require("hull").asInt() << 1);
if (map.has("edges")) mesh.setEdges(map.require("edges").asShortArray()); if (map.has("edges")) mesh.setEdges(map.require("edges").asShortArray());
return mesh; return mesh;
} }
@ -512,39 +512,94 @@ public class SkeletonJson {
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 (int frameIndex = 0; keyMap != null; keyMap = keyMap.next, frameIndex++) for (int frame = 0; keyMap != null; keyMap = keyMap.next, frame++)
timeline.setFrame(frameIndex, keyMap.getFloat("time", 0), keyMap.getString("name")); timeline.setFrame(frame, keyMap.getFloat("time", 0), keyMap.getString("name"));
timelines.add(timeline); timelines.add(timeline);
} else if (timelineName.equals("color")) { } else if (timelineName.equals("color")) {
ColorTimeline timeline = new ColorTimeline(timelineMap.size, timelineMap.size, slot.index); ColorTimeline timeline = new ColorTimeline(timelineMap.size, timelineMap.size << 2, slot.index);
float time = timelineMap.child.getFloat("time", 0); float time = keyMap.getFloat("time", 0);
for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) { String color = keyMap.getString("color");
Color color = Color.valueOf(keyMap.getString("color")); float r = Integer.parseInt(color.substring(0, 2), 16) / 255f;
timeline.setFrame(frameIndex, time, color.r, color.g, color.b, color.a); float g = Integer.parseInt(color.substring(2, 4), 16) / 255f;
float b = Integer.parseInt(color.substring(4, 6), 16) / 255f;
float a = Integer.parseInt(color.substring(6, 8), 16) / 255f;
for (int frame = 0, bezier = 0;; frame++) {
timeline.setFrame(frame, time, r, g, b, a);
JsonValue nextMap = keyMap.next; JsonValue nextMap = keyMap.next;
if (nextMap == null) { if (nextMap == null) {
timeline.shrink(bezierIndex); timeline.shrink(bezier);
break; break;
} }
bezierIndex = readCurve(keyMap, timeline, frameIndex, bezierIndex, time, time = nextMap.getFloat("time", 0)); float time2 = nextMap.getFloat("time", 0);
color = nextMap.getString("color");
float nr = Integer.parseInt(color.substring(0, 2), 16) / 255f;
float ng = Integer.parseInt(color.substring(2, 4), 16) / 255f;
float nb = Integer.parseInt(color.substring(4, 6), 16) / 255f;
float na = Integer.parseInt(color.substring(6, 8), 16) / 255f;
JsonValue curve = keyMap.get("curve");
if (curve != null) {
bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, r, nr);
bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, g, ng);
bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, b, nb);
bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, a, na);
}
time = time2;
r = nr;
g = ng;
b = nb;
a = na;
keyMap = nextMap; keyMap = nextMap;
} }
timelines.add(timeline); timelines.add(timeline);
} else if (timelineName.equals("twoColor")) { } else if (timelineName.equals("twoColor")) {
TwoColorTimeline timeline = new TwoColorTimeline(timelineMap.size, timelineMap.size, slot.index); TwoColorTimeline timeline = new TwoColorTimeline(timelineMap.size, timelineMap.size * 7, slot.index);
float time = timelineMap.child.getFloat("time", 0); float time = keyMap.getFloat("time", 0);
for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) { String color = keyMap.getString("light");
Color light = Color.valueOf(keyMap.getString("light")), dark = Color.valueOf(keyMap.getString("dark")); float r = Integer.parseInt(color.substring(0, 2), 16) / 255f;
timeline.setFrame(frameIndex, time, light.r, light.g, light.b, light.a, // float g = Integer.parseInt(color.substring(2, 4), 16) / 255f;
dark.r, dark.g, dark.b); float b = Integer.parseInt(color.substring(4, 6), 16) / 255f;
float a = Integer.parseInt(color.substring(6, 8), 16) / 255f;
color = keyMap.getString("dark");
float r2 = Integer.parseInt(color.substring(0, 2), 16) / 255f;
float g2 = Integer.parseInt(color.substring(2, 4), 16) / 255f;
float b2 = Integer.parseInt(color.substring(4, 6), 16) / 255f;
for (int frame = 0, bezier = 0;; frame++) {
timeline.setFrame(frame, time, r, g, b, a, r2, g2, b2);
JsonValue nextMap = keyMap.next; JsonValue nextMap = keyMap.next;
if (nextMap == null) { if (nextMap == null) {
timeline.shrink(bezierIndex); timeline.shrink(bezier);
break; break;
} }
bezierIndex = readCurve(keyMap, timeline, frameIndex, bezierIndex, time, time = nextMap.getFloat("time", 0)); float time2 = nextMap.getFloat("time", 0);
color = nextMap.getString("light");
float nr = Integer.parseInt(color.substring(0, 2), 16) / 255f;
float ng = Integer.parseInt(color.substring(2, 4), 16) / 255f;
float nb = Integer.parseInt(color.substring(4, 6), 16) / 255f;
float na = Integer.parseInt(color.substring(6, 8), 16) / 255f;
color = nextMap.getString("dark");
float nr2 = Integer.parseInt(color.substring(8, 10), 16) / 255f;
float ng2 = Integer.parseInt(color.substring(10, 12), 16) / 255f;
float nb2 = Integer.parseInt(color.substring(12, 14), 16) / 255f;
JsonValue curve = keyMap.get("curve");
if (curve != null) {
bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, r, nr);
bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, g, ng);
bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, b, nb);
bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, a, na);
bezier = readCurve(curve, timeline, bezier, frame, 4, time, time2, r2, nr2);
bezier = readCurve(curve, timeline, bezier, frame, 5, time, time2, g2, ng2);
bezier = readCurve(curve, timeline, bezier, frame, 6, time, time2, b2, nb2);
}
time = time2;
r = nr;
g = ng;
b = nb;
a = na;
r2 = nr2;
g2 = ng2;
b2 = nb2;
keyMap = nextMap; keyMap = nextMap;
} }
timelines.add(timeline); timelines.add(timeline);
@ -566,13 +621,15 @@ public class SkeletonJson {
if (timelineName.equals("rotate")) if (timelineName.equals("rotate"))
timelines.add(readTimeline(keyMap, new RotateTimeline(timelineMap.size, timelineMap.size, bone.index), 0, 1)); timelines.add(readTimeline(keyMap, new RotateTimeline(timelineMap.size, timelineMap.size, bone.index), 0, 1));
else if (timelineName.equals("translate")) { else if (timelineName.equals("translate")) {
timelines TranslateTimeline timeline = new TranslateTimeline(timelineMap.size, timelineMap.size << 1, bone.index);
.add(readTimeline(keyMap, new TranslateTimeline(timelineMap.size, timelineMap.size, bone.index), 0, scale)); timelines.add(readTimeline(keyMap, timeline, "x", "y", 0, scale));
} else if (timelineName.equals("scale")) } else if (timelineName.equals("scale")) {
timelines.add(readTimeline(keyMap, new ScaleTimeline(timelineMap.size, timelineMap.size, bone.index), 1, 1)); ScaleTimeline timeline = new ScaleTimeline(timelineMap.size, timelineMap.size << 1, bone.index);
else if (timelineName.equals("shear")) timelines.add(readTimeline(keyMap, timeline, "x", "y", 1, 1));
timelines.add(readTimeline(keyMap, new ShearTimeline(timelineMap.size, timelineMap.size, bone.index), 0, 1)); } else if (timelineName.equals("shear")) {
else ShearTimeline timeline = new ShearTimeline(timelineMap.size, timelineMap.size << 1, bone.index);
timelines.add(readTimeline(keyMap, timeline, "x", "y", 0, 1));
} else
throw new RuntimeException("Invalid timeline type for a bone: " + timelineName + " (" + boneMap.name + ")"); throw new RuntimeException("Invalid timeline type for a bone: " + timelineName + " (" + boneMap.name + ")");
} }
} }
@ -582,19 +639,28 @@ public class SkeletonJson {
JsonValue keyMap = timelineMap.child; JsonValue keyMap = timelineMap.child;
if (keyMap == null) continue; if (keyMap == null) continue;
IkConstraintData constraint = skeletonData.findIkConstraint(timelineMap.name); IkConstraintData constraint = skeletonData.findIkConstraint(timelineMap.name);
IkConstraintTimeline timeline = new IkConstraintTimeline(timelineMap.size, timelineMap.size, IkConstraintTimeline timeline = new IkConstraintTimeline(timelineMap.size, timelineMap.size << 1,
skeletonData.getIkConstraints().indexOf(constraint, true)); skeletonData.getIkConstraints().indexOf(constraint, true));
float time = keyMap.getFloat("time", 0); float time = keyMap.getFloat("time", 0);
for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) { float mix = keyMap.getFloat("mix", 1), softness = keyMap.getFloat("softness", 0) * scale;
timeline.setFrame(frameIndex, time, keyMap.getFloat("mix", 1), keyMap.getFloat("softness", 0) * scale, for (int frame = 0, bezier = 0;; frame++) {
keyMap.getBoolean("bendPositive", true) ? 1 : -1, keyMap.getBoolean("compress", false), timeline.setFrame(frame, time, mix, softness, keyMap.getBoolean("bendPositive", true) ? 1 : -1,
keyMap.getBoolean("stretch", false)); keyMap.getBoolean("compress", false), keyMap.getBoolean("stretch", false));
JsonValue nextMap = keyMap.next; JsonValue nextMap = keyMap.next;
if (nextMap == null) { if (nextMap == null) {
timeline.shrink(bezierIndex); timeline.shrink(bezier);
break; break;
} }
bezierIndex = readCurve(keyMap, timeline, frameIndex, bezierIndex, time, time = nextMap.getFloat("time", 0)); float time2 = nextMap.getFloat("time", 0);
float mix2 = nextMap.getFloat("mix", 1), softness2 = nextMap.getFloat("softness", 0) * scale;
JsonValue curve = keyMap.get("curve");
if (curve != null) {
bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, mix, mix2);
bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, softness, softness2);
}
time = time2;
mix = mix2;
softness = softness2;
keyMap = nextMap; keyMap = nextMap;
} }
timelines.add(timeline); timelines.add(timeline);
@ -605,18 +671,33 @@ public class SkeletonJson {
JsonValue keyMap = timelineMap.child; JsonValue keyMap = timelineMap.child;
if (keyMap == null) continue; if (keyMap == null) continue;
TransformConstraintData constraint = skeletonData.findTransformConstraint(timelineMap.name); TransformConstraintData constraint = skeletonData.findTransformConstraint(timelineMap.name);
TransformConstraintTimeline timeline = new TransformConstraintTimeline(timelineMap.size, timelineMap.size, TransformConstraintTimeline timeline = new TransformConstraintTimeline(timelineMap.size, timelineMap.size << 2,
skeletonData.getTransformConstraints().indexOf(constraint, true)); skeletonData.getTransformConstraints().indexOf(constraint, true));
float time = keyMap.getFloat("time", 0); float time = keyMap.getFloat("time", 0);
for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) { float rotateMix = keyMap.getFloat("rotateMix", 1), translateMix = keyMap.getFloat("translateMix", 1);
timeline.setFrame(frameIndex, time, keyMap.getFloat("rotateMix", 1), keyMap.getFloat("translateMix", 1), float scaleMix = keyMap.getFloat("scaleMix", 1), shearMix = keyMap.getFloat("shearMix", 1);
keyMap.getFloat("scaleMix", 1), keyMap.getFloat("shearMix", 1)); for (int frame = 0, bezier = 0;; frame++) {
timeline.setFrame(frame, time, rotateMix, translateMix, scaleMix, shearMix);
JsonValue nextMap = keyMap.next; JsonValue nextMap = keyMap.next;
if (nextMap == null) { if (nextMap == null) {
timeline.shrink(bezierIndex); timeline.shrink(bezier);
break; break;
} }
bezierIndex = readCurve(keyMap, timeline, frameIndex, bezierIndex, time, time = nextMap.getFloat("time", 0)); float time2 = nextMap.getFloat("time", 0);
float rotateMix2 = nextMap.getFloat("rotateMix", 1), translateMix2 = nextMap.getFloat("translateMix", 1);
float scaleMix2 = nextMap.getFloat("scaleMix", 1), shearMix2 = nextMap.getFloat("shearMix", 1);
JsonValue curve = keyMap.get("curve");
if (curve != null) {
bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, rotateMix, rotateMix2);
bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, translateMix, translateMix2);
bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, scaleMix, scaleMix2);
bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, shearMix, shearMix2);
}
time = time2;
rotateMix = rotateMix2;
translateMix = translateMix2;
scaleMix = scaleMix2;
shearMix = shearMix2;
keyMap = nextMap; keyMap = nextMap;
} }
timelines.add(timeline); timelines.add(timeline);
@ -631,16 +712,16 @@ public class SkeletonJson {
JsonValue keyMap = timelineMap.child; JsonValue keyMap = timelineMap.child;
if (keyMap == null) continue; if (keyMap == null) continue;
String timelineName = timelineMap.name; String timelineName = timelineMap.name;
if (timelineName.equals("position")) { if (timelineName.equals("position")) {
timelines.add(readTimeline(keyMap, new PathConstraintPositionTimeline(timelineMap.size, timelineMap.size, index), CurveTimeline1 timeline = new PathConstraintPositionTimeline(timelineMap.size, timelineMap.size, index);
0, data.positionMode == PositionMode.fixed ? scale : 1)); timelines.add(readTimeline(keyMap, timeline, 0, data.positionMode == PositionMode.fixed ? scale : 1));
} else if (timelineName.equals("spacing")) { } else if (timelineName.equals("spacing")) {
timelines.add(readTimeline(keyMap, new PathConstraintSpacingTimeline(timelineMap.size, timelineMap.size, index), 0, CurveTimeline1 timeline = new PathConstraintSpacingTimeline(timelineMap.size, timelineMap.size, index);
timelines.add(readTimeline(keyMap, timeline, 0,
data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed ? scale : 1)); data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed ? scale : 1));
} else if (timelineName.equals("mix")) { } else if (timelineName.equals("mix")) {
timelines CurveTimeline2 timeline = new PathConstraintMixTimeline(timelineMap.size, timelineMap.size << 1, index);
.add(readTimeline(keyMap, new PathConstraintMixTimeline(timelineMap.size, timelineMap.size, index), 1, 1)); timelines.add(readTimeline(keyMap, timeline, "rotateMix", "translateMix", 1, 1));
} }
} }
} }
@ -660,11 +741,11 @@ public class SkeletonJson {
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;
float[] vertices = attachment.getVertices(); float[] vertices = attachment.getVertices();
int deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; int deformLength = weighted ? (vertices.length / 3) << 1 : vertices.length;
DeformTimeline timeline = new DeformTimeline(timelineMap.size, timelineMap.size, slot.index, attachment); DeformTimeline timeline = new DeformTimeline(timelineMap.size, timelineMap.size, slot.index, attachment);
float time = keyMap.getFloat("time", 0); float time = keyMap.getFloat("time", 0);
for (int frameIndex = 0, bezierIndex = 0;; frameIndex++) { for (int frame = 0, bezier = 0;; frame++) {
float[] deform; float[] deform;
JsonValue verticesValue = keyMap.get("vertices"); JsonValue verticesValue = keyMap.get("vertices");
if (verticesValue == null) if (verticesValue == null)
@ -683,16 +764,19 @@ public class SkeletonJson {
} }
} }
timeline.setFrame(frameIndex, time, deform); timeline.setFrame(frame, time, deform);
JsonValue nextMap = keyMap.next; JsonValue nextMap = keyMap.next;
if (nextMap == null) { if (nextMap == null) {
timeline.shrink(bezierIndex); timeline.shrink(bezier);
break; break;
} }
bezierIndex = readCurve(keyMap, timeline, frameIndex, bezierIndex, time, time = nextMap.getFloat("time", 0)); float time2 = nextMap.getFloat("time", 0);
JsonValue curve = keyMap.get("curve");
if (curve != null) bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, 0, 1);
time = time2;
keyMap = nextMap; keyMap = nextMap;
} }
//timelines.add(timeline); timelines.add(timeline);
} }
} }
} }
@ -703,8 +787,8 @@ public class SkeletonJson {
if (drawOrdersMap != null) { if (drawOrdersMap != null) {
DrawOrderTimeline timeline = new DrawOrderTimeline(drawOrdersMap.size); DrawOrderTimeline timeline = new DrawOrderTimeline(drawOrdersMap.size);
int slotCount = skeletonData.slots.size; int slotCount = skeletonData.slots.size;
int frameIndex = 0; int frame = 0;
for (JsonValue drawOrderMap = drawOrdersMap.child; drawOrderMap != null; drawOrderMap = drawOrderMap.next, frameIndex++) { for (JsonValue drawOrderMap = drawOrdersMap.child; drawOrderMap != null; drawOrderMap = drawOrderMap.next, frame++) {
int[] drawOrder = null; int[] drawOrder = null;
JsonValue offsets = drawOrderMap.get("offsets"); JsonValue offsets = drawOrderMap.get("offsets");
if (offsets != null) { if (offsets != null) {
@ -729,7 +813,7 @@ public class SkeletonJson {
for (int i = slotCount - 1; i >= 0; i--) for (int i = slotCount - 1; i >= 0; i--)
if (drawOrder[i] == -1) drawOrder[i] = unchanged[--unchangedIndex]; if (drawOrder[i] == -1) drawOrder[i] = unchanged[--unchangedIndex];
} }
timeline.setFrame(frameIndex, drawOrderMap.getFloat("time", 0), drawOrder); timeline.setFrame(frame, drawOrderMap.getFloat("time", 0), drawOrder);
} }
timelines.add(timeline); timelines.add(timeline);
} }
@ -738,8 +822,8 @@ public class SkeletonJson {
JsonValue eventsMap = map.get("events"); JsonValue eventsMap = map.get("events");
if (eventsMap != null) { if (eventsMap != null) {
EventTimeline timeline = new EventTimeline(eventsMap.size); EventTimeline timeline = new EventTimeline(eventsMap.size);
int frameIndex = 0; int frame = 0;
for (JsonValue eventMap = eventsMap.child; eventMap != null; eventMap = eventMap.next, frameIndex++) { for (JsonValue eventMap = eventsMap.child; eventMap != null; eventMap = eventMap.next, frame++) {
EventData eventData = skeletonData.findEvent(eventMap.getString("name")); EventData eventData = skeletonData.findEvent(eventMap.getString("name"));
if (eventData == null) throw new SerializationException("Event not found: " + eventMap.getString("name")); if (eventData == null) throw new SerializationException("Event not found: " + eventMap.getString("name"));
Event event = new Event(eventMap.getFloat("time", 0), eventData); Event event = new Event(eventMap.getFloat("time", 0), eventData);
@ -750,7 +834,7 @@ public class SkeletonJson {
event.volume = eventMap.getFloat("volume", eventData.volume); event.volume = eventMap.getFloat("volume", eventData.volume);
event.balance = eventMap.getFloat("balance", eventData.balance); event.balance = eventMap.getFloat("balance", eventData.balance);
} }
timeline.setFrame(frameIndex, event); timeline.setFrame(frame, event);
} }
timelines.add(timeline); timelines.add(timeline);
} }
@ -762,62 +846,71 @@ public class SkeletonJson {
skeletonData.animations.add(new Animation(name, timelines, duration)); skeletonData.animations.add(new Animation(name, timelines, duration));
} }
private ValueCurveTimeline readTimeline (JsonValue keyMap, ValueCurveTimeline timeline, float defaultValue, float scale) { private Timeline readTimeline (JsonValue keyMap, CurveTimeline1 timeline, float defaultValue, float scale) {
float time = keyMap.getFloat("time", 0), value = keyMap.getFloat("value", defaultValue); float time = keyMap.getFloat("time", 0), value = keyMap.getFloat("value", defaultValue);
int bezierIndex = 0; int bezier = 0;
for (int frameIndex = 0;; frameIndex++) { for (int frame = 0;; frame++) {
timeline.setFrame(frameIndex, time, value); timeline.setFrame(frame, time, value);
JsonValue nextMap = keyMap.next; JsonValue nextMap = keyMap.next;
if (nextMap == null) break; if (nextMap == null) break;
bezierIndex = readCurve(keyMap, timeline, frameIndex, bezierIndex, // float time2 = nextMap.getFloat("time", 0);
time, value, time = nextMap.getFloat("time", 0), value = nextMap.getFloat("value", defaultValue)); float value2 = nextMap.getFloat("value", defaultValue);
JsonValue curve = keyMap.get("curve");
if (curve != null) bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, value, value2);
time = time2;
value = value2;
keyMap = nextMap; keyMap = nextMap;
} }
timeline.shrink(bezierIndex); timeline.shrink(bezier);
return timeline; return timeline;
} }
private PercentCurveTimeline2 readTimeline (JsonValue keyMap, PercentCurveTimeline2 timeline, float defaultValue, private Timeline readTimeline (JsonValue keyMap, CurveTimeline2 timeline, String name1, String name2, float defaultValue,
float scale) { float scale) {
float time = keyMap.getFloat("time", 0); float time = keyMap.getFloat("time", 0);
int bezierIndex = 0; float value1 = keyMap.getFloat(name1, defaultValue), value2 = keyMap.getFloat(name2, defaultValue);
for (int frameIndex = 0;; frameIndex++) { int bezier = 0;
float x = keyMap.getFloat("x", defaultValue), y = keyMap.getFloat("y", defaultValue); for (int frame = 0;; frame++) {
timeline.setFrame(frameIndex, time, x * scale, y * scale); timeline.setFrame(frame, time, value1, value2);
JsonValue nextMap = keyMap.next; JsonValue nextMap = keyMap.next;
if (nextMap == null) break; if (nextMap == null) break;
bezierIndex = readCurve(keyMap, timeline, frameIndex, bezierIndex, time, time = nextMap.getFloat("time", 0)); float time2 = nextMap.getFloat("time", 0);
float nvalue1 = nextMap.getFloat(name1, defaultValue), nvalue2 = nextMap.getFloat(name2, defaultValue);
JsonValue curve = keyMap.get("curve");
if (curve != null) {
bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, value1, nvalue1);
bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, value2, nvalue2);
}
time = time2;
value1 = nvalue1;
value2 = nvalue2;
keyMap = nextMap; keyMap = nextMap;
} }
timeline.shrink(bezierIndex); timeline.shrink(bezier);
return timeline; return timeline;
} }
int readCurve (JsonValue map, PercentCurveTimeline timeline, int frameIndex, int bezierIndex, float time1, float time2) { int readCurve (JsonValue curve, CurveTimeline timeline, int bezier, int frame, int value, float time1, float time2,
JsonValue curve = map.get("curve"); float value1, float value2) {
if (curve != null) { if (curve.isString()) {
if (curve.isString()) if (value != 0) timeline.setStepped(frame);
timeline.setStepped(frameIndex); } else {
else { curve = curve.get(value * 4);
timeline.setBezier(frameIndex, bezierIndex++, time1, curve.asFloat(), map.getFloat("c2", 0), map.getFloat("c3", 1), float cx1 = curve.asFloat();
map.getFloat("c4", 1), time2); curve = curve.next;
} float cy1 = curve.asFloat();
curve = curve.next;
float cx2 = curve.asFloat();
curve = curve.next;
float cy2 = curve.asFloat();
setBezier(timeline, frame, value, bezier++, time1, value1, cx1, cy1, cx2, cy2, time2, value2);
} }
return bezierIndex; return bezier;
} }
int readCurve (JsonValue map, ValueCurveTimeline timeline, int frameIndex, int bezierIndex, float time1, float value1, void setBezier (CurveTimeline timeline, int frame, int value, int bezier, float time1, float value1, float cx1, float cy1,
float time2, float value2) { float cx2, float cy2, float time2, float value2) {
JsonValue curve = map.get("curve"); timeline.setBezier(bezier, frame, value, time1, value1, cx1, cy1, cx2, cy2, time2, value2);
if (curve != null) {
if (curve.isString())
timeline.setStepped(frameIndex);
else {
timeline.setBezier(frameIndex, bezierIndex++, time1, value1, curve.asFloat(), map.getFloat("c2", 0),
map.getFloat("c3", 1), map.getFloat("c4", 1), time2, value2);
}
}
return bezierIndex;
} }
static class LinkedMesh { static class LinkedMesh {