mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-20 17:26:01 +08:00
[ts][canvaskit] Added CanvasKit runtime for NodeJS and browser environments
This commit is contained in:
parent
853dc33e19
commit
a1f077d43c
@ -6,10 +6,11 @@ up into multiple modules:
|
|||||||
1. `spine-core/`, the core classes to load and process Spine skeletons.
|
1. `spine-core/`, the core classes to load and process Spine skeletons.
|
||||||
1. `spine-webgl/`, a self-contained WebGL backend, built on the core classes.
|
1. `spine-webgl/`, a self-contained WebGL backend, built on the core classes.
|
||||||
1. `spine-canvas/`, a self-contained Canvas backend, built on the core classes.
|
1. `spine-canvas/`, a self-contained Canvas backend, built on the core classes.
|
||||||
1. `spine-threejs/`, a self-contained THREE.JS backend, built on the core classes.
|
1. `spine-canvaskit/`, a self-contained [CanvasKit](https://skia.org/docs/user/modules/canvaskit/) backend, built on the core classes for CanvasKit, supporting both NodeJS for headless rendering, and browsers.
|
||||||
|
1. `spine-threejs/`, a self-contained [THREE.JS](https://threejs.org/) backend, built on the core classes.
|
||||||
1. `spine-player/`, a self-contained player to easily display Spine animations on your website, built on the core classes and WebGL backend.
|
1. `spine-player/`, a self-contained player to easily display Spine animations on your website, built on the core classes and WebGL backend.
|
||||||
1. `spine-phaser/`, a Phaser backend, built on the core classes.
|
1. `spine-phaser/`, a [Phaser](https://phaser.io/) backend, built on the core classes.
|
||||||
1. `spine-pixi/`, a Pixi backend, built on the core classes.
|
1. `spine-pixi/`, a [PixiJS](https://pixijs.com/) backend, built on the core classes.
|
||||||
|
|
||||||
In most cases, the `spine-player` module is best suited for your needs. Please refer to the [Spine Web Player documentation](https://esotericsoftware.com/spine-player) for more information.
|
In most cases, the `spine-player` module is best suited for your needs. Please refer to the [Spine Web Player documentation](https://esotericsoftware.com/spine-player) for more information.
|
||||||
|
|
||||||
@ -35,9 +36,11 @@ For the official legal terms governing the Spine Runtimes, please read the [Spin
|
|||||||
|
|
||||||
spine-ts works with data exported from Spine 4.2.xx.
|
spine-ts works with data exported from Spine 4.2.xx.
|
||||||
|
|
||||||
The spine-ts WebGL and Player backends support all Spine features.
|
spine-ts Canvas does not support mesh attachments, clipping attachments, or two-color tinting. Only the alpha channel from tint colors is applied. Experimental support for mesh attachments can be enabled by setting `spine.SkeletonRenderer.useTriangleRendering` to true. Note that this experimental mesh rendering is slow and render with artifacts on some browsers.
|
||||||
|
|
||||||
spine-ts Canvas does not support mesh attachments, clipping attachments, or color tinting. Only the alpha channel from tint colors is applied. Experimental support for mesh attachments can be enabled by setting `spine.SkeletonRenderer.useTriangleRendering` to true. Note that this experimental mesh rendering is slow and render with artifacts on some browsers.
|
spine-canvaskit supports all Spine features except two-color tinting.
|
||||||
|
|
||||||
|
The spine-webgl and spine-player support all Spine features.
|
||||||
|
|
||||||
spine-ts THREE.JS does not support two color tinting. 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. The THREE.JS backend provides `SkeletonMesh.zOffset` to avoid z-fighting. Adjust to your near/far plane settings.
|
||||||
|
|
||||||
@ -50,20 +53,23 @@ All spine-ts modules are published to [npm](http://npmjs.com) for consumption vi
|
|||||||
You can include a module in your project via a `<script>` tag from the [unpkg](https://unpkg.com/) CDN, specifying the version as part of the URL. In the examples below, the version is `4.0.*`, which fetches the latest patch release, and which will work with all exports from Spine Editor version `4.0.x`.
|
You can include a module in your project via a `<script>` tag from the [unpkg](https://unpkg.com/) CDN, specifying the version as part of the URL. In the examples below, the version is `4.0.*`, which fetches the latest patch release, and which will work with all exports from Spine Editor version `4.0.x`.
|
||||||
|
|
||||||
```
|
```
|
||||||
// spine-ts Core
|
// spine-core
|
||||||
<script src="https://unpkg.com/@esotericsoftware/spine-core@4.2.*/dist/iife/spine-core.js"></script>
|
<script src="https://unpkg.com/@esotericsoftware/spine-core@4.2.*/dist/iife/spine-core.js"></script>
|
||||||
|
|
||||||
// spine-ts Canvas
|
// spine-canvas
|
||||||
<script src="https://unpkg.com/@esotericsoftware/spine-canvas@4.2.*/dist/iife/spine-canvas.js"></script>
|
<script src="https://unpkg.com/@esotericsoftware/spine-canvas@4.2.*/dist/iife/spine-canvas.js"></script>
|
||||||
|
|
||||||
// spine-ts WebGL
|
// spine-canvaskit
|
||||||
|
<script src="https://unpkg.com/@esotericsoftware/spine-canvas@4.2.*/dist/iife/spine-canvaskit.js"></script>
|
||||||
|
|
||||||
|
// spine-webgl
|
||||||
<script src="https://unpkg.com/@esotericsoftware/spine-webgl@4.2.*/dist/iife/spine-webgl.js"></script>
|
<script src="https://unpkg.com/@esotericsoftware/spine-webgl@4.2.*/dist/iife/spine-webgl.js"></script>
|
||||||
|
|
||||||
// spine-ts Player, which requires a spine-player.css as well
|
// spine-player, which requires a spine-player.css as well
|
||||||
<script src="https://unpkg.com/@esotericsoftware/spine-player@4.2.*/dist/iife/spine-player.js"></script>
|
<script src="https://unpkg.com/@esotericsoftware/spine-player@4.2.*/dist/iife/spine-player.js"></script>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/@esotericsoftware/spine-player@4.0.*/dist/spine-player.css">
|
<link rel="stylesheet" href="https://unpkg.com/@esotericsoftware/spine-player@4.0.*/dist/spine-player.css">
|
||||||
|
|
||||||
// spine-ts ThreeJS
|
// spine-threejs
|
||||||
<script src="https://unpkg.com/@esotericsoftware/spine-threejs@4.2.*/dist/iife/spine-threejs.js"></script>
|
<script src="https://unpkg.com/@esotericsoftware/spine-threejs@4.2.*/dist/iife/spine-threejs.js"></script>
|
||||||
|
|
||||||
// spine-phaser
|
// spine-phaser
|
||||||
@ -84,6 +90,7 @@ If your project dependencies are managed through NPM or Yarn, you can add spine-
|
|||||||
```
|
```
|
||||||
npm install @esotericsoftware/spine-core
|
npm install @esotericsoftware/spine-core
|
||||||
npm install @esotericsoftware/spine-canvas
|
npm install @esotericsoftware/spine-canvas
|
||||||
|
npm install @esotericsoftware/spine-canvaskit
|
||||||
npm install @esotericsoftware/spine-webgl
|
npm install @esotericsoftware/spine-webgl
|
||||||
npm install @esotericsoftware/spine-player
|
npm install @esotericsoftware/spine-player
|
||||||
npm install @esotericsoftware/spine-threejs
|
npm install @esotericsoftware/spine-threejs
|
||||||
|
|||||||
@ -20,6 +20,10 @@
|
|||||||
<a href="/spine-canvas/example/mouse-click.html">Mouse click</a>
|
<a href="/spine-canvas/example/mouse-click.html">Mouse click</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<li>CanvasKit</li>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/spine-canvaskit/example">Example</a></li>
|
||||||
|
</ul>
|
||||||
<li>Pixi</li>
|
<li>Pixi</li>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="/spine-pixi/example/index.html">Basic example</a></li>
|
<li><a href="/spine-pixi/example/index.html">Basic example</a></li>
|
||||||
|
|||||||
61
spine-ts/package-lock.json
generated
61
spine-ts/package-lock.json
generated
@ -15,6 +15,7 @@
|
|||||||
"spine-player",
|
"spine-player",
|
||||||
"spine-threejs",
|
"spine-threejs",
|
||||||
"spine-pixi",
|
"spine-pixi",
|
||||||
|
"spine-canvaskit",
|
||||||
"spine-webgl"
|
"spine-webgl"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -45,6 +46,10 @@
|
|||||||
"resolved": "spine-canvas",
|
"resolved": "spine-canvas",
|
||||||
"link": true
|
"link": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@esotericsoftware/spine-canvaskit": {
|
||||||
|
"resolved": "spine-canvaskit",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/@esotericsoftware/spine-core": {
|
"node_modules/@esotericsoftware/spine-core": {
|
||||||
"resolved": "spine-core",
|
"resolved": "spine-core",
|
||||||
"link": true
|
"link": true
|
||||||
@ -69,6 +74,15 @@
|
|||||||
"resolved": "spine-webgl",
|
"resolved": "spine-webgl",
|
||||||
"link": true
|
"link": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@pdf-lib/upng": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@pdf-lib/upng/-/upng-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"pako": "^1.0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@pixi/assets": {
|
"node_modules/@pixi/assets": {
|
||||||
"version": "7.4.2",
|
"version": "7.4.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -226,6 +240,15 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "20.14.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.9.tgz",
|
||||||
|
"integrity": "sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~5.26.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/offscreencanvas": {
|
"node_modules/@types/offscreencanvas": {
|
||||||
"version": "2019.7.3",
|
"version": "2019.7.3",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -244,6 +267,11 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@webgpu/types": {
|
||||||
|
"version": "0.1.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.21.tgz",
|
||||||
|
"integrity": "sha512-pUrWq3V5PiSGFLeLxoGqReTZmiiXwY3jRkIG5sLLKjyqNxrwm/04b4nw7LSmGWJcKk59XOM/YRTUwOzo4MMlow=="
|
||||||
|
},
|
||||||
"node_modules/accepts": {
|
"node_modules/accepts": {
|
||||||
"version": "1.3.8",
|
"version": "1.3.8",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -516,6 +544,14 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/canvaskit-wasm": {
|
||||||
|
"version": "0.39.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/canvaskit-wasm/-/canvaskit-wasm-0.39.1.tgz",
|
||||||
|
"integrity": "sha512-Gy3lCmhUdKq+8bvDrs9t8+qf7RvcjuQn+we7vTVVyqgOVO1UVfHpsnBxkTZw+R4ApEJ3D5fKySl9TU11hmjl/A==",
|
||||||
|
"dependencies": {
|
||||||
|
"@webgpu/types": "0.1.21"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/chalk": {
|
"node_modules/chalk": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -1954,6 +1990,12 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pako": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/parseurl": {
|
"node_modules/parseurl": {
|
||||||
"version": "1.3.3",
|
"version": "1.3.3",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -2760,6 +2802,12 @@
|
|||||||
"node": ">=4.2.0"
|
"node": ">=4.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "5.26.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/union-value": {
|
"node_modules/union-value": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -2995,6 +3043,19 @@
|
|||||||
"@esotericsoftware/spine-core": "4.2.48"
|
"@esotericsoftware/spine-core": "4.2.48"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"spine-canvaskit": {
|
||||||
|
"name": "@esotericsoftware/spine-canvaskit",
|
||||||
|
"version": "4.2.48",
|
||||||
|
"license": "LicenseRef-LICENSE",
|
||||||
|
"dependencies": {
|
||||||
|
"@esotericsoftware/spine-core": "4.2.48",
|
||||||
|
"canvaskit-wasm": "0.39.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@pdf-lib/upng": "1.0.1",
|
||||||
|
"@types/node": "20.14.9"
|
||||||
|
}
|
||||||
|
},
|
||||||
"spine-core": {
|
"spine-core": {
|
||||||
"name": "@esotericsoftware/spine-core",
|
"name": "@esotericsoftware/spine-core",
|
||||||
"version": "4.2.48",
|
"version": "4.2.48",
|
||||||
|
|||||||
@ -8,21 +8,23 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepublish": "npm run clean && npm run build",
|
"prepublish": "npm run clean && npm run build",
|
||||||
"clean": "npx rimraf spine-core/dist spine-canvas/dist spine-webgl/dist spine-phaser/dist spine-player/dist spine-threejs/dist spine-pixi/dist",
|
"clean": "npx rimraf spine-core/dist spine-canvas/dist spine-canvaskit/dist spine-webgl/dist spine-phaser/dist spine-player/dist spine-threejs/dist spine-pixi/dist",
|
||||||
"build": "npm run clean && npm run build:modules && concurrently \"npm run build:core\" \"npm run build:canvas\" \"npm run build:webgl\" \"npm run build:phaser\" \"npm run build:player\" \"npm run build:threejs\" \"npm run build:pixi\"",
|
"build": "npm run clean && npm run build:modules && concurrently \"npm run build:core\" \"npm run build:canvas\" \"npm run build:canvaskit\" \"npm run build:webgl\" \"npm run build:phaser\" \"npm run build:player\" \"npm run build:threejs\" \"npm run build:pixi\"",
|
||||||
"postbuild": "npm run minify",
|
"postbuild": "npm run minify",
|
||||||
"build:modules": "npx tsc -b -clean && npx tsc -b",
|
"build:modules": "npx tsc -b -clean && npx tsc -b",
|
||||||
"build:core": "npx esbuild --bundle spine-core/src/index.ts --tsconfig=spine-core/tsconfig.json --sourcemap --outfile=spine-core/dist/iife/spine-core.js --format=iife --global-name=spine",
|
"build:core": "npx esbuild --bundle spine-core/src/index.ts --tsconfig=spine-core/tsconfig.json --sourcemap --outfile=spine-core/dist/iife/spine-core.js --format=iife --global-name=spine",
|
||||||
"build:canvas": "npx esbuild --bundle spine-canvas/src/index.ts --tsconfig=spine-canvas/tsconfig.json --sourcemap --outfile=spine-canvas/dist/iife/spine-canvas.js --format=iife --global-name=spine",
|
"build:canvas": "npx esbuild --bundle spine-canvas/src/index.ts --tsconfig=spine-canvas/tsconfig.json --sourcemap --outfile=spine-canvas/dist/iife/spine-canvas.js --format=iife --global-name=spine",
|
||||||
|
"build:canvaskit": "npx esbuild --bundle spine-canvaskit/src/index.ts --tsconfig=spine-canvaskit/tsconfig.json --sourcemap --outfile=spine-canvaskit/dist/iife/spine-canvaskit.js --external:canvaskit-wasm --format=iife --global-name=spine",
|
||||||
"build:webgl": "npx esbuild --bundle spine-webgl/src/index.ts --tsconfig=spine-webgl/tsconfig.json --sourcemap --outfile=spine-webgl/dist/iife/spine-webgl.js --format=iife --global-name=spine",
|
"build:webgl": "npx esbuild --bundle spine-webgl/src/index.ts --tsconfig=spine-webgl/tsconfig.json --sourcemap --outfile=spine-webgl/dist/iife/spine-webgl.js --format=iife --global-name=spine",
|
||||||
"build:player": "npx copyfiles -f spine-player/css/spine-player.css spine-player/dist/ && npx esbuild spine-player/dist/spine-player.css --minify --outfile=spine-player/dist/spine-player.min.css && npx esbuild --bundle spine-player/src/index.ts --tsconfig=spine-player/tsconfig.json --sourcemap --outfile=spine-player/dist/iife/spine-player.js --format=iife --global-name=spine",
|
"build:player": "npx copyfiles -f spine-player/css/spine-player.css spine-player/dist/ && npx esbuild spine-player/dist/spine-player.css --minify --outfile=spine-player/dist/spine-player.min.css && npx esbuild --bundle spine-player/src/index.ts --tsconfig=spine-player/tsconfig.json --sourcemap --outfile=spine-player/dist/iife/spine-player.js --format=iife --global-name=spine",
|
||||||
"build:phaser": "npx esbuild --bundle spine-phaser/src/index.ts --tsconfig=spine-phaser/tsconfig.json --sourcemap --outfile=spine-phaser/dist/iife/spine-phaser.js --external:Phaser --alias:phaser=Phaser --format=iife --global-name=spine",
|
"build:phaser": "npx esbuild --bundle spine-phaser/src/index.ts --tsconfig=spine-phaser/tsconfig.json --sourcemap --outfile=spine-phaser/dist/iife/spine-phaser.js --external:Phaser --alias:phaser=Phaser --format=iife --global-name=spine",
|
||||||
"build:threejs": "npx esbuild --bundle spine-threejs/src/index.ts --tsconfig=spine-threejs/tsconfig.json --sourcemap --outfile=spine-threejs/dist/iife/spine-threejs.js --external:three --format=iife --global-name=spine",
|
"build:threejs": "npx esbuild --bundle spine-threejs/src/index.ts --tsconfig=spine-threejs/tsconfig.json --sourcemap --outfile=spine-threejs/dist/iife/spine-threejs.js --external:three --format=iife --global-name=spine",
|
||||||
"build:pixi": "npx esbuild --bundle spine-pixi/src/index.ts --tsconfig=spine-pixi/tsconfig.json --sourcemap --outfile=spine-pixi/dist/iife/spine-pixi.js --external:@pixi/* --format=iife --global-name=spine",
|
"build:pixi": "npx esbuild --bundle spine-pixi/src/index.ts --tsconfig=spine-pixi/tsconfig.json --sourcemap --outfile=spine-pixi/dist/iife/spine-pixi.js --external:@pixi/* --format=iife --global-name=spine",
|
||||||
"minify": "npx esbuild --minify spine-core/dist/iife/spine-core.js --outfile=spine-core/dist/iife/spine-core.min.js && npx esbuild --minify spine-canvas/dist/iife/spine-canvas.js --outfile=spine-canvas/dist/iife/spine-canvas.min.js && npx esbuild --minify spine-player/dist/iife/spine-player.js --outfile=spine-player/dist/iife/spine-player.min.js && npx esbuild --minify spine-phaser/dist/iife/spine-phaser.js --outfile=spine-phaser/dist/iife/spine-phaser.min.js && npx esbuild --minify spine-webgl/dist/iife/spine-webgl.js --outfile=spine-webgl/dist/iife/spine-webgl.min.js && npx esbuild --minify spine-threejs/dist/iife/spine-threejs.js --outfile=spine-threejs/dist/iife/spine-threejs.min.js && npx esbuild --minify spine-pixi/dist/iife/spine-pixi.js --outfile=spine-pixi/dist/iife/spine-pixi.min.js",
|
"minify": "npx esbuild --minify spine-core/dist/iife/spine-core.js --outfile=spine-core/dist/iife/spine-core.min.js && npx esbuild --minify spine-canvas/dist/iife/spine-canvas.js --outfile=spine-canvas/dist/iife/spine-canvas.min.js && npx esbuild --minify spine-canvaskit/dist/iife/spine-canvaskit.js --outfile=spine-canvaskit/dist/iife/spine-canvaskit.min.js && npx esbuild --minify spine-player/dist/iife/spine-player.js --outfile=spine-player/dist/iife/spine-player.min.js && npx esbuild --minify spine-phaser/dist/iife/spine-phaser.js --outfile=spine-phaser/dist/iife/spine-phaser.min.js && npx esbuild --minify spine-webgl/dist/iife/spine-webgl.js --outfile=spine-webgl/dist/iife/spine-webgl.min.js && npx esbuild --minify spine-threejs/dist/iife/spine-threejs.js --outfile=spine-threejs/dist/iife/spine-threejs.min.js && npx esbuild --minify spine-pixi/dist/iife/spine-pixi.js --outfile=spine-pixi/dist/iife/spine-pixi.min.js",
|
||||||
"dev": "concurrently \"npx live-server\" \"npm run dev:canvas\" \"npm run dev:webgl\" \"npm run dev:phaser\" \"npm run dev:player\" \"npm run dev:threejs\" \"npm run dev:pixi\"",
|
"dev": "concurrently \"npx live-server\" \"npm run dev:canvas\" \"npm run dev:canvaskit\" \"npm run dev:webgl\" \"npm run dev:phaser\" \"npm run dev:player\" \"npm run dev:threejs\" \"npm run dev:pixi\" \"npm run dev:modules\"",
|
||||||
"dev:modules": "npm run build:modules -- --watch",
|
"dev:modules": "npm run build:modules -- --watch",
|
||||||
"dev:canvas": "npm run build:canvas -- --watch",
|
"dev:canvas": "npm run build:canvas -- --watch",
|
||||||
|
"dev:canvaskit": "npm run build:canvaskit -- --watch",
|
||||||
"dev:webgl": "npm run build:webgl -- --watch",
|
"dev:webgl": "npm run build:webgl -- --watch",
|
||||||
"dev:phaser": "npm run build:phaser -- --watch",
|
"dev:phaser": "npm run build:phaser -- --watch",
|
||||||
"dev:player": "npm run build:player -- --watch",
|
"dev:player": "npm run build:player -- --watch",
|
||||||
@ -55,18 +57,19 @@
|
|||||||
"spine-player",
|
"spine-player",
|
||||||
"spine-threejs",
|
"spine-threejs",
|
||||||
"spine-pixi",
|
"spine-pixi",
|
||||||
|
"spine-canvaskit",
|
||||||
"spine-webgl"
|
"spine-webgl"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/offscreencanvas": "^2019.6.4",
|
"@types/offscreencanvas": "^2019.6.4",
|
||||||
|
"@types/three": "^0.146.0",
|
||||||
"concurrently": "^7.6.0",
|
"concurrently": "^7.6.0",
|
||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
"esbuild": "^0.16.4",
|
"esbuild": "^0.16.4",
|
||||||
"live-server": "^1.2.2",
|
"live-server": "^1.2.2",
|
||||||
|
"phaser": "^3.60.0",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"typescript": "^4.9.4",
|
|
||||||
"@types/three": "^0.146.0",
|
|
||||||
"three": "^0.146.0",
|
"three": "^0.146.0",
|
||||||
"phaser": "^3.60.0"
|
"typescript": "^4.9.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
26
spine-ts/spine-canvaskit/LICENSE
Normal file
26
spine-ts/spine-canvaskit/LICENSE
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
Spine Runtimes License Agreement
|
||||||
|
Last updated May 1, 2019. Replaces all prior versions.
|
||||||
|
|
||||||
|
Copyright (c) 2013-2019, Esoteric Software LLC
|
||||||
|
|
||||||
|
Integration of the Spine Runtimes into software or otherwise creating
|
||||||
|
derivative works of the Spine Runtimes is permitted under the terms and
|
||||||
|
conditions of Section 2 of the Spine Editor License Agreement:
|
||||||
|
http://esotericsoftware.com/spine-editor-license
|
||||||
|
|
||||||
|
Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||||
|
or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||||
|
"Products"), provided that each user of the Products must obtain their own
|
||||||
|
Spine Editor license and redistribution of the Products in any form must
|
||||||
|
include this license and copyright notice.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS
|
||||||
|
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||||
|
NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS
|
||||||
|
INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
3
spine-ts/spine-canvaskit/README.md
Normal file
3
spine-ts/spine-canvaskit/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# spine-ts CanvasKit
|
||||||
|
|
||||||
|
Please see the top-level [README.md](../README.md) for more information.
|
||||||
BIN
spine-ts/spine-canvaskit/example/assets/spineboy-pro.skel
Normal file
BIN
spine-ts/spine-canvaskit/example/assets/spineboy-pro.skel
Normal file
Binary file not shown.
94
spine-ts/spine-canvaskit/example/assets/spineboy.atlas
Normal file
94
spine-ts/spine-canvaskit/example/assets/spineboy.atlas
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
spineboy.png
|
||||||
|
size: 1024, 256
|
||||||
|
filter: Linear, Linear
|
||||||
|
scale: 0.5
|
||||||
|
crosshair
|
||||||
|
bounds: 352, 7, 45, 45
|
||||||
|
eye-indifferent
|
||||||
|
bounds: 862, 105, 47, 45
|
||||||
|
eye-surprised
|
||||||
|
bounds: 505, 79, 47, 45
|
||||||
|
front-bracer
|
||||||
|
bounds: 826, 66, 29, 40
|
||||||
|
front-fist-closed
|
||||||
|
bounds: 786, 65, 38, 41
|
||||||
|
front-fist-open
|
||||||
|
bounds: 710, 51, 43, 44
|
||||||
|
rotate: 90
|
||||||
|
front-foot
|
||||||
|
bounds: 210, 6, 63, 35
|
||||||
|
front-shin
|
||||||
|
bounds: 665, 128, 41, 92
|
||||||
|
rotate: 90
|
||||||
|
front-thigh
|
||||||
|
bounds: 2, 2, 23, 56
|
||||||
|
rotate: 90
|
||||||
|
front-upper-arm
|
||||||
|
bounds: 250, 205, 23, 49
|
||||||
|
goggles
|
||||||
|
bounds: 665, 171, 131, 83
|
||||||
|
gun
|
||||||
|
bounds: 798, 152, 105, 102
|
||||||
|
head
|
||||||
|
bounds: 2, 27, 136, 149
|
||||||
|
hoverboard-board
|
||||||
|
bounds: 2, 178, 246, 76
|
||||||
|
hoverboard-thruster
|
||||||
|
bounds: 722, 96, 30, 32
|
||||||
|
rotate: 90
|
||||||
|
hoverglow-small
|
||||||
|
bounds: 275, 81, 137, 38
|
||||||
|
mouth-grind
|
||||||
|
bounds: 614, 97, 47, 30
|
||||||
|
mouth-oooo
|
||||||
|
bounds: 612, 65, 47, 30
|
||||||
|
mouth-smile
|
||||||
|
bounds: 661, 64, 47, 30
|
||||||
|
muzzle-glow
|
||||||
|
bounds: 382, 54, 25, 25
|
||||||
|
muzzle-ring
|
||||||
|
bounds: 275, 54, 25, 105
|
||||||
|
rotate: 90
|
||||||
|
muzzle01
|
||||||
|
bounds: 911, 95, 67, 40
|
||||||
|
rotate: 90
|
||||||
|
muzzle02
|
||||||
|
bounds: 792, 108, 68, 42
|
||||||
|
muzzle03
|
||||||
|
bounds: 956, 171, 83, 53
|
||||||
|
rotate: 90
|
||||||
|
muzzle04
|
||||||
|
bounds: 275, 7, 75, 45
|
||||||
|
muzzle05
|
||||||
|
bounds: 140, 3, 68, 38
|
||||||
|
neck
|
||||||
|
bounds: 250, 182, 18, 21
|
||||||
|
portal-bg
|
||||||
|
bounds: 140, 43, 133, 133
|
||||||
|
portal-flare1
|
||||||
|
bounds: 554, 65, 56, 30
|
||||||
|
portal-flare2
|
||||||
|
bounds: 759, 112, 57, 31
|
||||||
|
rotate: 90
|
||||||
|
portal-flare3
|
||||||
|
bounds: 554, 97, 58, 30
|
||||||
|
portal-shade
|
||||||
|
bounds: 275, 121, 133, 133
|
||||||
|
portal-streaks1
|
||||||
|
bounds: 410, 126, 126, 128
|
||||||
|
portal-streaks2
|
||||||
|
bounds: 538, 129, 125, 125
|
||||||
|
rear-bracer
|
||||||
|
bounds: 857, 67, 28, 36
|
||||||
|
rear-foot
|
||||||
|
bounds: 663, 96, 57, 30
|
||||||
|
rear-shin
|
||||||
|
bounds: 414, 86, 38, 89
|
||||||
|
rotate: 90
|
||||||
|
rear-thigh
|
||||||
|
bounds: 756, 63, 28, 47
|
||||||
|
rear-upper-arm
|
||||||
|
bounds: 60, 5, 20, 44
|
||||||
|
rotate: 90
|
||||||
|
torso
|
||||||
|
bounds: 905, 164, 49, 90
|
||||||
BIN
spine-ts/spine-canvaskit/example/assets/spineboy.png
Normal file
BIN
spine-ts/spine-canvaskit/example/assets/spineboy.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 240 KiB |
76
spine-ts/spine-canvaskit/example/headless.js
Normal file
76
spine-ts/spine-canvaskit/example/headless.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import * as fs from "fs"
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import path from 'path';
|
||||||
|
import CanvasKitInit from "canvaskit-wasm/bin/canvaskit.js";
|
||||||
|
import UPNG from "@pdf-lib/upng"
|
||||||
|
import {loadTextureAtlas, SkeletonRenderer, Skeleton, SkeletonBinary, AnimationState, AnimationStateData, AtlasAttachmentLoader, Physics} from "../dist/index.js"
|
||||||
|
|
||||||
|
// Get the current directory
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
|
// This app loads the Spineboy skeleton and its atlas, then renders Spineboy's "portal" animation
|
||||||
|
// at 30 fps to individual frames, which are then encoded as an animated PNG (APNG), which is
|
||||||
|
// written to "output.png"
|
||||||
|
async function main() {
|
||||||
|
// Initialize CanvasKit and create a surface and canvas.
|
||||||
|
const ck = await CanvasKitInit();
|
||||||
|
const surface = ck.MakeSurface(600, 400);
|
||||||
|
if (!surface) throw new Error();
|
||||||
|
const canvas = surface.getCanvas();
|
||||||
|
|
||||||
|
// Load atlas
|
||||||
|
const atlas = await loadTextureAtlas(ck, __dirname + "/assets/spineboy.atlas", async (path) => fs.readFileSync(path));
|
||||||
|
|
||||||
|
// Load skeleton data
|
||||||
|
const binary = new SkeletonBinary(new AtlasAttachmentLoader(atlas));
|
||||||
|
const skeletonData = binary.readSkeletonData(fs.readFileSync(__dirname + "/assets/spineboy-pro.skel"));
|
||||||
|
|
||||||
|
// Create a skeleton and scale and position it.
|
||||||
|
const skeleton = new Skeleton(skeletonData);
|
||||||
|
skeleton.scaleX = skeleton.scaleY = 0.5;
|
||||||
|
skeleton.x = 300;
|
||||||
|
skeleton.y = 380;
|
||||||
|
|
||||||
|
// Create an animation state to apply and mix one or more animations
|
||||||
|
const animationState = new AnimationState(new AnimationStateData(skeletonData));
|
||||||
|
animationState.setAnimation(0, "hoverboard", true);
|
||||||
|
|
||||||
|
// Create a skeleton renderer to render the skeleton with to the canvas
|
||||||
|
const renderer = new SkeletonRenderer(ck);
|
||||||
|
|
||||||
|
// Render the full animation in 1/30 second steps (30fps) and save it to an APNG
|
||||||
|
const animationDuration = skeletonData.findAnimation("hoverboard")?.duration ?? 0;
|
||||||
|
const FRAME_TIME = 1 / 30; // 30 FPS
|
||||||
|
let deltaTime = 0;
|
||||||
|
const frames = [];
|
||||||
|
const imageInfo = { width: 600, height: 400, colorType: ck.ColorType.RGBA_8888, alphaType: ck.AlphaType.Unpremul, colorSpace: ck.ColorSpace.SRGB };
|
||||||
|
const pixelArray = ck.Malloc(Uint8Array, imageInfo.width * imageInfo.height * 4);
|
||||||
|
for (let time = 0; time <= animationDuration; time += deltaTime) {
|
||||||
|
// Clear the canvas
|
||||||
|
canvas.clear(ck.WHITE);
|
||||||
|
|
||||||
|
// Update and apply the animations to the skeleton
|
||||||
|
animationState.update(deltaTime);
|
||||||
|
animationState.apply(skeleton);
|
||||||
|
|
||||||
|
// Update the skeleton time for physics, and its world transforms
|
||||||
|
skeleton.update(deltaTime);
|
||||||
|
skeleton.updateWorldTransform(Physics.update);
|
||||||
|
|
||||||
|
// Render the skeleton to the canvas
|
||||||
|
renderer.render(canvas, skeleton)
|
||||||
|
|
||||||
|
// Read the pixels of the current frame and store it.
|
||||||
|
canvas.readPixels(0, 0, imageInfo, pixelArray);
|
||||||
|
frames.push(new Uint8Array(pixelArray.toTypedArray()).buffer.slice(0));
|
||||||
|
|
||||||
|
// First frame has deltaTime 0, subsequent use FRAME_TIME
|
||||||
|
deltaTime = FRAME_TIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
const apng = UPNG.default.encode(frames, 600, 400, 0, frames.map(() => FRAME_TIME * 1000));
|
||||||
|
fs.writeFileSync('output.png', Buffer.from(apng));
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
80
spine-ts/spine-canvaskit/example/index.html
Normal file
80
spine-ts/spine-canvaskit/example/index.html
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="stylesheet" href="../../index.css">
|
||||||
|
<script src="https://unpkg.com/canvaskit-wasm@latest/bin/canvaskit.js"></script>
|
||||||
|
<script src="../dist/iife/spine-canvaskit.js"></script>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="p-4 flex flex-col items-center">
|
||||||
|
<h1>CanvasKit Example</h1>
|
||||||
|
<canvas id=foo width=600 height=400 style="margin: 0 auto;"></canvas>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
// Function to read file contents from a path, used to load texture atlas and skeleton file.
|
||||||
|
async function readFile(path) {
|
||||||
|
const response = await fetch(path);
|
||||||
|
if (!response.ok) throw new Error("Could not load file " + path);
|
||||||
|
return await response.arrayBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Initialize CanvasKit and create a surface from the Canvas element to draw to
|
||||||
|
const ck = await CanvasKitInit();
|
||||||
|
const surface = ck.MakeCanvasSurface('foo');
|
||||||
|
|
||||||
|
// Load the texture atlas
|
||||||
|
const atlas = await spine.loadTextureAtlas(ck, "assets/spineboy.atlas", readFile);
|
||||||
|
|
||||||
|
// Load skeleton data
|
||||||
|
const binary = new spine.SkeletonBinary(new spine.AtlasAttachmentLoader(atlas));
|
||||||
|
const skeletonData = binary.readSkeletonData(await readFile("assets/spineboy-pro.skel"));
|
||||||
|
|
||||||
|
// Create a skeleton and scale and position it.
|
||||||
|
const skeleton = new spine.Skeleton(skeletonData);
|
||||||
|
skeleton.scaleX = skeleton.scaleY = 0.4;
|
||||||
|
skeleton.x = 300;
|
||||||
|
skeleton.y = 380;
|
||||||
|
skeleton.setToSetupPose();
|
||||||
|
|
||||||
|
// Create an animation state to apply and mix one or more animations
|
||||||
|
const animationState = new spine.AnimationState(new spine.AnimationStateData(skeletonData));
|
||||||
|
animationState.setAnimation(0, "hoverboard", true);
|
||||||
|
|
||||||
|
// Create a skeleton renderer to render the skeleton with to the canvas
|
||||||
|
const renderer = new spine.SkeletonRenderer(ck);
|
||||||
|
|
||||||
|
let lastTime = performance.now();
|
||||||
|
// Rendering loop
|
||||||
|
function drawFrame(canvas) {
|
||||||
|
canvas.clear(ck.Color(52, 52, 54, 1));
|
||||||
|
|
||||||
|
// Calculate the time that's passed between now and the last frame
|
||||||
|
const now = performance.now();
|
||||||
|
const deltaTime = (now - lastTime) / 1000;
|
||||||
|
lastTime = now;
|
||||||
|
|
||||||
|
// Update and apply the animations to the skeleton
|
||||||
|
animationState.update(deltaTime);
|
||||||
|
animationState.apply(skeleton);
|
||||||
|
|
||||||
|
// Update the skeleton time for physics, and its world transforms
|
||||||
|
skeleton.update(deltaTime);
|
||||||
|
skeleton.updateWorldTransform(spine.Physics.update);
|
||||||
|
renderer.render(canvas, skeleton);
|
||||||
|
surface.requestAnimationFrame(drawFrame);
|
||||||
|
}
|
||||||
|
surface.requestAnimationFrame(drawFrame);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</html>
|
||||||
41
spine-ts/spine-canvaskit/package.json
Normal file
41
spine-ts/spine-canvaskit/package.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"name": "@esotericsoftware/spine-canvaskit",
|
||||||
|
"version": "4.2.48",
|
||||||
|
"description": "The official Spine Runtimes for CanvasKit for NodeJS",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
|
"type": "module",
|
||||||
|
"files": [
|
||||||
|
"dist/**/*",
|
||||||
|
"README.md",
|
||||||
|
"LICENSE"
|
||||||
|
],
|
||||||
|
"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",
|
||||||
|
"dependencies": {
|
||||||
|
"@esotericsoftware/spine-core": "4.2.48",
|
||||||
|
"canvaskit-wasm": "0.39.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@pdf-lib/upng": "1.0.1",
|
||||||
|
"@types/node": "20.14.9"
|
||||||
|
}
|
||||||
|
}
|
||||||
180
spine-ts/spine-canvaskit/src/index.ts
Normal file
180
spine-ts/spine-canvaskit/src/index.ts
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
export * from "@esotericsoftware/spine-core";
|
||||||
|
|
||||||
|
import { BlendMode, ClippingAttachment, Color, MeshAttachment, NumberArrayLike, RegionAttachment, Skeleton, SkeletonClipping, Texture, TextureAtlas, TextureFilter, TextureWrap, Utils } from "@esotericsoftware/spine-core";
|
||||||
|
import { Canvas, CanvasKit, Image, Paint, Shader, BlendMode as CanvasKitBlendMode } from "canvaskit-wasm";
|
||||||
|
|
||||||
|
Skeleton.yDown = true;
|
||||||
|
|
||||||
|
type CanvasKitImage = { shaders: Shader[], paintPerBlendMode: Map<BlendMode, Paint>, image: Image };
|
||||||
|
|
||||||
|
// CanvasKit blend modes for premultiplied alpha
|
||||||
|
function toCkBlendMode(ck: CanvasKit, blendMode: BlendMode) {
|
||||||
|
switch(blendMode) {
|
||||||
|
case BlendMode.Normal: return ck.BlendMode.SrcOver;
|
||||||
|
case BlendMode.Additive: return ck.BlendMode.Plus;
|
||||||
|
case BlendMode.Multiply: return ck.BlendMode.Modulate;
|
||||||
|
case BlendMode.Screen: return ck.BlendMode.Screen;
|
||||||
|
default: return ck.BlendMode.SrcOver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CanvasKitTexture extends Texture {
|
||||||
|
getImage(): CanvasKitImage {
|
||||||
|
return this._image;
|
||||||
|
}
|
||||||
|
|
||||||
|
setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): void {
|
||||||
|
const data: CanvasKitImage = this._image;
|
||||||
|
for (const paint of data.paintPerBlendMode.values()) {
|
||||||
|
paint.delete();
|
||||||
|
}
|
||||||
|
for (const shader of data.shaders) {
|
||||||
|
shader.delete();
|
||||||
|
}
|
||||||
|
data.image.delete();
|
||||||
|
this._image = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async fromFile(ck: CanvasKit, path: string, readFile: (path: string) => Promise<Buffer>): Promise<CanvasKitTexture> {
|
||||||
|
const imgData = await readFile(path);
|
||||||
|
if (!imgData) throw new Error(`Could not load image ${path}`);
|
||||||
|
const image = ck.MakeImageFromEncoded(imgData);
|
||||||
|
if (!image) throw new Error(`Could not load image ${path}`);
|
||||||
|
const paintPerBlendMode = new Map<BlendMode, Paint>();
|
||||||
|
const shaders: Shader[] = [];
|
||||||
|
for (const blendMode of [BlendMode.Normal, BlendMode.Additive, BlendMode.Multiply, BlendMode.Screen]) {
|
||||||
|
const paint = new ck.Paint();
|
||||||
|
const shader = image.makeShaderOptions(ck.TileMode.Clamp, ck.TileMode.Clamp, ck.FilterMode.Linear, ck.MipmapMode.Linear);
|
||||||
|
paint.setShader(shader);
|
||||||
|
paint.setBlendMode(toCkBlendMode(ck, blendMode));
|
||||||
|
paintPerBlendMode.set(blendMode, paint);
|
||||||
|
shaders.push(shader);
|
||||||
|
}
|
||||||
|
return new CanvasKitTexture({ shaders, paintPerBlendMode, image });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bufferToUtf8String(buffer: any) {
|
||||||
|
if (typeof Buffer !== 'undefined') {
|
||||||
|
return buffer.toString('utf-8');
|
||||||
|
} else if (typeof TextDecoder !== 'undefined') {
|
||||||
|
return new TextDecoder('utf-8').decode(buffer);
|
||||||
|
} else {
|
||||||
|
throw new Error('Unsupported environment');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadTextureAtlas(ck: CanvasKit, atlasFile: string, readFile: (path: string) => Promise<Buffer>): Promise<TextureAtlas> {
|
||||||
|
const atlas = new TextureAtlas(bufferToUtf8String(await readFile(atlasFile)));
|
||||||
|
const slashIndex = atlasFile.lastIndexOf("/");
|
||||||
|
const parentDir = slashIndex >= 0 ? atlasFile.substring(0, slashIndex + 1) : "";
|
||||||
|
for (const page of atlas.pages) {
|
||||||
|
const texture = await CanvasKitTexture.fromFile(ck, parentDir + "/" + page.name, readFile);
|
||||||
|
page.setTexture(texture);
|
||||||
|
}
|
||||||
|
return atlas;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SkeletonRenderer {
|
||||||
|
private clipper = new SkeletonClipping();
|
||||||
|
private tempColor = new Color();
|
||||||
|
private tempColor2 = new Color();
|
||||||
|
private static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
|
||||||
|
private scratchPositions = Utils.newFloatArray(100);
|
||||||
|
private scratchColors = Utils.newFloatArray(100);
|
||||||
|
constructor(private ck: CanvasKit) {}
|
||||||
|
|
||||||
|
render(canvas: Canvas, skeleton: Skeleton) {
|
||||||
|
let clipper = this.clipper;
|
||||||
|
let drawOrder = skeleton.drawOrder;
|
||||||
|
let skeletonColor = skeleton.color;
|
||||||
|
|
||||||
|
for (let i = 0, n = drawOrder.length; i < n; i++) {
|
||||||
|
let slot = drawOrder[i];
|
||||||
|
if (!slot.bone.active) {
|
||||||
|
clipper.clipEndWithSlot(slot);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let attachment = slot.getAttachment();
|
||||||
|
let positions = this.scratchPositions;
|
||||||
|
let colors = this.scratchColors;
|
||||||
|
let uvs: NumberArrayLike;
|
||||||
|
let texture: CanvasKitTexture;
|
||||||
|
let triangles: Array<number>;
|
||||||
|
let attachmentColor: Color;
|
||||||
|
let numVertices = 0;
|
||||||
|
if (attachment instanceof RegionAttachment) {
|
||||||
|
let region = attachment as RegionAttachment;
|
||||||
|
positions = positions.length < 8 ? Utils.newFloatArray(8) : positions;
|
||||||
|
numVertices = 4;
|
||||||
|
region.computeWorldVertices(slot, positions, 0, 2);
|
||||||
|
triangles = SkeletonRenderer.QUAD_TRIANGLES;
|
||||||
|
uvs = region.uvs as Float32Array;
|
||||||
|
texture = region.region?.texture as CanvasKitTexture;
|
||||||
|
attachmentColor = region.color;
|
||||||
|
} else if (attachment instanceof MeshAttachment) {
|
||||||
|
let mesh = attachment as MeshAttachment;
|
||||||
|
positions = positions.length < mesh.worldVerticesLength ? Utils.newFloatArray(mesh.worldVerticesLength) : positions;
|
||||||
|
numVertices = mesh.worldVerticesLength >> 1;
|
||||||
|
mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, positions, 0, 2);
|
||||||
|
triangles = mesh.triangles;
|
||||||
|
texture = mesh.region?.texture as CanvasKitTexture;
|
||||||
|
uvs = mesh.uvs as Float32Array;
|
||||||
|
attachmentColor = mesh.color;
|
||||||
|
} else if (attachment instanceof ClippingAttachment) {
|
||||||
|
let clip = attachment as ClippingAttachment;
|
||||||
|
clipper.clipStart(slot, clip);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
clipper.clipEndWithSlot(slot);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (texture) {
|
||||||
|
if (clipper.isClipping()) {
|
||||||
|
clipper.clipTrianglesUnpacked(positions, triangles, triangles.length, uvs);
|
||||||
|
positions = clipper.clippedVertices;
|
||||||
|
uvs = clipper.clippedUVs;
|
||||||
|
triangles = clipper.clippedTriangles;
|
||||||
|
}
|
||||||
|
|
||||||
|
let slotColor = slot.color;
|
||||||
|
let finalColor = this.tempColor;
|
||||||
|
finalColor.r = skeletonColor.r * slotColor.r * attachmentColor.r;
|
||||||
|
finalColor.g = skeletonColor.g * slotColor.g * attachmentColor.g;
|
||||||
|
finalColor.b = skeletonColor.b * slotColor.b * attachmentColor.b;
|
||||||
|
finalColor.a = skeletonColor.a * slotColor.a * attachmentColor.a;
|
||||||
|
|
||||||
|
if (colors.length / 4 < numVertices) colors = Utils.newFloatArray(numVertices * 4);
|
||||||
|
for (let i = 0, n = numVertices * 4; i < n; i += 4) {
|
||||||
|
colors[i] = finalColor.r;
|
||||||
|
colors[i + 1] = finalColor.g;
|
||||||
|
colors[i + 2] = finalColor.b;
|
||||||
|
colors[i + 3] = finalColor.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
const scaledUvs = new Array<number>(uvs.length);
|
||||||
|
const width = texture.getImage().image.width();
|
||||||
|
const height = texture.getImage().image.height();
|
||||||
|
for (let i = 0; i < uvs.length; i+=2) {
|
||||||
|
scaledUvs[i] = uvs[i] * width;
|
||||||
|
scaledUvs[i + 1] = uvs[i + 1] * height;
|
||||||
|
}
|
||||||
|
|
||||||
|
const blendMode = slot.data.blendMode;
|
||||||
|
const vertices = this.ck.MakeVertices(this.ck.VertexMode.Triangles, positions, scaledUvs, colors, triangles, false);
|
||||||
|
canvas.drawVertices(vertices, this.ck.BlendMode.Modulate, texture.getImage().paintPerBlendMode.get(blendMode)!);
|
||||||
|
}
|
||||||
|
|
||||||
|
clipper.clipEndWithSlot(slot);
|
||||||
|
}
|
||||||
|
clipper.clipEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
18
spine-ts/spine-canvaskit/tsconfig.json
Normal file
18
spine-ts/spine-canvaskit/tsconfig.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./dist",
|
||||||
|
"paths": {
|
||||||
|
"@esotericsoftware/spine-core": ["../spine-core/src"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": ["**/*.ts"],
|
||||||
|
"exclude": ["dist/**/*.d.ts"],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../spine-core"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -64,7 +64,7 @@ export class SkeletonBinary {
|
|||||||
this.attachmentLoader = attachmentLoader;
|
this.attachmentLoader = attachmentLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
readSkeletonData (binary: Uint8Array): SkeletonData {
|
readSkeletonData (binary: Uint8Array | ArrayBuffer): SkeletonData {
|
||||||
let scale = this.scale;
|
let scale = this.scale;
|
||||||
|
|
||||||
let skeletonData = new SkeletonData();
|
let skeletonData = new SkeletonData();
|
||||||
@ -1115,7 +1115,7 @@ export class SkeletonBinary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class BinaryInput {
|
export class BinaryInput {
|
||||||
constructor (data: Uint8Array, public strings = new Array<string>(), private index: number = 0, private buffer = new DataView(data.buffer)) {
|
constructor (data: Uint8Array | ArrayBuffer, public strings = new Array<string>(), private index: number = 0, private buffer = new DataView(data instanceof ArrayBuffer ? data : data.buffer)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
readByte (): number {
|
readByte (): number {
|
||||||
|
|||||||
@ -90,11 +90,6 @@ export class StringSet {
|
|||||||
export type NumberArrayLike = Array<number> | Float32Array;
|
export type NumberArrayLike = Array<number> | Float32Array;
|
||||||
export type IntArrayLike = Array<number> | Int16Array;
|
export type IntArrayLike = Array<number> | Int16Array;
|
||||||
|
|
||||||
/*export interface NumberArrayLike {
|
|
||||||
readonly length: number;
|
|
||||||
[n: number]: number;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
export interface Disposable {
|
export interface Disposable {
|
||||||
dispose (): void;
|
dispose (): void;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -212,7 +212,7 @@ export class SpinePlayer implements Disposable {
|
|||||||
|
|
||||||
private playTime = 0;
|
private playTime = 0;
|
||||||
private selectedBones: (Bone | null)[] = [];
|
private selectedBones: (Bone | null)[] = [];
|
||||||
private cancelId = 0;
|
private cancelId: any = 0;
|
||||||
popup: Popup | null = null;
|
popup: Popup | null = null;
|
||||||
|
|
||||||
/* True if the player is unable to load or render the skeleton. */
|
/* True if the player is unable to load or render the skeleton. */
|
||||||
|
|||||||
@ -128,7 +128,7 @@ body { margin: 0px; }
|
|||||||
this.startPlayer();
|
this.startPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
private timerId = 0;
|
private timerId: any = 0;
|
||||||
startPlayer () {
|
startPlayer () {
|
||||||
clearTimeout(this.timerId);
|
clearTimeout(this.timerId);
|
||||||
this.timerId = setTimeout(() => {
|
this.timerId = setTimeout(() => {
|
||||||
|
|||||||
@ -1,26 +1,29 @@
|
|||||||
{
|
{
|
||||||
"files": [],
|
"files": [],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "./spine-core"
|
"path": "./spine-core"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "./spine-canvas"
|
"path": "./spine-canvas"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "./spine-webgl"
|
"path": "./spine-canvaskit"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "./spine-phaser"
|
"path": "./spine-webgl"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "./spine-player"
|
"path": "./spine-phaser"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "./spine-threejs"
|
"path": "./spine-player"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "./spine-pixi"
|
"path": "./spine-threejs"
|
||||||
}
|
},
|
||||||
]
|
{
|
||||||
|
"path": "./spine-pixi"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user