Browse Source

[ts] More demo polishing

badlogic 9 years ago
parent
commit
47e706c972

+ 47 - 34
spine-ts/webgl/demos/ikconstraint.js

@@ -1,11 +1,9 @@
 var ikConstraintDemo = function(pathPrefix, loadingComplete) {
-	var CIRCLE_INNER_COLOR = new spine.Color(0.8, 0, 0, 0.5);
-	var CIRCLE_OUTER_COLOR = new spine.Color(0.8, 0, 0, 0.8);
-
 	var canvas, gl, renderer, input, assetManager;
 	var skeleton, bounds;		
 	var lastFrameTime = Date.now() / 1000;
-	var target = null;	
+	var target = null;
+	var isHover = false;
 	var boneName = "hip";
 	var coords = new spine.webgl.Vector3(), temp = new spine.webgl.Vector3(), temp2 = new spine.Vector2();		
 
@@ -17,33 +15,7 @@ var ikConstraintDemo = function(pathPrefix, loadingComplete) {
 
 		renderer = new spine.webgl.SceneRenderer(canvas, gl);
 		assetManager = new spine.webgl.AssetManager(gl, pathPrefix);
-		input = new spine.webgl.Input(canvas);
-		input.addListener({
-			down: function(x, y) {			
-				var bone = skeleton.findBone(boneName);				
-				renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);				
-				if (temp.set(skeleton.x + bone.worldX, skeleton.y + bone.worldY, 0).distance(coords) < 20) {
-					target = bone;
-				}				
-			},
-			up: function(x, y) {
-				target = null;
-			},
-			dragged: function(x, y) {
-				if (target != null) {
-					renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);
-					if (target.parent !== null) {
-						target.parent.worldToLocal(temp2.set(coords.x - skeleton.x, coords.y - skeleton.y));
-						target.x = temp2.x;
-						target.y = temp2.y;
-					} else {
-						target.x = coords.x - skeleton.x;
-						target.y = coords.y - skeleton.y;
-					}
-				}
-			},
-			moved: function (x, y) { }
-		})
+		input = new spine.webgl.Input(canvas);		
 		assetManager.loadTexture("spineboy.png");
 		assetManager.loadText("spineboy-mesh.json");
 		assetManager.loadText("spineboy.atlas");
@@ -68,10 +40,45 @@ var ikConstraintDemo = function(pathPrefix, loadingComplete) {
 			renderer.camera.position.x = offset.x + bounds.x / 2;
 			renderer.camera.position.y = offset.y + bounds.y / 2;
 
+			setupInput();
+
 			loadingComplete(canvas, render);
 		} else requestAnimationFrame(load);
 	}
 
+	function setupInput() {
+		input.addListener({
+			down: function(x, y) {			
+				var bone = skeleton.findBone(boneName);				
+				renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);				
+				if (temp.set(skeleton.x + bone.worldX, skeleton.y + bone.worldY, 0).distance(coords) < 20) {
+					target = bone;
+				}				
+			},
+			up: function(x, y) {
+				target = null;
+			},
+			dragged: function(x, y) {
+				if (target != null) {
+					renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);
+					if (target.parent !== null) {
+						target.parent.worldToLocal(temp2.set(coords.x - skeleton.x, coords.y - skeleton.y));
+						target.x = temp2.x;
+						target.y = temp2.y;
+					} else {
+						target.x = coords.x - skeleton.x;
+						target.y = coords.y - skeleton.y;
+					}
+				}
+			},
+			moved: function (x, y) { 
+				var bone = skeleton.findBone(boneName);				
+				renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);				
+				isHover = temp.set(skeleton.x + bone.worldX, skeleton.y + bone.worldY, 0).distance(coords) < 20;					
+			}
+		});
+	}
+
 	function render () {
 		var now = Date.now() / 1000;
 		var delta = now - lastFrameTime;
@@ -90,9 +97,15 @@ var ikConstraintDemo = function(pathPrefix, loadingComplete) {
 		renderer.begin();				
 		renderer.drawSkeleton(skeleton, true);
 		var bone = skeleton.findBone(boneName);
-		renderer.circle(true, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, CIRCLE_INNER_COLOR);
-		renderer.circle(false, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, CIRCLE_OUTER_COLOR);
-		renderer.end();		
+
+		var colorInner = isHover ? spineDemos.HOVER_COLOR_INNER : spineDemos.NON_HOVER_COLOR_INNER;
+		var colorOuter = isHover ? spineDemos.HOVER_COLOR_OUTER : spineDemos.NON_HOVER_COLOR_OUTER;
+
+		renderer.circle(true, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, colorInner);
+		gl.lineWidth(2);
+		renderer.circle(false, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, colorOuter);			
+		renderer.end();
+		gl.lineWidth(1);
 	}
 	init();
 };

+ 2 - 2
spine-ts/webgl/demos/imagesequences.js

@@ -92,7 +92,7 @@ var imageSequencesDemo = function(pathPrefix, loadingComplete) {
 		var anim = skeletonData.findAnimation(animation);		
 		state.setAnimation(0, animation, true);
 		if (name === "alien") {
-			state.update(anim.duration / 2);			
+			state.update(anim.duration / 2.5);			
 		}
 		state.apply(skeleton);
 		skeleton.updateWorldTransform();			
@@ -100,7 +100,7 @@ var imageSequencesDemo = function(pathPrefix, loadingComplete) {
 		var size = new spine.Vector2();
 		skeleton.getBounds(offset, size);
 		if (name === "alien") {
-			state.update(-anim.duration / 2);
+			state.update(-anim.duration / 2.5);
 		}
 
 		var regions = [];

+ 2 - 2
spine-ts/webgl/demos/meshes.html

@@ -16,9 +16,9 @@
 <div style="position: fixed; top: 0; width: 100%">
 	<select id="meshesdemo-active-skeleton"></select></br>
 	<span style="color: #fff">Draw Bones</span>	
-	<input type="checkbox" id="meshesdemo-drawbonescheckbox" style="color: #fff;" checked="true"></input>		
+	<input type="checkbox" id="meshesdemo-drawbonescheckbox" style="color: #fff;"></input>		
 	<span style="color: #fff">Draw Triangles</span>	
-	<input type="checkbox" id="meshesdemo-drawmeshtrianglescheckbox" style="color: #fff;" checked="true"></input>
+	<input type="checkbox" id="meshesdemo-drawmeshtrianglescheckbox" style="color: #fff;"></input>
 	<br>
 	<input id="meshesdemo-playbutton" type="button" value="Pause"></input>
 	<div id="meshesdemo-timeline" class="slider"></input>

+ 4 - 0
spine-ts/webgl/demos/meshes.js

@@ -80,9 +80,13 @@ var meshesDemo = function(pathPrefix, loadingComplete) {
 			timeLine.slider("value", (active.playTime / animationDuration * 100));
 		})
 
+		renderer.skeletonDebugRenderer.drawBones = false;
 		$("#meshesdemo-drawbonescheckbox").click(function() {
 			renderer.skeletonDebugRenderer.drawBones = this.checked;
 		})
+
+		renderer.skeletonDebugRenderer.drawMeshHull = false;
+		renderer.skeletonDebugRenderer.drawMeshTriangles = false;
 		$("#meshesdemo-drawmeshtrianglescheckbox").click(function() {
 			renderer.skeletonDebugRenderer.drawMeshHull = this.checked;
 			renderer.skeletonDebugRenderer.drawMeshTriangles = this.checked;

+ 2 - 3
spine-ts/webgl/demos/skins.html

@@ -15,9 +15,8 @@
 <center>
 <div style="position: fixed; top: 0; width: 100%">
 	<select id="skinsdemo-active-skin"></select></br>
-	<br>	
-	<input id="skinsdemo-playbutton" type="button" value="Pause"></input>
-	<div id="skinsdemo-timeline" class="slider"></input>
+	<button id="skinsdemo-randomizeskin" value="Random Skin">Random Skin</button>						
+	<button id="skinsdemo-randomizeattachments" value="Randomize Attachments">Randomize Attachments</button>	
 </div>
 </center>
 <script src="utils.js"></script>

+ 110 - 54
spine-ts/webgl/demos/skins.js

@@ -13,23 +13,28 @@ var skinsDemo = function(pathPrefix, loadingComplete) {
 
 		renderer = new spine.webgl.SceneRenderer(canvas, gl);		
 		assetManager = new spine.webgl.AssetManager(gl, pathPrefix);		
-		assetManager.loadTexture("goblins.png");
-		assetManager.loadText("goblins-mesh.json");
-		assetManager.loadText("goblins.atlas");
+		assetManager.loadTexture("heroes.png");
+		assetManager.loadText("heroes.json");
+		assetManager.loadText("heroes.atlas");
 		requestAnimationFrame(load);
 	}
 
 	function load () {
 		if (assetManager.isLoadingComplete()) {
-			var atlas = new spine.TextureAtlas(assetManager.get("goblins.atlas"), function(path) {
+			var atlas = new spine.TextureAtlas(assetManager.get("heroes.atlas"), function(path) {
 				return assetManager.get(path);		
 			});
 			var atlasLoader = new spine.TextureAtlasAttachmentLoader(atlas);
 			var skeletonJson = new spine.SkeletonJson(atlasLoader);
-			var skeletonData = skeletonJson.readSkeletonData(assetManager.get("goblins-mesh.json"));
+			var skeletonData = skeletonJson.readSkeletonData(assetManager.get("heroes.json"));
 			skeleton = new spine.Skeleton(skeletonData);
-			state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data));
-			state.setAnimation(0, "walk", true);
+			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();
@@ -40,42 +45,66 @@ var skinsDemo = function(pathPrefix, loadingComplete) {
 		} else requestAnimationFrame(load);
 	}
 
-	function setupUI() {
-		playButton = $("#skinsdemo-playbutton");
-		var playButtonUpdate = function () {			
-			isPlaying = !isPlaying;
-			if (isPlaying) {
-				playButton.val("Pause");
-				playButton.addClass("pause").removeClass("play");		
-			} else {
-				playButton.val("Play");
-				playButton.addClass("play").removeClass("pause");
-			}		
-		}
-		playButton.click(playButtonUpdate);
-
-		timeLine = $("#skinsdemo-timeline");
-		timeLine.slider({ range: "max", min: 0, max: 100, value: 0, slide: function () {
-			if (isPlaying) playButton.click();
-			if (!isPlaying) {				
-				var time = timeLine.slider("value") / 100;
-				var animationDuration = state.getCurrent(0).animation.duration;
-				time = animationDuration * time;				
-				state.update(time - playTime);
-				state.apply(skeleton);
-				skeleton.updateWorldTransform();
-				playTime = time;												
-			}
-		}});
+	function setupAnimations(state) {
+		state.addAnimation(0, "idle", true, 1);
+		state.addAnimation(0, "walk", true, 2);
+		state.addAnimation(0, "run", true, 4);
+		state.addAnimation(0, "roll", false, 3);
+		state.addAnimation(0, "run", true, 0);
+		state.addAnimation(0, "run2", true, 1.5);
+		state.addAnimation(0, "jump", false, 3);
+		state.addAnimation(0, "run2", true, 0);
+		state.addAnimation(0, "run", true, 1);
+		state.addAnimation(0, "idle", true, 3);
+		state.addAnimation(0, "idleTired", true, 0.5);
+		state.addAnimation(0, "idle", true, 2);
+		state.addAnimation(0, "walk2", true, 1);
+		state.addAnimation(0, "block", true, 3);
+		state.addAnimation(0, "punch1", false, 1.5);
+		state.addAnimation(0, "block", true, 0);
+		state.addAnimation(0, "punch1", false, 1.5);
+		state.addAnimation(0, "punch2", false, 0);
+		state.addAnimation(0, "block", true, 0);
+		state.addAnimation(0, "hitBig", false, 1.5);
+		state.addAnimation(0, "floorIdle", true, 0);
+		state.addAnimation(0, "floorGetUp", false, 1.5);
+		state.addAnimation(0, "idle", true, 0);
+		state.addAnimation(0, "meleeSwing1-fullBody", false, 1.5);
+		state.addAnimation(0, "idle", true, 0);
+		state.addAnimation(0, "meleeSwing2-fullBody", false, 1.5);
+		state.addAnimation(0, "idle", true, 0);
+		state.addAnimation(0, "idleTired", true, 0.5);
+		state.addAnimation(0, "crouchIdle", true, 1.5);
+		state.addAnimation(0, "crouchWalk", true, 2);
+		state.addAnimation(0, "crouchIdle", true, 2.5);
+
+		state.addAnimation(1, "meleeSwing1", false, 4);
+
+		state.addAnimation(2, "meleeSwing1", false, 7.5);
 
+		state.addAnimation(3, "meleeSwing2", false, 10.5);
+		state.addAnimation(3, "meleeSwing1", false, 0);
+		state.addAnimation(3, "meleeSwing2", false, 0);
+
+		state.addAnimation(4, "hideSword", false, 19.15).listener = {
+			event: function (trackIndex, event) {},
+			complete: function (trackIndex, loopCount) {},
+			start: function (trackIndex) { 
+				setAnimations(state);
+			},
+			end: function (trackIndex) {}
+		};
+	}
+
+	function setupUI() {
 		var list = $("#skinsdemo-active-skin");	
 		for (var skin in skeleton.data.skins) {
 			skin = skeleton.data.skins[skin];
 			var option = $("<option></option>");
 			option.attr("value", skin.name).text(skin.name);
-			if (skin.name === "goblin") {
+			if (skin.name === "Assassin") {
 				option.attr("selected", "selected");
-				skeleton.setSkinByName("goblin");
+				skeleton.setSkinByName("Assassin");
 			}
 			list.append(option);
 		}
@@ -84,6 +113,42 @@ var skinsDemo = function(pathPrefix, loadingComplete) {
 			skeleton.setSkinByName(activeSkin);
 			skeleton.setSlotsToSetupPose();
 		});
+
+		var randomSkin = $("#skinsdemo-randomizeskin");
+		randomSkin.click(function() {
+			var result;
+			var count = 0;
+			for (var skin in skeleton.data.skins) {
+				if (skeleton.data.skins[skin].name === "default") continue;
+				if (Math.random() < 1/++count) {
+					result = skeleton.data.skins[skin];
+				}
+			}
+			skeleton.setSkin(result);
+			skeleton.setSlotsToSetupPose();
+			$("#skinsdemo-active-skin select").val(result.name);
+		});
+
+		var randomizeAttachments = $("#skinsdemo-randomizeattachments");
+		randomizeAttachments.click(function() {
+			var skins = [];
+			for (var skin in skeleton.data.skins) {
+				skin = skeleton.data.skins[skin];
+				if (skin.name === "default") continue;
+				skins.push(skin);
+			}
+
+			var newSkin = new spine.Skin("random-skin");
+			for (var slot = 0; slot < skeleton.slots.length; slot++) {
+				var skin = skins[(Math.random() * skins.length - 1) | 0];
+				var attachments = skin.attachments[slot];
+				for (var attachmentName in attachments) {
+					newSkin.addAttachment(slot, attachmentName, attachments[attachmentName]);
+				}
+			}
+			skeleton.setSkin(newSkin);
+			skeleton.setSlotsToSetupPose();			
+		});
 	}
 
 	function render () {
@@ -92,35 +157,26 @@ var skinsDemo = function(pathPrefix, loadingComplete) {
 		lastFrameTime = now;
 		if (delta > 0.032) delta = 0.032;
 
-		renderer.camera.position.x = offset.x + bounds.x;
+		renderer.camera.position.x = offset.x + bounds.x * 1.5 - 150;
 		renderer.camera.position.y = offset.y + bounds.y / 2;
-		renderer.camera.viewportWidth = bounds.x * 2.2;
+		renderer.camera.viewportWidth = bounds.x * 3;
 		renderer.camera.viewportHeight = bounds.y * 1.2;
 		renderer.resize(spine.webgl.ResizeMode.Fit);
 
 		gl.clearColor(0.2, 0.2, 0.2, 1);
-		gl.clear(gl.COLOR_BUFFER_BIT);
-		
-		if (isPlaying) {
-			var animationDuration = state.getCurrent(0).animation.duration;
-			playTime += delta;			
-			while (playTime >= animationDuration) {
-				playTime -= animationDuration;
-			}
-			timeLine.slider("value", (playTime / animationDuration * 100));
+		gl.clear(gl.COLOR_BUFFER_BIT);			
 
-			state.update(delta);
-			state.apply(skeleton);
-			skeleton.updateWorldTransform();			
-		}		
+		state.update(delta);
+		state.apply(skeleton);
+		skeleton.updateWorldTransform();		
 
 		renderer.begin();				
 		renderer.drawSkeleton(skeleton, true);
-		var texture = assetManager.get("goblins.png");
-		var width = bounds.x * 1.3;
+		var texture = assetManager.get("heroes.png");
+		var width = bounds.x;
 		var scale = width / texture.getImage().width;
 		var height = scale * texture.getImage().height;
-		renderer.drawTexture(texture, offset.x + bounds.x, offset.y + bounds.y / 2 - height / 2, width, height);		
+		renderer.drawTexture(texture, offset.x + bounds.x + 300, offset.y + bounds.y / 2 - height / 2 - 50, width, height);		
 		renderer.end();		
 	}
 

+ 1 - 3
spine-ts/webgl/demos/spritesheet.html

@@ -15,9 +15,7 @@
 <div style="position: fixed; top: 0; width: 100%">
 	<center>
 	<span style="color: #fff">Time Multiplier</span>
-	<div id="spritesheetdemo-timeslider" class="slider"></div></br>		
-	<input id="spritesheetdemo-playbutton" type="button" value="Pause"></input>
-	<div id="spritesheetdemo-timeline" class="slider"></div>
+	<div id="spritesheetdemo-timeslider" class="slider"></div></br>
 	</center>
 </div>
 <script src="utils.js"></script>

+ 20 - 61
spine-ts/webgl/demos/spritesheet.js

@@ -8,9 +8,8 @@ var spritesheetDemo = function(pathPrefix, loadingComplete) {
 	var skeletonAtlas;	
 	var viewportWidth, viewportHeight;
 	var frames = [], currFrame = 0, frameTime = 0, frameScale = 0, FPS = 30;
-	var lastFrameTime = Date.now() / 1000;
-	var timeSlider, timeSliderLabel;
-	var playButton, timeLine, isPlaying = true, playTime = 0, framePlaytime = 0;
+	var lastFrameTime = Date.now() / 1000;	
+	var playTime = 0, framePlaytime = 0;
 
 	function init () {
 		if (pathPrefix === undefined) pathPrefix = "";		
@@ -58,43 +57,6 @@ var spritesheetDemo = function(pathPrefix, loadingComplete) {
 	}
 
 	function setupUI() {
-		playButton = $("#spritesheetdemo-playbutton");
-		var playButtonUpdate = function () {	
-			isPlaying = !isPlaying;
-			if (isPlaying) {
-				playButton.val("Pause");
-				playButton.addClass("pause").removeClass("play");		
-			} else {
-				playButton.val("Play");
-				playButton.addClass("play").removeClass("pause");
-			}		
-		}
-		playButton.click(playButtonUpdate);
-
-		timeLine = $("#spritesheetdemo-timeline");
-		timeLine.slider({ range: "max", min: 0, max: 100, value: 0, slide: function () {
-			if (isPlaying) playButton.click();		
-			if (!isPlaying) {				
-				var time = timeLine.slider("value") / 100;
-				var animationDuration = animationState.getCurrent(0).animation.duration;
-				time = animationDuration * time;
-				var playDelta = time - playTime;				
-				animationState.update(playDelta);
-				animationState.apply(skeleton);
-				skeleton.updateWorldTransform();
-				playTime = time;
-								
-				walkLastTimePrecise += playDelta;
-				var sign = playDelta < 0 ? -1 : 1;	
-				while (Math.abs(walkLastTimePrecise - walkLastTime) > 1 / FPS) {
-					var newWalkTime = walkLastTime + sign * 1 / FPS;
-					walkAnim.apply(skeletonSeq, walkLastTime, newWalkTime, true, null);
-					walkLastTime = newWalkTime;
-				}
-				skeletonSeq.updateWorldTransform();											
-			}
-		}});		
-
 		timeSlider = $("#spritesheetdemo-timeslider");
 		timeSlider.slider({ range: "max", min: 0, max: 200, value: 50 });
 		timeSliderLabel = $("#spritesheetdemo-timeslider-label");		
@@ -108,30 +70,27 @@ var spritesheetDemo = function(pathPrefix, loadingComplete) {
 
 		delta *= (timeSlider.slider("value") / 100);
 		if (timeSliderLabel) timeSliderLabel.text(timeSlider.slider("value") + "%");	
-		
-		if (isPlaying) {
-			var animationDuration = animationState.getCurrent(0).animation.duration;
-			playTime += delta;			
-			while (playTime >= animationDuration) {
-				playTime -= animationDuration;
-			}
-			timeLine.slider("value", (playTime / animationDuration * 100));
-							
-			animationState.update(delta);
-			animationState.apply(skeleton);
-			skeleton.updateWorldTransform();
-
-			walkLastTimePrecise += delta;				
-			while (walkLastTimePrecise - walkLastTime > 1 / FPS) {
-				var newWalkTime = walkLastTime + 1 / FPS;
-				walkAnim.apply(skeletonSeq, walkLastTime, newWalkTime, true, null);
-				walkLastTime = newWalkTime;
-			}								
-			skeletonSeq.updateWorldTransform();
+				
+		var animationDuration = animationState.getCurrent(0).animation.duration;
+		playTime += delta;			
+		while (playTime >= animationDuration) {
+			playTime -= animationDuration;
 		}			
+						
+		animationState.update(delta);
+		animationState.apply(skeleton);
+		skeleton.updateWorldTransform();
+
+		walkLastTimePrecise += delta;				
+		while (walkLastTimePrecise - walkLastTime > 1 / FPS) {
+			var newWalkTime = walkLastTime + 1 / FPS;
+			walkAnim.apply(skeletonSeq, walkLastTime, newWalkTime, true, null);
+			walkLastTime = newWalkTime;
+		}								
+		skeletonSeq.updateWorldTransform();					
 
 		renderer.camera.position.x = offset.x + viewportWidth / 2 + 100;
-		renderer.camera.position.y = offset.y + viewportHeight / 2;	
+		renderer.camera.position.y = offset.y + viewportHeight / 2  - 160;	
 		renderer.camera.viewportWidth = viewportWidth * 1.2;
 		renderer.camera.viewportHeight = viewportHeight * 1.2;
 		renderer.resize(spine.webgl.ResizeMode.Fit);

+ 1 - 1
spine-ts/webgl/demos/stretchy.html

@@ -16,7 +16,7 @@
 <center>
 <div style="position: fixed; top: 0; width: 100%">
 	<br>
-	<div>Display Bones</div><input id="stretchydemo-drawbones" type="checkbox" checked="true"></input>
+	<div>Display Bones</div><input id="stretchydemo-drawbones" type="checkbox"></input>
 	</br>
 	<input id="stretchydemo-playbutton" type="button" value="Pause"></input>	
 	<div id="stretchydemo-timeline" class="slider"></div>

+ 53 - 34
spine-ts/webgl/demos/stretchy.js

@@ -9,6 +9,7 @@ var stretchyDemo = function(pathPrefix, loadingComplete) {
 	var lastFrameTime = Date.now() / 1000;
 	var target = null;
 	var kneeFront, kneeBack;
+	var hoverTargets = [null, null, null];
 	var controlBones = ["front leg controller", "back leg controller", "hip"];
 	var coords = new spine.webgl.Vector3(), temp = new spine.webgl.Vector3(), temp2 = new spine.Vector2(), temp3 = new spine.webgl.Vector3();
 	var kneePos = new spine.Vector2();
@@ -22,35 +23,7 @@ var stretchyDemo = function(pathPrefix, loadingComplete) {
 
 		renderer = new spine.webgl.SceneRenderer(canvas, gl);
 		assetManager = new spine.webgl.AssetManager(gl, pathPrefix);
-		input = new spine.webgl.Input(canvas);
-		input.addListener({
-			down: function(x, y) {
-				for (var i = 0; i < controlBones.length; i++) {	
-					var bone = skeleton.findBone(controlBones[i]);				
-					renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);				
-					if (temp.set(skeleton.x + bone.worldX, skeleton.y + bone.worldY, 0).distance(coords) < 20) {
-						target = bone;
-					}				
-				}
-			},
-			up: function(x, y) {
-				target = null;
-			},
-			dragged: function(x, y) {
-				if (target != null) {
-					renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);
-					if (target.parent !== null) {
-						target.parent.worldToLocal(temp2.set(coords.x - skeleton.x, coords.y - skeleton.y));
-						target.x = temp2.x;
-						target.y = temp2.y;
-					} else {
-						target.x = coords.x - skeleton.x;
-						target.y = coords.y - skeleton.y;
-					}
-				}
-			},
-			moved: function (x, y) { }
-		})
+		input = new spine.webgl.Input(canvas);		
 		assetManager.loadTexture("stretchyman.png");
 		assetManager.loadText("stretchyman.json");
 		assetManager.loadText("stretchyman.atlas");
@@ -82,6 +55,7 @@ var stretchyDemo = function(pathPrefix, loadingComplete) {
 			renderer.skeletonDebugRenderer.drawMeshTriangles = false;
 
 			setupUI();
+			setupInput();
 
 			loadingComplete(canvas, render);
 		} else requestAnimationFrame(load);
@@ -89,12 +63,55 @@ var stretchyDemo = function(pathPrefix, loadingComplete) {
 
 	function setupUI() {		
 		var checkbox = $("#stretchydemo-drawbones");
+		renderer.skeletonDebugRenderer.drawPaths = false;
+		renderer.skeletonDebugRenderer.drawBones = false;
 		checkbox.change(function() {
 			renderer.skeletonDebugRenderer.drawPaths = this.checked;
 			renderer.skeletonDebugRenderer.drawBones = this.checked;			
 		});
 	}
 
+	function setupInput (){
+		input.addListener({
+			down: function(x, y) {
+				for (var i = 0; i < controlBones.length; i++) {	
+					var bone = skeleton.findBone(controlBones[i]);				
+					renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);				
+					if (temp.set(skeleton.x + bone.worldX, skeleton.y + bone.worldY, 0).distance(coords) < 20) {
+						target = bone;
+					}				
+				}
+			},
+			up: function(x, y) {
+				target = null;
+			},
+			dragged: function(x, y) {
+				if (target != null) {
+					renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);
+					if (target.parent !== null) {
+						target.parent.worldToLocal(temp2.set(coords.x - skeleton.x, coords.y - skeleton.y));
+						target.x = temp2.x;
+						target.y = temp2.y;
+					} else {
+						target.x = coords.x - skeleton.x;
+						target.y = coords.y - skeleton.y;
+					}
+				}
+			},
+			moved: function (x, y) { 
+				for (var i = 0; i < controlBones.length; i++) {	
+					var bone = skeleton.findBone(controlBones[i]);				
+					renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);				
+					if (temp.set(skeleton.x + bone.worldX, skeleton.y + bone.worldY, 0).distance(coords) < 20) {
+						hoverTargets[i] = bone;
+					} else {
+						hoverTargets[i] = null;
+					}
+				}	
+			}
+		});
+	}
+
 	function centerKnee(kneeBone, hipBone, footBone) {
 		temp.set(footBone.worldX + skeleton.x, footBone.worldY + skeleton.y, 0)
 			.sub(temp3.set(hipBone.worldX + skeleton.x, hipBone.worldY + skeleton.y, 0));
@@ -126,14 +143,16 @@ var stretchyDemo = function(pathPrefix, loadingComplete) {
 		renderer.begin();				
 		renderer.drawSkeleton(skeleton, true);
 		renderer.drawSkeletonDebug(skeleton, false, ["root", "front leg middle", "back leg middle"]);
+		gl.lineWidth(2);
 		for (var i = 0; i < controlBones.length; i++) {		
 			var bone = skeleton.findBone(controlBones[i]);
-			var colorInner = bone === target ? COLOR_INNER_SELECTED : COLOR_INNER;
-			var colorOuter = bone === target ? COLOR_OUTER_SELECTED : COLOR_OUTER;
-			renderer.circle(true, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, colorInner);
-			renderer.circle(false, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, colorOuter);
+			var colorInner = hoverTargets[i] !== null ? spineDemos.HOVER_COLOR_INNER : spineDemos.NON_HOVER_COLOR_INNER;
+			var colorOuter = hoverTargets[i] !== null ? spineDemos.HOVER_COLOR_OUTER : spineDemos.NON_HOVER_COLOR_OUTER;
+			renderer.circle(true, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, colorInner);			
+			renderer.circle(false, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, colorOuter);			
 		}
-		renderer.end();				
+		renderer.end();
+		gl.lineWidth(1);
 	}
 
 	init();

+ 2 - 1
spine-ts/webgl/demos/transformconstraint.html

@@ -16,7 +16,8 @@
 <center>
 <div style="position: fixed; top: 0; width: 100%">
 	<div id="info"></div></br>	
-	<div>Rotation Offset</div><div id="transformdemo-rotationoffset" class="slider"></div>		
+	<div>Rotation Offset</div><div id="transformdemo-rotationoffset" class="slider"></div>
+	<div>Translation Mix</div><div id="transformdemo-translationmix" class="slider"></div>		
 </div>
 </center>
 <script src="utils.js"></script>

+ 85 - 31
spine-ts/webgl/demos/transformconstraint.js

@@ -6,12 +6,14 @@ var transformConstraintDemo = function(pathPrefix, loadingComplete) {
 
 	var canvas, gl, renderer, input, assetManager;
 	var skeleton, state, bounds;		
-	var lastFrameTime = Date.now() / 1000;
-	var target = null;	
-	var wheel1;
+	var lastFrameTime = Date.now() / 1000;		
+	var rotateHandle;	
+	var target = null;
+	var hoverTargets = [null, null, null];
+	var controlBones = ["wheel2overlay", "wheel3overlay", "rotate-handle"];	
 	var coords = new spine.webgl.Vector3(), temp = new spine.webgl.Vector3(), temp2 = new spine.Vector2();
 	var lastRotation = 0;
-	var rotationOffset, mix, lastOffset = 0;
+	var rotationOffset, mix, lastOffset = 0, lastMix = 50;
 
 	function init () {
 
@@ -22,26 +24,6 @@ var transformConstraintDemo = function(pathPrefix, loadingComplete) {
 		renderer = new spine.webgl.SceneRenderer(canvas, gl);
 		assetManager = new spine.webgl.AssetManager(gl, pathPrefix);
 		input = new spine.webgl.Input(canvas);
-		var getRotation = function(x, y) {
-			renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);
-			var v = coords.sub(new spine.webgl.Vector3(wheel1.worldX, wheel1.worldY, 0)).normalize();
-			var angle = Math.acos(v.x) * spine.MathUtils.radiansToDegrees;
-			if (v.y < 0) angle = 360 - angle;			
-			return angle;
-		}
-		input.addListener({
-			down: function(x, y) { 
-				lastRotation = getRotation(x, y);
-			},
-			up: function(x, y) { },
-			dragged: function(x, y) {
-				var rotation = getRotation(x, y);
-				var delta = rotation - lastRotation;
-				wheel1.rotation += delta;
-				lastRotation = rotation;
-			 },
-			moved: function (x, y) { }
-		})
 		assetManager.loadTexture("tank.png");
 		assetManager.loadText("transformConstraint.json");
 		assetManager.loadText("tank.atlas");
@@ -65,7 +47,7 @@ var transformConstraintDemo = function(pathPrefix, loadingComplete) {
 			state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data));
 			skeleton.setToSetupPose();			
 			skeleton.updateWorldTransform();
-			wheel1 = skeleton.findBone("wheel1");		
+			rotateHandle = skeleton.findBone("rotate-handle");		
 
 			renderer.camera.position.x = offset.x + bounds.x / 2;
 			renderer.camera.position.y = offset.y + bounds.y / 2;
@@ -73,8 +55,9 @@ var transformConstraintDemo = function(pathPrefix, loadingComplete) {
 			renderer.skeletonDebugRenderer.drawRegionAttachments = false;
 			renderer.skeletonDebugRenderer.drawMeshHull = false;
 			renderer.skeletonDebugRenderer.drawMeshTriangles = false;
-
+			
 			setupUI();
+			setupInput();
 
 			loadingComplete(canvas, render);
 		} else requestAnimationFrame(load);
@@ -89,9 +72,75 @@ var transformConstraintDemo = function(pathPrefix, loadingComplete) {
 			skeleton.findTransformConstraint("wheel2").data.offsetRotation += delta;			
 			skeleton.findTransformConstraint("wheel3").data.offsetRotation += delta;
 			$("#transformdemo-rotationoffset-label").text(val + "°");
+		}});
+
+		translationMix = $("#transformdemo-translationmix");
+		translationMix.slider({ range: "max", min: 0, max: 100, value: 50, slide: function () {
+			var val = translationMix.slider("value");
+			var delta = val - lastMix;
+			lastMix = val;
+			skeleton.findTransformConstraint("wheel1").translateMix += delta / 100;			
+			$("#transformdemo-translationmix-label").text(val + "%");
 		}});	
 	}
 
+	function setupInput() {
+		var getRotation = function(x, y) {
+			renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);
+			var wheel1 = skeleton.findBone("wheel1overlay");
+			var v = coords.sub(new spine.webgl.Vector3(wheel1.worldX, wheel1.worldY, 0)).normalize();
+			var angle = Math.acos(v.x) * spine.MathUtils.radiansToDegrees;
+			if (v.y < 0) angle = 360 - angle;			
+			return angle;
+		}
+		input.addListener({
+			down: function(x, y) { 
+				renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);
+				for (var i = 0; i < controlBones.length; i++) {	
+					var bone = skeleton.findBone(controlBones[i]);													
+					if (temp.set(skeleton.x + bone.worldX, skeleton.y + bone.worldY, 0).distance(coords) < 20) {
+						target = bone;
+						if (target === rotateHandle) lastRotation = getRotation(x, y);
+					}				
+				}				
+			},
+			up: function(x, y) { 
+				target = null;
+			},
+			dragged: function(x, y) {
+				if (target != null) {
+					if (target === rotateHandle) {
+						var rotation = getRotation(x, y);
+						var delta = rotation - lastRotation;
+						skeleton.findBone("wheel1").rotation += delta;
+						lastRotation = rotation;
+					} else {
+						renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);
+						if (target.parent !== null) {
+							target.parent.worldToLocal(temp2.set(coords.x - skeleton.x, coords.y - skeleton.y));
+							target.x = temp2.x;
+							target.y = temp2.y;
+						} else {
+							target.x = coords.x - skeleton.x;
+							target.y = coords.y - skeleton.y;
+						}
+					}
+				}
+			 },
+			moved: function (x, y) { 
+				renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);
+				for (var i = 0; i < controlBones.length; i++) {
+					var bone = skeleton.findBone(controlBones[i]);													
+					if (temp.set(skeleton.x + bone.worldX, skeleton.y + bone.worldY, 0).distance(coords) < 20) {
+						hoverTargets[i] = bone;
+					} else {
+						hoverTargets[i] = null;
+					}
+				}
+			}
+		})
+	}
+
 	function render () {
 		var now = Date.now() / 1000;
 		var delta = now - lastFrameTime;
@@ -109,11 +158,16 @@ var transformConstraintDemo = function(pathPrefix, loadingComplete) {
 
 		renderer.begin();				
 		renderer.drawSkeleton(skeleton, true);
-		renderer.drawSkeletonDebug(skeleton, false, ["root"]);				
-		var bone = wheel1;
-		var colorInner = bone === target ? COLOR_INNER_SELECTED : COLOR_INNER;
-		var colorOuter = bone === target ? COLOR_OUTER_SELECTED : COLOR_OUTER;		
-		renderer.circle(false, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, colorOuter);		
+		renderer.drawSkeletonDebug(skeleton, false, ["root", "rotate-handle"]);
+		gl.lineWidth(2);
+		for (var i = 0; i < controlBones.length; i++) {		
+			var bone = skeleton.findBone(controlBones[i]);
+			var colorInner = hoverTargets[i] !== null ? spineDemos.HOVER_COLOR_INNER : spineDemos.NON_HOVER_COLOR_INNER;
+			var colorOuter = hoverTargets[i] !== null ? spineDemos.HOVER_COLOR_OUTER : spineDemos.NON_HOVER_COLOR_OUTER;
+			renderer.circle(true, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, colorInner);			
+			renderer.circle(false, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, colorOuter);			
+		}
+		gl.lineWidth(1);
 		renderer.end();		
 	}
 

+ 5 - 0
spine-ts/webgl/demos/utils.js

@@ -1,5 +1,10 @@
 var spineDemos;
 (function(spineDemos) {
+	spineDemos.HOVER_COLOR_INNER = new spine.Color(0.478, 0, 0, 0.25);
+	spineDemos.HOVER_COLOR_OUTER = new spine.Color(1, 1, 1, 1);
+	spineDemos.NON_HOVER_COLOR_INNER = new spine.Color(0.478, 0, 0, 0.5);
+	spineDemos.NON_HOVER_COLOR_OUTER = new spine.Color(1, 0, 0, 0.8);
+
 	spineDemos.setupRendering = function (canvas, renderFunc) {
 		var isVisible = false;
 

+ 2 - 5
spine-ts/webgl/demos/vine.html

@@ -14,11 +14,8 @@
 <body>
 <canvas id="vinedemo-canvas"></canvas>
 <center>
-<div style="position: fixed; top: 0; width: 100%">
-	<div id="info"></div></br>	
-	<div>Spacing</div><div id="vinedemo-spacing" class="slider"></div>
-	<br>
-	<div>Display Bones & Path</div><input id="vinedemo-drawbones" type="checkbox" checked="true"></input>
+<div style="position: fixed; top: 0; width: 100%">	
+	<div>Display Bones & Path</div><input id="vinedemo-drawbones" type="checkbox"></input>
 	</br>
 	<input id="vinedemo-playbutton" type="button" value="Pause"></input>	
 	<div id="vinedemo-timeline" class="slider"></div>

+ 53 - 40
spine-ts/webgl/demos/vine.js

@@ -7,10 +7,11 @@ var vineDemo = function(pathPrefix, loadingComplete) {
 	var canvas, gl, renderer, input, assetManager;
 	var skeleton, state, bounds;		
 	var lastFrameTime = Date.now() / 1000;
-	var target = null;	
+	var target = null;
+	var hoverTargets = [null, null, null, null, null];
 	var controlBones = ["vine-control1", "vine-control2", "vine-control3", "vine-control4"];
 	var coords = new spine.webgl.Vector3(), temp = new spine.webgl.Vector3(), temp2 = new spine.Vector2();
-	var playButton, timeLine, spacing, isPlaying = true, playTime = 0;		
+	var playButton, timeLine, isPlaying = true, playTime = 0;		
 
 	function init () {
 
@@ -21,34 +22,6 @@ var vineDemo = function(pathPrefix, loadingComplete) {
 		renderer = new spine.webgl.SceneRenderer(canvas, gl);
 		assetManager = new spine.webgl.AssetManager(gl, pathPrefix);
 		input = new spine.webgl.Input(canvas);
-		input.addListener({
-			down: function(x, y) {
-				for (var i = 0; i < controlBones.length; i++) {	
-					var bone = skeleton.findBone(controlBones[i]);				
-					renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);				
-					if (temp.set(skeleton.x + bone.worldX, skeleton.y + bone.worldY, 0).distance(coords) < 20) {
-						target = bone;
-					}				
-				}
-			},
-			up: function(x, y) {
-				target = null;
-			},
-			dragged: function(x, y) {
-				if (target != null) {
-					renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);
-					if (target.parent !== null) {
-						target.parent.worldToLocal(temp2.set(coords.x - skeleton.x, coords.y - skeleton.y));
-						target.x = temp2.x;
-						target.y = temp2.y;
-					} else {
-						target.x = coords.x - skeleton.x;
-						target.y = coords.y - skeleton.y;
-					}
-				}
-			},
-			moved: function (x, y) { }
-		})
 		assetManager.loadTexture("vine.png");
 		assetManager.loadText("vine.json");
 		assetManager.loadText("vine.atlas");
@@ -81,6 +54,7 @@ var vineDemo = function(pathPrefix, loadingComplete) {
 			renderer.skeletonDebugRenderer.drawMeshTriangles = false;
 
 			setupUI();
+			setupInput();
 
 			loadingComplete(canvas, render);
 		} else requestAnimationFrame(load);
@@ -114,12 +88,8 @@ var vineDemo = function(pathPrefix, loadingComplete) {
 			}
 		}});
 
-		spacing = $("#vinedemo-spacing");
-		spacing.slider({ range: "max", min: -100, max: 100, value: 0, slide: function () {
-			skeleton.findPathConstraint("vine-path").spacing = spacing.slider("value");
-			$("#vinedemo-spacing-label").text(skeleton.findPathConstraint("vine-path").spacing + "%");
-		}});
-
+		renderer.skeletonDebugRenderer.drawPaths = false;
+		renderer.skeletonDebugRenderer.drawBones = false;
 		var checkbox = $("#vinedemo-drawbones");
 		checkbox.change(function() {
 			renderer.skeletonDebugRenderer.drawPaths = this.checked;
@@ -127,6 +97,47 @@ var vineDemo = function(pathPrefix, loadingComplete) {
 		});
 	}
 
+	function setupInput() {
+		input.addListener({
+			down: function(x, y) {
+				for (var i = 0; i < controlBones.length; i++) {	
+					var bone = skeleton.findBone(controlBones[i]);				
+					renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);				
+					if (temp.set(skeleton.x + bone.worldX, skeleton.y + bone.worldY, 0).distance(coords) < 20) {
+						target = bone;
+					}				
+				}
+			},
+			up: function(x, y) {
+				target = null;
+			},
+			dragged: function(x, y) {
+				if (target != null) {
+					renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);
+					if (target.parent !== null) {
+						target.parent.worldToLocal(temp2.set(coords.x - skeleton.x, coords.y - skeleton.y));
+						target.x = temp2.x;
+						target.y = temp2.y;
+					} else {
+						target.x = coords.x - skeleton.x;
+						target.y = coords.y - skeleton.y;
+					}
+				}
+			},
+			moved: function (x, y) {
+				for (var i = 0; i < controlBones.length; i++) {	
+					var bone = skeleton.findBone(controlBones[i]);				
+					renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);				
+					if (temp.set(skeleton.x + bone.worldX, skeleton.y + bone.worldY, 0).distance(coords) < 20) {
+						hoverTargets[i] = bone;
+					} else {
+						hoverTargets[i] = null;
+					}
+				}				
+			}
+		});
+	}
+
 	function render () {
 		var now = Date.now() / 1000;
 		var delta = now - lastFrameTime;
@@ -157,13 +168,15 @@ var vineDemo = function(pathPrefix, loadingComplete) {
 		renderer.begin();				
 		renderer.drawSkeleton(skeleton, true);
 		renderer.drawSkeletonDebug(skeleton);
+		gl.lineWidth(2);
 		for (var i = 0; i < controlBones.length; i++) {		
 			var bone = skeleton.findBone(controlBones[i]);
-			var colorInner = bone === target ? COLOR_INNER_SELECTED : COLOR_INNER;
-			var colorOuter = bone === target ? COLOR_OUTER_SELECTED : COLOR_OUTER;
-			renderer.circle(true, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, colorInner);
-			renderer.circle(false, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, colorOuter);
+			var colorInner = hoverTargets[i] !== null ? spineDemos.HOVER_COLOR_INNER : spineDemos.NON_HOVER_COLOR_INNER;
+			var colorOuter = hoverTargets[i] !== null ? spineDemos.HOVER_COLOR_OUTER : spineDemos.NON_HOVER_COLOR_OUTER;
+			renderer.circle(true, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, colorInner);			
+			renderer.circle(false, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, colorOuter);			
 		}
+		gl.lineWidth(1);
 		renderer.end();				
 	}