|
@@ -5,166 +5,74 @@
|
|
|
margin: 0;
|
|
|
padding: 0;
|
|
|
}
|
|
|
-
|
|
|
- body,
|
|
|
- html {
|
|
|
- height: 100%
|
|
|
- }
|
|
|
-
|
|
|
- canvas {
|
|
|
- position: absolute;
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- }
|
|
|
</style>
|
|
|
|
|
|
<body>
|
|
|
- <canvas id="canvas"></canvas>
|
|
|
+ <canvas id="canvas" style="position: absolute; width: 100%; height: 100%;"></canvas>
|
|
|
<script>
|
|
|
-
|
|
|
- var canvas;
|
|
|
- var gl;
|
|
|
- var shader;
|
|
|
- var batcher;
|
|
|
- var mvp = new spine.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;
|
|
|
+ class App {
|
|
|
+ skeleton;
|
|
|
+ animationState;
|
|
|
+
|
|
|
+ loadAssets(canvas) {
|
|
|
+ // Load the skeleton file.
|
|
|
+ canvas.assetManager.loadBinary("assets/spineboy-pro.skel");
|
|
|
+ // Load the atlas and its pages.
|
|
|
+ canvas.assetManager.loadTextureAtlas("assets/spineboy-pma.atlas");
|
|
|
}
|
|
|
|
|
|
- // Create a simple shader, mesh, model-view-projection matrix, SkeletonRenderer, and AssetManager.
|
|
|
- shader = spine.Shader.newTwoColoredTextured(gl);
|
|
|
- batcher = new spine.PolygonBatcher(gl);
|
|
|
- mvp.ortho2d(0, 0, canvas.width - 1, canvas.height - 1);
|
|
|
- skeletonRenderer = new spine.SkeletonRenderer(gl);
|
|
|
- assetManager = new spine.AssetManager(gl);
|
|
|
+ initialize(canvas) {
|
|
|
+ let assetManager = canvas.assetManager;
|
|
|
|
|
|
- // 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);
|
|
|
- }
|
|
|
- }
|
|
|
+ // Create the texture atlas.
|
|
|
+ var atlas = assetManager.require("assets/spineboy-pma.atlas");
|
|
|
|
|
|
- function loadSpineboy(initialAnimation, premultipliedAlpha) {
|
|
|
- // Load the texture atlas from the AssetManager.
|
|
|
- var atlas = assetManager.require("assets/spineboy-pma.atlas");
|
|
|
+ // Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
|
|
|
+ var atlasLoader = new spine.AtlasAttachmentLoader(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);
|
|
|
|
|
|
- // 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.require("assets/spineboy-pro.skel"));
|
|
|
+ this.skeleton = new spine.Skeleton(skeletonData);
|
|
|
|
|
|
- // Set the scale to apply during parsing, parse the file, and create a new skeleton.
|
|
|
- skeletonBinary.scale = 1;
|
|
|
- var skeletonData = skeletonBinary.readSkeletonData(assetManager.require("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.Shader.SAMPLER, 0);
|
|
|
- shader.setUniform4x4f(spine.Shader.MVP_MATRIX, mvp.values);
|
|
|
+ // Create an AnimationState, and set the "run" animation in looping mode.
|
|
|
+ var animationStateData = new spine.AnimationStateData(skeletonData);
|
|
|
+ this.animationState = new spine.AnimationState(animationStateData);
|
|
|
+ this.animationState.setAnimation(0, "run", true);
|
|
|
+ }
|
|
|
|
|
|
- // Start the batch and tell the SkeletonRenderer to render the active skeleton.
|
|
|
- batcher.begin(shader);
|
|
|
- skeletonRenderer.premultipliedAlpha = premultipliedAlpha;
|
|
|
- skeletonRenderer.draw(batcher, skeleton);
|
|
|
- batcher.end();
|
|
|
+ update(canvas, delta) {
|
|
|
+ // Update the animation state using the delta time.
|
|
|
+ this.animationState.update(delta);
|
|
|
+ // Apply the animation state to the skeleton.
|
|
|
+ this.animationState.apply(this.skeleton);
|
|
|
+ // Let the skeleton update the transforms of its bones.
|
|
|
+ this.skeleton.updateWorldTransform();
|
|
|
+ }
|
|
|
|
|
|
- shader.unbind();
|
|
|
+ render(canvas) {
|
|
|
+ let renderer = canvas.renderer;
|
|
|
+ // Resize the viewport to the full canvas.
|
|
|
+ renderer.resize(spine.ResizeMode.Expand);
|
|
|
|
|
|
- requestAnimationFrame(render);
|
|
|
- }
|
|
|
+ // Clear the canvas with a light gray color.
|
|
|
+ canvas.clear(0.2, 0.2, 0.2, 1);
|
|
|
|
|
|
- function resize() {
|
|
|
- var w = canvas.clientWidth;
|
|
|
- var h = canvas.clientHeight;
|
|
|
- if (canvas.width != w || canvas.height != h) {
|
|
|
- canvas.width = w;
|
|
|
- canvas.height = h;
|
|
|
+ // Begin rendering.
|
|
|
+ renderer.begin();
|
|
|
+ // Draw the skeleton
|
|
|
+ renderer.drawSkeleton(this.skeleton, true);
|
|
|
+ // Complete rendering.
|
|
|
+ renderer.end();
|
|
|
}
|
|
|
-
|
|
|
- // 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();
|
|
|
-
|
|
|
+ new spine.SpineCanvas(document.getElementById("canvas"), {
|
|
|
+ app: new App()
|
|
|
+ })
|
|
|
</script>
|
|
|
</body>
|
|
|
|