spine-libgdx updated to 3.2.00.

* Added transform constraint rotate, scale, and shear offsets and mixes.
* Added TransformConstraintTimeline.
* Added bone shearing.
* Added ShearTimeline.
* Changed Skeleton#updateCache.
* Changed JSON and binary formats. Some binary format fields and enums were rearranged for consistency -- sorry, but it's better for the long term. Docs for both are up to date.
http://esotericsoftware.com/spine-json-format
http://esotericsoftware.com/spine-binary-format
This commit is contained in:
NathanSweet 2016-04-26 22:51:04 +02:00
parent 506dc49d8a
commit 8d7f761311
28 changed files with 550 additions and 174 deletions

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version
spine-as3 works with data exported from the latest version of Spine.
spine-as3 works with data exported from Spine 3.1.08. Updating spine-as3 to [v3.2](https://trello.com/c/k7KtGdPW/76-update-runtimes-to-support-v3-2-shearing) is in progress.
spine-as3 supports all Spine features, including meshes. If using the `spine.flash` classes for rendering, meshes are not supported.

View File

@ -12,7 +12,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version
spine-c works with data exported from the latest version of Spine.
spine-c works with data exported from Spine 3.1.08. Updating spine-c to [v3.2](https://trello.com/c/k7KtGdPW/76-update-runtimes-to-support-v3-2-shearing) is in progress.
spine-c supports all Spine features.

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version
spine-cocos2d-iphone v2 works with data exported from the latest version of Spine.
spine-cocos2d-iphone v2 works with data exported from Spine 3.1.08. Updating spine-cocos2d-iphone v2 to [v3.2](https://trello.com/c/k7KtGdPW/76-update-runtimes-to-support-v3-2-shearing) is in progress.
spine-cocos2d-iphone v2 supports all Spine features.

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version
spine-cocos2d-iphone v3 works with data exported from the latest version of Spine.
spine-cocos2d-iphone v3 works with data exported from Spine 3.1.08. Updating spine-cocos2d-iphone v3 to [v3.2](https://trello.com/c/k7KtGdPW/76-update-runtimes-to-support-v3-2-shearing) is in progress.
spine-cocos2d-iphone v3 supports all Spine features.

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version
spine-cocos2dx v2 works with data exported from the latest version of Spine.
spine-cocos2dx v2 works with data exported from Spine 3.1.08. Updating spine-cocos2dx v2 to [v3.2](https://trello.com/c/k7KtGdPW/76-update-runtimes-to-support-v3-2-shearing) is in progress.
spine-cocos2dx v2 supports all Spine features.

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version
spine-cocos2dx v3 works with data exported from the latest version of Spine.
spine-cocos2dx v3 works with data exported from Spine 3.1.08. Updating spine-cocos2dx v3 to [v3.2](https://trello.com/c/k7KtGdPW/76-update-runtimes-to-support-v3-2-shearing) is in progress.
spine-cocos2dx v3 supports all Spine features.

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version
spine-corona works with data exported from Spine 2.1.27. Updating spine-corona to [v3.0](https://trello.com/c/tF8UykBM/72-update-runtimes-to-support-v3-0-skewing-scale) and [v3.1](https://trello.com/c/bERJAFEq/73-update-runtimes-to-support-v3-1-linked-meshes) is in progress.
spine-corona works with data exported from Spine 2.1.27. Updating spine-corona to [v3.0](https://trello.com/c/tF8UykBM/72-update-runtimes-to-support-v3-0-skewing-scale), [v3.1](https://trello.com/c/bERJAFEq/73-update-runtimes-to-support-v3-1-linked-meshes), and [v3.2](https://trello.com/c/k7KtGdPW/76-update-runtimes-to-support-v3-2-shearing) is in progress.
spine-corona supports all Spine features except for rendering meshes due to Corona having a limited graphics API.

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version
spine-csharp works with data exported from the latest version of Spine.
spine-csharp works with data exported from Spine 3.1.08. Updating spine-csharp to [v3.2](https://trello.com/c/k7KtGdPW/76-update-runtimes-to-support-v3-2-shearing) is in progress.
spine-csharp supports all Spine features.

View File

@ -14,9 +14,9 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version
spine-js works with data exported from the latest version of Spine.
spine-js works with data exported from Spine 3.1.08. Updating spine-js to [v3.2](https://trello.com/c/k7KtGdPW/76-update-runtimes-to-support-v3-2-shearing) is in progress.
spine-js supports all Spine features. spine-canvas does not support mesh attachments or nonuniform scaling.~
spine-js supports all Spine features. spine-canvas does not support mesh attachments or nonuniform scaling.
spine-js does not yet support loading the binary format.

View File

@ -240,11 +240,11 @@ public class Animation {
}
static public class RotateTimeline extends CurveTimeline {
static private final int PREV_FRAME_TIME = -2;
static private final int FRAME_VALUE = 1;
static final int PREV_TIME = -2;
static final int VALUE = 1;
int boneIndex;
private final float[] frames; // time, angle, ...
final float[] frames; // time, angle, ...
public RotateTimeline (int frameCount) {
super(frameCount);
@ -287,13 +287,13 @@ public class Animation {
}
// Interpolate between the previous frame and the current frame.
int frameIndex = binarySearch(frames, time, 2);
float prevFrameValue = frames[frameIndex - 1];
float frameTime = frames[frameIndex];
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frameIndex + PREV_FRAME_TIME] - frameTime), 0, 1);
percent = getCurvePercent((frameIndex >> 1) - 1, percent);
int frame = binarySearch(frames, time, 2);
float prevFrameValue = frames[frame - 1];
float frameTime = frames[frame];
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime), 0, 1);
percent = getCurvePercent((frame >> 1) - 1, percent);
float amount = frames[frameIndex + FRAME_VALUE] - prevFrameValue;
float amount = frames[frame + VALUE] - prevFrameValue;
while (amount > 180)
amount -= 360;
while (amount < -180)
@ -308,9 +308,9 @@ public class Animation {
}
static public class TranslateTimeline extends CurveTimeline {
static final int PREV_FRAME_TIME = -3;
static final int FRAME_X = 1;
static final int FRAME_Y = 2;
static final int PREV_TIME = -3;
static final int X = 1;
static final int Y = 2;
int boneIndex;
final float[] frames; // time, x, y, ...
@ -353,15 +353,15 @@ public class Animation {
}
// Interpolate between the previous frame and the current frame.
int frameIndex = binarySearch(frames, time, 3);
float prevFrameX = frames[frameIndex - 2];
float prevFrameY = frames[frameIndex - 1];
float frameTime = frames[frameIndex];
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frameIndex + PREV_FRAME_TIME] - frameTime), 0, 1);
percent = getCurvePercent(frameIndex / 3 - 1, percent);
int frame = binarySearch(frames, time, 3);
float prevFrameX = frames[frame - 2];
float prevFrameY = frames[frame - 1];
float frameTime = frames[frame];
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime), 0, 1);
percent = getCurvePercent(frame / 3 - 1, percent);
bone.x += (bone.data.x + prevFrameX + (frames[frameIndex + FRAME_X] - prevFrameX) * percent - bone.x) * alpha;
bone.y += (bone.data.y + prevFrameY + (frames[frameIndex + FRAME_Y] - prevFrameY) * percent - bone.y) * alpha;
bone.x += (bone.data.x + prevFrameX + (frames[frame + X] - prevFrameX) * percent - bone.x) * alpha;
bone.y += (bone.data.y + prevFrameY + (frames[frame + Y] - prevFrameY) * percent - bone.y) * alpha;
}
}
@ -382,26 +382,53 @@ public class Animation {
}
// Interpolate between the previous frame and the current frame.
int frameIndex = binarySearch(frames, time, 3);
float prevFrameX = frames[frameIndex - 2];
float prevFrameY = frames[frameIndex - 1];
float frameTime = frames[frameIndex];
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frameIndex + PREV_FRAME_TIME] - frameTime), 0, 1);
percent = getCurvePercent(frameIndex / 3 - 1, percent);
int frame = binarySearch(frames, time, 3);
float prevFrameX = frames[frame - 2];
float prevFrameY = frames[frame - 1];
float frameTime = frames[frame];
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime), 0, 1);
percent = getCurvePercent(frame / 3 - 1, percent);
bone.scaleX += (bone.data.scaleX * (prevFrameX + (frames[frameIndex + FRAME_X] - prevFrameX) * percent) - bone.scaleX)
* alpha;
bone.scaleY += (bone.data.scaleY * (prevFrameY + (frames[frameIndex + FRAME_Y] - prevFrameY) * percent) - bone.scaleY)
* alpha;
bone.scaleX += (bone.data.scaleX * (prevFrameX + (frames[frame + X] - prevFrameX) * percent) - bone.scaleX) * alpha;
bone.scaleY += (bone.data.scaleY * (prevFrameY + (frames[frame + Y] - prevFrameY) * percent) - bone.scaleY) * alpha;
}
}
static public class ShearTimeline extends TranslateTimeline {
public ShearTimeline (int frameCount) {
super(frameCount);
}
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha) {
float[] frames = this.frames;
if (time < frames[0]) return; // Time is before first frame.
Bone bone = skeleton.bones.get(boneIndex);
if (time >= frames[frames.length - 3]) { // Time is after last frame.
bone.shearX += (bone.data.shearX + frames[frames.length - 2] - bone.shearX) * alpha;
bone.shearY += (bone.data.shearY + frames[frames.length - 1] - bone.shearY) * alpha;
return;
}
// Interpolate between the previous frame and the current frame.
int frame = binarySearch(frames, time, 3);
float prevFrameX = frames[frame - 2];
float prevFrameY = frames[frame - 1];
float frameTime = frames[frame];
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime), 0, 1);
percent = getCurvePercent(frame / 3 - 1, percent);
bone.shearX += (bone.data.shearX + (prevFrameX + (frames[frame + X] - prevFrameX) * percent) - bone.shearX) * alpha;
bone.shearY += (bone.data.shearY + (prevFrameY + (frames[frame + Y] - prevFrameY) * percent) - bone.shearY) * alpha;
}
}
static public class ColorTimeline extends CurveTimeline {
static private final int PREV_FRAME_TIME = -5;
static private final int FRAME_R = 1;
static private final int FRAME_G = 2;
static private final int FRAME_B = 3;
static private final int FRAME_A = 4;
static private final int PREV_TIME = -5;
static private final int R = 1;
static private final int G = 2;
static private final int B = 3;
static private final int A = 4;
int slotIndex;
private final float[] frames; // time, r, g, b, a, ...
@ -438,8 +465,7 @@ public class Animation {
if (time < frames[0]) return; // Time is before first frame.
float r, g, b, a;
if (time >= frames[frames.length - 5]) {
// Time is after last frame.
if (time >= frames[frames.length - 5]) { // Time is after last frame.
int i = frames.length - 1;
r = frames[i - 3];
g = frames[i - 2];
@ -447,19 +473,19 @@ public class Animation {
a = frames[i];
} else {
// Interpolate between the previous frame and the current frame.
int frameIndex = binarySearch(frames, time, 5);
float prevFrameR = frames[frameIndex - 4];
float prevFrameG = frames[frameIndex - 3];
float prevFrameB = frames[frameIndex - 2];
float prevFrameA = frames[frameIndex - 1];
float frameTime = frames[frameIndex];
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frameIndex + PREV_FRAME_TIME] - frameTime), 0, 1);
percent = getCurvePercent(frameIndex / 5 - 1, percent);
int frame = binarySearch(frames, time, 5);
float frameTime = frames[frame];
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime), 0, 1);
percent = getCurvePercent(frame / 5 - 1, percent);
r = prevFrameR + (frames[frameIndex + FRAME_R] - prevFrameR) * percent;
g = prevFrameG + (frames[frameIndex + FRAME_G] - prevFrameG) * percent;
b = prevFrameB + (frames[frameIndex + FRAME_B] - prevFrameB) * percent;
a = prevFrameA + (frames[frameIndex + FRAME_A] - prevFrameA) * percent;
r = frames[frame - 4];
g = frames[frame - 3];
b = frames[frame - 2];
a = frames[frame - 1];
r += (frames[frame + R] - r) * percent;
g += (frames[frame + G] - g) * percent;
b += (frames[frame + B] - b) * percent;
a += (frames[frame + A] - a) * percent;
}
Color color = skeleton.slots.get(slotIndex).color;
if (alpha < 1)
@ -513,10 +539,10 @@ public class Animation {
} else if (lastTime > time) //
lastTime = -1;
int frameIndex = (time >= frames[frames.length - 1] ? frames.length : binarySearch(frames, time)) - 1;
if (frames[frameIndex] < lastTime) return;
int frame = (time >= frames[frames.length - 1] ? frames.length : binarySearch(frames, time)) - 1;
if (frames[frame] < lastTime) return;
String attachmentName = attachmentNames[frameIndex];
String attachmentName = attachmentNames[frame];
skeleton.slots.get(slotIndex)
.setAttachment(attachmentName == null ? null : skeleton.getAttachment(slotIndex, attachmentName));
}
@ -562,19 +588,19 @@ public class Animation {
return;
if (time < frames[0]) return; // Time is before first frame.
int frameIndex;
int frame;
if (lastTime < frames[0])
frameIndex = 0;
frame = 0;
else {
frameIndex = binarySearch(frames, lastTime);
float frame = frames[frameIndex];
while (frameIndex > 0) { // Fire multiple events with the same frame.
if (frames[frameIndex - 1] != frame) break;
frameIndex--;
frame = binarySearch(frames, lastTime);
float frameTime = frames[frame];
while (frame > 0) { // Fire multiple events with the same frame.
if (frames[frame - 1] != frameTime) break;
frame--;
}
}
for (; frameIndex < frameCount && time >= frames[frameIndex]; frameIndex++)
firedEvents.add(events[frameIndex]);
for (; frame < frameCount && time >= frames[frame]; frame++)
firedEvents.add(events[frame]);
}
}
@ -610,15 +636,15 @@ public class Animation {
float[] frames = this.frames;
if (time < frames[0]) return; // Time is before first frame.
int frameIndex;
int frame;
if (time >= frames[frames.length - 1]) // Time is after last frame.
frameIndex = frames.length - 1;
frame = frames.length - 1;
else
frameIndex = binarySearch(frames, time) - 1;
frame = binarySearch(frames, time) - 1;
Array<Slot> drawOrder = skeleton.drawOrder;
Array<Slot> slots = skeleton.slots;
int[] drawOrderToSetupIndex = drawOrders[frameIndex];
int[] drawOrderToSetupIndex = drawOrders[frame];
if (drawOrderToSetupIndex == null)
System.arraycopy(slots.items, 0, drawOrder.items, 0, slots.size);
else {
@ -699,14 +725,13 @@ public class Animation {
}
// Interpolate between the previous frame and the current frame.
int frameIndex = binarySearch(frames, time);
float frameTime = frames[frameIndex];
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frameIndex - 1] - frameTime), 0, 1);
percent = getCurvePercent(frameIndex - 1, percent);
float[] prevVertices = frameVertices[frameIndex - 1];
float[] nextVertices = frameVertices[frameIndex];
int frame = binarySearch(frames, time);
float frameTime = frames[frame];
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frame - 1] - frameTime), 0, 1);
percent = getCurvePercent(frame - 1, percent);
float[] prevVertices = frameVertices[frame - 1];
float[] nextVertices = frameVertices[frame];
if (alpha < 1) {
for (int i = 0; i < vertexCount; i++) {
float prev = prevVertices[i];
@ -722,10 +747,10 @@ public class Animation {
}
static public class IkConstraintTimeline extends CurveTimeline {
static private final int PREV_FRAME_TIME = -3;
static private final int PREV_FRAME_MIX = -2;
static private final int PREV_FRAME_BEND_DIRECTION = -1;
static private final int FRAME_MIX = 1;
static private final int PREV_TIME = -3;
static private final int PREV_MIX = -2;
static private final int PREV_BEND_DIRECTION = -1;
static private final int MIX = 1;
int ikConstraintIndex;
private final float[] frames; // time, mix, bendDirection, ...
@ -759,24 +784,97 @@ public class Animation {
float[] frames = this.frames;
if (time < frames[0]) return; // Time is before first frame.
IkConstraint ikConstraint = skeleton.ikConstraints.get(ikConstraintIndex);
IkConstraint constraint = skeleton.ikConstraints.get(ikConstraintIndex);
if (time >= frames[frames.length - 3]) { // Time is after last frame.
ikConstraint.mix += (frames[frames.length - 2] - ikConstraint.mix) * alpha;
ikConstraint.bendDirection = (int)frames[frames.length - 1];
constraint.mix += (frames[frames.length + PREV_MIX] - constraint.mix) * alpha;
constraint.bendDirection = (int)frames[frames.length + PREV_BEND_DIRECTION];
return;
}
// Interpolate between the previous frame and the current frame.
int frameIndex = binarySearch(frames, time, 3);
float prevFrameMix = frames[frameIndex + PREV_FRAME_MIX];
float frameTime = frames[frameIndex];
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frameIndex + PREV_FRAME_TIME] - frameTime), 0, 1);
percent = getCurvePercent(frameIndex / 3 - 1, percent);
int frame = binarySearch(frames, time, 3);
float frameTime = frames[frame];
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime), 0, 1);
percent = getCurvePercent(frame / 3 - 1, percent);
float mix = prevFrameMix + (frames[frameIndex + FRAME_MIX] - prevFrameMix) * percent;
ikConstraint.mix += (mix - ikConstraint.mix) * alpha;
ikConstraint.bendDirection = (int)frames[frameIndex + PREV_FRAME_BEND_DIRECTION];
float mix = frames[frame + PREV_MIX];
constraint.mix += (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha;
constraint.bendDirection = (int)frames[frame + PREV_BEND_DIRECTION];
}
}
static public class TransformConstraintTimeline extends CurveTimeline {
static private final int PREV_TIME = -5;
static private final int PREV_ROTATE_MIX = -4;
static private final int PREV_TRANSLATE_MIX = -3;
static private final int PREV_SCALE_MIX = -2;
static private final int PREV_SHEAR_MIX = -1;
static private final int ROTATE_MIX = 1;
static private final int TRANSLATE_MIX = 2;
static private final int SCALE_MIX = 3;
static private final int SHEAR_MIX = 4;
int transformConstraintIndex;
private final float[] frames; // time, rotate mix, translate mix, scale mix, shear mix, ...
public TransformConstraintTimeline (int frameCount) {
super(frameCount);
frames = new float[frameCount * 5];
}
public void setTransformConstraintIndex (int ikConstraint) {
this.transformConstraintIndex = ikConstraint;
}
public int getTransformConstraintIndex () {
return transformConstraintIndex;
}
public float[] getFrames () {
return frames;
}
/** Sets the time and mixes of the specified keyframe. */
public void setFrame (int frameIndex, float time, float rotateMix, float translateMix, float scaleMix, float shearMix) {
frameIndex *= 5;
frames[frameIndex] = time;
frames[frameIndex + 1] = rotateMix;
frames[frameIndex + 2] = translateMix;
frames[frameIndex + 3] = scaleMix;
frames[frameIndex + 4] = shearMix;
}
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha) {
float[] frames = this.frames;
if (time < frames[0]) return; // Time is before first frame.
TransformConstraint constraint = skeleton.transformConstraints.get(transformConstraintIndex);
if (time >= frames[frames.length - 5]) { // Time is after last frame.
int i = frames.length - 1;
constraint.rotateMix += (frames[i - 3] - constraint.rotateMix) * alpha;
constraint.translateMix += (frames[i - 2] - constraint.translateMix) * alpha;
constraint.scaleMix += (frames[i - 1] - constraint.scaleMix) * alpha;
constraint.shearMix += (frames[i] - constraint.shearMix) * alpha;
return;
}
// Interpolate between the previous frame and the current frame.
int frame = binarySearch(frames, time, 5);
float frameTime = frames[frame];
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime), 0, 1);
percent = getCurvePercent(frame / 5 - 1, percent);
float rotate = frames[frame + PREV_ROTATE_MIX];
float translate = frames[frame + PREV_TRANSLATE_MIX];
float scale = frames[frame + PREV_SCALE_MIX];
float shear = frames[frame + PREV_SHEAR_MIX];
constraint.rotateMix += (rotate + (frames[frame + ROTATE_MIX] - rotate) * percent - constraint.rotateMix) * alpha;
constraint.translateMix += (translate + (frames[frame + TRANSLATE_MIX] - translate) * percent - constraint.translateMix)
* alpha;
constraint.scaleMix += (scale + (frames[frame + SCALE_MIX] - scale) * percent - constraint.scaleMix) * alpha;
constraint.shearMix += (shear + (frames[frame + SHEAR_MIX] - shear) * percent - constraint.shearMix) * alpha;
}
}
}

View File

@ -31,9 +31,9 @@
package com.esotericsoftware.spine;
import static com.badlogic.gdx.math.MathUtils.*;
import static com.badlogic.gdx.math.Matrix3.*;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Matrix3;
import com.badlogic.gdx.math.Vector2;
@ -41,7 +41,7 @@ public class Bone implements Updatable {
final BoneData data;
final Skeleton skeleton;
final Bone parent;
float x, y, rotation, scaleX, scaleY;
float x, y, rotation, scaleX, scaleY, shearX, shearY;
float appliedRotation, appliedScaleX, appliedScaleY;
float a, b, worldX;
@ -76,26 +76,30 @@ public class Bone implements Updatable {
rotation = bone.rotation;
scaleX = bone.scaleX;
scaleY = bone.scaleY;
shearX = bone.shearX;
shearY = bone.shearY;
}
/** Same as {@link #updateWorldTransform()}. This method exists for Bone to implement {@link Updatable}. */
public void update () {
updateWorldTransform(x, y, rotation, scaleX, scaleY);
updateWorldTransform(x, y, rotation, scaleX, scaleY, shearX, shearY);
}
/** Computes the world SRT using the parent bone and this bone's local SRT. */
public void updateWorldTransform () {
updateWorldTransform(x, y, rotation, scaleX, scaleY);
updateWorldTransform(x, y, rotation, scaleX, scaleY, shearX, shearY);
}
/** Computes the world SRT using the parent bone and the specified local SRT. */
public void updateWorldTransform (float x, float y, float rotation, float scaleX, float scaleY) {
public void updateWorldTransform (float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY) {
appliedRotation = rotation;
appliedScaleX = scaleX;
appliedScaleY = scaleY;
float cos = MathUtils.cosDeg(rotation), sin = MathUtils.sinDeg(rotation);
float la = cos * scaleX, lb = -sin * scaleY, lc = sin * scaleX, ld = cos * scaleY;
float rotationY = rotation + 90 + shearY;
float la = cosDeg(rotation + shearX) * scaleX, lb = cosDeg(rotationY) * scaleY;
float lc = sinDeg(rotation + shearX) * scaleX, ld = sinDeg(rotationY) * scaleY;
Bone parent = this.parent;
if (parent == null) { // Root bone.
Skeleton skeleton = this.skeleton;
@ -138,8 +142,7 @@ public class Bone implements Updatable {
pc = 0;
pd = 1;
do {
cos = MathUtils.cosDeg(parent.appliedRotation);
sin = MathUtils.sinDeg(parent.appliedRotation);
float cos = cosDeg(parent.appliedRotation), sin = sinDeg(parent.appliedRotation);
float temp = pa * cos + pb * sin;
pb = pa * -sin + pb * cos;
pa = temp;
@ -160,9 +163,7 @@ public class Bone implements Updatable {
pc = 0;
pd = 1;
do {
float r = parent.appliedRotation;
cos = MathUtils.cosDeg(r);
sin = MathUtils.sinDeg(r);
float r = parent.appliedRotation, cos = cosDeg(r), sin = sinDeg(r);
float psx = parent.appliedScaleX, psy = parent.appliedScaleY;
float za = cos * psx, zb = -sin * psy, zc = sin * psx, zd = cos * psy;
float temp = pa * za + pb * zc;
@ -173,8 +174,8 @@ public class Bone implements Updatable {
pc = temp;
if (psx < 0) r = -r;
cos = MathUtils.cosDeg(-r);
sin = MathUtils.sinDeg(-r);
cos = cosDeg(-r);
sin = sinDeg(-r);
temp = pa * cos + pb * sin;
pb = pa * -sin + pb * cos;
pa = temp;
@ -213,6 +214,8 @@ public class Bone implements Updatable {
rotation = data.rotation;
scaleX = data.scaleX;
scaleY = data.scaleY;
shearX = data.shearX;
shearY = data.shearY;
}
public BoneData getData () {
@ -248,7 +251,6 @@ public class Bone implements Updatable {
this.y = y;
}
/** Returns the forward kinetics rotation. */
public float getRotation () {
return rotation;
}
@ -283,6 +285,22 @@ public class Bone implements Updatable {
scaleY = scale;
}
public float getShearX () {
return shearX;
}
public void setShearX (float shearX) {
this.shearX = shearX;
}
public float getShearY () {
return shearY;
}
public void setShearY (float shearY) {
this.shearY = shearY;
}
public float getA () {
return a;
}
@ -316,11 +334,11 @@ public class Bone implements Updatable {
}
public float getWorldRotationX () {
return MathUtils.atan2(c, a) * MathUtils.radDeg;
return atan2(c, a) * radDeg;
}
public float getWorldRotationY () {
return MathUtils.atan2(d, b) * MathUtils.radDeg;
return atan2(d, b) * radDeg;
}
public float getWorldScaleX () {

View File

@ -37,9 +37,7 @@ public class BoneData {
final BoneData parent;
final String name;
float length;
float x, y;
float rotation;
float scaleX = 1, scaleY = 1;
float x, y, rotation, scaleX = 1, scaleY = 1, shearX, shearY;
boolean inheritScale = true, inheritRotation = true;
// Nonessential.
@ -64,6 +62,8 @@ public class BoneData {
rotation = bone.rotation;
scaleX = bone.scaleX;
scaleY = bone.scaleY;
shearX = bone.shearX;
shearY = bone.shearY;
}
/** @return May be null. */
@ -133,6 +133,22 @@ public class BoneData {
this.scaleY = scaleY;
}
public float getShearX () {
return shearX;
}
public void setShearX (float shearX) {
this.shearX = shearX;
}
public float getShearY () {
return shearY;
}
public void setShearY (float shearY) {
this.shearY = shearY;
}
public boolean getInheritScale () {
return inheritScale;
}

View File

@ -130,7 +130,7 @@ public class IkConstraint implements Updatable {
rotationIK -= 360;
else if (rotationIK < -180) rotationIK += 360;
bone.updateWorldTransform(bone.x, bone.y, rotation + (rotationIK - rotation) * alpha, bone.appliedScaleX,
bone.appliedScaleY);
bone.appliedScaleY, bone.shearX, bone.shearY);
}
/** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The
@ -259,8 +259,10 @@ public class IkConstraint implements Updatable {
a2 -= 360;
else if (a2 < -180) a2 += 360;
float rotation = parent.rotation;
parent.updateWorldTransform(px, py, rotation + (a1 - rotation) * alpha, parent.appliedScaleX, parent.appliedScaleY);
parent.updateWorldTransform(px, py, rotation + (a1 - rotation) * alpha, parent.appliedScaleX, parent.appliedScaleY,
parent.shearX, parent.shearY);
rotation = child.rotation;
child.updateWorldTransform(cx, cy, rotation + (a2 - rotation) * alpha, child.appliedScaleX, child.appliedScaleY);
child.updateWorldTransform(cx, cy, rotation + (a2 - rotation) * alpha, child.appliedScaleX, child.appliedScaleY,
child.shearX, child.shearY);
}
}

View File

@ -148,8 +148,7 @@ public class Skeleton {
for (int i = 0; i < transformConstraintsCount; i++) {
TransformConstraint transformConstraint = transformConstraints.get(i);
for (int ii = updateCache.size - 1; ii >= 0; ii--) {
Updatable object = updateCache.get(ii);
if (object == transformConstraint.bone || object == transformConstraint.target) {
if (updateCache.get(ii) == transformConstraint.bone) {
updateCache.insert(ii + 1, transformConstraint);
break;
}
@ -186,9 +185,11 @@ public class Skeleton {
Array<TransformConstraint> transformConstraints = this.transformConstraints;
for (int i = 0, n = transformConstraints.size; i < n; i++) {
TransformConstraint constraint = transformConstraints.get(i);
constraint.translateMix = constraint.data.translateMix;
constraint.x = constraint.data.x;
constraint.y = constraint.data.y;
TransformConstraintData data = constraint.data;
constraint.rotateMix = data.rotateMix;
constraint.translateMix = data.translateMix;
constraint.scaleMix = data.scaleMix;
constraint.translateMix = data.translateMix;
}
}

View File

@ -50,7 +50,9 @@ import com.esotericsoftware.spine.Animation.FfdTimeline;
import com.esotericsoftware.spine.Animation.IkConstraintTimeline;
import com.esotericsoftware.spine.Animation.RotateTimeline;
import com.esotericsoftware.spine.Animation.ScaleTimeline;
import com.esotericsoftware.spine.Animation.ShearTimeline;
import com.esotericsoftware.spine.Animation.Timeline;
import com.esotericsoftware.spine.Animation.TransformConstraintTimeline;
import com.esotericsoftware.spine.Animation.TranslateTimeline;
import com.esotericsoftware.spine.SkeletonJson.LinkedMesh;
import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
@ -63,11 +65,12 @@ import com.esotericsoftware.spine.attachments.RegionAttachment;
import com.esotericsoftware.spine.attachments.WeightedMeshAttachment;
public class SkeletonBinary {
static public final int TIMELINE_SCALE = 0;
static public final int TIMELINE_ROTATE = 1;
static public final int TIMELINE_TRANSLATE = 2;
static public final int TIMELINE_ATTACHMENT = 3;
static public final int TIMELINE_COLOR = 4;
static public final int TIMELINE_ROTATE = 0;
static public final int TIMELINE_TRANSLATE = 1;
static public final int TIMELINE_SCALE = 2;
static public final int TIMELINE_SHEAR = 3;
static public final int TIMELINE_ATTACHMENT = 4;
static public final int TIMELINE_COLOR = 5;
static public final int CURVE_LINEAR = 0;
static public final int CURVE_STEPPED = 1;
@ -159,14 +162,16 @@ public class SkeletonBinary {
String name = input.readString();
BoneData parent = i == 0 ? null : skeletonData.bones.get(input.readInt(true));
BoneData boneData = new BoneData(name, parent);
boneData.rotation = input.readFloat();
boneData.x = input.readFloat() * scale;
boneData.y = input.readFloat() * scale;
boneData.scaleX = input.readFloat();
boneData.scaleY = input.readFloat();
boneData.rotation = input.readFloat();
boneData.shearX = input.readFloat();
boneData.shearY = input.readFloat();
boneData.length = input.readFloat() * scale;
boneData.inheritScale = input.readBoolean();
boneData.inheritRotation = input.readBoolean();
boneData.inheritScale = input.readBoolean();
if (nonessential) Color.rgba8888ToColor(boneData.color, input.readInt());
skeletonData.bones.add(boneData);
}
@ -187,9 +192,16 @@ public class SkeletonBinary {
TransformConstraintData transformConstraintData = new TransformConstraintData(input.readString());
transformConstraintData.bone = skeletonData.bones.get(input.readInt(true));
transformConstraintData.target = skeletonData.bones.get(input.readInt(true));
transformConstraintData.offsetRotation = input.readFloat();
transformConstraintData.offsetX = input.readFloat();
transformConstraintData.offsetY = input.readFloat();
transformConstraintData.offsetScaleX = input.readFloat();
transformConstraintData.offsetScaleY = input.readFloat();
transformConstraintData.offsetShearY = input.readFloat();
transformConstraintData.rotateMix = input.readFloat();
transformConstraintData.translateMix = input.readFloat();
transformConstraintData.x = input.readFloat();
transformConstraintData.y = input.readFloat();
transformConstraintData.scaleMix = input.readFloat();
transformConstraintData.shearMix = input.readFloat();
skeletonData.transformConstraints.add(transformConstraintData);
}
@ -291,11 +303,11 @@ public class SkeletonBinary {
switch (type) {
case region: {
String path = input.readString();
float rotation = input.readFloat();
float x = input.readFloat();
float y = input.readFloat();
float scaleX = input.readFloat();
float scaleY = input.readFloat();
float rotation = input.readFloat();
float width = input.readFloat();
float height = input.readFloat();
int color = input.readInt();
@ -532,11 +544,14 @@ public class SkeletonBinary {
break;
}
case TIMELINE_TRANSLATE:
case TIMELINE_SCALE: {
case TIMELINE_SCALE:
case TIMELINE_SHEAR: {
TranslateTimeline timeline;
float timelineScale = 1;
if (timelineType == TIMELINE_SCALE)
timeline = new ScaleTimeline(frameCount);
else if (timelineType == TIMELINE_SHEAR)
timeline = new ShearTimeline(frameCount);
else {
timeline = new TranslateTimeline(frameCount);
timelineScale = scale;
@ -555,12 +570,12 @@ public class SkeletonBinary {
}
}
// IK timelines.
// IK constraint timelines.
for (int i = 0, n = input.readInt(true); i < n; i++) {
IkConstraintData ikConstraint = skeletonData.ikConstraints.get(input.readInt(true));
IkConstraintData constraint = skeletonData.ikConstraints.get(input.readInt(true));
int frameCount = input.readInt(true);
IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount);
timeline.ikConstraintIndex = skeletonData.getIkConstraints().indexOf(ikConstraint, true);
timeline.ikConstraintIndex = skeletonData.getIkConstraints().indexOf(constraint, true);
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) {
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readByte());
if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline);
@ -569,6 +584,21 @@ public class SkeletonBinary {
duration = Math.max(duration, timeline.getFrames()[frameCount * 3 - 3]);
}
// Transform constraint timelines.
for (int i = 0, n = input.readInt(true); i < n; i++) {
TransformConstraintData constraint = skeletonData.transformConstraints.get(input.readInt(true));
int frameCount = input.readInt(true);
TransformConstraintTimeline timeline = new TransformConstraintTimeline(frameCount);
timeline.transformConstraintIndex = skeletonData.getTransformConstraints().indexOf(constraint, true);
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) {
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat(),
input.readFloat());
if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline);
}
timelines.add(timeline);
duration = Math.max(duration, timeline.getFrames()[frameCount * 5 - 5]);
}
// FFD timelines.
for (int i = 0, n = input.readInt(true); i < n; i++) {
Skin skin = skeletonData.skins.get(input.readInt(true));

View File

@ -49,7 +49,9 @@ import com.esotericsoftware.spine.Animation.FfdTimeline;
import com.esotericsoftware.spine.Animation.IkConstraintTimeline;
import com.esotericsoftware.spine.Animation.RotateTimeline;
import com.esotericsoftware.spine.Animation.ScaleTimeline;
import com.esotericsoftware.spine.Animation.ShearTimeline;
import com.esotericsoftware.spine.Animation.Timeline;
import com.esotericsoftware.spine.Animation.TransformConstraintTimeline;
import com.esotericsoftware.spine.Animation.TranslateTimeline;
import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
import com.esotericsoftware.spine.attachments.Attachment;
@ -117,6 +119,8 @@ public class SkeletonJson {
boneData.rotation = boneMap.getFloat("rotation", 0);
boneData.scaleX = boneMap.getFloat("scaleX", 1);
boneData.scaleY = boneMap.getFloat("scaleY", 1);
boneData.shearX = boneMap.getFloat("shearX", 0);
boneData.shearY = boneMap.getFloat("shearY", 0);
boneData.inheritScale = boneMap.getBoolean("inheritScale", true);
boneData.inheritRotation = boneMap.getBoolean("inheritRotation", true);
@ -159,9 +163,17 @@ public class SkeletonJson {
transformConstraintData.target = skeletonData.findBone(targetName);
if (transformConstraintData.target == null) throw new SerializationException("Target bone not found: " + targetName);
transformConstraintData.offsetRotation = transformMap.getFloat("rotation", 0);
transformConstraintData.offsetX = transformMap.getFloat("x", 0) * scale;
transformConstraintData.offsetY = transformMap.getFloat("y", 0) * scale;
transformConstraintData.offsetScaleX = transformMap.getFloat("scaleX", 0) * scale;
transformConstraintData.offsetScaleY = transformMap.getFloat("scaleY", 0) * scale;
transformConstraintData.offsetShearY = transformMap.getFloat("shearY", 0) * scale;
transformConstraintData.rotateMix = transformMap.getFloat("rotateMix", 1);
transformConstraintData.translateMix = transformMap.getFloat("translateMix", 1);
transformConstraintData.x = transformMap.getFloat("x", 0) * scale;
transformConstraintData.y = transformMap.getFloat("y", 0) * scale;
transformConstraintData.scaleMix = transformMap.getFloat("scaleMix", 1);
transformConstraintData.shearMix = transformMap.getFloat("shearMix", 1);
skeletonData.transformConstraints.add(transformConstraintData);
}
@ -422,11 +434,13 @@ public class SkeletonJson {
timelines.add(timeline);
duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() * 2 - 2]);
} else if (timelineName.equals("translate") || timelineName.equals("scale")) {
} else if (timelineName.equals("translate") || timelineName.equals("scale") || timelineName.equals("shear")) {
TranslateTimeline timeline;
float timelineScale = 1;
if (timelineName.equals("scale"))
timeline = new ScaleTimeline(timelineMap.size);
else if (timelineName.equals("shear"))
timeline = new ShearTimeline(timelineMap.size);
else {
timeline = new TranslateTimeline(timelineMap.size);
timelineScale = scale;
@ -448,14 +462,14 @@ public class SkeletonJson {
}
}
// IK timelines.
for (JsonValue ikMap = map.getChild("ik"); ikMap != null; ikMap = ikMap.next) {
IkConstraintData ikConstraint = skeletonData.findIkConstraint(ikMap.name);
IkConstraintTimeline timeline = new IkConstraintTimeline(ikMap.size);
timeline.ikConstraintIndex = skeletonData.getIkConstraints().indexOf(ikConstraint, true);
// IK constraint timelines.
for (JsonValue constraintMap = map.getChild("ik"); constraintMap != null; constraintMap = constraintMap.next) {
IkConstraintData constraint = skeletonData.findIkConstraint(constraintMap.name);
IkConstraintTimeline timeline = new IkConstraintTimeline(constraintMap.size);
timeline.ikConstraintIndex = skeletonData.getIkConstraints().indexOf(constraint, true);
int frameIndex = 0;
for (JsonValue valueMap = ikMap.child; valueMap != null; valueMap = valueMap.next) {
timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat("mix"),
for (JsonValue valueMap = constraintMap.child; valueMap != null; valueMap = valueMap.next) {
timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat("mix", 1),
valueMap.getBoolean("bendPositive") ? 1 : -1);
readCurve(timeline, frameIndex, valueMap);
frameIndex++;
@ -464,6 +478,22 @@ public class SkeletonJson {
duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() * 3 - 3]);
}
// Transform constraint timelines.
for (JsonValue constraintMap = map.getChild("transform"); constraintMap != null; constraintMap = constraintMap.next) {
TransformConstraintData constraint = skeletonData.findTransformConstraint(constraintMap.name);
TransformConstraintTimeline timeline = new TransformConstraintTimeline(constraintMap.size);
timeline.transformConstraintIndex = skeletonData.getTransformConstraints().indexOf(constraint, true);
int frameIndex = 0;
for (JsonValue valueMap = constraintMap.child; valueMap != null; valueMap = valueMap.next) {
timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat("rotateMix", 1),
valueMap.getFloat("translateMix", 1), valueMap.getFloat("scaleMix", 1), valueMap.getFloat("shearMix", 1));
readCurve(timeline, frameIndex, valueMap);
frameIndex++;
}
timelines.add(timeline);
duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() * 5 - 5]);
}
// FFD timelines.
for (JsonValue ffdMap = map.getChild("ffd"); ffdMap != null; ffdMap = ffdMap.next) {
Skin skin = skeletonData.findSkin(ffdMap.name);

View File

@ -84,6 +84,7 @@ public class SkeletonMeshRenderer extends SkeletonRenderer<PolygonSpriteBatch> {
attachmentSkeleton.setPosition(skeleton.getX() + bone.getWorldX(), skeleton.getY() + bone.getWorldY());
// rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX);
// rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY);
// Set shear.
rootBone.setRotation(oldRotation + bone.getWorldRotationX());
attachmentSkeleton.updateWorldTransform();

View File

@ -78,6 +78,7 @@ public class SkeletonRenderer<T extends Batch> {
attachmentSkeleton.setPosition(skeleton.getX() + bone.getWorldX(), skeleton.getY() + bone.getWorldY());
// rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX);
// rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY);
// Set shear.
rootBone.setRotation(oldRotation + bone.getWorldRotationX());
attachmentSkeleton.updateWorldTransform();

View File

@ -1,19 +1,25 @@
package com.esotericsoftware.spine;
import static com.badlogic.gdx.math.MathUtils.*;
import com.badlogic.gdx.math.Vector2;
public class TransformConstraint implements Updatable {
final TransformConstraintData data;
Bone bone, target;
float translateMix, x, y;
float rotateMix, translateMix, scaleMix, shearMix;
float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY;
final Vector2 temp = new Vector2();
public TransformConstraint (TransformConstraintData data, Skeleton skeleton) {
this.data = data;
translateMix = data.translateMix;
x = data.x;
y = data.y;
rotateMix = data.rotateMix;
scaleMix = data.scaleMix;
shearMix = data.shearMix;
offsetX = data.offsetX;
offsetY = data.offsetY;
if (skeleton != null) {
bone = skeleton.findBone(data.bone.name);
@ -27,8 +33,11 @@ public class TransformConstraint implements Updatable {
bone = skeleton.bones.get(constraint.bone.skeleton.bones.indexOf(constraint.bone, true));
target = skeleton.bones.get(constraint.target.skeleton.bones.indexOf(constraint.target, true));
translateMix = constraint.translateMix;
x = constraint.x;
y = constraint.y;
rotateMix = constraint.rotateMix;
scaleMix = constraint.scaleMix;
shearMix = constraint.shearMix;
offsetX = constraint.offsetX;
offsetY = constraint.offsetY;
}
public void apply () {
@ -36,11 +45,53 @@ public class TransformConstraint implements Updatable {
}
public void update () {
Bone bone = this.bone;
Bone target = this.target;
if (rotateMix > 0) {
float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
float r = atan2(target.c, target.a) - atan2(c, a) + offsetRotation * degRad;
if (r > PI)
r -= PI2;
else if (r < -PI) r += PI2;
r *= rotateMix;
float cos = cos(r), sin = sin(r);
bone.a = cos * a - sin * c;
bone.b = cos * b - sin * d;
bone.c = sin * a + cos * c;
bone.d = sin * b + cos * d;
}
if (scaleMix > 0) {
float bs = (float)Math.sqrt(bone.a * bone.a + bone.c * bone.c);
float ts = (float)Math.sqrt(target.a * target.a + target.c * target.c);
float s = (bs > 0.00001f ? (bs + (ts - bs) * scaleMix) / bs : 0) + offsetScaleX;
bone.a *= s;
bone.c *= s;
bs = (float)Math.sqrt(bone.b * bone.b + bone.d * bone.d);
ts = (float)Math.sqrt(target.b * target.b + target.d * target.d);
s = (bs > 0.00001f ? (bs + (ts - bs) * scaleMix) / bs : 0) + offsetScaleY;
bone.b *= s;
bone.d *= s;
}
if (shearMix > 0) {
float b = bone.b, d = bone.d;
float by = atan2(d, b);
float r = (atan2(target.d, target.b) - atan2(target.c, target.a)) - (by - atan2(bone.c, bone.a));
if (r > PI)
r -= PI2;
else if (r < -PI) r += PI2;
r = by + r * shearMix;
float s = (float)Math.sqrt(b * b + d * d);
bone.b = cos(r + offsetShearY * degRad) * s;
bone.d = sin(r + offsetShearY * degRad) * s;
}
float translateMix = this.translateMix;
if (translateMix > 0) {
Vector2 temp = this.temp;
target.localToWorld(temp.set(x, y));
Bone bone = this.bone;
target.localToWorld(temp.set(offsetX, offsetY));
bone.worldX += (temp.x - bone.worldX) * translateMix;
bone.worldY += (temp.y - bone.worldY) * translateMix;
}
@ -62,6 +113,14 @@ public class TransformConstraint implements Updatable {
this.target = target;
}
public float getRotateMix () {
return rotateMix;
}
public void setRotateMix (float rotateMix) {
this.rotateMix = rotateMix;
}
public float getTranslateMix () {
return translateMix;
}
@ -70,6 +129,70 @@ public class TransformConstraint implements Updatable {
this.translateMix = translateMix;
}
public float getScaleMix () {
return scaleMix;
}
public void setScaleMix (float scaleMix) {
this.scaleMix = scaleMix;
}
public float getShearMix () {
return shearMix;
}
public void setShearMix (float shearMix) {
this.shearMix = shearMix;
}
public float getOffsetRotation () {
return offsetRotation;
}
public void setOffsetRotation (float offsetRotation) {
this.offsetRotation = offsetRotation;
}
public float getOffsetX () {
return offsetX;
}
public void setOffsetX (float offsetX) {
this.offsetX = offsetX;
}
public float getOffsetY () {
return offsetY;
}
public void setOffsetY (float offsetY) {
this.offsetY = offsetY;
}
public float getOffsetScaleX () {
return offsetScaleX;
}
public void setOffsetScaleX (float offsetScaleX) {
this.offsetScaleX = offsetScaleX;
}
public float getOffsetScaleY () {
return offsetScaleY;
}
public void setOffsetScaleY (float offsetScaleY) {
this.offsetScaleY = offsetScaleY;
}
public float getOffsetShearY () {
return offsetShearY;
}
public void setOffsetShearY (float offsetShearY) {
this.offsetShearY = offsetShearY;
}
public TransformConstraintData getData () {
return data;
}

View File

@ -4,8 +4,8 @@ package com.esotericsoftware.spine;
public class TransformConstraintData {
final String name;
BoneData bone, target;
float translateMix;
float x, y;
float rotateMix, translateMix, scaleMix, shearMix;
float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY;
public TransformConstraintData (String name) {
this.name = name;
@ -31,6 +31,14 @@ public class TransformConstraintData {
this.target = target;
}
public float getRotateMix () {
return rotateMix;
}
public void setRotateMix (float rotateMix) {
this.rotateMix = rotateMix;
}
public float getTranslateMix () {
return translateMix;
}
@ -39,20 +47,68 @@ public class TransformConstraintData {
this.translateMix = translateMix;
}
public float getX () {
return x;
public float getScaleMix () {
return scaleMix;
}
public void setX (float x) {
this.x = x;
public void setScaleMix (float scaleMix) {
this.scaleMix = scaleMix;
}
public float getY () {
return y;
public float getShearMix () {
return shearMix;
}
public void setY (float y) {
this.y = y;
public void setShearMix (float shearMix) {
this.shearMix = shearMix;
}
public float getOffsetRotation () {
return offsetRotation;
}
public void setOffsetRotation (float offsetRotation) {
this.offsetRotation = offsetRotation;
}
public float getOffsetX () {
return offsetX;
}
public void setOffsetX (float offsetX) {
this.offsetX = offsetX;
}
public float getOffsetY () {
return offsetY;
}
public void setOffsetY (float offsetY) {
this.offsetY = offsetY;
}
public float getOffsetScaleX () {
return offsetScaleX;
}
public void setOffsetScaleX (float offsetScaleX) {
this.offsetScaleX = offsetScaleX;
}
public float getOffsetScaleY () {
return offsetScaleY;
}
public void setOffsetScaleY (float offsetScaleY) {
this.offsetScaleY = offsetScaleY;
}
public float getOffsetShearY () {
return offsetShearY;
}
public void setOffsetShearY (float offsetShearY) {
this.offsetShearY = offsetShearY;
}
public String toString () {

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version
spine-love works with data exported from Spine 2.1.27. Updating spine-love to [v3.0](https://trello.com/c/tF8UykBM/72-update-runtimes-to-support-v3-0-skewing-scale) and [v3.1](https://trello.com/c/bERJAFEq/73-update-runtimes-to-support-v3-1-linked-meshes) is in progress.
spine-love works with data exported from Spine 2.1.27. Updating spine-love to [v3.0](https://trello.com/c/tF8UykBM/72-update-runtimes-to-support-v3-0-skewing-scale), [v3.1](https://trello.com/c/bERJAFEq/73-update-runtimes-to-support-v3-1-linked-meshes), and [v3.2](https://trello.com/c/k7KtGdPW/76-update-runtimes-to-support-v3-2-shearing) is in progress.
spine-love supports all Spine features except for rendering meshes.

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version
spine-lua works with data exported from Spine 2.1.27. Updating spine-lua to [v3.0](https://trello.com/c/tF8UykBM/72-update-runtimes-to-support-v3-0-skewing-scale) and [v3.1](https://trello.com/c/bERJAFEq/73-update-runtimes-to-support-v3-1-linked-meshes) is in progress.
spine-lua works with data exported from Spine 2.1.27. Updating spine-lua to [v3.0](https://trello.com/c/tF8UykBM/72-update-runtimes-to-support-v3-0-skewing-scale), [v3.1](https://trello.com/c/bERJAFEq/73-update-runtimes-to-support-v3-1-linked-meshes), and [v3.2](https://trello.com/c/k7KtGdPW/76-update-runtimes-to-support-v3-2-shearing) is in progress.
spine-lua supports all Spine features.

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version
spine-monogame works with data exported from the latest version of Spine.
spine-monogame works with data exported from Spine 3.1.08. Updating spine-monogame to [v3.2](https://trello.com/c/k7KtGdPW/76-update-runtimes-to-support-v3-2-shearing) is in progress.
spine-monogame supports all Spine features.

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version
spine-sfml works with data exported from the latest version of Spine.
spine-sfml works with data exported from Spine 3.1.08. Updating spine-sfml to [v3.2](https://trello.com/c/k7KtGdPW/76-update-runtimes-to-support-v3-2-shearing) is in progress.
spine-sfml supports all Spine features.

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version
spine-starling works with data exported from the latest version of Spine.
spine-starling works with data exported from Spine 3.1.08. Updating spine-starling to [v3.2](https://trello.com/c/k7KtGdPW/76-update-runtimes-to-support-v3-2-shearing) is in progress.
spine-starling supports all Spine features.

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version
spine-threejs works with data exported from the latest version of Spine.
spine-threejs works with data exported from Spine 3.1.08. Updating spine-threejs to [v3.2](https://trello.com/c/k7KtGdPW/76-update-runtimes-to-support-v3-2-shearing) is in progress.
spine-threejs supports all Spine features except for rendering meshes.

View File

@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version
spine-turbulenz works with data exported from the latest version of Spine.
spine-turbulenz works with data exported from Spine 3.1.08. Updating spine-turbulenz to [v3.2](https://trello.com/c/k7KtGdPW/76-update-runtimes-to-support-v3-2-shearing) is in progress.
spine-turbulenz supports all Spine features except for rendering meshes.

View File

@ -14,7 +14,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
## Spine version
spine-unity works with data exported from the latest version of Spine.
spine-unity works with data exported from Spine 3.1.08. Updating spine-unity to [v3.2](https://trello.com/c/k7KtGdPW/76-update-runtimes-to-support-v3-2-shearing) is in progress.
spine-unity supports all Spine features.