mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-19 16:26:40 +08:00
Previously, we'd export to global objects called spine.canvas, spine.webgl, spine.threejs. Going forward, all Spine APIs will be hosted by the global spine object when the runtime is used straight from the bundled .js files in the build/ folder. This is a minor change with a simple fix on the user side, i.e. replace spine.canvas. with spine.
171 lines
5.3 KiB
HTML
171 lines
5.3 KiB
HTML
<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.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.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);
|
|
|
|
// 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.require("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.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);
|
|
|
|
// 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> |