From b14fb26ad8987220b754330560cac779f5be2349 Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Mon, 11 Sep 2017 21:35:35 +0200 Subject: [PATCH 01/20] Updated spineboy and alien demos. --- spine-ts/webgl/demos/hoverboard.js | 7 ++-- spine-ts/webgl/demos/imagechanges.js | 56 ++++++++++++++-------------- spine-ts/webgl/demos/transitions.js | 24 ++++++------ 3 files changed, 42 insertions(+), 45 deletions(-) diff --git a/spine-ts/webgl/demos/hoverboard.js b/spine-ts/webgl/demos/hoverboard.js index ad8128c87..643d7559f 100644 --- a/spine-ts/webgl/demos/hoverboard.js +++ b/spine-ts/webgl/demos/hoverboard.js @@ -46,16 +46,17 @@ var hoverboardDemo = function(loadingComplete, bgColor) { }); var atlasLoader = new spine.AtlasAttachmentLoader(atlas); var skeletonJson = new spine.SkeletonJson(atlasLoader); - var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json")["spineboy-hover"]); + var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json")["spineboy"]); skeleton = new spine.Skeleton(skeletonData); state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data)); - state.setAnimation(0, "idle", true); + state.setAnimation(0, "hoverboard", true); state.apply(skeleton); skeleton.updateWorldTransform(); var offset = new spine.Vector2(); bounds = new spine.Vector2(); skeleton.getBounds(offset, bounds, []); - for (var i = 0; i < controlBones.length; i++) hoverTargets.push(null); + for (var i = 0; i < controlBones.length; i++) + hoverTargets.push(null); renderer.camera.position.x = offset.x + bounds.x / 2; renderer.camera.position.y = offset.y + bounds.y / 2; diff --git a/spine-ts/webgl/demos/imagechanges.js b/spine-ts/webgl/demos/imagechanges.js index 90feb0a2d..ef55c595e 100644 --- a/spine-ts/webgl/demos/imagechanges.js +++ b/spine-ts/webgl/demos/imagechanges.js @@ -35,7 +35,7 @@ var imageChangesDemo = function(loadingComplete, bgColor) { function load () { timeKeeper.update(); if (assetManager.isLoadingComplete(DEMO_NAME)) { - skeletons["Alien"] = loadSkeleton("alien", "death", ["head", "splat01"]); + skeletons["Alien"] = loadSkeleton("alien", "death", ["head", "splat-fg", "splat-bg"]); skeletons["Dragon"] = loadSkeleton("dragon", "flying", ["R_wing"]) setupUI(); loadingComplete(canvas, render); @@ -109,9 +109,8 @@ var imageChangesDemo = function(loadingComplete, bgColor) { for(var i = 0; i < sequenceSlots.length; i++) { var slot = sequenceSlots[i]; var index = skeleton.findSlotIndex(slot); - for (var name in skeleton.skin.attachments[index]) { + for (var name in skeleton.skin.attachments[index]) regions.push(skeleton.skin.attachments[index][name]); - } } return { @@ -138,17 +137,22 @@ var imageChangesDemo = function(loadingComplete, bgColor) { var offset = active.bounds.offset; var size = active.bounds.size; - var x = offset.x + size.x + 100, offsetY = offset.y; + var x = offset.x + size.x + 100, offsetY = offset.y, zoom = 1, rows, regionOffset = 0; if (activeSkeleton === "Alien") { - renderer.camera.position.x = offset.x + size.x; - renderer.camera.position.y = offset.y + size.y / 2; + renderer.camera.position.x = offset.x + size.x + 400; + renderer.camera.position.y = offset.y + size.y / 2 + 450; + x += 400; + zoom = 0.31; + rows = 3; + regionOffset = 3; } else { renderer.camera.position.x = offset.x + size.x; renderer.camera.position.y = offset.y + size.y / 2; x += 100; + rows = 3; } - renderer.camera.viewportWidth = size.x * 2.4; - renderer.camera.viewportHeight = size.y * 1.4; + renderer.camera.viewportWidth = size.x * 2.4 / zoom; + renderer.camera.viewportHeight = size.y * 1.4 / zoom; renderer.resize(spine.webgl.ResizeMode.Fit); gl.clearColor(bgColor.r, bgColor.g, bgColor.b, bgColor.a); @@ -172,39 +176,33 @@ var imageChangesDemo = function(loadingComplete, bgColor) { var y = offsetY; var slotsWidth = 0, slotsHeight = 0; - var slotSize = size.y / 3; + var slotSize = size.y / rows; var maxSlotWidth = 0; var j = 0; - for (var i = 0; i < active.regions.length; i++) { - var region = active.regions[i].region; - var scale = Math.min(slotSize / region.height, slotSize / region.width); - renderer.drawRegion(region, x, y, region.width * scale, region.height * scale); + for (var i = 0, n = active.regions.length; i < n; i++) { + var region = active.regions[(i + regionOffset) % n].region; + var width = region.rotate ? region.height : region.width; + var height = region.rotate ? region.width : region.height; + var scale = Math.min(slotSize / height, slotSize / width) / zoom; + renderer.drawRegion(region, x, y, width * scale, height * scale); var isVisible = false; for (var ii = 0; ii < active.slots.length; ii++) { var slotName = active.slots[ii]; - var slotIndex = skeleton.findSlotIndex(slotName); - - for (var iii = 0; iii < skeleton.drawOrder.length; iii++) { - var slot = skeleton.drawOrder[iii]; - if (slot.data.index == slotIndex) { - if (slot.attachment != null) { - if (slot.attachment.name === active.regions[i].name) { - isVisible = true; - break; - } - } - } + var slot = skeleton.findSlot(slotName); + if (slot && slot.attachment && slot.attachment.name === region.name) { + isVisible = true; + break; } if (isVisible) break; } - if (isVisible) renderer.rect(false, x, y, region.width * scale, region.height * scale, OUTLINE_COLOR); + if (isVisible) renderer.rect(false, x, y, width * scale, height * scale, OUTLINE_COLOR); - maxSlotWidth = Math.max(maxSlotWidth, region.width * scale); - y += slotSize; + maxSlotWidth = Math.max(maxSlotWidth, width * scale); + y += slotSize / zoom + 2; j++; - if (j == 3) { + if (j == rows) { x += maxSlotWidth + 10; maxSlotWidth = 0; y = offsetY; diff --git a/spine-ts/webgl/demos/transitions.js b/spine-ts/webgl/demos/transitions.js index 968aab432..1e38f0b13 100644 --- a/spine-ts/webgl/demos/transitions.js +++ b/spine-ts/webgl/demos/transitions.js @@ -45,9 +45,9 @@ var transitionsDemo = function(loadingComplete, bgColor) { skeletonNoMix = new spine.Skeleton(skeleton.data); state = createState(0.25); state.multipleMixing = true; - setAnimations(state, 0); + setAnimations(state, 0, true); stateNoMix = createState(0); - setAnimations(stateNoMix, -0.25); + setAnimations(stateNoMix, -0.25, true); state.apply(skeleton); skeleton.updateWorldTransform(); @@ -79,20 +79,18 @@ var transitionsDemo = function(loadingComplete, bgColor) { return state; } - function setAnimations(state, mix) { - state.addAnimation(0, "idle", true, 0.7); - state.addAnimation(0, "walk", true, 0.7); - state.addAnimation(0, "idle", true, 0.8); - state.addAnimation(0, "run", true, 0.7); - state.addAnimation(0, "idle", true, 0.8); + function setAnimations(state, mix, first) { + state.addAnimation(0, "idle", true, first ? 0 : 0.6); state.addAnimation(0, "walk", true, 0.6); - state.addAnimation(0, "run", true, 0.6); - state.addAnimation(0, "jump", false, 0.6); + state.addAnimation(0, "run", true, 1); + state.addAnimation(0, "walk", true, 1.2); + state.addAnimation(0, "run", true, 0.5); + state.addAnimation(0, "jump", false, 1); state.addAnimation(0, "run", true, mix); state.addAnimation(0, "jump", true, 0.5); - state.addAnimation(0, "run", true, mix).listener = { + state.addAnimation(0, "walk", true, mix).listener = { start: function (trackIndex) { - setAnimations(state, mix); + setAnimations(state, mix, false); } }; } @@ -134,7 +132,7 @@ var transitionsDemo = function(loadingComplete, bgColor) { state.update(delta); state.apply(skeleton); skeleton.updateWorldTransform(); - skeleton.x = -300; + skeleton.x = -200; skeleton.y = -100; renderer.drawSkeleton(skeleton, true); From b493b0ad67a5d717511407591f41459d89f69c9c Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Mon, 11 Sep 2017 21:53:45 +0200 Subject: [PATCH 02/20] Added clipping demo. --- spine-ts/webgl/demos/clipping.html | 24 ++++++ spine-ts/webgl/demos/clipping.js | 133 +++++++++++++++++++++++++++++ spine-ts/webgl/demos/meshes.js | 13 ++- 3 files changed, 163 insertions(+), 7 deletions(-) create mode 100644 spine-ts/webgl/demos/clipping.html create mode 100644 spine-ts/webgl/demos/clipping.js diff --git a/spine-ts/webgl/demos/clipping.html b/spine-ts/webgl/demos/clipping.html new file mode 100644 index 000000000..a9f8952b7 --- /dev/null +++ b/spine-ts/webgl/demos/clipping.html @@ -0,0 +1,24 @@ + + +Clipping - Spine Demo + + + + + + + +
+
+
+
+ Draw triangles
+
+ + + + + \ No newline at end of file diff --git a/spine-ts/webgl/demos/clipping.js b/spine-ts/webgl/demos/clipping.js new file mode 100644 index 000000000..fa59388c4 --- /dev/null +++ b/spine-ts/webgl/demos/clipping.js @@ -0,0 +1,133 @@ +var clippingDemo = function(loadingComplete, bgColor) { + var canvas, gl, renderer, assetManager; + var skeleton, state, bounds; + var timeKeeper, loadingScreen; + var playButton, timeline, isPlaying = true, playTime = 0; + + var DEMO_NAME = "ClippingDemo"; + + if (!bgColor) bgColor = new spine.Color(235 / 255, 239 / 255, 244 / 255, 1); + + function init () { + canvas = document.getElementById("clipping-canvas"); + canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; + gl = canvas.getContext("webgl", { alpha: false }) || canvas.getContext("experimental-webgl", { alpha: false }); + if (!gl) { + alert('WebGL is unavailable.'); + return; + } + + renderer = new spine.webgl.SceneRenderer(canvas, gl); + assetManager = spineDemos.assetManager; + var textureLoader = function(img) { return new spine.webgl.GLTexture(gl, img); }; + assetManager.loadTexture(DEMO_NAME, textureLoader, "atlas1.png"); + assetManager.loadText(DEMO_NAME, "atlas1.atlas"); + assetManager.loadJson(DEMO_NAME, "demos.json"); + timeKeeper = new spine.TimeKeeper(); + loadingScreen = new spine.webgl.LoadingScreen(renderer); + requestAnimationFrame(load); + } + + function load () { + timeKeeper.update(); + if (assetManager.isLoadingComplete(DEMO_NAME)) { + var atlas = new spine.TextureAtlas(assetManager.get(DEMO_NAME, "atlas1.atlas"), function(path) { + return assetManager.get(DEMO_NAME, path); + }); + var atlasLoader = new spine.AtlasAttachmentLoader(atlas); + var skeletonJson = new spine.SkeletonJson(atlasLoader); + var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json")["spineboy"]); + skeleton = new spine.Skeleton(skeletonData); + state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data)); + state.setAnimation(0, "portal", true); + state.apply(skeleton); + skeleton.updateWorldTransform(); + var offset = new spine.Vector2(); + bounds = new spine.Vector2(); + skeleton.getBounds(offset, bounds, []); + + renderer.camera.position.x = offset.x + bounds.x + 200; + renderer.camera.position.y = offset.y + bounds.y / 2 + 100; + + renderer.skeletonDebugRenderer.drawMeshHull = false; + renderer.skeletonDebugRenderer.drawMeshTriangles = false; + + setupUI(); + + loadingComplete(canvas, render); + } else { + loadingScreen.draw(); + requestAnimationFrame(load); + } + } + + function setupUI() { + playButton = $("#clipping-playbutton"); + var playButtonUpdate = function () { + isPlaying = !isPlaying; + if (isPlaying) + playButton.addClass("pause").removeClass("play"); + else + playButton.addClass("play").removeClass("pause"); + } + playButton.click(playButtonUpdate); + playButton.addClass("pause"); + + timeline = $("#clipping-timeline").data("slider"); + timeline.changed = function (percent) { + if (isPlaying) playButton.click(); + if (!isPlaying) { + var animationDuration = state.getCurrent(0).animation.duration; + var time = animationDuration * percent; + state.update(time - playTime); + state.apply(skeleton); + skeleton.updateWorldTransform(); + playTime = time; + } + }; + + renderer.skeletonDebugRenderer.drawClipping = false; + renderer.skeletonDebugRenderer.drawBones = false; + renderer.skeletonDebugRenderer.drawMeshHull = false; + renderer.skeletonDebugRenderer.drawMeshTriangles = false; + $("#clipping-drawtriangles").click(function() { + renderer.skeletonDebugRenderer.drawMeshHull = this.checked; + renderer.skeletonDebugRenderer.drawMeshTriangles = this.checked; + renderer.skeletonDebugRenderer.drawClipping = this.checked; + renderer.skeletonDebugRenderer.drawRegionAttachments = this.checked; + }) + } + + function render () { + timeKeeper.update(); + var delta = timeKeeper.delta; + + if (isPlaying) { + var animationDuration = state.getCurrent(0).animation.duration; + playTime += delta; + while (playTime >= animationDuration) + playTime -= animationDuration; + timeline.set(playTime / animationDuration); + + state.update(delta); + state.apply(skeleton); + skeleton.updateWorldTransform(); + } + + renderer.camera.viewportWidth = bounds.x * 1.6; + renderer.camera.viewportHeight = bounds.y * 1.6; + renderer.resize(spine.webgl.ResizeMode.Fit); + + gl.clearColor(bgColor.r, bgColor.g, bgColor.b, bgColor.a); + gl.clear(gl.COLOR_BUFFER_BIT); + + renderer.begin(); + renderer.drawSkeleton(skeleton, true); + renderer.drawSkeletonDebug(skeleton, false, ["root"]); + renderer.end(); + + loadingScreen.draw(true); + } + + init(); +}; \ No newline at end of file diff --git a/spine-ts/webgl/demos/meshes.js b/spine-ts/webgl/demos/meshes.js index 9b601a589..898f248d4 100644 --- a/spine-ts/webgl/demos/meshes.js +++ b/spine-ts/webgl/demos/meshes.js @@ -4,7 +4,7 @@ var meshesDemo = function(loadingComplete, bgColor) { var timeKeeper, loadingScreen; var skeletons = {}; var activeSkeleton = "Orange Girl"; - var playButton, timeLine, isPlaying = true; + var playButton, timeline, isPlaying = true; var DEMO_NAME = "MeshesDemo"; @@ -57,8 +57,8 @@ var meshesDemo = function(loadingComplete, bgColor) { playButton.click(playButtonUpdate); playButton.addClass("pause"); - timeLine = $("#meshes-timeline").data("slider"); - timeLine.changed = function (percent) { + timeline = $("#meshes-timeline").data("slider"); + timeline.changed = function (percent) { if (isPlaying) playButton.click(); if (!isPlaying) { var active = skeletons[activeSkeleton]; @@ -82,7 +82,7 @@ var meshesDemo = function(loadingComplete, bgColor) { activeSkeleton = $("#meshes-skeleton option:selected").text(); var active = skeletons[activeSkeleton]; var animationDuration = active.state.getCurrent(0).animation.duration; - timeLine.set(active.playTime / animationDuration); + timeline.set(active.playTime / animationDuration); }) renderer.skeletonDebugRenderer.drawBones = false; @@ -150,10 +150,9 @@ var meshesDemo = function(loadingComplete, bgColor) { if (isPlaying) { var animationDuration = state.getCurrent(0).animation.duration; active.playTime += delta; - while (active.playTime >= animationDuration) { + while (active.playTime >= animationDuration) active.playTime -= animationDuration; - } - timeLine.set(active.playTime / animationDuration); + timeline.set(active.playTime / animationDuration); state.update(delta); state.apply(skeleton); From eb5fa18be7a8f48567a858a2a8704645addfd13e Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Mon, 11 Sep 2017 22:03:35 +0200 Subject: [PATCH 03/20] Updated clipping demo. --- spine-ts/README.md | 5 +++-- spine-ts/webgl/demos/clipping.js | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/spine-ts/README.md b/spine-ts/README.md index bba830f7b..8d941d3be 100644 --- a/spine-ts/README.md +++ b/spine-ts/README.md @@ -71,10 +71,11 @@ The spine-ts WebGL demos load their image, atlas, and JSON files from our webser - [Meshes](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/meshes.html) - [Skins](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/skins.html) - [Hoverboard](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/hoverboard.html) -- [Transform constraints](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/transforms.html) -- [Tank](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/tank.html) - [Vine](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/vine.html) +- [Clipping](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/clipping.html) - [Stretchyman](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/stretchyman.html) +- [Tank](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/spine-ts/webgl/demos/tank.html) +- [Transform constraints](http://rawgit.com/EsotericSoftware/spine-runtimes/3.6/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. diff --git a/spine-ts/webgl/demos/clipping.js b/spine-ts/webgl/demos/clipping.js index fa59388c4..55604db73 100644 --- a/spine-ts/webgl/demos/clipping.js +++ b/spine-ts/webgl/demos/clipping.js @@ -86,6 +86,7 @@ var clippingDemo = function(loadingComplete, bgColor) { } }; + renderer.skeletonDebugRenderer.drawRegionAttachments = false; renderer.skeletonDebugRenderer.drawClipping = false; renderer.skeletonDebugRenderer.drawBones = false; renderer.skeletonDebugRenderer.drawMeshHull = false; From 0033209e87684e483ca0322911e930cf1841d3b2 Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Mon, 11 Sep 2017 23:23:24 +0200 Subject: [PATCH 04/20] Aim and shoot buttons for hoverboard demo. --- spine-ts/webgl/demos/hoverboard.html | 4 +++- spine-ts/webgl/demos/hoverboard.js | 27 +++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/spine-ts/webgl/demos/hoverboard.html b/spine-ts/webgl/demos/hoverboard.html index 92b7fa1b7..b2a2a473e 100644 --- a/spine-ts/webgl/demos/hoverboard.html +++ b/spine-ts/webgl/demos/hoverboard.html @@ -10,7 +10,9 @@
- Display Bones + Display Bones
+ Aim
+
+ + + + + + + + + + + + + + + + + +
+
+
+
+

Spine versus sprite sheets

+
+
+
+
+
Spine
All animations, all frame rates
0.18 MB
+
Sprite sheet
1 second of animation @ 30FPS
3.39 MB = 18x larger!
+
+
+
+

Traditional sprite animation requires an image for each frame of animation, resulting in massive sprite sheets. Each additional animation greatly increases your games' disk space and memory requirements, especially at frame rates necessary for smooth playback. It quickly becomes an enormous amount of work for your artists and your finished product suffers when the number of animations must be reduced to meet size constraints.

+

Spine animations store only the bone and animation data, coupled with a single set of individual images which are reused for every animation. This allows you to bring your games to life by packing them full of unique animations. Also, Spine animations are interpolated so playback is always perfectly smooth, regardless of the frame rate.

+

+ + Compare the memory and disk space requirements of Spine versus sprite sheet animations. +

+
+
+
Animation speed
+
 
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+

Spine with frame-based animation

+
+
+ + + +
+
+
+
+

While Spine largely replaces the need for traditional frame-by-frame animation, images can still be swapped when needed. For example, a change of perspective for a torso or flapping wing, alternative facial expressions, or a muzzle flash.

+

Spine's slots, attachments, and draw order mechanisms allow you to easily integrate frame-by-frame animations in your otherwise fully dynamic Spine animations. Even better, Spine can manipulate the frame-by-frame images, shown in this demo by scaling on the alien's exploding head.

+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+

Transitions and layering

+
+
+
+
Smooth
+
Abrupt
+
+
+
+
+

An often felt disadvantage of 2D games is the lack of smooth animation transitions. In 3D games, transitions between animations can be calculated on-the-fly at runtime. Animations can even be blended, for example half walking and half running. In 2D games without Spine, blending is impossible and typically transitions are jarring. Artists can manually create frames for every possible transition, but even that doesn't help when animations can be interrupted mid playback.

+

Spine brings the benefits from the 3D world back to 2D. The Spine Runtimes smoothly and dynamically transition from one animation to the next, giving your characters natural looking fluidity. Layering allows animations to be blended on top of others, for example to play a shooting animation while your character is running or to blend walking and limping more and more as damage is taken.

+
+
+
+ +
+
+
+
Animation speed
+
 
+
+
+
+
+
+
+
+
+
+
+

Mesh deformation

+
+
+ + + +
+
+
+
+

A Spine character made up of rigid 2D images can already give excellent results, such as Spineboy in the demo above. To give your characters even more life, Spine brings more tricks from the 3D world in the form of meshes and weights. With meshes, images are no longer rigid and can bend and deform however you like. Weights bind meshes to bones, so the images deform automatically as the bones are moved.

+

Meshes can also improve your game's performance, reducing fill rate usage by not drawing transparent portions of your images. This is especially important on mobile devices.

+

The amazing art for this demo was kindly provided by Hwadock (a.k.a. dugy). Follow him on Twitter and his blog.

+
+
+ +
+ +
+
+
+
+ + +
+ Show bones +
+
+
+ + +
+ Show triangles +
+
+
+
+
+
+
+
+
+

Skins

+
+
+
+
+
+

Spine's skins feature is perfect for providing customization and variety while keeping your workload reasonable. With skins, the work of animating only needs to be done once, then you can assign different looks to your skeletons while reusing all your animations. For ultimate flexibility, the Spine Runtimes let you combine parts from different skins at runtime, covering all possible customization needs.

+

Skins give players the ability to add their own touch to your game's world by outfitting their avatars with new looks, clothing, weapons, and other accessories. Skins also give you more mileage out of your animations: mix and match your art for enemies, items, and other game objects to greatly increase variety for little effort.

+

The art for this demo can be found in the 2D Anim Heroes character pack for Unity. +

+
+ +
+ +
+
+
+
+ + +
+
+
+
+ + +
+ Random skins +
+
+
+
+
+
+
+
+
+

Inverse kinematics

+
+
+
+
+
+

Spine's support for inverse kinematics allows for realistic and dynamic movement that would otherwise be difficult or impossible to animate. It also enables more advanced rigging, where complex poses can be easily controlled by a small number of bones.

+

Since Spine doesn't use baking or plotting, IK really shines at runtime. By dynamically positioning bones at runtime, IK constraints allow your character to easily react to the environment, such as aiming at enemies, having feet follow slopes and bumps in the terrain, and much more. In this demo Spineboy is balanced on a user controlled hover board while playing an animation at the same time.

+

Try it out! Drag the red circles around to dynamically pose Spineboy. The shoot and jump buttons and aim checkbox layer animations on top of the idle animation.

+
+
+
+ + +
+
+
+
+ + +
+ Aim +
+
+
+ + +
+ Show bones +
+
+
+
+
+
+
+
+
+

Path constraints

+
+
+ + + +
+
+
+
+

Often a part of a character follows an open or closed path. Rather than key this movement manually, Spine's path constraints can be used to make bones automatically follow a path. The composite Bézier path is made up of a set of interconnected points that let you bend and shape the path. The path itself can be animated and even weighted to bones, so the path deforms automatically as the bones are moved.

+

In this demo a vine mesh is bound to bones which are constrained to a path. The more vertices in the mesh, the smoother it will bend.

+

Path constraints can also be used to great effect at runtime. Move the red handles to dynamically modify the path and watch the vine follow it seamlessly!

+
+
+
+ + +
+ Show bones & paths +
+
+
+
+
+
+
+
+
+
+

Path constraints enable powerful rigging, shown by Stretchyman in this demo. For the arms and legs, meshes are weighted to many small bones which are then constrained to follow simple paths for the limbs. The paths are then weighted to bones which can be moved to control the limbs. This setups allows a large number of bones to be controlled with just a few bones. Not only does this make animating easier, but at runtime only a few bones need to be adjusted for posing dynamically.

+

Move the red handles and make Stretchyman dance!

+
+
+
+ + +
+ Show bones & paths +
+
+
+
+
+
+
+
+
+

Clipping

+
+
+ + + +
+
+
+
+

Sometimes parts of an animation must be partially hidden, like in this example where Spineboy comes out of a portal. Clipping comes in handy in these cases by restricting rendering to a polygonal area. Only the parts of the skeleton inside the predefined, animatable area are shown. This enables many effects that wouldn't otherwise be possible, such as windows, lighting effects, and more. It is also possible to have clipping only affect a subset of the skeleton. For example, an animation where a character goes through an x-ray.

+
+
+
+ + +
+ Show triangles +
+
+
+
+
+
+
+
+
+

Transform constraints

+
+
+ + + +
+
+
+
+

Animating complex skeletons with many interdependent pieces can be tedious. Spine's transform constraints remove this pain by unlocking more powerful rigging. By constraining bone transforms to the transform of another bone, you only need to animate one of the bones and the others are adjusted automatically. While seemingly simple on the surface, advanced rigging can make great use of this to automate how a skeleton behaves as it is posed.

+

Transform constraints are also great for machinery, such as the tank in this demo. Instead of keying the rotation of each individual wheel, a single wheel is animated while the others follow via a transform constraint. Offsetting and mixing can add individualism back to constrained parts.

+

The treads on the tank are circulated using a path constraint, which would be impossible to animate without paths. The path is weighted to the wheels, so the path bends automatically as the wheels move up and down.

+
+
+
+ + +
+ Show bones & paths +
+
+
+
+
+
+
+
+
+
+

In this demo, the rotation of the two smaller wheels is constrained by the big wheel's rotation. Also, the big wheel's translation is constrained so it stays between the two smaller wheels.

+
+
+
Rotation offset
+
 
+
+
+
+
Translation mix
+
 
+
+
+
+
+
+
+
+
+ \ No newline at end of file diff --git a/spine-ts/webgl/demos/demos.js b/spine-ts/webgl/demos/demos.js new file mode 100644 index 000000000..0dc753f47 --- /dev/null +++ b/spine-ts/webgl/demos/demos.js @@ -0,0 +1,81 @@ + +$(function () { + window.onerror = function(message, url, lineNo) { + alert("Error: " + message + "\n" + "URL:" + url + "\nLine: " + lineNo); + } + + spineDemos.assetManager = new spine.SharedAssetManager("assets/"); + spineDemos.loadSliders(); + + var demos = [ + spritesheetsDemo, + imageChangesDemo, + transitionsDemo, + meshesDemo, + skinsDemo, + hoverboardDemo, + vineDemo, + clippingDemo, + stretchymanDemo, + tankDemo, + transformsDemo, + ]; + for (var i = 0; i < demos.length; i++) + demos[i](spineDemos.setupRendering); + + function resizeSliders () { + $(".slider").each(function () { + $(this).data("slider").resized(); + }); + } + + function windowResized () { + // Keep canvas from taking up whole screen. + $(".aspect").each(function () { + $(this).css("padding-bottom", Math.min(70.14, $(window).height() * 0.75 / $(this).width() * 100) + "%"); + }); + + // Swap controls when media query puts text below canvas. + var below = $("#below").is(':visible'); + $(".demo .description").each(function () { + var description = $(this); + var controls = description.children(".controls"); + if (below || description.hasClass("fullsize")) + description.prepend(controls); + else + description.append(controls); + }); + + resizeSliders(); + } + windowResized(); + $(window).resize(windowResized); + + $(".resize").click(function () { + var resizeButton = $(this); + var container = resizeButton.parent(); + var parent = container.parent(); + var overlayLabels = parent.find(".overlay-label"); + var description = parent.children(".description"); + var controls = description.children(".controls"); + + container.toggleClass("fullsize"); + resizeButton.toggleClass("checked"); + + var offset = parseFloat(overlayLabels.css("bottom")); + description.toggleClass("fullsize"); + if (description.hasClass("fullsize")) { + overlayLabels.css("bottom", offset * 1.666); + } else { + resizeSliders(); + overlayLabels.css("bottom", offset / 1.666); + } + setTimeout(function() { + windowResized(); + }, 500); + }); + + $(".checkbox-overlay").change(function () { + $(this).closest(".demo").find(".overlay").toggleClass("overlay-hide"); + }); +}); From ff1a81bab32767248f5c9704c20cdd6e871287db Mon Sep 17 00:00:00 2001 From: badlogic Date: Thu, 14 Sep 2017 12:15:23 +0200 Subject: [PATCH 14/20] [webgl] Refactored demos to use preallocated canvas & context --- spine-ts/webgl/demos/clipping.html | 12 ++++++----- spine-ts/webgl/demos/clipping.js | 12 +++-------- spine-ts/webgl/demos/hoverboard.html | 7 ++++-- spine-ts/webgl/demos/hoverboard.js | 13 ++++------- spine-ts/webgl/demos/imagechanges.html | 8 ++++--- spine-ts/webgl/demos/imagechanges.js | 9 ++------ spine-ts/webgl/demos/meshes.html | 8 ++++--- spine-ts/webgl/demos/meshes.js | 10 ++------- spine-ts/webgl/demos/skins.html | 7 ++++-- spine-ts/webgl/demos/skins.js | 9 ++------ spine-ts/webgl/demos/spritesheets.html | 10 +++++---- spine-ts/webgl/demos/spritesheets.js | 9 ++------ spine-ts/webgl/demos/stretchyman.html | 7 ++++-- spine-ts/webgl/demos/stretchyman.js | 9 ++------ spine-ts/webgl/demos/tank.html | 8 ++++--- spine-ts/webgl/demos/tank.js | 9 ++------ spine-ts/webgl/demos/transforms.html | 12 ++++++----- spine-ts/webgl/demos/transforms.js | 9 ++------ spine-ts/webgl/demos/transitions.html | 8 ++++--- spine-ts/webgl/demos/transitions.js | 10 +++------ spine-ts/webgl/demos/utils.js | 30 ++++++++++++++++++++++---- spine-ts/webgl/demos/vine.html | 10 +++++---- spine-ts/webgl/demos/vine.js | 9 ++------ 23 files changed, 113 insertions(+), 122 deletions(-) diff --git a/spine-ts/webgl/demos/clipping.html b/spine-ts/webgl/demos/clipping.html index a9f8952b7..6565d2d47 100644 --- a/spine-ts/webgl/demos/clipping.html +++ b/spine-ts/webgl/demos/clipping.html @@ -9,15 +9,17 @@
-
+
+
-
- Draw triangles
+ Draw triangles
diff --git a/spine-ts/webgl/demos/clipping.js b/spine-ts/webgl/demos/clipping.js index 55604db73..f35157097 100644 --- a/spine-ts/webgl/demos/clipping.js +++ b/spine-ts/webgl/demos/clipping.js @@ -1,5 +1,5 @@ -var clippingDemo = function(loadingComplete, bgColor) { - var canvas, gl, renderer, assetManager; +var clippingDemo = function(canvas, loadingComplete, bgColor) { + var gl, renderer, assetManager; var skeleton, state, bounds; var timeKeeper, loadingScreen; var playButton, timeline, isPlaying = true, playTime = 0; @@ -9,14 +9,8 @@ var clippingDemo = function(loadingComplete, bgColor) { if (!bgColor) bgColor = new spine.Color(235 / 255, 239 / 255, 244 / 255, 1); function init () { - canvas = document.getElementById("clipping-canvas"); canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; - gl = canvas.getContext("webgl", { alpha: false }) || canvas.getContext("experimental-webgl", { alpha: false }); - if (!gl) { - alert('WebGL is unavailable.'); - return; - } - + gl = canvas.ctx.gl; renderer = new spine.webgl.SceneRenderer(canvas, gl); assetManager = spineDemos.assetManager; var textureLoader = function(img) { return new spine.webgl.GLTexture(gl, img); }; diff --git a/spine-ts/webgl/demos/hoverboard.html b/spine-ts/webgl/demos/hoverboard.html index c7bc4e4bd..6f8184ef1 100644 --- a/spine-ts/webgl/demos/hoverboard.html +++ b/spine-ts/webgl/demos/hoverboard.html @@ -9,7 +9,7 @@
-
+
> Display Bones
Aim
@@ -17,7 +17,10 @@
diff --git a/spine-ts/webgl/demos/hoverboard.js b/spine-ts/webgl/demos/hoverboard.js index 23d9e3038..56656c17a 100644 --- a/spine-ts/webgl/demos/hoverboard.js +++ b/spine-ts/webgl/demos/hoverboard.js @@ -1,10 +1,10 @@ -var hoverboardDemo = function(loadingComplete, bgColor) { +var hoverboardDemo = function(canvas, loadingComplete, bgColor) { var COLOR_INNER = new spine.Color(0.8, 0, 0, 0.5); var COLOR_OUTER = new spine.Color(0.8, 0, 0, 0.8); var COLOR_INNER_SELECTED = new spine.Color(0.0, 0, 0.8, 0.5); var COLOR_OUTER_SELECTED = new spine.Color(0.0, 0, 0.8, 0.8); - var canvas, gl, renderer, input, assetManager; + var gl, renderer, input, assetManager; var skeleton, state, bounds; var timeKeeper, loadingScreen; var target = null; @@ -18,13 +18,8 @@ var hoverboardDemo = function(loadingComplete, bgColor) { if (!bgColor) bgColor = new spine.Color(235 / 255, 239 / 255, 244 / 255, 1); function init () { - canvas = document.getElementById("hoverboard-canvas"); canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; - gl = canvas.getContext("webgl", { alpha: false }) || canvas.getContext("experimental-webgl", { alpha: false }); - if (!gl) { - alert('WebGL is unavailable.'); - return; - } + gl = canvas.ctx.gl; renderer = new spine.webgl.SceneRenderer(canvas, gl); assetManager = spineDemos.assetManager; @@ -114,7 +109,7 @@ var hoverboardDemo = function(loadingComplete, bgColor) { state.addAnimation(aimTrack, "aim", true, 0.4).mixDuration = 0.2; }); } - + function setupInput () { input.addListener({ down: function(x, y) { diff --git a/spine-ts/webgl/demos/imagechanges.html b/spine-ts/webgl/demos/imagechanges.html index fdec4dcfc..f2d3cfc4a 100644 --- a/spine-ts/webgl/demos/imagechanges.html +++ b/spine-ts/webgl/demos/imagechanges.html @@ -9,15 +9,17 @@
-
+

diff --git a/spine-ts/webgl/demos/imagechanges.js b/spine-ts/webgl/demos/imagechanges.js index fabcbe6ab..0bb11cc76 100644 --- a/spine-ts/webgl/demos/imagechanges.js +++ b/spine-ts/webgl/demos/imagechanges.js @@ -1,4 +1,4 @@ -var imageChangesDemo = function(loadingComplete, bgColor) { +var imageChangesDemo = function(canvas, loadingComplete, bgColor) { var OUTLINE_COLOR = new spine.Color(0, 0.8, 0, 1); var canvas, gl, renderer, input, assetManager; @@ -13,13 +13,8 @@ var imageChangesDemo = function(loadingComplete, bgColor) { if (!bgColor) bgColor = new spine.Color(235 / 255, 239 / 255, 244 / 255, 1); function init () { - canvas = document.getElementById("imagechanges-canvas"); canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; - gl = canvas.getContext("webgl", { alpha: false }) || canvas.getContext("experimental-webgl", { alpha: false }); - if (!gl) { - alert('WebGL is unavailable.'); - return; - } + gl = canvas.ctx.gl; renderer = new spine.webgl.SceneRenderer(canvas, gl); assetManager = spineDemos.assetManager; diff --git a/spine-ts/webgl/demos/meshes.html b/spine-ts/webgl/demos/meshes.html index 748a1a76f..026360e52 100644 --- a/spine-ts/webgl/demos/meshes.html +++ b/spine-ts/webgl/demos/meshes.html @@ -9,7 +9,7 @@
-
+


@@ -18,8 +18,10 @@
diff --git a/spine-ts/webgl/demos/meshes.js b/spine-ts/webgl/demos/meshes.js index 898f248d4..36f6a09ad 100644 --- a/spine-ts/webgl/demos/meshes.js +++ b/spine-ts/webgl/demos/meshes.js @@ -1,4 +1,4 @@ -var meshesDemo = function(loadingComplete, bgColor) { +var meshesDemo = function(canvas, loadingComplete, bgColor) { var canvas, gl, renderer, input, assetManager; var skeleton, bounds; var timeKeeper, loadingScreen; @@ -11,14 +11,8 @@ var meshesDemo = function(loadingComplete, bgColor) { if (!bgColor) bgColor = new spine.Color(235 / 255, 239 / 255, 244 / 255, 1); function init () { - canvas = document.getElementById("meshes-canvas"); canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; - gl = canvas.getContext("webgl", { alpha: false }) || canvas.getContext("experimental-webgl", { alpha: false }); - if (!gl) { - alert('WebGL is unavailable.'); - return; - } - + gl = canvas.ctx.gl; renderer = new spine.webgl.SceneRenderer(canvas, gl); renderer.skeletonDebugRenderer.drawRegionAttachments = false; assetManager = spineDemos.assetManager; diff --git a/spine-ts/webgl/demos/skins.html b/spine-ts/webgl/demos/skins.html index 8acdf8d41..0c9b8ea28 100644 --- a/spine-ts/webgl/demos/skins.html +++ b/spine-ts/webgl/demos/skins.html @@ -9,7 +9,7 @@
-
+


@@ -17,7 +17,10 @@
diff --git a/spine-ts/webgl/demos/skins.js b/spine-ts/webgl/demos/skins.js index 2c68faaf5..a473f9383 100644 --- a/spine-ts/webgl/demos/skins.js +++ b/spine-ts/webgl/demos/skins.js @@ -1,4 +1,4 @@ -var skinsDemo = function(loadingComplete, bgColor) { +var skinsDemo = function(canvas, loadingComplete, bgColor) { var canvas, gl, renderer, input, assetManager; var skeleton, state, offset, bounds; var timeKeeper, loadingScreen; @@ -10,13 +10,8 @@ var skinsDemo = function(loadingComplete, bgColor) { if (!bgColor) bgColor = new spine.Color(235 / 255, 239 / 255, 244 / 255, 1); function init () { - canvas = document.getElementById("skins-canvas"); canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; - gl = canvas.getContext("webgl", { alpha: false }) || canvas.getContext("experimental-webgl", { alpha: false }); - if (!gl) { - alert('WebGL is unavailable.'); - return; - } + gl = canvas.ctx.gl; renderer = new spine.webgl.SceneRenderer(canvas, gl); assetManager = spineDemos.assetManager; diff --git a/spine-ts/webgl/demos/spritesheets.html b/spine-ts/webgl/demos/spritesheets.html index c499bcb6a..d936c13ea 100644 --- a/spine-ts/webgl/demos/spritesheets.html +++ b/spine-ts/webgl/demos/spritesheets.html @@ -9,16 +9,18 @@
-
+

Time multiplier
- diff --git a/spine-ts/webgl/demos/spritesheets.js b/spine-ts/webgl/demos/spritesheets.js index 4e4cbd80f..4d21705ee 100644 --- a/spine-ts/webgl/demos/spritesheets.js +++ b/spine-ts/webgl/demos/spritesheets.js @@ -1,4 +1,4 @@ -var spritesheetsDemo = function(loadingComplete, bgColor) { +var spritesheetsDemo = function(canvas, loadingComplete, bgColor) { var SKELETON_ATLAS_COLOR = new spine.Color(0, 0.8, 0, 0.8); var FRAME_ATLAS_COLOR = new spine.Color(0.8, 0, 0, 0.8); @@ -16,13 +16,8 @@ var spritesheetsDemo = function(loadingComplete, bgColor) { if (!bgColor) bgColor = new spine.Color(235 / 255, 239 / 255, 244 / 255, 1); function init () { - canvas = document.getElementById("spritesheets-canvas"); canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; - gl = canvas.getContext("webgl", { alpha: false }) || canvas.getContext("experimental-webgl", { alpha: false }); - if (!gl) { - alert('WebGL is unavailable.'); - return; - } + gl = canvas.ctx.gl; renderer = new spine.webgl.SceneRenderer(canvas, gl); assetManager = spineDemos.assetManager; diff --git a/spine-ts/webgl/demos/stretchyman.html b/spine-ts/webgl/demos/stretchyman.html index f2d31ecab..8f9ef9030 100644 --- a/spine-ts/webgl/demos/stretchyman.html +++ b/spine-ts/webgl/demos/stretchyman.html @@ -9,12 +9,15 @@
-
+
Display bones
diff --git a/spine-ts/webgl/demos/stretchyman.js b/spine-ts/webgl/demos/stretchyman.js index 16dbc156f..8bbe6cc34 100644 --- a/spine-ts/webgl/demos/stretchyman.js +++ b/spine-ts/webgl/demos/stretchyman.js @@ -1,4 +1,4 @@ -var stretchymanDemo = function(loadingComplete, bgColor) { +var stretchymanDemo = function(canvas, loadingComplete, bgColor) { var COLOR_INNER = new spine.Color(0.8, 0, 0, 0.5); var COLOR_OUTER = new spine.Color(0.8, 0, 0, 0.8); var COLOR_INNER_SELECTED = new spine.Color(0.0, 0, 0.8, 0.5); @@ -26,13 +26,8 @@ var stretchymanDemo = function(loadingComplete, bgColor) { if (!bgColor) bgColor = new spine.Color(235 / 255, 239 / 255, 244 / 255, 1); function init () { - canvas = document.getElementById("stretchyman-canvas"); canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; - gl = canvas.getContext("webgl", { alpha: false }) || canvas.getContext("experimental-webgl", { alpha: false }); - if (!gl) { - alert('WebGL is unavailable.'); - return; - } + gl = canvas.ctx.gl; renderer = new spine.webgl.SceneRenderer(canvas, gl); assetManager = spineDemos.assetManager; diff --git a/spine-ts/webgl/demos/tank.html b/spine-ts/webgl/demos/tank.html index 0c9c6d803..02868ec7a 100644 --- a/spine-ts/webgl/demos/tank.html +++ b/spine-ts/webgl/demos/tank.html @@ -9,15 +9,17 @@
-
+

Display bones
diff --git a/spine-ts/webgl/demos/tank.js b/spine-ts/webgl/demos/tank.js index 5cbeba3dc..e57822c46 100644 --- a/spine-ts/webgl/demos/tank.js +++ b/spine-ts/webgl/demos/tank.js @@ -1,4 +1,4 @@ -var tankDemo = function(loadingComplete, bgColor) { +var tankDemo = function(canvas, loadingComplete, bgColor) { var canvas, gl, renderer, input, assetManager; var skeleton, state, offset, bounds; var timeKeeper, loadingScreen; @@ -9,13 +9,8 @@ var tankDemo = function(loadingComplete, bgColor) { if (!bgColor) bgColor = new spine.Color(235 / 255, 239 / 255, 244 / 255, 1); function init () { - canvas = document.getElementById("tank-canvas"); canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; - gl = canvas.getContext("webgl", { alpha: false }) || canvas.getContext("experimental-webgl", { alpha: false }); - if (!gl) { - alert('WebGL is unavailable.'); - return; - } + gl = canvas.ctx.gl; renderer = new spine.webgl.SceneRenderer(canvas, gl); assetManager = spineDemos.assetManager; diff --git a/spine-ts/webgl/demos/transforms.html b/spine-ts/webgl/demos/transforms.html index 6b2ec36ff..9a32b3304 100644 --- a/spine-ts/webgl/demos/transforms.html +++ b/spine-ts/webgl/demos/transforms.html @@ -9,16 +9,18 @@
-
+
Rotation offset

Translation mix -
+
- diff --git a/spine-ts/webgl/demos/transforms.js b/spine-ts/webgl/demos/transforms.js index fd999c6d7..43ea78895 100644 --- a/spine-ts/webgl/demos/transforms.js +++ b/spine-ts/webgl/demos/transforms.js @@ -1,4 +1,4 @@ -var transformsDemo = function(loadingComplete, bgColor) { +var transformsDemo = function(canvas, loadingComplete, bgColor) { var COLOR_INNER = new spine.Color(0.8, 0, 0, 0.5); var COLOR_OUTER = new spine.Color(0.8, 0, 0, 0.8); var COLOR_INNER_SELECTED = new spine.Color(0.0, 0, 0.8, 0.5); @@ -20,13 +20,8 @@ var transformsDemo = function(loadingComplete, bgColor) { if (!bgColor) bgColor = new spine.Color(235 / 255, 239 / 255, 244 / 255, 1); function init () { - canvas = document.getElementById("transforms-canvas"); canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; - gl = canvas.getContext("webgl", { alpha: false }) || canvas.getContext("experimental-webgl", { alpha: false }); - if (!gl) { - alert('WebGL is unavailable.'); - return; - } + gl = canvas.ctx.gl; renderer = new spine.webgl.SceneRenderer(canvas, gl); assetManager = spineDemos.assetManager; diff --git a/spine-ts/webgl/demos/transitions.html b/spine-ts/webgl/demos/transitions.html index 9f173191f..471604b57 100644 --- a/spine-ts/webgl/demos/transitions.html +++ b/spine-ts/webgl/demos/transitions.html @@ -9,15 +9,17 @@
-
+
Time multiplier

diff --git a/spine-ts/webgl/demos/transitions.js b/spine-ts/webgl/demos/transitions.js index 0c653da0e..a482f2d9e 100644 --- a/spine-ts/webgl/demos/transitions.js +++ b/spine-ts/webgl/demos/transitions.js @@ -1,4 +1,4 @@ -var transitionsDemo = function(loadingComplete, bgColor) { +var transitionsDemo = function(canvas, loadingComplete, bgColor) { var OUTLINE_COLOR = new spine.Color(0, 0.8, 0, 1); var canvas, gl, renderer, input, assetManager; @@ -15,13 +15,9 @@ var transitionsDemo = function(loadingComplete, bgColor) { timeSlider = $("#transitions-timeslider").data("slider"); timeSlider.set(0.5); timeSliderLabel = $("#transitions-timeslider-label")[0]; - canvas = document.getElementById("transitions-canvas"); + canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; - gl = canvas.getContext("webgl", { alpha: false }) || canvas.getContext("experimental-webgl", { alpha: false }); - if (!gl) { - alert('WebGL is unavailable.'); - return; - } + gl = canvas.ctx.gl; renderer = new spine.webgl.SceneRenderer(canvas, gl); assetManager = spineDemos.assetManager; diff --git a/spine-ts/webgl/demos/utils.js b/spine-ts/webgl/demos/utils.js index 23289b135..bfb1447f9 100644 --- a/spine-ts/webgl/demos/utils.js +++ b/spine-ts/webgl/demos/utils.js @@ -3,9 +3,10 @@ var spineDemos = { HOVER_COLOR_OUTER: new spine.Color(1, 1, 1, 1), NON_HOVER_COLOR_INNER: new spine.Color(0.478, 0, 0, 0.5), NON_HOVER_COLOR_OUTER: new spine.Color(1, 0, 0, 0.8), - assetManager: new spine.SharedAssetManager("http://esotericsoftware.com/demos/exports/"), + assetManager: new spine.SharedAssetManager("assets/"), demos: [], - loopRunning: false + loopRunning: false, + canvases: [] }; (function () { var timeKeeper = new spine.TimeKeeper(); @@ -13,7 +14,7 @@ var spineDemos = { timeKeeper.update(); if (spineDemos.log) console.log(timeKeeper.delta + ", " + timeKeeper.framesPerSecond); requestAnimationFrame(loop); - var demos = spineDemos.demos; + var demos = spineDemos.demos; for (var i = 0; i < demos.length; i++) { var demo = demos[i]; var canvas = demo.canvas; @@ -41,13 +42,34 @@ var spineDemos = { checkElementVisible(demo); }); checkElementVisible(demo); - if (!spineDemos.loopRunning) { + if (!spineDemos.loopRunning) { loop(); spineDemos.loopRunning = true; } spineDemos.demos.push(demo); }; + spineDemos.init = function () { + spineDemos.createCanvases(3); + spineDemos.loadSliders(); + } + + spineDemos.createCanvases = function (numCanvases) { + for (var i = 0; i < numCanvases; i++) { + var canvas = document.createElement("canvas"); + canvas.ctx = new spine.webgl.ManagedWebGLRenderingContext(canvas, { alpha: false }); + spineDemos.canvases.push(canvas); + } + } + + spineDemos.obtainCanvas = function () { + return spineDemos.canvases.splice(0, 1)[0]; + } + + spineDemos.freeCanvas = function (canvas) { + canvases.push(canvas); + } + spineDemos.loadSliders = function () { $(window).resize(function() { $(".slider").each(function () { diff --git a/spine-ts/webgl/demos/vine.html b/spine-ts/webgl/demos/vine.html index 89c7af28b..df9b4b2a9 100644 --- a/spine-ts/webgl/demos/vine.html +++ b/spine-ts/webgl/demos/vine.html @@ -9,15 +9,17 @@
-
+

Display bones & path
- diff --git a/spine-ts/webgl/demos/vine.js b/spine-ts/webgl/demos/vine.js index 5f1029954..f0b4cdf65 100644 --- a/spine-ts/webgl/demos/vine.js +++ b/spine-ts/webgl/demos/vine.js @@ -1,4 +1,4 @@ -var vineDemo = function(loadingComplete, bgColor) { +var vineDemo = function(canvas, loadingComplete, bgColor) { var COLOR_INNER = new spine.Color(0.8, 0, 0, 0.5); var COLOR_OUTER = new spine.Color(0.8, 0, 0, 0.8); var COLOR_INNER_SELECTED = new spine.Color(0.0, 0, 0.8, 0.5); @@ -18,13 +18,8 @@ var vineDemo = function(loadingComplete, bgColor) { if (!bgColor) bgColor = new spine.Color(235 / 255, 239 / 255, 244 / 255, 1); function init () { - canvas = document.getElementById("vine-canvas"); canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; - gl = canvas.getContext("webgl", { alpha: false }) || canvas.getContext("experimental-webgl", { alpha: false }); - if (!gl) { - alert('WebGL is unavailable.'); - return; - } + gl = canvas.ctx.gl; renderer = new spine.webgl.SceneRenderer(canvas, gl); input = new spine.webgl.Input(canvas); From 4fe53ac8568669aaf07a7fb5eca29c909233a20c Mon Sep 17 00:00:00 2001 From: badlogic Date: Thu, 14 Sep 2017 15:47:51 +0200 Subject: [PATCH 15/20] [webgl] Refactored WebGL demos. They reuse a preallocated set of canvases to limit the number of WebGL contexts required. At most 3 canvases can be visible at a time, so we preallocate 3 canvases, then dynamically attach them to placeholder divs based on their visibility. I'm a juggalo. --- spine-ts/webgl/demos/clipping.html | 6 +- spine-ts/webgl/demos/clipping.js | 59 +++++++++----------- spine-ts/webgl/demos/demos.css | 5 ++ spine-ts/webgl/demos/demos.html | 22 ++++---- spine-ts/webgl/demos/demos.js | 8 ++- spine-ts/webgl/demos/hoverboard.html | 6 +- spine-ts/webgl/demos/hoverboard.js | 63 +++++++++------------ spine-ts/webgl/demos/imagechanges.html | 6 +- spine-ts/webgl/demos/imagechanges.js | 24 +++----- spine-ts/webgl/demos/meshes.html | 6 +- spine-ts/webgl/demos/meshes.js | 25 +++------ spine-ts/webgl/demos/skins.html | 6 +- spine-ts/webgl/demos/skins.js | 60 +++++++++----------- spine-ts/webgl/demos/spritesheets.html | 6 +- spine-ts/webgl/demos/spritesheets.js | 76 ++++++++++++-------------- spine-ts/webgl/demos/stretchyman.html | 6 +- spine-ts/webgl/demos/stretchyman.js | 61 +++++++++------------ spine-ts/webgl/demos/tank.html | 6 +- spine-ts/webgl/demos/tank.js | 62 +++++++++------------ spine-ts/webgl/demos/transforms.html | 6 +- spine-ts/webgl/demos/transforms.js | 67 ++++++++++------------- spine-ts/webgl/demos/transitions.html | 6 +- spine-ts/webgl/demos/transitions.js | 48 +++++++--------- spine-ts/webgl/demos/utils.js | 74 +++++++++++++++---------- spine-ts/webgl/demos/vine.html | 6 +- spine-ts/webgl/demos/vine.js | 65 ++++++++++------------ 26 files changed, 347 insertions(+), 438 deletions(-) diff --git a/spine-ts/webgl/demos/clipping.html b/spine-ts/webgl/demos/clipping.html index 6565d2d47..5e936076d 100644 --- a/spine-ts/webgl/demos/clipping.html +++ b/spine-ts/webgl/demos/clipping.html @@ -9,7 +9,7 @@
-
+
Draw triangles @@ -17,9 +17,7 @@ diff --git a/spine-ts/webgl/demos/clipping.js b/spine-ts/webgl/demos/clipping.js index f35157097..29d481838 100644 --- a/spine-ts/webgl/demos/clipping.js +++ b/spine-ts/webgl/demos/clipping.js @@ -1,7 +1,7 @@ -var clippingDemo = function(canvas, loadingComplete, bgColor) { +var clippingDemo = function(canvas, bgColor) { var gl, renderer, assetManager; var skeleton, state, bounds; - var timeKeeper, loadingScreen; + var timeKeeper; var playButton, timeline, isPlaying = true, playTime = 0; var DEMO_NAME = "ClippingDemo"; @@ -18,41 +18,31 @@ var clippingDemo = function(canvas, loadingComplete, bgColor) { assetManager.loadText(DEMO_NAME, "atlas1.atlas"); assetManager.loadJson(DEMO_NAME, "demos.json"); timeKeeper = new spine.TimeKeeper(); - loadingScreen = new spine.webgl.LoadingScreen(renderer); - requestAnimationFrame(load); } - function load () { - timeKeeper.update(); - if (assetManager.isLoadingComplete(DEMO_NAME)) { - var atlas = new spine.TextureAtlas(assetManager.get(DEMO_NAME, "atlas1.atlas"), function(path) { - return assetManager.get(DEMO_NAME, path); - }); - var atlasLoader = new spine.AtlasAttachmentLoader(atlas); - var skeletonJson = new spine.SkeletonJson(atlasLoader); - var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json")["spineboy"]); - skeleton = new spine.Skeleton(skeletonData); - state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data)); - state.setAnimation(0, "portal", true); - state.apply(skeleton); - skeleton.updateWorldTransform(); - var offset = new spine.Vector2(); - bounds = new spine.Vector2(); - skeleton.getBounds(offset, bounds, []); + function loadingComplete () { + var atlas = new spine.TextureAtlas(assetManager.get(DEMO_NAME, "atlas1.atlas"), function(path) { + return assetManager.get(DEMO_NAME, path); + }); + var atlasLoader = new spine.AtlasAttachmentLoader(atlas); + var skeletonJson = new spine.SkeletonJson(atlasLoader); + var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json")["spineboy"]); + skeleton = new spine.Skeleton(skeletonData); + state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data)); + state.setAnimation(0, "portal", true); + state.apply(skeleton); + skeleton.updateWorldTransform(); + var offset = new spine.Vector2(); + bounds = new spine.Vector2(); + skeleton.getBounds(offset, bounds, []); - renderer.camera.position.x = offset.x + bounds.x + 200; - renderer.camera.position.y = offset.y + bounds.y / 2 + 100; + renderer.camera.position.x = offset.x + bounds.x + 200; + renderer.camera.position.y = offset.y + bounds.y / 2 + 100; - renderer.skeletonDebugRenderer.drawMeshHull = false; - renderer.skeletonDebugRenderer.drawMeshTriangles = false; + renderer.skeletonDebugRenderer.drawMeshHull = false; + renderer.skeletonDebugRenderer.drawMeshTriangles = false; - setupUI(); - - loadingComplete(canvas, render); - } else { - loadingScreen.draw(); - requestAnimationFrame(load); - } + setupUI(); } function setupUI() { @@ -120,9 +110,10 @@ var clippingDemo = function(canvas, loadingComplete, bgColor) { renderer.drawSkeleton(skeleton, true); renderer.drawSkeletonDebug(skeleton, false, ["root"]); renderer.end(); - - loadingScreen.draw(true); } + clippingDemo.loadingComplete = loadingComplete; + clippingDemo.render = render; + clippingDemo.DEMO_NAME = DEMO_NAME; init(); }; \ No newline at end of file diff --git a/spine-ts/webgl/demos/demos.css b/spine-ts/webgl/demos/demos.css index ce5b1ea0b..8b26f115a 100644 --- a/spine-ts/webgl/demos/demos.css +++ b/spine-ts/webgl/demos/demos.css @@ -17,6 +17,11 @@ canvas { height: 480px; } +.aspect { + width: 640px; + height: 480px; +} + .play { background: black; background-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3Cpath%20fill%3D%27%23F2F2F2%27%20d%3D%27M30.185%2C15.5L12.556%2C24.8V6.201L30.185%2C15.5z%27%2F%3E%3C%2Fsvg%3E"); diff --git a/spine-ts/webgl/demos/demos.html b/spine-ts/webgl/demos/demos.html index 3b1f52f22..88e0ac3c6 100644 --- a/spine-ts/webgl/demos/demos.html +++ b/spine-ts/webgl/demos/demos.html @@ -30,7 +30,7 @@

Spine versus sprite sheets

-
+
Spine
All animations, all frame rates
0.18 MB
@@ -66,7 +66,7 @@

Spine with frame-based animation

-
+
@@ -93,7 +93,7 @@

Transitions and layering

-
+
Smooth
Abrupt
@@ -124,7 +124,7 @@
@@ -166,7 +166,7 @@

Skins

-
+
@@ -203,7 +203,7 @@

Inverse kinematics

-
+
@@ -241,7 +241,7 @@
@@ -265,7 +265,7 @@
-
+
@@ -289,7 +289,7 @@

Clipping

-
+
@@ -316,7 +316,7 @@
@@ -340,7 +340,7 @@
-
+
diff --git a/spine-ts/webgl/demos/demos.js b/spine-ts/webgl/demos/demos.js index 0dc753f47..97acf91ce 100644 --- a/spine-ts/webgl/demos/demos.js +++ b/spine-ts/webgl/demos/demos.js @@ -4,8 +4,9 @@ $(function () { alert("Error: " + message + "\n" + "URL:" + url + "\nLine: " + lineNo); } + + spineDemos.init(); spineDemos.assetManager = new spine.SharedAssetManager("assets/"); - spineDemos.loadSliders(); var demos = [ spritesheetsDemo, @@ -20,8 +21,11 @@ $(function () { tankDemo, transformsDemo, ]; + + var placeholders = document.getElementsByClassName("aspect"); + for (var i = 0; i < demos.length; i++) - demos[i](spineDemos.setupRendering); + spineDemos.addDemo(demos[i], placeholders[i]); function resizeSliders () { $(".slider").each(function () { diff --git a/spine-ts/webgl/demos/hoverboard.html b/spine-ts/webgl/demos/hoverboard.html index 6f8184ef1..8448c24ca 100644 --- a/spine-ts/webgl/demos/hoverboard.html +++ b/spine-ts/webgl/demos/hoverboard.html @@ -9,7 +9,7 @@
-
> +
Display Bones
Aim
@@ -18,9 +18,7 @@ diff --git a/spine-ts/webgl/demos/hoverboard.js b/spine-ts/webgl/demos/hoverboard.js index 56656c17a..8c54d5f5a 100644 --- a/spine-ts/webgl/demos/hoverboard.js +++ b/spine-ts/webgl/demos/hoverboard.js @@ -1,4 +1,4 @@ -var hoverboardDemo = function(canvas, loadingComplete, bgColor) { +var hoverboardDemo = function(canvas, bgColor) { var COLOR_INNER = new spine.Color(0.8, 0, 0, 0.5); var COLOR_OUTER = new spine.Color(0.8, 0, 0, 0.8); var COLOR_INNER_SELECTED = new spine.Color(0.0, 0, 0.8, 0.5); @@ -29,44 +29,34 @@ var hoverboardDemo = function(canvas, loadingComplete, bgColor) { assetManager.loadJson(DEMO_NAME, "demos.json"); input = new spine.webgl.Input(canvas); timeKeeper = new spine.TimeKeeper(); - loadingScreen = new spine.webgl.LoadingScreen(renderer); - requestAnimationFrame(load); } - function load () { - timeKeeper.update(); - if (assetManager.isLoadingComplete(DEMO_NAME)) { - var atlas = new spine.TextureAtlas(assetManager.get(DEMO_NAME, "atlas1.atlas"), function(path) { - return assetManager.get(DEMO_NAME, path); - }); - var atlasLoader = new spine.AtlasAttachmentLoader(atlas); - var skeletonJson = new spine.SkeletonJson(atlasLoader); - var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json")["spineboy"]); - skeleton = new spine.Skeleton(skeletonData); - state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data)); - state.setAnimation(0, "hoverboard", true); - state.apply(skeleton); - skeleton.updateWorldTransform(); - var offset = new spine.Vector2(); - bounds = new spine.Vector2(); - skeleton.getBounds(offset, bounds, []); - for (var i = 0; i < controlBones.length; i++) - hoverTargets.push(null); + function loadingComplete () { + var atlas = new spine.TextureAtlas(assetManager.get(DEMO_NAME, "atlas1.atlas"), function(path) { + return assetManager.get(DEMO_NAME, path); + }); + var atlasLoader = new spine.AtlasAttachmentLoader(atlas); + var skeletonJson = new spine.SkeletonJson(atlasLoader); + var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json")["spineboy"]); + skeleton = new spine.Skeleton(skeletonData); + state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data)); + state.setAnimation(0, "hoverboard", true); + state.apply(skeleton); + skeleton.updateWorldTransform(); + var offset = new spine.Vector2(); + bounds = new spine.Vector2(); + skeleton.getBounds(offset, bounds, []); + for (var i = 0; i < controlBones.length; i++) + hoverTargets.push(null); - renderer.camera.position.x = offset.x + bounds.x / 2; - renderer.camera.position.y = offset.y + bounds.y / 2; + renderer.camera.position.x = offset.x + bounds.x / 2; + renderer.camera.position.y = offset.y + bounds.y / 2; - renderer.skeletonDebugRenderer.drawMeshHull = false; - renderer.skeletonDebugRenderer.drawMeshTriangles = false; + renderer.skeletonDebugRenderer.drawMeshHull = false; + renderer.skeletonDebugRenderer.drawMeshTriangles = false; - setupUI(); - setupInput(); - - loadingComplete(canvas, render); - } else { - loadingScreen.draw(); - requestAnimationFrame(load); - } + setupUI(); + setupInput(); } function setupUI () { @@ -180,9 +170,10 @@ var hoverboardDemo = function(canvas, loadingComplete, bgColor) { } renderer.end(); gl.lineWidth(1); - - loadingScreen.draw(true); } + hoverboardDemo.loadingComplete = loadingComplete; + hoverboardDemo.render = render; + hoverboardDemo.DEMO_NAME = DEMO_NAME; init(); }; \ No newline at end of file diff --git a/spine-ts/webgl/demos/imagechanges.html b/spine-ts/webgl/demos/imagechanges.html index f2d3cfc4a..dfb86255f 100644 --- a/spine-ts/webgl/demos/imagechanges.html +++ b/spine-ts/webgl/demos/imagechanges.html @@ -9,7 +9,7 @@
-
+

@@ -17,9 +17,7 @@ diff --git a/spine-ts/webgl/demos/imagechanges.js b/spine-ts/webgl/demos/imagechanges.js index 0bb11cc76..e918027f4 100644 --- a/spine-ts/webgl/demos/imagechanges.js +++ b/spine-ts/webgl/demos/imagechanges.js @@ -1,4 +1,4 @@ -var imageChangesDemo = function(canvas, loadingComplete, bgColor) { +var imageChangesDemo = function(canvas, bgColor) { var OUTLINE_COLOR = new spine.Color(0, 0.8, 0, 1); var canvas, gl, renderer, input, assetManager; @@ -23,21 +23,12 @@ var imageChangesDemo = function(canvas, loadingComplete, bgColor) { assetManager.loadText(DEMO_NAME, "atlas1.atlas"); assetManager.loadJson(DEMO_NAME, "demos.json"); timeKeeper = new spine.TimeKeeper(); - loadingScreen = new spine.webgl.LoadingScreen(renderer); - requestAnimationFrame(load); } - function load () { - timeKeeper.update(); - if (assetManager.isLoadingComplete(DEMO_NAME)) { - skeletons["Alien"] = loadSkeleton("alien", "death", ["head", "splat-fg", "splat-bg"]); - skeletons["Dragon"] = loadSkeleton("dragon", "flying", ["R_wing"]) - setupUI(); - loadingComplete(canvas, render); - } else { - loadingScreen.draw(); - requestAnimationFrame(load); - } + function loadingComplete () { + skeletons["Alien"] = loadSkeleton("alien", "death", ["head", "splat-fg", "splat-bg"]); + skeletons["Dragon"] = loadSkeleton("dragon", "flying", ["R_wing"]) + setupUI(); } function setupUI() { @@ -197,9 +188,10 @@ var imageChangesDemo = function(canvas, loadingComplete, bgColor) { } renderer.end(); - - loadingScreen.draw(true); } + imageChangesDemo.loadingComplete = loadingComplete; + imageChangesDemo.render = render; + imageChangesDemo.DEMO_NAME = DEMO_NAME; init(); }; \ No newline at end of file diff --git a/spine-ts/webgl/demos/meshes.html b/spine-ts/webgl/demos/meshes.html index 026360e52..82b1b83d0 100644 --- a/spine-ts/webgl/demos/meshes.html +++ b/spine-ts/webgl/demos/meshes.html @@ -9,7 +9,7 @@
-
+


@@ -19,9 +19,7 @@ diff --git a/spine-ts/webgl/demos/meshes.js b/spine-ts/webgl/demos/meshes.js index 36f6a09ad..eaecb5c1e 100644 --- a/spine-ts/webgl/demos/meshes.js +++ b/spine-ts/webgl/demos/meshes.js @@ -1,4 +1,4 @@ -var meshesDemo = function(canvas, loadingComplete, bgColor) { +var meshesDemo = function(canvas, bgColor) { var canvas, gl, renderer, input, assetManager; var skeleton, bounds; var timeKeeper, loadingScreen; @@ -21,22 +21,14 @@ var meshesDemo = function(canvas, loadingComplete, bgColor) { assetManager.loadText(DEMO_NAME, "atlas2.atlas"); assetManager.loadJson(DEMO_NAME, "demos.json"); timeKeeper = new spine.TimeKeeper(); - loadingScreen = new spine.webgl.LoadingScreen(renderer); - requestAnimationFrame(load); } - function load () { + function loadingComplete () { timeKeeper.update(); - if (assetManager.isLoadingComplete(DEMO_NAME)) { - skeletons["Orange Girl"] = loadSkeleton("orangegirl", "animation"); - skeletons["Green Girl"] = loadSkeleton("greengirl", "animation"); - skeletons["Armor Girl"] = loadSkeleton("armorgirl", "animation"); - setupUI(); - loadingComplete(canvas, render); - } else { - loadingScreen.draw(); - requestAnimationFrame(load); - } + skeletons["Orange Girl"] = loadSkeleton("orangegirl", "animation"); + skeletons["Green Girl"] = loadSkeleton("greengirl", "animation"); + skeletons["Armor Girl"] = loadSkeleton("armorgirl", "animation"); + setupUI(); } function setupUI() { @@ -157,9 +149,10 @@ var meshesDemo = function(canvas, loadingComplete, bgColor) { renderer.drawSkeleton(skeleton, true); renderer.drawSkeletonDebug(skeleton); renderer.end(); - - loadingScreen.draw(true); } + meshesDemo.loadingComplete = loadingComplete; + meshesDemo.render = render; + meshesDemo.DEMO_NAME = DEMO_NAME; init(); }; \ No newline at end of file diff --git a/spine-ts/webgl/demos/skins.html b/spine-ts/webgl/demos/skins.html index 0c9b8ea28..ba37b70c9 100644 --- a/spine-ts/webgl/demos/skins.html +++ b/spine-ts/webgl/demos/skins.html @@ -9,7 +9,7 @@
-
+


@@ -18,9 +18,7 @@ diff --git a/spine-ts/webgl/demos/skins.js b/spine-ts/webgl/demos/skins.js index a473f9383..d41a45282 100644 --- a/spine-ts/webgl/demos/skins.js +++ b/spine-ts/webgl/demos/skins.js @@ -1,4 +1,4 @@ -var skinsDemo = function(canvas, loadingComplete, bgColor) { +var skinsDemo = function(canvas, bgColor) { var canvas, gl, renderer, input, assetManager; var skeleton, state, offset, bounds; var timeKeeper, loadingScreen; @@ -21,39 +21,30 @@ var skinsDemo = function(canvas, loadingComplete, bgColor) { assetManager.loadJson(DEMO_NAME, "demos.json"); input = new spine.webgl.Input(canvas); timeKeeper = new spine.TimeKeeper(); - loadingScreen = new spine.webgl.LoadingScreen(renderer); - requestAnimationFrame(load); } - function load () { - timeKeeper.update(); - if (assetManager.isLoadingComplete(DEMO_NAME)) { - var atlas = new spine.TextureAtlas(assetManager.get(DEMO_NAME, "heroes.atlas"), function(path) { - return assetManager.get(DEMO_NAME, path); - }); - var atlasLoader = new spine.AtlasAttachmentLoader(atlas); - var skeletonJson = new spine.SkeletonJson(atlasLoader); - var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json").heroes); - skeleton = new spine.Skeleton(skeletonData); - skeleton.setSkinByName("Assassin"); - var stateData = new spine.AnimationStateData(skeleton.data); - stateData.defaultMix = 0.2; - stateData.setMix("roll", "run", 0); - stateData.setMix("jump", "run2", 0); - state = new spine.AnimationState(stateData); - setupAnimations(state); - state.apply(skeleton); - skeleton.updateWorldTransform(); - offset = new spine.Vector2(); - bounds = new spine.Vector2(); - skeleton.getBounds(offset, bounds, []); - setupUI(); - setupInput(); - loadingComplete(canvas, render); - } else { - loadingScreen.draw(); - requestAnimationFrame(load); - } + function loadingComplete () { + var atlas = new spine.TextureAtlas(assetManager.get(DEMO_NAME, "heroes.atlas"), function(path) { + return assetManager.get(DEMO_NAME, path); + }); + var atlasLoader = new spine.AtlasAttachmentLoader(atlas); + var skeletonJson = new spine.SkeletonJson(atlasLoader); + var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json").heroes); + skeleton = new spine.Skeleton(skeletonData); + skeleton.setSkinByName("Assassin"); + var stateData = new spine.AnimationStateData(skeleton.data); + stateData.defaultMix = 0.2; + stateData.setMix("roll", "run", 0); + stateData.setMix("jump", "run2", 0); + state = new spine.AnimationState(stateData); + setupAnimations(state); + state.apply(skeleton); + skeleton.updateWorldTransform(); + offset = new spine.Vector2(); + bounds = new spine.Vector2(); + skeleton.getBounds(offset, bounds, []); + setupUI(); + setupInput(); } function setupInput (){ @@ -213,9 +204,10 @@ var skinsDemo = function(canvas, loadingComplete, bgColor) { var height = scale * texture.getImage().height; renderer.drawTexture(texture, offset.x + bounds.x + 190, offset.y + bounds.y / 2 - height / 2 - 5, width, height); renderer.end(); - - loadingScreen.draw(true); } + skinsDemo.loadingComplete = loadingComplete; + skinsDemo.render = render; + skinsDemo.DEMO_NAME = DEMO_NAME; init(); }; \ No newline at end of file diff --git a/spine-ts/webgl/demos/spritesheets.html b/spine-ts/webgl/demos/spritesheets.html index d936c13ea..79ea89b82 100644 --- a/spine-ts/webgl/demos/spritesheets.html +++ b/spine-ts/webgl/demos/spritesheets.html @@ -9,7 +9,7 @@
-
+

Time multiplier @@ -18,9 +18,7 @@ Time multiplier diff --git a/spine-ts/webgl/demos/spritesheets.js b/spine-ts/webgl/demos/spritesheets.js index 4d21705ee..7e8e416fc 100644 --- a/spine-ts/webgl/demos/spritesheets.js +++ b/spine-ts/webgl/demos/spritesheets.js @@ -1,4 +1,4 @@ -var spritesheetsDemo = function(canvas, loadingComplete, bgColor) { +var spritesheetsDemo = function(canvas, bgColor) { var SKELETON_ATLAS_COLOR = new spine.Color(0, 0.8, 0, 0.8); var FRAME_ATLAS_COLOR = new spine.Color(0.8, 0, 0, 0.8); @@ -27,50 +27,41 @@ var spritesheetsDemo = function(canvas, loadingComplete, bgColor) { assetManager.loadJson(DEMO_NAME, "demos.json"); timeKeeper = new spine.TimeKeeper(); input = new spine.webgl.Input(canvas); - loadingScreen = new spine.webgl.LoadingScreen(renderer); - requestAnimationFrame(load); } - function load () { - timeKeeper.update(); - if (assetManager.isLoadingComplete(DEMO_NAME)) { - skeletonAtlas = new spine.TextureAtlas(assetManager.get(DEMO_NAME, "atlas1.atlas"), function(path) { - return assetManager.get(DEMO_NAME, path); - }); - var atlasLoader = new spine.AtlasAttachmentLoader(skeletonAtlas); - var skeletonJson = new spine.SkeletonJson(atlasLoader); - var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json").raptor); - skeleton = new spine.Skeleton(skeletonData); - var stateData = new spine.AnimationStateData(skeleton.data); - stateData.defaultMix = 0.5; - stateData.setMix("jump", "walk", 0.3); - animationState = new spine.AnimationState(stateData); - animationState.setAnimation(0, "walk", true); - animationState.apply(skeleton); - skeleton.updateWorldTransform(); - offset = new spine.Vector2(); - bounds = new spine.Vector2(); - skeleton.getBounds(offset, bounds, []); - skeleton.x -= 60; + function loadingComplete () { + skeletonAtlas = new spine.TextureAtlas(assetManager.get(DEMO_NAME, "atlas1.atlas"), function(path) { + return assetManager.get(DEMO_NAME, path); + }); + var atlasLoader = new spine.AtlasAttachmentLoader(skeletonAtlas); + var skeletonJson = new spine.SkeletonJson(atlasLoader); + var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json").raptor); + skeleton = new spine.Skeleton(skeletonData); + var stateData = new spine.AnimationStateData(skeleton.data); + stateData.defaultMix = 0.5; + stateData.setMix("jump", "walk", 0.3); + animationState = new spine.AnimationState(stateData); + animationState.setAnimation(0, "walk", true); + animationState.apply(skeleton); + skeleton.updateWorldTransform(); + offset = new spine.Vector2(); + bounds = new spine.Vector2(); + skeleton.getBounds(offset, bounds, []); + skeleton.x -= 60; - skeletonSeq = new spine.Skeleton(skeletonData); - walkAnim = skeletonSeq.data.findAnimation("walk"); - walkAnim.apply(skeletonSeq, 0, 0, true, null, 1, true, false); - skeletonSeq.x += bounds.x + 150; + skeletonSeq = new spine.Skeleton(skeletonData); + walkAnim = skeletonSeq.data.findAnimation("walk"); + walkAnim.apply(skeletonSeq, 0, 0, true, null, 1, true, false); + skeletonSeq.x += bounds.x + 150; - viewportWidth = ((700 + bounds.x) - offset.x); - viewportHeight = ((0 + bounds.y) - offset.y); - resize(); - setupUI(); - setupInput(); + viewportWidth = ((700 + bounds.x) - offset.x); + viewportHeight = ((0 + bounds.y) - offset.y); + resize(); + setupUI(); + setupInput(); - $("#spritesheets-overlay").removeClass("overlay-hide"); - $("#spritesheets-overlay").addClass("overlay"); - loadingComplete(canvas, render); - } else { - loadingScreen.draw(); - requestAnimationFrame(load); - } + $("#spritesheets-overlay").removeClass("overlay-hide"); + $("#spritesheets-overlay").addClass("overlay"); } function setupUI () { @@ -150,9 +141,10 @@ var spritesheetsDemo = function(canvas, loadingComplete, bgColor) { renderer.drawSkeleton(skeleton, true); renderer.drawSkeleton(skeletonSeq, true); renderer.end(); - - loadingScreen.draw(true); } + spritesheetsDemo.loadingComplete = loadingComplete; + spritesheetsDemo.render = render; + spritesheetsDemo.DEMO_NAME = DEMO_NAME; init(); }; \ No newline at end of file diff --git a/spine-ts/webgl/demos/stretchyman.html b/spine-ts/webgl/demos/stretchyman.html index 8f9ef9030..9b5dcbffc 100644 --- a/spine-ts/webgl/demos/stretchyman.html +++ b/spine-ts/webgl/demos/stretchyman.html @@ -9,15 +9,13 @@
-
+
Display bones
diff --git a/spine-ts/webgl/demos/stretchyman.js b/spine-ts/webgl/demos/stretchyman.js index 8bbe6cc34..459d6ff29 100644 --- a/spine-ts/webgl/demos/stretchyman.js +++ b/spine-ts/webgl/demos/stretchyman.js @@ -1,4 +1,4 @@ -var stretchymanDemo = function(canvas, loadingComplete, bgColor) { +var stretchymanDemo = function(canvas, bgColor) { var COLOR_INNER = new spine.Color(0.8, 0, 0, 0.5); var COLOR_OUTER = new spine.Color(0.8, 0, 0, 0.8); var COLOR_INNER_SELECTED = new spine.Color(0.0, 0, 0.8, 0.5); @@ -37,43 +37,33 @@ var stretchymanDemo = function(canvas, loadingComplete, bgColor) { assetManager.loadText(DEMO_NAME, "atlas2.atlas"); assetManager.loadJson(DEMO_NAME, "demos.json"); timeKeeper = new spine.TimeKeeper(); - loadingScreen = new spine.webgl.LoadingScreen(renderer); - requestAnimationFrame(load); } - function load () { - timeKeeper.update(); - if (assetManager.isLoadingComplete(DEMO_NAME)) { - var atlas = new spine.TextureAtlas(assetManager.get(DEMO_NAME, "atlas2.atlas"), function(path) { - return assetManager.get(DEMO_NAME, path); - }); - var atlasLoader = new spine.AtlasAttachmentLoader(atlas); - var skeletonJson = new spine.SkeletonJson(atlasLoader); - var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json").stretchyman); - skeleton = new spine.Skeleton(skeletonData); - skeleton.setToSetupPose(); - skeleton.updateWorldTransform(); - var offset = new spine.Vector2(); - bounds = new spine.Vector2(); - skeleton.getBounds(offset, bounds, []); - for (var i = 0; i < controlBones.length; i++) hoverTargets.push(null); - state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data)); - state.setAnimation(0, "idle", true); + function loadingComplete () { + var atlas = new spine.TextureAtlas(assetManager.get(DEMO_NAME, "atlas2.atlas"), function(path) { + return assetManager.get(DEMO_NAME, path); + }); + var atlasLoader = new spine.AtlasAttachmentLoader(atlas); + var skeletonJson = new spine.SkeletonJson(atlasLoader); + var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json").stretchyman); + skeleton = new spine.Skeleton(skeletonData); + skeleton.setToSetupPose(); + skeleton.updateWorldTransform(); + var offset = new spine.Vector2(); + bounds = new spine.Vector2(); + skeleton.getBounds(offset, bounds, []); + for (var i = 0; i < controlBones.length; i++) hoverTargets.push(null); + state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data)); + state.setAnimation(0, "idle", true); - renderer.camera.position.x = offset.x + bounds.x / 2; - renderer.camera.position.y = offset.y + bounds.y / 2; + renderer.camera.position.x = offset.x + bounds.x / 2; + renderer.camera.position.y = offset.y + bounds.y / 2; - renderer.skeletonDebugRenderer.drawMeshHull = false; - renderer.skeletonDebugRenderer.drawMeshTriangles = false; + renderer.skeletonDebugRenderer.drawMeshHull = false; + renderer.skeletonDebugRenderer.drawMeshTriangles = false; - setupUI(); - setupInput(); - - loadingComplete(canvas, render); - } else { - loadingScreen.draw(); - requestAnimationFrame(load); - } + setupUI(); + setupInput(); } function setupUI() { @@ -189,9 +179,10 @@ var stretchymanDemo = function(canvas, loadingComplete, bgColor) { } renderer.end(); gl.lineWidth(1); - - loadingScreen.draw(true); } + stretchymanDemo.loadingComplete = loadingComplete; + stretchymanDemo.render = render; + stretchymanDemo.DEMO_NAME = DEMO_NAME; init(); }; \ No newline at end of file diff --git a/spine-ts/webgl/demos/tank.html b/spine-ts/webgl/demos/tank.html index 02868ec7a..0c6c7d054 100644 --- a/spine-ts/webgl/demos/tank.html +++ b/spine-ts/webgl/demos/tank.html @@ -9,7 +9,7 @@
-
+

Display bones @@ -17,9 +17,7 @@ diff --git a/spine-ts/webgl/demos/tank.js b/spine-ts/webgl/demos/tank.js index e57822c46..86918d4a0 100644 --- a/spine-ts/webgl/demos/tank.js +++ b/spine-ts/webgl/demos/tank.js @@ -1,7 +1,7 @@ -var tankDemo = function(canvas, loadingComplete, bgColor) { +var tankDemo = function(canvas, bgColor) { var canvas, gl, renderer, input, assetManager; var skeleton, state, offset, bounds; - var timeKeeper, loadingScreen; + var timeKeeper; var playButton, timeLine, isPlaying = true, playTime = 0; var DEMO_NAME = "TankDemo"; @@ -19,41 +19,32 @@ var tankDemo = function(canvas, loadingComplete, bgColor) { assetManager.loadText(DEMO_NAME, "atlas2.atlas"); assetManager.loadJson(DEMO_NAME, "demos.json"); timeKeeper = new spine.TimeKeeper(); - loadingScreen = new spine.webgl.LoadingScreen(renderer); - requestAnimationFrame(load); } - function load () { - timeKeeper.update(); - if (assetManager.isLoadingComplete(DEMO_NAME)) { - var atlas = new spine.TextureAtlas(assetManager.get(DEMO_NAME, "atlas2.atlas"), function(path) { - return assetManager.get(DEMO_NAME, path); - }); - var atlasLoader = new spine.AtlasAttachmentLoader(atlas); - var skeletonJson = new spine.SkeletonJson(atlasLoader); - var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json").tank); - skeleton = new spine.Skeleton(skeletonData); - state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data)); - state.setAnimation(0, "drive", true); - state.apply(skeleton); - skeleton.updateWorldTransform(); - offset = new spine.Vector2(); - bounds = new spine.Vector2(); - offset.x = -1204.22; - bounds.x = 1914.52; - bounds.y = 965.78; - // skeleton.getBounds(offset, bounds); + function loadingComplete () { + var atlas = new spine.TextureAtlas(assetManager.get(DEMO_NAME, "atlas2.atlas"), function(path) { + return assetManager.get(DEMO_NAME, path); + }); + var atlasLoader = new spine.AtlasAttachmentLoader(atlas); + var skeletonJson = new spine.SkeletonJson(atlasLoader); + var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json").tank); + skeleton = new spine.Skeleton(skeletonData); + state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data)); + state.setAnimation(0, "drive", true); + state.apply(skeleton); + skeleton.updateWorldTransform(); + offset = new spine.Vector2(); + bounds = new spine.Vector2(); + offset.x = -1204.22; + bounds.x = 1914.52; + bounds.y = 965.78; + // skeleton.getBounds(offset, bounds); - renderer.skeletonDebugRenderer.drawRegionAttachments = false; - renderer.skeletonDebugRenderer.drawMeshHull = false; - renderer.skeletonDebugRenderer.drawMeshTriangles = false; + renderer.skeletonDebugRenderer.drawRegionAttachments = false; + renderer.skeletonDebugRenderer.drawMeshHull = false; + renderer.skeletonDebugRenderer.drawMeshTriangles = false; - setupUI(); - loadingComplete(canvas, render); - } else { - loadingScreen.draw(); - requestAnimationFrame(load); - } + setupUI(); } function setupUI() { @@ -121,9 +112,10 @@ var tankDemo = function(canvas, loadingComplete, bgColor) { renderer.drawSkeleton(skeleton, true); renderer.drawSkeletonDebug(skeleton, true); renderer.end(); - - loadingScreen.draw(true); } + tankDemo.loadingComplete = loadingComplete; + tankDemo.render = render; + tankDemo.DEMO_NAME = DEMO_NAME; init(); }; \ No newline at end of file diff --git a/spine-ts/webgl/demos/transforms.html b/spine-ts/webgl/demos/transforms.html index 9a32b3304..9bc4d711b 100644 --- a/spine-ts/webgl/demos/transforms.html +++ b/spine-ts/webgl/demos/transforms.html @@ -9,7 +9,7 @@
-
+
Rotation offset

Translation mix @@ -18,9 +18,7 @@ Translation mix diff --git a/spine-ts/webgl/demos/transforms.js b/spine-ts/webgl/demos/transforms.js index 43ea78895..8e984b2b0 100644 --- a/spine-ts/webgl/demos/transforms.js +++ b/spine-ts/webgl/demos/transforms.js @@ -1,4 +1,4 @@ -var transformsDemo = function(canvas, loadingComplete, bgColor) { +var transformsDemo = function(canvas, bgColor) { var COLOR_INNER = new spine.Color(0.8, 0, 0, 0.5); var COLOR_OUTER = new spine.Color(0.8, 0, 0, 0.8); var COLOR_INNER_SELECTED = new spine.Color(0.0, 0, 0.8, 0.5); @@ -6,7 +6,7 @@ var transformsDemo = function(canvas, loadingComplete, bgColor) { var canvas, gl, renderer, input, assetManager; var skeleton, state, bounds; - var timeKeeper, loadingScreen; + var timeKeeper; var rotateHandle; var target = null; var hoverTargets = [null, null, null]; @@ -31,45 +31,35 @@ var transformsDemo = function(canvas, loadingComplete, bgColor) { assetManager.loadJson(DEMO_NAME, "demos.json"); input = new spine.webgl.Input(canvas); timeKeeper = new spine.TimeKeeper(); - loadingScreen = new spine.webgl.LoadingScreen(renderer); - requestAnimationFrame(load); } - function load () { - timeKeeper.update(); - if (assetManager.isLoadingComplete(DEMO_NAME)) { - var atlas = new spine.TextureAtlas(assetManager.get(DEMO_NAME, "atlas2.atlas"), function(path) { - return assetManager.get(DEMO_NAME, path); - }); - var atlasLoader = new spine.AtlasAttachmentLoader(atlas); - var skeletonJson = new spine.SkeletonJson(atlasLoader); - var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json").transforms); - skeleton = new spine.Skeleton(skeletonData); - skeleton.setToSetupPose(); - skeleton.updateWorldTransform(); - var offset = new spine.Vector2(); - bounds = new spine.Vector2(); - skeleton.getBounds(offset, bounds, []); - state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data)); - skeleton.setToSetupPose(); - skeleton.updateWorldTransform(); - rotateHandle = skeleton.findBone("rotate-handle"); + function loadingComplete () { + var atlas = new spine.TextureAtlas(assetManager.get(DEMO_NAME, "atlas2.atlas"), function(path) { + return assetManager.get(DEMO_NAME, path); + }); + var atlasLoader = new spine.AtlasAttachmentLoader(atlas); + var skeletonJson = new spine.SkeletonJson(atlasLoader); + var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json").transforms); + skeleton = new spine.Skeleton(skeletonData); + skeleton.setToSetupPose(); + skeleton.updateWorldTransform(); + var offset = new spine.Vector2(); + bounds = new spine.Vector2(); + skeleton.getBounds(offset, bounds, []); + state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data)); + skeleton.setToSetupPose(); + skeleton.updateWorldTransform(); + rotateHandle = skeleton.findBone("rotate-handle"); - renderer.camera.position.x = offset.x + bounds.x / 2; - renderer.camera.position.y = offset.y + bounds.y / 2; + renderer.camera.position.x = offset.x + bounds.x / 2; + renderer.camera.position.y = offset.y + bounds.y / 2; - renderer.skeletonDebugRenderer.drawRegionAttachments = false; - renderer.skeletonDebugRenderer.drawMeshHull = false; - renderer.skeletonDebugRenderer.drawMeshTriangles = false; + renderer.skeletonDebugRenderer.drawRegionAttachments = false; + renderer.skeletonDebugRenderer.drawMeshHull = false; + renderer.skeletonDebugRenderer.drawMeshTriangles = false; - setupUI(); - setupInput(); - - loadingComplete(canvas, render); - } else { - loadingScreen.draw(); - requestAnimationFrame(load); - } + setupUI(); + setupInput(); } function setupUI() { @@ -178,9 +168,10 @@ var transformsDemo = function(canvas, loadingComplete, bgColor) { } gl.lineWidth(1); renderer.end(); - - loadingScreen.draw(true); } + transformsDemo.loadingComplete = loadingComplete; + transformsDemo.render = render; + transformsDemo.DEMO_NAME = DEMO_NAME; init(); }; \ No newline at end of file diff --git a/spine-ts/webgl/demos/transitions.html b/spine-ts/webgl/demos/transitions.html index 471604b57..718d4a353 100644 --- a/spine-ts/webgl/demos/transitions.html +++ b/spine-ts/webgl/demos/transitions.html @@ -9,7 +9,7 @@
-
+
Time multiplier

@@ -17,9 +17,7 @@ Time multiplier diff --git a/spine-ts/webgl/demos/transitions.js b/spine-ts/webgl/demos/transitions.js index a482f2d9e..263391918 100644 --- a/spine-ts/webgl/demos/transitions.js +++ b/spine-ts/webgl/demos/transitions.js @@ -5,7 +5,6 @@ var transitionsDemo = function(canvas, loadingComplete, bgColor) { var skeleton, skeletonNoMix, state, stateNoMix, bounds; var timeSlider, timeSliderLabel; var timeKeeper; - var loadingScreen; var DEMO_NAME = "TransitionsDemo"; @@ -29,34 +28,24 @@ var transitionsDemo = function(canvas, loadingComplete, bgColor) { input = new spine.webgl.Input(canvas); timeKeeper = new spine.TimeKeeper(); - loadingScreen = new spine.webgl.LoadingScreen(renderer); - - requestAnimationFrame(load); } - function load () { - timeKeeper.update(); - if (assetManager.isLoadingComplete(DEMO_NAME)) { - skeleton = loadSkeleton("spineboy"); - skeletonNoMix = new spine.Skeleton(skeleton.data); - state = createState(0.25); - state.multipleMixing = true; - setAnimations(state, 0, 0); - stateNoMix = createState(0); - setAnimations(stateNoMix, -0.25, 0); + function loadingComplete () { + skeleton = loadSkeleton("spineboy"); + skeletonNoMix = new spine.Skeleton(skeleton.data); + state = createState(0.25); + state.multipleMixing = true; + setAnimations(state, 0, 0); + stateNoMix = createState(0); + setAnimations(stateNoMix, -0.25, 0); - state.apply(skeleton); - skeleton.updateWorldTransform(); - bounds = { offset: new spine.Vector2(), size: new spine.Vector2() }; - skeleton.getBounds(bounds.offset, bounds.size, []); - setupInput(); - $("#transitions-overlay").removeClass("overlay-hide"); - $("#transitions-overlay").addClass("overlay"); - loadingComplete(canvas, render); - } else { - loadingScreen.draw(); - requestAnimationFrame(load); - } + state.apply(skeleton); + skeleton.updateWorldTransform(); + bounds = { offset: new spine.Vector2(), size: new spine.Vector2() }; + skeleton.getBounds(bounds.offset, bounds.size, []); + setupInput(); + $("#transitions-overlay").removeClass("overlay-hide"); + $("#transitions-overlay").addClass("overlay"); } function setupInput() { @@ -142,9 +131,10 @@ var transitionsDemo = function(canvas, loadingComplete, bgColor) { skeletonNoMix.y = -100; renderer.drawSkeleton(skeletonNoMix, true); renderer.end(); - - loadingScreen.draw(true); } + + transitionsDemo.loadingComplete = loadingComplete; + transitionsDemo.render = render; + transitionsDemo.DEMO_NAME = DEMO_NAME; init(); - return render; }; \ No newline at end of file diff --git a/spine-ts/webgl/demos/utils.js b/spine-ts/webgl/demos/utils.js index bfb1447f9..56b1a98d6 100644 --- a/spine-ts/webgl/demos/utils.js +++ b/spine-ts/webgl/demos/utils.js @@ -18,16 +18,36 @@ var spineDemos = { for (var i = 0; i < demos.length; i++) { var demo = demos[i]; var canvas = demo.canvas; - var renderFunc = demo.renderFunc; - if (demo.visible) { - if (spineDemos.log) console.log("Rendering " + canvas.id); - renderFunc(); + + if (!spineDemos.assetManager.isLoadingComplete(demo.DEMO_NAME)) { + if (demo.visible) { + if (canvas.parentElement != demo.placeholder) { + $(canvas).detach(); + demo.placeholder.appendChild(canvas); + } + demo.loadingScreen.draw(); + } + } else { + if (!demo.loaded) { + demo.loadingComplete(); + demo.loaded = true; + } + + if (demo.visible) { + if (canvas.parentElement != demo.placeholder) { + $(canvas).detach(); + demo.placeholder.appendChild(canvas); + } + if (spineDemos.log) console.log("Rendering " + canvas.id); + demo.render(); + demo.loadingScreen.draw(true); + } } } } function checkElementVisible(demo) { - const rect = demo.canvas.getBoundingClientRect(); + const rect = demo.placeholder.getBoundingClientRect(); const windowHeight = (window.innerHeight || document.documentElement.clientHeight); const windowWidth = (window.innerWidth || document.documentElement.clientWidth); const vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) >= 0); @@ -36,41 +56,37 @@ var spineDemos = { demo.visible = (vertInView && horInView); } - spineDemos.setupRendering = function (canvas, renderFunc) { - var demo = {canvas: canvas, renderFunc: renderFunc, visible: false}; - $(window).on('DOMContentLoaded load resize scroll', function() { - checkElementVisible(demo); - }); - checkElementVisible(demo); - if (!spineDemos.loopRunning) { - loop(); - spineDemos.loopRunning = true; - } - spineDemos.demos.push(demo); - }; - - spineDemos.init = function () { - spineDemos.createCanvases(3); - spineDemos.loadSliders(); - } - - spineDemos.createCanvases = function (numCanvases) { + function createCanvases (numCanvases) { for (var i = 0; i < numCanvases; i++) { var canvas = document.createElement("canvas"); canvas.ctx = new spine.webgl.ManagedWebGLRenderingContext(canvas, { alpha: false }); + canvas.id = "canvas-" + i; spineDemos.canvases.push(canvas); } } - spineDemos.obtainCanvas = function () { - return spineDemos.canvases.splice(0, 1)[0]; + spineDemos.init = function () { + createCanvases(3); + loadSliders(); + requestAnimationFrame(loop); } - spineDemos.freeCanvas = function (canvas) { - canvases.push(canvas); + spineDemos.addDemo = function (demo, placeholder) { + var canvas = spineDemos.canvases[spineDemos.demos.length % spineDemos.canvases.length]; + demo(canvas); + demo.placeholder = placeholder; + demo.canvas = canvas; + demo.visible = false; + var renderer = new spine.webgl.SceneRenderer(canvas, canvas.ctx.gl); + demo.loadingScreen = new spine.webgl.LoadingScreen(renderer); + $(window).on('DOMContentLoaded load resize scroll', function() { + checkElementVisible(demo); + }); + checkElementVisible(demo); + spineDemos.demos.push(demo); } - spineDemos.loadSliders = function () { + loadSliders = function () { $(window).resize(function() { $(".slider").each(function () { $(this).data("slider").resized(); diff --git a/spine-ts/webgl/demos/vine.html b/spine-ts/webgl/demos/vine.html index df9b4b2a9..fada25492 100644 --- a/spine-ts/webgl/demos/vine.html +++ b/spine-ts/webgl/demos/vine.html @@ -9,7 +9,7 @@
-
+

Display bones & path @@ -17,9 +17,7 @@ diff --git a/spine-ts/webgl/demos/vine.js b/spine-ts/webgl/demos/vine.js index f0b4cdf65..6b0e61990 100644 --- a/spine-ts/webgl/demos/vine.js +++ b/spine-ts/webgl/demos/vine.js @@ -1,4 +1,4 @@ -var vineDemo = function(canvas, loadingComplete, bgColor) { +var vineDemo = function(canvas, bgColor) { var COLOR_INNER = new spine.Color(0.8, 0, 0, 0.5); var COLOR_OUTER = new spine.Color(0.8, 0, 0, 0.8); var COLOR_INNER_SELECTED = new spine.Color(0.0, 0, 0.8, 0.5); @@ -6,7 +6,7 @@ var vineDemo = function(canvas, loadingComplete, bgColor) { var canvas, gl, renderer, input, assetManager; var skeleton, state, bounds; - var timeKeeper, loadingScreen; + var timeKeeper; var target = null; var hoverTargets = [null, null, null, null, null, null]; var controlBones = ["base", "vine-control1", "vine-control2", "vine-control3", "vine-control4"]; @@ -29,44 +29,34 @@ var vineDemo = function(canvas, loadingComplete, bgColor) { assetManager.loadText(DEMO_NAME, "atlas2.atlas"); assetManager.loadJson(DEMO_NAME, "demos.json"); timeKeeper = new spine.TimeKeeper(); - loadingScreen = new spine.webgl.LoadingScreen(renderer); - requestAnimationFrame(load); } - function load () { - timeKeeper.update(); - if (assetManager.isLoadingComplete(DEMO_NAME)) { - var atlas = new spine.TextureAtlas(assetManager.get(DEMO_NAME, "atlas2.atlas"), function(path) { - return assetManager.get(DEMO_NAME, path); - }); - var atlasLoader = new spine.AtlasAttachmentLoader(atlas); - var skeletonJson = new spine.SkeletonJson(atlasLoader); - var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json").vine); - skeleton = new spine.Skeleton(skeletonData); - skeleton.setToSetupPose(); - skeleton.updateWorldTransform(); - var offset = new spine.Vector2(); - bounds = new spine.Vector2(); - skeleton.getBounds(offset, bounds, []); - state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data)); - state.setAnimation(0, "animation", true); - state.apply(skeleton); - skeleton.updateWorldTransform(); + function loadingComplete () { + var atlas = new spine.TextureAtlas(assetManager.get(DEMO_NAME, "atlas2.atlas"), function(path) { + return assetManager.get(DEMO_NAME, path); + }); + var atlasLoader = new spine.AtlasAttachmentLoader(atlas); + var skeletonJson = new spine.SkeletonJson(atlasLoader); + var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json").vine); + skeleton = new spine.Skeleton(skeletonData); + skeleton.setToSetupPose(); + skeleton.updateWorldTransform(); + var offset = new spine.Vector2(); + bounds = new spine.Vector2(); + skeleton.getBounds(offset, bounds, []); + state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data)); + state.setAnimation(0, "animation", true); + state.apply(skeleton); + skeleton.updateWorldTransform(); - renderer.camera.position.x = offset.x + bounds.x / 2; - renderer.camera.position.y = offset.y + bounds.y / 2; + renderer.camera.position.x = offset.x + bounds.x / 2; + renderer.camera.position.y = offset.y + bounds.y / 2; - renderer.skeletonDebugRenderer.drawMeshHull = false; - renderer.skeletonDebugRenderer.drawMeshTriangles = false; + renderer.skeletonDebugRenderer.drawMeshHull = false; + renderer.skeletonDebugRenderer.drawMeshTriangles = false; - setupUI(); - setupInput(); - - loadingComplete(canvas, render); - } else { - loadingScreen.draw(); - requestAnimationFrame(load); - } + setupUI(); + setupInput(); } function setupUI() { @@ -182,9 +172,10 @@ var vineDemo = function(canvas, loadingComplete, bgColor) { } gl.lineWidth(1); renderer.end(); - - loadingScreen.draw(true); } + vineDemo.loadingComplete = loadingComplete; + vineDemo.render = render; + vineDemo.DEMO_NAME = DEMO_NAME; init(); }; \ No newline at end of file From 1cb78f658dd04ead0c1cb9cc19211a3f00fb7a6e Mon Sep 17 00:00:00 2001 From: NathanSweet Date: Thu, 14 Sep 2017 20:21:41 +0200 Subject: [PATCH 16/20] Shoot after moving hoverboard crosshair. --- spine-ts/webgl/demos/hoverboard.js | 1 + 1 file changed, 1 insertion(+) diff --git a/spine-ts/webgl/demos/hoverboard.js b/spine-ts/webgl/demos/hoverboard.js index 8c54d5f5a..e41091088 100644 --- a/spine-ts/webgl/demos/hoverboard.js +++ b/spine-ts/webgl/demos/hoverboard.js @@ -113,6 +113,7 @@ var hoverboardDemo = function(canvas, bgColor) { } }, up: function(x, y) { + if (target && target.data.name == "crosshair") $("#hoverboard-shoot").click(); target = null; }, dragged: function(x, y) { From 705a523949f961ba52f541edad09c11fb22981a4 Mon Sep 17 00:00:00 2001 From: NathanSweet Date: Thu, 14 Sep 2017 20:22:03 +0200 Subject: [PATCH 17/20] Fixed up layout to be similar to real demos page. --- spine-ts/webgl/demos/demos.css | 42 +++++++++++-- spine-ts/webgl/demos/demos.html | 102 +++++++++++--------------------- 2 files changed, 72 insertions(+), 72 deletions(-) diff --git a/spine-ts/webgl/demos/demos.css b/spine-ts/webgl/demos/demos.css index 8b26f115a..ad69fdd40 100644 --- a/spine-ts/webgl/demos/demos.css +++ b/spine-ts/webgl/demos/demos.css @@ -1,6 +1,5 @@ body, html { margin: 0; - height: 100%; font-family: Tahoma; font-size: 11pt; } @@ -12,14 +11,40 @@ br { content: ""; margin-top: 15px; } +h2 { + padding-top: 1em; +} canvas { - width: 640px; - height: 480px; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + width: 100%; + height: 100%; } .aspect { - width: 640px; - height: 480px; + position: relative; + width: 100%; +} + +.demo { + clear: both; +} +.demo-container { + float: left; + width: 58%; +} +.demo-text { + float: left; + width: 38%; + margin-left: 2%; + margin-right: 2%; +} + +.timeline, .timeline td:nth-child(2) { + width: 100%; } .play { @@ -36,13 +61,18 @@ canvas { margin: 0; } +.checkbox { + display: inline; +} + .slider { - width: 597px; + width: 100%; max-width: 800px; border-radius: 3px; text-align: left; transform: translateZ(0); background: #222; + display: inline-block; } .slider, .slider.filled span { height: 15px; diff --git a/spine-ts/webgl/demos/demos.html b/spine-ts/webgl/demos/demos.html index 88e0ac3c6..490a0c118 100644 --- a/spine-ts/webgl/demos/demos.html +++ b/spine-ts/webgl/demos/demos.html @@ -1,11 +1,8 @@ - - - Spine: Demos - - + + +Spine: Demos - @@ -23,13 +20,15 @@ + +
-
+

Spine versus sprite sheets

-
+
@@ -37,13 +36,7 @@
Sprite sheet
1 second of animation @ 30FPS
3.39 MB = 18x larger!
-
-

Traditional sprite animation requires an image for each frame of animation, resulting in massive sprite sheets. Each additional animation greatly increases your games' disk space and memory requirements, especially at frame rates necessary for smooth playback. It quickly becomes an enormous amount of work for your artists and your finished product suffers when the number of animations must be reduced to meet size constraints.

-

Spine animations store only the bone and animation data, coupled with a single set of individual images which are reused for every animation. This allows you to bring your games to life by packing them full of unique animations. Also, Spine animations are interpolated so playback is always perfectly smooth, regardless of the frame rate.

-

- - Compare the memory and disk space requirements of Spine versus sprite sheet animations. -

+
Animation speed
@@ -61,11 +54,11 @@
-
@@ -73,9 +66,7 @@
-
-

While Spine largely replaces the need for traditional frame-by-frame animation, images can still be swapped when needed. For example, a change of perspective for a torso or flapping wing, alternative facial expressions, or a muzzle flash.

-

Spine's slots, attachments, and draw order mechanisms allow you to easily integrate frame-by-frame animations in your otherwise fully dynamic Spine animations. Even better, Spine can manipulate the frame-by-frame images, shown in this demo by scaling on the alien's exploding head.

+
@@ -88,11 +79,11 @@
-
+

Transitions and layering

-
+
Smooth
@@ -100,9 +91,7 @@
-
-

An often felt disadvantage of 2D games is the lack of smooth animation transitions. In 3D games, transitions between animations can be calculated on-the-fly at runtime. Animations can even be blended, for example half walking and half running. In 2D games without Spine, blending is impossible and typically transitions are jarring. Artists can manually create frames for every possible transition, but even that doesn't help when animations can be interrupted mid playback.

-

Spine brings the benefits from the 3D world back to 2D. The Spine Runtimes smoothly and dynamically transition from one animation to the next, giving your characters natural looking fluidity. Layering allows animations to be blended on top of others, for example to play a shooting animation while your character is running or to blend walking and limping more and more as damage is taken.

+
@@ -119,11 +108,11 @@
-
+

Mesh deformation

-
+
@@ -131,10 +120,7 @@
-
-

A Spine character made up of rigid 2D images can already give excellent results, such as Spineboy in the demo above. To give your characters even more life, Spine brings more tricks from the 3D world in the form of meshes and weights. With meshes, images are no longer rigid and can bend and deform however you like. Weights bind meshes to bones, so the images deform automatically as the bones are moved.

-

Meshes can also improve your game's performance, reducing fill rate usage by not drawing transparent portions of your images. This is especially important on mobile devices.

-

The amazing art for this demo was kindly provided by Hwadock (a.k.a. dugy). Follow him on Twitter and his blog.

+
@@ -161,18 +147,15 @@
-
+

Skins

-
+
-
-

Spine's skins feature is perfect for providing customization and variety while keeping your workload reasonable. With skins, the work of animating only needs to be done once, then you can assign different looks to your skeletons while reusing all your animations. For ultimate flexibility, the Spine Runtimes let you combine parts from different skins at runtime, covering all possible customization needs.

-

Skins give players the ability to add their own touch to your game's world by outfitting their avatars with new looks, clothing, weapons, and other accessories. Skins also give you more mileage out of your animations: mix and match your art for enemies, items, and other game objects to greatly increase variety for little effort.

-

The art for this demo can be found in the 2D Anim Heroes character pack for Unity. +

@@ -198,18 +181,15 @@
-
+

Inverse kinematics

-
+
-
-

Spine's support for inverse kinematics allows for realistic and dynamic movement that would otherwise be difficult or impossible to animate. It also enables more advanced rigging, where complex poses can be easily controlled by a small number of bones.

-

Since Spine doesn't use baking or plotting, IK really shines at runtime. By dynamically positioning bones at runtime, IK constraints allow your character to easily react to the environment, such as aiming at enemies, having feet follow slopes and bumps in the terrain, and much more. In this demo Spineboy is balanced on a user controlled hover board while playing an animation at the same time.

-

Try it out! Drag the red circles around to dynamically pose Spineboy. The shoot and jump buttons and aim checkbox layer animations on top of the idle animation.

+
@@ -236,11 +216,11 @@
-
+

Path constraints

-
+
@@ -248,10 +228,7 @@
-
-

Often a part of a character follows an open or closed path. Rather than key this movement manually, Spine's path constraints can be used to make bones automatically follow a path. The composite Bézier path is made up of a set of interconnected points that let you bend and shape the path. The path itself can be animated and even weighted to bones, so the path deforms automatically as the bones are moved.

-

In this demo a vine mesh is bound to bones which are constrained to a path. The more vertices in the mesh, the smoother it will bend.

-

Path constraints can also be used to great effect at runtime. Move the red handles to dynamically modify the path and watch the vine follow it seamlessly!

+
@@ -264,13 +241,11 @@
-
+
-
-

Path constraints enable powerful rigging, shown by Stretchyman in this demo. For the arms and legs, meshes are weighted to many small bones which are then constrained to follow simple paths for the limbs. The paths are then weighted to bones which can be moved to control the limbs. This setups allows a large number of bones to be controlled with just a few bones. Not only does this make animating easier, but at runtime only a few bones need to be adjusted for posing dynamically.

-

Move the red handles and make Stretchyman dance!

+
@@ -284,11 +259,11 @@
-
+

Clipping

-
+
@@ -296,8 +271,7 @@
-
-

Sometimes parts of an animation must be partially hidden, like in this example where Spineboy comes out of a portal. Clipping comes in handy in these cases by restricting rendering to a polygonal area. Only the parts of the skeleton inside the predefined, animatable area are shown. This enables many effects that wouldn't otherwise be possible, such as windows, lighting effects, and more. It is also possible to have clipping only affect a subset of the skeleton. For example, an animation where a character goes through an x-ray.

+
@@ -311,11 +285,11 @@
-
+

Transform constraints

-
+
@@ -323,10 +297,7 @@
-
-

Animating complex skeletons with many interdependent pieces can be tedious. Spine's transform constraints remove this pain by unlocking more powerful rigging. By constraining bone transforms to the transform of another bone, you only need to animate one of the bones and the others are adjusted automatically. While seemingly simple on the surface, advanced rigging can make great use of this to automate how a skeleton behaves as it is posed.

-

Transform constraints are also great for machinery, such as the tank in this demo. Instead of keying the rotation of each individual wheel, a single wheel is animated while the others follow via a transform constraint. Offsetting and mixing can add individualism back to constrained parts.

-

The treads on the tank are circulated using a path constraint, which would be impossible to animate without paths. The path is weighted to the wheels, so the path bends automatically as the wheels move up and down.

+
@@ -339,12 +310,11 @@
-
+
-
-

In this demo, the rotation of the two smaller wheels is constrained by the big wheel's rotation. Also, the big wheel's translation is constrained so it stays between the two smaller wheels.

+
Rotation offset
From cb9e025390b53f71b9112cf73aa8b12b3cb05a8e Mon Sep 17 00:00:00 2001 From: badlogic Date: Fri, 15 Sep 2017 10:07:43 +0200 Subject: [PATCH 18/20] [webgl] Added visibility check to demo mainloop. --- spine-ts/webgl/demos/utils.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spine-ts/webgl/demos/utils.js b/spine-ts/webgl/demos/utils.js index 56b1a98d6..f4495508d 100644 --- a/spine-ts/webgl/demos/utils.js +++ b/spine-ts/webgl/demos/utils.js @@ -19,6 +19,8 @@ var spineDemos = { var demo = demos[i]; var canvas = demo.canvas; + checkElementVisible(demo); + if (!spineDemos.assetManager.isLoadingComplete(demo.DEMO_NAME)) { if (demo.visible) { if (canvas.parentElement != demo.placeholder) { From 61394b931768d9c2dbfb4f3f02bc3691aa72d300 Mon Sep 17 00:00:00 2001 From: badlogic Date: Fri, 15 Sep 2017 10:59:39 +0200 Subject: [PATCH 19/20] [webgl] Increased number of preallocated canvases to 4, seems save on mobile. --- spine-ts/webgl/demos/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spine-ts/webgl/demos/utils.js b/spine-ts/webgl/demos/utils.js index f4495508d..9b1d71241 100644 --- a/spine-ts/webgl/demos/utils.js +++ b/spine-ts/webgl/demos/utils.js @@ -68,7 +68,7 @@ var spineDemos = { } spineDemos.init = function () { - createCanvases(3); + createCanvases(4); loadSliders(); requestAnimationFrame(loop); } From 786f24c7dc5dccee1a6ac82b2e815f00d925dbc1 Mon Sep 17 00:00:00 2001 From: badlogic Date: Fri, 15 Sep 2017 11:00:28 +0200 Subject: [PATCH 20/20] [ue4] Don't redefine SP_API in dll.h, seems UBT passes -werror,-wmacro-redefine to compiler by default. Closes #994 --- spine-c/spine-c/include/spine/dll.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spine-c/spine-c/include/spine/dll.h b/spine-c/spine-c/include/spine/dll.h index ed9c328b5..02714ca45 100644 --- a/spine-c/spine-c/include/spine/dll.h +++ b/spine-c/spine-c/include/spine/dll.h @@ -31,8 +31,6 @@ #ifndef SPINE_SHAREDLIB_H #define SPINE_SHAREDLIB_H -#define SP_API - #ifdef _WIN32 #define DLLIMPORT __declspec(dllimport) #define DLLEXPORT __declspec(dllexport) @@ -43,6 +41,8 @@ #ifdef SPINEPLUGIN_API #define SP_API SPINEPLUGIN_API +#else + #define SP_API #endif #endif /* SPINE_SHAREDLIB_H */