mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-25 19:21:26 +08:00
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:
parent
506dc49d8a
commit
8d7f761311
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
|||||||
|
|
||||||
## Spine version
|
## 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.
|
spine-as3 supports all Spine features, including meshes. If using the `spine.flash` classes for rendering, meshes are not supported.
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
|||||||
|
|
||||||
## Spine version
|
## 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.
|
spine-c supports all Spine features.
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
|||||||
|
|
||||||
## Spine version
|
## 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.
|
spine-cocos2d-iphone v2 supports all Spine features.
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
|||||||
|
|
||||||
## Spine version
|
## 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.
|
spine-cocos2d-iphone v3 supports all Spine features.
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
|||||||
|
|
||||||
## Spine version
|
## 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.
|
spine-cocos2dx v2 supports all Spine features.
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
|||||||
|
|
||||||
## Spine version
|
## 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.
|
spine-cocos2dx v3 supports all Spine features.
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
|||||||
|
|
||||||
## Spine version
|
## 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.
|
spine-corona supports all Spine features except for rendering meshes due to Corona having a limited graphics API.
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
|||||||
|
|
||||||
## Spine version
|
## 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.
|
spine-csharp supports all Spine features.
|
||||||
|
|
||||||
|
|||||||
@ -14,9 +14,9 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
|||||||
|
|
||||||
## Spine version
|
## 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.
|
spine-js does not yet support loading the binary format.
|
||||||
|
|
||||||
|
|||||||
@ -240,11 +240,11 @@ public class Animation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static public class RotateTimeline extends CurveTimeline {
|
static public class RotateTimeline extends CurveTimeline {
|
||||||
static private final int PREV_FRAME_TIME = -2;
|
static final int PREV_TIME = -2;
|
||||||
static private final int FRAME_VALUE = 1;
|
static final int VALUE = 1;
|
||||||
|
|
||||||
int boneIndex;
|
int boneIndex;
|
||||||
private final float[] frames; // time, angle, ...
|
final float[] frames; // time, angle, ...
|
||||||
|
|
||||||
public RotateTimeline (int frameCount) {
|
public RotateTimeline (int frameCount) {
|
||||||
super(frameCount);
|
super(frameCount);
|
||||||
@ -287,13 +287,13 @@ public class Animation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Interpolate between the previous frame and the current frame.
|
// Interpolate between the previous frame and the current frame.
|
||||||
int frameIndex = binarySearch(frames, time, 2);
|
int frame = binarySearch(frames, time, 2);
|
||||||
float prevFrameValue = frames[frameIndex - 1];
|
float prevFrameValue = frames[frame - 1];
|
||||||
float frameTime = frames[frameIndex];
|
float frameTime = frames[frame];
|
||||||
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frameIndex + PREV_FRAME_TIME] - frameTime), 0, 1);
|
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime), 0, 1);
|
||||||
percent = getCurvePercent((frameIndex >> 1) - 1, percent);
|
percent = getCurvePercent((frame >> 1) - 1, percent);
|
||||||
|
|
||||||
float amount = frames[frameIndex + FRAME_VALUE] - prevFrameValue;
|
float amount = frames[frame + VALUE] - prevFrameValue;
|
||||||
while (amount > 180)
|
while (amount > 180)
|
||||||
amount -= 360;
|
amount -= 360;
|
||||||
while (amount < -180)
|
while (amount < -180)
|
||||||
@ -308,9 +308,9 @@ public class Animation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static public class TranslateTimeline extends CurveTimeline {
|
static public class TranslateTimeline extends CurveTimeline {
|
||||||
static final int PREV_FRAME_TIME = -3;
|
static final int PREV_TIME = -3;
|
||||||
static final int FRAME_X = 1;
|
static final int X = 1;
|
||||||
static final int FRAME_Y = 2;
|
static final int Y = 2;
|
||||||
|
|
||||||
int boneIndex;
|
int boneIndex;
|
||||||
final float[] frames; // time, x, y, ...
|
final float[] frames; // time, x, y, ...
|
||||||
@ -353,15 +353,15 @@ public class Animation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Interpolate between the previous frame and the current frame.
|
// Interpolate between the previous frame and the current frame.
|
||||||
int frameIndex = binarySearch(frames, time, 3);
|
int frame = binarySearch(frames, time, 3);
|
||||||
float prevFrameX = frames[frameIndex - 2];
|
float prevFrameX = frames[frame - 2];
|
||||||
float prevFrameY = frames[frameIndex - 1];
|
float prevFrameY = frames[frame - 1];
|
||||||
float frameTime = frames[frameIndex];
|
float frameTime = frames[frame];
|
||||||
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frameIndex + PREV_FRAME_TIME] - frameTime), 0, 1);
|
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime), 0, 1);
|
||||||
percent = getCurvePercent(frameIndex / 3 - 1, percent);
|
percent = getCurvePercent(frame / 3 - 1, percent);
|
||||||
|
|
||||||
bone.x += (bone.data.x + prevFrameX + (frames[frameIndex + FRAME_X] - prevFrameX) * percent - bone.x) * alpha;
|
bone.x += (bone.data.x + prevFrameX + (frames[frame + X] - prevFrameX) * percent - bone.x) * alpha;
|
||||||
bone.y += (bone.data.y + prevFrameY + (frames[frameIndex + FRAME_Y] - prevFrameY) * percent - bone.y) * 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.
|
// Interpolate between the previous frame and the current frame.
|
||||||
int frameIndex = binarySearch(frames, time, 3);
|
int frame = binarySearch(frames, time, 3);
|
||||||
float prevFrameX = frames[frameIndex - 2];
|
float prevFrameX = frames[frame - 2];
|
||||||
float prevFrameY = frames[frameIndex - 1];
|
float prevFrameY = frames[frame - 1];
|
||||||
float frameTime = frames[frameIndex];
|
float frameTime = frames[frame];
|
||||||
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frameIndex + PREV_FRAME_TIME] - frameTime), 0, 1);
|
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime), 0, 1);
|
||||||
percent = getCurvePercent(frameIndex / 3 - 1, percent);
|
percent = getCurvePercent(frame / 3 - 1, percent);
|
||||||
|
|
||||||
bone.scaleX += (bone.data.scaleX * (prevFrameX + (frames[frameIndex + FRAME_X] - prevFrameX) * percent) - bone.scaleX)
|
bone.scaleX += (bone.data.scaleX * (prevFrameX + (frames[frame + X] - prevFrameX) * percent) - bone.scaleX) * alpha;
|
||||||
* alpha;
|
bone.scaleY += (bone.data.scaleY * (prevFrameY + (frames[frame + Y] - prevFrameY) * percent) - bone.scaleY) * alpha;
|
||||||
bone.scaleY += (bone.data.scaleY * (prevFrameY + (frames[frameIndex + 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 public class ColorTimeline extends CurveTimeline {
|
||||||
static private final int PREV_FRAME_TIME = -5;
|
static private final int PREV_TIME = -5;
|
||||||
static private final int FRAME_R = 1;
|
static private final int R = 1;
|
||||||
static private final int FRAME_G = 2;
|
static private final int G = 2;
|
||||||
static private final int FRAME_B = 3;
|
static private final int B = 3;
|
||||||
static private final int FRAME_A = 4;
|
static private final int A = 4;
|
||||||
|
|
||||||
int slotIndex;
|
int slotIndex;
|
||||||
private final float[] frames; // time, r, g, b, a, ...
|
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.
|
if (time < frames[0]) return; // Time is before first frame.
|
||||||
|
|
||||||
float r, g, b, a;
|
float r, g, b, a;
|
||||||
if (time >= frames[frames.length - 5]) {
|
if (time >= frames[frames.length - 5]) { // Time is after last frame.
|
||||||
// Time is after last frame.
|
|
||||||
int i = frames.length - 1;
|
int i = frames.length - 1;
|
||||||
r = frames[i - 3];
|
r = frames[i - 3];
|
||||||
g = frames[i - 2];
|
g = frames[i - 2];
|
||||||
@ -447,19 +473,19 @@ public class Animation {
|
|||||||
a = frames[i];
|
a = frames[i];
|
||||||
} else {
|
} else {
|
||||||
// Interpolate between the previous frame and the current frame.
|
// Interpolate between the previous frame and the current frame.
|
||||||
int frameIndex = binarySearch(frames, time, 5);
|
int frame = binarySearch(frames, time, 5);
|
||||||
float prevFrameR = frames[frameIndex - 4];
|
float frameTime = frames[frame];
|
||||||
float prevFrameG = frames[frameIndex - 3];
|
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime), 0, 1);
|
||||||
float prevFrameB = frames[frameIndex - 2];
|
percent = getCurvePercent(frame / 5 - 1, percent);
|
||||||
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);
|
|
||||||
|
|
||||||
r = prevFrameR + (frames[frameIndex + FRAME_R] - prevFrameR) * percent;
|
r = frames[frame - 4];
|
||||||
g = prevFrameG + (frames[frameIndex + FRAME_G] - prevFrameG) * percent;
|
g = frames[frame - 3];
|
||||||
b = prevFrameB + (frames[frameIndex + FRAME_B] - prevFrameB) * percent;
|
b = frames[frame - 2];
|
||||||
a = prevFrameA + (frames[frameIndex + FRAME_A] - prevFrameA) * percent;
|
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;
|
Color color = skeleton.slots.get(slotIndex).color;
|
||||||
if (alpha < 1)
|
if (alpha < 1)
|
||||||
@ -513,10 +539,10 @@ public class Animation {
|
|||||||
} else if (lastTime > time) //
|
} else if (lastTime > time) //
|
||||||
lastTime = -1;
|
lastTime = -1;
|
||||||
|
|
||||||
int frameIndex = (time >= frames[frames.length - 1] ? frames.length : binarySearch(frames, time)) - 1;
|
int frame = (time >= frames[frames.length - 1] ? frames.length : binarySearch(frames, time)) - 1;
|
||||||
if (frames[frameIndex] < lastTime) return;
|
if (frames[frame] < lastTime) return;
|
||||||
|
|
||||||
String attachmentName = attachmentNames[frameIndex];
|
String attachmentName = attachmentNames[frame];
|
||||||
skeleton.slots.get(slotIndex)
|
skeleton.slots.get(slotIndex)
|
||||||
.setAttachment(attachmentName == null ? null : skeleton.getAttachment(slotIndex, attachmentName));
|
.setAttachment(attachmentName == null ? null : skeleton.getAttachment(slotIndex, attachmentName));
|
||||||
}
|
}
|
||||||
@ -562,19 +588,19 @@ public class Animation {
|
|||||||
return;
|
return;
|
||||||
if (time < frames[0]) return; // Time is before first frame.
|
if (time < frames[0]) return; // Time is before first frame.
|
||||||
|
|
||||||
int frameIndex;
|
int frame;
|
||||||
if (lastTime < frames[0])
|
if (lastTime < frames[0])
|
||||||
frameIndex = 0;
|
frame = 0;
|
||||||
else {
|
else {
|
||||||
frameIndex = binarySearch(frames, lastTime);
|
frame = binarySearch(frames, lastTime);
|
||||||
float frame = frames[frameIndex];
|
float frameTime = frames[frame];
|
||||||
while (frameIndex > 0) { // Fire multiple events with the same frame.
|
while (frame > 0) { // Fire multiple events with the same frame.
|
||||||
if (frames[frameIndex - 1] != frame) break;
|
if (frames[frame - 1] != frameTime) break;
|
||||||
frameIndex--;
|
frame--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (; frameIndex < frameCount && time >= frames[frameIndex]; frameIndex++)
|
for (; frame < frameCount && time >= frames[frame]; frame++)
|
||||||
firedEvents.add(events[frameIndex]);
|
firedEvents.add(events[frame]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -610,15 +636,15 @@ public class Animation {
|
|||||||
float[] frames = this.frames;
|
float[] frames = this.frames;
|
||||||
if (time < frames[0]) return; // Time is before first frame.
|
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.
|
if (time >= frames[frames.length - 1]) // Time is after last frame.
|
||||||
frameIndex = frames.length - 1;
|
frame = frames.length - 1;
|
||||||
else
|
else
|
||||||
frameIndex = binarySearch(frames, time) - 1;
|
frame = binarySearch(frames, time) - 1;
|
||||||
|
|
||||||
Array<Slot> drawOrder = skeleton.drawOrder;
|
Array<Slot> drawOrder = skeleton.drawOrder;
|
||||||
Array<Slot> slots = skeleton.slots;
|
Array<Slot> slots = skeleton.slots;
|
||||||
int[] drawOrderToSetupIndex = drawOrders[frameIndex];
|
int[] drawOrderToSetupIndex = drawOrders[frame];
|
||||||
if (drawOrderToSetupIndex == null)
|
if (drawOrderToSetupIndex == null)
|
||||||
System.arraycopy(slots.items, 0, drawOrder.items, 0, slots.size);
|
System.arraycopy(slots.items, 0, drawOrder.items, 0, slots.size);
|
||||||
else {
|
else {
|
||||||
@ -699,14 +725,13 @@ public class Animation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Interpolate between the previous frame and the current frame.
|
// Interpolate between the previous frame and the current frame.
|
||||||
int frameIndex = binarySearch(frames, time);
|
int frame = binarySearch(frames, time);
|
||||||
float frameTime = frames[frameIndex];
|
float frameTime = frames[frame];
|
||||||
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frameIndex - 1] - frameTime), 0, 1);
|
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frame - 1] - frameTime), 0, 1);
|
||||||
percent = getCurvePercent(frameIndex - 1, percent);
|
percent = getCurvePercent(frame - 1, percent);
|
||||||
|
|
||||||
float[] prevVertices = frameVertices[frameIndex - 1];
|
|
||||||
float[] nextVertices = frameVertices[frameIndex];
|
|
||||||
|
|
||||||
|
float[] prevVertices = frameVertices[frame - 1];
|
||||||
|
float[] nextVertices = frameVertices[frame];
|
||||||
if (alpha < 1) {
|
if (alpha < 1) {
|
||||||
for (int i = 0; i < vertexCount; i++) {
|
for (int i = 0; i < vertexCount; i++) {
|
||||||
float prev = prevVertices[i];
|
float prev = prevVertices[i];
|
||||||
@ -722,10 +747,10 @@ public class Animation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static public class IkConstraintTimeline extends CurveTimeline {
|
static public class IkConstraintTimeline extends CurveTimeline {
|
||||||
static private final int PREV_FRAME_TIME = -3;
|
static private final int PREV_TIME = -3;
|
||||||
static private final int PREV_FRAME_MIX = -2;
|
static private final int PREV_MIX = -2;
|
||||||
static private final int PREV_FRAME_BEND_DIRECTION = -1;
|
static private final int PREV_BEND_DIRECTION = -1;
|
||||||
static private final int FRAME_MIX = 1;
|
static private final int MIX = 1;
|
||||||
|
|
||||||
int ikConstraintIndex;
|
int ikConstraintIndex;
|
||||||
private final float[] frames; // time, mix, bendDirection, ...
|
private final float[] frames; // time, mix, bendDirection, ...
|
||||||
@ -759,24 +784,97 @@ public class Animation {
|
|||||||
float[] frames = this.frames;
|
float[] frames = this.frames;
|
||||||
if (time < frames[0]) return; // Time is before first frame.
|
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.
|
if (time >= frames[frames.length - 3]) { // Time is after last frame.
|
||||||
ikConstraint.mix += (frames[frames.length - 2] - ikConstraint.mix) * alpha;
|
constraint.mix += (frames[frames.length + PREV_MIX] - constraint.mix) * alpha;
|
||||||
ikConstraint.bendDirection = (int)frames[frames.length - 1];
|
constraint.bendDirection = (int)frames[frames.length + PREV_BEND_DIRECTION];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpolate between the previous frame and the current frame.
|
// Interpolate between the previous frame and the current frame.
|
||||||
int frameIndex = binarySearch(frames, time, 3);
|
int frame = binarySearch(frames, time, 3);
|
||||||
float prevFrameMix = frames[frameIndex + PREV_FRAME_MIX];
|
float frameTime = frames[frame];
|
||||||
float frameTime = frames[frameIndex];
|
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime), 0, 1);
|
||||||
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frameIndex + PREV_FRAME_TIME] - frameTime), 0, 1);
|
percent = getCurvePercent(frame / 3 - 1, percent);
|
||||||
percent = getCurvePercent(frameIndex / 3 - 1, percent);
|
|
||||||
|
|
||||||
float mix = prevFrameMix + (frames[frameIndex + FRAME_MIX] - prevFrameMix) * percent;
|
float mix = frames[frame + PREV_MIX];
|
||||||
ikConstraint.mix += (mix - ikConstraint.mix) * alpha;
|
constraint.mix += (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha;
|
||||||
ikConstraint.bendDirection = (int)frames[frameIndex + PREV_FRAME_BEND_DIRECTION];
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,9 +31,9 @@
|
|||||||
|
|
||||||
package com.esotericsoftware.spine;
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import static com.badlogic.gdx.math.MathUtils.*;
|
||||||
import static com.badlogic.gdx.math.Matrix3.*;
|
import static com.badlogic.gdx.math.Matrix3.*;
|
||||||
|
|
||||||
import com.badlogic.gdx.math.MathUtils;
|
|
||||||
import com.badlogic.gdx.math.Matrix3;
|
import com.badlogic.gdx.math.Matrix3;
|
||||||
import com.badlogic.gdx.math.Vector2;
|
import com.badlogic.gdx.math.Vector2;
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ public class Bone implements Updatable {
|
|||||||
final BoneData data;
|
final BoneData data;
|
||||||
final Skeleton skeleton;
|
final Skeleton skeleton;
|
||||||
final Bone parent;
|
final Bone parent;
|
||||||
float x, y, rotation, scaleX, scaleY;
|
float x, y, rotation, scaleX, scaleY, shearX, shearY;
|
||||||
float appliedRotation, appliedScaleX, appliedScaleY;
|
float appliedRotation, appliedScaleX, appliedScaleY;
|
||||||
|
|
||||||
float a, b, worldX;
|
float a, b, worldX;
|
||||||
@ -76,26 +76,30 @@ public class Bone implements Updatable {
|
|||||||
rotation = bone.rotation;
|
rotation = bone.rotation;
|
||||||
scaleX = bone.scaleX;
|
scaleX = bone.scaleX;
|
||||||
scaleY = bone.scaleY;
|
scaleY = bone.scaleY;
|
||||||
|
shearX = bone.shearX;
|
||||||
|
shearY = bone.shearY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Same as {@link #updateWorldTransform()}. This method exists for Bone to implement {@link Updatable}. */
|
/** Same as {@link #updateWorldTransform()}. This method exists for Bone to implement {@link Updatable}. */
|
||||||
public void update () {
|
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. */
|
/** Computes the world SRT using the parent bone and this bone's local SRT. */
|
||||||
public void updateWorldTransform () {
|
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. */
|
/** 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;
|
appliedRotation = rotation;
|
||||||
appliedScaleX = scaleX;
|
appliedScaleX = scaleX;
|
||||||
appliedScaleY = scaleY;
|
appliedScaleY = scaleY;
|
||||||
|
|
||||||
float cos = MathUtils.cosDeg(rotation), sin = MathUtils.sinDeg(rotation);
|
float rotationY = rotation + 90 + shearY;
|
||||||
float la = cos * scaleX, lb = -sin * scaleY, lc = sin * scaleX, ld = cos * scaleY;
|
float la = cosDeg(rotation + shearX) * scaleX, lb = cosDeg(rotationY) * scaleY;
|
||||||
|
float lc = sinDeg(rotation + shearX) * scaleX, ld = sinDeg(rotationY) * scaleY;
|
||||||
|
|
||||||
Bone parent = this.parent;
|
Bone parent = this.parent;
|
||||||
if (parent == null) { // Root bone.
|
if (parent == null) { // Root bone.
|
||||||
Skeleton skeleton = this.skeleton;
|
Skeleton skeleton = this.skeleton;
|
||||||
@ -138,8 +142,7 @@ public class Bone implements Updatable {
|
|||||||
pc = 0;
|
pc = 0;
|
||||||
pd = 1;
|
pd = 1;
|
||||||
do {
|
do {
|
||||||
cos = MathUtils.cosDeg(parent.appliedRotation);
|
float cos = cosDeg(parent.appliedRotation), sin = sinDeg(parent.appliedRotation);
|
||||||
sin = MathUtils.sinDeg(parent.appliedRotation);
|
|
||||||
float temp = pa * cos + pb * sin;
|
float temp = pa * cos + pb * sin;
|
||||||
pb = pa * -sin + pb * cos;
|
pb = pa * -sin + pb * cos;
|
||||||
pa = temp;
|
pa = temp;
|
||||||
@ -160,9 +163,7 @@ public class Bone implements Updatable {
|
|||||||
pc = 0;
|
pc = 0;
|
||||||
pd = 1;
|
pd = 1;
|
||||||
do {
|
do {
|
||||||
float r = parent.appliedRotation;
|
float r = parent.appliedRotation, cos = cosDeg(r), sin = sinDeg(r);
|
||||||
cos = MathUtils.cosDeg(r);
|
|
||||||
sin = MathUtils.sinDeg(r);
|
|
||||||
float psx = parent.appliedScaleX, psy = parent.appliedScaleY;
|
float psx = parent.appliedScaleX, psy = parent.appliedScaleY;
|
||||||
float za = cos * psx, zb = -sin * psy, zc = sin * psx, zd = cos * psy;
|
float za = cos * psx, zb = -sin * psy, zc = sin * psx, zd = cos * psy;
|
||||||
float temp = pa * za + pb * zc;
|
float temp = pa * za + pb * zc;
|
||||||
@ -173,8 +174,8 @@ public class Bone implements Updatable {
|
|||||||
pc = temp;
|
pc = temp;
|
||||||
|
|
||||||
if (psx < 0) r = -r;
|
if (psx < 0) r = -r;
|
||||||
cos = MathUtils.cosDeg(-r);
|
cos = cosDeg(-r);
|
||||||
sin = MathUtils.sinDeg(-r);
|
sin = sinDeg(-r);
|
||||||
temp = pa * cos + pb * sin;
|
temp = pa * cos + pb * sin;
|
||||||
pb = pa * -sin + pb * cos;
|
pb = pa * -sin + pb * cos;
|
||||||
pa = temp;
|
pa = temp;
|
||||||
@ -213,6 +214,8 @@ public class Bone implements Updatable {
|
|||||||
rotation = data.rotation;
|
rotation = data.rotation;
|
||||||
scaleX = data.scaleX;
|
scaleX = data.scaleX;
|
||||||
scaleY = data.scaleY;
|
scaleY = data.scaleY;
|
||||||
|
shearX = data.shearX;
|
||||||
|
shearY = data.shearY;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BoneData getData () {
|
public BoneData getData () {
|
||||||
@ -248,7 +251,6 @@ public class Bone implements Updatable {
|
|||||||
this.y = y;
|
this.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the forward kinetics rotation. */
|
|
||||||
public float getRotation () {
|
public float getRotation () {
|
||||||
return rotation;
|
return rotation;
|
||||||
}
|
}
|
||||||
@ -283,6 +285,22 @@ public class Bone implements Updatable {
|
|||||||
scaleY = scale;
|
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 () {
|
public float getA () {
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
@ -316,11 +334,11 @@ public class Bone implements Updatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public float getWorldRotationX () {
|
public float getWorldRotationX () {
|
||||||
return MathUtils.atan2(c, a) * MathUtils.radDeg;
|
return atan2(c, a) * radDeg;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getWorldRotationY () {
|
public float getWorldRotationY () {
|
||||||
return MathUtils.atan2(d, b) * MathUtils.radDeg;
|
return atan2(d, b) * radDeg;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getWorldScaleX () {
|
public float getWorldScaleX () {
|
||||||
|
|||||||
@ -37,9 +37,7 @@ public class BoneData {
|
|||||||
final BoneData parent;
|
final BoneData parent;
|
||||||
final String name;
|
final String name;
|
||||||
float length;
|
float length;
|
||||||
float x, y;
|
float x, y, rotation, scaleX = 1, scaleY = 1, shearX, shearY;
|
||||||
float rotation;
|
|
||||||
float scaleX = 1, scaleY = 1;
|
|
||||||
boolean inheritScale = true, inheritRotation = true;
|
boolean inheritScale = true, inheritRotation = true;
|
||||||
|
|
||||||
// Nonessential.
|
// Nonessential.
|
||||||
@ -64,6 +62,8 @@ public class BoneData {
|
|||||||
rotation = bone.rotation;
|
rotation = bone.rotation;
|
||||||
scaleX = bone.scaleX;
|
scaleX = bone.scaleX;
|
||||||
scaleY = bone.scaleY;
|
scaleY = bone.scaleY;
|
||||||
|
shearX = bone.shearX;
|
||||||
|
shearY = bone.shearY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return May be null. */
|
/** @return May be null. */
|
||||||
@ -133,6 +133,22 @@ public class BoneData {
|
|||||||
this.scaleY = scaleY;
|
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 () {
|
public boolean getInheritScale () {
|
||||||
return inheritScale;
|
return inheritScale;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -130,7 +130,7 @@ public class IkConstraint implements Updatable {
|
|||||||
rotationIK -= 360;
|
rotationIK -= 360;
|
||||||
else if (rotationIK < -180) rotationIK += 360;
|
else if (rotationIK < -180) rotationIK += 360;
|
||||||
bone.updateWorldTransform(bone.x, bone.y, rotation + (rotationIK - rotation) * alpha, bone.appliedScaleX,
|
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
|
/** 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;
|
a2 -= 360;
|
||||||
else if (a2 < -180) a2 += 360;
|
else if (a2 < -180) a2 += 360;
|
||||||
float rotation = parent.rotation;
|
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;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -148,8 +148,7 @@ public class Skeleton {
|
|||||||
for (int i = 0; i < transformConstraintsCount; i++) {
|
for (int i = 0; i < transformConstraintsCount; i++) {
|
||||||
TransformConstraint transformConstraint = transformConstraints.get(i);
|
TransformConstraint transformConstraint = transformConstraints.get(i);
|
||||||
for (int ii = updateCache.size - 1; ii >= 0; ii--) {
|
for (int ii = updateCache.size - 1; ii >= 0; ii--) {
|
||||||
Updatable object = updateCache.get(ii);
|
if (updateCache.get(ii) == transformConstraint.bone) {
|
||||||
if (object == transformConstraint.bone || object == transformConstraint.target) {
|
|
||||||
updateCache.insert(ii + 1, transformConstraint);
|
updateCache.insert(ii + 1, transformConstraint);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -186,9 +185,11 @@ public class Skeleton {
|
|||||||
Array<TransformConstraint> transformConstraints = this.transformConstraints;
|
Array<TransformConstraint> transformConstraints = this.transformConstraints;
|
||||||
for (int i = 0, n = transformConstraints.size; i < n; i++) {
|
for (int i = 0, n = transformConstraints.size; i < n; i++) {
|
||||||
TransformConstraint constraint = transformConstraints.get(i);
|
TransformConstraint constraint = transformConstraints.get(i);
|
||||||
constraint.translateMix = constraint.data.translateMix;
|
TransformConstraintData data = constraint.data;
|
||||||
constraint.x = constraint.data.x;
|
constraint.rotateMix = data.rotateMix;
|
||||||
constraint.y = constraint.data.y;
|
constraint.translateMix = data.translateMix;
|
||||||
|
constraint.scaleMix = data.scaleMix;
|
||||||
|
constraint.translateMix = data.translateMix;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -50,7 +50,9 @@ import com.esotericsoftware.spine.Animation.FfdTimeline;
|
|||||||
import com.esotericsoftware.spine.Animation.IkConstraintTimeline;
|
import com.esotericsoftware.spine.Animation.IkConstraintTimeline;
|
||||||
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.Timeline;
|
import com.esotericsoftware.spine.Animation.Timeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.TransformConstraintTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.TranslateTimeline;
|
import com.esotericsoftware.spine.Animation.TranslateTimeline;
|
||||||
import com.esotericsoftware.spine.SkeletonJson.LinkedMesh;
|
import com.esotericsoftware.spine.SkeletonJson.LinkedMesh;
|
||||||
import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
|
import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
|
||||||
@ -63,11 +65,12 @@ import com.esotericsoftware.spine.attachments.RegionAttachment;
|
|||||||
import com.esotericsoftware.spine.attachments.WeightedMeshAttachment;
|
import com.esotericsoftware.spine.attachments.WeightedMeshAttachment;
|
||||||
|
|
||||||
public class SkeletonBinary {
|
public class SkeletonBinary {
|
||||||
static public final int TIMELINE_SCALE = 0;
|
static public final int TIMELINE_ROTATE = 0;
|
||||||
static public final int TIMELINE_ROTATE = 1;
|
static public final int TIMELINE_TRANSLATE = 1;
|
||||||
static public final int TIMELINE_TRANSLATE = 2;
|
static public final int TIMELINE_SCALE = 2;
|
||||||
static public final int TIMELINE_ATTACHMENT = 3;
|
static public final int TIMELINE_SHEAR = 3;
|
||||||
static public final int TIMELINE_COLOR = 4;
|
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_LINEAR = 0;
|
||||||
static public final int CURVE_STEPPED = 1;
|
static public final int CURVE_STEPPED = 1;
|
||||||
@ -159,14 +162,16 @@ public class SkeletonBinary {
|
|||||||
String name = input.readString();
|
String name = input.readString();
|
||||||
BoneData parent = i == 0 ? null : skeletonData.bones.get(input.readInt(true));
|
BoneData parent = i == 0 ? null : skeletonData.bones.get(input.readInt(true));
|
||||||
BoneData boneData = new BoneData(name, parent);
|
BoneData boneData = new BoneData(name, parent);
|
||||||
|
boneData.rotation = input.readFloat();
|
||||||
boneData.x = input.readFloat() * scale;
|
boneData.x = input.readFloat() * scale;
|
||||||
boneData.y = input.readFloat() * scale;
|
boneData.y = input.readFloat() * scale;
|
||||||
boneData.scaleX = input.readFloat();
|
boneData.scaleX = input.readFloat();
|
||||||
boneData.scaleY = input.readFloat();
|
boneData.scaleY = input.readFloat();
|
||||||
boneData.rotation = input.readFloat();
|
boneData.shearX = input.readFloat();
|
||||||
|
boneData.shearY = input.readFloat();
|
||||||
boneData.length = input.readFloat() * scale;
|
boneData.length = input.readFloat() * scale;
|
||||||
boneData.inheritScale = input.readBoolean();
|
|
||||||
boneData.inheritRotation = input.readBoolean();
|
boneData.inheritRotation = input.readBoolean();
|
||||||
|
boneData.inheritScale = input.readBoolean();
|
||||||
if (nonessential) Color.rgba8888ToColor(boneData.color, input.readInt());
|
if (nonessential) Color.rgba8888ToColor(boneData.color, input.readInt());
|
||||||
skeletonData.bones.add(boneData);
|
skeletonData.bones.add(boneData);
|
||||||
}
|
}
|
||||||
@ -187,9 +192,16 @@ public class SkeletonBinary {
|
|||||||
TransformConstraintData transformConstraintData = new TransformConstraintData(input.readString());
|
TransformConstraintData transformConstraintData = new TransformConstraintData(input.readString());
|
||||||
transformConstraintData.bone = skeletonData.bones.get(input.readInt(true));
|
transformConstraintData.bone = skeletonData.bones.get(input.readInt(true));
|
||||||
transformConstraintData.target = 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.translateMix = input.readFloat();
|
||||||
transformConstraintData.x = input.readFloat();
|
transformConstraintData.scaleMix = input.readFloat();
|
||||||
transformConstraintData.y = input.readFloat();
|
transformConstraintData.shearMix = input.readFloat();
|
||||||
skeletonData.transformConstraints.add(transformConstraintData);
|
skeletonData.transformConstraints.add(transformConstraintData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,11 +303,11 @@ public class SkeletonBinary {
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case region: {
|
case region: {
|
||||||
String path = input.readString();
|
String path = input.readString();
|
||||||
|
float rotation = input.readFloat();
|
||||||
float x = input.readFloat();
|
float x = input.readFloat();
|
||||||
float y = input.readFloat();
|
float y = input.readFloat();
|
||||||
float scaleX = input.readFloat();
|
float scaleX = input.readFloat();
|
||||||
float scaleY = input.readFloat();
|
float scaleY = input.readFloat();
|
||||||
float rotation = input.readFloat();
|
|
||||||
float width = input.readFloat();
|
float width = input.readFloat();
|
||||||
float height = input.readFloat();
|
float height = input.readFloat();
|
||||||
int color = input.readInt();
|
int color = input.readInt();
|
||||||
@ -532,11 +544,14 @@ public class SkeletonBinary {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TIMELINE_TRANSLATE:
|
case TIMELINE_TRANSLATE:
|
||||||
case TIMELINE_SCALE: {
|
case TIMELINE_SCALE:
|
||||||
|
case TIMELINE_SHEAR: {
|
||||||
TranslateTimeline timeline;
|
TranslateTimeline timeline;
|
||||||
float timelineScale = 1;
|
float timelineScale = 1;
|
||||||
if (timelineType == TIMELINE_SCALE)
|
if (timelineType == TIMELINE_SCALE)
|
||||||
timeline = new ScaleTimeline(frameCount);
|
timeline = new ScaleTimeline(frameCount);
|
||||||
|
else if (timelineType == TIMELINE_SHEAR)
|
||||||
|
timeline = new ShearTimeline(frameCount);
|
||||||
else {
|
else {
|
||||||
timeline = new TranslateTimeline(frameCount);
|
timeline = new TranslateTimeline(frameCount);
|
||||||
timelineScale = scale;
|
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++) {
|
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);
|
int frameCount = input.readInt(true);
|
||||||
IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount);
|
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++) {
|
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) {
|
||||||
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readByte());
|
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readByte());
|
||||||
if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline);
|
if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline);
|
||||||
@ -569,6 +584,21 @@ public class SkeletonBinary {
|
|||||||
duration = Math.max(duration, timeline.getFrames()[frameCount * 3 - 3]);
|
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.
|
// FFD timelines.
|
||||||
for (int i = 0, n = input.readInt(true); i < n; i++) {
|
for (int i = 0, n = input.readInt(true); i < n; i++) {
|
||||||
Skin skin = skeletonData.skins.get(input.readInt(true));
|
Skin skin = skeletonData.skins.get(input.readInt(true));
|
||||||
|
|||||||
@ -49,7 +49,9 @@ import com.esotericsoftware.spine.Animation.FfdTimeline;
|
|||||||
import com.esotericsoftware.spine.Animation.IkConstraintTimeline;
|
import com.esotericsoftware.spine.Animation.IkConstraintTimeline;
|
||||||
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.Timeline;
|
import com.esotericsoftware.spine.Animation.Timeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.TransformConstraintTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.TranslateTimeline;
|
import com.esotericsoftware.spine.Animation.TranslateTimeline;
|
||||||
import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
|
import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
|
||||||
import com.esotericsoftware.spine.attachments.Attachment;
|
import com.esotericsoftware.spine.attachments.Attachment;
|
||||||
@ -117,6 +119,8 @@ public class SkeletonJson {
|
|||||||
boneData.rotation = boneMap.getFloat("rotation", 0);
|
boneData.rotation = boneMap.getFloat("rotation", 0);
|
||||||
boneData.scaleX = boneMap.getFloat("scaleX", 1);
|
boneData.scaleX = boneMap.getFloat("scaleX", 1);
|
||||||
boneData.scaleY = boneMap.getFloat("scaleY", 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.inheritScale = boneMap.getBoolean("inheritScale", true);
|
||||||
boneData.inheritRotation = boneMap.getBoolean("inheritRotation", true);
|
boneData.inheritRotation = boneMap.getBoolean("inheritRotation", true);
|
||||||
|
|
||||||
@ -159,9 +163,17 @@ public class SkeletonJson {
|
|||||||
transformConstraintData.target = skeletonData.findBone(targetName);
|
transformConstraintData.target = skeletonData.findBone(targetName);
|
||||||
if (transformConstraintData.target == null) throw new SerializationException("Target bone not found: " + 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.translateMix = transformMap.getFloat("translateMix", 1);
|
||||||
transformConstraintData.x = transformMap.getFloat("x", 0) * scale;
|
transformConstraintData.scaleMix = transformMap.getFloat("scaleMix", 1);
|
||||||
transformConstraintData.y = transformMap.getFloat("y", 0) * scale;
|
transformConstraintData.shearMix = transformMap.getFloat("shearMix", 1);
|
||||||
|
|
||||||
skeletonData.transformConstraints.add(transformConstraintData);
|
skeletonData.transformConstraints.add(transformConstraintData);
|
||||||
}
|
}
|
||||||
@ -422,11 +434,13 @@ public class SkeletonJson {
|
|||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() * 2 - 2]);
|
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;
|
TranslateTimeline timeline;
|
||||||
float timelineScale = 1;
|
float timelineScale = 1;
|
||||||
if (timelineName.equals("scale"))
|
if (timelineName.equals("scale"))
|
||||||
timeline = new ScaleTimeline(timelineMap.size);
|
timeline = new ScaleTimeline(timelineMap.size);
|
||||||
|
else if (timelineName.equals("shear"))
|
||||||
|
timeline = new ShearTimeline(timelineMap.size);
|
||||||
else {
|
else {
|
||||||
timeline = new TranslateTimeline(timelineMap.size);
|
timeline = new TranslateTimeline(timelineMap.size);
|
||||||
timelineScale = scale;
|
timelineScale = scale;
|
||||||
@ -448,14 +462,14 @@ public class SkeletonJson {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IK timelines.
|
// IK constraint timelines.
|
||||||
for (JsonValue ikMap = map.getChild("ik"); ikMap != null; ikMap = ikMap.next) {
|
for (JsonValue constraintMap = map.getChild("ik"); constraintMap != null; constraintMap = constraintMap.next) {
|
||||||
IkConstraintData ikConstraint = skeletonData.findIkConstraint(ikMap.name);
|
IkConstraintData constraint = skeletonData.findIkConstraint(constraintMap.name);
|
||||||
IkConstraintTimeline timeline = new IkConstraintTimeline(ikMap.size);
|
IkConstraintTimeline timeline = new IkConstraintTimeline(constraintMap.size);
|
||||||
timeline.ikConstraintIndex = skeletonData.getIkConstraints().indexOf(ikConstraint, true);
|
timeline.ikConstraintIndex = skeletonData.getIkConstraints().indexOf(constraint, true);
|
||||||
int frameIndex = 0;
|
int frameIndex = 0;
|
||||||
for (JsonValue valueMap = ikMap.child; valueMap != null; valueMap = valueMap.next) {
|
for (JsonValue valueMap = constraintMap.child; valueMap != null; valueMap = valueMap.next) {
|
||||||
timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat("mix"),
|
timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat("mix", 1),
|
||||||
valueMap.getBoolean("bendPositive") ? 1 : -1);
|
valueMap.getBoolean("bendPositive") ? 1 : -1);
|
||||||
readCurve(timeline, frameIndex, valueMap);
|
readCurve(timeline, frameIndex, valueMap);
|
||||||
frameIndex++;
|
frameIndex++;
|
||||||
@ -464,6 +478,22 @@ public class SkeletonJson {
|
|||||||
duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() * 3 - 3]);
|
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.
|
// FFD timelines.
|
||||||
for (JsonValue ffdMap = map.getChild("ffd"); ffdMap != null; ffdMap = ffdMap.next) {
|
for (JsonValue ffdMap = map.getChild("ffd"); ffdMap != null; ffdMap = ffdMap.next) {
|
||||||
Skin skin = skeletonData.findSkin(ffdMap.name);
|
Skin skin = skeletonData.findSkin(ffdMap.name);
|
||||||
|
|||||||
@ -84,6 +84,7 @@ public class SkeletonMeshRenderer extends SkeletonRenderer<PolygonSpriteBatch> {
|
|||||||
attachmentSkeleton.setPosition(skeleton.getX() + bone.getWorldX(), skeleton.getY() + bone.getWorldY());
|
attachmentSkeleton.setPosition(skeleton.getX() + bone.getWorldX(), skeleton.getY() + bone.getWorldY());
|
||||||
// rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX);
|
// rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX);
|
||||||
// rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY);
|
// rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY);
|
||||||
|
// Set shear.
|
||||||
rootBone.setRotation(oldRotation + bone.getWorldRotationX());
|
rootBone.setRotation(oldRotation + bone.getWorldRotationX());
|
||||||
attachmentSkeleton.updateWorldTransform();
|
attachmentSkeleton.updateWorldTransform();
|
||||||
|
|
||||||
|
|||||||
@ -78,6 +78,7 @@ public class SkeletonRenderer<T extends Batch> {
|
|||||||
attachmentSkeleton.setPosition(skeleton.getX() + bone.getWorldX(), skeleton.getY() + bone.getWorldY());
|
attachmentSkeleton.setPosition(skeleton.getX() + bone.getWorldX(), skeleton.getY() + bone.getWorldY());
|
||||||
// rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX);
|
// rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX);
|
||||||
// rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY);
|
// rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY);
|
||||||
|
// Set shear.
|
||||||
rootBone.setRotation(oldRotation + bone.getWorldRotationX());
|
rootBone.setRotation(oldRotation + bone.getWorldRotationX());
|
||||||
attachmentSkeleton.updateWorldTransform();
|
attachmentSkeleton.updateWorldTransform();
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,25 @@
|
|||||||
|
|
||||||
package com.esotericsoftware.spine;
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import static com.badlogic.gdx.math.MathUtils.*;
|
||||||
|
|
||||||
import com.badlogic.gdx.math.Vector2;
|
import com.badlogic.gdx.math.Vector2;
|
||||||
|
|
||||||
public class TransformConstraint implements Updatable {
|
public class TransformConstraint implements Updatable {
|
||||||
final TransformConstraintData data;
|
final TransformConstraintData data;
|
||||||
Bone bone, target;
|
Bone bone, target;
|
||||||
float translateMix, x, y;
|
float rotateMix, translateMix, scaleMix, shearMix;
|
||||||
|
float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY;
|
||||||
final Vector2 temp = new Vector2();
|
final Vector2 temp = new Vector2();
|
||||||
|
|
||||||
public TransformConstraint (TransformConstraintData data, Skeleton skeleton) {
|
public TransformConstraint (TransformConstraintData data, Skeleton skeleton) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
translateMix = data.translateMix;
|
translateMix = data.translateMix;
|
||||||
x = data.x;
|
rotateMix = data.rotateMix;
|
||||||
y = data.y;
|
scaleMix = data.scaleMix;
|
||||||
|
shearMix = data.shearMix;
|
||||||
|
offsetX = data.offsetX;
|
||||||
|
offsetY = data.offsetY;
|
||||||
|
|
||||||
if (skeleton != null) {
|
if (skeleton != null) {
|
||||||
bone = skeleton.findBone(data.bone.name);
|
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));
|
bone = skeleton.bones.get(constraint.bone.skeleton.bones.indexOf(constraint.bone, true));
|
||||||
target = skeleton.bones.get(constraint.target.skeleton.bones.indexOf(constraint.target, true));
|
target = skeleton.bones.get(constraint.target.skeleton.bones.indexOf(constraint.target, true));
|
||||||
translateMix = constraint.translateMix;
|
translateMix = constraint.translateMix;
|
||||||
x = constraint.x;
|
rotateMix = constraint.rotateMix;
|
||||||
y = constraint.y;
|
scaleMix = constraint.scaleMix;
|
||||||
|
shearMix = constraint.shearMix;
|
||||||
|
offsetX = constraint.offsetX;
|
||||||
|
offsetY = constraint.offsetY;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply () {
|
public void apply () {
|
||||||
@ -36,11 +45,53 @@ public class TransformConstraint implements Updatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void update () {
|
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;
|
float translateMix = this.translateMix;
|
||||||
if (translateMix > 0) {
|
if (translateMix > 0) {
|
||||||
Vector2 temp = this.temp;
|
Vector2 temp = this.temp;
|
||||||
target.localToWorld(temp.set(x, y));
|
target.localToWorld(temp.set(offsetX, offsetY));
|
||||||
Bone bone = this.bone;
|
|
||||||
bone.worldX += (temp.x - bone.worldX) * translateMix;
|
bone.worldX += (temp.x - bone.worldX) * translateMix;
|
||||||
bone.worldY += (temp.y - bone.worldY) * translateMix;
|
bone.worldY += (temp.y - bone.worldY) * translateMix;
|
||||||
}
|
}
|
||||||
@ -62,6 +113,14 @@ public class TransformConstraint implements Updatable {
|
|||||||
this.target = target;
|
this.target = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float getRotateMix () {
|
||||||
|
return rotateMix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRotateMix (float rotateMix) {
|
||||||
|
this.rotateMix = rotateMix;
|
||||||
|
}
|
||||||
|
|
||||||
public float getTranslateMix () {
|
public float getTranslateMix () {
|
||||||
return translateMix;
|
return translateMix;
|
||||||
}
|
}
|
||||||
@ -70,6 +129,70 @@ public class TransformConstraint implements Updatable {
|
|||||||
this.translateMix = translateMix;
|
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 () {
|
public TransformConstraintData getData () {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,8 @@ package com.esotericsoftware.spine;
|
|||||||
public class TransformConstraintData {
|
public class TransformConstraintData {
|
||||||
final String name;
|
final String name;
|
||||||
BoneData bone, target;
|
BoneData bone, target;
|
||||||
float translateMix;
|
float rotateMix, translateMix, scaleMix, shearMix;
|
||||||
float x, y;
|
float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY;
|
||||||
|
|
||||||
public TransformConstraintData (String name) {
|
public TransformConstraintData (String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@ -31,6 +31,14 @@ public class TransformConstraintData {
|
|||||||
this.target = target;
|
this.target = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float getRotateMix () {
|
||||||
|
return rotateMix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRotateMix (float rotateMix) {
|
||||||
|
this.rotateMix = rotateMix;
|
||||||
|
}
|
||||||
|
|
||||||
public float getTranslateMix () {
|
public float getTranslateMix () {
|
||||||
return translateMix;
|
return translateMix;
|
||||||
}
|
}
|
||||||
@ -39,20 +47,68 @@ public class TransformConstraintData {
|
|||||||
this.translateMix = translateMix;
|
this.translateMix = translateMix;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getX () {
|
public float getScaleMix () {
|
||||||
return x;
|
return scaleMix;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setX (float x) {
|
public void setScaleMix (float scaleMix) {
|
||||||
this.x = x;
|
this.scaleMix = scaleMix;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getY () {
|
public float getShearMix () {
|
||||||
return y;
|
return shearMix;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setY (float y) {
|
public void setShearMix (float shearMix) {
|
||||||
this.y = y;
|
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 () {
|
public String toString () {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
|||||||
|
|
||||||
## Spine version
|
## 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.
|
spine-love supports all Spine features except for rendering meshes.
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
|||||||
|
|
||||||
## Spine version
|
## 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.
|
spine-lua supports all Spine features.
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
|||||||
|
|
||||||
## Spine version
|
## 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.
|
spine-monogame supports all Spine features.
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
|||||||
|
|
||||||
## Spine version
|
## 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.
|
spine-sfml supports all Spine features.
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
|||||||
|
|
||||||
## Spine version
|
## 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.
|
spine-starling supports all Spine features.
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
|||||||
|
|
||||||
## Spine version
|
## 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.
|
spine-threejs supports all Spine features except for rendering meshes.
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
|||||||
|
|
||||||
## Spine version
|
## 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.
|
spine-turbulenz supports all Spine features except for rendering meshes.
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
|||||||
|
|
||||||
## Spine version
|
## 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.
|
spine-unity supports all Spine features.
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user