Merge branch '3.6' into 3.7-beta

This commit is contained in:
badlogic 2018-01-22 16:13:22 +01:00
commit c24990a1c4
21 changed files with 436 additions and 175 deletions

View File

@ -257,6 +257,7 @@
* Fixed renderer to work with 3.6 changes. Two color tinting is not supported. * Fixed renderer to work with 3.6 changes. Two color tinting is not supported.
* Added clipping support * 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 `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 ### Widget backend
* Fixed WebGL context loss (see WebGL backend changes). Enabled automatically. * Fixed WebGL context loss (see WebGL backend changes). Enabled automatically.

View File

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

View File

@ -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 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. 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 // If you use SceneRenderer, disable two-color tinting via the last constructor argument
var sceneRenderer = new spine.SceneRenderer(canvas, gl, false); 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 // disable two-color tinting in the respective constructor
// and use the shader returned by Shader.newColoredTextured() // and use the shader returned by Shader.newColoredTextured()
// instead of Shader.newTwoColoredTextured() // instead of Shader.newTwoColoredTextured()

View File

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

View File

@ -2131,6 +2131,7 @@ var spine;
path = this.pathPrefix + path; path = this.pathPrefix + path;
this.toLoad++; this.toLoad++;
AssetManager.downloadText(path, function (atlasData) { AssetManager.downloadText(path, function (atlasData) {
var pagesLoaded = { count: 0 };
var atlasPages = new Array(); var atlasPages = new Array();
try { try {
var atlas = new spine.TextureAtlas(atlasData, function (path) { var atlas = new spine.TextureAtlas(atlasData, function (path) {
@ -2151,11 +2152,10 @@ var spine;
return; return;
} }
var _loop_1 = function (atlasPage) { var _loop_1 = function (atlasPage) {
var pagesLoaded = 0;
var pageLoadError = false; var pageLoadError = false;
_this.loadTexture(atlasPage, function (imagePath, image) { _this.loadTexture(atlasPage, function (imagePath, image) {
pagesLoaded++; pagesLoaded.count++;
if (pagesLoaded == atlasPages.length) { if (pagesLoaded.count == atlasPages.length) {
if (!pageLoadError) { if (!pageLoadError) {
try { try {
var atlas = new spine.TextureAtlas(atlasData, function (path) { var atlas = new spine.TextureAtlas(atlasData, function (path) {
@ -2186,8 +2186,8 @@ var spine;
} }
}, function (imagePath, errorMessage) { }, function (imagePath, errorMessage) {
pageLoadError = true; 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; _this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path;
if (error) if (error)
error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path); error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path);
@ -9563,18 +9563,19 @@ var spine;
(function (spine) { (function (spine) {
var threejs; var threejs;
(function (threejs) { (function (threejs) {
var MeshBatcher = (function () { var MeshBatcher = (function (_super) {
function MeshBatcher(mesh, maxVertices) { __extends(MeshBatcher, _super);
function MeshBatcher(maxVertices) {
if (maxVertices === void 0) { maxVertices = 10920; } if (maxVertices === void 0) { maxVertices = 10920; }
this.verticesLength = 0; var _this = _super.call(this) || this;
this.indicesLength = 0; _this.verticesLength = 0;
_this.indicesLength = 0;
if (maxVertices > 10920) if (maxVertices > 10920)
throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices); throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices);
var vertices = this.vertices = new Float32Array(maxVertices * MeshBatcher.VERTEX_SIZE); var vertices = _this.vertices = new Float32Array(maxVertices * MeshBatcher.VERTEX_SIZE);
var indices = this.indices = new Uint16Array(maxVertices * 3); var indices = _this.indices = new Uint16Array(maxVertices * 3);
this.mesh = mesh;
var geo = new THREE.BufferGeometry(); 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; vertexBuffer.dynamic = true;
geo.addAttribute("position", new THREE.InterleavedBufferAttribute(vertexBuffer, 3, 0, false)); geo.addAttribute("position", new THREE.InterleavedBufferAttribute(vertexBuffer, 3, 0, false));
geo.addAttribute("color", new THREE.InterleavedBufferAttribute(vertexBuffer, 4, 3, false)); geo.addAttribute("color", new THREE.InterleavedBufferAttribute(vertexBuffer, 4, 3, false));
@ -9583,12 +9584,27 @@ var spine;
geo.getIndex().dynamic = true; geo.getIndex().dynamic = true;
geo.drawRange.start = 0; geo.drawRange.start = 0;
geo.drawRange.count = 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 () { MeshBatcher.prototype.begin = function () {
this.verticesLength = 0; this.verticesLength = 0;
this.indicesLength = 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) { MeshBatcher.prototype.batch = function (vertices, verticesLength, indices, indicesLength, z) {
if (z === void 0) { z = 0; } if (z === void 0) { z = 0; }
var indexStart = this.verticesLength / MeshBatcher.VERTEX_SIZE; var indexStart = this.verticesLength / MeshBatcher.VERTEX_SIZE;
@ -9616,7 +9632,7 @@ var spine;
this.vertexBuffer.needsUpdate = true; this.vertexBuffer.needsUpdate = true;
this.vertexBuffer.updateRange.offset = 0; this.vertexBuffer.updateRange.offset = 0;
this.vertexBuffer.updateRange.count = this.verticesLength; this.vertexBuffer.updateRange.count = this.verticesLength;
var geo = this.mesh.geometry; var geo = this.geometry;
geo.getIndex().needsUpdate = true; geo.getIndex().needsUpdate = true;
geo.getIndex().updateRange.offset = 0; geo.getIndex().updateRange.offset = 0;
geo.getIndex().updateRange.count = this.indicesLength; geo.getIndex().updateRange.count = this.indicesLength;
@ -9624,7 +9640,7 @@ var spine;
geo.drawRange.count = this.indicesLength; geo.drawRange.count = this.indicesLength;
}; };
return MeshBatcher; return MeshBatcher;
}()); }(THREE.Mesh));
MeshBatcher.VERTEX_SIZE = 9; MeshBatcher.VERTEX_SIZE = 9;
threejs.MeshBatcher = MeshBatcher; threejs.MeshBatcher = MeshBatcher;
})(threejs = spine.threejs || (spine.threejs = {})); })(threejs = spine.threejs || (spine.threejs = {}));
@ -9633,6 +9649,29 @@ var spine;
(function (spine) { (function (spine) {
var threejs; var threejs;
(function (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) { var SkeletonMesh = (function (_super) {
__extends(SkeletonMesh, _super); __extends(SkeletonMesh, _super);
function SkeletonMesh(skeletonData) { function SkeletonMesh(skeletonData) {
@ -9642,17 +9681,14 @@ var spine;
_this.tempLight = new spine.Color(); _this.tempLight = new spine.Color();
_this.tempDark = new spine.Color(); _this.tempDark = new spine.Color();
_this.zOffset = 0.1; _this.zOffset = 0.1;
_this.batches = new Array();
_this.nextBatchIndex = 0;
_this.clipper = new spine.SkeletonClipping(); _this.clipper = new spine.SkeletonClipping();
_this.vertices = spine.Utils.newFloatArray(1024); _this.vertices = spine.Utils.newFloatArray(1024);
_this.tempColor = new spine.Color(); _this.tempColor = new spine.Color();
_this.skeleton = new spine.Skeleton(skeletonData); _this.skeleton = new spine.Skeleton(skeletonData);
var animData = new spine.AnimationStateData(skeletonData); var animData = new spine.AnimationStateData(skeletonData);
_this.state = new spine.AnimationState(animData); _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; return _this;
} }
SkeletonMesh.prototype.update = function (deltaTime) { SkeletonMesh.prototype.update = function (deltaTime) {
@ -9663,12 +9699,29 @@ var spine;
skeleton.updateWorldTransform(); skeleton.updateWorldTransform();
this.updateGeometry(); 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 () { SkeletonMesh.prototype.updateGeometry = function () {
this.clearBatches();
var tempPos = this.tempPos; var tempPos = this.tempPos;
var tempUv = this.tempUv; var tempUv = this.tempUv;
var tempLight = this.tempLight; var tempLight = this.tempLight;
var tempDark = this.tempDark; var tempDark = this.tempDark;
var geometry = this.geometry;
var numVertices = 0; var numVertices = 0;
var verticesLength = 0; var verticesLength = 0;
var indicesLength = 0; var indicesLength = 0;
@ -9678,8 +9731,8 @@ var spine;
var triangles = null; var triangles = null;
var uvs = null; var uvs = null;
var drawOrder = this.skeleton.drawOrder; var drawOrder = this.skeleton.drawOrder;
var batcher = this.batcher; var batch = this.nextBatch();
batcher.begin(); batch.begin();
var z = 0; var z = 0;
var zOffset = this.zOffset; var zOffset = this.zOffset;
for (var i = 0, n = drawOrder.length; i < n; i++) { for (var i = 0, n = drawOrder.length; i < n; i++) {
@ -9720,17 +9773,16 @@ var spine;
else else
continue; continue;
if (texture != null) { if (texture != null) {
if (!this.material.map) {
var mat = this.material;
mat.map = texture.texture;
mat.needsUpdate = true;
}
var skeleton = slot.bone.skeleton; var skeleton = slot.bone.skeleton;
var skeletonColor = skeleton.color; var skeletonColor = skeleton.color;
var slotColor = slot.color; var slotColor = slot.color;
var alpha = skeletonColor.a * slotColor.a * attachmentColor.a; var alpha = skeletonColor.a * slotColor.a * attachmentColor.a;
var color = this.tempColor; 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); 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()) { if (clipper.isClipping()) {
clipper.clipTriangles(vertices, numFloats, triangles, triangles.length, uvs, color, null, false); clipper.clipTriangles(vertices, numFloats, triangles, triangles.length, uvs, color, null, false);
var clippedVertices = clipper.clippedVertices; var clippedVertices = clipper.clippedVertices;
@ -9756,7 +9808,10 @@ var spine;
verts[v + 7] = tempUv.y; 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 { else {
var verts = vertices; var verts = vertices;
@ -9790,15 +9845,40 @@ var spine;
verts[v + 5] = uvs[u + 1]; 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; z += zOffset;
} }
clipper.clipEndWithSlot(slot);
} }
batcher.end(); clipper.clipEnd();
batch.end();
}; };
return SkeletonMesh; return SkeletonMesh;
}(THREE.Mesh)); }(THREE.Object3D));
SkeletonMesh.QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; SkeletonMesh.QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
SkeletonMesh.VERTEX_SIZE = 2 + 2 + 4; SkeletonMesh.VERTEX_SIZE = 2 + 2 + 4;
threejs.SkeletonMesh = SkeletonMesh; threejs.SkeletonMesh = SkeletonMesh;

File diff suppressed because one or more lines are too long

View File

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

File diff suppressed because one or more lines are too long

View File

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

File diff suppressed because one or more lines are too long

View File

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

View File

@ -2131,6 +2131,7 @@ var spine;
path = this.pathPrefix + path; path = this.pathPrefix + path;
this.toLoad++; this.toLoad++;
AssetManager.downloadText(path, function (atlasData) { AssetManager.downloadText(path, function (atlasData) {
var pagesLoaded = { count: 0 };
var atlasPages = new Array(); var atlasPages = new Array();
try { try {
var atlas = new spine.TextureAtlas(atlasData, function (path) { var atlas = new spine.TextureAtlas(atlasData, function (path) {
@ -2151,11 +2152,10 @@ var spine;
return; return;
} }
var _loop_1 = function (atlasPage) { var _loop_1 = function (atlasPage) {
var pagesLoaded = 0;
var pageLoadError = false; var pageLoadError = false;
_this.loadTexture(atlasPage, function (imagePath, image) { _this.loadTexture(atlasPage, function (imagePath, image) {
pagesLoaded++; pagesLoaded.count++;
if (pagesLoaded == atlasPages.length) { if (pagesLoaded.count == atlasPages.length) {
if (!pageLoadError) { if (!pageLoadError) {
try { try {
var atlas = new spine.TextureAtlas(atlasData, function (path) { var atlas = new spine.TextureAtlas(atlasData, function (path) {
@ -2186,8 +2186,8 @@ var spine;
} }
}, function (imagePath, errorMessage) { }, function (imagePath, errorMessage) {
pageLoadError = true; 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; _this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path;
if (error) if (error)
error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path); error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path);
@ -6734,18 +6734,19 @@ var spine;
(function (spine) { (function (spine) {
var threejs; var threejs;
(function (threejs) { (function (threejs) {
var MeshBatcher = (function () { var MeshBatcher = (function (_super) {
function MeshBatcher(mesh, maxVertices) { __extends(MeshBatcher, _super);
function MeshBatcher(maxVertices) {
if (maxVertices === void 0) { maxVertices = 10920; } if (maxVertices === void 0) { maxVertices = 10920; }
this.verticesLength = 0; var _this = _super.call(this) || this;
this.indicesLength = 0; _this.verticesLength = 0;
_this.indicesLength = 0;
if (maxVertices > 10920) if (maxVertices > 10920)
throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices); throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices);
var vertices = this.vertices = new Float32Array(maxVertices * MeshBatcher.VERTEX_SIZE); var vertices = _this.vertices = new Float32Array(maxVertices * MeshBatcher.VERTEX_SIZE);
var indices = this.indices = new Uint16Array(maxVertices * 3); var indices = _this.indices = new Uint16Array(maxVertices * 3);
this.mesh = mesh;
var geo = new THREE.BufferGeometry(); 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; vertexBuffer.dynamic = true;
geo.addAttribute("position", new THREE.InterleavedBufferAttribute(vertexBuffer, 3, 0, false)); geo.addAttribute("position", new THREE.InterleavedBufferAttribute(vertexBuffer, 3, 0, false));
geo.addAttribute("color", new THREE.InterleavedBufferAttribute(vertexBuffer, 4, 3, false)); geo.addAttribute("color", new THREE.InterleavedBufferAttribute(vertexBuffer, 4, 3, false));
@ -6754,12 +6755,27 @@ var spine;
geo.getIndex().dynamic = true; geo.getIndex().dynamic = true;
geo.drawRange.start = 0; geo.drawRange.start = 0;
geo.drawRange.count = 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 () { MeshBatcher.prototype.begin = function () {
this.verticesLength = 0; this.verticesLength = 0;
this.indicesLength = 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) { MeshBatcher.prototype.batch = function (vertices, verticesLength, indices, indicesLength, z) {
if (z === void 0) { z = 0; } if (z === void 0) { z = 0; }
var indexStart = this.verticesLength / MeshBatcher.VERTEX_SIZE; var indexStart = this.verticesLength / MeshBatcher.VERTEX_SIZE;
@ -6787,7 +6803,7 @@ var spine;
this.vertexBuffer.needsUpdate = true; this.vertexBuffer.needsUpdate = true;
this.vertexBuffer.updateRange.offset = 0; this.vertexBuffer.updateRange.offset = 0;
this.vertexBuffer.updateRange.count = this.verticesLength; this.vertexBuffer.updateRange.count = this.verticesLength;
var geo = this.mesh.geometry; var geo = this.geometry;
geo.getIndex().needsUpdate = true; geo.getIndex().needsUpdate = true;
geo.getIndex().updateRange.offset = 0; geo.getIndex().updateRange.offset = 0;
geo.getIndex().updateRange.count = this.indicesLength; geo.getIndex().updateRange.count = this.indicesLength;
@ -6795,7 +6811,7 @@ var spine;
geo.drawRange.count = this.indicesLength; geo.drawRange.count = this.indicesLength;
}; };
return MeshBatcher; return MeshBatcher;
}()); }(THREE.Mesh));
MeshBatcher.VERTEX_SIZE = 9; MeshBatcher.VERTEX_SIZE = 9;
threejs.MeshBatcher = MeshBatcher; threejs.MeshBatcher = MeshBatcher;
})(threejs = spine.threejs || (spine.threejs = {})); })(threejs = spine.threejs || (spine.threejs = {}));
@ -6804,6 +6820,29 @@ var spine;
(function (spine) { (function (spine) {
var threejs; var threejs;
(function (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) { var SkeletonMesh = (function (_super) {
__extends(SkeletonMesh, _super); __extends(SkeletonMesh, _super);
function SkeletonMesh(skeletonData) { function SkeletonMesh(skeletonData) {
@ -6813,17 +6852,14 @@ var spine;
_this.tempLight = new spine.Color(); _this.tempLight = new spine.Color();
_this.tempDark = new spine.Color(); _this.tempDark = new spine.Color();
_this.zOffset = 0.1; _this.zOffset = 0.1;
_this.batches = new Array();
_this.nextBatchIndex = 0;
_this.clipper = new spine.SkeletonClipping(); _this.clipper = new spine.SkeletonClipping();
_this.vertices = spine.Utils.newFloatArray(1024); _this.vertices = spine.Utils.newFloatArray(1024);
_this.tempColor = new spine.Color(); _this.tempColor = new spine.Color();
_this.skeleton = new spine.Skeleton(skeletonData); _this.skeleton = new spine.Skeleton(skeletonData);
var animData = new spine.AnimationStateData(skeletonData); var animData = new spine.AnimationStateData(skeletonData);
_this.state = new spine.AnimationState(animData); _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; return _this;
} }
SkeletonMesh.prototype.update = function (deltaTime) { SkeletonMesh.prototype.update = function (deltaTime) {
@ -6834,12 +6870,29 @@ var spine;
skeleton.updateWorldTransform(); skeleton.updateWorldTransform();
this.updateGeometry(); 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 () { SkeletonMesh.prototype.updateGeometry = function () {
this.clearBatches();
var tempPos = this.tempPos; var tempPos = this.tempPos;
var tempUv = this.tempUv; var tempUv = this.tempUv;
var tempLight = this.tempLight; var tempLight = this.tempLight;
var tempDark = this.tempDark; var tempDark = this.tempDark;
var geometry = this.geometry;
var numVertices = 0; var numVertices = 0;
var verticesLength = 0; var verticesLength = 0;
var indicesLength = 0; var indicesLength = 0;
@ -6849,8 +6902,8 @@ var spine;
var triangles = null; var triangles = null;
var uvs = null; var uvs = null;
var drawOrder = this.skeleton.drawOrder; var drawOrder = this.skeleton.drawOrder;
var batcher = this.batcher; var batch = this.nextBatch();
batcher.begin(); batch.begin();
var z = 0; var z = 0;
var zOffset = this.zOffset; var zOffset = this.zOffset;
for (var i = 0, n = drawOrder.length; i < n; i++) { for (var i = 0, n = drawOrder.length; i < n; i++) {
@ -6891,17 +6944,16 @@ var spine;
else else
continue; continue;
if (texture != null) { if (texture != null) {
if (!this.material.map) {
var mat = this.material;
mat.map = texture.texture;
mat.needsUpdate = true;
}
var skeleton = slot.bone.skeleton; var skeleton = slot.bone.skeleton;
var skeletonColor = skeleton.color; var skeletonColor = skeleton.color;
var slotColor = slot.color; var slotColor = slot.color;
var alpha = skeletonColor.a * slotColor.a * attachmentColor.a; var alpha = skeletonColor.a * slotColor.a * attachmentColor.a;
var color = this.tempColor; 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); 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()) { if (clipper.isClipping()) {
clipper.clipTriangles(vertices, numFloats, triangles, triangles.length, uvs, color, null, false); clipper.clipTriangles(vertices, numFloats, triangles, triangles.length, uvs, color, null, false);
var clippedVertices = clipper.clippedVertices; var clippedVertices = clipper.clippedVertices;
@ -6927,7 +6979,10 @@ var spine;
verts[v + 7] = tempUv.y; 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 { else {
var verts = vertices; var verts = vertices;
@ -6961,15 +7016,40 @@ var spine;
verts[v + 5] = uvs[u + 1]; 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; z += zOffset;
} }
clipper.clipEndWithSlot(slot);
} }
batcher.end(); clipper.clipEnd();
batch.end();
}; };
return SkeletonMesh; return SkeletonMesh;
}(THREE.Mesh)); }(THREE.Object3D));
SkeletonMesh.QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; SkeletonMesh.QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
SkeletonMesh.VERTEX_SIZE = 2 + 2 + 4; SkeletonMesh.VERTEX_SIZE = 2 + 2 + 4;
threejs.SkeletonMesh = SkeletonMesh; threejs.SkeletonMesh = SkeletonMesh;

File diff suppressed because one or more lines are too long

View File

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

File diff suppressed because one or more lines are too long

View File

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

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

@ -29,9 +29,7 @@
*****************************************************************************/ *****************************************************************************/
module spine.threejs { module spine.threejs {
export class MeshBatcher { export class MeshBatcher extends THREE.Mesh {
mesh: THREE.Mesh;
private static VERTEX_SIZE = 9; private static VERTEX_SIZE = 9;
private vertexBuffer: THREE.InterleavedBuffer; private vertexBuffer: THREE.InterleavedBuffer;
private vertices: Float32Array; private vertices: Float32Array;
@ -39,12 +37,11 @@ module spine.threejs {
private indices: Uint16Array; private indices: Uint16Array;
private indicesLength = 0; 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); 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 vertices = this.vertices = new Float32Array(maxVertices * MeshBatcher.VERTEX_SIZE);
let indices = this.indices = new Uint16Array(maxVertices * 3); let indices = this.indices = new Uint16Array(maxVertices * 3);
this.mesh = mesh;
let geo = new THREE.BufferGeometry(); let geo = new THREE.BufferGeometry();
let vertexBuffer = this.vertexBuffer = new THREE.InterleavedBuffer(vertices, MeshBatcher.VERTEX_SIZE); let vertexBuffer = this.vertexBuffer = new THREE.InterleavedBuffer(vertices, MeshBatcher.VERTEX_SIZE);
vertexBuffer.dynamic = true; vertexBuffer.dynamic = true;
@ -55,7 +52,15 @@ module spine.threejs {
geo.getIndex().dynamic = true; geo.getIndex().dynamic = true;
geo.drawRange.start = 0; geo.drawRange.start = 0;
geo.drawRange.count = 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 () { begin () {
@ -63,6 +68,12 @@ module spine.threejs {
this.indicesLength = 0; 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) { batch (vertices: ArrayLike<number>, verticesLength: number, indices: ArrayLike<number>, indicesLength: number, z: number = 0) {
let indexStart = this.verticesLength / MeshBatcher.VERTEX_SIZE; let indexStart = this.verticesLength / MeshBatcher.VERTEX_SIZE;
let vertexBuffer = this.vertices; let vertexBuffer = this.vertices;
@ -91,7 +102,7 @@ module spine.threejs {
this.vertexBuffer.needsUpdate = true; this.vertexBuffer.needsUpdate = true;
this.vertexBuffer.updateRange.offset = 0; this.vertexBuffer.updateRange.offset = 0;
this.vertexBuffer.updateRange.count = this.verticesLength; 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().needsUpdate = true;
geo.getIndex().updateRange.offset = 0; geo.getIndex().updateRange.offset = 0;
geo.getIndex().updateRange.count = this.indicesLength; geo.getIndex().updateRange.count = this.indicesLength;

View File

@ -29,7 +29,42 @@
*****************************************************************************/ *****************************************************************************/
module spine.threejs { 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(); tempPos: Vector2 = new Vector2();
tempUv: Vector2 = new Vector2(); tempUv: Vector2 = new Vector2();
tempLight = new Color(); tempLight = new Color();
@ -39,7 +74,8 @@ module spine.threejs {
zOffset: number = 0.1; zOffset: number = 0.1;
vertexEffect: VertexEffect; vertexEffect: VertexEffect;
private batcher: MeshBatcher; private batches = new Array<MeshBatcher>();
private nextBatchIndex = 0;
private clipper: SkeletonClipping = new SkeletonClipping(); private clipper: SkeletonClipping = new SkeletonClipping();
static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
@ -54,12 +90,6 @@ module spine.threejs {
this.skeleton = new Skeleton(skeletonData); this.skeleton = new Skeleton(skeletonData);
let animData = new AnimationStateData(skeletonData); let animData = new AnimationStateData(skeletonData);
this.state = new AnimationState(animData); 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) { update(deltaTime: number) {
@ -73,13 +103,33 @@ module spine.threejs {
this.updateGeometry(); 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() { private updateGeometry() {
this.clearBatches();
let tempPos = this.tempPos; let tempPos = this.tempPos;
let tempUv = this.tempUv; let tempUv = this.tempUv;
let tempLight = this.tempLight; let tempLight = this.tempLight;
let tempDark = this.tempDark; let tempDark = this.tempDark;
let geometry = <THREE.BufferGeometry>this.geometry;
var numVertices = 0; var numVertices = 0;
var verticesLength = 0; var verticesLength = 0;
var indicesLength = 0; var indicesLength = 0;
@ -91,8 +141,8 @@ module spine.threejs {
let triangles: Array<number> = null; let triangles: Array<number> = null;
let uvs: ArrayLike<number> = null; let uvs: ArrayLike<number> = null;
let drawOrder = this.skeleton.drawOrder; let drawOrder = this.skeleton.drawOrder;
let batcher = this.batcher; let batch = this.nextBatch();
batcher.begin(); batch.begin();
let z = 0; let z = 0;
let zOffset = this.zOffset; let zOffset = this.zOffset;
for (let i = 0, n = drawOrder.length; i < n; i++) { for (let i = 0, n = drawOrder.length; i < n; i++) {
@ -130,12 +180,6 @@ module spine.threejs {
} else continue; } else continue;
if (texture != null) { 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 skeleton = slot.bone.skeleton;
let skeletonColor = skeleton.color; let skeletonColor = skeleton.color;
let slotColor = slot.color; let slotColor = slot.color;
@ -145,12 +189,11 @@ module spine.threejs {
skeletonColor.g * slotColor.g * attachmentColor.g, skeletonColor.g * slotColor.g * attachmentColor.g,
skeletonColor.b * slotColor.b * attachmentColor.b, skeletonColor.b * slotColor.b * attachmentColor.b,
alpha); alpha);
// FIXME per slot blending would require multiple material support
//let slotBlendMode = slot.data.blendMode; let finalVertices: ArrayLike<number>;
//if (slotBlendMode != blendMode) { let finalVerticesLength: number;
// blendMode = slotBlendMode; let finalIndices: ArrayLike<number>;
// batcher.setBlendMode(getSourceGLBlendMode(this._gl, blendMode, premultipliedAlpha), getDestGLBlendMode(this._gl, blendMode)); let finalIndicesLength: number;
//}
if (clipper.isClipping()) { if (clipper.isClipping()) {
clipper.clipTriangles(vertices, numFloats, triangles, triangles.length, uvs, color, null, false); clipper.clipTriangles(vertices, numFloats, triangles, triangles.length, uvs, color, null, false);
@ -177,7 +220,10 @@ module spine.threejs {
verts[v + 7] = tempUv.y; 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 { } else {
let verts = vertices; let verts = vertices;
if (this.vertexEffect != null) { if (this.vertexEffect != null) {
@ -209,13 +255,50 @@ module spine.threejs {
verts[v + 5] = uvs[u + 1]; 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; z += zOffset;
} }
}
batcher.end(); clipper.clipEndWithSlot(slot);
}
clipper.clipEnd();
batch.end();
} }
} }
} }