Эх сурвалжийг харах

JSON and binary loading for sequences.

Nathan Sweet 4 жил өмнө
parent
commit
515d238886

+ 83 - 53
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java

@@ -63,6 +63,7 @@ import com.esotericsoftware.spine.Animation.RotateTimeline;
 import com.esotericsoftware.spine.Animation.ScaleTimeline;
 import com.esotericsoftware.spine.Animation.ScaleXTimeline;
 import com.esotericsoftware.spine.Animation.ScaleYTimeline;
+import com.esotericsoftware.spine.Animation.SequenceTimeline;
 import com.esotericsoftware.spine.Animation.ShearTimeline;
 import com.esotericsoftware.spine.Animation.ShearXTimeline;
 import com.esotericsoftware.spine.Animation.ShearYTimeline;
@@ -85,6 +86,8 @@ import com.esotericsoftware.spine.attachments.MeshAttachment;
 import com.esotericsoftware.spine.attachments.PathAttachment;
 import com.esotericsoftware.spine.attachments.PointAttachment;
 import com.esotericsoftware.spine.attachments.RegionAttachment;
+import com.esotericsoftware.spine.attachments.Sequence;
+import com.esotericsoftware.spine.attachments.Sequence.SequenceMode;
 import com.esotericsoftware.spine.attachments.VertexAttachment;
 
 /** Loads skeleton data in the Spine binary format.
@@ -111,6 +114,9 @@ public class SkeletonBinary extends SkeletonLoader {
 	static public final int SLOT_RGB2 = 4;
 	static public final int SLOT_ALPHA = 5;
 
+	static public final int ATTACHMENT_DEFORM = 0;
+	static public final int ATTACHMENT_SEQUENCE = 1;
+
 	static public final int PATH_POSITION = 0;
 	static public final int PATH_SPACING = 1;
 	static public final int PATH_MIX = 2;
@@ -302,7 +308,7 @@ public class SkeletonBinary extends SkeletonLoader {
 				if (parent == null) throw new SerializationException("Parent mesh not found: " + linkedMesh.parent);
 				linkedMesh.mesh.setTimelineAttachment(linkedMesh.inheritTimelines ? (VertexAttachment)parent : linkedMesh.mesh);
 				linkedMesh.mesh.setParentMesh((MeshAttachment)parent);
-				linkedMesh.mesh.updateRegion();
+				if (linkedMesh.mesh.getSequence() == null) linkedMesh.mesh.updateRegion();
 			}
 			linkedMeshes.clear();
 
@@ -395,11 +401,10 @@ public class SkeletonBinary extends SkeletonLoader {
 			float width = input.readFloat();
 			float height = input.readFloat();
 			int color = input.readInt();
-
-			// BOZO! - Read sequence.
+			Sequence sequence = readSequence(input);
 
 			if (path == null) path = name;
-			RegionAttachment region = attachmentLoader.newRegionAttachment(skin, name, path, null);
+			RegionAttachment region = attachmentLoader.newRegionAttachment(skin, name, path, sequence);
 			if (region == null) return null;
 			region.setPath(path);
 			region.setX(x * scale);
@@ -410,7 +415,8 @@ public class SkeletonBinary extends SkeletonLoader {
 			region.setWidth(width * scale);
 			region.setHeight(height * scale);
 			Color.rgba8888ToColor(region.getColor(), color);
-			region.updateRegion();
+			region.setSequence(sequence);
+			if (sequence == null) region.updateRegion();
 			return region;
 		}
 		case boundingbox: {
@@ -434,6 +440,7 @@ public class SkeletonBinary extends SkeletonLoader {
 			short[] triangles = readShortArray(input);
 			Vertices vertices = readVertices(input, vertexCount);
 			int hullLength = input.readInt(true);
+			Sequence sequence = readSequence(input);
 			short[] edges = null;
 			float width = 0, height = 0;
 			if (nonessential) {
@@ -442,10 +449,8 @@ public class SkeletonBinary extends SkeletonLoader {
 				height = input.readFloat();
 			}
 
-			// BOZO! - Read sequence.
-
 			if (path == null) path = name;
-			MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path, null);
+			MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path, sequence);
 			if (mesh == null) return null;
 			mesh.setPath(path);
 			Color.rgba8888ToColor(mesh.getColor(), color);
@@ -454,8 +459,9 @@ public class SkeletonBinary extends SkeletonLoader {
 			mesh.setWorldVerticesLength(vertexCount << 1);
 			mesh.setTriangles(triangles);
 			mesh.setRegionUVs(uvs);
-			mesh.updateRegion();
+			if (sequence == null) mesh.updateRegion();
 			mesh.setHullLength(hullLength << 1);
+			mesh.setSequence(sequence);
 			if (nonessential) {
 				mesh.setEdges(edges);
 				mesh.setWidth(width * scale);
@@ -469,19 +475,19 @@ public class SkeletonBinary extends SkeletonLoader {
 			String skinName = input.readStringRef();
 			String parent = input.readStringRef();
 			boolean inheritTimelines = input.readBoolean();
+			Sequence sequence = readSequence(input);
 			float width = 0, height = 0;
 			if (nonessential) {
 				width = input.readFloat();
 				height = input.readFloat();
 			}
 
-			// BOZO! - Read sequence.
-
 			if (path == null) path = name;
-			MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path, null);
+			MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path, sequence);
 			if (mesh == null) return null;
 			mesh.setPath(path);
 			Color.rgba8888ToColor(mesh.getColor(), color);
+			mesh.setSequence(sequence);
 			if (nonessential) {
 				mesh.setWidth(width * scale);
 				mesh.setHeight(height * scale);
@@ -542,6 +548,15 @@ public class SkeletonBinary extends SkeletonLoader {
 		return null;
 	}
 
+	private Sequence readSequence (SkeletonInput input) throws IOException {
+		if (!input.readBoolean()) return null;
+		Sequence sequence = new Sequence(input.readInt(true));
+		sequence.setStart(input.readInt(true));
+		sequence.setDigits(input.readInt(true));
+		sequence.setSetupIndex(input.readInt(true));
+		return sequence;
+	}
+
 	private Vertices readVertices (SkeletonInput input, int vertexCount) throws IOException {
 		float scale = this.scale;
 		int verticesLength = vertexCount << 1;
@@ -751,7 +766,6 @@ public class SkeletonBinary extends SkeletonLoader {
 						a = a2;
 					}
 					timelines.add(timeline);
-					break;
 				}
 			}
 		}
@@ -897,57 +911,73 @@ public class SkeletonBinary extends SkeletonLoader {
 			}
 		}
 
-		// Deform timelines.
+		// Attachment timelines.
 		for (int i = 0, n = input.readInt(true); i < n; i++) {
 			Skin skin = skeletonData.skins.get(input.readInt(true));
 			for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) {
 				int slotIndex = input.readInt(true);
 				for (int iii = 0, nnn = input.readInt(true); iii < nnn; iii++) {
 					String attachmentName = input.readStringRef();
-					VertexAttachment attachment = (VertexAttachment)skin.getAttachment(slotIndex, attachmentName);
-					if (attachment == null) throw new SerializationException("Vertex attachment not found: " + attachmentName);
-					boolean weighted = attachment.getBones() != null;
-					float[] vertices = attachment.getVertices();
-					int deformLength = weighted ? (vertices.length / 3) << 1 : vertices.length;
-
-					int frameCount = input.readInt(true), frameLast = frameCount - 1;
-					DeformTimeline timeline = new DeformTimeline(frameCount, input.readInt(true), slotIndex, attachment);
-
-					float time = input.readFloat();
-					for (int frame = 0, bezier = 0;; frame++) {
-						float[] deform;
-						int end = input.readInt(true);
-						if (end == 0)
-							deform = weighted ? new float[deformLength] : vertices;
-						else {
-							deform = new float[deformLength];
-							int start = input.readInt(true);
-							end += start;
-							if (scale == 1) {
-								for (int v = start; v < end; v++)
-									deform[v] = input.readFloat();
-							} else {
-								for (int v = start; v < end; v++)
-									deform[v] = input.readFloat() * scale;
+					Attachment attachment = skin.getAttachment(slotIndex, attachmentName);
+					if (attachment == null) throw new SerializationException("Timeline attachment not found: " + attachmentName);
+
+					int timelineType = input.readByte(), frameCount = input.readInt(true), frameLast = frameCount - 1;
+					switch (timelineType) {
+					case ATTACHMENT_DEFORM: {
+						VertexAttachment vertexAttachment = (VertexAttachment)attachment;
+						boolean weighted = vertexAttachment.getBones() != null;
+						float[] vertices = vertexAttachment.getVertices();
+						int deformLength = weighted ? (vertices.length / 3) << 1 : vertices.length;
+
+						DeformTimeline timeline = new DeformTimeline(frameCount, input.readInt(true), slotIndex, vertexAttachment);
+
+						float time = input.readFloat();
+						for (int frame = 0, bezier = 0;; frame++) {
+							float[] deform;
+							int end = input.readInt(true);
+							if (end == 0)
+								deform = weighted ? new float[deformLength] : vertices;
+							else {
+								deform = new float[deformLength];
+								int start = input.readInt(true);
+								end += start;
+								if (scale == 1) {
+									for (int v = start; v < end; v++)
+										deform[v] = input.readFloat();
+								} else {
+									for (int v = start; v < end; v++)
+										deform[v] = input.readFloat() * scale;
+								}
+								if (!weighted) {
+									for (int v = 0, vn = deform.length; v < vn; v++)
+										deform[v] += vertices[v];
+								}
 							}
-							if (!weighted) {
-								for (int v = 0, vn = deform.length; v < vn; v++)
-									deform[v] += vertices[v];
+							timeline.setFrame(frame, time, deform);
+							if (frame == frameLast) break;
+							float time2 = input.readFloat();
+							switch (input.readByte()) {
+							case CURVE_STEPPED:
+								timeline.setStepped(frame);
+								break;
+							case CURVE_BEZIER:
+								setBezier(input, timeline, bezier++, frame, 0, time, time2, 0, 1, 1);
 							}
+							time = time2;
 						}
-						timeline.setFrame(frame, time, deform);
-						if (frame == frameLast) break;
-						float time2 = input.readFloat();
-						switch (input.readByte()) {
-						case CURVE_STEPPED:
-							timeline.setStepped(frame);
-							break;
-						case CURVE_BEZIER:
-							setBezier(input, timeline, bezier++, frame, 0, time, time2, 0, 1, 1);
+						timelines.add(timeline);
+						break;
+					}
+					case ATTACHMENT_SEQUENCE:
+						SequenceTimeline timeline = new SequenceTimeline(frameCount, slotIndex, attachment);
+						for (int frame = 0; frame < frameCount; frame++) {
+							float time = input.readFloat();
+							int modeAndIndex = input.readInt();
+							timeline.setFrame(frame, time, SequenceMode.values[modeAndIndex & 0xf], modeAndIndex >> 4,
+								input.readFloat());
 						}
-						time = time2;
+						timelines.add(timeline);
 					}
-					timelines.add(timeline);
 				}
 			}
 		}

+ 76 - 44
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java

@@ -41,6 +41,7 @@ import com.badlogic.gdx.utils.FloatArray;
 import com.badlogic.gdx.utils.IntArray;
 import com.badlogic.gdx.utils.JsonReader;
 import com.badlogic.gdx.utils.JsonValue;
+import com.badlogic.gdx.utils.Null;
 import com.badlogic.gdx.utils.SerializationException;
 
 import com.esotericsoftware.spine.Animation.AlphaTimeline;
@@ -63,6 +64,7 @@ import com.esotericsoftware.spine.Animation.RotateTimeline;
 import com.esotericsoftware.spine.Animation.ScaleTimeline;
 import com.esotericsoftware.spine.Animation.ScaleXTimeline;
 import com.esotericsoftware.spine.Animation.ScaleYTimeline;
+import com.esotericsoftware.spine.Animation.SequenceTimeline;
 import com.esotericsoftware.spine.Animation.ShearTimeline;
 import com.esotericsoftware.spine.Animation.ShearXTimeline;
 import com.esotericsoftware.spine.Animation.ShearYTimeline;
@@ -84,6 +86,8 @@ import com.esotericsoftware.spine.attachments.MeshAttachment;
 import com.esotericsoftware.spine.attachments.PathAttachment;
 import com.esotericsoftware.spine.attachments.PointAttachment;
 import com.esotericsoftware.spine.attachments.RegionAttachment;
+import com.esotericsoftware.spine.attachments.Sequence;
+import com.esotericsoftware.spine.attachments.Sequence.SequenceMode;
 import com.esotericsoftware.spine.attachments.VertexAttachment;
 
 /** Loads skeleton data in the Spine JSON format.
@@ -323,7 +327,7 @@ public class SkeletonJson extends SkeletonLoader {
 			if (parent == null) throw new SerializationException("Parent mesh not found: " + linkedMesh.parent);
 			linkedMesh.mesh.setTimelineAttachment(linkedMesh.inheritTimelines ? (VertexAttachment)parent : linkedMesh.mesh);
 			linkedMesh.mesh.setParentMesh((MeshAttachment)parent);
-			linkedMesh.mesh.updateRegion();
+			if (linkedMesh.mesh.getSequence() == null) linkedMesh.mesh.updateRegion();
 		}
 		linkedMeshes.clear();
 
@@ -366,8 +370,8 @@ public class SkeletonJson extends SkeletonLoader {
 		switch (AttachmentType.valueOf(map.getString("type", AttachmentType.region.name()))) {
 		case region: {
 			String path = map.getString("path", name);
-			// BOZO! - Read sequence.
-			RegionAttachment region = attachmentLoader.newRegionAttachment(skin, name, path, null);
+			Sequence sequence = readSequence(map.get("sequence"));
+			RegionAttachment region = attachmentLoader.newRegionAttachment(skin, name, path, sequence);
 			if (region == null) return null;
 			region.setPath(path);
 			region.setX(map.getFloat("x", 0) * scale);
@@ -377,11 +381,12 @@ public class SkeletonJson extends SkeletonLoader {
 			region.setRotation(map.getFloat("rotation", 0));
 			region.setWidth(map.getFloat("width") * scale);
 			region.setHeight(map.getFloat("height") * scale);
+			region.setSequence(sequence);
 
 			String color = map.getString("color", null);
 			if (color != null) Color.valueOf(color, region.getColor());
 
-			region.updateRegion();
+			if (region.getSequence() == null) region.updateRegion();
 			return region;
 		}
 		case boundingbox: {
@@ -396,8 +401,8 @@ public class SkeletonJson extends SkeletonLoader {
 		case mesh:
 		case linkedmesh: {
 			String path = map.getString("path", name);
-			// BOZO! - Read sequence.
-			MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path, null);
+			Sequence sequence = readSequence(map.get("sequence"));
+			MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path, sequence);
 			if (mesh == null) return null;
 			mesh.setPath(path);
 
@@ -406,6 +411,7 @@ public class SkeletonJson extends SkeletonLoader {
 
 			mesh.setWidth(map.getFloat("width", 0) * scale);
 			mesh.setHeight(map.getFloat("height", 0) * scale);
+			mesh.setSequence(sequence);
 
 			String parent = map.getString("parent", null);
 			if (parent != null) {
@@ -418,7 +424,7 @@ public class SkeletonJson extends SkeletonLoader {
 			readVertices(map, mesh, uvs.length);
 			mesh.setTriangles(map.require("triangles").asShortArray());
 			mesh.setRegionUVs(uvs);
-			mesh.updateRegion();
+			if (mesh.getSequence() == null) mesh.updateRegion();
 
 			if (map.has("hull")) mesh.setHullLength(map.require("hull").asInt() << 1);
 			if (map.has("edges")) mesh.setEdges(map.require("edges").asShortArray());
@@ -474,6 +480,15 @@ public class SkeletonJson extends SkeletonLoader {
 		return null;
 	}
 
+	private Sequence readSequence (@Null JsonValue map) {
+		if (map == null) return null;
+		Sequence sequence = new Sequence(map.getInt("count"));
+		sequence.setStart(map.getInt("start", 1));
+		sequence.setDigits(map.getInt("digits", 0));
+		sequence.setSetupIndex(map.getInt("setup", 0));
+		return sequence;
+	}
+
 	private void readVertices (JsonValue map, VertexAttachment attachment, int verticesLength) {
 		attachment.setWorldVerticesLength(verticesLength);
 		float[] vertices = map.require("vertices").asFloatArray();
@@ -862,8 +877,8 @@ public class SkeletonJson extends SkeletonLoader {
 			}
 		}
 
-		// Deform timelines.
-		for (JsonValue deformMap = map.getChild("deform"); deformMap != null; deformMap = deformMap.next) {
+		// Attachment timelines.
+		for (JsonValue deformMap = map.getChild("attachments"); deformMap != null; deformMap = deformMap.next) {
 			Skin skin = skeletonData.findSkin(deformMap.name);
 			if (skin == null) throw new SerializationException("Skin not found: " + deformMap.name);
 			for (JsonValue slotMap = deformMap.child; slotMap != null; slotMap = slotMap.next) {
@@ -873,46 +888,63 @@ public class SkeletonJson extends SkeletonLoader {
 					JsonValue keyMap = timelineMap.child;
 					if (keyMap == null) continue;
 
-					VertexAttachment attachment = (VertexAttachment)skin.getAttachment(slot.index, timelineMap.name);
-					if (attachment == null) throw new SerializationException("Deform attachment not found: " + timelineMap.name);
-					boolean weighted = attachment.getBones() != null;
-					float[] vertices = attachment.getVertices();
-					int deformLength = weighted ? (vertices.length / 3) << 1 : vertices.length;
-
-					DeformTimeline timeline = new DeformTimeline(timelineMap.size, timelineMap.size, slot.index, attachment);
-					float time = keyMap.getFloat("time", 0);
-					for (int frame = 0, bezier = 0;; frame++) {
-						float[] deform;
-						JsonValue verticesValue = keyMap.get("vertices");
-						if (verticesValue == null)
-							deform = weighted ? new float[deformLength] : vertices;
-						else {
-							deform = new float[deformLength];
-							int start = keyMap.getInt("offset", 0);
-							arraycopy(verticesValue.asFloatArray(), 0, deform, start, verticesValue.size);
-							if (scale != 1) {
-								for (int i = start, n = i + verticesValue.size; i < n; i++)
-									deform[i] *= scale;
+					Attachment attachment = skin.getAttachment(slot.index, timelineMap.name);
+					if (attachment == null) throw new SerializationException("Timeline attachment not found: " + timelineMap.name);
+
+					int frames = keyMap.size;
+					String timelineName = keyMap.name;
+					keyMap = keyMap.child;
+					if (timelineName.equals("deform")) {
+						VertexAttachment vertexAttachment = (VertexAttachment)attachment;
+						boolean weighted = vertexAttachment.getBones() != null;
+						float[] vertices = vertexAttachment.getVertices();
+						int deformLength = weighted ? (vertices.length / 3) << 1 : vertices.length;
+
+						DeformTimeline timeline = new DeformTimeline(frames, frames, slot.index, vertexAttachment);
+						float time = keyMap.getFloat("time", 0);
+						for (int frame = 0, bezier = 0;; frame++) {
+							float[] deform;
+							JsonValue verticesValue = keyMap.get("vertices");
+							if (verticesValue == null)
+								deform = weighted ? new float[deformLength] : vertices;
+							else {
+								deform = new float[deformLength];
+								int start = keyMap.getInt("offset", 0);
+								arraycopy(verticesValue.asFloatArray(), 0, deform, start, verticesValue.size);
+								if (scale != 1) {
+									for (int i = start, n = i + verticesValue.size; i < n; i++)
+										deform[i] *= scale;
+								}
+								if (!weighted) {
+									for (int i = 0; i < deformLength; i++)
+										deform[i] += vertices[i];
+								}
 							}
-							if (!weighted) {
-								for (int i = 0; i < deformLength; i++)
-									deform[i] += vertices[i];
+
+							timeline.setFrame(frame, time, deform);
+							JsonValue nextMap = keyMap.next;
+							if (nextMap == null) {
+								timeline.shrink(bezier);
+								break;
 							}
+							float time2 = nextMap.getFloat("time", 0);
+							JsonValue curve = keyMap.get("curve");
+							if (curve != null) bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, 0, 1, 1);
+							time = time2;
+							keyMap = nextMap;
 						}
-
-						timeline.setFrame(frame, time, deform);
-						JsonValue nextMap = keyMap.next;
-						if (nextMap == null) {
-							timeline.shrink(bezier);
-							break;
+						timelines.add(timeline);
+					} else if (timelineName.equals("sequence")) {
+						SequenceTimeline timeline = new SequenceTimeline(frames, slot.index, attachment);
+						float lastDelay = 0;
+						for (int frame = 0; keyMap != null; keyMap = keyMap.next, frame++) {
+							float delay = keyMap.getFloat("delay", lastDelay);
+							timeline.setFrame(frame, keyMap.getFloat("time", 0), SequenceMode.valueOf(keyMap.getString("mode", "stop")),
+								keyMap.getInt("index", 0), delay);
+							delay = lastDelay;
 						}
-						float time2 = nextMap.getFloat("time", 0);
-						JsonValue curve = keyMap.get("curve");
-						if (curve != null) bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, 0, 1, 1);
-						time = time2;
-						keyMap = nextMap;
+						timelines.add(timeline);
 					}
-					timelines.add(timeline);
 				}
 			}
 		}

+ 1 - 2
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/MeshAttachment.java

@@ -95,8 +95,7 @@ public class MeshAttachment extends VertexAttachment implements HasTextureRegion
 		this.region = region;
 	}
 
-	public TextureRegion getRegion () {
-		if (region == null) throw new IllegalStateException("Region has not been set: " + this);
+	public @Null TextureRegion getRegion () {
 		return region;
 	}
 

+ 1 - 2
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionAttachment.java

@@ -156,8 +156,7 @@ public class RegionAttachment extends Attachment implements HasTextureRegion {
 		this.region = region;
 	}
 
-	public TextureRegion getRegion () {
-		if (region == null) throw new IllegalStateException("Region has not been set: " + name);
+	public @Null TextureRegion getRegion () {
 		return region;
 	}