Refactoring to bring spine-libgdx up to date with spine-csharp and spine-xna.

This commit is contained in:
NathanSweet 2013-04-16 12:44:55 +02:00
parent 655d2d856b
commit 23e04c3b08
20 changed files with 173 additions and 94 deletions

View File

@ -34,7 +34,7 @@ namespace Spine {
this.atlas = atlas;
}
public Attachment NewAttachment (AttachmentType type, String name) {
public Attachment NewAttachment (Skin skin, AttachmentType type, String name) {
switch (type) {
case AttachmentType.region:
AtlasRegion region = atlas.FindRegion(name);

View File

@ -28,6 +28,6 @@ using System;
namespace Spine {
public interface AttachmentLoader {
/** @return May be null to not load any attachment. */
Attachment NewAttachment (AttachmentType type, String name);
Attachment NewAttachment (Skin skin, AttachmentType type, String name);
}
}

View File

@ -119,7 +119,7 @@ namespace Spine {
foreach (KeyValuePair<String, Object> slotEntry in (Dictionary<String, Object>)entry.Value) {
int slotIndex = skeletonData.FindSlotIndex(slotEntry.Key);
foreach (KeyValuePair<String, Object> attachmentEntry in ((Dictionary<String, Object>)slotEntry.Value)) {
Attachment attachment = readAttachment(attachmentEntry.Key, (Dictionary<String, Object>)attachmentEntry.Value);
Attachment attachment = readAttachment(skin, attachmentEntry.Key, (Dictionary<String, Object>)attachmentEntry.Value);
skin.AddAttachment(slotIndex, attachmentEntry.Key, attachment);
}
}
@ -144,14 +144,14 @@ namespace Spine {
return skeletonData;
}
private Attachment readAttachment (String name, Dictionary<String, Object> map) {
private Attachment readAttachment (Skin skin, String name, Dictionary<String, Object> map) {
if (map.ContainsKey("name"))
name = (String)map["name"];
AttachmentType type = AttachmentType.region;
if (map.ContainsKey("type"))
type = (AttachmentType)Enum.Parse(typeof(AttachmentType), (String)map["type"], false);
Attachment attachment = attachmentLoader.NewAttachment(type, name);
Attachment attachment = attachmentLoader.NewAttachment(skin, type, name);
if (attachment is RegionAttachment) {
RegionAttachment regionAttachment = (RegionAttachment)attachment;

View File

@ -25,6 +25,8 @@
package com.esotericsoftware.spine;
import com.esotericsoftware.spine.attachments.Attachment;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
@ -117,37 +119,6 @@ public class Skeleton {
slots.get(i).setToBindPose(i);
}
public void draw (SpriteBatch batch) {
Array<Slot> drawOrder = this.drawOrder;
for (int i = 0, n = drawOrder.size; i < n; i++) {
Slot slot = drawOrder.get(i);
Attachment attachment = slot.attachment;
if (attachment != null) attachment.draw(batch, slot);
}
}
public void drawDebug (ShapeRenderer renderer) {
renderer.setColor(Color.RED);
renderer.begin(ShapeType.Line);
for (int i = 0, n = bones.size; i < n; i++) {
Bone bone = bones.get(i);
if (bone.parent == null) continue;
float x = bone.data.length * bone.m00 + bone.worldX;
float y = bone.data.length * bone.m10 + bone.worldY;
renderer.line(bone.worldX, bone.worldY, x, y);
}
renderer.end();
renderer.setColor(Color.GREEN);
renderer.begin(ShapeType.Filled);
for (int i = 0, n = bones.size; i < n; i++) {
Bone bone = bones.get(i);
renderer.setColor(Color.GREEN);
renderer.circle(bone.worldX, bone.worldY, 3);
}
renderer.end();
}
public SkeletonData getData () {
return data;
}

View File

@ -32,6 +32,9 @@ import com.esotericsoftware.spine.Animation.RotateTimeline;
import com.esotericsoftware.spine.Animation.ScaleTimeline;
import com.esotericsoftware.spine.Animation.Timeline;
import com.esotericsoftware.spine.Animation.TranslateTimeline;
import com.esotericsoftware.spine.attachments.Attachment;
import com.esotericsoftware.spine.attachments.AttachmentLoader;
import com.esotericsoftware.spine.attachments.AttachmentType;
import com.esotericsoftware.spine.attachments.RegionAttachment;
import com.esotericsoftware.spine.attachments.RegionSequenceAttachment;
import com.esotericsoftware.spine.attachments.RegionSequenceAttachment.Mode;

View File

@ -32,10 +32,13 @@ import com.esotericsoftware.spine.Animation.RotateTimeline;
import com.esotericsoftware.spine.Animation.ScaleTimeline;
import com.esotericsoftware.spine.Animation.Timeline;
import com.esotericsoftware.spine.Animation.TranslateTimeline;
import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
import com.esotericsoftware.spine.attachments.Attachment;
import com.esotericsoftware.spine.attachments.AttachmentLoader;
import com.esotericsoftware.spine.attachments.AttachmentType;
import com.esotericsoftware.spine.attachments.RegionAttachment;
import com.esotericsoftware.spine.attachments.RegionSequenceAttachment;
import com.esotericsoftware.spine.attachments.RegionSequenceAttachment.Mode;
import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
@ -46,8 +49,6 @@ import com.badlogic.gdx.utils.ObjectMap.Entry;
import com.badlogic.gdx.utils.OrderedMap;
import com.badlogic.gdx.utils.SerializationException;
import java.io.StringWriter;
public class SkeletonJson {
static public final String TIMELINE_SCALE = "scale";
static public final String TIMELINE_ROTATE = "rotate";
@ -161,7 +162,7 @@ public class SkeletonJson {
if (attachment instanceof RegionSequenceAttachment) {
RegionSequenceAttachment regionSequenceAttachment = (RegionSequenceAttachment)attachment;
Float fps = (Float)map.get("fps");
Float fps = getFloat(map, "fps");
if (fps == null) throw new SerializationException("Region sequence attachment missing fps: " + name);
regionSequenceAttachment.setFrameTime(fps);
@ -187,6 +188,19 @@ public class SkeletonJson {
private float getFloat (OrderedMap map, String name, float defaultValue) {
Object value = map.get(name);
if (value == null) return defaultValue;
if (value instanceof Long) return (Long)value;
return (Float)value;
}
private float getFloat (OrderedMap map, String name) {
Object value = map.get(name);
if (value instanceof Long) return (Long)value;
return (Float)value;
}
private float getFloat (Array array, int index) {
Object value = array.get(index);
if (value instanceof Long) return (Long)value;
return (Float)value;
}
@ -211,8 +225,8 @@ public class SkeletonJson {
int frameIndex = 0;
for (OrderedMap valueMap : values) {
float time = (Float)valueMap.get("time");
timeline.setFrame(frameIndex, time, (Float)valueMap.get("angle"));
float time = getFloat(valueMap, "time");
timeline.setFrame(frameIndex, time, getFloat(valueMap, "angle"));
readCurve(timeline, frameIndex, valueMap);
frameIndex++;
}
@ -232,8 +246,8 @@ public class SkeletonJson {
int frameIndex = 0;
for (OrderedMap valueMap : values) {
float time = (Float)valueMap.get("time");
Float x = (Float)valueMap.get("x"), y = (Float)valueMap.get("y");
float time = getFloat(valueMap, "time");
Float x = getFloat(valueMap, "x"), y = getFloat(valueMap, "y");
timeline
.setFrame(frameIndex, time, x == null ? 0 : (x * timelineScale), y == null ? 0 : (y * timelineScale));
readCurve(timeline, frameIndex, valueMap);
@ -264,7 +278,7 @@ public class SkeletonJson {
int frameIndex = 0;
for (OrderedMap valueMap : values) {
float time = (Float)valueMap.get("time");
float time = getFloat(valueMap, "time");
Color color = Color.valueOf((String)valueMap.get("color"));
timeline.setFrame(frameIndex, time, color.r, color.g, color.b, color.a);
readCurve(timeline, frameIndex, valueMap);
@ -279,7 +293,7 @@ public class SkeletonJson {
int frameIndex = 0;
for (OrderedMap valueMap : values) {
float time = (Float)valueMap.get("time");
float time = getFloat(valueMap, "time");
timeline.setFrame(frameIndex++, time, (String)valueMap.get("name"));
}
timelines.add(timeline);
@ -302,7 +316,7 @@ public class SkeletonJson {
timeline.setStepped(frameIndex);
else if (curveObject instanceof Array) {
Array curve = (Array)curveObject;
timeline.setCurve(frameIndex, (Float)curve.get(0), (Float)curve.get(1), (Float)curve.get(2), (Float)curve.get(3));
timeline.setCurve(frameIndex, getFloat(curve, 0), getFloat(curve, 1), getFloat(curve, 2), getFloat(curve, 3));
}
}
}

View File

@ -0,0 +1,24 @@
package com.esotericsoftware.spine;
import com.esotericsoftware.spine.attachments.Attachment;
import com.esotericsoftware.spine.attachments.RegionAttachment;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.Array;
public class SkeletonRenderer {
public void draw (SpriteBatch batch, Skeleton skeleton) {
Array<Slot> drawOrder = skeleton.drawOrder;
for (int i = 0, n = drawOrder.size; i < n; i++) {
Slot slot = drawOrder.get(i);
Attachment attachment = slot.attachment;
if (attachment instanceof RegionAttachment) {
RegionAttachment regionAttachment = (RegionAttachment)attachment;
regionAttachment.updateVertices(slot);
float[] vertices = regionAttachment.getVertices();
batch.draw(regionAttachment.getRegion().getTexture(), vertices, 0, vertices.length);
}
}
}
}

View File

@ -0,0 +1,65 @@
package com.esotericsoftware.spine;
import com.esotericsoftware.spine.attachments.Attachment;
import com.esotericsoftware.spine.attachments.RegionAttachment;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import static com.badlogic.gdx.graphics.g2d.SpriteBatch.*;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.utils.Array;
public class SkeletonRendererDebug {
private ShapeRenderer renderer;
public SkeletonRendererDebug () {
renderer = new ShapeRenderer();
}
public void draw (SpriteBatch batch, Skeleton skeleton) {
renderer.begin(ShapeType.Line);
renderer.setColor(Color.RED);
Array<Bone> bones = skeleton.getBones();
for (int i = 0, n = bones.size; i < n; i++) {
Bone bone = bones.get(i);
if (bone.parent == null) continue;
float x = bone.data.length * bone.m00 + bone.worldX;
float y = bone.data.length * bone.m10 + bone.worldY;
renderer.line(bone.worldX, bone.worldY, x, y);
}
renderer.setColor(Color.BLUE);
Array<Slot> slots = skeleton.getSlots();
for (int i = 0, n = slots.size; i < n; i++) {
Slot slot = slots.get(i);
Attachment attachment = slot.attachment;
if (attachment instanceof RegionAttachment) {
RegionAttachment regionAttachment = (RegionAttachment)attachment;
regionAttachment.updateVertices(slot);
float[] vertices = regionAttachment.getVertices();
renderer.line(vertices[X1], vertices[Y1], vertices[X2], vertices[Y2]);
renderer.line(vertices[X2], vertices[Y2], vertices[X3], vertices[Y3]);
renderer.line(vertices[X3], vertices[Y3], vertices[X4], vertices[Y4]);
renderer.line(vertices[X4], vertices[Y4], vertices[X1], vertices[Y1]);
}
}
renderer.end();
renderer.setColor(Color.GREEN);
renderer.begin(ShapeType.Filled);
for (int i = 0, n = bones.size; i < n; i++) {
Bone bone = bones.get(i);
renderer.setColor(Color.GREEN);
renderer.circle(bone.worldX, bone.worldY, 3);
}
renderer.end();
}
public ShapeRenderer getShapeRenderer () {
return renderer;
}
}

View File

@ -25,6 +25,8 @@
package com.esotericsoftware.spine;
import com.esotericsoftware.spine.attachments.Attachment;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;
import com.badlogic.gdx.utils.ObjectMap.Entry;

View File

@ -25,6 +25,8 @@
package com.esotericsoftware.spine;
import com.esotericsoftware.spine.attachments.Attachment;
import com.badlogic.gdx.graphics.Color;
public class Slot {

View File

@ -25,9 +25,6 @@
package com.esotericsoftware.spine.attachments;
import com.esotericsoftware.spine.Attachment;
import com.esotericsoftware.spine.AttachmentLoader;
import com.esotericsoftware.spine.AttachmentType;
import com.esotericsoftware.spine.Skin;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;

View File

@ -23,7 +23,9 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package com.esotericsoftware.spine;
package com.esotericsoftware.spine.attachments;
import com.esotericsoftware.spine.Slot;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
@ -35,8 +37,6 @@ abstract public class Attachment {
this.name = name;
}
abstract public void draw (SpriteBatch batch, Slot slot);
public String getName () {
return name;
}

View File

@ -23,7 +23,9 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package com.esotericsoftware.spine;
package com.esotericsoftware.spine.attachments;
import com.esotericsoftware.spine.Skin;
public interface AttachmentLoader {
/** @return May be null to not load any attachment. */

View File

@ -23,7 +23,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package com.esotericsoftware.spine;
package com.esotericsoftware.spine.attachments;
public enum AttachmentType {
region, regionSequence

View File

@ -25,7 +25,6 @@
package com.esotericsoftware.spine.attachments;
import com.esotericsoftware.spine.Attachment;
import com.esotericsoftware.spine.Bone;
import com.esotericsoftware.spine.Slot;
@ -128,13 +127,11 @@ public class RegionAttachment extends Attachment {
}
public TextureRegion getRegion () {
if (region == null) throw new IllegalStateException("RegionAttachment is not resolved: " + this);
if (region == null) throw new IllegalStateException("Region has not been set: " + this);
return region;
}
public void draw (SpriteBatch batch, Slot slot) {
if (region == null) throw new IllegalStateException("RegionAttachment is not resolved: " + this);
public void updateVertices (Slot slot) {
Color skeletonColor = slot.getSkeleton().getColor();
Color slotColor = slot.getColor();
float color = NumberUtils.intToFloatColor( //
@ -148,14 +145,8 @@ public class RegionAttachment extends Attachment {
vertices[C3] = color;
vertices[C4] = color;
updateWorldVertices(slot.getBone());
batch.draw(region.getTexture(), vertices, 0, vertices.length);
}
public void updateWorldVertices (Bone bone) {
float[] vertices = this.vertices;
float[] offset = this.offset;
Bone bone = slot.getBone();
float x = bone.getWorldX();
float y = bone.getWorldY();
float m00 = bone.getM00();
@ -172,7 +163,7 @@ public class RegionAttachment extends Attachment {
vertices[Y4] = offset[6] * m10 + offset[7] * m11 + y;
}
public float[] getWorldVertices () {
public float[] getVertices () {
return vertices;
}

View File

@ -41,8 +41,8 @@ public class RegionSequenceAttachment extends RegionAttachment {
super(name);
}
public void draw (SpriteBatch batch, Slot slot) {
if (regions == null) throw new IllegalStateException("RegionSequenceAttachment is not resolved: " + this);
public void updateVertices (Slot slot) {
if (regions == null) throw new IllegalStateException("Regions have not been set: " + this);
int frameIndex = (int)(slot.getAttachmentTime() / frameTime);
switch (mode) {
@ -68,12 +68,12 @@ public class RegionSequenceAttachment extends RegionAttachment {
break;
}
setRegion(regions[frameIndex]);
super.draw(batch, slot);
super.updateVertices(slot);
}
/** May be null if the attachment is not resolved. */
public TextureRegion[] getRegions () {
if (regions == null) throw new IllegalStateException("RegionSequenceAttachment is not resolved: " + this);
if (regions == null) throw new IllegalStateException("Regions have not been set: " + this);
return regions;
}

View File

@ -35,7 +35,8 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
public class AnimationStateTest extends ApplicationAdapter {
SpriteBatch batch;
ShapeRenderer renderer;
SkeletonRenderer renderer;
SkeletonRendererDebug debugRenderer;
TextureAtlas atlas;
Skeleton skeleton;
@ -44,11 +45,12 @@ public class AnimationStateTest extends ApplicationAdapter {
public void create () {
batch = new SpriteBatch();
renderer = new ShapeRenderer();
renderer = new SkeletonRenderer();
debugRenderer = new SkeletonRendererDebug();
atlas = new TextureAtlas(Gdx.files.internal("spineboy.atlas"));
SkeletonJson json = new SkeletonJson(atlas);
SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("spineboy-skeleton.json"));
SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("spineboy.json"));
// Define mixing between animations.
AnimationStateData stateData = new AnimationStateData(skeletonData);
@ -71,7 +73,6 @@ public class AnimationStateTest extends ApplicationAdapter {
state.update(Gdx.graphics.getDeltaTime() / 3);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.begin();
state.apply(skeleton);
if (state.getAnimation().getName().equals("walk")) {
@ -81,14 +82,17 @@ public class AnimationStateTest extends ApplicationAdapter {
if (state.getTime() > 1) state.setAnimation("walk", true);
}
skeleton.updateWorldTransform();
skeleton.draw(batch);
batch.begin();
renderer.draw(batch, skeleton);
batch.end();
debugRenderer.draw(batch, skeleton);
}
public void resize (int width, int height) {
batch.getProjectionMatrix().setToOrtho2D(0, 0, width, height);
renderer.setProjectionMatrix(batch.getProjectionMatrix());
debugRenderer.getShapeRenderer().setProjectionMatrix(batch.getProjectionMatrix());
}
public void dispose () {

View File

@ -38,7 +38,8 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
public class MixTest extends ApplicationAdapter {
SpriteBatch batch;
float time;
ShapeRenderer renderer;
SkeletonRenderer renderer;
SkeletonRendererDebug debugRenderer;
SkeletonData skeletonData;
Skeleton skeleton;
@ -47,7 +48,8 @@ public class MixTest extends ApplicationAdapter {
public void create () {
batch = new SpriteBatch();
renderer = new ShapeRenderer();
renderer = new SkeletonRenderer();
debugRenderer = new SkeletonRendererDebug();
final String name = "spineboy";
@ -56,7 +58,7 @@ public class MixTest extends ApplicationAdapter {
if (true) {
SkeletonJson json = new SkeletonJson(atlas);
// json.setScale(2);
skeletonData = json.readSkeletonData(Gdx.files.internal(name + "-skeleton.json"));
skeletonData = json.readSkeletonData(Gdx.files.internal(name + ".json"));
} else {
SkeletonBinary binary = new SkeletonBinary(atlas);
// binary.setScale(2);
@ -94,8 +96,6 @@ public class MixTest extends ApplicationAdapter {
root.setX(root.getX() + speed * delta);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.setColor(Color.GRAY);
// This shows how to manage state manually. See AnimationStatesTest.
if (time > total) {
@ -123,16 +123,17 @@ public class MixTest extends ApplicationAdapter {
skeleton.updateWorldTransform();
skeleton.update(Gdx.graphics.getDeltaTime());
skeleton.draw(batch);
batch.begin();
renderer.draw(batch, skeleton);
batch.end();
// skeleton.drawDebug(renderer);
debugRenderer.draw(batch, skeleton);
}
public void resize (int width, int height) {
batch.getProjectionMatrix().setToOrtho2D(0, 0, width, height);
renderer.setProjectionMatrix(batch.getProjectionMatrix());
debugRenderer.getShapeRenderer().setProjectionMatrix(batch.getProjectionMatrix());
}
public static void main (String[] args) throws Exception {

View File

@ -46,7 +46,8 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
public class SkeletonTest extends ApplicationAdapter {
SpriteBatch batch;
float time;
ShapeRenderer renderer;
SkeletonRenderer renderer;
SkeletonRendererDebug debugRenderer;
SkeletonData skeletonData;
Skeleton skeleton;
@ -54,7 +55,8 @@ public class SkeletonTest extends ApplicationAdapter {
public void create () {
batch = new SpriteBatch();
renderer = new ShapeRenderer();
renderer = new SkeletonRenderer();
debugRenderer = new SkeletonRendererDebug();
final String name = "goblins"; // "spineboy";
@ -118,22 +120,21 @@ public class SkeletonTest extends ApplicationAdapter {
root.setX(x);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.setColor(Color.GRAY);
animation.apply(skeleton, time, true);
skeleton.updateWorldTransform();
skeleton.update(Gdx.graphics.getDeltaTime());
skeleton.draw(batch);
batch.begin();
renderer.draw(batch, skeleton);
batch.end();
skeleton.drawDebug(renderer);
debugRenderer.draw(batch, skeleton);
}
public void resize (int width, int height) {
batch.getProjectionMatrix().setToOrtho2D(0, 0, width, height);
renderer.setProjectionMatrix(batch.getProjectionMatrix());
debugRenderer.getShapeRenderer().setProjectionMatrix(batch.getProjectionMatrix());
}
public static void main (String[] args) throws Exception {

View File

@ -61,6 +61,7 @@ public class SkeletonComponent : MonoBehaviour {
skeleton = new Skeleton(skeletonDataAsset.GetSkeletonData(false));
}
public void Update () {
// Clear fields if missing information to render.
if (skeletonDataAsset == null || skeletonDataAsset.GetSkeletonData(false) == null) {
@ -83,6 +84,7 @@ public class SkeletonComponent : MonoBehaviour {
state.Loop = loop;
// Apply animation.
skeleton.Update(Time.deltaTime * timeScale);
state.Update(Time.deltaTime * timeScale);
state.Apply(skeleton);
skeleton.UpdateWorldTransform();