[ts] Modularize spine-canvas, fixup rollup setup

This commit is contained in:
Mario Zechner 2021-08-25 01:32:39 +02:00
parent 4e4f73cc58
commit ca6b3d0bac
38 changed files with 17717 additions and 66519 deletions

2
.gitignore vendored
View File

@ -149,3 +149,5 @@ cmake-build-debug-visual-studio
spine-cocos2dx/build-v4/ spine-cocos2dx/build-v4/
spine-cocos2dx/example-v4/cocos2d spine-cocos2dx/example-v4/cocos2d
spine-cocos2dx/example-v4/cocos2dx.zip spine-cocos2dx/example-v4/cocos2dx.zip
spine-ts/spine-canvas/dist
spine-ts/spine-core/dist

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -13,7 +13,13 @@
"spine-player", "spine-player",
"spine-threejs", "spine-threejs",
"spine-webgl" "spine-webgl"
] ],
"devDependencies": {
"npx": "^10.2.2",
"rollup": "^2.56.2",
"rollup-plugin-dts": "^3.0.2",
"typescript": "^4.3.5"
}
}, },
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
"version": "7.14.5", "version": "7.14.5",
@ -53,6 +59,10 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@esotericsoftware/spine-canvas": {
"resolved": "spine-canvas",
"link": true
},
"node_modules/@esotericsoftware/spine-core": { "node_modules/@esotericsoftware/spine-core": {
"resolved": "spine-core", "resolved": "spine-core",
"link": true "link": true
@ -102,16 +112,6 @@
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"node_modules/esbuild": {
"version": "0.12.21",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.21.tgz",
"integrity": "sha512-7hyXbU3g94aREufI/5nls7Xcc+RGQeZWZApm6hoBaFvt2BPtpT4TjFMQ9Tb1jU8XyBGz00ShmiyflCogphMHFQ==",
"dev": true,
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
}
},
"node_modules/escape-string-regexp": { "node_modules/escape-string-regexp": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@ -5272,17 +5272,21 @@
"node": ">=4.2.0" "node": ">=4.2.0"
} }
}, },
"spine-core": { "spine-canvas": {
"name": "@esotericsoftware/spine-core", "name": "@esotericsoftware/spine-canvas",
"version": "4.0.1", "version": "4.0.1",
"license": "LicenseRef-LICENSE", "license": "LicenseRef-LICENSE",
"devDependencies": { "devDependencies": {
"esbuild": "^0.12.21",
"npx": "^10.2.2", "npx": "^10.2.2",
"rollup": "^2.56.2", "rollup": "^2.56.2",
"rollup-plugin-dts": "^3.0.2", "rollup-plugin-dts": "^3.0.2",
"typescript": "^4.3.5" "typescript": "^4.3.5"
} }
},
"spine-core": {
"name": "@esotericsoftware/spine-core",
"version": "4.0.1",
"license": "LicenseRef-LICENSE"
} }
}, },
"dependencies": { "dependencies": {
@ -5315,16 +5319,18 @@
"js-tokens": "^4.0.0" "js-tokens": "^4.0.0"
} }
}, },
"@esotericsoftware/spine-core": { "@esotericsoftware/spine-canvas": {
"version": "file:spine-core", "version": "file:spine-canvas",
"requires": { "requires": {
"esbuild": "^0.12.21",
"npx": "^10.2.2", "npx": "^10.2.2",
"rollup": "^2.56.2", "rollup": "^2.56.2",
"rollup-plugin-dts": "^3.0.2", "rollup-plugin-dts": "^3.0.2",
"typescript": "^4.3.5" "typescript": "^4.3.5"
} }
}, },
"@esotericsoftware/spine-core": {
"version": "file:spine-core"
},
"ansi-styles": { "ansi-styles": {
"version": "3.2.1", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
@ -5364,12 +5370,6 @@
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild": {
"version": "0.12.21",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.21.tgz",
"integrity": "sha512-7hyXbU3g94aREufI/5nls7Xcc+RGQeZWZApm6hoBaFvt2BPtpT4TjFMQ9Tb1jU8XyBGz00ShmiyflCogphMHFQ==",
"dev": true
},
"escape-string-regexp": { "escape-string-regexp": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",

View File

@ -2,7 +2,9 @@
"name": "spine-ts", "name": "spine-ts",
"version": "4.0.1", "version": "4.0.1",
"description": "The official Spine Runtimes for the web.", "description": "The official Spine Runtimes for the web.",
"scripts": {}, "scripts": {
"build": "npx tsc -b --clean; tsc -b; npx rollup -c rollup.config.js --sourcemap;"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/esotericsoftware/spine-runtimes.git" "url": "git+https://github.com/esotericsoftware/spine-runtimes.git"
@ -29,5 +31,11 @@
"spine-player", "spine-player",
"spine-threejs", "spine-threejs",
"spine-webgl" "spine-webgl"
] ],
} "devDependencies": {
"npx": "^10.2.2",
"rollup": "^2.56.2",
"rollup-plugin-dts": "^3.0.2",
"typescript": "^4.3.5"
}
}

34
spine-ts/rollup.config.js Normal file
View File

@ -0,0 +1,34 @@
import dts from 'rollup-plugin-dts'
export default [
{
input: 'spine-core/dist/index.js',
context: 'this',
output: [
{
file: 'build/spine-core.js',
name: 'spine',
format: 'umd',
exports: 'named',
}
]
},
{
input: 'spine-core/dist/index.d.ts',
output: [{ file: 'build/spine-core.d.ts', format: 'es' }],
plugins: [dts()],
},
{
input: 'spine-canvas/dist/index.js',
context: 'this',
output: [
{
file: 'build/spine-canvas.js',
name: 'spine',
format: 'umd',
exports: 'named',
}
]
}
]

View File

@ -0,0 +1,32 @@
{
"name": "@esotericsoftware/spine-canvas",
"version": "4.0.1",
"description": "The official Spine Runtimes for the web.",
"main": "dist/index.js",
"scripts": {},
"repository": {
"type": "git",
"url": "git+https://github.com/esotericsoftware/spine-runtimes.git"
},
"keywords": [
"gamedev",
"animations",
"2d",
"spine",
"game-dev",
"runtimes",
"skeletal"
],
"author": "Esoteric Software LLC",
"license": "LicenseRef-LICENSE",
"bugs": {
"url": "https://github.com/esotericsoftware/spine-runtimes/issues"
},
"homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
"devDependencies": {
"npx": "^10.2.2",
"rollup": "^2.56.2",
"rollup-plugin-dts": "^3.0.2",
"typescript": "^4.3.5"
}
}

View File

@ -27,12 +27,11 @@
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
/// <reference path="../../core/src/AssetManager.ts"/> import { Downloader, AssetManagerBase } from "../../spine-core/dist/index";
import { CanvasTexture } from "./CanvasTexture";
module spine.canvas { export class AssetManager extends AssetManagerBase {
export class AssetManager extends spine.AssetManager { constructor(pathPrefix: string = "", downloader: Downloader = null) {
constructor (pathPrefix: string = "", downloader: Downloader = null) { super((image: HTMLImageElement) => { return new CanvasTexture(image); }, pathPrefix, downloader);
super((image: HTMLImageElement) => { return new spine.canvas.CanvasTexture(image); }, pathPrefix, downloader);
}
} }
} }

View File

@ -27,16 +27,14 @@
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
/// <reference path="../../core/src/Texture.ts"/> import { Texture, TextureFilter, TextureWrap } from "../../spine-core/dist/index";
module spine.canvas { export class CanvasTexture extends Texture {
export class CanvasTexture extends Texture { constructor(image: HTMLImageElement) {
constructor (image: HTMLImageElement) { super(image);
super(image);
}
setFilters (minFilter: TextureFilter, magFilter: TextureFilter) { }
setWraps (uWrap: TextureWrap, vWrap: TextureWrap) { }
dispose () { }
} }
setFilters(minFilter: TextureFilter, magFilter: TextureFilter) { }
setWraps(uWrap: TextureWrap, vWrap: TextureWrap) { }
dispose() { }
} }

View File

@ -27,283 +27,284 @@
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
module spine.canvas { import { Utils, Color, Skeleton, RegionAttachment, TextureAtlasRegion, BlendMode, MeshAttachment, Slot } from "../../spine-core/dist/index";
export class SkeletonRenderer { import { CanvasTexture } from "./CanvasTexture";
static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
static VERTEX_SIZE = 2 + 2 + 4;
private ctx: CanvasRenderingContext2D; export class SkeletonRenderer {
static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
static VERTEX_SIZE = 2 + 2 + 4;
public triangleRendering = false; private ctx: CanvasRenderingContext2D;
public debugRendering = false;
private vertices = Utils.newFloatArray(8 * 1024);
private tempColor = new Color();
constructor(context: CanvasRenderingContext2D) { public triangleRendering = false;
this.ctx = context; public debugRendering = false;
private vertices = Utils.newFloatArray(8 * 1024);
private tempColor = new Color();
constructor(context: CanvasRenderingContext2D) {
this.ctx = context;
}
draw(skeleton: Skeleton) {
if (this.triangleRendering) this.drawTriangles(skeleton);
else this.drawImages(skeleton);
}
private drawImages(skeleton: Skeleton) {
let ctx = this.ctx;
let color = this.tempColor;
let skeletonColor = skeleton.color;
let drawOrder = skeleton.drawOrder;
if (this.debugRendering) ctx.strokeStyle = "green";
for (let i = 0, n = drawOrder.length; i < n; i++) {
let slot = drawOrder[i];
let bone = slot.bone;
if (!bone.active) continue;
let attachment = slot.getAttachment();
if (!(attachment instanceof RegionAttachment)) continue;
let region: TextureAtlasRegion = <TextureAtlasRegion>attachment.region;
let image: HTMLImageElement = (<CanvasTexture>region.page.texture).getImage() as HTMLImageElement;
let slotColor = slot.color;
let regionColor = attachment.color;
color.set(skeletonColor.r * slotColor.r * regionColor.r,
skeletonColor.g * slotColor.g * regionColor.g,
skeletonColor.b * slotColor.b * regionColor.b,
skeletonColor.a * slotColor.a * regionColor.a);
ctx.save();
ctx.transform(bone.a, bone.c, bone.b, bone.d, bone.worldX, bone.worldY);
ctx.translate(attachment.offset[0], attachment.offset[1]);
ctx.rotate(attachment.rotation * Math.PI / 180);
let atlasScale = attachment.width / region.originalWidth;
ctx.scale(atlasScale * attachment.scaleX, atlasScale * attachment.scaleY);
let w = region.width, h = region.height;
ctx.translate(w / 2, h / 2);
if (attachment.region.degrees == 90) {
let t = w;
w = h;
h = t;
ctx.rotate(-Math.PI / 2);
}
ctx.scale(1, -1);
ctx.translate(-w / 2, -h / 2);
if (color.r != 1 || color.g != 1 || color.b != 1 || color.a != 1) {
ctx.globalAlpha = color.a;
// experimental tinting via compositing, doesn't work
// ctx.globalCompositeOperation = "source-atop";
// ctx.fillStyle = "rgba(" + (color.r * 255 | 0) + ", " + (color.g * 255 | 0) + ", " + (color.b * 255 | 0) + ", " + color.a + ")";
// ctx.fillRect(0, 0, w, h);
}
ctx.drawImage(image, region.x, region.y, w, h, 0, 0, w, h);
if (this.debugRendering) ctx.strokeRect(0, 0, w, h);
ctx.restore();
} }
}
draw(skeleton: Skeleton) { private drawTriangles(skeleton: Skeleton) {
if (this.triangleRendering) this.drawTriangles(skeleton); let ctx = this.ctx;
else this.drawImages(skeleton); let color = this.tempColor;
} let skeletonColor = skeleton.color;
let drawOrder = skeleton.drawOrder;
private drawImages(skeleton: Skeleton) { let blendMode: BlendMode = null;
let ctx = this.ctx; let vertices: ArrayLike<number> = this.vertices;
let color = this.tempColor; let triangles: Array<number> = null;
let skeletonColor = skeleton.color;
let drawOrder = skeleton.drawOrder;
if (this.debugRendering) ctx.strokeStyle = "green"; for (let i = 0, n = drawOrder.length; i < n; i++) {
let slot = drawOrder[i];
let attachment = slot.getAttachment();
for (let i = 0, n = drawOrder.length; i < n; i++) { let texture: HTMLImageElement;
let slot = drawOrder[i]; let region: TextureAtlasRegion;
let bone = slot.bone; if (attachment instanceof RegionAttachment) {
if (!bone.active) continue; let regionAttachment = <RegionAttachment>attachment;
vertices = this.computeRegionVertices(slot, regionAttachment, false);
triangles = SkeletonRenderer.QUAD_TRIANGLES;
region = <TextureAtlasRegion>regionAttachment.region;
texture = (<CanvasTexture>region.page.texture).getImage() as HTMLImageElement;
} else if (attachment instanceof MeshAttachment) {
let mesh = <MeshAttachment>attachment;
vertices = this.computeMeshVertices(slot, mesh, false);
triangles = mesh.triangles;
texture = (<TextureAtlasRegion>mesh.region.renderObject).page.texture.getImage() as HTMLImageElement;
} else
continue;
let attachment = slot.getAttachment(); if (texture) {
if (!(attachment instanceof RegionAttachment)) continue; if (slot.data.blendMode != blendMode) blendMode = slot.data.blendMode;
let region: TextureAtlasRegion = <TextureAtlasRegion>attachment.region;
let image: HTMLImageElement = (<CanvasTexture>region.page.texture).getImage() as HTMLImageElement;
let slotColor = slot.color; let slotColor = slot.color;
let regionColor = attachment.color; let attachmentColor = attachment.color;
color.set(skeletonColor.r * slotColor.r * regionColor.r, color.set(skeletonColor.r * slotColor.r * attachmentColor.r,
skeletonColor.g * slotColor.g * regionColor.g, skeletonColor.g * slotColor.g * attachmentColor.g,
skeletonColor.b * slotColor.b * regionColor.b, skeletonColor.b * slotColor.b * attachmentColor.b,
skeletonColor.a * slotColor.a * regionColor.a); skeletonColor.a * slotColor.a * attachmentColor.a);
ctx.save();
ctx.transform(bone.a, bone.c, bone.b, bone.d, bone.worldX, bone.worldY);
ctx.translate(attachment.offset[0], attachment.offset[1]);
ctx.rotate(attachment.rotation * Math.PI / 180);
let atlasScale = attachment.width / region.originalWidth;
ctx.scale(atlasScale * attachment.scaleX, atlasScale * attachment.scaleY);
let w = region.width, h = region.height;
ctx.translate(w / 2, h / 2);
if (attachment.region.degrees == 90) {
let t = w;
w = h;
h = t;
ctx.rotate(-Math.PI / 2);
}
ctx.scale(1, -1);
ctx.translate(-w / 2, -h / 2);
if (color.r != 1 || color.g != 1 || color.b != 1 || color.a != 1) { if (color.r != 1 || color.g != 1 || color.b != 1 || color.a != 1) {
ctx.globalAlpha = color.a; ctx.globalAlpha = color.a;
// experimental tinting via compositing, doesn't work // experimental tinting via compositing, doesn't work
// ctx.globalCompositeOperation = "source-atop"; // ctx.globalCompositeOperation = "source-atop";
// ctx.fillStyle = "rgba(" + (color.r * 255 | 0) + ", " + (color.g * 255 | 0) + ", " + (color.b * 255 | 0) + ", " + color.a + ")"; // ctx.fillStyle = "rgba(" + (color.r * 255 | 0) + ", " + (color.g * 255 | 0) + ", " + (color.b * 255 | 0) + ", " + color.a + ")";
// ctx.fillRect(0, 0, w, h); // ctx.fillRect(0, 0, w, h);
} }
ctx.drawImage(image, region.x, region.y, w, h, 0, 0, w, h);
if (this.debugRendering) ctx.strokeRect(0, 0, w, h);
ctx.restore();
}
}
private drawTriangles(skeleton: Skeleton) { for (var j = 0; j < triangles.length; j += 3) {
let ctx = this.ctx; let t1 = triangles[j] * 8, t2 = triangles[j + 1] * 8, t3 = triangles[j + 2] * 8;
let color = this.tempColor;
let skeletonColor = skeleton.color;
let drawOrder = skeleton.drawOrder;
let blendMode: BlendMode = null; let x0 = vertices[t1], y0 = vertices[t1 + 1], u0 = vertices[t1 + 6], v0 = vertices[t1 + 7];
let vertices: ArrayLike<number> = this.vertices; let x1 = vertices[t2], y1 = vertices[t2 + 1], u1 = vertices[t2 + 6], v1 = vertices[t2 + 7];
let triangles: Array<number> = null; let x2 = vertices[t3], y2 = vertices[t3 + 1], u2 = vertices[t3 + 6], v2 = vertices[t3 + 7];
for (let i = 0, n = drawOrder.length; i < n; i++) { this.drawTriangle(texture, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2);
let slot = drawOrder[i];
let attachment = slot.getAttachment();
let texture: HTMLImageElement; if (this.debugRendering) {
let region: TextureAtlasRegion; ctx.strokeStyle = "green";
if (attachment instanceof RegionAttachment) { ctx.beginPath();
let regionAttachment = <RegionAttachment>attachment; ctx.moveTo(x0, y0);
vertices = this.computeRegionVertices(slot, regionAttachment, false); ctx.lineTo(x1, y1);
triangles = SkeletonRenderer.QUAD_TRIANGLES; ctx.lineTo(x2, y2);
region = <TextureAtlasRegion>regionAttachment.region; ctx.lineTo(x0, y0);
texture = (<CanvasTexture>region.page.texture).getImage() as HTMLImageElement; ctx.stroke();
} else if (attachment instanceof MeshAttachment) {
let mesh = <MeshAttachment>attachment;
vertices = this.computeMeshVertices(slot, mesh, false);
triangles = mesh.triangles;
texture = (<TextureAtlasRegion>mesh.region.renderObject).page.texture.getImage() as HTMLImageElement;
} else
continue;
if (texture) {
if (slot.data.blendMode != blendMode) blendMode = slot.data.blendMode;
let slotColor = slot.color;
let attachmentColor = attachment.color;
color.set(skeletonColor.r * slotColor.r * attachmentColor.r,
skeletonColor.g * slotColor.g * attachmentColor.g,
skeletonColor.b * slotColor.b * attachmentColor.b,
skeletonColor.a * slotColor.a * attachmentColor.a);
if (color.r != 1 || color.g != 1 || color.b != 1 || color.a != 1) {
ctx.globalAlpha = color.a;
// experimental tinting via compositing, doesn't work
// ctx.globalCompositeOperation = "source-atop";
// ctx.fillStyle = "rgba(" + (color.r * 255 | 0) + ", " + (color.g * 255 | 0) + ", " + (color.b * 255 | 0) + ", " + color.a + ")";
// ctx.fillRect(0, 0, w, h);
}
for (var j = 0; j < triangles.length; j += 3) {
let t1 = triangles[j] * 8, t2 = triangles[j + 1] * 8, t3 = triangles[j + 2] * 8;
let x0 = vertices[t1], y0 = vertices[t1 + 1], u0 = vertices[t1 + 6], v0 = vertices[t1 + 7];
let x1 = vertices[t2], y1 = vertices[t2 + 1], u1 = vertices[t2 + 6], v1 = vertices[t2 + 7];
let x2 = vertices[t3], y2 = vertices[t3 + 1], u2 = vertices[t3 + 6], v2 = vertices[t3 + 7];
this.drawTriangle(texture, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2);
if (this.debugRendering) {
ctx.strokeStyle = "green";
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.lineTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.lineTo(x0, y0);
ctx.stroke();
}
} }
} }
} }
this.ctx.globalAlpha = 1;
} }
// Adapted from http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 this.ctx.globalAlpha = 1;
// Apache 2 licensed
private drawTriangle(img: HTMLImageElement, x0: number, y0: number, u0: number, v0: number,
x1: number, y1: number, u1: number, v1: number,
x2: number, y2: number, u2: number, v2: number) {
let ctx = this.ctx;
u0 *= img.width;
v0 *= img.height;
u1 *= img.width;
v1 *= img.height;
u2 *= img.width;
v2 *= img.height;
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.lineTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.closePath();
x1 -= x0;
y1 -= y0;
x2 -= x0;
y2 -= y0;
u1 -= u0;
v1 -= v0;
u2 -= u0;
v2 -= v0;
var det = 1 / (u1 * v2 - u2 * v1),
// linear transformation
a = (v2 * x1 - v1 * x2) * det,
b = (v2 * y1 - v1 * y2) * det,
c = (u1 * x2 - u2 * x1) * det,
d = (u1 * y2 - u2 * y1) * det,
// translation
e = x0 - a * u0 - c * v0,
f = y0 - b * u0 - d * v0;
ctx.save();
ctx.transform(a, b, c, d, e, f);
ctx.clip();
ctx.drawImage(img, 0, 0);
ctx.restore();
}
private computeRegionVertices(slot: Slot, region: RegionAttachment, pma: boolean) {
let skeletonColor = slot.bone.skeleton.color;
let slotColor = slot.color;
let regionColor = region.color;
let alpha = skeletonColor.a * slotColor.a * regionColor.a;
let multiplier = pma ? alpha : 1;
let color = this.tempColor;
color.set(skeletonColor.r * slotColor.r * regionColor.r * multiplier,
skeletonColor.g * slotColor.g * regionColor.g * multiplier,
skeletonColor.b * slotColor.b * regionColor.b * multiplier,
alpha);
region.computeWorldVertices(slot.bone, this.vertices, 0, SkeletonRenderer.VERTEX_SIZE);
let vertices = this.vertices;
let uvs = region.uvs;
vertices[RegionAttachment.C1R] = color.r;
vertices[RegionAttachment.C1G] = color.g;
vertices[RegionAttachment.C1B] = color.b;
vertices[RegionAttachment.C1A] = color.a;
vertices[RegionAttachment.U1] = uvs[0];
vertices[RegionAttachment.V1] = uvs[1];
vertices[RegionAttachment.C2R] = color.r;
vertices[RegionAttachment.C2G] = color.g;
vertices[RegionAttachment.C2B] = color.b;
vertices[RegionAttachment.C2A] = color.a;
vertices[RegionAttachment.U2] = uvs[2];
vertices[RegionAttachment.V2] = uvs[3];
vertices[RegionAttachment.C3R] = color.r;
vertices[RegionAttachment.C3G] = color.g;
vertices[RegionAttachment.C3B] = color.b;
vertices[RegionAttachment.C3A] = color.a;
vertices[RegionAttachment.U3] = uvs[4];
vertices[RegionAttachment.V3] = uvs[5];
vertices[RegionAttachment.C4R] = color.r;
vertices[RegionAttachment.C4G] = color.g;
vertices[RegionAttachment.C4B] = color.b;
vertices[RegionAttachment.C4A] = color.a;
vertices[RegionAttachment.U4] = uvs[6];
vertices[RegionAttachment.V4] = uvs[7];
return vertices;
}
private computeMeshVertices(slot: Slot, mesh: MeshAttachment, pma: boolean) {
let skeletonColor = slot.bone.skeleton.color;
let slotColor = slot.color;
let regionColor = mesh.color;
let alpha = skeletonColor.a * slotColor.a * regionColor.a;
let multiplier = pma ? alpha : 1;
let color = this.tempColor;
color.set(skeletonColor.r * slotColor.r * regionColor.r * multiplier,
skeletonColor.g * slotColor.g * regionColor.g * multiplier,
skeletonColor.b * slotColor.b * regionColor.b * multiplier,
alpha);
let vertexCount = mesh.worldVerticesLength / 2;
let vertices = this.vertices;
if (vertices.length < mesh.worldVerticesLength) this.vertices = vertices = Utils.newFloatArray(mesh.worldVerticesLength);
mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, vertices, 0, SkeletonRenderer.VERTEX_SIZE);
let uvs = mesh.uvs;
for (let i = 0, u = 0, v = 2; i < vertexCount; i++) {
vertices[v++] = color.r;
vertices[v++] = color.g;
vertices[v++] = color.b;
vertices[v++] = color.a;
vertices[v++] = uvs[u++];
vertices[v++] = uvs[u++];
v += 2;
}
return vertices;
}
} }
}
// Adapted from http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
// Apache 2 licensed
private drawTriangle(img: HTMLImageElement, x0: number, y0: number, u0: number, v0: number,
x1: number, y1: number, u1: number, v1: number,
x2: number, y2: number, u2: number, v2: number) {
let ctx = this.ctx;
u0 *= img.width;
v0 *= img.height;
u1 *= img.width;
v1 *= img.height;
u2 *= img.width;
v2 *= img.height;
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.lineTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.closePath();
x1 -= x0;
y1 -= y0;
x2 -= x0;
y2 -= y0;
u1 -= u0;
v1 -= v0;
u2 -= u0;
v2 -= v0;
var det = 1 / (u1 * v2 - u2 * v1),
// linear transformation
a = (v2 * x1 - v1 * x2) * det,
b = (v2 * y1 - v1 * y2) * det,
c = (u1 * x2 - u2 * x1) * det,
d = (u1 * y2 - u2 * y1) * det,
// translation
e = x0 - a * u0 - c * v0,
f = y0 - b * u0 - d * v0;
ctx.save();
ctx.transform(a, b, c, d, e, f);
ctx.clip();
ctx.drawImage(img, 0, 0);
ctx.restore();
}
private computeRegionVertices(slot: Slot, region: RegionAttachment, pma: boolean) {
let skeletonColor = slot.bone.skeleton.color;
let slotColor = slot.color;
let regionColor = region.color;
let alpha = skeletonColor.a * slotColor.a * regionColor.a;
let multiplier = pma ? alpha : 1;
let color = this.tempColor;
color.set(skeletonColor.r * slotColor.r * regionColor.r * multiplier,
skeletonColor.g * slotColor.g * regionColor.g * multiplier,
skeletonColor.b * slotColor.b * regionColor.b * multiplier,
alpha);
region.computeWorldVertices(slot.bone, this.vertices, 0, SkeletonRenderer.VERTEX_SIZE);
let vertices = this.vertices;
let uvs = region.uvs;
vertices[RegionAttachment.C1R] = color.r;
vertices[RegionAttachment.C1G] = color.g;
vertices[RegionAttachment.C1B] = color.b;
vertices[RegionAttachment.C1A] = color.a;
vertices[RegionAttachment.U1] = uvs[0];
vertices[RegionAttachment.V1] = uvs[1];
vertices[RegionAttachment.C2R] = color.r;
vertices[RegionAttachment.C2G] = color.g;
vertices[RegionAttachment.C2B] = color.b;
vertices[RegionAttachment.C2A] = color.a;
vertices[RegionAttachment.U2] = uvs[2];
vertices[RegionAttachment.V2] = uvs[3];
vertices[RegionAttachment.C3R] = color.r;
vertices[RegionAttachment.C3G] = color.g;
vertices[RegionAttachment.C3B] = color.b;
vertices[RegionAttachment.C3A] = color.a;
vertices[RegionAttachment.U3] = uvs[4];
vertices[RegionAttachment.V3] = uvs[5];
vertices[RegionAttachment.C4R] = color.r;
vertices[RegionAttachment.C4G] = color.g;
vertices[RegionAttachment.C4B] = color.b;
vertices[RegionAttachment.C4A] = color.a;
vertices[RegionAttachment.U4] = uvs[6];
vertices[RegionAttachment.V4] = uvs[7];
return vertices;
}
private computeMeshVertices(slot: Slot, mesh: MeshAttachment, pma: boolean) {
let skeletonColor = slot.bone.skeleton.color;
let slotColor = slot.color;
let regionColor = mesh.color;
let alpha = skeletonColor.a * slotColor.a * regionColor.a;
let multiplier = pma ? alpha : 1;
let color = this.tempColor;
color.set(skeletonColor.r * slotColor.r * regionColor.r * multiplier,
skeletonColor.g * slotColor.g * regionColor.g * multiplier,
skeletonColor.b * slotColor.b * regionColor.b * multiplier,
alpha);
let vertexCount = mesh.worldVerticesLength / 2;
let vertices = this.vertices;
if (vertices.length < mesh.worldVerticesLength) this.vertices = vertices = Utils.newFloatArray(mesh.worldVerticesLength);
mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, vertices, 0, SkeletonRenderer.VERTEX_SIZE);
let uvs = mesh.uvs;
for (let i = 0, u = 0, v = 2; i < vertexCount; i++) {
vertices[v++] = color.r;
vertices[v++] = color.g;
vertices[v++] = color.b;
vertices[v++] = color.a;
vertices[v++] = uvs[u++];
vertices[v++] = uvs[u++];
v += 2;
}
return vertices;
}
}

View File

@ -0,0 +1,28 @@
import { AssetManager } from "./AssetManager";
import { CanvasTexture } from "./CanvasTexture";
import { SkeletonRenderer } from "./SkeletonRenderer";
export * from "./AssetManager";
export * from "./CanvasTexture";
export * from "./SkeletonRenderer";
export * from "../../spine-core/dist/index"
// Needed for compatibility with the old way of how
// spine-canvas worked. We'd set all exported types
// on the global spine.canvas. However, with rollup
// we can only specify a single default object global
// name, which is spine, not spine.canvas. If spine-canvas.js
// is used in vanilla.js, we added a property spine.canvas
// and assign the types of spine-canvas to it. This way
// old code keeps on working.
declare global {
var spine: any;
}
if (globalThis.spine) {
globalThis.spine.canvas = {
AssetManager: AssetManager,
CanvasTexture: CanvasTexture,
SkeletonRenderer: SkeletonRenderer
};
}

View File

@ -0,0 +1,19 @@
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist",
"moduleResolution": "node",
},
"include": [
"**/*.ts"
],
"exclude": [
"dist/**/*.d.ts"
],
"references": [
{
"path": "../spine-core"
}
]
}

View File

@ -2,10 +2,8 @@
"name": "@esotericsoftware/spine-core", "name": "@esotericsoftware/spine-core",
"version": "4.0.1", "version": "4.0.1",
"description": "The official Spine Runtimes for the web.", "description": "The official Spine Runtimes for the web.",
"main": "build/index.js", "main": "dist/index.js",
"scripts": { "scripts": {},
"build": "npx tsc -p ./tsconfig.json; npx rollup -c rollup.config.js --sourcemap;"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/esotericsoftware/spine-runtimes.git" "url": "git+https://github.com/esotericsoftware/spine-runtimes.git"
@ -24,11 +22,5 @@
"bugs": { "bugs": {
"url": "https://github.com/esotericsoftware/spine-runtimes/issues" "url": "https://github.com/esotericsoftware/spine-runtimes/issues"
}, },
"homepage": "https://github.com/esotericsoftware/spine-runtimes#readme", "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme"
"devDependencies": { }
"npx": "^10.2.2",
"rollup": "^2.56.2",
"rollup-plugin-dts": "^3.0.2",
"typescript": "^4.3.5"
}
}

View File

@ -1,16 +0,0 @@
import dts from 'rollup-plugin-dts'
export default [
{
input: 'build/index.js',
context: 'this',
output: [
{
file: '../build/spine-core.js',
name: 'spine',
format: 'umd',
exports: 'named',
}
]
}
]

View File

@ -31,7 +31,7 @@ import { Texture } from "./Texture";
import { TextureAtlas } from "./TextureAtlas"; import { TextureAtlas } from "./TextureAtlas";
import { Disposable, StringMap } from "./Utils"; import { Disposable, StringMap } from "./Utils";
export class AssetManager implements Disposable { export class AssetManagerBase implements Disposable {
private pathPrefix: string; private pathPrefix: string;
private textureLoader: (image: HTMLImageElement | ImageBitmap) => Texture; private textureLoader: (image: HTMLImageElement | ImageBitmap) => Texture;
private downloader: Downloader; private downloader: Downloader;

View File

@ -27,7 +27,7 @@
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
import { AssetManager } from "./AssetManager"; import { AssetManagerBase } from "./AssetManagerBase";
import { TextureFilter, TextureWrap, Texture, TextureRegion } from "./Texture"; import { TextureFilter, TextureWrap, Texture, TextureRegion } from "./Texture";
import { Disposable, Utils, StringMap } from "./Utils"; import { Disposable, Utils, StringMap } from "./Utils";
@ -185,7 +185,7 @@ export class TextureAtlas implements Disposable {
return null; return null;
} }
setTextures(assetManager: AssetManager, pathPrefix: string = "") { setTextures(assetManager: AssetManagerBase, pathPrefix: string = "") {
for (let page of this.pages) for (let page of this.pages)
page.setTexture(assetManager.get(pathPrefix + page.name)); page.setTexture(assetManager.get(pathPrefix + page.name));
} }

View File

@ -0,0 +1,8 @@
export * from './Attachment';
export * from './AttachmentLoader';
export * from './BoundingBoxAttachment';
export * from './ClippingAttachment';
export * from './MeshAttachment';
export * from './PathAttachment';
export * from './PointAttachment';
export * from './RegionAttachment';

View File

@ -1,42 +1,42 @@
export * from "./Animation"; export * from './Animation';
export * from "./AnimationState"; export * from './AnimationState';
export * from "./AnimationStateData"; export * from './AnimationStateData';
export * from "./AssetManager"; export * from './AtlasAttachmentLoader';
export * from "./AtlasAttachmentLoader"; export * from './Bone';
export * from "./Bone"; export * from './BoneData';
export * from "./BoneData"; export * from './ConstraintData';
export * from "./ConstraintData"; export * from './AssetManagerBase';
export * from "./Event"; export * from './Event';
export * from "./EventData"; export * from './EventData';
export * from "./IkConstraint"; export * from './IkConstraint';
export * from "./IkConstraintData"; export * from './IkConstraintData';
export * from "./PathConstraint"; export * from './PathConstraint';
export * from "./PathConstraintData"; export * from './PathConstraintData';
export * from "./Skeleton"; export * from './Skeleton';
export * from "./SkeletonBinary"; export * from './SkeletonBinary';
export * from "./SkeletonBounds"; export * from './SkeletonBounds';
export * from "./SkeletonClipping"; export * from './SkeletonClipping';
export * from "./SkeletonData"; export * from './SkeletonData';
export * from "./SkeletonJson"; export * from './SkeletonJson';
export * from "./Skin"; export * from './Skin';
export * from "./Slot"; export * from './Slot';
export * from "./SlotData"; export * from './SlotData';
export * from "./Texture"; export * from './Texture';
export * from "./TextureAtlas"; export * from './TextureAtlas';
export * from "./TransformConstraint"; export * from './TransformConstraint';
export * from "./TransformConstraintData"; export * from './TransformConstraintData';
export * from "./Triangulator"; export * from './Triangulator';
export * from "./Updatable"; export * from './Updatable';
export * from "./Utils"; export * from './Utils';
export * from "./VertexEffect"; export * from './VertexEffect';
export * from "./polyfills"; export * from './polyfills';
export * from "./attachments/Attachment"; export * from './attachments/Attachment';
export * from "./attachments/AttachmentLoader"; export * from './attachments/AttachmentLoader';
export * from "./attachments/BoundingBoxAttachment"; export * from './attachments/BoundingBoxAttachment';
export * from "./attachments/ClippingAttachment"; export * from './attachments/ClippingAttachment';
export * from "./attachments/MeshAttachment"; export * from './attachments/MeshAttachment';
export * from "./attachments/PathAttachment"; export * from './attachments/PathAttachment';
export * from "./attachments/PointAttachment"; export * from './attachments/PointAttachment';
export * from "./attachments/RegionAttachment"; export * from './attachments/RegionAttachment';
export * from "./vertexeffects/JitterEffect"; export * from './vertexeffects/JitterEffect';
export * from "./vertexeffects/SwirlEffect"; export * from './vertexeffects/SwirlEffect';

View File

@ -1,14 +1,14 @@
{ {
"extends": "../tsconfig.json", "extends": "../tsconfig.base.json",
"compilerOptions": { "compilerOptions": {
"rootDir": "src", "rootDir": "./src",
"outDir": "build", "outDir": "./dist",
"module": "es2015", },
"target": "es5", "include": [
"moduleResolution": "node", "**/*.ts"
"lib": [ ],
"dom", "exclude": [
"es2015" "dist/**/*.d.ts"
] ],
} "references": []
} }

View File

@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"noImplicitAny": true,
"preserveConstEnums": true,
"sourceMap": true,
"esModuleInterop": true,
"isolatedModules": true,
"lib": [
"DOM",
"ES2015"
],
"declaration": true,
"declarationMap": true,
"composite": true,
},
"exclude": [
"node_modules"
]
}

View File

@ -1,4 +0,0 @@
{
"files": [],
"references": [{ "path": "spine-core" }]
}

View File

@ -1,13 +1,14 @@
{ {
"compilerOptions": { "files": [],
"noImplicitAny": true, "references": [
"removeComments": true, {
"preserveConstEnums": true, "path": "./spine-core"
"sourceMap": true, },
"declaration": true, {
"declarationMap": true, "path": "./spine-canvas"
"composite": true, }
"esModuleInterop": true, ],
"isolatedModules": true, "paths": {
}, "@esotericsoftware/spine-core": "./spine-core/src/index.ts"
}
} }