Readme update, added barebones.html.

This commit is contained in:
Nathan Sweet 2020-07-17 19:50:39 +02:00
parent 498cf7ac6f
commit acc9e127d4
4 changed files with 257 additions and 88 deletions

View File

@ -1,17 +1,18 @@
# spine-ts # spine-ts
The spine-ts runtime provides functionality to load and manipulate [Spine](http://esotericsoftware.com) skeletal animation data using TypeScript and JavaScript. spine-ts is split The spine-ts runtime provides functionality to load and manipulate [Spine](http://esotericsoftware.com) skeletal animation data using TypeScript and JavaScript. spine-ts is split
up into multiple modules: up into multiple modules:
1. **Core**: `core/`, the core classes to load and process Spine models 1. **Core**: `core/`, the core classes to load and process Spine skeletons.
1. **WebGL**: `webgl/`, a self-contained WebGL backend, build on the core classes 1. **WebGL**: `webgl/`, a self-contained WebGL backend, built on the core classes.
1. **Canvas**: `canvas/`, a self-contained Canvas backend, build on the core classes 1. **Canvas**: `canvas/`, a self-contained Canvas backend, built on the core classes.
1. **THREE.JS**: `threejs/`, a self-contained THREE.JS backend, build on the core classes 1. **THREE.JS**: `threejs/`, a self-contained THREE.JS backend, built on the core classes.
1. **Player**: `player/`, a self-contained player to easily display Spine animations on your website, build on core classes & WebGL backend. 1. **Player**: `player/`, a self-contained player to easily display Spine animations on your website, built on core the classes and WebGL backend.
While the source code for the core library and backends is written in TypeScript, all code is compiled to easily consumable JavaScript. While the source code for the core library and backends is written in TypeScript, all code is compiled to JavaScript.
## Licensing ## Licensing
You are welcome to evaluate the Spine Runtimes and the examples we provide in this repository free of charge. You are welcome to evaluate the Spine Runtimes and the examples we provide in this repository free of charge.
You can integrate the Spine Runtimes into your software free of charge, but users of your software must have their own [Spine license](https://esotericsoftware.com/spine-purchase). Please make your users aware of this requirement! This option is often chosen by those making development tools, such as an SDK, game toolkit, or software library. You can integrate the Spine Runtimes into your software free of charge, but users of your software must have their own [Spine license](https://esotericsoftware.com/spine-purchase). Please make your users aware of this requirement! This option is often chosen by those making development tools, such as an SDK, game toolkit, or software library.
@ -24,15 +25,14 @@ For the official legal terms governing the Spine Runtimes, please read the [Spin
spine-ts works with data exported from Spine 3.8.xx. spine-ts works with data exported from Spine 3.8.xx.
spine-ts WebGL & players backends supports all Spine features. The spine-ts WebGL and Player backends support all Spine features.
spine-ts Canvas does not support white space stripped texture atlases, 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 white space stripped texture atlases, color tinting, mesh attachments, or 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 experimental mesh rendering is slow and may lead to artifacts on some browsers.
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 THREE.JS does not support two color tinting or 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.
## Usage ## Usage
1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it as a zip via the download button above. 1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it as a zip via the download button above.
2. To use only the core library without rendering support, include the `build/spine-core.js` file in your project. 2. To use only the core library without rendering support, include the `build/spine-core.js` file in your project.
3. To use the WebGL backend, include the `build/spine-webgl.js` file in your project. 3. To use the WebGL backend, include the `build/spine-webgl.js` file in your project.
@ -42,91 +42,102 @@ spine-ts does not yet support loading the binary format.
All `*.js` files are self-contained and include both the core and respective backend classes. All `*.js` files are self-contained and include both the core and respective backend classes.
If you write your app with TypeScript, additionally copy the corresponding `build/spine-*.d.ts` file to your project. If you write your app with TypeScript, additionally copy the corresponding `build/spine-*.d.ts` file into your project.
**Note:** If you are using the compiled `.js` files with ES6 or other module systems, you have to add **Note:** If you are using the compiled `.js` files with ES6 or other module systems, you need to add:
``` ```
export { spine }; export { spine };
``` ```
At the bottom of the `.js` file you are using. You can then import the module as usual, e.g.: At the bottom of the `.js` file you are using. You can then import the module as usual, for example:
``` ```
import { spine } from './spine-webgl.js'; import { spine } from './spine-webgl.js';
``` ```
## Examples ## Examples
To run the examples, the image, atlas, and JSON files must be served by a webserver, they can't be loaded from your local disk. Spawn a light-weight web server in the root of spine-ts, then navigate to the `index.html` file for the example you want to view. E.g.:
To run the various examples found in each of the spine-ts backend folders, the image, atlas, and JSON files must be served by a webserver. For security reasons browsers will not load these files from your local disk. To work around this, you can spawn a lightweight web server in the spine-ts folder, then navigate to the `index.html` file for the example you want to view. For example:
``` ```
cd spine-ts cd spine-ts
python -m SimpleHTTPServer python -m SimpleHTTPServer // for Python 2
python -m http.server // for Python 3
``` ```
Then open `http://localhost:8000/webgl/example`, `http://localhost:8000/canvas/example`, `https://localhost:8000/threejs/example` or `http://localhost:8000/player/example` in your browser. Then open `http://localhost:8000/webgl/example`, `http://localhost:8000/canvas/example`, `https://localhost:8000/threejs/example`, or `http://localhost:8000/player/example` in your browser.
## WebGL Demos ### WebGL demos
The spine-ts WebGL demos load their image, atlas, and JSON files from our webserver and so can be run directly, without needing a webserver. The demos can be viewed [all on one page](http://esotericsoftware.com/spine-demos/) or in individual, standalone pages which are easy for you to explore and edit. See the [standalone demos source code](webgl/demos) and view the pages here:
- [Spine vs sprite sheets](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/spritesheets.html) The spine-ts WebGL demos can be viewed [all on one page](http://esotericsoftware.com/spine-demos/) or in individual, standalone pages which are easy for you to explore and edit. See the [standalone demos source code](webgl/demos) and view the pages here:
- [Image changes](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/imagechanges.html)
- [Transitions](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/transitions.html) - [Spine vs sprite sheets](http://rawgit.com/EsotericSoftware/spine-runtimes/3.8/spine-ts/webgl/demos/spritesheets.html)
- [Meshes](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/meshes.html) - [Image changes](http://rawgit.com/EsotericSoftware/spine-runtimes/3.8/spine-ts/webgl/demos/imagechanges.html)
- [Skins](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/skins.html) - [Transitions](http://rawgit.com/EsotericSoftware/spine-runtimes/3.8/spine-ts/webgl/demos/transitions.html)
- [Hoverboard](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/hoverboard.html) - [Meshes](http://rawgit.com/EsotericSoftware/spine-runtimes/3.8/spine-ts/webgl/demos/meshes.html)
- [Vine](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/vine.html) - [Skins](http://rawgit.com/EsotericSoftware/spine-runtimes/3.8/spine-ts/webgl/demos/skins.html)
- [Clipping](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/clipping.html) - [Hoverboard](http://rawgit.com/EsotericSoftware/spine-runtimes/3.8/spine-ts/webgl/demos/hoverboard.html)
- [Stretchyman](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/stretchyman.html) - [Vine](http://rawgit.com/EsotericSoftware/spine-runtimes/3.8/spine-ts/webgl/demos/vine.html)
- [Tank](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/tank.html) - [Clipping](http://rawgit.com/EsotericSoftware/spine-runtimes/3.8/spine-ts/webgl/demos/clipping.html)
- [Transform constraints](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/transforms.html) - [Stretchyman](http://rawgit.com/EsotericSoftware/spine-runtimes/3.8/spine-ts/webgl/demos/stretchyman.html)
- [Tank](http://rawgit.com/EsotericSoftware/spine-runtimes/3.8/spine-ts/webgl/demos/tank.html)
- [Transform constraints](http://rawgit.com/EsotericSoftware/spine-runtimes/3.8/spine-ts/webgl/demos/transforms.html)
Please note that Chrome and possibly other browsers do not use the original CORS headers when loading cached resources. After the initial page load for a demo, you may need to forcefully refresh (hold `shift` and click refresh) or clear your browser cache. Please note that Chrome and possibly other browsers do not use the original CORS headers when loading cached resources. After the initial page load for a demo, you may need to forcefully refresh (hold `shift` and click refresh) or clear your browser cache.
## Development Setup ### WebGL examples
The spine-ts runtime and the various backends are implemented in TypeScript for greater maintainability and better tooling support. To
setup a development environment, follow these steps.
1. Install [NPM](https://nodejs.org/en/download/) and make sure it's available on the command line The WebGL demos serve well as examples, showing various ways to use the APIs. We also provide a simple, self-contained example with UI to control the skeletons:
2. On the command line, Install the TypeScript compiler via `npm install -g typescript`
3. Install [Visual Studio Code](https://code.visualstudio.com/) - [WebGL example](http://rawgit.com/EsotericSoftware/spine-runtimes/3.8/spine-ts/webgl/example/index.html)
4. On the command line, change into the `spine-ts` directory
A barebones example is also available. It doesn't use JQuery and shows the minimal code necessary to use spine-ts with WebGL to load and render a skeleton:
- [WebGL barebones](http://rawgit.com/EsotericSoftware/spine-runtimes/3.8/spine-ts/webgl/example/barebones.html)
## Development setup
The spine-ts runtime and the various backends are implemented in TypeScript for greater maintainability and better tooling support. To setup a development environment, follow these steps:
1. Install [NPM](https://nodejs.org/en/download/) and make sure it's available on the command line.
2. On the command line, Install the TypeScript compiler via `npm install -g typescript`.
3. Install [Visual Studio Code](https://code.visualstudio.com/).
4. On the command line, change into the `spine-ts` directory.
5. Start the TypeScript compiler in watcher mode for the backend you want to work on: 5. Start the TypeScript compiler in watcher mode for the backend you want to work on:
* **Core**: `tsc -w -p tsconfig.core.json`, builds `core/src`, outputs `build/spine-core.js|d.ts|js.map` * **Core**: `tsc -w -p tsconfig.core.json`, builds `core/src`, outputs `build/spine-core.js|d.ts|js.map`.
* **WebGL**: `tsc -w -p tsconfig.webgl.json`, builds `core/src` and `webgl/src`, outputs `build/spine-webgl.js|d.ts|js.map` * **WebGL**: `tsc -w -p tsconfig.webgl.json`, builds `core/src` and `webgl/src`, outputs `build/spine-webgl.js|d.ts|js.map`.
* **Canvas**: `tsc -w -p tsconfig.canvas.json`, builds `core/src` and `canvas/src`, outputs `build/spine-canvas.js|d.ts|js.map` * **Canvas**: `tsc -w -p tsconfig.canvas.json`, builds `core/src` and `canvas/src`, outputs `build/spine-canvas.js|d.ts|js.map`.
* **THREE.JS**: `tsc -w -p tsconfig.threejs.json`, builds `core/src` and `threejs/src`, outputs `build/spine-threejs.js|d.ts|js.map` * **THREE.JS**: `tsc -w -p tsconfig.threejs.json`, builds `core/src` and `threejs/src`, outputs `build/spine-threejs.js|d.ts|js.map`.
* **Player**: `tsc -w -p tsconfig.player.json`, builds `core/src` and `player/src`, outputs `build/spine-player.js|d.ts|js.map` * **Player**: `tsc -w -p tsconfig.player.json`, builds `core/src` and `player/src`, outputs `build/spine-player.js|d.ts|js.map`.
6. Open the `spine-ts` folder in Visual Studio Code. VS Code will use the `tsconfig.json` file all source files from core and all 6. Open the `spine-ts` folder in Visual Studio Code. VS Code will use the `tsconfig.json` file to find all source files for your development pleasure. The actual JavaScript output is still created by the command line TypeScript compiler process from the previous step.
backends for your development pleasure. The actual JavaScript output is still created by the command line TypeScript compiler process from the previous step.
Each backend contains an `example/` folder with an `index.html` file that demonstrates the respective backend. For development, we Each backend contains an `example/` folder with an `index.html` file that demonstrates the respective backend. For development, we suggest to run a HTTP server in the root of `spine-ts`, for example:
suggest to run a HTTP server in the root of `spine-ts`, e.g.
``` ```
cd spine-ts cd spine-ts
python -m SimpleHTTPServer python -m SimpleHTTPServer // for Python 2
python -m http.server // for Python 3
``` ```
Then navigate to `http://localhost:8000/webgl/example`, `http://localhost:8000/canvas/example`, `http://localhost:8000/threejs/example` or `http://localhost:8000/player/example` Then navigate to `http://localhost:8000/webgl/example`, `http://localhost:8000/canvas/example`, `http://localhost:8000/threejs/example`, or `http://localhost:8000/player/example`.
### Spine-ts WebGL backend ### WebGL backend
By default, the spine-ts WebGL backend supports two-color tinting. This has a neglible effect on performance, as more per vertex data has to be submitted to the GPU, and the fragment shader has to do a few more arithmetic operations.
You can disable two-color tinting like this: By default, the spine-ts WebGL backend supports two-color tinting. This requires more per vertex data to be submitted to the GPU and the fragment shader has to do a few more arithmetic operations. It has a neglible effect on performance, but you can disable two-color tinting like this:
```javascript ```javascript
// 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
// disable two-color tinting in the respective constructor // tinting in the respective constructor and use the shader returned by
// and use the shader returned by Shader.newColoredTextured() // Shader.newColoredTextured() instead of Shader.newTwoColoredTextured().
// instead of Shader.newTwoColoredTextured()
var batcher = new spine.PolygonBatcher(gl, false); var batcher = new spine.PolygonBatcher(gl, false);
var skeletonRenderer = new spine.SkeletonRenderer(gl, false); var skeletonRenderer = new spine.SkeletonRenderer(gl, false);
var shader = Shader.newColoredTextured(); var shader = Shader.newColoredTextured();
``` ```
### Using the Player ### Using the Player
Please see the documentation for the [Spine Web Player](https://esotericsoftware.com/spine-player)
Please see the documentation for the [Spine Web Player](https://esotericsoftware.com/spine-player).

View File

@ -4,7 +4,6 @@ $(function () {
alert("Error: " + message + "\n" + "URL:" + url + "\nLine: " + lineNo); alert("Error: " + message + "\n" + "URL:" + url + "\nLine: " + lineNo);
} }
spineDemos.init(); spineDemos.init();
spineDemos.assetManager = new spine.SharedAssetManager("assets/"); spineDemos.assetManager = new spine.SharedAssetManager("assets/");

View File

@ -0,0 +1,157 @@
<html>
<script src="../../build/spine-webgl.js"></script>
<style>
* { margin: 0; padding: 0; }
body, html { height: 100% }
canvas { position: absolute; width: 100% ;height: 100%; }
</style>
<body>
<canvas id="canvas"></canvas>
<script>
var canvas;
var gl;
var shader;
var batcher;
var mvp = new spine.webgl.Matrix4();
var assetManager;
var skeletonRenderer;
var lastFrameTime;
var spineboy;
function init () {
// Setup canvas and WebGL context. We pass alpha: false to canvas.getContext() so we don't use premultiplied alpha when
// loading textures. That is handled separately by PolygonBatcher.
canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var config = { alpha: false };
gl = canvas.getContext("webgl", config) || canvas.getContext("experimental-webgl", config);
if (!gl) {
alert('WebGL is unavailable.');
return;
}
// Create a simple shader, mesh, model-view-projection matrix, SkeletonRenderer, and AssetManager.
shader = spine.webgl.Shader.newTwoColoredTextured(gl);
batcher = new spine.webgl.PolygonBatcher(gl);
mvp.ortho2d(0, 0, canvas.width - 1, canvas.height - 1);
skeletonRenderer = new spine.webgl.SkeletonRenderer(gl);
assetManager = new spine.webgl.AssetManager(gl);
// Tell AssetManager to load the resources for each skeleton, including the exported .skel file, the .atlas file and the .png
// file for the atlas. We then wait until all resources are loaded in the load() method.
assetManager.loadBinary("assets/spineboy-pro.skel");
assetManager.loadTextureAtlas("assets/spineboy-pma.atlas");
requestAnimationFrame(load);
}
function load () {
// Wait until the AssetManager has loaded all resources, then load the skeletons.
if (assetManager.isLoadingComplete()) {
spineboy = loadSpineboy("run", true);
lastFrameTime = Date.now() / 1000;
requestAnimationFrame(render); // Loading is done, call render every frame.
} else {
requestAnimationFrame(load);
}
}
function loadSpineboy (initialAnimation, premultipliedAlpha) {
// Load the texture atlas from the AssetManager.
var atlas = assetManager.get("assets/spineboy-pma.atlas");
// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
var atlasLoader = new spine.AtlasAttachmentLoader(atlas);
// Create a SkeletonBinary instance for parsing the .skel file.
var skeletonBinary = new spine.SkeletonBinary(atlasLoader);
// Set the scale to apply during parsing, parse the file, and create a new skeleton.
skeletonBinary.scale = 1;
var skeletonData = skeletonBinary.readSkeletonData(assetManager.get("assets/spineboy-pro.skel"));
var skeleton = new spine.Skeleton(skeletonData);
var bounds = calculateSetupPoseBounds(skeleton);
// Create an AnimationState, and set the initial animation in looping mode.
var animationStateData = new spine.AnimationStateData(skeleton.data);
var animationState = new spine.AnimationState(animationStateData);
animationState.setAnimation(0, initialAnimation, true);
// Pack everything up and return to caller.
return { skeleton: skeleton, state: animationState, bounds: bounds, premultipliedAlpha: premultipliedAlpha };
}
function calculateSetupPoseBounds (skeleton) {
skeleton.setToSetupPose();
skeleton.updateWorldTransform();
var offset = new spine.Vector2();
var size = new spine.Vector2();
skeleton.getBounds(offset, size, []);
return { offset: offset, size: size };
}
function render () {
var now = Date.now() / 1000;
var delta = now - lastFrameTime;
lastFrameTime = now;
// Update the MVP matrix to adjust for canvas size changes
resize();
gl.clearColor(0.3, 0.3, 0.3, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// Apply the animation state based on the delta time.
var skeleton = spineboy.skeleton;
var state = spineboy.state;
var premultipliedAlpha = spineboy.premultipliedAlpha;
state.update(delta);
state.apply(skeleton);
skeleton.updateWorldTransform();
// Bind the shader and set the texture and model-view-projection matrix.
shader.bind();
shader.setUniformi(spine.webgl.Shader.SAMPLER, 0);
shader.setUniform4x4f(spine.webgl.Shader.MVP_MATRIX, mvp.values);
// Start the batch and tell the SkeletonRenderer to render the active skeleton.
batcher.begin(shader);
skeletonRenderer.premultipliedAlpha = premultipliedAlpha;
skeletonRenderer.draw(batcher, skeleton);
batcher.end();
shader.unbind();
requestAnimationFrame(render);
}
function resize () {
var w = canvas.clientWidth;
var h = canvas.clientHeight;
if (canvas.width != w || canvas.height != h) {
canvas.width = w;
canvas.height = h;
}
// Calculations to center the skeleton in the canvas.
var bounds = spineboy.bounds;
var centerX = bounds.offset.x + bounds.size.x / 2;
var centerY = bounds.offset.y + bounds.size.y / 2;
var scaleX = bounds.size.x / canvas.width;
var scaleY = bounds.size.y / canvas.height;
var scale = Math.max(scaleX, scaleY) * 1.2;
if (scale < 1) scale = 1;
var width = canvas.width * scale;
var height = canvas.height * scale;
mvp.ortho2d(centerX - width / 2, centerY - height / 2, width, height);
gl.viewport(0, 0, canvas.width, canvas.height);
}
init();
</script>
</body>
</html>

View File

@ -2,9 +2,9 @@
<script src="../../build/spine-webgl.js"></script> <script src="../../build/spine-webgl.js"></script>
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<style> <style>
* { margin: 0; padding: 0; } * { margin: 0; padding: 0; }
body, html { height: 100% } body, html { height: 100% }
canvas { position: absolute; width: 100% ;height: 100%; } canvas { position: absolute; width: 100% ;height: 100%; }
</style> </style>
<body> <body>
<canvas id="canvas"></canvas> <canvas id="canvas"></canvas>
@ -15,21 +15,22 @@
<span>Skin:</span><select id="skinList"></select> <span>Skin:</span><select id="skinList"></select>
<span>Vertex Effect:</span><select id="effectList"></select> <span>Vertex Effect:</span><select id="effectList"></select>
<span>Debug:</span><input type="checkbox" id="debug"> <span>Debug:</span><input type="checkbox" id="debug">
<div> </div>
</center> </center>
</body>
<script> <script>
var lastFrameTime = Date.now() / 1000;
var canvas; var canvas;
var gl;
var shader; var shader;
var batcher; var batcher;
var gl;
var mvp = new spine.webgl.Matrix4(); var mvp = new spine.webgl.Matrix4();
var assetManager;
var skeletonRenderer; var skeletonRenderer;
var assetManager;
var debugRenderer; var debugRenderer;
var shapes; var shapes;
var lastFrameTime;
var skeletons = {}; var skeletons = {};
var activeSkeleton = "spineboy"; var activeSkeleton = "spineboy";
var swirlEffect = new spine.SwirlEffect(0); var swirlEffect = new spine.SwirlEffect(0);
@ -49,11 +50,14 @@ function init () {
return; return;
} }
// Create a simple shader, mesh, model-view-projection matrix and SkeletonRenderer. // Create a simple shader, mesh, model-view-projection matrix, SkeletonRenderer, and AssetManager.
shader = spine.webgl.Shader.newTwoColoredTextured(gl); shader = spine.webgl.Shader.newTwoColoredTextured(gl);
batcher = new spine.webgl.PolygonBatcher(gl); batcher = new spine.webgl.PolygonBatcher(gl);
mvp.ortho2d(0, 0, canvas.width - 1, canvas.height - 1); mvp.ortho2d(0, 0, canvas.width - 1, canvas.height - 1);
skeletonRenderer = new spine.webgl.SkeletonRenderer(gl); skeletonRenderer = new spine.webgl.SkeletonRenderer(gl);
assetManager = new spine.webgl.AssetManager(gl);
// Create a debug renderer and the ShapeRenderer it needs to render lines.
debugRenderer = new spine.webgl.SkeletonDebugRenderer(gl); debugRenderer = new spine.webgl.SkeletonDebugRenderer(gl);
debugRenderer.drawRegionAttachments = true; debugRenderer.drawRegionAttachments = true;
debugRenderer.drawBoundingBoxes = true; debugRenderer.drawBoundingBoxes = true;
@ -62,9 +66,8 @@ function init () {
debugRenderer.drawPaths = true; debugRenderer.drawPaths = true;
debugShader = spine.webgl.Shader.newColored(gl); debugShader = spine.webgl.Shader.newColored(gl);
shapes = new spine.webgl.ShapeRenderer(gl); shapes = new spine.webgl.ShapeRenderer(gl);
assetManager = new spine.webgl.AssetManager(gl);
// Tell AssetManager to load the resources for each model, including the exported .skel file, the .atlas file and the .png // Tell AssetManager to load the resources for each skeleton, including the exported .skel file, the .atlas file and the .png
// file for the atlas. We then wait until all resources are loaded in the load() method. // file for the atlas. We then wait until all resources are loaded in the load() method.
assetManager.loadBinary("assets/spineboy-pro.skel"); assetManager.loadBinary("assets/spineboy-pro.skel");
assetManager.loadTextureAtlas("assets/spineboy-pma.atlas"); assetManager.loadTextureAtlas("assets/spineboy-pma.atlas");
@ -94,7 +97,8 @@ function load () {
skeletons["stretchyman"] = loadSkeleton("stretchyman-pro", "sneak", true); skeletons["stretchyman"] = loadSkeleton("stretchyman-pro", "sneak", true);
skeletons["coin"] = loadSkeleton("coin-pro", "animation", true); skeletons["coin"] = loadSkeleton("coin-pro", "animation", true);
setupUI(); setupUI();
requestAnimationFrame(render); lastFrameTime = Date.now() / 1000;
requestAnimationFrame(render); // Loading is done, call render every frame.
} else { } else {
requestAnimationFrame(load); requestAnimationFrame(load);
} }
@ -104,22 +108,23 @@ function loadSkeleton (name, initialAnimation, premultipliedAlpha, skin) {
if (skin === undefined) skin = "default"; if (skin === undefined) skin = "default";
// Load the texture atlas using name.atlas from the AssetManager. // Load the texture atlas using name.atlas from the AssetManager.
atlas = assetManager.get("assets/" + name.replace("-ess", "").replace("-pro", "") + (premultipliedAlpha ? "-pma": "") + ".atlas"); var atlas = assetManager.get("assets/" + name.replace("-ess", "").replace("-pro", "") + (premultipliedAlpha ? "-pma": "") + ".atlas");
// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments // Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
atlasLoader = new spine.AtlasAttachmentLoader(atlas); var atlasLoader = new spine.AtlasAttachmentLoader(atlas);
// Create a SkeletonBinary instance for parsing the .skel file. // Create a SkeletonBinary instance for parsing the .skel file.
var skeletonBinary = new spine.SkeletonBinary(atlasLoader); var skeletonBinary = new spine.SkeletonBinary(atlasLoader);
// Set the scale to apply during parsing, parse the file, and create a new skeleton. // Set the scale to apply during parsing, parse the file, and create a new skeleton.
skeletonBinary.scale = 1;
var skeletonData = skeletonBinary.readSkeletonData(assetManager.get("assets/" + name + ".skel")); var skeletonData = skeletonBinary.readSkeletonData(assetManager.get("assets/" + name + ".skel"));
var skeleton = new spine.Skeleton(skeletonData); var skeleton = new spine.Skeleton(skeletonData);
skeleton.setSkinByName(skin); skeleton.setSkinByName(skin);
var bounds = calculateBounds(skeleton); var bounds = calculateSetupPoseBounds(skeleton);
// Create an AnimationState, and set the initial animation in looping mode. // Create an AnimationState, and set the initial animation in looping mode.
animationStateData = new spine.AnimationStateData(skeleton.data); var animationStateData = new spine.AnimationStateData(skeleton.data);
var animationState = new spine.AnimationState(animationStateData); var animationState = new spine.AnimationState(animationStateData);
if (name == "spineboy") { if (name == "spineboy") {
animationStateData.setMix("walk", "jump", 0.4) animationStateData.setMix("walk", "jump", 0.4)
@ -155,7 +160,7 @@ function loadSkeleton (name, initialAnimation, premultipliedAlpha, skin) {
return { skeleton: skeleton, state: animationState, bounds: bounds, premultipliedAlpha: premultipliedAlpha }; return { skeleton: skeleton, state: animationState, bounds: bounds, premultipliedAlpha: premultipliedAlpha };
} }
function calculateBounds(skeleton) { function calculateSetupPoseBounds(skeleton) {
skeleton.setToSetupPose(); skeleton.setToSetupPose();
skeleton.updateWorldTransform(); skeleton.updateWorldTransform();
var offset = new spine.Vector2(); var offset = new spine.Vector2();
@ -236,7 +241,6 @@ function setupUI () {
function render () { function render () {
var now = Date.now() / 1000; var now = Date.now() / 1000;
var delta = now - lastFrameTime; var delta = now - lastFrameTime;
delta = 0.016;
lastFrameTime = now; lastFrameTime = now;
// Update the MVP matrix to adjust for canvas size changes // Update the MVP matrix to adjust for canvas size changes
@ -246,8 +250,8 @@ function render () {
gl.clear(gl.COLOR_BUFFER_BIT); gl.clear(gl.COLOR_BUFFER_BIT);
// Apply the animation state based on the delta time. // Apply the animation state based on the delta time.
var state = skeletons[activeSkeleton].state;
var skeleton = skeletons[activeSkeleton].skeleton; var skeleton = skeletons[activeSkeleton].skeleton;
var state = skeletons[activeSkeleton].state;
var bounds = skeletons[activeSkeleton].bounds; var bounds = skeletons[activeSkeleton].bounds;
var premultipliedAlpha = skeletons[activeSkeleton].premultipliedAlpha; var premultipliedAlpha = skeletons[activeSkeleton].premultipliedAlpha;
state.update(delta); state.update(delta);
@ -269,10 +273,9 @@ function render () {
swirlTime += delta; swirlTime += delta;
var percent = swirlTime % 2; var percent = swirlTime % 2;
if (percent > 1) percent = 1 - (percent -1 ); if (percent > 1) percent = 1 - (percent -1 );
// swirlEffect.angle = -60 + 120 * (perecent < 0.5 ? Math.pow(percent * 2, 2) / 2 : Math.pow((percent - 1) * 2, 2) / -2 + 1); swirlEffect.angle = 120 * percent - 60;
swirlEffect.angle = 360 * percent; swirlEffect.centerX = bounds.offset.x + bounds.size.x / 2;
swirlEffect.centerX = 200; //bounds.offset.x + bounds.size.x / 2 swirlEffect.centerY = bounds.offset.y + bounds.size.y / 2;
swirlEffect.centerY = 200; //bounds.offset.y + bounds.size.y / 2
swirlEffect.radius = Math.sqrt(bounds.size.x * bounds.size.x + bounds.size.y * bounds.size.y); swirlEffect.radius = Math.sqrt(bounds.size.x * bounds.size.x + bounds.size.y * bounds.size.y);
skeletonRenderer.vertexEffect = swirlEffect; skeletonRenderer.vertexEffect = swirlEffect;
} else if (effect == "Jitter") { } else if (effect == "Jitter") {
@ -285,7 +288,7 @@ function render () {
shader.unbind(); shader.unbind();
// draw debug information // Draw debug information.
var debug = $('#debug').is(':checked'); var debug = $('#debug').is(':checked');
if (debug) { if (debug) {
debugShader.bind(); debugShader.bind();
@ -303,13 +306,13 @@ function render () {
function resize () { function resize () {
var w = canvas.clientWidth; var w = canvas.clientWidth;
var h = canvas.clientHeight; var h = canvas.clientHeight;
var bounds = skeletons[activeSkeleton].bounds;
if (canvas.width != w || canvas.height != h) { if (canvas.width != w || canvas.height != h) {
canvas.width = w; canvas.width = w;
canvas.height = h; canvas.height = h;
} }
// magic // Calculations to center the skeleton in the canvas.
var bounds = skeletons[activeSkeleton].bounds;
var centerX = bounds.offset.x + bounds.size.x / 2; var centerX = bounds.offset.x + bounds.size.x / 2;
var centerY = bounds.offset.y + bounds.size.y / 2; var centerY = bounds.offset.y + bounds.size.y / 2;
var scaleX = bounds.size.x / canvas.width; var scaleX = bounds.size.x / canvas.width;
@ -323,9 +326,8 @@ function resize () {
gl.viewport(0, 0, canvas.width, canvas.height); gl.viewport(0, 0, canvas.width, canvas.height);
} }
(function() { init();
init();
})();
</script> </script>
</body>
</html> </html>