Updated for Spine 3.0.00.

This commit is contained in:
NathanSweet 2016-01-11 00:30:49 +01:00
parent f6e4027ef1
commit 37f2f9e880
34 changed files with 1367 additions and 733 deletions

View File

@ -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

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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();

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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;
}
}
}
}

View File

@ -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;
}

View File

@ -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 + ")");
}

View File

@ -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);
}
}
}
}

View File

@ -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);

View File

@ -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]);

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,6 @@
package com.esotericsoftware.spine;
public interface Updatable {
public void update ();
}

View File

@ -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];

View File

@ -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 () {

View File

@ -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 () {

View File

@ -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 () {

View File

@ -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 () {

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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.TextTooltip$TextTooltipStyle: {
default: {
label: { font: default, fontColor: white },
background: group
},
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.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.Touchpad$TouchpadStyle: {
default: { background: default-pane, knob: default-round-large }
com.badlogic.gdx.scenes.scene2d.ui.Slider$SliderStyle: {
default-horizontal: { background: slider-bg, knob: slider-handle },
},
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

View File

@ -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();
}
}