mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 14:24:53 +08:00
Updated for Spine 3.0.00.
This commit is contained in:
parent
f6e4027ef1
commit
37f2f9e880
8
LICENSE
8
LICENSE
@ -1,7 +1,7 @@
|
||||
Spine Runtimes Software License
|
||||
Version 2.3
|
||||
Version 2.4
|
||||
|
||||
Copyright (c) 2013-2015, Esoteric Software
|
||||
Copyright (c) 2013-2016, Esoteric Software
|
||||
All rights reserved.
|
||||
|
||||
You are granted a perpetual, non-exclusive, non-sublicensable and
|
||||
@ -9,8 +9,8 @@ non-transferable license to use, install, execute and perform the Spine
|
||||
Runtimes Software (the "Software") and derivative works solely for personal
|
||||
or internal use. Without the written permission of Esoteric Software (see
|
||||
Section 2 of the Spine Software License Agreement), you may not (a) modify,
|
||||
translate, adapt or otherwise create derivative works, improvements of the
|
||||
Software or develop new applications using the Software or (b) remove,
|
||||
translate, adapt or otherwise create derivative works, improvements of
|
||||
the Software or develop new applications using the Software or (b) remove,
|
||||
delete, alter or obscure any trademarks or any copyright, trademark, patent
|
||||
or other intellectual property or proprietary rights notices on or in the
|
||||
Software, including any copy thereof. Redistributions in binary or source
|
||||
|
||||
@ -67,8 +67,8 @@ public class BonePlotting {
|
||||
while (time < animation.getDuration()) {
|
||||
animation.apply(skeleton, time, time, false, null);
|
||||
skeleton.updateWorldTransform();
|
||||
System.out.println(animation.getName() + "," + bone.getWorldX() + "," + bone.getWorldY() + ","
|
||||
+ bone.getWorldRotation() + "," + bone.getWorldScaleX() + "," + bone.getWorldScaleY());
|
||||
System.out
|
||||
.println(animation.getName() + "," + bone.getWorldX() + "," + bone.getWorldY() + "," + bone.getWorldRotationX());
|
||||
time += fps;
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,7 +160,7 @@ public class Box2DExample extends ApplicationAdapter {
|
||||
if (attachment.body == null) continue;
|
||||
float x = skeleton.x + slot.getBone().getWorldX();
|
||||
float y = skeleton.y + slot.getBone().getWorldY();
|
||||
float rotation = slot.getBone().getWorldRotation();
|
||||
float rotation = slot.getBone().getWorldRotationX();
|
||||
attachment.body.setTransform(x, y, rotation * MathUtils.degRad);
|
||||
}
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||
public class SimpleTest3 extends ApplicationAdapter {
|
||||
OrthographicCamera camera;
|
||||
PolygonSpriteBatch batch;
|
||||
SkeletonRenderer renderer;
|
||||
SkeletonMeshRenderer renderer;
|
||||
SkeletonRendererDebug debugRenderer;
|
||||
|
||||
TextureAtlas atlas;
|
||||
@ -52,7 +52,7 @@ public class SimpleTest3 extends ApplicationAdapter {
|
||||
public void create () {
|
||||
camera = new OrthographicCamera();
|
||||
batch = new PolygonSpriteBatch(); // Required to render meshes. SpriteBatch can't render meshes.
|
||||
renderer = new SkeletonRenderer();
|
||||
renderer = new SkeletonMeshRenderer();
|
||||
renderer.setPremultipliedAlpha(true);
|
||||
debugRenderer = new SkeletonRendererDebug();
|
||||
debugRenderer.setMeshTriangles(false);
|
||||
|
||||
@ -45,7 +45,7 @@ import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||
public class SkeletonAttachmentTest extends ApplicationAdapter {
|
||||
OrthographicCamera camera;
|
||||
PolygonSpriteBatch batch;
|
||||
SkeletonRenderer renderer;
|
||||
SkeletonMeshRenderer renderer;
|
||||
|
||||
Skeleton spineboy, goblin;
|
||||
AnimationState spineboyState, goblinState;
|
||||
@ -53,7 +53,7 @@ public class SkeletonAttachmentTest extends ApplicationAdapter {
|
||||
public void create () {
|
||||
camera = new OrthographicCamera();
|
||||
batch = new PolygonSpriteBatch();
|
||||
renderer = new SkeletonRenderer();
|
||||
renderer = new SkeletonMeshRenderer();
|
||||
renderer.setPremultipliedAlpha(true);
|
||||
|
||||
{
|
||||
@ -77,9 +77,9 @@ public class SkeletonAttachmentTest extends ApplicationAdapter {
|
||||
}
|
||||
|
||||
{
|
||||
TextureAtlas atlas = new TextureAtlas(Gdx.files.internal("goblins/goblins-ffd.atlas"));
|
||||
TextureAtlas atlas = new TextureAtlas(Gdx.files.internal("goblins/goblins-mesh.atlas"));
|
||||
SkeletonJson json = new SkeletonJson(atlas);
|
||||
SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("goblins/goblins-ffd.json"));
|
||||
SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("goblins/goblins-mesh.json"));
|
||||
goblin = new Skeleton(skeletonData);
|
||||
goblin.setSkin("goblin");
|
||||
goblin.setSlotsToSetupPose();
|
||||
|
||||
@ -777,62 +777,4 @@ public class Animation {
|
||||
ikConstraint.bendDirection = (int)frames[frameIndex + PREV_FRAME_BEND_DIRECTION];
|
||||
}
|
||||
}
|
||||
|
||||
static public class FlipXTimeline implements Timeline {
|
||||
int boneIndex;
|
||||
final float[] frames; // time, flip, ...
|
||||
|
||||
public FlipXTimeline (int frameCount) {
|
||||
frames = new float[frameCount << 1];
|
||||
}
|
||||
|
||||
public void setBoneIndex (int boneIndex) {
|
||||
this.boneIndex = boneIndex;
|
||||
}
|
||||
|
||||
public int getBoneIndex () {
|
||||
return boneIndex;
|
||||
}
|
||||
|
||||
public int getFrameCount () {
|
||||
return frames.length >> 1;
|
||||
}
|
||||
|
||||
public float[] getFrames () {
|
||||
return frames;
|
||||
}
|
||||
|
||||
/** Sets the time and value of the specified keyframe. */
|
||||
public void setFrame (int frameIndex, float time, boolean flip) {
|
||||
frameIndex *= 2;
|
||||
frames[frameIndex] = time;
|
||||
frames[frameIndex + 1] = flip ? 1 : 0;
|
||||
}
|
||||
|
||||
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha) {
|
||||
float[] frames = this.frames;
|
||||
if (time < frames[0]) {
|
||||
if (lastTime > time) apply(skeleton, lastTime, Integer.MAX_VALUE, null, 0);
|
||||
return;
|
||||
} else if (lastTime > time) //
|
||||
lastTime = -1;
|
||||
int frameIndex = (time >= frames[frames.length - 2] ? frames.length : binarySearch(frames, time, 2)) - 2;
|
||||
if (frames[frameIndex] < lastTime) return;
|
||||
setFlip(skeleton.bones.get(boneIndex), frames[frameIndex + 1] != 0);
|
||||
}
|
||||
|
||||
protected void setFlip (Bone bone, boolean flip) {
|
||||
bone.setFlipX(flip);
|
||||
}
|
||||
}
|
||||
|
||||
static public class FlipYTimeline extends FlipXTimeline {
|
||||
public FlipYTimeline (int frameCount) {
|
||||
super(frameCount);
|
||||
}
|
||||
|
||||
protected void setFlip (Bone bone, boolean flip) {
|
||||
bone.setFlipY(flip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ import com.badlogic.gdx.utils.Pool.Poolable;
|
||||
|
||||
/** Stores state for an animation and automatically mixes between animations. */
|
||||
public class AnimationState {
|
||||
private final AnimationStateData data;
|
||||
private AnimationStateData data;
|
||||
private Array<TrackEntry> tracks = new Array();
|
||||
private final Array<Event> events = new Array();
|
||||
private final Array<AnimationStateListener> listeners = new Array();
|
||||
@ -49,6 +49,10 @@ public class AnimationState {
|
||||
}
|
||||
};
|
||||
|
||||
/** Creates an uninitialized AnimationState. The animation state data must be set. */
|
||||
public AnimationState () {
|
||||
}
|
||||
|
||||
public AnimationState (AnimationStateData data) {
|
||||
if (data == null) throw new IllegalArgumentException("data cannot be null.");
|
||||
this.data = data;
|
||||
@ -269,6 +273,10 @@ public class AnimationState {
|
||||
listeners.removeValue(listener, true);
|
||||
}
|
||||
|
||||
public void clearListeners () {
|
||||
listeners.clear();
|
||||
}
|
||||
|
||||
public float getTimeScale () {
|
||||
return timeScale;
|
||||
}
|
||||
@ -281,6 +289,10 @@ public class AnimationState {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData (AnimationStateData data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/** Returns the list of tracks that have animations, which may contain nulls. */
|
||||
public Array<TrackEntry> getTracks () {
|
||||
return tracks;
|
||||
|
||||
@ -31,26 +31,23 @@
|
||||
|
||||
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;
|
||||
|
||||
public class Bone {
|
||||
public class Bone implements Updatable {
|
||||
final BoneData data;
|
||||
final Skeleton skeleton;
|
||||
final Bone parent;
|
||||
float x, y;
|
||||
float rotation, rotationIK;
|
||||
float scaleX, scaleY;
|
||||
boolean flipX, flipY;
|
||||
float x, y, rotation, scaleX, scaleY;
|
||||
float appliedRotation, appliedScaleX, appliedScaleY;
|
||||
|
||||
float m00, m01, worldX; // a b x
|
||||
float m10, m11, worldY; // c d y
|
||||
float worldRotation;
|
||||
float worldScaleX, worldScaleY;
|
||||
boolean worldFlipX, worldFlipY;
|
||||
float a, b, worldX;
|
||||
float c, d, worldY;
|
||||
float worldSignX, worldSignY;
|
||||
|
||||
Bone (BoneData data) {
|
||||
this.data = data;
|
||||
@ -78,57 +75,126 @@ public class Bone {
|
||||
x = bone.x;
|
||||
y = bone.y;
|
||||
rotation = bone.rotation;
|
||||
rotationIK = bone.rotationIK;
|
||||
scaleX = bone.scaleX;
|
||||
scaleY = bone.scaleY;
|
||||
flipX = bone.flipX;
|
||||
flipY = bone.flipY;
|
||||
}
|
||||
|
||||
/** Computes the world SRT using the parent bone and the local SRT. */
|
||||
/** Computes the world SRT using the parent bone and this bone's local SRT. */
|
||||
public void updateWorldTransform () {
|
||||
Skeleton skeleton = this.skeleton;
|
||||
updateWorldTransform(x, y, rotation, scaleX, scaleY);
|
||||
}
|
||||
|
||||
/** 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) {
|
||||
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;
|
||||
Bone parent = this.parent;
|
||||
float x = this.x, y = this.y;
|
||||
if (parent != null) {
|
||||
worldX = x * parent.m00 + y * parent.m01 + parent.worldX;
|
||||
worldY = x * parent.m10 + y * parent.m11 + parent.worldY;
|
||||
if (data.inheritScale) {
|
||||
worldScaleX = parent.worldScaleX * scaleX;
|
||||
worldScaleY = parent.worldScaleY * scaleY;
|
||||
} else {
|
||||
worldScaleX = scaleX;
|
||||
worldScaleY = scaleY;
|
||||
}
|
||||
worldRotation = data.inheritRotation ? parent.worldRotation + rotationIK : rotationIK;
|
||||
worldFlipX = parent.worldFlipX ^ flipX;
|
||||
worldFlipY = parent.worldFlipY ^ flipY;
|
||||
} else {
|
||||
if (parent == null) { // Root bone.
|
||||
Skeleton skeleton = this.skeleton;
|
||||
boolean skeletonFlipX = skeleton.flipX, skeletonFlipY = skeleton.flipY;
|
||||
worldX = skeletonFlipX ? -x : x;
|
||||
worldY = skeletonFlipY ? -y : y;
|
||||
worldScaleX = scaleX;
|
||||
worldScaleY = scaleY;
|
||||
worldRotation = rotationIK;
|
||||
worldFlipX = skeletonFlipX ^ flipX;
|
||||
worldFlipY = skeletonFlipY ^ flipY;
|
||||
if (skeletonFlipX) {
|
||||
scaleX = -scaleX;
|
||||
x = -x;
|
||||
}
|
||||
float cos = MathUtils.cosDeg(worldRotation);
|
||||
float sin = MathUtils.sinDeg(worldRotation);
|
||||
if (worldFlipX) {
|
||||
m00 = -cos * worldScaleX;
|
||||
m01 = sin * worldScaleY;
|
||||
if (skeletonFlipY) {
|
||||
scaleY = -scaleY;
|
||||
y = -y;
|
||||
}
|
||||
a = la;
|
||||
b = lb;
|
||||
c = lc;
|
||||
d = ld;
|
||||
worldX = x;
|
||||
worldY = y;
|
||||
worldSignX = Math.signum(scaleX);
|
||||
worldSignY = Math.signum(scaleY);
|
||||
return;
|
||||
}
|
||||
|
||||
float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d;
|
||||
worldX = pa * x + pb * y + parent.worldX;
|
||||
worldY = pc * x + pd * y + parent.worldY;
|
||||
worldSignX = parent.worldSignX * Math.signum(scaleX);
|
||||
worldSignY = parent.worldSignY * Math.signum(scaleY);
|
||||
|
||||
if (data.inheritRotation && data.inheritScale) {
|
||||
a = pa * la + pb * lc;
|
||||
b = pa * lb + pb * ld;
|
||||
c = pc * la + pd * lc;
|
||||
d = pc * lb + pd * ld;
|
||||
} else if (data.inheritRotation) { // No scale inheritance.
|
||||
Bone p = parent;
|
||||
pa = 1;
|
||||
pb = 0;
|
||||
pc = 0;
|
||||
pd = 1;
|
||||
while (p != null) {
|
||||
cos = MathUtils.cosDeg(p.appliedRotation);
|
||||
sin = MathUtils.sinDeg(p.appliedRotation);
|
||||
float a = pa * cos + pb * sin;
|
||||
float b = pa * -sin + pb * cos;
|
||||
float c = pc * cos + pd * sin;
|
||||
float d = pc * -sin + pd * cos;
|
||||
pa = a;
|
||||
pb = b;
|
||||
pc = c;
|
||||
pd = d;
|
||||
p = p.parent;
|
||||
}
|
||||
a = pa * la + pb * lc;
|
||||
b = pa * lb + pb * ld;
|
||||
c = pc * la + pd * lc;
|
||||
d = pc * lb + pd * ld;
|
||||
} else if (data.inheritScale) { // No rotation inheritance.
|
||||
Bone p = parent;
|
||||
pa = 1;
|
||||
pb = 0;
|
||||
pc = 0;
|
||||
pd = 1;
|
||||
while (p != null) {
|
||||
float r = p.rotation;
|
||||
cos = MathUtils.cosDeg(r);
|
||||
sin = MathUtils.sinDeg(r);
|
||||
float psx = p.appliedScaleX, psy = p.appliedScaleY;
|
||||
float za = cos * psx, zb = -sin * psy, zc = sin * psx, zd = cos * psy;
|
||||
float temp = pa * za + pb * zc;
|
||||
pb = pa * zb + pb * zd;
|
||||
pa = temp;
|
||||
temp = pc * za + pd * zc;
|
||||
pd = pc * zb + pd * zd;
|
||||
pc = temp;
|
||||
|
||||
if (psx < 0) r = PI - r;
|
||||
cos = MathUtils.cosDeg(-r);
|
||||
sin = MathUtils.sinDeg(-r);
|
||||
temp = pa * cos + pb * sin;
|
||||
pb = pa * -sin + pb * cos;
|
||||
pa = temp;
|
||||
temp = pc * cos + pd * sin;
|
||||
pd = pc * -sin + pd * cos;
|
||||
pc = temp;
|
||||
|
||||
p = p.parent;
|
||||
}
|
||||
a = pa * la + pb * lc;
|
||||
b = pa * lb + pb * ld;
|
||||
c = pc * la + pd * lc;
|
||||
d = pc * lb + pd * ld;
|
||||
} else {
|
||||
m00 = cos * worldScaleX;
|
||||
m01 = -sin * worldScaleY;
|
||||
a = la;
|
||||
b = lb;
|
||||
c = lc;
|
||||
d = ld;
|
||||
}
|
||||
if (worldFlipY) {
|
||||
m10 = -sin * worldScaleX;
|
||||
m11 = -cos * worldScaleY;
|
||||
} else {
|
||||
m10 = sin * worldScaleX;
|
||||
m11 = cos * worldScaleY;
|
||||
}
|
||||
|
||||
/** Same as {@link #updateWorldTransform()}. This method exists for Bone to implement {@link Updatable}. */
|
||||
public void update () {
|
||||
updateWorldTransform(x, y, rotation, scaleX, scaleY);
|
||||
}
|
||||
|
||||
public void setToSetupPose () {
|
||||
@ -136,11 +202,8 @@ public class Bone {
|
||||
x = data.x;
|
||||
y = data.y;
|
||||
rotation = data.rotation;
|
||||
rotationIK = rotation;
|
||||
scaleX = data.scaleX;
|
||||
scaleY = data.scaleY;
|
||||
flipX = data.flipX;
|
||||
flipY = data.flipY;
|
||||
}
|
||||
|
||||
public BoneData getData () {
|
||||
@ -185,15 +248,6 @@ public class Bone {
|
||||
this.rotation = rotation;
|
||||
}
|
||||
|
||||
/** Returns the inverse kinetics rotation, as calculated by any IK constraints. */
|
||||
public float getRotationIK () {
|
||||
return rotationIK;
|
||||
}
|
||||
|
||||
public void setRotationIK (float rotationIK) {
|
||||
this.rotationIK = rotationIK;
|
||||
}
|
||||
|
||||
public float getScaleX () {
|
||||
return scaleX;
|
||||
}
|
||||
@ -220,36 +274,20 @@ public class Bone {
|
||||
scaleY = scale;
|
||||
}
|
||||
|
||||
public boolean getFlipX () {
|
||||
return flipX;
|
||||
public float getA () {
|
||||
return a;
|
||||
}
|
||||
|
||||
public void setFlipX (boolean flipX) {
|
||||
this.flipX = flipX;
|
||||
public float getB () {
|
||||
return b;
|
||||
}
|
||||
|
||||
public boolean getFlipY () {
|
||||
return flipY;
|
||||
public float getC () {
|
||||
return c;
|
||||
}
|
||||
|
||||
public void setFlipY (boolean flipY) {
|
||||
this.flipY = flipY;
|
||||
}
|
||||
|
||||
public float getM00 () {
|
||||
return m00;
|
||||
}
|
||||
|
||||
public float getM01 () {
|
||||
return m01;
|
||||
}
|
||||
|
||||
public float getM10 () {
|
||||
return m10;
|
||||
}
|
||||
|
||||
public float getM11 () {
|
||||
return m11;
|
||||
public float getD () {
|
||||
return d;
|
||||
}
|
||||
|
||||
public float getWorldX () {
|
||||
@ -260,33 +298,37 @@ public class Bone {
|
||||
return worldY;
|
||||
}
|
||||
|
||||
public float getWorldRotation () {
|
||||
return worldRotation;
|
||||
public float getWorldRotationX () {
|
||||
return (float)Math.atan2(c, a) * MathUtils.radDeg;
|
||||
}
|
||||
|
||||
public float getWorldRotationY () {
|
||||
return (float)Math.atan2(d, b) * MathUtils.radDeg;
|
||||
}
|
||||
|
||||
public float getWorldScaleX () {
|
||||
return worldScaleX;
|
||||
return (float)Math.sqrt(a * a + b * b) * worldSignX;
|
||||
}
|
||||
|
||||
public float getWorldScaleY () {
|
||||
return worldScaleY;
|
||||
return (float)Math.sqrt(c * c + d * d) * worldSignY;
|
||||
}
|
||||
|
||||
public boolean getWorldFlipX () {
|
||||
return worldFlipX;
|
||||
public float getWorldSignX () {
|
||||
return worldSignX;
|
||||
}
|
||||
|
||||
public boolean getWorldFlipY () {
|
||||
return worldFlipY;
|
||||
public float getWorldSignY () {
|
||||
return worldSignY;
|
||||
}
|
||||
|
||||
public Matrix3 getWorldTransform (Matrix3 worldTransform) {
|
||||
if (worldTransform == null) throw new IllegalArgumentException("worldTransform cannot be null.");
|
||||
float[] val = worldTransform.val;
|
||||
val[M00] = m00;
|
||||
val[M01] = m01;
|
||||
val[M10] = m10;
|
||||
val[M11] = m11;
|
||||
val[M00] = a;
|
||||
val[M01] = b;
|
||||
val[M10] = c;
|
||||
val[M11] = d;
|
||||
val[M02] = worldX;
|
||||
val[M12] = worldY;
|
||||
val[M20] = 0;
|
||||
@ -297,21 +339,17 @@ public class Bone {
|
||||
|
||||
public Vector2 worldToLocal (Vector2 world) {
|
||||
float x = world.x - worldX, y = world.y - worldY;
|
||||
float m00 = this.m00, m10 = this.m10, m01 = this.m01, m11 = this.m11;
|
||||
if (worldFlipX != worldFlipY) {
|
||||
m00 = -m00;
|
||||
m11 = -m11;
|
||||
}
|
||||
float invDet = 1 / (m00 * m11 - m01 * m10);
|
||||
world.x = (x * m00 * invDet - y * m01 * invDet);
|
||||
world.y = (y * m11 * invDet - x * m10 * invDet);
|
||||
float a = this.a, b = this.b, c = this.c, d = this.d;
|
||||
float invDet = 1 / (a * d - b * c);
|
||||
world.x = (x * a * invDet - y * b * invDet);
|
||||
world.y = (y * d * invDet - x * c * invDet);
|
||||
return world;
|
||||
}
|
||||
|
||||
public Vector2 localToWorld (Vector2 local) {
|
||||
float x = local.x, y = local.y;
|
||||
local.x = x * m00 + y * m01 + worldX;
|
||||
local.y = x * m10 + y * m11 + worldY;
|
||||
local.x = x * a + y * b + worldX;
|
||||
local.y = x * c + y * d + worldY;
|
||||
return local;
|
||||
}
|
||||
|
||||
|
||||
@ -40,8 +40,7 @@ public class BoneData {
|
||||
float x, y;
|
||||
float rotation;
|
||||
float scaleX = 1, scaleY = 1;
|
||||
boolean flipX, flipY;
|
||||
boolean inheritScale = true, inheritRotation = true;
|
||||
boolean inheritScale, inheritRotation;
|
||||
|
||||
// Nonessential.
|
||||
final Color color = new Color(0.61f, 0.61f, 0.61f, 1);
|
||||
@ -65,8 +64,6 @@ public class BoneData {
|
||||
rotation = bone.rotation;
|
||||
scaleX = bone.scaleX;
|
||||
scaleY = bone.scaleY;
|
||||
flipX = bone.flipX;
|
||||
flipY = bone.flipY;
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
@ -136,22 +133,6 @@ public class BoneData {
|
||||
this.scaleY = scaleY;
|
||||
}
|
||||
|
||||
public boolean getFlipX () {
|
||||
return flipX;
|
||||
}
|
||||
|
||||
public void setFlipX (boolean flipX) {
|
||||
this.flipX = flipX;
|
||||
}
|
||||
|
||||
public boolean getFlipY () {
|
||||
return flipY;
|
||||
}
|
||||
|
||||
public void setFlipY (boolean flipY) {
|
||||
this.flipY = flipY;
|
||||
}
|
||||
|
||||
public boolean getInheritScale () {
|
||||
return inheritScale;
|
||||
}
|
||||
|
||||
@ -33,12 +33,9 @@ package com.esotericsoftware.spine;
|
||||
|
||||
import static com.badlogic.gdx.math.MathUtils.*;
|
||||
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
public class IkConstraint {
|
||||
static private final Vector2 temp = new Vector2();
|
||||
|
||||
public class IkConstraint implements Updatable {
|
||||
final IkConstraintData data;
|
||||
final Array<Bone> bones;
|
||||
Bone target;
|
||||
@ -59,15 +56,21 @@ public class IkConstraint {
|
||||
}
|
||||
|
||||
/** Copy constructor. */
|
||||
public IkConstraint (IkConstraint ikConstraint, Array<Bone> bones, Bone target) {
|
||||
public IkConstraint (IkConstraint ikConstraint, Skeleton skeleton) {
|
||||
data = ikConstraint.data;
|
||||
this.bones = bones;
|
||||
this.target = target;
|
||||
bones = new Array(ikConstraint.bones.size);
|
||||
for (Bone bone : ikConstraint.bones)
|
||||
bones.add(skeleton.bones.get(bone.skeleton.bones.indexOf(bone, true)));
|
||||
target = skeleton.bones.get(ikConstraint.target.skeleton.bones.indexOf(ikConstraint.target, true));
|
||||
mix = ikConstraint.mix;
|
||||
bendDirection = ikConstraint.bendDirection;
|
||||
}
|
||||
|
||||
public void apply () {
|
||||
update();
|
||||
}
|
||||
|
||||
public void update () {
|
||||
Bone target = this.target;
|
||||
Array<Bone> bones = this.bones;
|
||||
switch (bones.size) {
|
||||
@ -113,67 +116,143 @@ public class IkConstraint {
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
return data.name;
|
||||
return data.name + " CONSTRAINT";
|
||||
}
|
||||
|
||||
/** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world
|
||||
* coordinate system. */
|
||||
static public void apply (Bone bone, float targetX, float targetY, float alpha) {
|
||||
float parentRotation = (!bone.data.inheritRotation || bone.parent == null) ? 0 : bone.parent.worldRotation;
|
||||
float parentRotation = bone.parent == null ? 0 : bone.parent.getWorldRotationX();
|
||||
float rotation = bone.rotation;
|
||||
float rotationIK = (float)Math.atan2(targetY - bone.worldY, targetX - bone.worldX) * radDeg - parentRotation;
|
||||
bone.rotationIK = rotation + (rotationIK - rotation) * alpha;
|
||||
float rotationIK = atan2(targetY - bone.worldY, targetX - bone.worldX) * radDeg - parentRotation;
|
||||
if (rotationIK > 180)
|
||||
rotationIK -= 360;
|
||||
else if (rotationIK < -180) rotationIK += 360;
|
||||
bone.updateWorldTransform(bone.x, bone.y, rotation + (rotationIK - rotation) * alpha, bone.scaleX, bone.scaleY);
|
||||
}
|
||||
|
||||
/** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The
|
||||
* target is specified in the world coordinate system.
|
||||
* @param child Any descendant bone of the parent. */
|
||||
static public void apply (Bone parent, Bone child, float targetX, float targetY, int bendDirection, float alpha) {
|
||||
float childRotation = child.rotation, parentRotation = parent.rotation;
|
||||
if (alpha == 0) {
|
||||
child.rotationIK = childRotation;
|
||||
parent.rotationIK = parentRotation;
|
||||
return;
|
||||
}
|
||||
Vector2 position = temp;
|
||||
Bone parentParent = parent.parent;
|
||||
if (parentParent != null) {
|
||||
parentParent.worldToLocal(position.set(targetX, targetY));
|
||||
targetX = (position.x - parent.x) * parentParent.worldScaleX;
|
||||
targetY = (position.y - parent.y) * parentParent.worldScaleY;
|
||||
static public void apply (Bone parent, Bone child, float targetX, float targetY, int bendDir, float alpha) {
|
||||
if (alpha == 0) return;
|
||||
float px = parent.x, py = parent.y, psx = parent.scaleX, psy = parent.scaleY, csx = child.scaleX, cy = child.y;
|
||||
int offset1, offset2, sign2;
|
||||
if (psx < 0) {
|
||||
psx = -psx;
|
||||
offset1 = 180;
|
||||
sign2 = -1;
|
||||
} else {
|
||||
targetX -= parent.x;
|
||||
targetY -= parent.y;
|
||||
offset1 = 0;
|
||||
sign2 = 1;
|
||||
}
|
||||
if (child.parent == parent)
|
||||
position.set(child.x, child.y);
|
||||
else
|
||||
parent.worldToLocal(child.parent.localToWorld(position.set(child.x, child.y)));
|
||||
float childX = position.x * parent.worldScaleX, childY = position.y * parent.worldScaleY;
|
||||
float offset = (float)Math.atan2(childY, childX);
|
||||
float len1 = (float)Math.sqrt(childX * childX + childY * childY), len2 = child.data.length * child.worldScaleX;
|
||||
// Based on code by Ryan Juckett with permission: Copyright (c) 2008-2009 Ryan Juckett, http://www.ryanjuckett.com/
|
||||
float cosDenom = 2 * len1 * len2;
|
||||
if (cosDenom < 0.0001f) {
|
||||
child.rotationIK = childRotation + ((float)Math.atan2(targetY, targetX) * radDeg - parentRotation - childRotation)
|
||||
* alpha;
|
||||
return;
|
||||
if (psy < 0) {
|
||||
psy = -psy;
|
||||
sign2 = -sign2;
|
||||
}
|
||||
float cos = clamp((targetX * targetX + targetY * targetY - len1 * len1 - len2 * len2) / cosDenom, -1, 1);
|
||||
float childAngle = (float)Math.acos(cos) * bendDirection;
|
||||
float adjacent = len1 + len2 * cos, opposite = len2 * sin(childAngle);
|
||||
float parentAngle = (float)Math.atan2(targetY * adjacent - targetX * opposite, targetX * adjacent + targetY * opposite);
|
||||
float rotation = (parentAngle - offset) * radDeg - parentRotation;
|
||||
if (rotation > 180)
|
||||
rotation -= 360;
|
||||
else if (rotation < -180) //
|
||||
rotation += 360;
|
||||
parent.rotationIK = parentRotation + rotation * alpha;
|
||||
rotation = (childAngle + offset) * radDeg - childRotation;
|
||||
if (rotation > 180)
|
||||
rotation -= 360;
|
||||
else if (rotation < -180) //
|
||||
rotation += 360;
|
||||
child.rotationIK = childRotation + (rotation + parent.worldRotation - child.parent.worldRotation) * alpha;
|
||||
if (csx < 0) {
|
||||
csx = -csx;
|
||||
offset2 = 180;
|
||||
} else
|
||||
offset2 = 0;
|
||||
Bone pp = parent.parent;
|
||||
float tx, ty, dx, dy;
|
||||
if (pp == null) {
|
||||
tx = targetX - px;
|
||||
ty = targetY - py;
|
||||
dx = child.worldX - px;
|
||||
dy = child.worldY - py;
|
||||
} else {
|
||||
float a = pp.a, b = pp.b, c = pp.c, d = pp.d, invDet = 1 / (a * d - b * c);
|
||||
float wx = pp.worldX, wy = pp.worldY, x = targetX - wx, y = targetY - wy;
|
||||
tx = (x * d - y * b) * invDet - px;
|
||||
ty = (y * a - x * c) * invDet - py;
|
||||
x = child.worldX - wx;
|
||||
y = child.worldY - wy;
|
||||
dx = (x * d - y * b) * invDet - px;
|
||||
dy = (y * a - x * c) * invDet - py;
|
||||
}
|
||||
float l1 = (float)Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2;
|
||||
outer:
|
||||
if (Math.abs(psx - psy) <= 0.0001f) {
|
||||
l2 *= psx;
|
||||
float cos = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2);
|
||||
if (cos < -1)
|
||||
cos = -1;
|
||||
else if (cos > 1) cos = 1;
|
||||
a2 = (float)Math.acos(cos) * bendDir;
|
||||
float a = l1 + l2 * cos, o = l2 * sin(a2);
|
||||
a1 = atan2(ty * a - tx * o, tx * a + ty * o);
|
||||
} else {
|
||||
cy = 0;
|
||||
float a = psx * l2, b = psy * l2, ta = atan2(ty, tx);
|
||||
float aa = a * a, bb = b * b, ll = l1 * l1, dd = tx * tx + ty * ty;
|
||||
float c0 = bb * ll + aa * dd - aa * bb, c1 = -2 * bb * l1, c2 = bb - aa;
|
||||
float d = c1 * c1 - 4 * c2 * c0;
|
||||
if (d >= 0) {
|
||||
float q = (float)Math.sqrt(d);
|
||||
if (c1 < 0) q = -q;
|
||||
q = -(c1 + q) / 2;
|
||||
float r0 = q / c2, r1 = c0 / q;
|
||||
float r = Math.abs(r0) < Math.abs(r1) ? r0 : r1;
|
||||
if (r * r <= dd) {
|
||||
float y = (float)Math.sqrt(dd - r * r) * bendDir;
|
||||
a1 = ta - atan2(y, r);
|
||||
a2 = atan2(y / psy, (r - l1) / psx);
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
float minAngle = 0, minDist = Float.MAX_VALUE, minX = 0, minY = 0;
|
||||
float maxAngle = 0, maxDist = 0, maxX = 0, maxY = 0;
|
||||
float x = l1 + a, dist = x * x;
|
||||
if (dist > maxDist) {
|
||||
maxAngle = 0;
|
||||
maxDist = dist;
|
||||
maxX = x;
|
||||
}
|
||||
x = l1 - a;
|
||||
dist = x * x;
|
||||
if (dist < minDist) {
|
||||
minAngle = PI;
|
||||
minDist = dist;
|
||||
minX = x;
|
||||
}
|
||||
float angle = (float)Math.acos(-a * l1 / (aa - bb));
|
||||
x = a * cos(angle) + l1;
|
||||
float y = b * sin(angle);
|
||||
dist = x * x + y * y;
|
||||
if (dist < minDist) {
|
||||
minAngle = angle;
|
||||
minDist = dist;
|
||||
minX = x;
|
||||
minY = y;
|
||||
}
|
||||
if (dist > maxDist) {
|
||||
maxAngle = angle;
|
||||
maxDist = dist;
|
||||
maxX = x;
|
||||
maxY = y;
|
||||
}
|
||||
if (dd <= (minDist + maxDist) / 2) {
|
||||
a1 = ta - atan2(minY * bendDir, minX);
|
||||
a2 = minAngle * bendDir;
|
||||
} else {
|
||||
a1 = ta - atan2(maxY * bendDir, maxX);
|
||||
a2 = maxAngle * bendDir;
|
||||
}
|
||||
}
|
||||
float offset = atan2(cy, child.x) * sign2;
|
||||
a1 = (a1 - offset) * radDeg + offset1;
|
||||
a2 = (a2 + offset) * radDeg * sign2 + offset2;
|
||||
if (a1 > 180)
|
||||
a1 -= 360;
|
||||
else if (a1 < -180) a1 += 360;
|
||||
if (a2 > 180)
|
||||
a2 -= 360;
|
||||
else if (a2 < -180) a2 += 360;
|
||||
float rotation = parent.rotation;
|
||||
parent.updateWorldTransform(parent.x, parent.y, rotation + (a1 - rotation) * alpha, parent.scaleX, parent.scaleY);
|
||||
rotation = child.rotation;
|
||||
child.updateWorldTransform(child.x, cy, rotation + (a2 - rotation) * alpha, child.scaleX, child.scaleY);
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +45,8 @@ public class Skeleton {
|
||||
final Array<Slot> slots;
|
||||
Array<Slot> drawOrder;
|
||||
final Array<IkConstraint> ikConstraints;
|
||||
private final Array<Array<Bone>> boneCache = new Array();
|
||||
final Array<TransformConstraint> transformConstraints;
|
||||
private final Array<Updatable> updateCache = new Array();
|
||||
Skin skin;
|
||||
final Color color;
|
||||
float time;
|
||||
@ -75,6 +76,10 @@ public class Skeleton {
|
||||
for (IkConstraintData ikConstraintData : data.ikConstraints)
|
||||
ikConstraints.add(new IkConstraint(ikConstraintData, this));
|
||||
|
||||
transformConstraints = new Array(data.transformConstraints.size);
|
||||
for (TransformConstraintData transformConstraintData : data.transformConstraints)
|
||||
transformConstraints.add(new TransformConstraint(transformConstraintData, this));
|
||||
|
||||
color = new Color(1, 1, 1, 1);
|
||||
|
||||
updateCache();
|
||||
@ -102,13 +107,12 @@ public class Skeleton {
|
||||
drawOrder.add(slots.get(skeleton.slots.indexOf(slot, true)));
|
||||
|
||||
ikConstraints = new Array(skeleton.ikConstraints.size);
|
||||
for (IkConstraint ikConstraint : skeleton.ikConstraints) {
|
||||
Bone target = bones.get(skeleton.bones.indexOf(ikConstraint.target, true));
|
||||
Array<Bone> ikBones = new Array(ikConstraint.bones.size);
|
||||
for (Bone bone : ikConstraint.bones)
|
||||
ikBones.add(bones.get(skeleton.bones.indexOf(bone, true)));
|
||||
ikConstraints.add(new IkConstraint(ikConstraint, ikBones, target));
|
||||
}
|
||||
for (IkConstraint ikConstraint : skeleton.ikConstraints)
|
||||
ikConstraints.add(new IkConstraint(ikConstraint, this));
|
||||
|
||||
transformConstraints = new Array(skeleton.transformConstraints.size);
|
||||
for (TransformConstraint transformConstraint : skeleton.transformConstraints)
|
||||
transformConstraints.add(new TransformConstraint(transformConstraint, this));
|
||||
|
||||
skin = skeleton.skin;
|
||||
color = new Color(skeleton.color);
|
||||
@ -119,72 +123,49 @@ public class Skeleton {
|
||||
updateCache();
|
||||
}
|
||||
|
||||
/** Caches information about bones and IK constraints. Must be called if bones or IK constraints are added or removed. */
|
||||
/** Caches information about bones and constraints. Must be called if bones or constraints are added or removed. */
|
||||
public void updateCache () {
|
||||
Array<Bone> bones = this.bones;
|
||||
Array<Array<Bone>> boneCache = this.boneCache;
|
||||
Array<Updatable> updateCache = this.updateCache;
|
||||
Array<IkConstraint> ikConstraints = this.ikConstraints;
|
||||
Array<TransformConstraint> transformConstraints = this.transformConstraints;
|
||||
int ikConstraintsCount = ikConstraints.size;
|
||||
|
||||
int arrayCount = ikConstraintsCount + 1;
|
||||
while (boneCache.size < arrayCount)
|
||||
boneCache.add(new Array());
|
||||
for (int i = 0; i < arrayCount; i++)
|
||||
boneCache.get(i).clear();
|
||||
|
||||
Array<Bone> nonIkBones = boneCache.first();
|
||||
|
||||
outer:
|
||||
int transformConstraintsCount = transformConstraints.size;
|
||||
updateCache.clear();
|
||||
for (int i = 0, n = bones.size; i < n; i++) {
|
||||
Bone bone = bones.get(i);
|
||||
Bone current = bone;
|
||||
do {
|
||||
updateCache.add(bone);
|
||||
for (int ii = 0; ii < transformConstraintsCount; ii++) {
|
||||
TransformConstraint transformConstraint = transformConstraints.get(ii);
|
||||
if (bone == transformConstraint.bone) {
|
||||
updateCache.add(transformConstraint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int ii = 0; ii < ikConstraintsCount; ii++) {
|
||||
IkConstraint ikConstraint = ikConstraints.get(ii);
|
||||
Bone parent = ikConstraint.bones.first();
|
||||
Bone child = ikConstraint.bones.peek();
|
||||
while (true) {
|
||||
if (current == child) {
|
||||
boneCache.get(ii).add(bone);
|
||||
boneCache.get(ii + 1).add(bone);
|
||||
continue outer;
|
||||
}
|
||||
if (child == parent) break;
|
||||
child = child.parent;
|
||||
if (bone == ikConstraint.bones.peek()) {
|
||||
updateCache.add(ikConstraint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
current = current.parent;
|
||||
} while (current != null);
|
||||
nonIkBones.add(bone);
|
||||
}
|
||||
}
|
||||
|
||||
/** Updates the world transform for each bone and applies IK constraints. */
|
||||
/** Updates the world transform for each bone and applies constraints. */
|
||||
public void updateWorldTransform () {
|
||||
Array<Bone> bones = this.bones;
|
||||
for (int i = 0, nn = bones.size; i < nn; i++) {
|
||||
Bone bone = bones.get(i);
|
||||
bone.rotationIK = bone.rotation;
|
||||
}
|
||||
Array<Array<Bone>> boneCache = this.boneCache;
|
||||
Array<IkConstraint> ikConstraints = this.ikConstraints;
|
||||
int i = 0, last = ikConstraints.size;
|
||||
while (true) {
|
||||
Array<Bone> updateBones = boneCache.get(i);
|
||||
for (int ii = 0, nn = updateBones.size; ii < nn; ii++)
|
||||
updateBones.get(ii).updateWorldTransform();
|
||||
if (i == last) break;
|
||||
ikConstraints.get(i).apply();
|
||||
i++;
|
||||
}
|
||||
Array<Updatable> updateCache = this.updateCache;
|
||||
for (int i = 0, n = updateCache.size; i < n; i++)
|
||||
updateCache.get(i).update();
|
||||
}
|
||||
|
||||
/** Sets the bones and slots to their setup pose values. */
|
||||
/** Sets the bones, constraints, and slots to their setup pose values. */
|
||||
public void setToSetupPose () {
|
||||
setBonesToSetupPose();
|
||||
setSlotsToSetupPose();
|
||||
}
|
||||
|
||||
/** Sets the bones and constraints to their setup pose values. */
|
||||
public void setBonesToSetupPose () {
|
||||
Array<Bone> bones = this.bones;
|
||||
for (int i = 0, n = bones.size; i < n; i++)
|
||||
@ -192,9 +173,17 @@ public class Skeleton {
|
||||
|
||||
Array<IkConstraint> ikConstraints = this.ikConstraints;
|
||||
for (int i = 0, n = ikConstraints.size; i < n; i++) {
|
||||
IkConstraint ikConstraint = ikConstraints.get(i);
|
||||
ikConstraint.bendDirection = ikConstraint.data.bendDirection;
|
||||
ikConstraint.mix = ikConstraint.data.mix;
|
||||
IkConstraint constraint = ikConstraints.get(i);
|
||||
constraint.bendDirection = constraint.data.bendDirection;
|
||||
constraint.mix = constraint.data.mix;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -350,12 +339,27 @@ public class Skeleton {
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public IkConstraint findIkConstraint (String ikConstraintName) {
|
||||
if (ikConstraintName == null) throw new IllegalArgumentException("ikConstraintName cannot be null.");
|
||||
public IkConstraint findIkConstraint (String constraintName) {
|
||||
if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null.");
|
||||
Array<IkConstraint> ikConstraints = this.ikConstraints;
|
||||
for (int i = 0, n = ikConstraints.size; i < n; i++) {
|
||||
IkConstraint ikConstraint = ikConstraints.get(i);
|
||||
if (ikConstraint.data.name.equals(ikConstraintName)) return ikConstraint;
|
||||
if (ikConstraint.data.name.equals(constraintName)) return ikConstraint;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Array<TransformConstraint> getTransformConstraints () {
|
||||
return transformConstraints;
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public TransformConstraint findTransformConstraint (String constraintName) {
|
||||
if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null.");
|
||||
Array<TransformConstraint> transformConstraints = this.transformConstraints;
|
||||
for (int i = 0, n = transformConstraints.size; i < n; i++) {
|
||||
TransformConstraint constraint = transformConstraints.get(i);
|
||||
if (constraint.data.name.equals(constraintName)) return constraint;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -371,19 +375,13 @@ public class Skeleton {
|
||||
float[] vertices = null;
|
||||
Attachment attachment = slot.attachment;
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
RegionAttachment region = (RegionAttachment)attachment;
|
||||
region.updateWorldVertices(slot, false);
|
||||
vertices = region.getWorldVertices();
|
||||
vertices = ((RegionAttachment)attachment).updateWorldVertices(slot, false);
|
||||
|
||||
} else if (attachment instanceof MeshAttachment) {
|
||||
MeshAttachment mesh = (MeshAttachment)attachment;
|
||||
mesh.updateWorldVertices(slot, true);
|
||||
vertices = mesh.getWorldVertices();
|
||||
vertices = ((MeshAttachment)attachment).updateWorldVertices(slot, true);
|
||||
|
||||
} else if (attachment instanceof SkinnedMeshAttachment) {
|
||||
SkinnedMeshAttachment mesh = (SkinnedMeshAttachment)attachment;
|
||||
mesh.updateWorldVertices(slot, true);
|
||||
vertices = mesh.getWorldVertices();
|
||||
vertices = ((SkinnedMeshAttachment)attachment).updateWorldVertices(slot, true);
|
||||
}
|
||||
if (vertices != null) {
|
||||
for (int ii = 0, nn = vertices.length; ii < nn; ii += 5) {
|
||||
|
||||
@ -47,8 +47,6 @@ import com.esotericsoftware.spine.Animation.CurveTimeline;
|
||||
import com.esotericsoftware.spine.Animation.DrawOrderTimeline;
|
||||
import com.esotericsoftware.spine.Animation.EventTimeline;
|
||||
import com.esotericsoftware.spine.Animation.FfdTimeline;
|
||||
import com.esotericsoftware.spine.Animation.FlipXTimeline;
|
||||
import com.esotericsoftware.spine.Animation.FlipYTimeline;
|
||||
import com.esotericsoftware.spine.Animation.IkConstraintTimeline;
|
||||
import com.esotericsoftware.spine.Animation.RotateTimeline;
|
||||
import com.esotericsoftware.spine.Animation.ScaleTimeline;
|
||||
@ -69,8 +67,6 @@ public class SkeletonBinary {
|
||||
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_FLIPX = 5;
|
||||
static public final int TIMELINE_FLIPY = 6;
|
||||
|
||||
static public final int CURVE_LINEAR = 0;
|
||||
static public final int CURVE_STEPPED = 1;
|
||||
@ -135,10 +131,6 @@ public class SkeletonBinary {
|
||||
boneData.scaleY = input.readFloat();
|
||||
boneData.rotation = input.readFloat();
|
||||
boneData.length = input.readFloat() * scale;
|
||||
boneData.flipX = input.readBoolean();
|
||||
boneData.flipY = input.readBoolean();
|
||||
boneData.inheritScale = input.readBoolean();
|
||||
boneData.inheritRotation = input.readBoolean();
|
||||
if (nonessential) Color.rgba8888ToColor(boneData.color, input.readInt());
|
||||
skeletonData.bones.add(boneData);
|
||||
}
|
||||
@ -419,17 +411,6 @@ public class SkeletonBinary {
|
||||
duration = Math.max(duration, timeline.getFrames()[frameCount * 3 - 3]);
|
||||
break;
|
||||
}
|
||||
case TIMELINE_FLIPX:
|
||||
case TIMELINE_FLIPY: {
|
||||
FlipXTimeline timeline = timelineType == TIMELINE_FLIPX ? new FlipXTimeline(frameCount) : new FlipYTimeline(
|
||||
frameCount);
|
||||
timeline.boneIndex = boneIndex;
|
||||
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
|
||||
timeline.setFrame(frameIndex, input.readFloat(), input.readBoolean());
|
||||
timelines.add(timeline);
|
||||
duration = Math.max(duration, timeline.getFrames()[frameCount * 2 - 2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,6 +42,7 @@ public class SkeletonData {
|
||||
final Array<EventData> events = new Array();
|
||||
final Array<Animation> animations = new Array();
|
||||
final Array<IkConstraintData> ikConstraints = new Array();
|
||||
final Array<TransformConstraintData> transformConstraints = new Array();
|
||||
float width, height;
|
||||
String version, hash, imagesPath;
|
||||
|
||||
@ -153,19 +154,36 @@ public class SkeletonData {
|
||||
return null;
|
||||
}
|
||||
|
||||
// --- IK
|
||||
// --- IK constraints
|
||||
|
||||
public Array<IkConstraintData> getIkConstraints () {
|
||||
return ikConstraints;
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public IkConstraintData findIkConstraint (String ikConstraintName) {
|
||||
if (ikConstraintName == null) throw new IllegalArgumentException("ikConstraintName cannot be null.");
|
||||
public IkConstraintData findIkConstraint (String constraintName) {
|
||||
if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null.");
|
||||
Array<IkConstraintData> ikConstraints = this.ikConstraints;
|
||||
for (int i = 0, n = ikConstraints.size; i < n; i++) {
|
||||
IkConstraintData ikConstraint = ikConstraints.get(i);
|
||||
if (ikConstraint.name.equals(ikConstraintName)) return ikConstraint;
|
||||
IkConstraintData constraint = ikConstraints.get(i);
|
||||
if (constraint.name.equals(constraintName)) return constraint;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// --- Transform constraints
|
||||
|
||||
public Array<TransformConstraintData> getTransformConstraints () {
|
||||
return transformConstraints;
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public TransformConstraintData findTransformConstraint (String constraintName) {
|
||||
if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null.");
|
||||
Array<TransformConstraintData> transformConstraints = this.transformConstraints;
|
||||
for (int i = 0, n = transformConstraints.size; i < n; i++) {
|
||||
TransformConstraintData constraint = transformConstraints.get(i);
|
||||
if (constraint.name.equals(constraintName)) return constraint;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -46,8 +46,6 @@ import com.esotericsoftware.spine.Animation.CurveTimeline;
|
||||
import com.esotericsoftware.spine.Animation.DrawOrderTimeline;
|
||||
import com.esotericsoftware.spine.Animation.EventTimeline;
|
||||
import com.esotericsoftware.spine.Animation.FfdTimeline;
|
||||
import com.esotericsoftware.spine.Animation.FlipXTimeline;
|
||||
import com.esotericsoftware.spine.Animation.FlipYTimeline;
|
||||
import com.esotericsoftware.spine.Animation.IkConstraintTimeline;
|
||||
import com.esotericsoftware.spine.Animation.RotateTimeline;
|
||||
import com.esotericsoftware.spine.Animation.ScaleTimeline;
|
||||
@ -118,10 +116,6 @@ public class SkeletonJson {
|
||||
boneData.rotation = boneMap.getFloat("rotation", 0);
|
||||
boneData.scaleX = boneMap.getFloat("scaleX", 1);
|
||||
boneData.scaleY = boneMap.getFloat("scaleY", 1);
|
||||
boneData.flipX = boneMap.getBoolean("flipX", false);
|
||||
boneData.flipY = boneMap.getBoolean("flipY", false);
|
||||
boneData.inheritScale = boneMap.getBoolean("inheritScale", true);
|
||||
boneData.inheritRotation = boneMap.getBoolean("inheritRotation", true);
|
||||
|
||||
String color = boneMap.getString("color", null);
|
||||
if (color != null) boneData.getColor().set(Color.valueOf(color));
|
||||
@ -389,20 +383,6 @@ public class SkeletonJson {
|
||||
timelines.add(timeline);
|
||||
duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() * 3 - 3]);
|
||||
|
||||
} else if (timelineName.equals("flipX") || timelineName.equals("flipY")) {
|
||||
boolean x = timelineName.equals("flipX");
|
||||
FlipXTimeline timeline = x ? new FlipXTimeline(timelineMap.size) : new FlipYTimeline(timelineMap.size);
|
||||
timeline.boneIndex = boneIndex;
|
||||
|
||||
String field = x ? "x" : "y";
|
||||
int frameIndex = 0;
|
||||
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) {
|
||||
timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getBoolean(field, false));
|
||||
frameIndex++;
|
||||
}
|
||||
timelines.add(timeline);
|
||||
duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() * 2 - 2]);
|
||||
|
||||
} else
|
||||
throw new RuntimeException("Invalid timeline type for a bone: " + timelineName + " (" + boneMap.name + ")");
|
||||
}
|
||||
|
||||
@ -0,0 +1,108 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes Software License
|
||||
* Version 2.3
|
||||
*
|
||||
* Copyright (c) 2013-2015, Esoteric Software
|
||||
* All rights reserved.
|
||||
*
|
||||
* You are granted a perpetual, non-exclusive, non-sublicensable and
|
||||
* non-transferable license to use, install, execute and perform the Spine
|
||||
* Runtimes Software (the "Software") and derivative works solely for personal
|
||||
* or internal use. Without the written permission of Esoteric Software (see
|
||||
* Section 2 of the Spine Software License Agreement), you may not (a) modify,
|
||||
* translate, adapt or otherwise create derivative works, improvements of the
|
||||
* Software or develop new applications using the Software or (b) remove,
|
||||
* delete, alter or obscure any trademarks or any copyright, trademark, patent
|
||||
* or other intellectual property or proprietary rights notices on or in the
|
||||
* Software, including any copy thereof. Redistributions in binary or source
|
||||
* form must include this license and terms.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
package com.esotericsoftware.spine;
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.esotericsoftware.spine.attachments.Attachment;
|
||||
import com.esotericsoftware.spine.attachments.MeshAttachment;
|
||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||
import com.esotericsoftware.spine.attachments.SkeletonAttachment;
|
||||
import com.esotericsoftware.spine.attachments.SkinnedMeshAttachment;
|
||||
|
||||
public class SkeletonMeshRenderer extends SkeletonRenderer<PolygonSpriteBatch> {
|
||||
static private final short[] quadTriangles = {0, 1, 2, 2, 3, 0};
|
||||
|
||||
@SuppressWarnings("null")
|
||||
public void draw (PolygonSpriteBatch batch, Skeleton skeleton) {
|
||||
boolean premultipliedAlpha = this.premultipliedAlpha;
|
||||
BlendMode blendMode = null;
|
||||
|
||||
float[] vertices = null;
|
||||
short[] triangles = null;
|
||||
Array<Slot> drawOrder = skeleton.drawOrder;
|
||||
for (int i = 0, n = drawOrder.size; i < n; i++) {
|
||||
Slot slot = drawOrder.get(i);
|
||||
Attachment attachment = slot.attachment;
|
||||
Texture texture = null;
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
RegionAttachment region = (RegionAttachment)attachment;
|
||||
vertices = region.updateWorldVertices(slot, premultipliedAlpha);
|
||||
triangles = quadTriangles;
|
||||
texture = region.getRegion().getTexture();
|
||||
|
||||
} else if (attachment instanceof MeshAttachment) {
|
||||
MeshAttachment mesh = (MeshAttachment)attachment;
|
||||
vertices = mesh.updateWorldVertices(slot, premultipliedAlpha);
|
||||
triangles = mesh.getTriangles();
|
||||
texture = mesh.getRegion().getTexture();
|
||||
|
||||
} else if (attachment instanceof SkinnedMeshAttachment) {
|
||||
SkinnedMeshAttachment mesh = (SkinnedMeshAttachment)attachment;
|
||||
vertices = mesh.updateWorldVertices(slot, premultipliedAlpha);
|
||||
triangles = mesh.getTriangles();
|
||||
texture = mesh.getRegion().getTexture();
|
||||
|
||||
} else if (attachment instanceof SkeletonAttachment) {
|
||||
Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton();
|
||||
if (attachmentSkeleton == null) continue;
|
||||
Bone bone = slot.getBone();
|
||||
Bone rootBone = attachmentSkeleton.getRootBone();
|
||||
float oldScaleX = rootBone.getScaleX();
|
||||
float oldScaleY = rootBone.getScaleY();
|
||||
float oldRotation = rootBone.getRotation();
|
||||
attachmentSkeleton.setPosition(skeleton.getX() + bone.getWorldX(), skeleton.getY() + bone.getWorldY());
|
||||
// rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX);
|
||||
// rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY);
|
||||
rootBone.setRotation(oldRotation + bone.getWorldRotationX());
|
||||
attachmentSkeleton.updateWorldTransform();
|
||||
|
||||
draw(batch, attachmentSkeleton);
|
||||
|
||||
attachmentSkeleton.setPosition(0, 0);
|
||||
rootBone.setScaleX(oldScaleX);
|
||||
rootBone.setScaleY(oldScaleY);
|
||||
rootBone.setRotation(oldRotation);
|
||||
}
|
||||
|
||||
if (texture != null) {
|
||||
BlendMode slotBlendMode = slot.data.getBlendMode();
|
||||
if (slotBlendMode != blendMode) {
|
||||
blendMode = slotBlendMode;
|
||||
batch.setBlendFunction(blendMode.getSource(premultipliedAlpha), blendMode.getDest());
|
||||
}
|
||||
batch.draw(texture, vertices, 0, vertices.length, triangles, 0, triangles.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -31,9 +31,7 @@
|
||||
|
||||
package com.esotericsoftware.spine;
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.esotericsoftware.spine.attachments.Attachment;
|
||||
import com.esotericsoftware.spine.attachments.MeshAttachment;
|
||||
@ -41,78 +39,14 @@ import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||
import com.esotericsoftware.spine.attachments.SkeletonAttachment;
|
||||
import com.esotericsoftware.spine.attachments.SkinnedMeshAttachment;
|
||||
|
||||
public class SkeletonRenderer {
|
||||
static private final short[] quadTriangles = {0, 1, 2, 2, 3, 0};
|
||||
public class SkeletonRenderer<T extends Batch> {
|
||||
boolean premultipliedAlpha;
|
||||
|
||||
private boolean premultipliedAlpha;
|
||||
|
||||
@SuppressWarnings("null")
|
||||
public void draw (PolygonSpriteBatch batch, Skeleton skeleton) {
|
||||
boolean premultipliedAlpha = this.premultipliedAlpha;
|
||||
BlendMode blendMode = null;
|
||||
|
||||
float[] vertices = null;
|
||||
short[] triangles = null;
|
||||
Array<Slot> drawOrder = skeleton.drawOrder;
|
||||
for (int i = 0, n = drawOrder.size; i < n; i++) {
|
||||
Slot slot = drawOrder.get(i);
|
||||
Attachment attachment = slot.attachment;
|
||||
Texture texture = null;
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
RegionAttachment region = (RegionAttachment)attachment;
|
||||
region.updateWorldVertices(slot, premultipliedAlpha);
|
||||
vertices = region.getWorldVertices();
|
||||
triangles = quadTriangles;
|
||||
texture = region.getRegion().getTexture();
|
||||
|
||||
} else if (attachment instanceof MeshAttachment) {
|
||||
MeshAttachment mesh = (MeshAttachment)attachment;
|
||||
mesh.updateWorldVertices(slot, premultipliedAlpha);
|
||||
vertices = mesh.getWorldVertices();
|
||||
triangles = mesh.getTriangles();
|
||||
texture = mesh.getRegion().getTexture();
|
||||
|
||||
} else if (attachment instanceof SkinnedMeshAttachment) {
|
||||
SkinnedMeshAttachment mesh = (SkinnedMeshAttachment)attachment;
|
||||
mesh.updateWorldVertices(slot, premultipliedAlpha);
|
||||
vertices = mesh.getWorldVertices();
|
||||
triangles = mesh.getTriangles();
|
||||
texture = mesh.getRegion().getTexture();
|
||||
|
||||
} else if (attachment instanceof SkeletonAttachment) {
|
||||
Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton();
|
||||
if (attachmentSkeleton == null) continue;
|
||||
Bone bone = slot.getBone();
|
||||
Bone rootBone = attachmentSkeleton.getRootBone();
|
||||
float oldScaleX = rootBone.getScaleX();
|
||||
float oldScaleY = rootBone.getScaleY();
|
||||
float oldRotation = rootBone.getRotation();
|
||||
attachmentSkeleton.setPosition(skeleton.getX() + bone.getWorldX(), skeleton.getY() + bone.getWorldY());
|
||||
rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX);
|
||||
rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY);
|
||||
rootBone.setRotation(oldRotation + bone.getWorldRotation());
|
||||
attachmentSkeleton.updateWorldTransform();
|
||||
|
||||
draw(batch, attachmentSkeleton);
|
||||
|
||||
attachmentSkeleton.setPosition(0, 0);
|
||||
rootBone.setScaleX(oldScaleX);
|
||||
rootBone.setScaleY(oldScaleY);
|
||||
rootBone.setRotation(oldRotation);
|
||||
public SkeletonRenderer () {
|
||||
super();
|
||||
}
|
||||
|
||||
if (texture != null) {
|
||||
BlendMode slotBlendMode = slot.data.getBlendMode();
|
||||
if (slotBlendMode != blendMode) {
|
||||
blendMode = slotBlendMode;
|
||||
batch.setBlendFunction(blendMode.getSource(premultipliedAlpha), blendMode.getDest());
|
||||
}
|
||||
batch.draw(texture, vertices, 0, vertices.length, triangles, 0, triangles.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void draw (Batch batch, Skeleton skeleton) {
|
||||
public void draw (T batch, Skeleton skeleton) {
|
||||
boolean premultipliedAlpha = this.premultipliedAlpha;
|
||||
BlendMode blendMode = null;
|
||||
|
||||
@ -122,8 +56,7 @@ public class SkeletonRenderer {
|
||||
Attachment attachment = slot.attachment;
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
RegionAttachment regionAttachment = (RegionAttachment)attachment;
|
||||
regionAttachment.updateWorldVertices(slot, premultipliedAlpha);
|
||||
float[] vertices = regionAttachment.getWorldVertices();
|
||||
float[] vertices = regionAttachment.updateWorldVertices(slot, premultipliedAlpha);
|
||||
BlendMode slotBlendMode = slot.data.getBlendMode();
|
||||
if (slotBlendMode != blendMode) {
|
||||
blendMode = slotBlendMode;
|
||||
@ -132,7 +65,7 @@ public class SkeletonRenderer {
|
||||
batch.draw(regionAttachment.getRegion().getTexture(), vertices, 0, 20);
|
||||
|
||||
} else if (attachment instanceof MeshAttachment || attachment instanceof SkinnedMeshAttachment) {
|
||||
throw new RuntimeException("PolygonSpriteBatch is required to render meshes.");
|
||||
throw new RuntimeException("SkeletonMeshRenderer is required to render meshes.");
|
||||
|
||||
} else if (attachment instanceof SkeletonAttachment) {
|
||||
Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton();
|
||||
@ -143,9 +76,9 @@ public class SkeletonRenderer {
|
||||
float oldScaleY = rootBone.getScaleY();
|
||||
float oldRotation = rootBone.getRotation();
|
||||
attachmentSkeleton.setPosition(skeleton.getX() + bone.getWorldX(), skeleton.getY() + bone.getWorldY());
|
||||
rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX);
|
||||
rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY);
|
||||
rootBone.setRotation(oldRotation + bone.getWorldRotation());
|
||||
// rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX);
|
||||
// rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY);
|
||||
rootBone.setRotation(oldRotation + bone.getWorldRotationX());
|
||||
attachmentSkeleton.updateWorldTransform();
|
||||
|
||||
draw(batch, attachmentSkeleton);
|
||||
|
||||
@ -87,8 +87,8 @@ public class SkeletonRendererDebug {
|
||||
for (int i = 0, n = bones.size; i < n; i++) {
|
||||
Bone bone = bones.get(i);
|
||||
if (bone.parent == null) continue;
|
||||
float x = skeletonX + bone.data.length * bone.m00 + bone.worldX;
|
||||
float y = skeletonY + bone.data.length * bone.m10 + bone.worldY;
|
||||
float x = skeletonX + bone.data.length * bone.a + bone.worldX;
|
||||
float y = skeletonY + bone.data.length * bone.c + bone.worldY;
|
||||
shapes.rectLine(skeletonX + bone.worldX, skeletonY + bone.worldY, x, y, boneWidth * scale);
|
||||
}
|
||||
shapes.end();
|
||||
@ -105,8 +105,7 @@ public class SkeletonRendererDebug {
|
||||
Attachment attachment = slot.attachment;
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
RegionAttachment regionAttachment = (RegionAttachment)attachment;
|
||||
regionAttachment.updateWorldVertices(slot, false);
|
||||
float[] vertices = regionAttachment.getWorldVertices();
|
||||
float[] vertices = regionAttachment.updateWorldVertices(slot, false);
|
||||
shapes.line(vertices[X1], vertices[Y1], vertices[X2], vertices[Y2]);
|
||||
shapes.line(vertices[X2], vertices[Y2], vertices[X3], vertices[Y3]);
|
||||
shapes.line(vertices[X3], vertices[Y3], vertices[X4], vertices[Y4]);
|
||||
|
||||
@ -0,0 +1,76 @@
|
||||
|
||||
package com.esotericsoftware.spine;
|
||||
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
|
||||
public class TransformConstraint implements Updatable {
|
||||
final TransformConstraintData data;
|
||||
Bone bone, target;
|
||||
float translateMix, x, y;
|
||||
final Vector2 temp = new Vector2();
|
||||
|
||||
public TransformConstraint (TransformConstraintData data, Skeleton skeleton) {
|
||||
this.data = data;
|
||||
translateMix = data.translateMix;
|
||||
|
||||
if (skeleton != null) {
|
||||
bone = skeleton.findBone(data.bone.name);
|
||||
target = skeleton.findBone(data.target.name);
|
||||
}
|
||||
}
|
||||
|
||||
/** Copy constructor. */
|
||||
public TransformConstraint (TransformConstraint constraint, Skeleton skeleton) {
|
||||
data = constraint.data;
|
||||
translateMix = data.translateMix;
|
||||
bone = skeleton.bones.get(constraint.bone.skeleton.bones.indexOf(constraint.target, true));
|
||||
target = skeleton.bones.get(constraint.target.skeleton.bones.indexOf(constraint.target, true));
|
||||
}
|
||||
|
||||
public void apply () {
|
||||
update();
|
||||
}
|
||||
|
||||
public void update () {
|
||||
float translateMix = this.translateMix;
|
||||
if (translateMix > 0) {
|
||||
Bone bone = this.bone;
|
||||
Vector2 temp = this.temp;
|
||||
target.localToWorld(temp.set(x, y));
|
||||
bone.worldX += (temp.x - bone.worldX) * translateMix;
|
||||
bone.worldY += (temp.y - bone.worldY) * translateMix;
|
||||
}
|
||||
}
|
||||
|
||||
public Bone getBone () {
|
||||
return bone;
|
||||
}
|
||||
|
||||
public void setBone (Bone bone) {
|
||||
this.bone = bone;
|
||||
}
|
||||
|
||||
public Bone getTarget () {
|
||||
return target;
|
||||
}
|
||||
|
||||
public void setTarget (Bone target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public float getTranslateMix () {
|
||||
return translateMix;
|
||||
}
|
||||
|
||||
public void setTranslateMix (float translateMix) {
|
||||
this.translateMix = translateMix;
|
||||
}
|
||||
|
||||
public TransformConstraintData getData () {
|
||||
return data;
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
return data.name;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
|
||||
package com.esotericsoftware.spine;
|
||||
|
||||
public class TransformConstraintData {
|
||||
final String name;
|
||||
BoneData bone, target;
|
||||
float translateMix;
|
||||
float x, y;
|
||||
|
||||
public TransformConstraintData (String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName () {
|
||||
return name;
|
||||
}
|
||||
|
||||
public BoneData getBone () {
|
||||
return bone;
|
||||
}
|
||||
|
||||
public void setBone (BoneData bone) {
|
||||
this.bone = bone;
|
||||
}
|
||||
|
||||
public BoneData getTarget () {
|
||||
return target;
|
||||
}
|
||||
|
||||
public void setTarget (BoneData target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public float getTranslateMix () {
|
||||
return translateMix;
|
||||
}
|
||||
|
||||
public void setTranslateMix (float translateMix) {
|
||||
this.translateMix = translateMix;
|
||||
}
|
||||
|
||||
public float getX () {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX (float x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public float getY () {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY (float y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
|
||||
package com.esotericsoftware.spine;
|
||||
|
||||
public interface Updatable {
|
||||
public void update ();
|
||||
}
|
||||
@ -44,10 +44,10 @@ public class BoundingBoxAttachment extends Attachment {
|
||||
public void computeWorldVertices (Bone bone, float[] worldVertices) {
|
||||
Skeleton skeleton = bone.getSkeleton();
|
||||
float x = skeleton.getX() + bone.getWorldX(), y = skeleton.getY() + bone.getWorldY();
|
||||
float m00 = bone.getM00();
|
||||
float m01 = bone.getM01();
|
||||
float m10 = bone.getM10();
|
||||
float m11 = bone.getM11();
|
||||
float m00 = bone.getA();
|
||||
float m01 = bone.getB();
|
||||
float m10 = bone.getC();
|
||||
float m11 = bone.getD();
|
||||
float[] vertices = this.vertices;
|
||||
for (int i = 0, n = vertices.length; i < n; i += 2) {
|
||||
float px = vertices[i];
|
||||
|
||||
@ -98,7 +98,8 @@ public class MeshAttachment extends Attachment {
|
||||
}
|
||||
}
|
||||
|
||||
public void updateWorldVertices (Slot slot, boolean premultipliedAlpha) {
|
||||
/** @return The updated world vertices. */
|
||||
public float[] updateWorldVertices (Slot slot, boolean premultipliedAlpha) {
|
||||
Skeleton skeleton = slot.getSkeleton();
|
||||
Color skeletonColor = skeleton.getColor();
|
||||
Color slotColor = slot.getColor();
|
||||
@ -117,7 +118,7 @@ public class MeshAttachment extends Attachment {
|
||||
if (slotVertices.size == vertices.length) vertices = slotVertices.items;
|
||||
Bone bone = slot.getBone();
|
||||
float x = skeleton.getX() + bone.getWorldX(), y = skeleton.getY() + bone.getWorldY();
|
||||
float m00 = bone.getM00(), m01 = bone.getM01(), m10 = bone.getM10(), m11 = bone.getM11();
|
||||
float m00 = bone.getA(), m01 = bone.getB(), m10 = bone.getC(), m11 = bone.getD();
|
||||
for (int v = 0, w = 0, n = worldVertices.length; w < n; v += 2, w += 5) {
|
||||
float vx = vertices[v];
|
||||
float vy = vertices[v + 1];
|
||||
@ -125,6 +126,7 @@ public class MeshAttachment extends Attachment {
|
||||
worldVertices[w + 1] = vx * m10 + vy * m11 + y;
|
||||
worldVertices[w + 2] = color;
|
||||
}
|
||||
return worldVertices;
|
||||
}
|
||||
|
||||
public float[] getWorldVertices () {
|
||||
|
||||
@ -146,7 +146,8 @@ public class RegionAttachment extends Attachment {
|
||||
return region;
|
||||
}
|
||||
|
||||
public void updateWorldVertices (Slot slot, boolean premultipliedAlpha) {
|
||||
/** @return The updated world vertices. */
|
||||
public float[] updateWorldVertices (Slot slot, boolean premultipliedAlpha) {
|
||||
Skeleton skeleton = slot.getSkeleton();
|
||||
Color skeletonColor = skeleton.getColor();
|
||||
Color slotColor = slot.getColor();
|
||||
@ -163,7 +164,7 @@ public class RegionAttachment extends Attachment {
|
||||
float[] offset = this.offset;
|
||||
Bone bone = slot.getBone();
|
||||
float x = skeleton.getX() + bone.getWorldX(), y = skeleton.getY() + bone.getWorldY();
|
||||
float m00 = bone.getM00(), m01 = bone.getM01(), m10 = bone.getM10(), m11 = bone.getM11();
|
||||
float m00 = bone.getA(), m01 = bone.getB(), m10 = bone.getC(), m11 = bone.getD();
|
||||
float offsetX, offsetY;
|
||||
|
||||
offsetX = offset[BRX];
|
||||
@ -189,6 +190,7 @@ public class RegionAttachment extends Attachment {
|
||||
vertices[X4] = offsetX * m00 + offsetY * m01 + x; // ur
|
||||
vertices[Y4] = offsetX * m10 + offsetY * m11 + y;
|
||||
vertices[C4] = color;
|
||||
return vertices;
|
||||
}
|
||||
|
||||
public float[] getWorldVertices () {
|
||||
|
||||
@ -46,7 +46,7 @@ public class RegionSequenceAttachment extends RegionAttachment {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void updateWorldVertices (Slot slot, boolean premultipliedAlpha) {
|
||||
public float[] updateWorldVertices (Slot slot, boolean premultipliedAlpha) {
|
||||
if (regions == null) throw new IllegalStateException("Regions have not been set: " + this);
|
||||
|
||||
int frameIndex = (int)(slot.getAttachmentTime() / frameTime);
|
||||
@ -74,7 +74,7 @@ public class RegionSequenceAttachment extends RegionAttachment {
|
||||
}
|
||||
setRegion(regions[frameIndex]);
|
||||
|
||||
super.updateWorldVertices(slot, premultipliedAlpha);
|
||||
return super.updateWorldVertices(slot, premultipliedAlpha);
|
||||
}
|
||||
|
||||
public TextureRegion[] getRegions () {
|
||||
|
||||
@ -99,7 +99,8 @@ public class SkinnedMeshAttachment extends Attachment {
|
||||
}
|
||||
}
|
||||
|
||||
public void updateWorldVertices (Slot slot, boolean premultipliedAlpha) {
|
||||
/** @return The updated world vertices. */
|
||||
public float[] updateWorldVertices (Slot slot, boolean premultipliedAlpha) {
|
||||
Skeleton skeleton = slot.getSkeleton();
|
||||
Color skeletonColor = skeleton.getColor();
|
||||
Color meshColor = slot.getColor();
|
||||
@ -126,8 +127,8 @@ public class SkinnedMeshAttachment extends Attachment {
|
||||
for (; v < nn; v++, b += 3) {
|
||||
Bone bone = (Bone)skeletonBones[bones[v]];
|
||||
float vx = weights[b], vy = weights[b + 1], weight = weights[b + 2];
|
||||
wx += (vx * bone.getM00() + vy * bone.getM01() + bone.getWorldX()) * weight;
|
||||
wy += (vx * bone.getM10() + vy * bone.getM11() + bone.getWorldY()) * weight;
|
||||
wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight;
|
||||
wy += (vx * bone.getC() + vy * bone.getD() + bone.getWorldY()) * weight;
|
||||
}
|
||||
worldVertices[w] = wx + x;
|
||||
worldVertices[w + 1] = wy + y;
|
||||
@ -141,14 +142,15 @@ public class SkinnedMeshAttachment extends Attachment {
|
||||
for (; v < nn; v++, b += 3, f += 2) {
|
||||
Bone bone = (Bone)skeletonBones[bones[v]];
|
||||
float vx = weights[b] + ffd[f], vy = weights[b + 1] + ffd[f + 1], weight = weights[b + 2];
|
||||
wx += (vx * bone.getM00() + vy * bone.getM01() + bone.getWorldX()) * weight;
|
||||
wy += (vx * bone.getM10() + vy * bone.getM11() + bone.getWorldY()) * weight;
|
||||
wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight;
|
||||
wy += (vx * bone.getC() + vy * bone.getD() + bone.getWorldY()) * weight;
|
||||
}
|
||||
worldVertices[w] = wx + x;
|
||||
worldVertices[w + 1] = wy + y;
|
||||
worldVertices[w + 2] = color;
|
||||
}
|
||||
}
|
||||
return worldVertices;
|
||||
}
|
||||
|
||||
public float[] getWorldVertices () {
|
||||
|
||||
@ -0,0 +1,68 @@
|
||||
|
||||
package com.esotericsoftware.spine.utils;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
import com.badlogic.gdx.scenes.scene2d.Actor;
|
||||
import com.esotericsoftware.spine.AnimationState;
|
||||
import com.esotericsoftware.spine.Skeleton;
|
||||
import com.esotericsoftware.spine.SkeletonRenderer;
|
||||
|
||||
/** A scene2d actor that draws a skeleton. */
|
||||
public class SkeletonActor extends Actor {
|
||||
private SkeletonRenderer renderer;
|
||||
private Skeleton skeleton;
|
||||
AnimationState state;
|
||||
|
||||
/** Creates an uninitialized SkeletonActor. The renderer, skeleton, and animation state must be set before use. */
|
||||
public SkeletonActor () {
|
||||
}
|
||||
|
||||
public SkeletonActor (SkeletonRenderer renderer, Skeleton skeleton, AnimationState state) {
|
||||
this.renderer = renderer;
|
||||
this.skeleton = skeleton;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public void act (float delta) {
|
||||
state.update(delta);
|
||||
state.apply(skeleton);
|
||||
skeleton.updateWorldTransform();
|
||||
super.act(delta);
|
||||
}
|
||||
|
||||
public void draw (Batch batch, float parentAlpha) {
|
||||
Color color = skeleton.getColor();
|
||||
float oldAlpha = color.a;
|
||||
skeleton.getColor().a *= parentAlpha;
|
||||
|
||||
skeleton.setPosition(getX(), getY());
|
||||
renderer.draw(batch, skeleton);
|
||||
|
||||
color.a = oldAlpha;
|
||||
}
|
||||
|
||||
public SkeletonRenderer getRenderer () {
|
||||
return renderer;
|
||||
}
|
||||
|
||||
public void setRenderer (SkeletonRenderer renderer) {
|
||||
this.renderer = renderer;
|
||||
}
|
||||
|
||||
public Skeleton getSkeleton () {
|
||||
return skeleton;
|
||||
}
|
||||
|
||||
public void setSkeleton (Skeleton skeleton) {
|
||||
this.skeleton = skeleton;
|
||||
}
|
||||
|
||||
public AnimationState getAnimationState () {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setAnimationState (AnimationState state) {
|
||||
this.state = state;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,102 @@
|
||||
|
||||
package com.esotericsoftware.spine.utils;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Pool;
|
||||
import com.esotericsoftware.spine.AnimationState;
|
||||
import com.esotericsoftware.spine.AnimationState.TrackEntry;
|
||||
import com.esotericsoftware.spine.AnimationStateData;
|
||||
import com.esotericsoftware.spine.Skeleton;
|
||||
import com.esotericsoftware.spine.SkeletonData;
|
||||
import com.esotericsoftware.spine.SkeletonRenderer;
|
||||
import com.esotericsoftware.spine.Skin;
|
||||
|
||||
public class SkeletonActorPool extends Pool<SkeletonActor> {
|
||||
private SkeletonRenderer renderer;
|
||||
SkeletonData skeletonData;
|
||||
AnimationStateData stateData;
|
||||
private final Pool<Skeleton> skeletonPool;
|
||||
private final Pool<AnimationState> statePool;
|
||||
private final Array<SkeletonActor> obtained;
|
||||
|
||||
public SkeletonActorPool (SkeletonRenderer renderer, SkeletonData skeletonData, AnimationStateData stateData) {
|
||||
this(renderer, skeletonData, stateData, 16, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public SkeletonActorPool (SkeletonRenderer renderer, SkeletonData skeletonData, AnimationStateData stateData,
|
||||
int initialCapacity, int max) {
|
||||
super(initialCapacity, max);
|
||||
|
||||
this.renderer = renderer;
|
||||
this.skeletonData = skeletonData;
|
||||
this.stateData = stateData;
|
||||
|
||||
obtained = new Array(false, initialCapacity);
|
||||
|
||||
skeletonPool = new Pool<Skeleton>(initialCapacity, max) {
|
||||
protected Skeleton newObject () {
|
||||
return new Skeleton(SkeletonActorPool.this.skeletonData);
|
||||
}
|
||||
|
||||
protected void reset (Skeleton skeleton) {
|
||||
skeleton.setColor(Color.WHITE);
|
||||
skeleton.setFlip(false, false);
|
||||
skeleton.setSkin((Skin)null);
|
||||
skeleton.setSkin(SkeletonActorPool.this.skeletonData.getDefaultSkin());
|
||||
skeleton.setToSetupPose();
|
||||
}
|
||||
};
|
||||
|
||||
statePool = new Pool<AnimationState>(initialCapacity, max) {
|
||||
protected AnimationState newObject () {
|
||||
return new AnimationState(SkeletonActorPool.this.stateData);
|
||||
}
|
||||
|
||||
protected void reset (AnimationState state) {
|
||||
state.clearTracks();
|
||||
state.clearListeners();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Each obtained skeleton actor that is no longer playing an animation is removed from the stage and returned to the pool. */
|
||||
public void freeComplete () {
|
||||
Array<SkeletonActor> obtained = this.obtained;
|
||||
outer:
|
||||
for (int i = obtained.size - 1; i >= 0; i--) {
|
||||
SkeletonActor actor = obtained.get(i);
|
||||
Array<TrackEntry> tracks = actor.state.getTracks();
|
||||
for (int ii = 0, nn = tracks.size; ii < nn; ii++)
|
||||
if (tracks.get(ii) != null) continue outer;
|
||||
free(actor);
|
||||
}
|
||||
}
|
||||
|
||||
protected SkeletonActor newObject () {
|
||||
SkeletonActor actor = new SkeletonActor();
|
||||
actor.setRenderer(renderer);
|
||||
return actor;
|
||||
}
|
||||
|
||||
/** This pool keeps a reference to the obtained instance, so it should be returned to the pool via {@link #free(SkeletonActor)}
|
||||
* , {@link #freeAll(Array)}, or {@link #freeComplete()} to avoid leaking memory. */
|
||||
public SkeletonActor obtain () {
|
||||
SkeletonActor actor = super.obtain();
|
||||
actor.setSkeleton(skeletonPool.obtain());
|
||||
actor.setAnimationState(statePool.obtain());
|
||||
obtained.add(actor);
|
||||
return actor;
|
||||
}
|
||||
|
||||
protected void reset (SkeletonActor actor) {
|
||||
actor.remove();
|
||||
obtained.removeValue(actor, true);
|
||||
skeletonPool.free(actor.getSkeleton());
|
||||
statePool.free(actor.getAnimationState());
|
||||
}
|
||||
|
||||
public Array<SkeletonActor> getObtained () {
|
||||
return obtained;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
|
||||
package com.esotericsoftware.spine.utils;
|
||||
|
||||
import com.badlogic.gdx.utils.Pool;
|
||||
import com.esotericsoftware.spine.Skeleton;
|
||||
import com.esotericsoftware.spine.SkeletonData;
|
||||
|
||||
public class SkeletonPool extends Pool<Skeleton> {
|
||||
private SkeletonData skeletonData;
|
||||
|
||||
public SkeletonPool (SkeletonData skeletonData) {
|
||||
this.skeletonData = skeletonData;
|
||||
}
|
||||
|
||||
public SkeletonPool (SkeletonData skeletonData, int initialCapacity) {
|
||||
super(initialCapacity);
|
||||
this.skeletonData = skeletonData;
|
||||
}
|
||||
|
||||
public SkeletonPool (SkeletonData skeletonData, int initialCapacity, int max) {
|
||||
super(initialCapacity, max);
|
||||
this.skeletonData = skeletonData;
|
||||
}
|
||||
|
||||
protected Skeleton newObject () {
|
||||
return new Skeleton(skeletonData);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,206 @@
|
||||
info face="Calibri" size=-12 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=0 aa=1 padding=1,1,2,1 spacing=1,1 outline=0
|
||||
common lineHeight=14 base=11 scaleW=512 scaleH=512 pages=1 packed=0 alphaChnl=0 redChnl=4 greenChnl=4 blueChnl=4
|
||||
page id=0 file="font-calibri-12_0.png"
|
||||
chars count=95
|
||||
char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=0 xadvance=3 page=0 chnl=15
|
||||
char id=33 x=494 y=0 width=3 height=11 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=15
|
||||
char id=34 x=157 y=12 width=5 height=6 xoffset=0 yoffset=2 xadvance=5 page=0 chnl=15
|
||||
char id=35 x=162 y=0 width=8 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=36 x=16 y=0 width=6 height=13 xoffset=0 yoffset=1 xadvance=6 page=0 chnl=15
|
||||
char id=37 x=101 y=0 width=10 height=11 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=15
|
||||
char id=38 x=123 y=0 width=9 height=11 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=15
|
||||
char id=39 x=168 y=12 width=3 height=6 xoffset=0 yoffset=2 xadvance=3 page=0 chnl=15
|
||||
char id=40 x=51 y=0 width=4 height=13 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=15
|
||||
char id=41 x=41 y=0 width=4 height=13 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=15
|
||||
char id=42 x=117 y=12 width=7 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=43 x=109 y=12 width=7 height=8 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15
|
||||
char id=44 x=163 y=12 width=4 height=6 xoffset=-1 yoffset=9 xadvance=3 page=0 chnl=15
|
||||
char id=45 x=194 y=12 width=5 height=4 xoffset=-1 yoffset=6 xadvance=4 page=0 chnl=15
|
||||
char id=46 x=204 y=12 width=3 height=4 xoffset=0 yoffset=9 xadvance=3 page=0 chnl=15
|
||||
char id=47 x=0 y=0 width=7 height=14 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=15
|
||||
char id=48 x=362 y=0 width=7 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=49 x=370 y=0 width=7 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=50 x=402 y=0 width=7 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=51 x=410 y=0 width=7 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=52 x=234 y=0 width=7 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=53 x=242 y=0 width=7 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=54 x=330 y=0 width=7 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=55 x=258 y=0 width=7 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=56 x=266 y=0 width=7 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=57 x=274 y=0 width=7 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=58 x=105 y=12 width=3 height=9 xoffset=0 yoffset=4 xadvance=3 page=0 chnl=15
|
||||
char id=59 x=481 y=0 width=4 height=11 xoffset=-1 yoffset=4 xadvance=3 page=0 chnl=15
|
||||
char id=60 x=133 y=12 width=7 height=8 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15
|
||||
char id=61 x=149 y=12 width=7 height=6 xoffset=-1 yoffset=5 xadvance=6 page=0 chnl=15
|
||||
char id=62 x=125 y=12 width=7 height=8 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15
|
||||
char id=63 x=468 y=0 width=6 height=11 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=64 x=65 y=0 width=11 height=12 xoffset=0 yoffset=2 xadvance=11 page=0 chnl=15
|
||||
char id=65 x=143 y=0 width=9 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=15
|
||||
char id=66 x=290 y=0 width=7 height=11 xoffset=0 yoffset=2 xadvance=7 page=0 chnl=15
|
||||
char id=67 x=298 y=0 width=7 height=11 xoffset=0 yoffset=2 xadvance=7 page=0 chnl=15
|
||||
char id=68 x=171 y=0 width=8 height=11 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=15
|
||||
char id=69 x=461 y=0 width=6 height=11 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=70 x=433 y=0 width=6 height=11 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=71 x=180 y=0 width=8 height=11 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=15
|
||||
char id=72 x=216 y=0 width=8 height=11 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=15
|
||||
char id=73 x=498 y=0 width=3 height=11 xoffset=0 yoffset=2 xadvance=3 page=0 chnl=15
|
||||
char id=74 x=475 y=0 width=5 height=11 xoffset=-1 yoffset=2 xadvance=4 page=0 chnl=15
|
||||
char id=75 x=314 y=0 width=7 height=11 xoffset=0 yoffset=2 xadvance=7 page=0 chnl=15
|
||||
char id=76 x=440 y=0 width=6 height=11 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=77 x=112 y=0 width=10 height=11 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=15
|
||||
char id=78 x=225 y=0 width=8 height=11 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=15
|
||||
char id=79 x=198 y=0 width=8 height=11 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=15
|
||||
char id=80 x=282 y=0 width=7 height=11 xoffset=0 yoffset=2 xadvance=7 page=0 chnl=15
|
||||
char id=81 x=77 y=0 width=9 height=12 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=15
|
||||
char id=82 x=306 y=0 width=7 height=11 xoffset=0 yoffset=2 xadvance=7 page=0 chnl=15
|
||||
char id=83 x=447 y=0 width=6 height=11 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=84 x=250 y=0 width=7 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=85 x=207 y=0 width=8 height=11 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=15
|
||||
char id=86 x=133 y=0 width=9 height=11 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=15
|
||||
char id=87 x=87 y=0 width=13 height=11 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=15
|
||||
char id=88 x=189 y=0 width=8 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=15
|
||||
char id=89 x=322 y=0 width=7 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=90 x=153 y=0 width=8 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=15
|
||||
char id=91 x=46 y=0 width=4 height=13 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=15
|
||||
char id=92 x=8 y=0 width=7 height=14 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=15
|
||||
char id=93 x=56 y=0 width=4 height=13 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=15
|
||||
char id=94 x=141 y=12 width=7 height=7 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=95 x=185 y=12 width=8 height=4 xoffset=-1 yoffset=11 xadvance=6 page=0 chnl=15
|
||||
char id=96 x=180 y=12 width=4 height=5 xoffset=0 yoffset=1 xadvance=4 page=0 chnl=15
|
||||
char id=97 x=71 y=13 width=7 height=9 xoffset=0 yoffset=4 xadvance=7 page=0 chnl=15
|
||||
char id=98 x=338 y=0 width=7 height=11 xoffset=0 yoffset=2 xadvance=7 page=0 chnl=15
|
||||
char id=99 x=79 y=13 width=6 height=9 xoffset=0 yoffset=4 xadvance=6 page=0 chnl=15
|
||||
char id=100 x=346 y=0 width=7 height=11 xoffset=0 yoffset=2 xadvance=7 page=0 chnl=15
|
||||
char id=101 x=23 y=14 width=7 height=9 xoffset=0 yoffset=4 xadvance=7 page=0 chnl=15
|
||||
char id=102 x=426 y=0 width=6 height=11 xoffset=-1 yoffset=2 xadvance=4 page=0 chnl=15
|
||||
char id=103 x=354 y=0 width=7 height=11 xoffset=0 yoffset=4 xadvance=6 page=0 chnl=15
|
||||
char id=104 x=386 y=0 width=7 height=11 xoffset=0 yoffset=2 xadvance=7 page=0 chnl=15
|
||||
char id=105 x=486 y=0 width=3 height=11 xoffset=0 yoffset=2 xadvance=3 page=0 chnl=15
|
||||
char id=106 x=29 y=0 width=5 height=13 xoffset=-2 yoffset=2 xadvance=2 page=0 chnl=15
|
||||
char id=107 x=454 y=0 width=6 height=11 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=108 x=490 y=0 width=3 height=11 xoffset=0 yoffset=2 xadvance=3 page=0 chnl=15
|
||||
char id=109 x=12 y=15 width=10 height=9 xoffset=0 yoffset=4 xadvance=10 page=0 chnl=15
|
||||
char id=110 x=31 y=14 width=7 height=9 xoffset=0 yoffset=4 xadvance=7 page=0 chnl=15
|
||||
char id=111 x=39 y=14 width=7 height=9 xoffset=0 yoffset=4 xadvance=7 page=0 chnl=15
|
||||
char id=112 x=378 y=0 width=7 height=11 xoffset=0 yoffset=4 xadvance=7 page=0 chnl=15
|
||||
char id=113 x=418 y=0 width=7 height=11 xoffset=0 yoffset=4 xadvance=7 page=0 chnl=15
|
||||
char id=114 x=93 y=12 width=5 height=9 xoffset=0 yoffset=4 xadvance=4 page=0 chnl=15
|
||||
char id=115 x=86 y=13 width=6 height=9 xoffset=0 yoffset=4 xadvance=6 page=0 chnl=15
|
||||
char id=116 x=502 y=0 width=6 height=10 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=15
|
||||
char id=117 x=47 y=14 width=7 height=9 xoffset=0 yoffset=4 xadvance=7 page=0 chnl=15
|
||||
char id=118 x=55 y=14 width=7 height=9 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15
|
||||
char id=119 x=0 y=15 width=11 height=9 xoffset=-1 yoffset=4 xadvance=10 page=0 chnl=15
|
||||
char id=120 x=63 y=14 width=7 height=9 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15
|
||||
char id=121 x=394 y=0 width=7 height=11 xoffset=-1 yoffset=4 xadvance=5 page=0 chnl=15
|
||||
char id=122 x=99 y=12 width=5 height=9 xoffset=0 yoffset=4 xadvance=5 page=0 chnl=15
|
||||
char id=123 x=35 y=0 width=5 height=13 xoffset=-1 yoffset=2 xadvance=4 page=0 chnl=15
|
||||
char id=124 x=61 y=0 width=3 height=13 xoffset=1 yoffset=2 xadvance=6 page=0 chnl=15
|
||||
char id=125 x=23 y=0 width=5 height=13 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=15
|
||||
char id=126 x=172 y=12 width=7 height=5 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=15
|
||||
kernings count=104
|
||||
kerning first=65 second=84 amount=-1
|
||||
kerning first=65 second=86 amount=-1
|
||||
kerning first=65 second=89 amount=-1
|
||||
kerning first=70 second=65 amount=-1
|
||||
kerning first=70 second=74 amount=-1
|
||||
kerning first=70 second=44 amount=-1
|
||||
kerning first=70 second=46 amount=-1
|
||||
kerning first=75 second=79 amount=-1
|
||||
kerning first=75 second=81 amount=-1
|
||||
kerning first=75 second=118 amount=-1
|
||||
kerning first=75 second=119 amount=-1
|
||||
kerning first=76 second=84 amount=-1
|
||||
kerning first=76 second=86 amount=-1
|
||||
kerning first=76 second=87 amount=-1
|
||||
kerning first=76 second=89 amount=-1
|
||||
kerning first=76 second=101 amount=-1
|
||||
kerning first=80 second=65 amount=-1
|
||||
kerning first=80 second=74 amount=-1
|
||||
kerning first=80 second=44 amount=-1
|
||||
kerning first=80 second=46 amount=-2
|
||||
kerning first=80 second=47 amount=-1
|
||||
kerning first=81 second=44 amount=1
|
||||
kerning first=81 second=47 amount=1
|
||||
kerning first=84 second=65 amount=-1
|
||||
kerning first=84 second=97 amount=-1
|
||||
kerning first=84 second=99 amount=-1
|
||||
kerning first=84 second=100 amount=-1
|
||||
kerning first=84 second=101 amount=-1
|
||||
kerning first=84 second=103 amount=-1
|
||||
kerning first=84 second=109 amount=-1
|
||||
kerning first=84 second=110 amount=-1
|
||||
kerning first=84 second=111 amount=-1
|
||||
kerning first=84 second=112 amount=-1
|
||||
kerning first=84 second=113 amount=-1
|
||||
kerning first=84 second=114 amount=-1
|
||||
kerning first=84 second=115 amount=-1
|
||||
kerning first=84 second=117 amount=-1
|
||||
kerning first=84 second=118 amount=-1
|
||||
kerning first=84 second=119 amount=-1
|
||||
kerning first=84 second=120 amount=-1
|
||||
kerning first=84 second=121 amount=-1
|
||||
kerning first=84 second=122 amount=-1
|
||||
kerning first=84 second=44 amount=-1
|
||||
kerning first=84 second=59 amount=-1
|
||||
kerning first=84 second=58 amount=-1
|
||||
kerning first=84 second=46 amount=-1
|
||||
kerning first=84 second=47 amount=-1
|
||||
kerning first=86 second=65 amount=-1
|
||||
kerning first=86 second=97 amount=-1
|
||||
kerning first=86 second=99 amount=-1
|
||||
kerning first=86 second=100 amount=-1
|
||||
kerning first=86 second=101 amount=-1
|
||||
kerning first=86 second=103 amount=-1
|
||||
kerning first=86 second=111 amount=-1
|
||||
kerning first=86 second=113 amount=-1
|
||||
kerning first=86 second=115 amount=-1
|
||||
kerning first=86 second=44 amount=-1
|
||||
kerning first=86 second=59 amount=-1
|
||||
kerning first=86 second=46 amount=-1
|
||||
kerning first=86 second=47 amount=-1
|
||||
kerning first=87 second=65 amount=-1
|
||||
kerning first=87 second=74 amount=-1
|
||||
kerning first=87 second=111 amount=-1
|
||||
kerning first=87 second=44 amount=-1
|
||||
kerning first=87 second=59 amount=-1
|
||||
kerning first=87 second=46 amount=-1
|
||||
kerning first=89 second=65 amount=-1
|
||||
kerning first=89 second=74 amount=-1
|
||||
kerning first=89 second=97 amount=-1
|
||||
kerning first=89 second=99 amount=-1
|
||||
kerning first=89 second=100 amount=-1
|
||||
kerning first=89 second=101 amount=-1
|
||||
kerning first=89 second=103 amount=-1
|
||||
kerning first=89 second=109 amount=-1
|
||||
kerning first=89 second=110 amount=-1
|
||||
kerning first=89 second=111 amount=-1
|
||||
kerning first=89 second=112 amount=-1
|
||||
kerning first=89 second=113 amount=-1
|
||||
kerning first=89 second=114 amount=-1
|
||||
kerning first=89 second=115 amount=-1
|
||||
kerning first=89 second=117 amount=-1
|
||||
kerning first=89 second=122 amount=-1
|
||||
kerning first=89 second=44 amount=-1
|
||||
kerning first=89 second=59 amount=-1
|
||||
kerning first=89 second=58 amount=-1
|
||||
kerning first=89 second=46 amount=-1
|
||||
kerning first=89 second=47 amount=-1
|
||||
kerning first=102 second=44 amount=-1
|
||||
kerning first=102 second=46 amount=-1
|
||||
kerning first=102 second=116 amount=1
|
||||
kerning first=114 second=44 amount=-1
|
||||
kerning first=114 second=46 amount=-1
|
||||
kerning first=118 second=44 amount=-1
|
||||
kerning first=118 second=46 amount=-1
|
||||
kerning first=119 second=44 amount=-1
|
||||
kerning first=119 second=46 amount=-1
|
||||
kerning first=121 second=44 amount=-1
|
||||
kerning first=121 second=46 amount=-1
|
||||
kerning first=44 second=84 amount=-1
|
||||
kerning first=44 second=86 amount=-1
|
||||
kerning first=44 second=87 amount=-1
|
||||
kerning first=44 second=89 amount=-1
|
||||
kerning first=46 second=84 amount=-1
|
||||
kerning first=46 second=86 amount=-1
|
||||
kerning first=46 second=87 amount=-1
|
||||
kerning first=46 second=89 amount=-1
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
@ -1,200 +1,194 @@
|
||||
|
||||
skin.png
|
||||
size: 256,128
|
||||
size: 93,139
|
||||
format: RGBA8888
|
||||
filter: Linear,Linear
|
||||
repeat: none
|
||||
check-off
|
||||
button-disabled
|
||||
rotate: false
|
||||
xy: 11, 5
|
||||
size: 14, 14
|
||||
orig: 14, 14
|
||||
xy: 75, 73
|
||||
size: 17, 17
|
||||
split: 6, 6, 5, 5
|
||||
pad: -1, -1, 3, 3
|
||||
orig: 17, 17
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
textfield
|
||||
button-down
|
||||
rotate: false
|
||||
xy: 11, 5
|
||||
size: 14, 14
|
||||
split: 3, 3, 3, 3
|
||||
orig: 14, 14
|
||||
xy: 75, 54
|
||||
size: 17, 17
|
||||
split: 6, 6, 5, 5
|
||||
pad: -1, -1, 3, 3
|
||||
orig: 17, 17
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
check-on
|
||||
button-over
|
||||
rotate: false
|
||||
xy: 125, 35
|
||||
size: 14, 14
|
||||
orig: 14, 14
|
||||
xy: 66, 35
|
||||
size: 17, 17
|
||||
split: 6, 6, 5, 5
|
||||
pad: -1, -1, 3, 3
|
||||
orig: 17, 17
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
cursor
|
||||
button-up
|
||||
rotate: false
|
||||
xy: 23, 1
|
||||
xy: 24, 30
|
||||
size: 17, 17
|
||||
split: 6, 6, 5, 5
|
||||
pad: -1, -1, 3, 3
|
||||
orig: 17, 17
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
checkbox-off
|
||||
rotate: false
|
||||
xy: 66, 18
|
||||
size: 15, 15
|
||||
orig: 19, 18
|
||||
offset: 0, 2
|
||||
index: -1
|
||||
checkbox-offDisabled
|
||||
rotate: false
|
||||
xy: 24, 13
|
||||
size: 15, 15
|
||||
orig: 19, 18
|
||||
offset: 0, 2
|
||||
index: -1
|
||||
checkbox-on
|
||||
rotate: false
|
||||
xy: 1, 5
|
||||
size: 15, 15
|
||||
orig: 19, 18
|
||||
offset: 0, 2
|
||||
index: -1
|
||||
checkbox-onDisabled
|
||||
rotate: false
|
||||
xy: 66, 1
|
||||
size: 15, 15
|
||||
orig: 19, 18
|
||||
offset: 0, 2
|
||||
index: -1
|
||||
group
|
||||
rotate: false
|
||||
xy: 27, 72
|
||||
size: 23, 23
|
||||
split: 6, 6, 8, 8
|
||||
pad: 11, 11, 11, 11
|
||||
orig: 23, 23
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
list-selection
|
||||
rotate: false
|
||||
xy: 18, 8
|
||||
size: 11, 3
|
||||
split: 5, 5, 1, 1
|
||||
orig: 11, 3
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
loading
|
||||
rotate: false
|
||||
xy: 61, 92
|
||||
size: 30, 31
|
||||
orig: 30, 31
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
scrollpane-horiz
|
||||
rotate: false
|
||||
xy: 1, 120
|
||||
size: 58, 18
|
||||
split: 3, 51, 0, 18
|
||||
orig: 58, 18
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
scrollpane-vert
|
||||
rotate: false
|
||||
xy: 46, 9
|
||||
size: 18, 58
|
||||
split: 0, 18, 51, 3
|
||||
orig: 18, 58
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
selectBox-closed
|
||||
rotate: false
|
||||
xy: 1, 97
|
||||
size: 24, 21
|
||||
split: 6, 14, 5, 13
|
||||
pad: 5, 13, 3, 3
|
||||
orig: 24, 21
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
selectBox-list
|
||||
rotate: false
|
||||
xy: 24, 49
|
||||
size: 20, 21
|
||||
split: 5, 12, 5, 13
|
||||
orig: 20, 21
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
selectBox-open
|
||||
rotate: false
|
||||
xy: 27, 97
|
||||
size: 24, 21
|
||||
split: 6, 14, 5, 13
|
||||
pad: 5, 13, 3, 3
|
||||
orig: 24, 21
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
selectBox-over
|
||||
rotate: false
|
||||
xy: 1, 74
|
||||
size: 24, 21
|
||||
split: 6, 14, 5, 13
|
||||
pad: 5, 13, 3, 3
|
||||
orig: 24, 21
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
slider-bg
|
||||
rotate: false
|
||||
xy: 61, 125
|
||||
size: 31, 13
|
||||
split: 7, 6, 0, 13
|
||||
pad: 3, 2, -1, -1
|
||||
orig: 31, 13
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
slider-handle
|
||||
rotate: false
|
||||
xy: 53, 101
|
||||
size: 6, 17
|
||||
orig: 6, 17
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
textField-cursor
|
||||
rotate: false
|
||||
xy: 53, 96
|
||||
size: 3, 3
|
||||
split: 1, 1, 1, 1
|
||||
orig: 3, 3
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default
|
||||
textField-round
|
||||
rotate: false
|
||||
xy: 1, 50
|
||||
size: 253, 77
|
||||
orig: 254, 77
|
||||
offset: 1, 0
|
||||
index: -1
|
||||
default-pane
|
||||
rotate: false
|
||||
xy: 11, 1
|
||||
size: 5, 3
|
||||
split: 1, 1, 1, 1
|
||||
orig: 5, 3
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-rect-pad
|
||||
rotate: false
|
||||
xy: 11, 1
|
||||
size: 5, 3
|
||||
split: 1, 1, 1, 1
|
||||
orig: 5, 3
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-pane-noborder
|
||||
rotate: false
|
||||
xy: 129, 33
|
||||
size: 1, 1
|
||||
split: 0, 0, 0, 0
|
||||
orig: 1, 1
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-rect
|
||||
rotate: false
|
||||
xy: 38, 25
|
||||
size: 3, 3
|
||||
split: 1, 1, 1, 1
|
||||
orig: 3, 3
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-rect-down
|
||||
rotate: false
|
||||
xy: 170, 46
|
||||
size: 3, 3
|
||||
split: 1, 1, 1, 1
|
||||
orig: 3, 3
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-round
|
||||
rotate: false
|
||||
xy: 112, 29
|
||||
size: 12, 20
|
||||
split: 5, 5, 5, 4
|
||||
pad: 4, 4, 1, 1
|
||||
orig: 12, 20
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-round-down
|
||||
rotate: false
|
||||
xy: 99, 29
|
||||
size: 12, 20
|
||||
split: 5, 5, 5, 4
|
||||
pad: 4, 4, 1, 1
|
||||
orig: 12, 20
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-round-large
|
||||
rotate: false
|
||||
xy: 57, 29
|
||||
size: 20, 20
|
||||
split: 5, 5, 5, 4
|
||||
orig: 20, 20
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-scroll
|
||||
rotate: false
|
||||
xy: 78, 29
|
||||
size: 20, 20
|
||||
split: 2, 2, 2, 2
|
||||
orig: 20, 20
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-select
|
||||
rotate: false
|
||||
xy: 29, 29
|
||||
size: 27, 20
|
||||
split: 4, 14, 4, 4
|
||||
orig: 27, 20
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-select-selection
|
||||
rotate: false
|
||||
xy: 26, 16
|
||||
size: 3, 3
|
||||
split: 1, 1, 1, 1
|
||||
orig: 3, 3
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-slider
|
||||
rotate: false
|
||||
xy: 29, 20
|
||||
size: 8, 8
|
||||
split: 2, 2, 2, 2
|
||||
orig: 8, 8
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-slider-knob
|
||||
rotate: false
|
||||
xy: 1, 1
|
||||
size: 9, 18
|
||||
orig: 9, 18
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-splitpane
|
||||
rotate: false
|
||||
xy: 17, 1
|
||||
size: 5, 3
|
||||
split: 0, 5, 0, 0
|
||||
orig: 5, 3
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-splitpane-vertical
|
||||
rotate: false
|
||||
xy: 125, 29
|
||||
size: 3, 5
|
||||
split: 0, 0, 0, 5
|
||||
orig: 3, 5
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-window
|
||||
rotate: false
|
||||
xy: 1, 20
|
||||
size: 27, 29
|
||||
split: 4, 3, 20, 3
|
||||
orig: 27, 29
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
selection
|
||||
rotate: false
|
||||
xy: 170, 44
|
||||
size: 1, 1
|
||||
orig: 1, 1
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
tree-minus
|
||||
rotate: false
|
||||
xy: 140, 35
|
||||
size: 14, 14
|
||||
orig: 14, 14
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
tree-plus
|
||||
rotate: false
|
||||
xy: 155, 35
|
||||
size: 14, 14
|
||||
orig: 14, 14
|
||||
xy: 52, 69
|
||||
size: 21, 21
|
||||
split: 6, 5, 5, 5
|
||||
pad: -1, -1, 3, 3
|
||||
orig: 21, 21
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
white
|
||||
rotate: false
|
||||
xy: 174, 48
|
||||
size: 1, 1
|
||||
orig: 1, 1
|
||||
xy: 66, 64
|
||||
size: 3, 3
|
||||
orig: 3, 3
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
window
|
||||
rotate: false
|
||||
xy: 1, 22
|
||||
size: 21, 50
|
||||
split: 10, 10, 36, 11
|
||||
pad: 9, 9, 41, 8
|
||||
orig: 21, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
|
||||
@ -1,59 +1,66 @@
|
||||
{
|
||||
com.badlogic.gdx.graphics.g2d.BitmapFont: { default-font: { file: com/badlogic/gdx/utils/arial-15.fnt } },
|
||||
com.badlogic.gdx.graphics.g2d.BitmapFont: {
|
||||
default: { file: font-calibri-12.fnt }
|
||||
}
|
||||
com.badlogic.gdx.graphics.Color: {
|
||||
green: { a: 1, b: 0, g: 1, r: 0 },
|
||||
white: { a: 1, b: 1, g: 1, r: 1 },
|
||||
red: { a: 1, b: 0, g: 0, r: 1 },
|
||||
black: { a: 1, b: 0, g: 0, r: 0 }
|
||||
white: { r: 1, g: 1, b: 1 },
|
||||
black: {},
|
||||
disabled: { r: 0.53, g: 0.53, b: 0.53 },
|
||||
selection: { r: 0.77, g: 1, b: 1, a: 0.25 },
|
||||
},
|
||||
com.badlogic.gdx.scenes.scene2d.ui.Skin$TintedDrawable: {
|
||||
dialogDim: { name: white, color: { r: 0, g: 0, b: 0, a: 0.45 } }
|
||||
},
|
||||
com.badlogic.gdx.scenes.scene2d.ui.Button$ButtonStyle: {
|
||||
default: { down: default-round-down, up: default-round },
|
||||
toggle: { down: default-round-down, checked: default-round-down, up: default-round }
|
||||
selection: { name: white, color: selection },
|
||||
dim: { name: white, color: { r: 0, g: 0, b: 0, a: 0.3 } },
|
||||
list-selection: { name: list-selection, color: selection },
|
||||
},
|
||||
com.badlogic.gdx.scenes.scene2d.ui.TextButton$TextButtonStyle: {
|
||||
default: { down: default-round-down, up: default-round, font: default-font, fontColor: white },
|
||||
toggle: { down: default-round-down, up: default-round, checked: default-round-down, font: default-font, fontColor: white, downFontColor: red }
|
||||
default: {
|
||||
up: button-up, down: button-down, over: button-over, disabled: button-disabled,
|
||||
font: default, fontColor: white, disabledFontColor: disabled, pressedOffsetY: -1
|
||||
},
|
||||
toggle: {
|
||||
up: button-up, down: button-down, over: button-over, disabled: button-disabled, checked: button-down,
|
||||
font: default, fontColor: white, disabledFontColor: disabled, pressedOffsetY: -1
|
||||
},
|
||||
},
|
||||
com.badlogic.gdx.scenes.scene2d.ui.Label$LabelStyle: {
|
||||
default: { font: default, fontColor: white },
|
||||
title: { font: default, fontColor: { hex: 00ffccff } },
|
||||
}
|
||||
com.badlogic.gdx.scenes.scene2d.ui.TextField$TextFieldStyle: {
|
||||
default: { background: textField-round, font: default, fontColor: white, disabledFontColor: disabled,
|
||||
selection: selection, cursor: textField-cursor },
|
||||
}
|
||||
com.badlogic.gdx.scenes.scene2d.ui.Window$WindowStyle: {
|
||||
default: { titleFont: default, titleFontColor: white, background: window },
|
||||
},
|
||||
com.badlogic.gdx.scenes.scene2d.ui.ScrollPane$ScrollPaneStyle: {
|
||||
default: { vScroll: default-scroll, hScrollKnob: default-round-large, background: default-rect, hScroll: default-scroll, vScrollKnob: default-round-large }
|
||||
default: { hScrollKnob: scrollpane-horiz, vScrollKnob: scrollpane-vert },
|
||||
bg: { hScrollKnob: scrollpane-horiz, vScrollKnob: scrollpane-vert, background: textField-round },
|
||||
},
|
||||
com.badlogic.gdx.scenes.scene2d.ui.List$ListStyle: {
|
||||
default: { font: default, selection: list-selection }
|
||||
},
|
||||
com.badlogic.gdx.scenes.scene2d.ui.SelectBox$SelectBoxStyle: {
|
||||
default: {
|
||||
font: default-font, fontColor: white, background: default-select,
|
||||
scrollStyle: default,
|
||||
listStyle: { font: default-font, selection: default-select-selection }
|
||||
}
|
||||
background: selectBox-closed, backgroundOver: selectBox-over, backgroundOpen: selectBox-open, font: default, fontColor: white,
|
||||
scrollStyle: { background: selectBox-list, hScrollKnob: scrollpane-horiz, vScrollKnob: scrollpane-vert },
|
||||
listStyle: { font: default, selection: list-selection },
|
||||
},
|
||||
},
|
||||
com.badlogic.gdx.scenes.scene2d.ui.SplitPane$SplitPaneStyle: {
|
||||
default-vertical: { handle: default-splitpane-vertical },
|
||||
default-horizontal: { handle: default-splitpane }
|
||||
},
|
||||
com.badlogic.gdx.scenes.scene2d.ui.Window$WindowStyle: {
|
||||
default: { titleFont: default-font, background: default-window, titleFontColor: white },
|
||||
dialog: { titleFont: default-font, background: default-window, titleFontColor: white, stageBackground: dialogDim }
|
||||
},
|
||||
com.badlogic.gdx.scenes.scene2d.ui.Slider$SliderStyle: {
|
||||
default-horizontal: { background: default-slider, knob: default-slider-knob }
|
||||
},
|
||||
com.badlogic.gdx.scenes.scene2d.ui.Label$LabelStyle: {
|
||||
default: { font: default-font, fontColor: white }
|
||||
},
|
||||
com.badlogic.gdx.scenes.scene2d.ui.TextField$TextFieldStyle: {
|
||||
default: { selection: selection, background: textfield, font: default-font, fontColor: white, cursor: cursor }
|
||||
com.badlogic.gdx.scenes.scene2d.ui.TextTooltip$TextTooltipStyle: {
|
||||
default: {
|
||||
label: { font: default, fontColor: white },
|
||||
background: group
|
||||
},
|
||||
},
|
||||
com.badlogic.gdx.scenes.scene2d.ui.CheckBox$CheckBoxStyle: {
|
||||
default: { checkboxOn: check-on, checkboxOff: check-off, font: default-font, fontColor: white }
|
||||
default: {
|
||||
checkboxOn: checkbox-on, checkboxOff: checkbox-off, checkboxOffDisabled: checkbox-offDisabled,
|
||||
checkboxOnDisabled: checkbox-onDisabled, font: default, fontColor: white, disabledFontColor: disabled
|
||||
},
|
||||
},
|
||||
com.badlogic.gdx.scenes.scene2d.ui.List$ListStyle: {
|
||||
default: { fontColorUnselected: white, selection: selection, fontColorSelected: white, font: default-font }
|
||||
com.badlogic.gdx.scenes.scene2d.ui.Slider$SliderStyle: {
|
||||
default-horizontal: { background: slider-bg, knob: slider-handle },
|
||||
},
|
||||
com.badlogic.gdx.scenes.scene2d.ui.Touchpad$TouchpadStyle: {
|
||||
default: { background: default-pane, knob: default-round-large }
|
||||
},
|
||||
com.badlogic.gdx.scenes.scene2d.ui.Tree$TreeStyle: {
|
||||
default: { minus: tree-minus, plus: tree-plus, selection: default-select-selection }
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 5.6 KiB |
@ -50,6 +50,7 @@ import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.Pixmap.Format;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.Texture.TextureFilter;
|
||||
import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
|
||||
@ -83,7 +84,7 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
UI ui;
|
||||
|
||||
PolygonSpriteBatch batch;
|
||||
SkeletonRenderer renderer;
|
||||
SkeletonMeshRenderer renderer;
|
||||
SkeletonRendererDebug debugRenderer;
|
||||
SkeletonData skeletonData;
|
||||
Skeleton skeleton;
|
||||
@ -96,18 +97,20 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
public void create () {
|
||||
ui = new UI();
|
||||
batch = new PolygonSpriteBatch();
|
||||
renderer = new SkeletonRenderer();
|
||||
renderer = new SkeletonMeshRenderer();
|
||||
debugRenderer = new SkeletonRendererDebug();
|
||||
skeletonX = (int)(ui.window.getWidth() + (Gdx.graphics.getWidth() - ui.window.getWidth()) / 2);
|
||||
skeletonY = Gdx.graphics.getHeight() / 4;
|
||||
|
||||
loadSkeleton(
|
||||
Gdx.files.internal(Gdx.app.getPreferences("spine-skeletontest").getString("lastFile", "spineboy/spineboy.json")), false);
|
||||
Gdx.files.internal(Gdx.app.getPreferences("spine-skeletonviewer").getString("lastFile", "spineboy/spineboy.json")),
|
||||
false);
|
||||
}
|
||||
|
||||
void loadSkeleton (FileHandle skeletonFile, boolean reload) {
|
||||
void loadSkeleton (final FileHandle skeletonFile, boolean reload) {
|
||||
if (skeletonFile == null) return;
|
||||
|
||||
try {
|
||||
// A regular texture atlas would normally usually be used. This returns a white image for images not found in the atlas.
|
||||
Pixmap pixmap = new Pixmap(32, 32, Format.RGBA8888);
|
||||
pixmap.setColor(new Color(1, 1, 1, 0.33f));
|
||||
@ -123,11 +126,20 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
TextureAtlas atlas = new TextureAtlas(data) {
|
||||
public AtlasRegion findRegion (String name) {
|
||||
AtlasRegion region = super.findRegion(name);
|
||||
if (region == null) {
|
||||
// Look for separate image file.
|
||||
FileHandle file = skeletonFile.sibling(name + ".png");
|
||||
if (file.exists()) {
|
||||
Texture texture = new Texture(file);
|
||||
texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
|
||||
region = new AtlasRegion(texture, 0, 0, texture.getWidth(), texture.getHeight());
|
||||
region.name = name;
|
||||
}
|
||||
}
|
||||
return region != null ? region : fake;
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
String extension = skeletonFile.extension();
|
||||
if (extension.equalsIgnoreCase("json") || extension.equalsIgnoreCase("txt")) {
|
||||
SkeletonJson json = new SkeletonJson(atlas);
|
||||
@ -137,6 +149,7 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
SkeletonBinary binary = new SkeletonBinary(atlas);
|
||||
binary.setScale(ui.scaleSlider.getValue());
|
||||
skeletonData = binary.readSkeletonData(skeletonFile);
|
||||
if (skeletonData.getBones().size == 0) throw new Exception("No bones in skeleton data.");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
@ -153,7 +166,7 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
state = new AnimationState(new AnimationStateData(skeletonData));
|
||||
|
||||
this.skeletonFile = skeletonFile;
|
||||
Preferences prefs = Gdx.app.getPreferences("spine-skeletontest");
|
||||
Preferences prefs = Gdx.app.getPreferences("spine-skeletonviewer");
|
||||
prefs.putString("lastFile", skeletonFile.path());
|
||||
prefs.flush();
|
||||
lastModified = skeletonFile.lastModified();
|
||||
@ -161,7 +174,7 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
|
||||
// Populate UI.
|
||||
|
||||
ui.skeletonLabel.setText(skeletonFile.name());
|
||||
ui.window.getTitleLabel().setText(skeletonFile.name());
|
||||
{
|
||||
Array<String> items = new Array();
|
||||
for (Skin skin : skeletonData.getSkins())
|
||||
@ -177,7 +190,8 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
|
||||
// Configure skeleton from UI.
|
||||
|
||||
skeleton.setSkin(ui.skinList.getSelected());
|
||||
if (ui.skinList.getSelected() != null) skeleton.setSkin(ui.skinList.getSelected());
|
||||
if (ui.animationList.getSelected() != null)
|
||||
state.setAnimation(0, ui.animationList.getSelected(), ui.loopCheckbox.isChecked());
|
||||
|
||||
if (reload) ui.toast("Reloaded.");
|
||||
@ -217,6 +231,7 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
// skeleton.getRootBone().setY(skeletonY);
|
||||
skeleton.updateWorldTransform();
|
||||
|
||||
batch.setColor(Color.WHITE);
|
||||
batch.begin();
|
||||
renderer.draw(batch, skeleton);
|
||||
batch.end();
|
||||
@ -252,7 +267,7 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
batch.getProjectionMatrix().setToOrtho2D(0, 0, width, height);
|
||||
debugRenderer.getShapeRenderer().setProjectionMatrix(batch.getProjectionMatrix());
|
||||
ui.stage.getViewport().update(width, height, true);
|
||||
if (!ui.minimizeButton.isChecked()) ui.window.setHeight(height);
|
||||
if (!ui.minimizeButton.isChecked()) ui.window.setHeight(height + 8);
|
||||
}
|
||||
|
||||
class UI {
|
||||
@ -262,8 +277,7 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
|
||||
Window window = new Window("Skeleton", skin);
|
||||
Table root = new Table(skin);
|
||||
TextButton browseButton = new TextButton("Browse", skin);
|
||||
Label skeletonLabel = new Label("", skin);
|
||||
TextButton openButton = new TextButton("Open", skin);
|
||||
List<String> animationList = new List(skin);
|
||||
List<String> skinList = new List(skin);
|
||||
CheckBox loopCheckbox = new CheckBox(" Loop", skin);
|
||||
@ -305,30 +319,24 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
|
||||
window.setMovable(false);
|
||||
window.setResizable(false);
|
||||
window.setKeepWithinStage(false);
|
||||
window.setX(-3);
|
||||
window.setY(-2);
|
||||
|
||||
minimizeButton.padTop(-2).padLeft(5);
|
||||
minimizeButton.getColor().a = 0.66f;
|
||||
window.getTitleTable().add(minimizeButton).size(20, 20);
|
||||
window.getTitleTable().add(openButton).space(3);
|
||||
window.getTitleTable().add(minimizeButton).width(20);
|
||||
|
||||
ScrollPane skinScroll = new ScrollPane(skinList, skin);
|
||||
ScrollPane skinScroll = new ScrollPane(skinList, skin, "bg");
|
||||
skinScroll.setFadeScrollBars(false);
|
||||
|
||||
ScrollPane animationScroll = new ScrollPane(animationList, skin);
|
||||
ScrollPane animationScroll = new ScrollPane(animationList, skin, "bg");
|
||||
animationScroll.setFadeScrollBars(false);
|
||||
|
||||
// Layout.
|
||||
|
||||
root.pad(2, 4, 4, 4).defaults().space(6);
|
||||
root.columnDefaults(0).top().right();
|
||||
root.defaults().space(6);
|
||||
root.columnDefaults(0).top().right().padTop(3);
|
||||
root.columnDefaults(1).left();
|
||||
root.row().padTop(6);
|
||||
root.add("Skeleton:");
|
||||
{
|
||||
Table table = table();
|
||||
table.add(skeletonLabel).fillX().expandX();
|
||||
table.add(browseButton);
|
||||
root.add(table).fill().row();
|
||||
}
|
||||
root.add("Scale:");
|
||||
{
|
||||
Table table = table();
|
||||
@ -378,7 +386,6 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
stage.addActor(table);
|
||||
table.pad(10).bottom().right();
|
||||
table.add(toasts);
|
||||
table.debug();
|
||||
}
|
||||
|
||||
// Events.
|
||||
@ -390,7 +397,7 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
}
|
||||
});
|
||||
|
||||
browseButton.addListener(new ChangeListener() {
|
||||
openButton.addListener(new ChangeListener() {
|
||||
public void changed (ChangeEvent event, Actor actor) {
|
||||
FileDialog fileDialog = new FileDialog((Frame)null, "Choose skeleton file");
|
||||
fileDialog.setMode(FileDialog.LOAD);
|
||||
@ -427,11 +434,11 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
public void clicked (InputEvent event, float x, float y) {
|
||||
if (minimizeButton.isChecked()) {
|
||||
window.getCells().get(0).setActor(null);
|
||||
window.setHeight(20);
|
||||
window.setHeight(37);
|
||||
minimizeButton.setText("+");
|
||||
} else {
|
||||
window.getCells().get(0).setActor(root);
|
||||
ui.window.setHeight(Gdx.graphics.getHeight());
|
||||
ui.window.setHeight(Gdx.graphics.getHeight() + 8);
|
||||
minimizeButton.setText("-");
|
||||
}
|
||||
}
|
||||
@ -466,7 +473,11 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
skinList.addListener(new ChangeListener() {
|
||||
public void changed (ChangeEvent event, Actor actor) {
|
||||
if (skeleton != null) {
|
||||
skeleton.setSkin(skinList.getSelected());
|
||||
String skinName = skinList.getSelected();
|
||||
if (skinName == null)
|
||||
skeleton.setSkin((Skin)null);
|
||||
else
|
||||
skeleton.setSkin(skinName);
|
||||
skeleton.setSlotsToSetupPose();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user