Browse Source

Merge branch '3.6' into 3.7-beta

badlogic 7 years ago
parent
commit
c24990a1c4

+ 1 - 0
CHANGELOG.md

@@ -257,6 +257,7 @@
  * Fixed renderer to work with 3.6 changes. Two color tinting is not supported.
  * Added clipping support
  * Added `VertexEffect` interface, instances of which can be set on `SkeletonMesh`. Allows to modify vertices before submitting them to GPU. See `SwirlEffect`, `JitterEffect`.
+ * Added support for multi-page atlases
 
 ### Widget backend
  * Fixed WebGL context loss (see WebGL backend changes). Enabled automatically.

+ 1 - 1
spine-libgdx/spine-libgdx/pom.xml

@@ -10,7 +10,7 @@
 	<groupId>com.esotericsoftware.spine</groupId>
 	<artifactId>spine-libgdx</artifactId>
 	<packaging>jar</packaging>
-	<version>3.7.0.1-SNAPSHOT</version>
+	<version>3.6.51.2-SNAPSHOT</version>
 
 	<name>spine-libgdx</name>
 	<description>Spine Runtime for libGDX</description>

+ 4 - 4
spine-ts/README.md

@@ -20,11 +20,11 @@ The Spine Runtimes are developed with the intent to be used with data exported f
 
 spine-ts works with data exported from Spine 3.6.xx.
 
-spine-ts WebGL & Widget backends supports all Spine features. 
+spine-ts WebGL & Widget backends supports all Spine features.
 
-spine-ts Canvas does not support color tinting, mesh attachments and clipping. Only the alpha channel from tint colors is applied. Experimental support for mesh attachments can be enabled by setting `spine.canvas.SkeletonRenderer.useTriangleRendering` to true. Note that this method is slow and may lead to artifacts on some browsers. 
+spine-ts Canvas does not support color tinting, mesh attachments and clipping. Only the alpha channel from tint colors is applied. Experimental support for mesh attachments can be enabled by setting `spine.canvas.SkeletonRenderer.useTriangleRendering` to true. Note that this method is slow and may lead to artifacts on some browsers.
 
-spine-ts THREE.JS does not support color tinting, blend modes and clipping. The THREE.JS backend provides `SkeletonMesh.zOffset` to avoid z-fighting. Adjust to your near/far plane settings.
+spine-ts THREE.JS does not support two color tinting & blend modes. The THREE.JS backend provides `SkeletonMesh.zOffset` to avoid z-fighting. Adjust to your near/far plane settings.
 
 spine-ts does not yet support loading the binary format.
 
@@ -115,7 +115,7 @@ You can disable two-color tinting like this:
 // If you use SceneRenderer, disable two-color tinting via the last constructor argument
 var sceneRenderer = new spine.SceneRenderer(canvas, gl, false);
 
-// If you use SkeletonRenderer and PolygonBatcher directly, 
+// If you use SkeletonRenderer and PolygonBatcher directly,
 // disable two-color tinting in the respective constructor
 // and use the shader returned by Shader.newColoredTextured()
 // instead of Shader.newTwoColoredTextured()

+ 12 - 5
spine-ts/build/spine-all.d.ts

@@ -1703,22 +1703,26 @@ declare module spine.threejs {
 	}
 }
 declare module spine.threejs {
-	class MeshBatcher {
-		mesh: THREE.Mesh;
+	class MeshBatcher extends THREE.Mesh {
 		private static VERTEX_SIZE;
 		private vertexBuffer;
 		private vertices;
 		private verticesLength;
 		private indices;
 		private indicesLength;
-		constructor(mesh: THREE.Mesh, maxVertices?: number);
+		constructor(maxVertices?: number);
+		clear(): void;
 		begin(): void;
+		canBatch(verticesLength: number, indicesLength: number): boolean;
 		batch(vertices: ArrayLike<number>, verticesLength: number, indices: ArrayLike<number>, indicesLength: number, z?: number): void;
 		end(): void;
 	}
 }
 declare module spine.threejs {
-	class SkeletonMesh extends THREE.Mesh {
+	class SkeletonMeshMaterial extends THREE.ShaderMaterial {
+		constructor();
+	}
+	class SkeletonMesh extends THREE.Object3D {
 		tempPos: Vector2;
 		tempUv: Vector2;
 		tempLight: Color;
@@ -1727,7 +1731,8 @@ declare module spine.threejs {
 		state: AnimationState;
 		zOffset: number;
 		vertexEffect: VertexEffect;
-		private batcher;
+		private batches;
+		private nextBatchIndex;
 		private clipper;
 		static QUAD_TRIANGLES: number[];
 		static VERTEX_SIZE: number;
@@ -1735,6 +1740,8 @@ declare module spine.threejs {
 		private tempColor;
 		constructor(skeletonData: SkeletonData);
 		update(deltaTime: number): void;
+		private clearBatches();
+		private nextBatch();
 		private updateGeometry();
 	}
 }

+ 113 - 33
spine-ts/build/spine-all.js

@@ -2131,6 +2131,7 @@ var spine;
 			path = this.pathPrefix + path;
 			this.toLoad++;
 			AssetManager.downloadText(path, function (atlasData) {
+				var pagesLoaded = { count: 0 };
 				var atlasPages = new Array();
 				try {
 					var atlas = new spine.TextureAtlas(atlasData, function (path) {
@@ -2151,11 +2152,10 @@ var spine;
 					return;
 				}
 				var _loop_1 = function (atlasPage) {
-					var pagesLoaded = 0;
 					var pageLoadError = false;
 					_this.loadTexture(atlasPage, function (imagePath, image) {
-						pagesLoaded++;
-						if (pagesLoaded == atlasPages.length) {
+						pagesLoaded.count++;
+						if (pagesLoaded.count == atlasPages.length) {
 							if (!pageLoadError) {
 								try {
 									var atlas = new spine.TextureAtlas(atlasData, function (path) {
@@ -2186,8 +2186,8 @@ var spine;
 						}
 					}, function (imagePath, errorMessage) {
 						pageLoadError = true;
-						pagesLoaded++;
-						if (pagesLoaded == atlasPages.length) {
+						pagesLoaded.count++;
+						if (pagesLoaded.count == atlasPages.length) {
 							_this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path;
 							if (error)
 								error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path);
@@ -9563,18 +9563,19 @@ var spine;
 (function (spine) {
 	var threejs;
 	(function (threejs) {
-		var MeshBatcher = (function () {
-			function MeshBatcher(mesh, maxVertices) {
+		var MeshBatcher = (function (_super) {
+			__extends(MeshBatcher, _super);
+			function MeshBatcher(maxVertices) {
 				if (maxVertices === void 0) { maxVertices = 10920; }
-				this.verticesLength = 0;
-				this.indicesLength = 0;
+				var _this = _super.call(this) || this;
+				_this.verticesLength = 0;
+				_this.indicesLength = 0;
 				if (maxVertices > 10920)
 					throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices);
-				var vertices = this.vertices = new Float32Array(maxVertices * MeshBatcher.VERTEX_SIZE);
-				var indices = this.indices = new Uint16Array(maxVertices * 3);
-				this.mesh = mesh;
+				var vertices = _this.vertices = new Float32Array(maxVertices * MeshBatcher.VERTEX_SIZE);
+				var indices = _this.indices = new Uint16Array(maxVertices * 3);
 				var geo = new THREE.BufferGeometry();
-				var vertexBuffer = this.vertexBuffer = new THREE.InterleavedBuffer(vertices, MeshBatcher.VERTEX_SIZE);
+				var vertexBuffer = _this.vertexBuffer = new THREE.InterleavedBuffer(vertices, MeshBatcher.VERTEX_SIZE);
 				vertexBuffer.dynamic = true;
 				geo.addAttribute("position", new THREE.InterleavedBufferAttribute(vertexBuffer, 3, 0, false));
 				geo.addAttribute("color", new THREE.InterleavedBufferAttribute(vertexBuffer, 4, 3, false));
@@ -9583,12 +9584,27 @@ var spine;
 				geo.getIndex().dynamic = true;
 				geo.drawRange.start = 0;
 				geo.drawRange.count = 0;
-				mesh.geometry = geo;
+				_this.geometry = geo;
+				_this.material = new threejs.SkeletonMeshMaterial();
+				return _this;
 			}
+			MeshBatcher.prototype.clear = function () {
+				var geo = this.geometry;
+				geo.drawRange.start = 0;
+				geo.drawRange.count = 0;
+				this.material.uniforms.map.value = null;
+			};
 			MeshBatcher.prototype.begin = function () {
 				this.verticesLength = 0;
 				this.indicesLength = 0;
 			};
+			MeshBatcher.prototype.canBatch = function (verticesLength, indicesLength) {
+				if (this.indicesLength + indicesLength >= this.indices.byteLength / 2)
+					return false;
+				if (this.verticesLength + verticesLength >= this.vertices.byteLength / 2)
+					return false;
+				return true;
+			};
 			MeshBatcher.prototype.batch = function (vertices, verticesLength, indices, indicesLength, z) {
 				if (z === void 0) { z = 0; }
 				var indexStart = this.verticesLength / MeshBatcher.VERTEX_SIZE;
@@ -9616,7 +9632,7 @@ var spine;
 				this.vertexBuffer.needsUpdate = true;
 				this.vertexBuffer.updateRange.offset = 0;
 				this.vertexBuffer.updateRange.count = this.verticesLength;
-				var geo = this.mesh.geometry;
+				var geo = this.geometry;
 				geo.getIndex().needsUpdate = true;
 				geo.getIndex().updateRange.offset = 0;
 				geo.getIndex().updateRange.count = this.indicesLength;
@@ -9624,7 +9640,7 @@ var spine;
 				geo.drawRange.count = this.indicesLength;
 			};
 			return MeshBatcher;
-		}());
+		}(THREE.Mesh));
 		MeshBatcher.VERTEX_SIZE = 9;
 		threejs.MeshBatcher = MeshBatcher;
 	})(threejs = spine.threejs || (spine.threejs = {}));
@@ -9633,6 +9649,29 @@ var spine;
 (function (spine) {
 	var threejs;
 	(function (threejs) {
+		var SkeletonMeshMaterial = (function (_super) {
+			__extends(SkeletonMeshMaterial, _super);
+			function SkeletonMeshMaterial() {
+				var _this = this;
+				var vertexShader = "\n\t\t\t\tattribute vec4 color;\n\t\t\t\tvarying vec2 vUv;\n\t\t\t\tvarying vec4 vColor;\n\t\t\t\tvoid main() {\n\t\t\t\t\tvUv = uv;\n\t\t\t\t\tvColor = color;\n\t\t\t\t\tgl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);\n\t\t\t\t}\n\t\t\t";
+				var fragmentShader = "\n\t\t\t\tuniform sampler2D map;\n\t\t\t\tvarying vec2 vUv;\n\t\t\t\tvarying vec4 vColor;\n\t\t\t\tvoid main(void) {\n\t\t\t\t\tgl_FragColor = texture2D(map, vUv)*vColor;\n\t\t\t\t}\n\t\t\t";
+				var parameters = {
+					uniforms: {
+						map: { type: "t", value: null }
+					},
+					vertexShader: vertexShader,
+					fragmentShader: fragmentShader,
+					side: THREE.DoubleSide,
+					transparent: true,
+					alphaTest: 0.5
+				};
+				_this = _super.call(this, parameters) || this;
+				return _this;
+			}
+			;
+			return SkeletonMeshMaterial;
+		}(THREE.ShaderMaterial));
+		threejs.SkeletonMeshMaterial = SkeletonMeshMaterial;
 		var SkeletonMesh = (function (_super) {
 			__extends(SkeletonMesh, _super);
 			function SkeletonMesh(skeletonData) {
@@ -9642,17 +9681,14 @@ var spine;
 				_this.tempLight = new spine.Color();
 				_this.tempDark = new spine.Color();
 				_this.zOffset = 0.1;
+				_this.batches = new Array();
+				_this.nextBatchIndex = 0;
 				_this.clipper = new spine.SkeletonClipping();
 				_this.vertices = spine.Utils.newFloatArray(1024);
 				_this.tempColor = new spine.Color();
 				_this.skeleton = new spine.Skeleton(skeletonData);
 				var animData = new spine.AnimationStateData(skeletonData);
 				_this.state = new spine.AnimationState(animData);
-				var material = _this.material = new THREE.MeshBasicMaterial();
-				material.side = THREE.DoubleSide;
-				material.transparent = true;
-				material.alphaTest = 0.5;
-				_this.batcher = new threejs.MeshBatcher(_this);
 				return _this;
 			}
 			SkeletonMesh.prototype.update = function (deltaTime) {
@@ -9663,12 +9699,29 @@ var spine;
 				skeleton.updateWorldTransform();
 				this.updateGeometry();
 			};
+			SkeletonMesh.prototype.clearBatches = function () {
+				for (var i = 0; i < this.batches.length; i++) {
+					this.batches[i].clear();
+					this.batches[i].visible = false;
+				}
+				this.nextBatchIndex = 0;
+			};
+			SkeletonMesh.prototype.nextBatch = function () {
+				if (this.batches.length == this.nextBatchIndex) {
+					var batch_1 = new threejs.MeshBatcher();
+					this.add(batch_1);
+					this.batches.push(batch_1);
+				}
+				var batch = this.batches[this.nextBatchIndex++];
+				batch.visible = true;
+				return batch;
+			};
 			SkeletonMesh.prototype.updateGeometry = function () {
+				this.clearBatches();
 				var tempPos = this.tempPos;
 				var tempUv = this.tempUv;
 				var tempLight = this.tempLight;
 				var tempDark = this.tempDark;
-				var geometry = this.geometry;
 				var numVertices = 0;
 				var verticesLength = 0;
 				var indicesLength = 0;
@@ -9678,8 +9731,8 @@ var spine;
 				var triangles = null;
 				var uvs = null;
 				var drawOrder = this.skeleton.drawOrder;
-				var batcher = this.batcher;
-				batcher.begin();
+				var batch = this.nextBatch();
+				batch.begin();
 				var z = 0;
 				var zOffset = this.zOffset;
 				for (var i = 0, n = drawOrder.length; i < n; i++) {
@@ -9720,17 +9773,16 @@ var spine;
 					else
 						continue;
 					if (texture != null) {
-						if (!this.material.map) {
-							var mat = this.material;
-							mat.map = texture.texture;
-							mat.needsUpdate = true;
-						}
 						var skeleton = slot.bone.skeleton;
 						var skeletonColor = skeleton.color;
 						var slotColor = slot.color;
 						var alpha = skeletonColor.a * slotColor.a * attachmentColor.a;
 						var color = this.tempColor;
 						color.set(skeletonColor.r * slotColor.r * attachmentColor.r, skeletonColor.g * slotColor.g * attachmentColor.g, skeletonColor.b * slotColor.b * attachmentColor.b, alpha);
+						var finalVertices = void 0;
+						var finalVerticesLength = void 0;
+						var finalIndices = void 0;
+						var finalIndicesLength = void 0;
 						if (clipper.isClipping()) {
 							clipper.clipTriangles(vertices, numFloats, triangles, triangles.length, uvs, color, null, false);
 							var clippedVertices = clipper.clippedVertices;
@@ -9756,7 +9808,10 @@ var spine;
 									verts[v + 7] = tempUv.y;
 								}
 							}
-							batcher.batch(clippedVertices, clippedVertices.length, clippedTriangles, clippedTriangles.length, z);
+							finalVertices = clippedVertices;
+							finalVerticesLength = clippedVertices.length;
+							finalIndices = clippedTriangles;
+							finalIndicesLength = clippedTriangles.length;
 						}
 						else {
 							var verts = vertices;
@@ -9790,15 +9845,40 @@ var spine;
 									verts[v + 5] = uvs[u + 1];
 								}
 							}
-							batcher.batch(vertices, numFloats, triangles, triangles.length, z);
+							finalVertices = vertices;
+							finalVerticesLength = numFloats;
+							finalIndices = triangles;
+							finalIndicesLength = triangles.length;
 						}
+						if (finalVerticesLength == 0 || finalIndicesLength == 0)
+							continue;
+						if (!batch.canBatch(finalVerticesLength, finalIndicesLength)) {
+							batch.end();
+							batch = this.nextBatch();
+							batch.begin();
+						}
+						var batchMaterial = batch.material;
+						if (batchMaterial.uniforms.map.value == null) {
+							batchMaterial.uniforms.map.value = texture.texture;
+						}
+						if (batchMaterial.uniforms.map.value != texture.texture) {
+							batch.end();
+							batch = this.nextBatch();
+							batch.begin();
+							batchMaterial = batch.material;
+							batchMaterial.uniforms.map.value = texture.texture;
+						}
+						batchMaterial.needsUpdate = true;
+						batch.batch(finalVertices, finalVerticesLength, finalIndices, finalIndicesLength, z);
 						z += zOffset;
 					}
+					clipper.clipEndWithSlot(slot);
 				}
-				batcher.end();
+				clipper.clipEnd();
+				batch.end();
 			};
 			return SkeletonMesh;
-		}(THREE.Mesh));
+		}(THREE.Object3D));
 		SkeletonMesh.QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
 		SkeletonMesh.VERTEX_SIZE = 2 + 2 + 4;
 		threejs.SkeletonMesh = SkeletonMesh;

File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-all.js.map


+ 5 - 5
spine-ts/build/spine-canvas.js

@@ -2131,6 +2131,7 @@ var spine;
 			path = this.pathPrefix + path;
 			this.toLoad++;
 			AssetManager.downloadText(path, function (atlasData) {
+				var pagesLoaded = { count: 0 };
 				var atlasPages = new Array();
 				try {
 					var atlas = new spine.TextureAtlas(atlasData, function (path) {
@@ -2151,11 +2152,10 @@ var spine;
 					return;
 				}
 				var _loop_1 = function (atlasPage) {
-					var pagesLoaded = 0;
 					var pageLoadError = false;
 					_this.loadTexture(atlasPage, function (imagePath, image) {
-						pagesLoaded++;
-						if (pagesLoaded == atlasPages.length) {
+						pagesLoaded.count++;
+						if (pagesLoaded.count == atlasPages.length) {
 							if (!pageLoadError) {
 								try {
 									var atlas = new spine.TextureAtlas(atlasData, function (path) {
@@ -2186,8 +2186,8 @@ var spine;
 						}
 					}, function (imagePath, errorMessage) {
 						pageLoadError = true;
-						pagesLoaded++;
-						if (pagesLoaded == atlasPages.length) {
+						pagesLoaded.count++;
+						if (pagesLoaded.count == atlasPages.length) {
 							_this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path;
 							if (error)
 								error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path);

File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-canvas.js.map


+ 5 - 5
spine-ts/build/spine-core.js

@@ -2131,6 +2131,7 @@ var spine;
 			path = this.pathPrefix + path;
 			this.toLoad++;
 			AssetManager.downloadText(path, function (atlasData) {
+				var pagesLoaded = { count: 0 };
 				var atlasPages = new Array();
 				try {
 					var atlas = new spine.TextureAtlas(atlasData, function (path) {
@@ -2151,11 +2152,10 @@ var spine;
 					return;
 				}
 				var _loop_1 = function (atlasPage) {
-					var pagesLoaded = 0;
 					var pageLoadError = false;
 					_this.loadTexture(atlasPage, function (imagePath, image) {
-						pagesLoaded++;
-						if (pagesLoaded == atlasPages.length) {
+						pagesLoaded.count++;
+						if (pagesLoaded.count == atlasPages.length) {
 							if (!pageLoadError) {
 								try {
 									var atlas = new spine.TextureAtlas(atlasData, function (path) {
@@ -2186,8 +2186,8 @@ var spine;
 						}
 					}, function (imagePath, errorMessage) {
 						pageLoadError = true;
-						pagesLoaded++;
-						if (pagesLoaded == atlasPages.length) {
+						pagesLoaded.count++;
+						if (pagesLoaded.count == atlasPages.length) {
 							_this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path;
 							if (error)
 								error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path);

File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-core.js.map


+ 12 - 5
spine-ts/build/spine-threejs.d.ts

@@ -1237,22 +1237,26 @@ declare module spine.threejs {
 	}
 }
 declare module spine.threejs {
-	class MeshBatcher {
-		mesh: THREE.Mesh;
+	class MeshBatcher extends THREE.Mesh {
 		private static VERTEX_SIZE;
 		private vertexBuffer;
 		private vertices;
 		private verticesLength;
 		private indices;
 		private indicesLength;
-		constructor(mesh: THREE.Mesh, maxVertices?: number);
+		constructor(maxVertices?: number);
+		clear(): void;
 		begin(): void;
+		canBatch(verticesLength: number, indicesLength: number): boolean;
 		batch(vertices: ArrayLike<number>, verticesLength: number, indices: ArrayLike<number>, indicesLength: number, z?: number): void;
 		end(): void;
 	}
 }
 declare module spine.threejs {
-	class SkeletonMesh extends THREE.Mesh {
+	class SkeletonMeshMaterial extends THREE.ShaderMaterial {
+		constructor();
+	}
+	class SkeletonMesh extends THREE.Object3D {
 		tempPos: Vector2;
 		tempUv: Vector2;
 		tempLight: Color;
@@ -1261,7 +1265,8 @@ declare module spine.threejs {
 		state: AnimationState;
 		zOffset: number;
 		vertexEffect: VertexEffect;
-		private batcher;
+		private batches;
+		private nextBatchIndex;
 		private clipper;
 		static QUAD_TRIANGLES: number[];
 		static VERTEX_SIZE: number;
@@ -1269,6 +1274,8 @@ declare module spine.threejs {
 		private tempColor;
 		constructor(skeletonData: SkeletonData);
 		update(deltaTime: number): void;
+		private clearBatches();
+		private nextBatch();
 		private updateGeometry();
 	}
 }

+ 113 - 33
spine-ts/build/spine-threejs.js

@@ -2131,6 +2131,7 @@ var spine;
 			path = this.pathPrefix + path;
 			this.toLoad++;
 			AssetManager.downloadText(path, function (atlasData) {
+				var pagesLoaded = { count: 0 };
 				var atlasPages = new Array();
 				try {
 					var atlas = new spine.TextureAtlas(atlasData, function (path) {
@@ -2151,11 +2152,10 @@ var spine;
 					return;
 				}
 				var _loop_1 = function (atlasPage) {
-					var pagesLoaded = 0;
 					var pageLoadError = false;
 					_this.loadTexture(atlasPage, function (imagePath, image) {
-						pagesLoaded++;
-						if (pagesLoaded == atlasPages.length) {
+						pagesLoaded.count++;
+						if (pagesLoaded.count == atlasPages.length) {
 							if (!pageLoadError) {
 								try {
 									var atlas = new spine.TextureAtlas(atlasData, function (path) {
@@ -2186,8 +2186,8 @@ var spine;
 						}
 					}, function (imagePath, errorMessage) {
 						pageLoadError = true;
-						pagesLoaded++;
-						if (pagesLoaded == atlasPages.length) {
+						pagesLoaded.count++;
+						if (pagesLoaded.count == atlasPages.length) {
 							_this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path;
 							if (error)
 								error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path);
@@ -6734,18 +6734,19 @@ var spine;
 (function (spine) {
 	var threejs;
 	(function (threejs) {
-		var MeshBatcher = (function () {
-			function MeshBatcher(mesh, maxVertices) {
+		var MeshBatcher = (function (_super) {
+			__extends(MeshBatcher, _super);
+			function MeshBatcher(maxVertices) {
 				if (maxVertices === void 0) { maxVertices = 10920; }
-				this.verticesLength = 0;
-				this.indicesLength = 0;
+				var _this = _super.call(this) || this;
+				_this.verticesLength = 0;
+				_this.indicesLength = 0;
 				if (maxVertices > 10920)
 					throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices);
-				var vertices = this.vertices = new Float32Array(maxVertices * MeshBatcher.VERTEX_SIZE);
-				var indices = this.indices = new Uint16Array(maxVertices * 3);
-				this.mesh = mesh;
+				var vertices = _this.vertices = new Float32Array(maxVertices * MeshBatcher.VERTEX_SIZE);
+				var indices = _this.indices = new Uint16Array(maxVertices * 3);
 				var geo = new THREE.BufferGeometry();
-				var vertexBuffer = this.vertexBuffer = new THREE.InterleavedBuffer(vertices, MeshBatcher.VERTEX_SIZE);
+				var vertexBuffer = _this.vertexBuffer = new THREE.InterleavedBuffer(vertices, MeshBatcher.VERTEX_SIZE);
 				vertexBuffer.dynamic = true;
 				geo.addAttribute("position", new THREE.InterleavedBufferAttribute(vertexBuffer, 3, 0, false));
 				geo.addAttribute("color", new THREE.InterleavedBufferAttribute(vertexBuffer, 4, 3, false));
@@ -6754,12 +6755,27 @@ var spine;
 				geo.getIndex().dynamic = true;
 				geo.drawRange.start = 0;
 				geo.drawRange.count = 0;
-				mesh.geometry = geo;
+				_this.geometry = geo;
+				_this.material = new threejs.SkeletonMeshMaterial();
+				return _this;
 			}
+			MeshBatcher.prototype.clear = function () {
+				var geo = this.geometry;
+				geo.drawRange.start = 0;
+				geo.drawRange.count = 0;
+				this.material.uniforms.map.value = null;
+			};
 			MeshBatcher.prototype.begin = function () {
 				this.verticesLength = 0;
 				this.indicesLength = 0;
 			};
+			MeshBatcher.prototype.canBatch = function (verticesLength, indicesLength) {
+				if (this.indicesLength + indicesLength >= this.indices.byteLength / 2)
+					return false;
+				if (this.verticesLength + verticesLength >= this.vertices.byteLength / 2)
+					return false;
+				return true;
+			};
 			MeshBatcher.prototype.batch = function (vertices, verticesLength, indices, indicesLength, z) {
 				if (z === void 0) { z = 0; }
 				var indexStart = this.verticesLength / MeshBatcher.VERTEX_SIZE;
@@ -6787,7 +6803,7 @@ var spine;
 				this.vertexBuffer.needsUpdate = true;
 				this.vertexBuffer.updateRange.offset = 0;
 				this.vertexBuffer.updateRange.count = this.verticesLength;
-				var geo = this.mesh.geometry;
+				var geo = this.geometry;
 				geo.getIndex().needsUpdate = true;
 				geo.getIndex().updateRange.offset = 0;
 				geo.getIndex().updateRange.count = this.indicesLength;
@@ -6795,7 +6811,7 @@ var spine;
 				geo.drawRange.count = this.indicesLength;
 			};
 			return MeshBatcher;
-		}());
+		}(THREE.Mesh));
 		MeshBatcher.VERTEX_SIZE = 9;
 		threejs.MeshBatcher = MeshBatcher;
 	})(threejs = spine.threejs || (spine.threejs = {}));
@@ -6804,6 +6820,29 @@ var spine;
 (function (spine) {
 	var threejs;
 	(function (threejs) {
+		var SkeletonMeshMaterial = (function (_super) {
+			__extends(SkeletonMeshMaterial, _super);
+			function SkeletonMeshMaterial() {
+				var _this = this;
+				var vertexShader = "\n\t\t\t\tattribute vec4 color;\n\t\t\t\tvarying vec2 vUv;\n\t\t\t\tvarying vec4 vColor;\n\t\t\t\tvoid main() {\n\t\t\t\t\tvUv = uv;\n\t\t\t\t\tvColor = color;\n\t\t\t\t\tgl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);\n\t\t\t\t}\n\t\t\t";
+				var fragmentShader = "\n\t\t\t\tuniform sampler2D map;\n\t\t\t\tvarying vec2 vUv;\n\t\t\t\tvarying vec4 vColor;\n\t\t\t\tvoid main(void) {\n\t\t\t\t\tgl_FragColor = texture2D(map, vUv)*vColor;\n\t\t\t\t}\n\t\t\t";
+				var parameters = {
+					uniforms: {
+						map: { type: "t", value: null }
+					},
+					vertexShader: vertexShader,
+					fragmentShader: fragmentShader,
+					side: THREE.DoubleSide,
+					transparent: true,
+					alphaTest: 0.5
+				};
+				_this = _super.call(this, parameters) || this;
+				return _this;
+			}
+			;
+			return SkeletonMeshMaterial;
+		}(THREE.ShaderMaterial));
+		threejs.SkeletonMeshMaterial = SkeletonMeshMaterial;
 		var SkeletonMesh = (function (_super) {
 			__extends(SkeletonMesh, _super);
 			function SkeletonMesh(skeletonData) {
@@ -6813,17 +6852,14 @@ var spine;
 				_this.tempLight = new spine.Color();
 				_this.tempDark = new spine.Color();
 				_this.zOffset = 0.1;
+				_this.batches = new Array();
+				_this.nextBatchIndex = 0;
 				_this.clipper = new spine.SkeletonClipping();
 				_this.vertices = spine.Utils.newFloatArray(1024);
 				_this.tempColor = new spine.Color();
 				_this.skeleton = new spine.Skeleton(skeletonData);
 				var animData = new spine.AnimationStateData(skeletonData);
 				_this.state = new spine.AnimationState(animData);
-				var material = _this.material = new THREE.MeshBasicMaterial();
-				material.side = THREE.DoubleSide;
-				material.transparent = true;
-				material.alphaTest = 0.5;
-				_this.batcher = new threejs.MeshBatcher(_this);
 				return _this;
 			}
 			SkeletonMesh.prototype.update = function (deltaTime) {
@@ -6834,12 +6870,29 @@ var spine;
 				skeleton.updateWorldTransform();
 				this.updateGeometry();
 			};
+			SkeletonMesh.prototype.clearBatches = function () {
+				for (var i = 0; i < this.batches.length; i++) {
+					this.batches[i].clear();
+					this.batches[i].visible = false;
+				}
+				this.nextBatchIndex = 0;
+			};
+			SkeletonMesh.prototype.nextBatch = function () {
+				if (this.batches.length == this.nextBatchIndex) {
+					var batch_1 = new threejs.MeshBatcher();
+					this.add(batch_1);
+					this.batches.push(batch_1);
+				}
+				var batch = this.batches[this.nextBatchIndex++];
+				batch.visible = true;
+				return batch;
+			};
 			SkeletonMesh.prototype.updateGeometry = function () {
+				this.clearBatches();
 				var tempPos = this.tempPos;
 				var tempUv = this.tempUv;
 				var tempLight = this.tempLight;
 				var tempDark = this.tempDark;
-				var geometry = this.geometry;
 				var numVertices = 0;
 				var verticesLength = 0;
 				var indicesLength = 0;
@@ -6849,8 +6902,8 @@ var spine;
 				var triangles = null;
 				var uvs = null;
 				var drawOrder = this.skeleton.drawOrder;
-				var batcher = this.batcher;
-				batcher.begin();
+				var batch = this.nextBatch();
+				batch.begin();
 				var z = 0;
 				var zOffset = this.zOffset;
 				for (var i = 0, n = drawOrder.length; i < n; i++) {
@@ -6891,17 +6944,16 @@ var spine;
 					else
 						continue;
 					if (texture != null) {
-						if (!this.material.map) {
-							var mat = this.material;
-							mat.map = texture.texture;
-							mat.needsUpdate = true;
-						}
 						var skeleton = slot.bone.skeleton;
 						var skeletonColor = skeleton.color;
 						var slotColor = slot.color;
 						var alpha = skeletonColor.a * slotColor.a * attachmentColor.a;
 						var color = this.tempColor;
 						color.set(skeletonColor.r * slotColor.r * attachmentColor.r, skeletonColor.g * slotColor.g * attachmentColor.g, skeletonColor.b * slotColor.b * attachmentColor.b, alpha);
+						var finalVertices = void 0;
+						var finalVerticesLength = void 0;
+						var finalIndices = void 0;
+						var finalIndicesLength = void 0;
 						if (clipper.isClipping()) {
 							clipper.clipTriangles(vertices, numFloats, triangles, triangles.length, uvs, color, null, false);
 							var clippedVertices = clipper.clippedVertices;
@@ -6927,7 +6979,10 @@ var spine;
 									verts[v + 7] = tempUv.y;
 								}
 							}
-							batcher.batch(clippedVertices, clippedVertices.length, clippedTriangles, clippedTriangles.length, z);
+							finalVertices = clippedVertices;
+							finalVerticesLength = clippedVertices.length;
+							finalIndices = clippedTriangles;
+							finalIndicesLength = clippedTriangles.length;
 						}
 						else {
 							var verts = vertices;
@@ -6961,15 +7016,40 @@ var spine;
 									verts[v + 5] = uvs[u + 1];
 								}
 							}
-							batcher.batch(vertices, numFloats, triangles, triangles.length, z);
+							finalVertices = vertices;
+							finalVerticesLength = numFloats;
+							finalIndices = triangles;
+							finalIndicesLength = triangles.length;
 						}
+						if (finalVerticesLength == 0 || finalIndicesLength == 0)
+							continue;
+						if (!batch.canBatch(finalVerticesLength, finalIndicesLength)) {
+							batch.end();
+							batch = this.nextBatch();
+							batch.begin();
+						}
+						var batchMaterial = batch.material;
+						if (batchMaterial.uniforms.map.value == null) {
+							batchMaterial.uniforms.map.value = texture.texture;
+						}
+						if (batchMaterial.uniforms.map.value != texture.texture) {
+							batch.end();
+							batch = this.nextBatch();
+							batch.begin();
+							batchMaterial = batch.material;
+							batchMaterial.uniforms.map.value = texture.texture;
+						}
+						batchMaterial.needsUpdate = true;
+						batch.batch(finalVertices, finalVerticesLength, finalIndices, finalIndicesLength, z);
 						z += zOffset;
 					}
+					clipper.clipEndWithSlot(slot);
 				}
-				batcher.end();
+				clipper.clipEnd();
+				batch.end();
 			};
 			return SkeletonMesh;
-		}(THREE.Mesh));
+		}(THREE.Object3D));
 		SkeletonMesh.QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
 		SkeletonMesh.VERTEX_SIZE = 2 + 2 + 4;
 		threejs.SkeletonMesh = SkeletonMesh;

File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-threejs.js.map


+ 5 - 5
spine-ts/build/spine-webgl.js

@@ -2131,6 +2131,7 @@ var spine;
 			path = this.pathPrefix + path;
 			this.toLoad++;
 			AssetManager.downloadText(path, function (atlasData) {
+				var pagesLoaded = { count: 0 };
 				var atlasPages = new Array();
 				try {
 					var atlas = new spine.TextureAtlas(atlasData, function (path) {
@@ -2151,11 +2152,10 @@ var spine;
 					return;
 				}
 				var _loop_1 = function (atlasPage) {
-					var pagesLoaded = 0;
 					var pageLoadError = false;
 					_this.loadTexture(atlasPage, function (imagePath, image) {
-						pagesLoaded++;
-						if (pagesLoaded == atlasPages.length) {
+						pagesLoaded.count++;
+						if (pagesLoaded.count == atlasPages.length) {
 							if (!pageLoadError) {
 								try {
 									var atlas = new spine.TextureAtlas(atlasData, function (path) {
@@ -2186,8 +2186,8 @@ var spine;
 						}
 					}, function (imagePath, errorMessage) {
 						pageLoadError = true;
-						pagesLoaded++;
-						if (pagesLoaded == atlasPages.length) {
+						pagesLoaded.count++;
+						if (pagesLoaded.count == atlasPages.length) {
 							_this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path;
 							if (error)
 								error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path);

File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-webgl.js.map


+ 5 - 5
spine-ts/build/spine-widget.js

@@ -2131,6 +2131,7 @@ var spine;
 			path = this.pathPrefix + path;
 			this.toLoad++;
 			AssetManager.downloadText(path, function (atlasData) {
+				var pagesLoaded = { count: 0 };
 				var atlasPages = new Array();
 				try {
 					var atlas = new spine.TextureAtlas(atlasData, function (path) {
@@ -2151,11 +2152,10 @@ var spine;
 					return;
 				}
 				var _loop_1 = function (atlasPage) {
-					var pagesLoaded = 0;
 					var pageLoadError = false;
 					_this.loadTexture(atlasPage, function (imagePath, image) {
-						pagesLoaded++;
-						if (pagesLoaded == atlasPages.length) {
+						pagesLoaded.count++;
+						if (pagesLoaded.count == atlasPages.length) {
 							if (!pageLoadError) {
 								try {
 									var atlas = new spine.TextureAtlas(atlasData, function (path) {
@@ -2186,8 +2186,8 @@ var spine;
 						}
 					}, function (imagePath, errorMessage) {
 						pageLoadError = true;
-						pagesLoaded++;
-						if (pagesLoaded == atlasPages.length) {
+						pagesLoaded.count++;
+						if (pagesLoaded.count == atlasPages.length) {
 							_this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path;
 							if (error)
 								error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path);

File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-widget.js.map


+ 5 - 5
spine-ts/core/src/AssetManager.ts

@@ -147,6 +147,7 @@ module spine {
 			this.toLoad++;
 
 			AssetManager.downloadText(path, (atlasData: string): void => {
+				var pagesLoaded: any = { count: 0 };
 				var atlasPages = new Array<string>();
 				try {
 					let atlas = new spine.TextureAtlas(atlasData, (path: string) => {
@@ -166,12 +167,11 @@ module spine {
 				}
 
 				for (let atlasPage of atlasPages) {
-					let pagesLoaded = 0;
 					let pageLoadError = false;
 					this.loadTexture(atlasPage, (imagePath: string, image: HTMLImageElement) => {
-						pagesLoaded++;
+						pagesLoaded.count++;
 
-						if (pagesLoaded == atlasPages.length) {
+						if (pagesLoaded.count == atlasPages.length) {
 							if (!pageLoadError) {
 								try {
 									let atlas = new spine.TextureAtlas(atlasData, (path: string) => {
@@ -197,9 +197,9 @@ module spine {
 						}
 					}, (imagePath: string, errorMessage: string) => {
 						pageLoadError = true;
-						pagesLoaded++;
+						pagesLoaded.count++;
 
-						if (pagesLoaded == atlasPages.length) {
+						if (pagesLoaded.count == atlasPages.length) {
 							this.errors[path] = `Couldn't load texture atlas page ${imagePath}} of atlas ${path}`;
 							if (error) error(path, `Couldn't load texture atlas page ${imagePath} of atlas ${path}`);
 							this.toLoad--;

+ 20 - 28
spine-ts/threejs/example/index.html

@@ -19,6 +19,11 @@ var assetManager;
 var canvas;
 var lastFrameTime = Date.now() / 1000;
 
+var baseUrl = "assets/";
+var skeletonFile = "raptor-pro.json";
+var atlasFile = skeletonFile.replace("-pro", "").replace("-ess", "").replace(".json", ".atlas");
+var animation = "walk";
+
 function init () {
 	// create the THREE.JS camera, scene and renderer (WebGL)
 	var width = window.innerWidth, height = window.innerHeight;
@@ -32,10 +37,9 @@ function init () {
 	canvas = renderer.domElement;
 
 	// load the assets required to display the Raptor model
-	assetManager = new spine.threejs.AssetManager();
-	assetManager.loadText("assets/raptor-pro.json");
-	assetManager.loadText("assets/raptor.atlas");
-	assetManager.loadTexture("assets/raptor.png");
+	assetManager = new spine.threejs.AssetManager(baseUrl);
+	assetManager.loadText(skeletonFile);
+	assetManager.loadTextureAtlas(atlasFile);
 
 	requestAnimationFrame(load);
 }
@@ -50,39 +54,27 @@ function load (name, scale) {
 
 		// Load the texture atlas using name.atlas and name.png from the AssetManager.
 		// The function passed to TextureAtlas is used to resolve relative paths.
-		atlas = new spine.TextureAtlas(assetManager.get("assets/raptor.atlas"), function(path) {
-			return assetManager.get("assets/" + path);
-		});
-		var skeletonData = loadSkeleton("raptor-pro", 0.4);
+		atlas = assetManager.get(atlasFile);
+
+		// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
+		atlasLoader = new spine.AtlasAttachmentLoader(atlas);
+
+		// Create a SkeletonJson instance for parsing the .json file.
+		var skeletonJson = new spine.SkeletonJson(atlasLoader);
+
+		// Set the scale to apply during parsing, parse the file, and create a new skeleton.
+		skeletonJson.scale = 0.4;
+		var skeletonData = skeletonJson.readSkeletonData(assetManager.get(skeletonFile));
 
 		// Create a SkeletonMesh from the data and attach it to the scene
 		skeletonMesh = new spine.threejs.SkeletonMesh(skeletonData);
-		skeletonMesh.state.setAnimation(0, "walk", true);
+		skeletonMesh.state.setAnimation(0, animation, true);
 		mesh.add(skeletonMesh);
 
 		requestAnimationFrame(render);
 	} else requestAnimationFrame(load);
 }
 
-function loadSkeleton (name, scale) {
-	// Load the texture atlas using name.atlas and name.png from the AssetManager.
-	// The function passed to TextureAtlas is used to resolve relative paths.
-	atlas = new spine.TextureAtlas(assetManager.get("assets/" + name.replace("-pro", "") + ".atlas"), function(path) {
-		return assetManager.get("assets/" + path);
-	});
-
-	// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
-	atlasLoader = new spine.AtlasAttachmentLoader(atlas);
-
-	// Create a SkeletonJson instance for parsing the .json file.
-	var skeletonJson = new spine.SkeletonJson(atlasLoader);
-
-	// Set the scale to apply during parsing, parse the file, and create a new skeleton.
-	skeletonJson.scale = scale;
-	var skeletonData = skeletonJson.readSkeletonData(assetManager.get("assets/" + name + ".json"));
-	return skeletonData;
-}
-
 var lastTime = Date.now();
 function render() {
 	// calculate delta time for animation purposes

+ 19 - 8
spine-ts/threejs/src/MeshBatcher.ts

@@ -29,9 +29,7 @@
  *****************************************************************************/
 
 module spine.threejs {
-	export class MeshBatcher {
-		mesh: THREE.Mesh;
-
+	export class MeshBatcher extends THREE.Mesh {
 		private static VERTEX_SIZE = 9;
 		private vertexBuffer: THREE.InterleavedBuffer;
 		private vertices: Float32Array;
@@ -39,12 +37,11 @@ module spine.threejs {
 		private indices: Uint16Array;
 		private indicesLength = 0;
 
-		constructor (mesh: THREE.Mesh, maxVertices: number = 10920) {
+		constructor (maxVertices: number = 10920) {
+			super();
 			if (maxVertices > 10920) throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices);
-
 			let vertices = this.vertices = new Float32Array(maxVertices * MeshBatcher.VERTEX_SIZE);
 			let indices = this.indices = new Uint16Array(maxVertices * 3);
-			this.mesh = mesh;
 			let geo = new THREE.BufferGeometry();
 			let vertexBuffer = this.vertexBuffer = new THREE.InterleavedBuffer(vertices, MeshBatcher.VERTEX_SIZE);
 			vertexBuffer.dynamic = true;
@@ -55,7 +52,15 @@ module spine.threejs {
 			geo.getIndex().dynamic = true;
 			geo.drawRange.start = 0;
 			geo.drawRange.count = 0;
-			mesh.geometry = geo;
+			this.geometry = geo;
+			this.material = new SkeletonMeshMaterial();
+		}
+
+		clear () {
+			let geo = (<THREE.BufferGeometry>this.geometry);
+			geo.drawRange.start = 0;
+			geo.drawRange.count = 0;
+			(<SkeletonMeshMaterial>this.material).uniforms.map.value = null;
 		}
 
 		begin () {
@@ -63,6 +68,12 @@ module spine.threejs {
 			this.indicesLength = 0;
 		}
 
+		canBatch(verticesLength: number, indicesLength: number) {
+			if (this.indicesLength + indicesLength >= this.indices.byteLength / 2) return false;
+			if (this.verticesLength + verticesLength >= this.vertices.byteLength / 2) return false;
+			return true;
+		}
+
 		batch (vertices: ArrayLike<number>, verticesLength: number, indices: ArrayLike<number>, indicesLength: number, z: number = 0) {
 			let indexStart = this.verticesLength / MeshBatcher.VERTEX_SIZE;
 			let vertexBuffer = this.vertices;
@@ -91,7 +102,7 @@ module spine.threejs {
 			this.vertexBuffer.needsUpdate = true;
 			this.vertexBuffer.updateRange.offset = 0;
 			this.vertexBuffer.updateRange.count = this.verticesLength;
-			let geo = (<THREE.BufferGeometry>this.mesh.geometry);
+			let geo = (<THREE.BufferGeometry>this.geometry);
 			geo.getIndex().needsUpdate = true;
 			geo.getIndex().updateRange.offset = 0;
 			geo.getIndex().updateRange.count = this.indicesLength;

+ 110 - 27
spine-ts/threejs/src/SkeletonMesh.ts

@@ -29,7 +29,42 @@
  *****************************************************************************/
 
 module spine.threejs {
-	export class SkeletonMesh extends THREE.Mesh {
+	export class SkeletonMeshMaterial extends THREE.ShaderMaterial {
+		constructor () {
+			let vertexShader = `
+				attribute vec4 color;
+				varying vec2 vUv;
+				varying vec4 vColor;
+				void main() {
+					vUv = uv;
+					vColor = color;
+					gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
+				}
+			`;
+			let fragmentShader = `
+				uniform sampler2D map;
+				varying vec2 vUv;
+				varying vec4 vColor;
+				void main(void) {
+					gl_FragColor = texture2D(map, vUv)*vColor;
+				}
+			`;
+
+			let parameters: THREE.ShaderMaterialParameters = {
+				uniforms: {
+					map: { type: "t", value: null }
+				},
+				vertexShader: vertexShader,
+				fragmentShader: fragmentShader,
+				side: THREE.DoubleSide,
+				transparent: true,
+				alphaTest: 0.5
+			};
+			super(parameters);
+		};
+	}
+
+	export class SkeletonMesh extends THREE.Object3D {
 		tempPos: Vector2 = new Vector2();
 		tempUv: Vector2 = new Vector2();
 		tempLight = new Color();
@@ -39,7 +74,8 @@ module spine.threejs {
 		zOffset: number = 0.1;
 		vertexEffect: VertexEffect;
 
-		private batcher: MeshBatcher;
+		private batches = new Array<MeshBatcher>();
+		private nextBatchIndex = 0;
 		private clipper: SkeletonClipping = new SkeletonClipping();
 
 		static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
@@ -54,12 +90,6 @@ module spine.threejs {
 			this.skeleton = new Skeleton(skeletonData);
 			let animData = new AnimationStateData(skeletonData);
 			this.state = new AnimationState(animData);
-
-			let material = this.material = new THREE.MeshBasicMaterial();
-			material.side = THREE.DoubleSide;
-			material.transparent = true;
-			material.alphaTest = 0.5;
-			this.batcher = new MeshBatcher(this);
 		}
 
 		update(deltaTime: number) {
@@ -73,13 +103,33 @@ module spine.threejs {
 			this.updateGeometry();
 		}
 
+		private clearBatches () {
+			for (var i = 0; i < this.batches.length; i++) {
+				this.batches[i].clear();
+				this.batches[i].visible = false;
+			}
+			this.nextBatchIndex = 0;
+		}
+
+		private nextBatch () {
+			if (this.batches.length == this.nextBatchIndex) {
+				let batch = new MeshBatcher();
+				this.add(batch);
+				this.batches.push(batch);
+			}
+			let batch = this.batches[this.nextBatchIndex++];
+			batch.visible = true;
+			return batch;
+		}
+
 		private updateGeometry() {
+			this.clearBatches();
+
 			let tempPos = this.tempPos;
 			let tempUv = this.tempUv;
 			let tempLight = this.tempLight;
 			let tempDark = this.tempDark;
 
-			let geometry = <THREE.BufferGeometry>this.geometry;
 			var numVertices = 0;
 			var verticesLength = 0;
 			var indicesLength = 0;
@@ -91,8 +141,8 @@ module spine.threejs {
 			let triangles: Array<number> = null;
 			let uvs: ArrayLike<number> = null;
 			let drawOrder = this.skeleton.drawOrder;
-			let batcher = this.batcher;
-			batcher.begin();
+			let batch = this.nextBatch();
+			batch.begin();
 			let z = 0;
 			let zOffset = this.zOffset;
 			for (let i = 0, n = drawOrder.length; i < n; i++) {
@@ -130,12 +180,6 @@ module spine.threejs {
 				} else continue;
 
 				if (texture != null) {
-					if (!(<THREE.MeshBasicMaterial>this.material).map) {
-						let mat = <THREE.MeshBasicMaterial>this.material;
-						mat.map = texture.texture;
-						mat.needsUpdate = true;
-					}
-
 					let skeleton = slot.bone.skeleton;
 					let skeletonColor = skeleton.color;
 					let slotColor = slot.color;
@@ -145,12 +189,11 @@ module spine.threejs {
 							skeletonColor.g * slotColor.g * attachmentColor.g,
 							skeletonColor.b * slotColor.b * attachmentColor.b,
 							alpha);
-					// FIXME per slot blending would require multiple material support
-					//let slotBlendMode = slot.data.blendMode;
-					//if (slotBlendMode != blendMode) {
-					//	blendMode = slotBlendMode;
-					//	batcher.setBlendMode(getSourceGLBlendMode(this._gl, blendMode, premultipliedAlpha), getDestGLBlendMode(this._gl, blendMode));
-					//}
+
+					let finalVertices: ArrayLike<number>;
+					let finalVerticesLength: number;
+					let finalIndices: ArrayLike<number>;
+					let finalIndicesLength: number;
 
 					if (clipper.isClipping()) {
 						clipper.clipTriangles(vertices, numFloats, triangles, triangles.length, uvs, color, null, false);
@@ -177,7 +220,10 @@ module spine.threejs {
 								verts[v + 7] = tempUv.y;
 							}
 						}
-						batcher.batch(clippedVertices, clippedVertices.length, clippedTriangles, clippedTriangles.length, z);
+						finalVertices = clippedVertices;
+						finalVerticesLength = clippedVertices.length;
+						finalIndices = clippedTriangles;
+						finalIndicesLength = clippedTriangles.length;
 					} else {
 						let verts = vertices;
 						if (this.vertexEffect != null) {
@@ -209,13 +255,50 @@ module spine.threejs {
 								verts[v + 5] = uvs[u + 1];
 							}
 						}
-						batcher.batch(vertices, numFloats, triangles, triangles.length, z);
+						finalVertices = vertices;
+						finalVerticesLength = numFloats;
+						finalIndices = triangles;
+						finalIndicesLength = triangles.length;
+					}
+
+					if (finalVerticesLength == 0 || finalIndicesLength == 0)
+						continue;
+
+					// Start new batch if this one can't hold vertices/indices
+					if (!batch.canBatch(finalVerticesLength, finalIndicesLength)) {
+						batch.end();
+						batch = this.nextBatch();
+						batch.begin();
 					}
+
+					// FIXME per slot blending would require multiple material support
+					//let slotBlendMode = slot.data.blendMode;
+					//if (slotBlendMode != blendMode) {
+					//	blendMode = slotBlendMode;
+					//	batcher.setBlendMode(getSourceGLBlendMode(this._gl, blendMode, premultipliedAlpha), getDestGLBlendMode(this._gl, blendMode));
+					//}
+
+					let batchMaterial = <SkeletonMeshMaterial>batch.material;
+					if (batchMaterial.uniforms.map.value == null) {
+						batchMaterial.uniforms.map.value = texture.texture;
+					}
+					if (batchMaterial.uniforms.map.value != texture.texture) {
+						batch.end();
+						batch = this.nextBatch();
+						batch.begin();
+						batchMaterial = <SkeletonMeshMaterial>batch.material;
+						batchMaterial.uniforms.map.value = texture.texture;
+					}
+					batchMaterial.needsUpdate = true;
+
+					batch.batch(finalVertices, finalVerticesLength, finalIndices, finalIndicesLength, z);
 					z += zOffset;
 				}
-			}
 
-			batcher.end();
+				clipper.clipEndWithSlot(slot);
+			}
+			clipper.clipEnd();
+			batch.end();
 		}
 	}
 }

Some files were not shown because too many files changed in this diff