[libgdx] Added separate keying for translateX/Y, scaleX/Y, shearX/Y, and colorRGB/A.

The first editor version able to export data in this format is 4.0.24-beta.

EsotericSoftware/spine-editor#26
EsotericSoftware/spine-editor#27
This commit is contained in:
Nathan Sweet 2020-11-10 17:43:47 -08:00
parent c223481255
commit 549e9ae67b
3 changed files with 870 additions and 52 deletions

View File

@ -187,9 +187,9 @@ public class Animation {
in, out
}
static enum Property {
static private enum Property {
rotate, translateX, translateY, scaleX, scaleY, shearX, shearY, //
rgba, rgb2, //
rgb, alpha, rgb2, //
attachment, deform, //
event, drawOrder, //
ikConstraint, transformConstraint, //
@ -560,6 +560,98 @@ public class Animation {
}
}
/** Changes a bone's local {@link Bone#getX()}. */
static public class TranslateXTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex;
public TranslateXTimeline (int frameCount, int bezierCount, int boneIndex) {
super(frameCount, bezierCount, Property.translateX.ordinal() + "|" + boneIndex);
this.boneIndex = boneIndex;
}
public int getBoneIndex () {
return boneIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction) {
Bone bone = skeleton.bones.get(boneIndex);
if (!bone.active) return;
float[] frames = this.frames;
if (time < frames[0]) { // Time is before first frame.
switch (blend) {
case setup:
bone.x = bone.data.x;
return;
case first:
bone.x += (bone.data.x - bone.x) * alpha;
}
return;
}
float x = getCurveValue(time);
switch (blend) {
case setup:
bone.x = bone.data.x + x * alpha;
break;
case first:
case replace:
bone.x += (bone.data.x + x - bone.x) * alpha;
break;
case add:
bone.x += x * alpha;
}
}
}
/** Changes a bone's local {@link Bone#getY()}. */
static public class TranslateYTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex;
public TranslateYTimeline (int frameCount, int bezierCount, int boneIndex) {
super(frameCount, bezierCount, Property.translateY.ordinal() + "|" + boneIndex);
this.boneIndex = boneIndex;
}
public int getBoneIndex () {
return boneIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction) {
Bone bone = skeleton.bones.get(boneIndex);
if (!bone.active) return;
float[] frames = this.frames;
if (time < frames[0]) { // Time is before first frame.
switch (blend) {
case setup:
bone.y = bone.data.y;
return;
case first:
bone.y += (bone.data.y - bone.y) * alpha;
}
return;
}
float y = getCurveValue(time);
switch (blend) {
case setup:
bone.y = bone.data.y + y * alpha;
break;
case first:
case replace:
bone.y += (bone.data.y + y - bone.y) * alpha;
break;
case add:
bone.y += y * alpha;
}
}
}
/** Changes a bone's local {@link Bone#getScaleX()} and {@link Bone#getScaleY()}. */
static public class ScaleTimeline extends CurveTimeline2 implements BoneTimeline {
final int boneIndex;
@ -675,6 +767,156 @@ public class Animation {
}
}
/** Changes a bone's local {@link Bone#getScaleX()}. */
static public class ScaleXTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex;
public ScaleXTimeline (int frameCount, int bezierCount, int boneIndex) {
super(frameCount, bezierCount, Property.scaleX.ordinal() + "|" + boneIndex);
this.boneIndex = boneIndex;
}
public int getBoneIndex () {
return boneIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction) {
Bone bone = skeleton.bones.get(boneIndex);
if (!bone.active) return;
float[] frames = this.frames;
if (time < frames[0]) { // Time is before first frame.
switch (blend) {
case setup:
bone.scaleX = bone.data.scaleX;
return;
case first:
bone.scaleX += (bone.data.scaleX - bone.scaleX) * alpha;
}
return;
}
float x = getCurveValue(time) * bone.data.scaleX;
if (alpha == 1) {
if (blend == add)
bone.scaleX += x - bone.data.scaleX;
else
bone.scaleX = x;
} else {
// Mixing out uses sign of setup or current pose, else use sign of key.
float bx;
if (direction == out) {
switch (blend) {
case setup:
bx = bone.data.scaleX;
bone.scaleX = bx + (Math.abs(x) * Math.signum(bx) - bx) * alpha;
break;
case first:
case replace:
bx = bone.scaleX;
bone.scaleX = bx + (Math.abs(x) * Math.signum(bx) - bx) * alpha;
break;
case add:
bx = bone.scaleX;
bone.scaleX = bx + (Math.abs(x) * Math.signum(bx) - bone.data.scaleX) * alpha;
}
} else {
switch (blend) {
case setup:
bx = Math.abs(bone.data.scaleX) * Math.signum(x);
bone.scaleX = bx + (x - bx) * alpha;
break;
case first:
case replace:
bx = Math.abs(bone.scaleX) * Math.signum(x);
bone.scaleX = bx + (x - bx) * alpha;
break;
case add:
bx = Math.signum(x);
bone.scaleX = Math.abs(bone.scaleX) * bx + (x - Math.abs(bone.data.scaleX) * bx) * alpha;
}
}
}
}
}
/** Changes a bone's local {@link Bone#getScaleY()}. */
static public class ScaleYTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex;
public ScaleYTimeline (int frameCount, int bezierCount, int boneIndex) {
super(frameCount, bezierCount, Property.scaleY.ordinal() + "|" + boneIndex);
this.boneIndex = boneIndex;
}
public int getBoneIndex () {
return boneIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction) {
Bone bone = skeleton.bones.get(boneIndex);
if (!bone.active) return;
float[] frames = this.frames;
if (time < frames[0]) { // Time is before first frame.
switch (blend) {
case setup:
bone.scaleY = bone.data.scaleY;
return;
case first:
bone.scaleY += (bone.data.scaleY - bone.scaleY) * alpha;
}
return;
}
float y = getCurveValue(time) * bone.data.scaleY;
if (alpha == 1) {
if (blend == add)
bone.scaleY += y - bone.data.scaleY;
else
bone.scaleY = y;
} else {
// Mixing out uses sign of setup or current pose, else use sign of key.
float by;
if (direction == out) {
switch (blend) {
case setup:
by = bone.data.scaleY;
bone.scaleY = by + (Math.abs(y) * Math.signum(by) - by) * alpha;
break;
case first:
case replace:
by = bone.scaleY;
bone.scaleY = by + (Math.abs(y) * Math.signum(by) - by) * alpha;
break;
case add:
by = bone.scaleY;
bone.scaleY = by + (Math.abs(y) * Math.signum(by) - bone.data.scaleY) * alpha;
}
} else {
switch (blend) {
case setup:
by = Math.abs(bone.data.scaleY) * Math.signum(y);
bone.scaleY = by + (y - by) * alpha;
break;
case first:
case replace:
by = Math.abs(bone.scaleY) * Math.signum(y);
bone.scaleY = by + (y - by) * alpha;
break;
case add:
by = Math.signum(y);
bone.scaleY = Math.abs(bone.scaleY) * by + (y - Math.abs(bone.data.scaleY) * by) * alpha;
}
}
}
}
}
/** Changes a bone's local {@link Bone#getShearX()} and {@link Bone#getShearY()}. */
static public class ShearTimeline extends CurveTimeline2 implements BoneTimeline {
final int boneIndex;
@ -747,16 +989,109 @@ public class Animation {
}
}
/** Changes a bone's local {@link Bone#getShearX()}. */
static public class ShearXTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex;
public ShearXTimeline (int frameCount, int bezierCount, int boneIndex) {
super(frameCount, bezierCount, Property.shearX.ordinal() + "|" + boneIndex);
this.boneIndex = boneIndex;
}
public int getBoneIndex () {
return boneIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction) {
Bone bone = skeleton.bones.get(boneIndex);
if (!bone.active) return;
float[] frames = this.frames;
if (time < frames[0]) { // Time is before first frame.
switch (blend) {
case setup:
bone.shearX = bone.data.shearX;
return;
case first:
bone.shearX += (bone.data.shearX - bone.shearX) * alpha;
}
return;
}
float x = getCurveValue(time);
switch (blend) {
case setup:
bone.shearX = bone.data.shearX + x * alpha;
break;
case first:
case replace:
bone.shearX += (bone.data.shearX + x - bone.shearX) * alpha;
break;
case add:
bone.shearX += x * alpha;
}
}
}
/** Changes a bone's local {@link Bone#getShearY()}. */
static public class ShearYTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex;
public ShearYTimeline (int frameCount, int bezierCount, int boneIndex) {
super(frameCount, bezierCount, Property.shearY.ordinal() + "|" + boneIndex);
this.boneIndex = boneIndex;
}
public int getBoneIndex () {
return boneIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction) {
Bone bone = skeleton.bones.get(boneIndex);
if (!bone.active) return;
float[] frames = this.frames;
if (time < frames[0]) { // Time is before first frame.
switch (blend) {
case setup:
bone.shearY = bone.data.shearY;
return;
case first:
bone.shearY += (bone.data.shearY - bone.shearY) * alpha;
}
return;
}
float y = getCurveValue(time);
switch (blend) {
case setup:
bone.shearY = bone.data.shearY + y * alpha;
break;
case first:
case replace:
bone.shearY += (bone.data.shearY + y - bone.shearY) * alpha;
break;
case add:
bone.shearY += y * alpha;
}
}
}
/** Changes a slot's {@link Slot#getColor()}. */
static public class ColorTimeline extends CurveTimeline implements SlotTimeline {
static public class RGBATimeline extends CurveTimeline implements SlotTimeline {
static public final int ENTRIES = 5;
static private final int R = 1, G = 2, B = 3, A = 4;
final int slotIndex;
public ColorTimeline (int frameCount, int bezierCount, int slotIndex) {
public RGBATimeline (int frameCount, int bezierCount, int slotIndex) {
super(frameCount, bezierCount, //
Property.rgba.ordinal() + "|" + slotIndex);
Property.rgb.ordinal() + "|" + slotIndex, //
Property.alpha.ordinal() + "|" + slotIndex);
this.slotIndex = slotIndex;
}
@ -788,12 +1123,12 @@ public class Animation {
float[] frames = this.frames;
if (time < frames[0]) { // Time is before first frame.
Color color = slot.color, setup = slot.data.color;
switch (blend) {
case setup:
slot.color.set(slot.data.color);
color.set(setup);
return;
case first:
Color color = slot.color, setup = slot.data.color;
color.add((setup.r - color.r) * alpha, (setup.g - color.g) * alpha, (setup.b - color.b) * alpha,
(setup.a - color.a) * alpha);
}
@ -828,26 +1163,170 @@ public class Animation {
a = getBezierValue(time, i, A, curveType + BEZIER_SIZE * 3 - BEZIER);
}
Color color = slot.color;
if (alpha == 1)
slot.color.set(r, g, b, a);
else {
Color color = slot.color;
if (blend == setup) color.set(slot.data.color);
color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha);
}
}
}
/** Changes the RGB for a slot's {@link Slot#getColor()}. */
static public class RGBTimeline extends CurveTimeline implements SlotTimeline {
static public final int ENTRIES = 4;
static private final int R = 1, G = 2, B = 3;
final int slotIndex;
public RGBTimeline (int frameCount, int bezierCount, int slotIndex) {
super(frameCount, bezierCount, Property.rgb.ordinal() + "|" + slotIndex);
this.slotIndex = slotIndex;
}
public int getFrameEntries () {
return ENTRIES;
}
public int getSlotIndex () {
return slotIndex;
}
/** Sets the time and color for the specified frame.
* @param frame Between 0 and <code>frameCount</code>, inclusive.
* @param time The frame time in seconds. */
public void setFrame (int frame, float time, float r, float g, float b) {
frame <<= 2;
frames[frame] = time;
frames[frame + R] = r;
frames[frame + G] = g;
frames[frame + B] = b;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction) {
Slot slot = skeleton.slots.get(slotIndex);
if (!slot.bone.active) return;
float[] frames = this.frames;
if (time < frames[0]) { // Time is before first frame.
Color color = slot.color, setup = slot.data.color;
switch (blend) {
case setup:
color.r = setup.r;
color.g = setup.g;
color.b = setup.b;
return;
case first:
color.r += (setup.r - color.r) * alpha;
color.g += (setup.g - color.g) * alpha;
color.b += (setup.b - color.b) * alpha;
}
return;
}
float r, g, b;
int i = search(frames, time, ENTRIES), curveType = (int)curves[i >> 2];
switch (curveType) {
case LINEAR:
float before = frames[i];
r = frames[i + R];
g = frames[i + G];
b = frames[i + B];
float t = (time - before) / (frames[i + ENTRIES] - before);
r += (frames[i + ENTRIES + R] - r) * t;
g += (frames[i + ENTRIES + G] - g) * t;
b += (frames[i + ENTRIES + B] - b) * t;
break;
case STEPPED:
r = frames[i + R];
g = frames[i + G];
b = frames[i + B];
break;
default:
r = getBezierValue(time, i, R, curveType - BEZIER);
g = getBezierValue(time, i, G, curveType + BEZIER_SIZE - BEZIER);
b = getBezierValue(time, i, B, curveType + BEZIER_SIZE * 2 - BEZIER);
}
Color color = slot.color;
if (alpha == 1) {
color.r = r;
color.g = g;
color.b = b;
} else {
if (blend == setup) {
Color setup = slot.data.color;
color.r = setup.r;
color.g = setup.g;
color.b = setup.b;
}
color.r += (r - color.r) * alpha;
color.g += (g - color.g) * alpha;
color.b += (b - color.b) * alpha;
}
}
}
/** Changes the alpha for a slot's {@link Slot#getColor()}. */
static public class AlphaTimeline extends CurveTimeline1 implements SlotTimeline {
final int slotIndex;
public AlphaTimeline (int frameCount, int bezierCount, int slotIndex) {
super(frameCount, bezierCount, Property.alpha.ordinal() + "|" + slotIndex);
this.slotIndex = slotIndex;
}
public int getSlotIndex () {
return slotIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction) {
Slot slot = skeleton.slots.get(slotIndex);
if (!slot.bone.active) return;
float[] frames = this.frames;
if (time < frames[0]) { // Time is before first frame.
Color color = slot.color, setup = slot.data.color;
switch (blend) {
case setup:
color.r = setup.r;
color.g = setup.g;
color.b = setup.b;
return;
case first:
color.r += (setup.r - color.r) * alpha;
color.g += (setup.g - color.g) * alpha;
color.b += (setup.b - color.b) * alpha;
}
return;
}
float a = getCurveValue(time);
if (alpha == 1)
slot.color.a = a;
else {
if (blend == setup) slot.color.a = slot.data.color.a;
slot.color.a += (a - slot.color.a) * alpha;
}
}
}
/** Changes a slot's {@link Slot#getColor()} and {@link Slot#getDarkColor()} for two color tinting. */
static public class TwoColorTimeline extends CurveTimeline implements SlotTimeline {
static public class RGBA2Timeline extends CurveTimeline implements SlotTimeline {
static public final int ENTRIES = 8;
static private final int R = 1, G = 2, B = 3, A = 4, R2 = 5, G2 = 6, B2 = 7;
final int slotIndex;
public TwoColorTimeline (int frameCount, int bezierCount, int slotIndex) {
public RGBA2Timeline (int frameCount, int bezierCount, int slotIndex) {
super(frameCount, bezierCount, //
Property.rgba.ordinal() + "|" + slotIndex, //
Property.rgb.ordinal() + "|" + slotIndex, //
Property.alpha.ordinal() + "|" + slotIndex, //
Property.rgb2.ordinal() + "|" + slotIndex);
this.slotIndex = slotIndex;
}
@ -885,16 +1364,20 @@ public class Animation {
float[] frames = this.frames;
if (time < frames[0]) { // Time is before first frame.
Color light = slot.color, dark = slot.darkColor, setupLight = slot.data.color, setupDark = slot.data.darkColor;
switch (blend) {
case setup:
slot.color.set(slot.data.color);
slot.darkColor.set(slot.data.darkColor);
light.set(setupLight);
dark.r = setupDark.r;
dark.g = setupDark.g;
dark.b = setupDark.b;
return;
case first:
Color light = slot.color, dark = slot.darkColor, setupLight = slot.data.color, setupDark = slot.data.darkColor;
light.add((setupLight.r - light.r) * alpha, (setupLight.g - light.g) * alpha, (setupLight.b - light.b) * alpha,
(setupLight.a - light.a) * alpha);
dark.add((setupDark.r - dark.r) * alpha, (setupDark.g - dark.g) * alpha, (setupDark.b - dark.b) * alpha, 0);
dark.r += (setupDark.r - dark.r) * alpha;
dark.g += (setupDark.g - dark.g) * alpha;
dark.b += (setupDark.b - dark.b) * alpha;
}
return;
}
@ -939,17 +1422,152 @@ public class Animation {
b2 = getBezierValue(time, i, B2, curveType + BEZIER_SIZE * 6 - BEZIER);
}
Color light = slot.color, dark = slot.darkColor;
if (alpha == 1) {
slot.color.set(r, g, b, a);
slot.darkColor.set(r2, g2, b2, 1);
dark.r = r2;
dark.g = g2;
dark.b = b2;
} else {
Color light = slot.color, dark = slot.darkColor;
if (blend == setup) {
light.set(slot.data.color);
dark.set(slot.data.darkColor);
}
light.add((r - light.r) * alpha, (g - light.g) * alpha, (b - light.b) * alpha, (a - light.a) * alpha);
dark.add((r2 - dark.r) * alpha, (g2 - dark.g) * alpha, (b2 - dark.b) * alpha, 0);
dark.r += (r2 - dark.r) * alpha;
dark.g += (g2 - dark.g) * alpha;
dark.b += (b2 - dark.b) * alpha;
}
}
}
/** Changes the RGB for a slot's {@link Slot#getColor()} and {@link Slot#getDarkColor()} for two color tinting. */
static public class RGB2Timeline extends CurveTimeline implements SlotTimeline {
static public final int ENTRIES = 7;
static private final int R = 1, G = 2, B = 3, R2 = 5, G2 = 6, B2 = 7;
final int slotIndex;
public RGB2Timeline (int frameCount, int bezierCount, int slotIndex) {
super(frameCount, bezierCount, //
Property.rgb.ordinal() + "|" + slotIndex, //
Property.rgb2.ordinal() + "|" + slotIndex);
this.slotIndex = slotIndex;
}
public int getFrameEntries () {
return ENTRIES;
}
/** The index of the slot in {@link Skeleton#getSlots()} that will be changed when this timeline is applied. The
* {@link Slot#getDarkColor()} must not be null. */
public int getSlotIndex () {
return slotIndex;
}
/** Sets the time, light color, and dark color for the specified frame.
* @param frame Between 0 and <code>frameCount</code>, inclusive.
* @param time The frame time in seconds. */
public void setFrame (int frame, float time, float r, float g, float b, float r2, float g2, float b2) {
frame *= ENTRIES;
frames[frame] = time;
frames[frame + R] = r;
frames[frame + G] = g;
frames[frame + B] = b;
frames[frame + R2] = r2;
frames[frame + G2] = g2;
frames[frame + B2] = b2;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction) {
Slot slot = skeleton.slots.get(slotIndex);
if (!slot.bone.active) return;
float[] frames = this.frames;
if (time < frames[0]) { // Time is before first frame.
Color light = slot.color, dark = slot.darkColor, setupLight = slot.data.color, setupDark = slot.data.darkColor;
switch (blend) {
case setup:
light.r = setupLight.r;
light.g = setupLight.g;
light.b = setupLight.b;
dark.r = setupDark.r;
dark.g = setupDark.g;
dark.b = setupDark.b;
return;
case first:
light.r += (setupLight.r - light.r) * alpha;
light.g += (setupLight.g - light.g) * alpha;
light.b += (setupLight.b - light.b) * alpha;
dark.r += (setupDark.r - dark.r) * alpha;
dark.g += (setupDark.g - dark.g) * alpha;
dark.b += (setupDark.b - dark.b) * alpha;
}
return;
}
float r, g, b, r2, g2, b2;
int i = search(frames, time, ENTRIES), curveType = (int)curves[i / ENTRIES];
switch (curveType) {
case LINEAR:
float before = frames[i];
r = frames[i + R];
g = frames[i + G];
b = frames[i + B];
r2 = frames[i + R2];
g2 = frames[i + G2];
b2 = frames[i + B2];
float t = (time - before) / (frames[i + ENTRIES] - before);
r += (frames[i + ENTRIES + R] - r) * t;
g += (frames[i + ENTRIES + G] - g) * t;
b += (frames[i + ENTRIES + B] - b) * t;
r2 += (frames[i + ENTRIES + R2] - r2) * t;
g2 += (frames[i + ENTRIES + G2] - g2) * t;
b2 += (frames[i + ENTRIES + B2] - b2) * t;
break;
case STEPPED:
r = frames[i + R];
g = frames[i + G];
b = frames[i + B];
r2 = frames[i + R2];
g2 = frames[i + G2];
b2 = frames[i + B2];
break;
default:
r = getBezierValue(time, i, R, curveType - BEZIER);
g = getBezierValue(time, i, G, curveType + BEZIER_SIZE - BEZIER);
b = getBezierValue(time, i, B, curveType + BEZIER_SIZE * 2 - BEZIER);
r2 = getBezierValue(time, i, R2, curveType + BEZIER_SIZE * 3 - BEZIER);
g2 = getBezierValue(time, i, G2, curveType + BEZIER_SIZE * 4 - BEZIER);
b2 = getBezierValue(time, i, B2, curveType + BEZIER_SIZE * 5 - BEZIER);
}
Color light = slot.color, dark = slot.darkColor;
if (alpha == 1) {
light.r = r;
light.g = g;
light.b = b;
dark.r = r2;
dark.g = g2;
dark.b = b2;
} else {
if (blend == setup) {
Color setupLight = slot.data.color, setupDark = slot.data.darkColor;
light.r = setupLight.r;
light.g = setupLight.g;
light.b = setupLight.b;
dark.r = setupDark.r;
dark.g = setupDark.g;
dark.b = setupDark.b;
}
light.r += (r - light.r) * alpha;
light.g += (g - light.g) * alpha;
light.b += (b - light.b) * alpha;
dark.r += (r2 - dark.r) * alpha;
dark.g += (g2 - dark.g) * alpha;
dark.b += (b2 - dark.b) * alpha;
}
}
}

View File

@ -42,8 +42,8 @@ import com.badlogic.gdx.utils.IntArray;
import com.badlogic.gdx.utils.Null;
import com.badlogic.gdx.utils.SerializationException;
import com.esotericsoftware.spine.Animation.AlphaTimeline;
import com.esotericsoftware.spine.Animation.AttachmentTimeline;
import com.esotericsoftware.spine.Animation.ColorTimeline;
import com.esotericsoftware.spine.Animation.CurveTimeline;
import com.esotericsoftware.spine.Animation.CurveTimeline1;
import com.esotericsoftware.spine.Animation.CurveTimeline2;
@ -54,13 +54,22 @@ import com.esotericsoftware.spine.Animation.IkConstraintTimeline;
import com.esotericsoftware.spine.Animation.PathConstraintMixTimeline;
import com.esotericsoftware.spine.Animation.PathConstraintPositionTimeline;
import com.esotericsoftware.spine.Animation.PathConstraintSpacingTimeline;
import com.esotericsoftware.spine.Animation.RGB2Timeline;
import com.esotericsoftware.spine.Animation.RGBA2Timeline;
import com.esotericsoftware.spine.Animation.RGBATimeline;
import com.esotericsoftware.spine.Animation.RGBTimeline;
import com.esotericsoftware.spine.Animation.RotateTimeline;
import com.esotericsoftware.spine.Animation.ScaleTimeline;
import com.esotericsoftware.spine.Animation.ScaleXTimeline;
import com.esotericsoftware.spine.Animation.ScaleYTimeline;
import com.esotericsoftware.spine.Animation.ShearTimeline;
import com.esotericsoftware.spine.Animation.ShearXTimeline;
import com.esotericsoftware.spine.Animation.ShearYTimeline;
import com.esotericsoftware.spine.Animation.Timeline;
import com.esotericsoftware.spine.Animation.TransformConstraintTimeline;
import com.esotericsoftware.spine.Animation.TranslateTimeline;
import com.esotericsoftware.spine.Animation.TwoColorTimeline;
import com.esotericsoftware.spine.Animation.TranslateXTimeline;
import com.esotericsoftware.spine.Animation.TranslateYTimeline;
import com.esotericsoftware.spine.BoneData.TransformMode;
import com.esotericsoftware.spine.PathConstraintData.PositionMode;
import com.esotericsoftware.spine.PathConstraintData.RotateMode;
@ -85,12 +94,21 @@ import com.esotericsoftware.spine.attachments.VertexAttachment;
public class SkeletonBinary extends SkeletonLoader {
static public final int BONE_ROTATE = 0;
static public final int BONE_TRANSLATE = 1;
static public final int BONE_SCALE = 2;
static public final int BONE_SHEAR = 3;
static public final int BONE_TRANSLATEX = 2;
static public final int BONE_TRANSLATEY = 3;
static public final int BONE_SCALE = 4;
static public final int BONE_SCALEX = 5;
static public final int BONE_SCALEY = 6;
static public final int BONE_SHEAR = 7;
static public final int BONE_SHEARX = 8;
static public final int BONE_SHEARY = 9;
static public final int SLOT_ATTACHMENT = 0;
static public final int SLOT_COLOR = 1;
static public final int SLOT_TWO_COLOR = 2;
static public final int SLOT_RGBA = 1;
static public final int SLOT_RGB = 2;
static public final int SLOT_ALPHA = 3;
static public final int SLOT_RGBA2 = 4;
static public final int SLOT_RGB2 = 5;
static public final int PATH_POSITION = 0;
static public final int PATH_SPACING = 1;
@ -493,7 +511,7 @@ public class SkeletonBinary extends SkeletonLoader {
if (nonessential) Color.rgba8888ToColor(point.getColor(), color);
return point;
}
case clipping: {
case clipping:
int endSlotIndex = input.readInt(true);
int vertexCount = input.readInt(true);
Vertices vertices = readVertices(input, vertexCount);
@ -508,7 +526,6 @@ public class SkeletonBinary extends SkeletonLoader {
if (nonessential) Color.rgba8888ToColor(clip.getColor(), color);
return clip;
}
}
return null;
}
@ -574,8 +591,8 @@ public class SkeletonBinary extends SkeletonLoader {
timelines.add(timeline);
break;
}
case SLOT_COLOR: {
ColorTimeline timeline = new ColorTimeline(frameCount, input.readInt(true), slotIndex);
case SLOT_RGBA: {
RGBATimeline timeline = new RGBATimeline(frameCount, input.readInt(true), slotIndex);
float time = input.readFloat();
float r = input.read() / 255f, g = input.read() / 255f;
float b = input.read() / 255f, a = input.read() / 255f;
@ -604,21 +621,48 @@ public class SkeletonBinary extends SkeletonLoader {
timelines.add(timeline);
break;
}
case SLOT_TWO_COLOR: {
TwoColorTimeline timeline = new TwoColorTimeline(frameCount, input.readInt(true), slotIndex);
case SLOT_ALPHA:
timelines.add(readTimeline(input, new AlphaTimeline(frameCount, input.readInt(true), input.readInt(true)), 1));
break;
case SLOT_RGB: {
RGBTimeline timeline = new RGBTimeline(frameCount, input.readInt(true), slotIndex);
float time = input.readFloat();
float r = input.read() / 255f, g = input.read() / 255f, b = input.read() / 255f;
for (int frame = 0, bezier = 0;; frame++) {
timeline.setFrame(frame, time, r, g, b);
if (frame == frameLast) break;
float time2 = input.readFloat();
float r2 = input.read() / 255f, g2 = input.read() / 255f, b2 = input.read() / 255f;
switch (input.readByte()) {
case CURVE_STEPPED:
timeline.setStepped(frame);
break;
case CURVE_BEZIER:
setBezier(input, timeline, bezier++, frame, 0, time, time2, r, r2, 1);
setBezier(input, timeline, bezier++, frame, 1, time, time2, g, g2, 1);
setBezier(input, timeline, bezier++, frame, 2, time, time2, b, b2, 1);
}
time = time2;
r = r2;
g = g2;
b = b2;
}
timelines.add(timeline);
break;
}
case SLOT_RGBA2: {
RGBA2Timeline timeline = new RGBA2Timeline(frameCount, input.readInt(true), slotIndex);
float time = input.readFloat();
float r = input.read() / 255f, g = input.read() / 255f;
float b = input.read() / 255f, a = input.read() / 255f;
float r2 = input.read() / 255f, g2 = input.read() / 255f;
float b2 = input.read() / 255f;
float r2 = input.read() / 255f, g2 = input.read() / 255f, b2 = input.read() / 255f;
for (int frame = 0, bezier = 0;; frame++) {
timeline.setFrame(frame, time, r, g, b, a, r2, g2, b2);
if (frame == frameLast) break;
float time2 = input.readFloat();
float nr = input.read() / 255f, ng = input.read() / 255f;
float nb = input.read() / 255f, na = input.read() / 255f;
float nr2 = input.read() / 255f, ng2 = input.read() / 255f;
float nb2 = input.read() / 255f;
float nr2 = input.read() / 255f, ng2 = input.read() / 255f, nb2 = input.read() / 255f;
switch (input.readByte()) {
case CURVE_STEPPED:
timeline.setStepped(frame);
@ -644,6 +688,39 @@ public class SkeletonBinary extends SkeletonLoader {
timelines.add(timeline);
break;
}
case SLOT_RGB2:
RGB2Timeline timeline = new RGB2Timeline(frameCount, input.readInt(true), slotIndex);
float time = input.readFloat();
float r = input.read() / 255f, g = input.read() / 255f, b = input.read() / 255f;
float r2 = input.read() / 255f, g2 = input.read() / 255f, b2 = input.read() / 255f;
for (int frame = 0, bezier = 0;; frame++) {
timeline.setFrame(frame, time, r, g, b, r2, g2, b2);
if (frame == frameLast) break;
float time2 = input.readFloat();
float nr = input.read() / 255f, ng = input.read() / 255f, nb = input.read() / 255f;
float nr2 = input.read() / 255f, ng2 = input.read() / 255f, nb2 = input.read() / 255f;
switch (input.readByte()) {
case CURVE_STEPPED:
timeline.setStepped(frame);
break;
case CURVE_BEZIER:
setBezier(input, timeline, bezier++, frame, 0, time, time2, r, nr, 1);
setBezier(input, timeline, bezier++, frame, 1, time, time2, g, ng, 1);
setBezier(input, timeline, bezier++, frame, 2, time, time2, b, nb, 1);
setBezier(input, timeline, bezier++, frame, 4, time, time2, r2, nr2, 1);
setBezier(input, timeline, bezier++, frame, 5, time, time2, g2, ng2, 1);
setBezier(input, timeline, bezier++, frame, 6, time, time2, b2, nb2, 1);
}
time = time2;
r = nr;
g = ng;
b = nb;
r2 = nr2;
g2 = ng2;
b2 = nb2;
}
timelines.add(timeline);
break;
}
}
}
@ -652,19 +729,37 @@ public class SkeletonBinary extends SkeletonLoader {
for (int i = 0, n = input.readInt(true); i < n; i++) {
int boneIndex = input.readInt(true);
for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) {
switch (input.readByte()) {
int type = input.readByte(), frameCount = input.readInt(true), bezierCount = input.readInt(true);
switch (type) {
case BONE_ROTATE:
timelines.add(readTimeline(input, new RotateTimeline(input.readInt(true), input.readInt(true), boneIndex), 1));
timelines.add(readTimeline(input, new RotateTimeline(frameCount, bezierCount, boneIndex), 1));
break;
case BONE_TRANSLATE:
timelines
.add(readTimeline(input, new TranslateTimeline(input.readInt(true), input.readInt(true), boneIndex), scale));
timelines.add(readTimeline(input, new TranslateTimeline(frameCount, bezierCount, boneIndex), scale));
break;
case BONE_TRANSLATEX:
timelines.add(readTimeline(input, new TranslateXTimeline(frameCount, bezierCount, boneIndex), scale));
break;
case BONE_TRANSLATEY:
timelines.add(readTimeline(input, new TranslateYTimeline(frameCount, bezierCount, boneIndex), scale));
break;
case BONE_SCALE:
timelines.add(readTimeline(input, new ScaleTimeline(input.readInt(true), input.readInt(true), boneIndex), 1));
timelines.add(readTimeline(input, new ScaleTimeline(frameCount, bezierCount, boneIndex), 1));
break;
case BONE_SCALEX:
timelines.add(readTimeline(input, new ScaleXTimeline(frameCount, bezierCount, boneIndex), 1));
break;
case BONE_SCALEY:
timelines.add(readTimeline(input, new ScaleYTimeline(frameCount, bezierCount, boneIndex), 1));
break;
case BONE_SHEAR:
timelines.add(readTimeline(input, new ShearTimeline(input.readInt(true), input.readInt(true), boneIndex), 1));
timelines.add(readTimeline(input, new ShearTimeline(frameCount, bezierCount, boneIndex), 1));
break;
case BONE_SHEARX:
timelines.add(readTimeline(input, new ShearXTimeline(frameCount, bezierCount, boneIndex), 1));
break;
case BONE_SHEARY:
timelines.add(readTimeline(input, new ShearYTimeline(frameCount, bezierCount, boneIndex), 1));
}
}
}

View File

@ -41,8 +41,8 @@ import com.badlogic.gdx.utils.JsonReader;
import com.badlogic.gdx.utils.JsonValue;
import com.badlogic.gdx.utils.SerializationException;
import com.esotericsoftware.spine.Animation.AlphaTimeline;
import com.esotericsoftware.spine.Animation.AttachmentTimeline;
import com.esotericsoftware.spine.Animation.ColorTimeline;
import com.esotericsoftware.spine.Animation.CurveTimeline;
import com.esotericsoftware.spine.Animation.CurveTimeline1;
import com.esotericsoftware.spine.Animation.CurveTimeline2;
@ -53,13 +53,22 @@ import com.esotericsoftware.spine.Animation.IkConstraintTimeline;
import com.esotericsoftware.spine.Animation.PathConstraintMixTimeline;
import com.esotericsoftware.spine.Animation.PathConstraintPositionTimeline;
import com.esotericsoftware.spine.Animation.PathConstraintSpacingTimeline;
import com.esotericsoftware.spine.Animation.RGB2Timeline;
import com.esotericsoftware.spine.Animation.RGBA2Timeline;
import com.esotericsoftware.spine.Animation.RGBATimeline;
import com.esotericsoftware.spine.Animation.RGBTimeline;
import com.esotericsoftware.spine.Animation.RotateTimeline;
import com.esotericsoftware.spine.Animation.ScaleTimeline;
import com.esotericsoftware.spine.Animation.ScaleXTimeline;
import com.esotericsoftware.spine.Animation.ScaleYTimeline;
import com.esotericsoftware.spine.Animation.ShearTimeline;
import com.esotericsoftware.spine.Animation.ShearXTimeline;
import com.esotericsoftware.spine.Animation.ShearYTimeline;
import com.esotericsoftware.spine.Animation.Timeline;
import com.esotericsoftware.spine.Animation.TransformConstraintTimeline;
import com.esotericsoftware.spine.Animation.TranslateTimeline;
import com.esotericsoftware.spine.Animation.TwoColorTimeline;
import com.esotericsoftware.spine.Animation.TranslateXTimeline;
import com.esotericsoftware.spine.Animation.TranslateYTimeline;
import com.esotericsoftware.spine.BoneData.TransformMode;
import com.esotericsoftware.spine.PathConstraintData.PositionMode;
import com.esotericsoftware.spine.PathConstraintData.RotateMode;
@ -435,7 +444,7 @@ public class SkeletonJson extends SkeletonLoader {
if (color != null) Color.valueOf(color, point.getColor());
return point;
}
case clipping: {
case clipping:
ClippingAttachment clip = attachmentLoader.newClippingAttachment(skin, name);
if (clip == null) return null;
@ -452,7 +461,6 @@ public class SkeletonJson extends SkeletonLoader {
if (color != null) Color.valueOf(color, clip.getColor());
return clip;
}
}
return null;
}
@ -502,10 +510,10 @@ public class SkeletonJson extends SkeletonLoader {
timeline.setFrame(frame, keyMap.getFloat("time", 0), keyMap.getString("name"));
timelines.add(timeline);
} else if (timelineName.equals("color")) {
ColorTimeline timeline = new ColorTimeline(timelineMap.size, timelineMap.size << 2, slot.index);
} else if (timelineName.equals("rgba")) {
RGBATimeline timeline = new RGBATimeline(timelineMap.size, timelineMap.size << 2, slot.index);
float time = keyMap.getFloat("time", 0);
String color = keyMap.getString("color");
String color = keyMap.getString("rgba");
float r = Integer.parseInt(color.substring(0, 2), 16) / 255f;
float g = Integer.parseInt(color.substring(2, 4), 16) / 255f;
float b = Integer.parseInt(color.substring(4, 6), 16) / 255f;
@ -518,7 +526,7 @@ public class SkeletonJson extends SkeletonLoader {
break;
}
float time2 = nextMap.getFloat("time", 0);
color = nextMap.getString("color");
color = nextMap.getString("rgba");
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;
@ -539,8 +547,44 @@ public class SkeletonJson extends SkeletonLoader {
}
timelines.add(timeline);
} else if (timelineName.equals("twoColor")) {
TwoColorTimeline timeline = new TwoColorTimeline(timelineMap.size, timelineMap.size * 7, slot.index);
} else if (timelineName.equals("rgb")) {
RGBTimeline timeline = new RGBTimeline(timelineMap.size, timelineMap.size * 3, slot.index);
float time = keyMap.getFloat("time", 0);
String color = keyMap.getString("rgb");
float r = Integer.parseInt(color.substring(0, 2), 16) / 255f;
float g = Integer.parseInt(color.substring(2, 4), 16) / 255f;
float b = Integer.parseInt(color.substring(4, 6), 16) / 255f;
for (int frame = 0, bezier = 0;; frame++) {
timeline.setFrame(frame, time, r, g, b);
JsonValue nextMap = keyMap.next;
if (nextMap == null) {
timeline.shrink(bezier);
break;
}
float time2 = nextMap.getFloat("time", 0);
color = nextMap.getString("rgb");
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;
JsonValue curve = keyMap.get("curve");
if (curve != null) {
bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, r, nr, 1);
bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, g, ng, 1);
bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, b, nb, 1);
}
time = time2;
r = nr;
g = ng;
b = nb;
keyMap = nextMap;
}
timelines.add(timeline);
} else if (timelineName.equals("alpha")) {
timelines.add(readTimeline(keyMap, new AlphaTimeline(timelineMap.size, timelineMap.size, slot.index), 0, 1));
} else if (timelineName.equals("rgba2")) {
RGBA2Timeline timeline = new RGBA2Timeline(timelineMap.size, timelineMap.size * 7, slot.index);
float time = keyMap.getFloat("time", 0);
String color = keyMap.getString("light");
float r = Integer.parseInt(color.substring(0, 2), 16) / 255f;
@ -590,6 +634,53 @@ public class SkeletonJson extends SkeletonLoader {
}
timelines.add(timeline);
} else if (timelineName.equals("rgb2")) {
RGB2Timeline timeline = new RGB2Timeline(timelineMap.size, timelineMap.size * 6, slot.index);
float time = keyMap.getFloat("time", 0);
String color = keyMap.getString("light");
float r = Integer.parseInt(color.substring(0, 2), 16) / 255f;
float g = Integer.parseInt(color.substring(2, 4), 16) / 255f;
float b = Integer.parseInt(color.substring(4, 6), 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, r2, g2, b2);
JsonValue nextMap = keyMap.next;
if (nextMap == null) {
timeline.shrink(bezier);
break;
}
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;
color = nextMap.getString("dark");
float nr2 = Integer.parseInt(color.substring(0, 2), 16) / 255f;
float ng2 = Integer.parseInt(color.substring(2, 4), 16) / 255f;
float nb2 = Integer.parseInt(color.substring(4, 6), 16) / 255f;
JsonValue curve = keyMap.get("curve");
if (curve != null) {
bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, r, nr, 1);
bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, g, ng, 1);
bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, b, nb, 1);
bezier = readCurve(curve, timeline, bezier, frame, 4, time, time2, r2, nr2, 1);
bezier = readCurve(curve, timeline, bezier, frame, 5, time, time2, g2, ng2, 1);
bezier = readCurve(curve, timeline, bezier, frame, 6, time, time2, b2, nb2, 1);
}
time = time2;
r = nr;
g = ng;
b = nb;
r2 = nr2;
g2 = ng2;
b2 = nb2;
keyMap = nextMap;
}
timelines.add(timeline);
} else
throw new RuntimeException("Invalid timeline type for a slot: " + timelineName + " (" + slotMap.name + ")");
}
@ -609,13 +700,27 @@ public class SkeletonJson extends SkeletonLoader {
else if (timelineName.equals("translate")) {
TranslateTimeline timeline = new TranslateTimeline(timelineMap.size, timelineMap.size << 1, bone.index);
timelines.add(readTimeline(keyMap, timeline, "x", "y", 0, scale));
} else if (timelineName.equals("translatex")) {
timelines
.add(readTimeline(keyMap, new TranslateXTimeline(timelineMap.size, timelineMap.size, bone.index), 0, scale));
} else if (timelineName.equals("translatey")) {
timelines
.add(readTimeline(keyMap, new TranslateYTimeline(timelineMap.size, timelineMap.size, bone.index), 0, scale));
} else if (timelineName.equals("scale")) {
ScaleTimeline timeline = new ScaleTimeline(timelineMap.size, timelineMap.size << 1, bone.index);
timelines.add(readTimeline(keyMap, timeline, "x", "y", 1, 1));
} else if (timelineName.equals("shear")) {
} else if (timelineName.equals("scalex"))
timelines.add(readTimeline(keyMap, new ScaleXTimeline(timelineMap.size, timelineMap.size, bone.index), 1, 1));
else if (timelineName.equals("scaley"))
timelines.add(readTimeline(keyMap, new ScaleYTimeline(timelineMap.size, timelineMap.size, bone.index), 1, 1));
else if (timelineName.equals("shear")) {
ShearTimeline timeline = new ShearTimeline(timelineMap.size, timelineMap.size << 1, bone.index);
timelines.add(readTimeline(keyMap, timeline, "x", "y", 0, 1));
} else
} else if (timelineName.equals("shearx"))
timelines.add(readTimeline(keyMap, new ShearXTimeline(timelineMap.size, timelineMap.size, bone.index), 0, 1));
else if (timelineName.equals("sheary"))
timelines.add(readTimeline(keyMap, new ShearYTimeline(timelineMap.size, timelineMap.size, bone.index), 0, 1));
else
throw new RuntimeException("Invalid timeline type for a bone: " + timelineName + " (" + boneMap.name + ")");
}
}