瀏覽代碼

Meshes, FFD and skinning for spine-starling.

NathanSweet 11 年之前
父節點
當前提交
6b9d514ca7

+ 1 - 1
spine-as3/spine-as3/src/spine/Skeleton.as

@@ -41,7 +41,7 @@ public class Skeleton {
 	public var g:Number = 1;
 	public var b:Number = 1;
 	public var a:Number = 1;
-	public var time:Number;
+	public var time:Number = 0;
 	public var flipX:Boolean;
 	public var flipY:Boolean;
 	public var x:Number = 0;

+ 3 - 3
spine-as3/spine-as3/src/spine/attachments/MeshAttachment.as

@@ -96,9 +96,9 @@ public dynamic class MeshAttachment extends Attachment {
 		if (slot.attachmentVertices.length == verticesCount) vertices = slot.attachmentVertices;
 		for (var i:int = 0, ii:int = 0; i < verticesCount; i += 2, ii += 2) {
 			var vx:Number = vertices[i];
-			var vy:Number = vertices[ii];
-			worldVertices[i] = vx * m00 + vy * m01 + x;
-			worldVertices[ii] = vx * m10 + vy * m11 + y;
+			var vy:Number = vertices[int(i + 1)];
+			worldVertices[ii] = vx * m00 + vy * m01 + x;
+			worldVertices[int(ii + 1)] = vx * m10 + vy * m11 + y;
 		}
 	}
 }

+ 103 - 103
spine-starling/spine-starling-example/html-template/index.template.html

@@ -1,109 +1,109 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <!-- saved from url=(0014)about:internet -->
 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> 
-    <!-- 
-    Smart developers always View Source. 
-    
-    This application was built using Adobe Flex, an open source framework
-    for building rich Internet applications that get delivered via the
-    Flash Player or to desktops via Adobe AIR. 
-    
-    Learn more about Flex at http://flex.org 
-    // -->
-    <head>
-        <title>${title}</title>
-        <meta name="google" value="notranslate" />         
-        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-        <!-- Include CSS to eliminate any default margins/padding and set the height of the html element and 
-             the body element to 100%, because Firefox, or any Gecko based browser, interprets percentage as 
-             the percentage of the height of its parent container, which has to be set explicitly.  Fix for
-             Firefox 3.6 focus border issues.  Initially, don't display flashContent div so it won't show 
-             if JavaScript disabled.
-        -->
-        <style type="text/css" media="screen"> 
-            html, body  { height:100%; }
-            body { margin:0; padding:0; overflow:auto; text-align:center; 
-                   background-color: ${bgcolor}; }   
-            object:focus { outline:none; }
-            #flashContent { display:none; }
-        </style>
-        
-        <!-- Enable Browser History by replacing useBrowserHistory tokens with two hyphens -->
-        <!-- BEGIN Browser History required section ${useBrowserHistory}>
-        <link rel="stylesheet" type="text/css" href="history/history.css" />
-        <script type="text/javascript" src="history/history.js"></script>
-        <!${useBrowserHistory} END Browser History required section -->  
-            
-        <script type="text/javascript" src="swfobject.js"></script>
-        <script type="text/javascript">
-            // For version detection, set to min. required Flash Player version, or 0 (or 0.0.0), for no version detection. 
-            var swfVersionStr = "${version_major}.${version_minor}.${version_revision}";
-            // To use express install, set to playerProductInstall.swf, otherwise the empty string. 
-            var xiSwfUrlStr = "${expressInstallSwf}";
-            var flashvars = {};
-            var params = {};
-            params.quality = "high";
-            params.bgcolor = "${bgcolor}";
-            params.allowscriptaccess = "sameDomain";
-            params.allowfullscreen = "true";
+	<!-- 
+	Smart developers always View Source. 
+	
+	This application was built using Adobe Flex, an open source framework
+	for building rich Internet applications that get delivered via the
+	Flash Player or to desktops via Adobe AIR. 
+	
+	Learn more about Flex at http://flex.org 
+	// -->
+	<head>
+		<title>${title}</title>
+		<meta name="google" value="notranslate" />		 
+		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+		<!-- Include CSS to eliminate any default margins/padding and set the height of the html element and 
+			 the body element to 100%, because Firefox, or any Gecko based browser, interprets percentage as 
+			 the percentage of the height of its parent container, which has to be set explicitly.  Fix for
+			 Firefox 3.6 focus border issues.  Initially, don't display flashContent div so it won't show 
+			 if JavaScript disabled.
+		-->
+		<style type="text/css" media="screen"> 
+			html, body  { height:100%; }
+			body { margin:0; padding:0; overflow:auto; text-align:center; 
+				   background-color: ${bgcolor}; }   
+			object:focus { outline:none; }
+			#flashContent { display:none; }
+		</style>
+		
+		<!-- Enable Browser History by replacing useBrowserHistory tokens with two hyphens -->
+		<!-- BEGIN Browser History required section ${useBrowserHistory}>
+		<link rel="stylesheet" type="text/css" href="history/history.css" />
+		<script type="text/javascript" src="history/history.js"></script>
+		<!${useBrowserHistory} END Browser History required section -->  
+			
+		<script type="text/javascript" src="swfobject.js"></script>
+		<script type="text/javascript">
+			// For version detection, set to min. required Flash Player version, or 0 (or 0.0.0), for no version detection. 
+			var swfVersionStr = "${version_major}.${version_minor}.${version_revision}";
+			// To use express install, set to playerProductInstall.swf, otherwise the empty string. 
+			var xiSwfUrlStr = "${expressInstallSwf}";
+			var flashvars = {};
+			var params = {};
+			params.quality = "high";
+			params.bgcolor = "${bgcolor}";
+			params.allowscriptaccess = "sameDomain";
+			params.allowfullscreen = "true";
 			params.wmode = "direct";
-            var attributes = {};
-            attributes.id = "${application}";
-            attributes.name = "${application}";
-            attributes.align = "middle";
-            swfobject.embedSWF(
-                "${swf}.swf", "flashContent", 
-                "${width}", "${height}", 
-                swfVersionStr, xiSwfUrlStr, 
-                flashvars, params, attributes);
-            // JavaScript enabled so display the flashContent div in case it is not replaced with a swf object.
-            swfobject.createCSS("#flashContent", "display:block;text-align:left;");
-        </script>
-    </head>
-    <body>
-        <!-- SWFObject's dynamic embed method replaces this alternative HTML content with Flash content when enough 
-             JavaScript and Flash plug-in support is available. The div is initially hidden so that it doesn't show
-             when JavaScript is disabled.
-        -->
-        <div id="flashContent">
-            <p>
-                To view this page ensure that Adobe Flash Player version 
-                ${version_major}.${version_minor}.${version_revision} or greater is installed. 
-            </p>
-            <script type="text/javascript"> 
-                var pageHost = ((document.location.protocol == "https:") ? "https://" : "http://"); 
-                document.write("<a href='http://www.adobe.com/go/getflashplayer'><img src='" 
-                                + pageHost + "www.adobe.com/images/shared/download_buttons/get_flash_player.gif' alt='Get Adobe Flash player' /></a>" ); 
-            </script> 
-        </div>
-        
-        <noscript>
-            <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="${width}" height="${height}" id="${application}">
-                <param name="movie" value="${swf}.swf" />
-                <param name="quality" value="high" />
-                <param name="bgcolor" value="${bgcolor}" />
-                <param name="allowScriptAccess" value="sameDomain" />
-                <param name="allowFullScreen" value="true" />
-                <!--[if !IE]>-->
-                <object type="application/x-shockwave-flash" data="${swf}.swf" width="${width}" height="${height}">
-                    <param name="quality" value="high" />
-                    <param name="bgcolor" value="${bgcolor}" />
-                    <param name="allowScriptAccess" value="sameDomain" />
-                    <param name="allowFullScreen" value="true" />
-                <!--<![endif]-->
-                <!--[if gte IE 6]>-->
-                    <p> 
-                        Either scripts and active content are not permitted to run or Adobe Flash Player version
-                        ${version_major}.${version_minor}.${version_revision} or greater is not installed.
-                    </p>
-                <!--<![endif]-->
-                    <a href="http://www.adobe.com/go/getflashplayer">
-                        <img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash Player" />
-                    </a>
-                <!--[if !IE]>-->
-                </object>
-                <!--<![endif]-->
-            </object>
-        </noscript>     
+			var attributes = {};
+			attributes.id = "${application}";
+			attributes.name = "${application}";
+			attributes.align = "middle";
+			swfobject.embedSWF(
+				"${swf}.swf", "flashContent", 
+				"${width}", "${height}", 
+				swfVersionStr, xiSwfUrlStr, 
+				flashvars, params, attributes);
+			// JavaScript enabled so display the flashContent div in case it is not replaced with a swf object.
+			swfobject.createCSS("#flashContent", "display:block;text-align:left;");
+		</script>
+	</head>
+	<body>
+		<!-- SWFObject's dynamic embed method replaces this alternative HTML content with Flash content when enough 
+			 JavaScript and Flash plug-in support is available. The div is initially hidden so that it doesn't show
+			 when JavaScript is disabled.
+		-->
+		<div id="flashContent">
+			<p>
+				To view this page ensure that Adobe Flash Player version 
+				${version_major}.${version_minor}.${version_revision} or greater is installed. 
+			</p>
+			<script type="text/javascript"> 
+				var pageHost = ((document.location.protocol == "https:") ? "https://" : "http://"); 
+				document.write("<a href='http://www.adobe.com/go/getflashplayer'><img src='" 
+								+ pageHost + "www.adobe.com/images/shared/download_buttons/get_flash_player.gif' alt='Get Adobe Flash player' /></a>" ); 
+			</script> 
+		</div>
+		
+		<noscript>
+			<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="${width}" height="${height}" id="${application}">
+				<param name="movie" value="${swf}.swf" />
+				<param name="quality" value="high" />
+				<param name="bgcolor" value="${bgcolor}" />
+				<param name="allowScriptAccess" value="sameDomain" />
+				<param name="allowFullScreen" value="true" />
+				<!--[if !IE]>-->
+				<object type="application/x-shockwave-flash" data="${swf}.swf" width="${width}" height="${height}">
+					<param name="quality" value="high" />
+					<param name="bgcolor" value="${bgcolor}" />
+					<param name="allowScriptAccess" value="sameDomain" />
+					<param name="allowFullScreen" value="true" />
+				<!--<![endif]-->
+				<!--[if gte IE 6]>-->
+					<p> 
+						Either scripts and active content are not permitted to run or Adobe Flash Player version
+						${version_major}.${version_minor}.${version_revision} or greater is not installed.
+					</p>
+				<!--<![endif]-->
+					<a href="http://www.adobe.com/go/getflashplayer">
+						<img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash Player" />
+					</a>
+				<!--[if !IE]>-->
+				</object>
+				<!--<![endif]-->
+			</object>
+		</noscript>	 
    </body>
 </html>

+ 9 - 9
spine-starling/spine-starling-example/src/AtlasExample.as

@@ -1,14 +1,15 @@
 package {
 
+import flash.display.Bitmap;
+
 import spine.Event;
 import spine.SkeletonData;
 import spine.SkeletonJson;
 import spine.animation.AnimationStateData;
 import spine.atlas.Atlas;
 import spine.attachments.AtlasAttachmentLoader;
-import spine.starling.StarlingTextureLoader;
 import spine.starling.SkeletonAnimation;
-import spine.starling.StarlingAtlasAttachmentLoader;
+import spine.starling.StarlingTextureLoader;
 
 import starling.core.Starling;
 import starling.display.Sprite;
@@ -16,7 +17,6 @@ import starling.events.Touch;
 import starling.events.TouchEvent;
 import starling.events.TouchPhase;
 import starling.textures.Texture;
-import starling.textures.TextureAtlas;
 
 public class AtlasExample extends Sprite {
 	[Embed(source = "spineboy.atlas", mimeType = "application/octet-stream")]
@@ -33,14 +33,14 @@ public class AtlasExample extends Sprite {
 	public function AtlasExample () {
 		var atlas:Atlas = new Atlas(new SpineboyAtlasFile(), new StarlingTextureLoader(new SpineboyAtlasTexture()));
 		var json:SkeletonJson = new SkeletonJson(new AtlasAttachmentLoader(atlas));
+		json.scale = 0.6;
 		var skeletonData:SkeletonData = json.readSkeletonData(new SpineboyJson());
 
 		var stateData:AnimationStateData = new AnimationStateData(skeletonData);
-		stateData.setMixByName("walk", "jump", 0.2);
-		stateData.setMixByName("jump", "walk", 0.4);
-		stateData.setMixByName("jump", "jump", 0.2);
+		stateData.defaultMix = 0.2;
+		stateData.setMixByName("jump", "run", 0.3);
 
-		skeleton = new SkeletonAnimation(skeletonData, stateData);
+		skeleton = new SkeletonAnimation(skeletonData, false, stateData);
 		skeleton.x = 320;
 		skeleton.y = 420;
 		
@@ -60,7 +60,7 @@ public class AtlasExample extends Sprite {
 
 		skeleton.state.setAnimationByName(0, "walk", true);
 		skeleton.state.addAnimationByName(0, "jump", false, 3);
-		skeleton.state.addAnimationByName(0, "walk", true, 0);
+		skeleton.state.addAnimationByName(0, "run", true, 0);
 
 		addChild(skeleton);
 		Starling.juggler.add(skeleton);
@@ -72,7 +72,7 @@ public class AtlasExample extends Sprite {
 		var touch:Touch = event.getTouch(this);
 		if (touch && touch.phase == TouchPhase.BEGAN) {
 			skeleton.state.setAnimationByName(0, "jump", false);
-			skeleton.state.addAnimationByName(0, "walk", true, 0);
+			skeleton.state.addAnimationByName(0, "run", true, 0);
 		}
 	}
 }

+ 4 - 4
spine-starling/spine-starling-example/src/GoblinsExample.as

@@ -19,13 +19,13 @@ import starling.textures.Texture;
 import starling.textures.TextureAtlas;
 
 public class GoblinsExample extends Sprite {
-	[Embed(source = "goblins.atlas", mimeType = "application/octet-stream")]
+	[Embed(source = "goblins-ffd.atlas", mimeType = "application/octet-stream")]
 	static public const SpineboyAtlasFile:Class;
 
-	[Embed(source = "goblins.png")]
+	[Embed(source = "goblins-ffd.png")]
 	static public const SpineboyAtlasTexture:Class;
 
-	[Embed(source = "goblins.json", mimeType = "application/octet-stream")]
+	[Embed(source = "goblins-ffd.json", mimeType = "application/octet-stream")]
 	static public const SpineboyJson:Class;
 
 	private var skeleton:SkeletonAnimation;
@@ -35,7 +35,7 @@ public class GoblinsExample extends Sprite {
 		var json:SkeletonJson = new SkeletonJson(new AtlasAttachmentLoader(atlas));
 		var skeletonData:SkeletonData = json.readSkeletonData(new SpineboyJson());
 
-		skeleton = new SkeletonAnimation(skeletonData);
+		skeleton = new SkeletonAnimation(skeletonData, true);
 		skeleton.x = 320;
 		skeleton.y = 420;
 		skeleton.skeleton.skinName = "goblin";

+ 8 - 1
spine-starling/spine-starling-example/src/Main.as

@@ -2,6 +2,7 @@
 package {
 
 import flash.display.Sprite;
+
 import starling.core.Starling;
 
 [SWF(width = "640", height = "480", frameRate = "60", backgroundColor = "#dddddd")]
@@ -9,7 +10,13 @@ public class Main extends Sprite {
 	private var _starling:Starling;
 
 	public function Main () {
-		_starling = new Starling(AtlasExample, stage);
+		var example:Class;
+		//example = AtlasExample;
+		//example = StarlingAtlasExample;
+		example = GoblinsExample;
+
+		_starling = new Starling(example, stage);
+		_starling.showStats = true;
 		_starling.start();
 	}
 }

+ 11 - 11
spine-starling/spine-starling-example/src/StarlingAtlasExample.as

@@ -22,7 +22,7 @@ public class StarlingAtlasExample extends Sprite {
 	[Embed(source = "spineboy-starling.png")]
 	static public const SpineboyAtlasTexture:Class;
 
-	[Embed(source = "spineboy.json", mimeType = "application/octet-stream")]
+	[Embed(source = "spineboy-starling.json", mimeType = "application/octet-stream")]
 	static public const SpineboyJson:Class;
 
 	private var skeleton:SkeletonAnimation;
@@ -40,24 +40,24 @@ public class StarlingAtlasExample extends Sprite {
 		stateData.setMixByName("jump", "walk", 0.4);
 		stateData.setMixByName("jump", "jump", 0.2);
 
-		skeleton = new SkeletonAnimation(skeletonData, stateData);
+		skeleton = new SkeletonAnimation(skeletonData, false, stateData);
 		skeleton.x = 320;
 		skeleton.y = 420;
 		
-		skeleton.state.onStart = function (trackIndex:int) : void {
+		skeleton.state.onStart.add(function (trackIndex:int) : void {
 			trace(trackIndex + " start: " + skeleton.state.getCurrent(trackIndex));
-		};
-		skeleton.state.onEnd = function (trackIndex:int) : void {
+		});
+		skeleton.state.onEnd.add(function (trackIndex:int) : void {
 			trace(trackIndex + " end: " + skeleton.state.getCurrent(trackIndex));
-		};
-		skeleton.state.onComplete = function (trackIndex:int, count:int) : void {
+		});
+		skeleton.state.onComplete.add(function (trackIndex:int, count:int) : void {
 			trace(trackIndex + " complete: " + skeleton.state.getCurrent(trackIndex) + ", " + count);
-		};
-		skeleton.state.onEvent = function (trackIndex:int, event:Event) : void {
+		});
+		skeleton.state.onEvent.add(function (trackIndex:int, event:Event) : void {
 			trace(trackIndex + " event: " + skeleton.state.getCurrent(trackIndex) + ", "
 				+ event.data.name + ": " + event.intValue + ", " + event.floatValue + ", " + event.stringValue);
-		};
-		
+		});
+
 		skeleton.state.setAnimationByName(0, "walk", true);
 		skeleton.state.addAnimationByName(0, "jump", false, 3);
 		skeleton.state.addAnimationByName(0, "walk", true, 0);

+ 57 - 57
spine-starling/spine-starling-example/src/goblins-ffd.atlas

@@ -4,288 +4,288 @@ format: RGBA8888
 filter: Linear,Linear
 repeat: none
 dagger
-  rotate: false
-  xy: 2, 28
+  rotate: true
+  xy: 372, 100
   size: 26, 108
   orig: 26, 108
   offset: 0, 0
   index: -1
 goblin/eyes-closed
   rotate: false
-  xy: 137, 29
+  xy: 2, 7
   size: 34, 12
   orig: 34, 12
   offset: 0, 0
   index: -1
 goblin/head
   rotate: false
-  xy: 26, 357
+  xy: 107, 36
   size: 103, 66
   orig: 103, 66
   offset: 0, 0
   index: -1
 goblin/left-arm
   rotate: false
-  xy: 30, 28
+  xy: 901, 56
   size: 37, 35
   orig: 37, 35
   offset: 0, 0
   index: -1
 goblin/left-foot
   rotate: false
-  xy: 134, 260
+  xy: 929, 95
   size: 65, 31
   orig: 65, 31
   offset: 0, 0
   index: -1
 goblin/left-hand
   rotate: false
-  xy: 69, 25
+  xy: 452, 2
   size: 36, 41
   orig: 36, 41
   offset: 0, 0
   index: -1
 goblin/left-lower-leg
-  rotate: false
-  xy: 134, 293
+  rotate: true
+  xy: 713, 93
   size: 33, 70
   orig: 33, 70
   offset: 0, 0
   index: -1
 goblin/left-shoulder
   rotate: false
-  xy: 137, 43
+  xy: 610, 44
   size: 29, 44
   orig: 29, 44
   offset: 0, 0
   index: -1
 goblin/left-upper-leg
-  rotate: false
-  xy: 30, 65
+  rotate: true
+  xy: 638, 93
   size: 33, 73
   orig: 33, 73
   offset: 0, 0
   index: -1
 goblin/neck
   rotate: false
-  xy: 201, 387
+  xy: 490, 2
   size: 36, 41
   orig: 36, 41
   offset: 0, 0
   index: -1
 goblin/pelvis
   rotate: false
-  xy: 26, 140
+  xy: 482, 45
   size: 62, 43
   orig: 62, 43
   offset: 0, 0
   index: -1
 goblin/right-arm
-  rotate: false
-  xy: 171, 84
+  rotate: true
+  xy: 690, 2
   size: 23, 50
   orig: 23, 50
   offset: 0, 0
   index: -1
 goblin/right-foot
   rotate: false
-  xy: 134, 225
+  xy: 771, 58
   size: 63, 33
   orig: 63, 33
   offset: 0, 0
   index: -1
 goblin/right-hand
   rotate: false
-  xy: 204, 258
+  xy: 940, 56
   size: 36, 37
   orig: 36, 37
   offset: 0, 0
   index: -1
 goblin/right-lower-leg
-  rotate: false
-  xy: 201, 430
+  rotate: true
+  xy: 482, 90
   size: 36, 76
   orig: 36, 76
   offset: 0, 0
   index: -1
 goblin/right-shoulder
-  rotate: false
-  xy: 130, 89
+  rotate: true
+  xy: 602, 3
   size: 39, 45
   orig: 39, 45
   offset: 0, 0
   index: -1
 goblin/right-upper-leg
-  rotate: false
-  xy: 98, 214
+  rotate: true
+  xy: 641, 57
   size: 34, 63
   orig: 34, 63
   offset: 0, 0
   index: -1
 goblin/torso
-  rotate: false
-  xy: 131, 410
+  rotate: true
+  xy: 212, 34
   size: 68, 96
   orig: 68, 96
   offset: 0, 0
   index: -1
 goblin/undie-straps
   rotate: false
-  xy: 2, 7
+  xy: 380, 5
   size: 55, 19
   orig: 55, 19
   offset: 0, 0
   index: -1
 goblin/undies
   rotate: false
-  xy: 199, 227
+  xy: 174, 5
   size: 36, 29
   orig: 36, 29
   offset: 0, 0
   index: -1
 goblingirl/eyes-closed
   rotate: false
-  xy: 59, 2
+  xy: 269, 11
   size: 37, 21
   orig: 37, 21
   offset: 0, 0
   index: -1
 goblingirl/head
   rotate: false
-  xy: 26, 425
+  xy: 2, 21
   size: 103, 81
   orig: 103, 81
   offset: 0, 0
   index: -1
 goblingirl/left-arm
-  rotate: false
-  xy: 201, 190
+  rotate: true
+  xy: 978, 56
   size: 37, 35
   orig: 37, 35
   offset: 0, 0
   index: -1
 goblingirl/left-foot
   rotate: false
-  xy: 134, 192
+  xy: 107, 3
   size: 65, 31
   orig: 65, 31
   offset: 0, 0
   index: -1
 goblingirl/left-hand
   rotate: false
-  xy: 196, 109
+  xy: 565, 2
   size: 35, 40
   orig: 35, 40
   offset: 0, 0
   index: -1
 goblingirl/left-lower-leg
-  rotate: false
-  xy: 169, 293
+  rotate: true
+  xy: 785, 93
   size: 33, 70
   orig: 33, 70
   offset: 0, 0
   index: -1
 goblingirl/left-shoulder
-  rotate: false
-  xy: 107, 30
+  rotate: true
+  xy: 690, 27
   size: 28, 46
   orig: 28, 46
   offset: 0, 0
   index: -1
 goblingirl/left-upper-leg
-  rotate: false
-  xy: 65, 68
+  rotate: true
+  xy: 857, 93
   size: 33, 70
   orig: 33, 70
   offset: 0, 0
   index: -1
 goblingirl/neck
   rotate: false
-  xy: 204, 297
+  xy: 528, 2
   size: 35, 41
   orig: 35, 41
   offset: 0, 0
   index: -1
 goblingirl/pelvis
   rotate: false
-  xy: 131, 365
+  xy: 546, 45
   size: 62, 43
   orig: 62, 43
   offset: 0, 0
   index: -1
 goblingirl/right-arm
   rotate: false
-  xy: 100, 97
+  xy: 452, 48
   size: 28, 50
   orig: 28, 50
   offset: 0, 0
   index: -1
 goblingirl/right-foot
   rotate: false
-  xy: 134, 157
+  xy: 836, 58
   size: 63, 33
   orig: 63, 33
   offset: 0, 0
   index: -1
 goblingirl/right-hand
-  rotate: false
-  xy: 199, 151
+  rotate: true
+  xy: 771, 20
   size: 36, 37
   orig: 36, 37
   offset: 0, 0
   index: -1
 goblingirl/right-lower-leg
-  rotate: false
-  xy: 96, 279
+  rotate: true
+  xy: 560, 90
   size: 36, 76
   orig: 36, 76
   offset: 0, 0
   index: -1
 goblingirl/right-shoulder
   rotate: false
-  xy: 204, 340
+  xy: 649, 10
   size: 39, 45
   orig: 39, 45
   offset: 0, 0
   index: -1
 goblingirl/right-upper-leg
-  rotate: false
-  xy: 98, 149
+  rotate: true
+  xy: 706, 57
   size: 34, 63
   orig: 34, 63
   offset: 0, 0
   index: -1
 goblingirl/torso
   rotate: false
-  xy: 26, 259
+  xy: 310, 2
   size: 68, 96
   orig: 68, 96
   offset: 0, 0
   index: -1
 goblingirl/undie-straps
   rotate: false
-  xy: 134, 136
+  xy: 212, 13
   size: 55, 19
   orig: 55, 19
   offset: 0, 0
   index: -1
 goblingirl/undies
   rotate: false
-  xy: 196, 78
+  xy: 810, 27
   size: 36, 29
   orig: 36, 29
   offset: 0, 0
   index: -1
 shield
   rotate: false
-  xy: 26, 185
+  xy: 380, 26
   size: 70, 72
   orig: 70, 72
   offset: 0, 0
   index: -1
 spear
-  rotate: false
-  xy: 2, 138
+  rotate: true
+  xy: 2, 104
   size: 22, 368
   orig: 22, 368
   offset: 0, 0

+ 5 - 0
spine-starling/spine-starling-example/src/goblins-ffd.json

@@ -759,6 +759,11 @@
 		},
 		"ffd": {
 			"default": {
+				"left hand item": {
+					"spear": [
+						{ "time": 0 }
+					]
+				},
 				"right hand item": {
 					"dagger": [
 						{

二進制
spine-starling/spine-starling-example/src/goblins-ffd.png


+ 1002 - 0
spine-starling/spine-starling-example/src/spineboy-starling.json

@@ -0,0 +1,1002 @@
+{
+"bones": [
+	{ "name": "root" },
+	{ "name": "hip", "parent": "root", "x": 0.64, "y": 114.41 },
+	{ "name": "left upper leg", "parent": "hip", "length": 50.39, "x": 14.45, "y": 2.81, "rotation": -89.09 },
+	{ "name": "pelvis", "parent": "hip", "x": 1.41, "y": -6.57 },
+	{ "name": "right upper leg", "parent": "hip", "length": 45.76, "x": -18.27, "rotation": -101.13 },
+	{ "name": "torso", "parent": "hip", "length": 85.82, "x": -6.42, "y": 1.97, "rotation": 94.95 },
+	{ "name": "left lower leg", "parent": "left upper leg", "length": 56.45, "x": 51.78, "y": 3.46, "rotation": -16.65 },
+	{ "name": "left shoulder", "parent": "torso", "length": 44.19, "x": 78.96, "y": -15.75, "rotation": -156.96 },
+	{ "name": "neck", "parent": "torso", "length": 18.38, "x": 83.64, "y": -1.78, "rotation": 0.9 },
+	{ "name": "right lower leg", "parent": "right upper leg", "length": 58.52, "x": 50.21, "y": 0.6, "rotation": -10.7 },
+	{ "name": "right shoulder", "parent": "torso", "length": 49.95, "x": 81.9, "y": 6.79, "rotation": 130.6 },
+	{ "name": "head", "parent": "neck", "length": 68.28, "x": 19.09, "y": 6.97, "rotation": -8.94 },
+	{ "name": "left arm", "parent": "left shoulder", "length": 35.62, "x": 44.19, "y": -0.01, "rotation": 28.16 },
+	{ "name": "left foot", "parent": "left lower leg", "length": 46.5, "x": 64.02, "y": -8.67, "rotation": 102.43 },
+	{ "name": "right arm", "parent": "right shoulder", "length": 36.74, "x": 49.95, "y": -0.12, "rotation": 40.12 },
+	{ "name": "right foot", "parent": "right lower leg", "length": 45.45, "x": 64.88, "y": 0.04, "rotation": 110.3 },
+	{ "name": "left hand", "parent": "left arm", "length": 11.52, "x": 35.62, "y": 0.07, "rotation": 2.7 },
+	{ "name": "right hand", "parent": "right arm", "length": 15.32, "x": 36.9, "y": 0.34, "rotation": 2.35 }
+],
+"slots": [
+	{ "name": "left shoulder", "bone": "left shoulder", "attachment": "left-shoulder" },
+	{ "name": "left arm", "bone": "left arm", "attachment": "left-arm" },
+	{ "name": "left hand", "bone": "left hand", "attachment": "left-hand" },
+	{ "name": "left foot", "bone": "left foot", "attachment": "left-foot" },
+	{ "name": "left lower leg", "bone": "left lower leg", "attachment": "left-lower-leg" },
+	{ "name": "left upper leg", "bone": "left upper leg", "attachment": "left-upper-leg" },
+	{ "name": "pelvis", "bone": "pelvis", "attachment": "pelvis" },
+	{ "name": "right foot", "bone": "right foot", "attachment": "right-foot" },
+	{ "name": "right lower leg", "bone": "right lower leg", "attachment": "right-lower-leg" },
+	{ "name": "right upper leg", "bone": "right upper leg", "attachment": "right-upper-leg" },
+	{ "name": "torso", "bone": "torso", "attachment": "torso" },
+	{ "name": "neck", "bone": "neck", "attachment": "neck" },
+	{ "name": "head", "bone": "head", "attachment": "head" },
+	{ "name": "eyes", "bone": "head", "attachment": "eyes" },
+	{ "name": "right shoulder", "bone": "right shoulder", "attachment": "right-shoulder", "additive": true },
+	{ "name": "right arm", "bone": "right arm", "attachment": "right-arm" },
+	{ "name": "right hand", "bone": "right hand", "attachment": "right-hand" },
+	{ "name": "bb-head", "bone": "head", "attachment": "bb-head" }
+],
+"skins": {
+	"default": {
+		"bb-head": {
+			"bb-head": {
+				"type": "boundingbox",
+				"vertices": [
+					55.69696,
+					-44.60648,
+					8.2226715,
+					-47.609646,
+					-11.244263,
+					-32.942703,
+					-0.05206299,
+					35.835804,
+					61.018433,
+					43.227512,
+					90.35846,
+					-16.054127,
+					115.41275,
+					-32.817406,
+					78.29431,
+					-56.05409
+				]
+			}
+		},
+		"eyes": {
+			"eyes": { "x": 28.94, "y": -32.92, "rotation": -86.9, "width": 34, "height": 27 },
+			"eyes-closed": { "x": 28.77, "y": -32.86, "rotation": -86.9, "width": 34, "height": 27 }
+		},
+		"head": {
+			"head": { "x": 53.94, "y": -5.75, "rotation": -86.9, "width": 121, "height": 132 }
+		},
+		"left arm": {
+			"left-arm": { "x": 15.11, "y": -0.44, "rotation": 33.84, "width": 35, "height": 29 }
+		},
+		"left foot": {
+			"left-foot": { "x": 24.35, "y": 8.88, "rotation": 3.32, "width": 65, "height": 30 }
+		},
+		"left hand": {
+			"left-hand": { "x": 0.75, "y": 1.86, "rotation": 31.14, "width": 35, "height": 38 }
+		},
+		"left lower leg": {
+			"left-lower-leg": { "x": 24.55, "y": -1.92, "rotation": 105.75, "width": 49, "height": 64 }
+		},
+		"left shoulder": {
+			"left-shoulder": { "x": 23.74, "y": 0.11, "rotation": 62.01, "width": 34, "height": 53 }
+		},
+		"left upper leg": {
+			"left-upper-leg": { "x": 26.12, "y": -1.85, "rotation": 89.09, "width": 33, "height": 67 }
+		},
+		"neck": {
+			"neck": { "x": 9.42, "y": -3.66, "rotation": -100.15, "width": 34, "height": 28 }
+		},
+		"pelvis": {
+			"pelvis": { "x": -4.83, "y": 10.62, "width": 63, "height": 47 }
+		},
+		"right arm": {
+			"right-arm": { "x": 18.34, "y": -2.64, "rotation": 94.32, "width": 21, "height": 45 }
+		},
+		"right foot": {
+			"right-foot": { "x": 19.02, "y": 8.47, "rotation": 1.52, "width": 67, "height": 30 }
+		},
+		"right hand": {
+			"right-hand": { "x": 6.82, "y": 1.25, "rotation": 91.96, "width": 32, "height": 32 }
+		},
+		"right lower leg": {
+			"right-lower-leg": { "x": 23.28, "y": -2.59, "rotation": 111.83, "width": 51, "height": 64 }
+		},
+		"right shoulder": {
+			"right-shoulder": { "x": 25.86, "y": 0.03, "rotation": 134.44, "width": 52, "height": 51 }
+		},
+		"right upper leg": {
+			"right-upper-leg": { "x": 23.03, "y": 0.25, "rotation": 101.13, "width": 44, "height": 70 }
+		},
+		"torso": {
+			"torso": { "x": 44.57, "y": -7.08, "rotation": -94.95, "width": 68, "height": 92 }
+		}
+	}
+},
+"events": {
+	"behind": {},
+	"headAttach": {},
+	"headPop": {}
+},
+"animations": {
+	"drawOrder": {
+		"bones": {
+			"head": {
+				"rotate": [
+					{ "time": 0, "angle": 0 },
+					{ "time": 0.4827, "angle": -23.11 },
+					{ "time": 0.8965, "angle": -56.45 },
+					{ "time": 1.3103, "angle": 1.38 },
+					{ "time": 1.7931, "angle": 36.12 },
+					{ "time": 2.1379, "angle": 1.24 },
+					{ "time": 2.6206, "angle": -37.12 },
+					{ "time": 2.9666, "angle": 2.07 },
+					{ "time": 3.4666, "angle": 34.72 },
+					{ "time": 3.9, "angle": 359.99 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.19, 0.4, 0.586, 0.75 ]
+					},
+					{
+						"time": 0.2758,
+						"x": 57.88,
+						"y": -35.72,
+						"curve": [ 0.39, 0.54, 0.632, 0.72 ]
+					},
+					{
+						"time": 0.4827,
+						"x": 87.26,
+						"y": -87.89,
+						"curve": [ 0.325, 0.23, 0.587, 0.36 ]
+					},
+					{
+						"time": 0.6896,
+						"x": 28.89,
+						"y": -114.62,
+						"curve": [ 0.383, 0.23, 0.736, 0.55 ]
+					},
+					{
+						"time": 0.8965,
+						"x": -76.58,
+						"y": -124.98,
+						"curve": [ 0.129, 0.21, 0.547, 0.64 ]
+					},
+					{
+						"time": 1.1034,
+						"x": -154.37,
+						"y": -77.13,
+						"curve": [ 0.354, 0.48, 0.729, 0.9 ]
+					},
+					{
+						"time": 1.3103,
+						"x": -181.02,
+						"y": 18.56,
+						"curve": [ 0.063, 0.15, 0.52, 0.62 ]
+					},
+					{
+						"time": 1.5862,
+						"x": -150.38,
+						"y": 128.67,
+						"curve": [ 0.381, 0.54, 0.778, 1 ]
+					},
+					{
+						"time": 1.7931,
+						"x": -112.08,
+						"y": 146.28,
+						"curve": [ 0.242, 0, 0.626, 0.45 ]
+					},
+					{
+						"time": 1.931,
+						"x": -63.7,
+						"y": 111.22,
+						"curve": [ 0.398, 0.35, 0.786, 0.76 ]
+					},
+					{
+						"time": 2.1379,
+						"x": -48.94,
+						"y": -1.55,
+						"curve": [ 0.188, 0.21, 0.575, 0.61 ]
+					},
+					{
+						"time": 2.3448,
+						"x": -91.69,
+						"y": -91.93,
+						"curve": [ 0.362, 0.51, 0.766, 1 ]
+					},
+					{
+						"time": 2.6206,
+						"x": -142.79,
+						"y": -126.83,
+						"curve": [ 0.227, 0.34, 0.593, 0.75 ]
+					},
+					{
+						"time": 2.7586,
+						"x": -176.7,
+						"y": -98.32,
+						"curve": [ 0.26, 0.4, 0.612, 0.71 ]
+					},
+					{
+						"time": 2.8965,
+						"x": -163.95,
+						"y": -24.04,
+						"curve": [ 0.338, 0.37, 0.676, 0.71 ]
+					},
+					{
+						"time": 2.9655,
+						"x": -150.17,
+						"y": 10.71,
+						"curve": [ 0.387, 0.61, 0.741, 1 ]
+					},
+					{
+						"time": 3.1034,
+						"x": -102.44,
+						"y": 45.92,
+						"curve": [ 0.31, 0.24, 0.648, 0.58 ]
+					},
+					{
+						"time": 3.2413,
+						"x": -53.99,
+						"y": 70.39,
+						"curve": [ 0.325, 0.29, 0.663, 0.63 ]
+					},
+					{
+						"time": 3.3793,
+						"x": 1.88,
+						"y": 55.54,
+						"curve": [ 0.387, 0.33, 0.769, 0.73 ]
+					},
+					{
+						"time": 3.5862,
+						"x": 34.26,
+						"y": 36.13,
+						"curve": [ 0.206, 0.28, 0.596, 0.67 ]
+					},
+					{
+						"time": 3.7931,
+						"x": 23.94,
+						"y": 1.01,
+						"curve": [ 0.373, 0.56, 0.759, 1 ]
+					},
+					{ "time": 4, "x": 0, "y": 0 }
+				],
+				"scale": [
+					{ "time": 0.8275, "x": 1, "y": 1 },
+					{ "time": 1.3103, "x": 0.742, "y": 0.742 },
+					{ "time": 1.7931, "x": 1, "y": 1 },
+					{ "time": 2.1379, "x": 1.502, "y": 1.502 },
+					{ "time": 2.6206, "x": 1, "y": 1 },
+					{ "time": 2.9655, "x": 0.707, "y": 0.707 },
+					{ "time": 3.3793, "x": 1, "y": 1 }
+				]
+			}
+		},
+		"events": [
+			{ "time": 0, "name": "headPop", "string": "pop.wav" },
+			{ "time": 1.3103, "name": "behind" },
+			{ "time": 2.9655, "name": "behind" },
+			{ "time": 4, "name": "headAttach", "string": "attach.wav" }
+		],
+		"draworder": [
+			{
+				"time": 0.6206,
+				"offsets": [
+					{ "slot": "head", "offset": -12 },
+					{ "slot": "eyes", "offset": -12 }
+				]
+			},
+			{
+				"time": 1.7931,
+				"offsets": [
+					{ "slot": "head", "offset": 3 },
+					{ "slot": "eyes", "offset": 3 }
+				]
+			},
+			{
+				"time": 2.6206,
+				"offsets": [
+					{ "slot": "head", "offset": -12 },
+					{ "slot": "eyes", "offset": -12 }
+				]
+			},
+			{ "time": 3.5862 }
+		]
+	},
+	"jump": {
+		"bones": {
+			"hip": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 0.9333, "angle": 0, "curve": "stepped" },
+					{ "time": 1.3666, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": -11.57, "y": -3 },
+					{ "time": 0.2333, "x": -16.2, "y": -19.43 },
+					{
+						"time": 0.3333,
+						"x": 7.66,
+						"y": -8.48,
+						"curve": [ 0.057, 0.06, 0.712, 1 ]
+					},
+					{ "time": 0.3666, "x": 15.38, "y": 5.01 },
+					{ "time": 0.4666, "x": -7.84, "y": 57.22 },
+					{
+						"time": 0.6,
+						"x": -10.81,
+						"y": 96.34,
+						"curve": [ 0.241, 0, 1, 1 ]
+					},
+					{ "time": 0.7333, "x": -7.01, "y": 54.7 },
+					{ "time": 0.8, "x": -10.58, "y": 32.2 },
+					{ "time": 0.9333, "x": -31.99, "y": 0.45 },
+					{ "time": 1.0666, "x": -12.48, "y": -29.47 },
+					{ "time": 1.3666, "x": -11.57, "y": -3 }
+				],
+				"scale": [
+					{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 1.3666, "x": 1, "y": 1 }
+				]
+			},
+			"left upper leg": {
+				"rotate": [
+					{ "time": 0, "angle": 17.13 },
+					{ "time": 0.2333, "angle": 44.35 },
+					{ "time": 0.3333, "angle": 16.46 },
+					{ "time": 0.4, "angle": -9.88 },
+					{ "time": 0.4666, "angle": -11.42 },
+					{ "time": 0.5666, "angle": 23.46 },
+					{ "time": 0.7666, "angle": 71.82 },
+					{ "time": 0.9333, "angle": 65.53 },
+					{ "time": 1.0666, "angle": 51.01 },
+					{ "time": 1.3666, "angle": 17.13 }
+				],
+				"translate": [
+					{ "time": 0, "x": -3, "y": -2.25, "curve": "stepped" },
+					{ "time": 0.9333, "x": -3, "y": -2.25, "curve": "stepped" },
+					{ "time": 1.3666, "x": -3, "y": -2.25 }
+				],
+				"scale": [
+					{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 1.3666, "x": 1, "y": 1 }
+				]
+			},
+			"left lower leg": {
+				"rotate": [
+					{ "time": 0, "angle": -16.25 },
+					{ "time": 0.2333, "angle": -52.21 },
+					{ "time": 0.4, "angle": 15.04 },
+					{ "time": 0.4666, "angle": -8.95 },
+					{ "time": 0.5666, "angle": -39.53 },
+					{ "time": 0.7666, "angle": -27.27 },
+					{ "time": 0.9333, "angle": -3.52 },
+					{ "time": 1.0666, "angle": -61.92 },
+					{ "time": 1.3666, "angle": -16.25 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 1.3666, "x": 0, "y": 0 }
+				],
+				"scale": [
+					{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 1.3666, "x": 1, "y": 1 }
+				]
+			},
+			"left foot": {
+				"rotate": [
+					{ "time": 0, "angle": 0.33 },
+					{ "time": 0.2333, "angle": 6.2 },
+					{ "time": 0.3333, "angle": 14.73 },
+					{ "time": 0.4, "angle": -15.54 },
+					{ "time": 0.4333, "angle": -21.2 },
+					{ "time": 0.5666, "angle": -7.55 },
+					{ "time": 0.7666, "angle": -0.67 },
+					{ "time": 0.9333, "angle": -0.58 },
+					{ "time": 1.0666, "angle": 14.64 },
+					{ "time": 1.3666, "angle": 0.33 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 1.3666, "x": 0, "y": 0 }
+				],
+				"scale": [
+					{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 1.3666, "x": 1, "y": 1 }
+				]
+			},
+			"right upper leg": {
+				"rotate": [
+					{ "time": 0, "angle": 25.97 },
+					{ "time": 0.2333, "angle": 46.43 },
+					{ "time": 0.3333, "angle": 22.61 },
+					{ "time": 0.4, "angle": 2.13 },
+					{
+						"time": 0.4666,
+						"angle": 0.04,
+						"curve": [ 0, 0, 0.637, 0.98 ]
+					},
+					{ "time": 0.6, "angle": 65.55 },
+					{ "time": 0.7666, "angle": 64.93 },
+					{ "time": 0.9333, "angle": 41.08 },
+					{ "time": 1.0666, "angle": 66.25 },
+					{ "time": 1.3666, "angle": 25.97 }
+				],
+				"translate": [
+					{ "time": 0, "x": 5.74, "y": 0.61 },
+					{ "time": 0.2333, "x": 4.79, "y": 1.79 },
+					{ "time": 0.3333, "x": 6.05, "y": -4.55 },
+					{ "time": 0.9333, "x": 4.79, "y": 1.79, "curve": "stepped" },
+					{ "time": 1.0666, "x": 4.79, "y": 1.79 },
+					{ "time": 1.3666, "x": 5.74, "y": 0.61 }
+				],
+				"scale": [
+					{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 1.3666, "x": 1, "y": 1 }
+				]
+			},
+			"right lower leg": {
+				"rotate": [
+					{ "time": 0, "angle": -27.46 },
+					{ "time": 0.2333, "angle": -64.03 },
+					{ "time": 0.4, "angle": -48.36 },
+					{ "time": 0.5666, "angle": -76.86 },
+					{ "time": 0.7666, "angle": -26.89 },
+					{ "time": 0.9, "angle": -18.97 },
+					{ "time": 0.9333, "angle": -14.18 },
+					{ "time": 1.0666, "angle": -80.45 },
+					{ "time": 1.3666, "angle": -27.46 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 1.3666, "x": 0, "y": 0 }
+				],
+				"scale": [
+					{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 1.3666, "x": 1, "y": 1 }
+				]
+			},
+			"right foot": {
+				"rotate": [
+					{ "time": 0, "angle": 1.08 },
+					{ "time": 0.2333, "angle": 16.02 },
+					{ "time": 0.3, "angle": 12.94 },
+					{ "time": 0.3333, "angle": 15.16 },
+					{ "time": 0.4, "angle": -14.7 },
+					{ "time": 0.4333, "angle": -12.85 },
+					{ "time": 0.4666, "angle": -19.18 },
+					{ "time": 0.5666, "angle": -15.82 },
+					{ "time": 0.6, "angle": -3.59 },
+					{ "time": 0.7666, "angle": -3.56 },
+					{ "time": 0.9333, "angle": 1.86 },
+					{ "time": 1.0666, "angle": 16.02 },
+					{ "time": 1.3666, "angle": 1.08 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 1.3666, "x": 0, "y": 0 }
+				],
+				"scale": [
+					{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 1.3666, "x": 1, "y": 1 }
+				]
+			},
+			"torso": {
+				"rotate": [
+					{ "time": 0, "angle": -13.35 },
+					{ "time": 0.2333, "angle": -48.95 },
+					{ "time": 0.4333, "angle": -35.77 },
+					{ "time": 0.6, "angle": -4.59 },
+					{ "time": 0.7666, "angle": 14.61 },
+					{ "time": 0.9333, "angle": 15.74 },
+					{ "time": 1.0666, "angle": -32.44 },
+					{ "time": 1.3666, "angle": -13.35 }
+				],
+				"translate": [
+					{ "time": 0, "x": -3.67, "y": 1.68, "curve": "stepped" },
+					{ "time": 0.9333, "x": -3.67, "y": 1.68, "curve": "stepped" },
+					{ "time": 1.3666, "x": -3.67, "y": 1.68 }
+				],
+				"scale": [
+					{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 1.3666, "x": 1, "y": 1 }
+				]
+			},
+			"neck": {
+				"rotate": [
+					{ "time": 0, "angle": 12.78 },
+					{ "time": 0.2333, "angle": 16.46 },
+					{ "time": 0.4, "angle": 26.49 },
+					{ "time": 0.6, "angle": 15.51 },
+					{ "time": 0.7666, "angle": 1.34 },
+					{ "time": 0.9333, "angle": 2.35 },
+					{ "time": 1.0666, "angle": 6.08 },
+					{ "time": 1.3, "angle": 21.23 },
+					{ "time": 1.3666, "angle": 12.78 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 1.3666, "x": 0, "y": 0 }
+				],
+				"scale": [
+					{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 1.3666, "x": 1, "y": 1 }
+				]
+			},
+			"head": {
+				"rotate": [
+					{ "time": 0, "angle": 5.19 },
+					{ "time": 0.2333, "angle": 20.27 },
+					{ "time": 0.4, "angle": 15.27 },
+					{ "time": 0.6, "angle": -24.69 },
+					{ "time": 0.7666, "angle": -11.02 },
+					{ "time": 0.9333, "angle": -24.38 },
+					{ "time": 1.0666, "angle": 11.99 },
+					{ "time": 1.3, "angle": 4.86 },
+					{ "time": 1.3666, "angle": 5.19 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 1.3666, "x": 0, "y": 0 }
+				],
+				"scale": [
+					{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 1.3666, "x": 1, "y": 1 }
+				]
+			},
+			"left shoulder": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 0.05,
+						"curve": [ 0, 0, 0.62, 1 ]
+					},
+					{
+						"time": 0.2333,
+						"angle": 279.66,
+						"curve": [ 0.218, 0.67, 0.66, 0.99 ]
+					},
+					{
+						"time": 0.5,
+						"angle": 62.27,
+						"curve": [ 0.462, 0, 0.764, 0.58 ]
+					},
+					{ "time": 0.9333, "angle": 28.91 },
+					{ "time": 1.0666, "angle": -8.62 },
+					{ "time": 1.1666, "angle": -18.43 },
+					{ "time": 1.3666, "angle": 0.05 }
+				],
+				"translate": [
+					{ "time": 0, "x": -1.76, "y": 0.56, "curve": "stepped" },
+					{ "time": 0.9333, "x": -1.76, "y": 0.56, "curve": "stepped" },
+					{ "time": 1.3666, "x": -1.76, "y": 0.56 }
+				],
+				"scale": [
+					{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 1.3666, "x": 1, "y": 1 }
+				]
+			},
+			"left hand": {
+				"rotate": [
+					{ "time": 0, "angle": 11.58, "curve": "stepped" },
+					{ "time": 0.9333, "angle": 11.58, "curve": "stepped" },
+					{ "time": 1.3666, "angle": 11.58 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 1.3666, "x": 0, "y": 0 }
+				],
+				"scale": [
+					{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 1.3666, "x": 1, "y": 1 }
+				]
+			},
+			"left arm": {
+				"rotate": [
+					{ "time": 0, "angle": 0.51 },
+					{ "time": 0.4333, "angle": 12.82 },
+					{ "time": 0.6, "angle": 47.55 },
+					{ "time": 0.9333, "angle": 12.82 },
+					{ "time": 1.1666, "angle": -6.5 },
+					{ "time": 1.3666, "angle": 0.51 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 1.3666, "x": 0, "y": 0 }
+				],
+				"scale": [
+					{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 1.3666, "x": 1, "y": 1 }
+				]
+			},
+			"right shoulder": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 43.82,
+						"curve": [ 0, 0, 0.62, 1 ]
+					},
+					{
+						"time": 0.2333,
+						"angle": -8.74,
+						"curve": [ 0.304, 0.58, 0.709, 0.97 ]
+					},
+					{
+						"time": 0.5333,
+						"angle": -208.02,
+						"curve": [ 0.462, 0, 0.764, 0.58 ]
+					},
+					{ "time": 0.9333, "angle": -246.72 },
+					{ "time": 1.0666, "angle": -307.13 },
+					{ "time": 1.1666, "angle": 37.15 },
+					{ "time": 1.3666, "angle": 43.82 }
+				],
+				"translate": [
+					{ "time": 0, "x": -7.84, "y": 7.19, "curve": "stepped" },
+					{ "time": 0.9333, "x": -7.84, "y": 7.19, "curve": "stepped" },
+					{ "time": 1.3666, "x": -7.84, "y": 7.19 }
+				],
+				"scale": [
+					{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 1.3666, "x": 1, "y": 1 }
+				]
+			},
+			"right arm": {
+				"rotate": [
+					{ "time": 0, "angle": -4.02 },
+					{ "time": 0.6, "angle": 17.5 },
+					{ "time": 0.9333, "angle": -4.02 },
+					{ "time": 1.1666, "angle": -16.72 },
+					{ "time": 1.3666, "angle": -4.02 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 1.3666, "x": 0, "y": 0 }
+				],
+				"scale": [
+					{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 1.3666, "x": 1, "y": 1 }
+				]
+			},
+			"right hand": {
+				"rotate": [
+					{ "time": 0, "angle": 22.92, "curve": "stepped" },
+					{ "time": 0.9333, "angle": 22.92, "curve": "stepped" },
+					{ "time": 1.3666, "angle": 22.92 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 1.3666, "x": 0, "y": 0 }
+				],
+				"scale": [
+					{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 1.3666, "x": 1, "y": 1 }
+				]
+			},
+			"root": {
+				"rotate": [
+					{ "time": 0, "angle": 0 },
+					{ "time": 0.4333, "angle": -14.52 },
+					{ "time": 0.8, "angle": 9.86 },
+					{ "time": 1.3666, "angle": 0 }
+				],
+				"scale": [
+					{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
+					{ "time": 1.3666, "x": 1, "y": 1 }
+				]
+			}
+		}
+	},
+	"walk": {
+		"bones": {
+			"left upper leg": {
+				"rotate": [
+					{ "time": 0, "angle": -26.55 },
+					{ "time": 0.1333, "angle": -8.78 },
+					{ "time": 0.2666, "angle": 9.51 },
+					{ "time": 0.4, "angle": 30.74 },
+					{ "time": 0.5333, "angle": 25.33 },
+					{ "time": 0.6666, "angle": 26.11 },
+					{ "time": 0.8, "angle": -7.7 },
+					{ "time": 0.9333, "angle": -21.19 },
+					{ "time": 1.0666, "angle": -26.55 }
+				],
+				"translate": [
+					{ "time": 0, "x": -3, "y": -2.25 },
+					{ "time": 0.4, "x": -2.18, "y": -2.25 },
+					{ "time": 1.0666, "x": -3, "y": -2.25 }
+				]
+			},
+			"right upper leg": {
+				"rotate": [
+					{ "time": 0, "angle": 42.45 },
+					{ "time": 0.1333, "angle": 52.1 },
+					{ "time": 0.2666, "angle": 5.96 },
+					{ "time": 0.5333, "angle": -16.93 },
+					{ "time": 0.6666, "angle": 1.89 },
+					{
+						"time": 0.8,
+						"angle": 28.06,
+						"curve": [ 0.462, 0.11, 1, 1 ]
+					},
+					{
+						"time": 0.9333,
+						"angle": 58.68,
+						"curve": [ 0.5, 0.02, 1, 1 ]
+					},
+					{ "time": 1.0666, "angle": 42.45 }
+				],
+				"translate": [
+					{ "time": 0, "x": 8.11, "y": -2.36 },
+					{ "time": 0.1333, "x": 10.03, "y": -2.56 },
+					{ "time": 0.4, "x": 2.76, "y": -2.97 },
+					{ "time": 0.5333, "x": 2.76, "y": -2.81 },
+					{ "time": 0.9333, "x": 8.67, "y": -2.54 },
+					{ "time": 1.0666, "x": 8.11, "y": -2.36 }
+				]
+			},
+			"left lower leg": {
+				"rotate": [
+					{ "time": 0, "angle": -10.21 },
+					{ "time": 0.1333, "angle": -55.64 },
+					{ "time": 0.2666, "angle": -68.12 },
+					{ "time": 0.5333, "angle": 5.11 },
+					{ "time": 0.6666, "angle": -28.29 },
+					{ "time": 0.8, "angle": 4.08 },
+					{ "time": 0.9333, "angle": 3.53 },
+					{ "time": 1.0666, "angle": -10.21 }
+				]
+			},
+			"left foot": {
+				"rotate": [
+					{ "time": 0, "angle": -3.69 },
+					{ "time": 0.1333, "angle": -10.42 },
+					{ "time": 0.2666, "angle": -17.14 },
+					{ "time": 0.4, "angle": -2.83 },
+					{ "time": 0.5333, "angle": -3.87 },
+					{ "time": 0.6666, "angle": 2.78 },
+					{ "time": 0.8, "angle": 1.68 },
+					{ "time": 0.9333, "angle": -8.54 },
+					{ "time": 1.0666, "angle": -3.69 }
+				]
+			},
+			"right shoulder": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 20.89,
+						"curve": [ 0.264, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.1333,
+						"angle": 3.72,
+						"curve": [ 0.272, 0, 0.841, 1 ]
+					},
+					{ "time": 0.6666, "angle": -278.28 },
+					{ "time": 1.0666, "angle": 20.89 }
+				],
+				"translate": [
+					{ "time": 0, "x": -7.84, "y": 7.19 },
+					{ "time": 0.1333, "x": -6.36, "y": 6.42 },
+					{ "time": 0.6666, "x": -11.07, "y": 5.25 },
+					{ "time": 1.0666, "x": -7.84, "y": 7.19 }
+				]
+			},
+			"right arm": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": -4.02,
+						"curve": [ 0.267, 0, 0.804, 0.99 ]
+					},
+					{
+						"time": 0.1333,
+						"angle": -13.99,
+						"curve": [ 0.341, 0, 1, 1 ]
+					},
+					{
+						"time": 0.6666,
+						"angle": 36.54,
+						"curve": [ 0.307, 0, 0.787, 0.99 ]
+					},
+					{ "time": 1.0666, "angle": -4.02 }
+				]
+			},
+			"right hand": {
+				"rotate": [
+					{ "time": 0, "angle": 22.92 },
+					{ "time": 0.4, "angle": -8.97 },
+					{ "time": 0.6666, "angle": 0.51 },
+					{ "time": 1.0666, "angle": 22.92 }
+				]
+			},
+			"left shoulder": {
+				"rotate": [
+					{ "time": 0, "angle": -1.47 },
+					{ "time": 0.1333, "angle": 13.6 },
+					{ "time": 0.6666, "angle": 280.74 },
+					{ "time": 1.0666, "angle": -1.47 }
+				],
+				"translate": [
+					{ "time": 0, "x": -1.76, "y": 0.56 },
+					{ "time": 0.6666, "x": -2.47, "y": 8.14 },
+					{ "time": 1.0666, "x": -1.76, "y": 0.56 }
+				]
+			},
+			"left hand": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 11.58,
+						"curve": [ 0.169, 0.37, 0.632, 1.55 ]
+					},
+					{
+						"time": 0.1333,
+						"angle": 28.13,
+						"curve": [ 0.692, 0, 0.692, 0.99 ]
+					},
+					{
+						"time": 0.6666,
+						"angle": -27.42,
+						"curve": [ 0.117, 0.41, 0.738, 1.76 ]
+					},
+					{ "time": 0.8, "angle": -36.32 },
+					{ "time": 1.0666, "angle": 11.58 }
+				]
+			},
+			"left arm": {
+				"rotate": [
+					{ "time": 0, "angle": -8.27 },
+					{ "time": 0.1333, "angle": 18.43 },
+					{ "time": 0.6666, "angle": 0.88 },
+					{ "time": 1.0666, "angle": -8.27 }
+				]
+			},
+			"torso": {
+				"rotate": [
+					{ "time": 0, "angle": -10.28 },
+					{
+						"time": 0.1333,
+						"angle": -15.38,
+						"curve": [ 0.545, 0, 1, 1 ]
+					},
+					{
+						"time": 0.4,
+						"angle": -9.78,
+						"curve": [ 0.58, 0.17, 1, 1 ]
+					},
+					{ "time": 0.6666, "angle": -15.75 },
+					{ "time": 0.9333, "angle": -7.06 },
+					{ "time": 1.0666, "angle": -10.28 }
+				],
+				"translate": [
+					{ "time": 0, "x": -3.67, "y": 1.68 },
+					{ "time": 0.1333, "x": -3.67, "y": 0.68 },
+					{ "time": 0.4, "x": -3.67, "y": 1.97 },
+					{ "time": 0.6666, "x": -3.67, "y": -0.14 },
+					{ "time": 1.0666, "x": -3.67, "y": 1.68 }
+				]
+			},
+			"right foot": {
+				"rotate": [
+					{ "time": 0, "angle": -5.25 },
+					{ "time": 0.2666, "angle": -4.08 },
+					{ "time": 0.4, "angle": -6.45 },
+					{ "time": 0.5333, "angle": -5.39 },
+					{ "time": 0.8, "angle": -11.68 },
+					{ "time": 0.9333, "angle": 0.46 },
+					{ "time": 1.0666, "angle": -5.25 }
+				]
+			},
+			"right lower leg": {
+				"rotate": [
+					{ "time": 0, "angle": -3.39 },
+					{ "time": 0.1333, "angle": -45.53 },
+					{ "time": 0.2666, "angle": -2.59 },
+					{ "time": 0.5333, "angle": -19.53 },
+					{ "time": 0.6666, "angle": -64.8 },
+					{
+						"time": 0.8,
+						"angle": -82.56,
+						"curve": [ 0.557, 0.18, 1, 1 ]
+					},
+					{ "time": 1.0666, "angle": -3.39 }
+				]
+			},
+			"hip": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 1.0666, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 },
+					{
+						"time": 0.1333,
+						"x": 0,
+						"y": -7.61,
+						"curve": [ 0.272, 0.86, 1, 1 ]
+					},
+					{ "time": 0.4, "x": 0, "y": 8.7 },
+					{ "time": 0.5333, "x": 0, "y": -0.41 },
+					{
+						"time": 0.6666,
+						"x": 0,
+						"y": -7.05,
+						"curve": [ 0.235, 0.89, 1, 1 ]
+					},
+					{ "time": 0.8, "x": 0, "y": 2.92 },
+					{ "time": 0.9333, "x": 0, "y": 6.78 },
+					{ "time": 1.0666, "x": 0, "y": 0 }
+				]
+			},
+			"neck": {
+				"rotate": [
+					{ "time": 0, "angle": 3.6 },
+					{ "time": 0.1333, "angle": 17.49 },
+					{ "time": 0.2666, "angle": 6.1 },
+					{ "time": 0.4, "angle": 3.45 },
+					{ "time": 0.5333, "angle": 5.17 },
+					{ "time": 0.6666, "angle": 18.36 },
+					{ "time": 0.8, "angle": 6.09 },
+					{ "time": 0.9333, "angle": 2.28 },
+					{ "time": 1.0666, "angle": 3.6 }
+				]
+			},
+			"head": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 3.6,
+						"curve": [ 0, 0, 0.704, 1.61 ]
+					},
+					{ "time": 0.1666, "angle": -0.2 },
+					{ "time": 0.2666, "angle": 6.1 },
+					{ "time": 0.4, "angle": 3.45 },
+					{
+						"time": 0.5333,
+						"angle": 5.17,
+						"curve": [ 0, 0, 0.704, 1.61 ]
+					},
+					{ "time": 0.7, "angle": 1.1 },
+					{ "time": 0.8, "angle": 6.09 },
+					{ "time": 0.9333, "angle": 2.28 },
+					{ "time": 1.0666, "angle": 3.6 }
+				]
+			}
+		}
+	}
+}
+}

+ 8 - 1
spine-starling/spine-starling-example/src/spineboy.json

@@ -54,7 +54,8 @@
 	{ "name": "goggles", "bone": "head", "attachment": "goggles" },
 	{ "name": "front_bracer", "bone": "front_bracer", "attachment": "front_bracer" },
 	{ "name": "front_fist", "bone": "front_fist", "attachment": "front_fist_closed" },
-	{ "name": "muzzle", "bone": "gunTip", "additive": true }
+	{ "name": "muzzle", "bone": "gunTip", "additive": true },
+	{ "name": "head-bb", "bone": "head" }
 ],
 "skins": {
 	"default": {
@@ -92,6 +93,12 @@
 		"head": {
 			"head": { "x": 128.95, "y": 0.29, "rotation": -70.63, "width": 271, "height": 298 }
 		},
+		"head-bb": {
+			"head": {
+				"type": "boundingbox",
+				"vertices": [ -19.143097, -70.30209, 40.80313, -118.074234, 257.77155, -115.61827, 285.16193, 57.18005, 120.77191, 164.95125, -5.067627, 76.94907 ]
+			}
+		},
 		"mouth": {
 			"mouth_grind": { "x": 23.68, "y": -32.23, "rotation": -70.63, "width": 93, "height": 59 },
 			"mouth_oooo": { "x": 23.68, "y": -32.23, "rotation": -70.63, "width": 93, "height": 59 },

二進制
spine-starling/spine-starling-example/src/spineboy.png


+ 1 - 1
spine-starling/spine-starling/.actionScriptProperties

@@ -10,7 +10,7 @@
         </excludedEntries>
       </libraryPathEntry>
       <libraryPathEntry kind="3" linkType="1" path="/spine-as3/bin/spine-as3.swc" useDefaultLinkType="false"/>
-      <libraryPathEntry kind="3" linkType="1" path="libs/starling-1.5rc.swc" useDefaultLinkType="false"/>
+      <libraryPathEntry kind="3" linkType="1" path="libs/starling-1.5.1.swc" useDefaultLinkType="false"/>
     </libraryPath>
     <sourceAttachmentPath/>
   </compiler>

二進制
spine-starling/spine-starling/libs/starling-1.5.1.swc


二進制
spine-starling/spine-starling/libs/starling-1.5rc.swc


+ 272 - 0
spine-starling/spine-starling/src/spine/starling/PolygonBatch.as

@@ -0,0 +1,272 @@
+/******************************************************************************
+ * Spine Runtimes Software License
+ * Version 2.1
+ * 
+ * Copyright (c) 2013, Esoteric Software
+ * All rights reserved.
+ * 
+ * You are granted a perpetual, non-exclusive, non-sublicensable and
+ * non-transferable license to install, execute and perform the Spine Runtimes
+ * Software (the "Software") solely for internal use. Without the written
+ * permission of Esoteric Software (typically granted by licensing Spine), you
+ * may not (a) modify, translate, adapt or otherwise create derivative works,
+ * improvements of the Software or develop new applications using the Software
+ * or (b) remove, delete, alter or obscure any trademarks or any copyright,
+ * trademark, patent or other intellectual property or proprietary rights
+ * notices on or in the Software, including any copy thereof. Redistributions
+ * in binary or source form must include this license and terms.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+package spine.starling {
+import flash.display3D.Context3D;
+import flash.display3D.Context3DProgramType;
+import flash.display3D.Context3DTextureFormat;
+import flash.display3D.Context3DVertexBufferFormat;
+import flash.display3D.IndexBuffer3D;
+import flash.display3D.Program3D;
+import flash.display3D.VertexBuffer3D;
+import flash.events.Event;
+import flash.geom.Matrix;
+import flash.geom.Point;
+import flash.utils.Dictionary;
+
+import starling.core.RenderSupport;
+import starling.core.Starling;
+import starling.display.BlendMode;
+import starling.textures.Texture;
+import starling.textures.TextureSmoothing;
+import starling.utils.MatrixUtil;
+import starling.utils.VertexData;
+
+internal class PolygonBatch {
+	static private var _tempPoint:Point = new Point();
+	static private var _renderAlpha:Vector.<Number> = new <Number>[1.0, 1.0, 1.0, 1.0];
+	static private var _programNameCache:Dictionary = new Dictionary();
+
+	private var _capacity:int;
+	public var maxCapacity:int = 2000;
+	public var smoothing:String = "bilinear";
+
+	private var _texture:Texture;
+	private var _support:RenderSupport;
+	private var _programBits:uint;
+	private var _blendMode:String;
+	private var _additive:Boolean;
+
+	private var _verticesCount:int;
+	private var _vertices:Vector.<Number> = new <Number>[];
+	private var _verticesBuffer:VertexBuffer3D;
+
+	private var _trianglesCount:int;
+	private var _triangles:Vector.<uint> = new <uint>[];
+	private var _trianglesBuffer:IndexBuffer3D;
+
+	public function PolygonBatch () {
+		resize(32);
+		Starling.current.stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreated, false, 0, true);
+	}
+
+	public function dispose () : void {
+		Starling.current.stage3D.removeEventListener(Event.CONTEXT3D_CREATE, onContextCreated);
+		if (_verticesBuffer) _verticesBuffer.dispose();
+		if (_trianglesBuffer) _trianglesBuffer.dispose();
+	}
+
+	public function begin (support:RenderSupport, alpha:Number, blendMode:String) : void {
+		_support = support;
+		_renderAlpha[3] = alpha;
+		_programBits = 0xffffffff;
+
+		support.finishQuadBatch();
+
+		support.blendMode = blendMode;
+		support.applyBlendMode(true);
+		_blendMode = support.blendMode;
+		_additive = false;
+
+		var context:Context3D = Starling.context;
+		context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 0, _renderAlpha, 1);
+		context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 1, support.mvpMatrix3D, true);
+
+		var verticesBuffer:VertexBuffer3D = _verticesBuffer;
+		if (verticesBuffer) {
+			context.setVertexBufferAt(0, verticesBuffer, VertexData.POSITION_OFFSET, Context3DVertexBufferFormat.FLOAT_2); 
+			context.setVertexBufferAt(1, verticesBuffer, VertexData.COLOR_OFFSET, Context3DVertexBufferFormat.FLOAT_4);		
+			context.setVertexBufferAt(2, verticesBuffer, VertexData.TEXCOORD_OFFSET, Context3DVertexBufferFormat.FLOAT_2);
+		}
+	}
+
+	public function end () : void {
+		flush();
+		var context:Context3D = Starling.context;
+		context.setTextureAt(0, null);
+		context.setVertexBufferAt(2, null);
+		context.setVertexBufferAt(1, null);
+		context.setVertexBufferAt(0, null);
+	}
+
+	public function add (texture:Texture, vertices:Vector.<Number>, vl:int, uvs:Vector.<Number>, triangles:Vector.<uint>,
+						 r:Number, g:Number, b:Number, a:Number, additive:Boolean, matrix:Matrix) : void {
+		if (additive != _additive) {
+			_additive = additive;
+			flush();
+			_support.blendMode = additive ? BlendMode.ADD : _blendMode;
+			_support.applyBlendMode(true);
+		}
+
+		if (texture != _texture) {
+			flush();
+			_texture = texture;
+		}
+
+		var tl:int = triangles.length;
+		var vc:int = _verticesCount, tc:int = _trianglesCount;
+		var firstVertex:int = vc >> 3;
+		if (firstVertex + (vl >> 1) > _capacity) resize(vl >> 1);
+		if (tc + tl > _triangles.length) resize(tl / 3);
+
+		var i:int, t:Vector.<uint> = _triangles;
+		for (i = 0; i < tl; i += 3, tc += 3) {
+			t[tc] = firstVertex + triangles[i];
+			t[int(tc + 1)] = firstVertex + triangles[int(i + 1)];
+			t[int(tc + 2)] = firstVertex + triangles[int(i + 2)];
+		}
+		_trianglesCount = tc;
+
+		var v:Vector.<Number> = _vertices;
+		if (matrix) {
+			var point:Point = _tempPoint;
+			for (i = 0; i < vl; i += 2, vc += 8) {
+				MatrixUtil.transformCoords(matrix, vertices[i], vertices[int(i + 1)], point);
+				v[vc] = point.x;
+				v[int(vc + 1)] = point.y;
+				v[int(vc + 2)] = r;
+				v[int(vc + 3)] = g;
+				v[int(vc + 4)] = b;
+				v[int(vc + 5)] = a;
+				v[int(vc + 6)] = uvs[i];
+				v[int(vc + 7)] = uvs[int(i + 1)];
+			}
+		} else {
+			for (i = 0; i < vl; i += 2, vc += 8) {
+				v[vc] = vertices[i];
+				v[int(vc + 1)] = vertices[int(i + 1)];
+				v[int(vc + 2)] = r;
+				v[int(vc + 3)] = g;
+				v[int(vc + 4)] = b;
+				v[int(vc + 5)] = a;
+				v[int(vc + 6)] = uvs[i];
+				v[int(vc + 7)] = uvs[int(i + 1)];
+			}
+		}
+		_verticesCount = vc;
+	}
+
+	private function resize (additional:int) : void {
+		var newCapacity:int = (_verticesCount >> 3) + additional;
+		if (newCapacity > maxCapacity) {
+			flush();
+			newCapacity = additional;
+			if (newCapacity < _capacity) return;
+			if (newCapacity > maxCapacity) throw new ArgumentError("Too many vertices: " + newCapacity + " > " + maxCapacity);
+		}
+		_capacity = newCapacity;		
+		_vertices.length = newCapacity << 3;
+		_triangles.length = newCapacity * 3;
+		_verticesBuffer = null;
+		_trianglesBuffer = null;	
+	}
+
+	public function flush () : void {
+		if (!_verticesCount) return;
+
+		var context:Context3D = Starling.context;
+
+		if (!_verticesBuffer) {
+			_verticesBuffer = context.createVertexBuffer(_capacity, 8);
+			var count:int = _verticesCount >> 3;
+			_verticesBuffer.uploadFromVector(_vertices, 0, count);
+			var verticesTemp:Vector.<Number> = new <Number>[]; // Buffer must be filled completely once.
+			verticesTemp.length = (_capacity << 3) - _verticesCount;
+			_verticesBuffer.uploadFromVector(verticesTemp, count, _capacity - count);
+			verticesTemp = null;
+
+			_trianglesBuffer = context.createIndexBuffer(_capacity * 3);
+			_trianglesBuffer.uploadFromVector(_triangles, 0, _trianglesCount);
+			var trianglesTemp:Vector.<uint> = new <uint>[]; // Buffer must be filled completely once.
+			trianglesTemp.length = _capacity * 3 - _trianglesCount;
+			_trianglesBuffer.uploadFromVector(trianglesTemp, _trianglesCount, trianglesTemp.length);
+			trianglesTemp = null;
+
+			context.setVertexBufferAt(0, _verticesBuffer, VertexData.POSITION_OFFSET, Context3DVertexBufferFormat.FLOAT_2); 
+			context.setVertexBufferAt(1, _verticesBuffer, VertexData.COLOR_OFFSET, Context3DVertexBufferFormat.FLOAT_4);		
+			context.setVertexBufferAt(2, _verticesBuffer, VertexData.TEXCOORD_OFFSET, Context3DVertexBufferFormat.FLOAT_2);
+		} else {
+			_verticesBuffer.uploadFromVector(_vertices, 0, _verticesCount >> 3);
+			_trianglesBuffer.uploadFromVector(_triangles, 0, _trianglesCount);
+		}
+
+		setProgram(context);
+		context.setTextureAt(0, _texture.base);
+		context.drawTriangles(_trianglesBuffer, 0, _trianglesCount / 3);
+
+		_verticesCount = 0;
+		_trianglesCount = 0;
+
+		_support.raiseDrawCount();
+	}
+
+	private function onContextCreated (event:Event) : void {
+		_verticesBuffer = null;
+		_trianglesBuffer = null;
+	}
+
+	private function setProgram (context:Context3D) : void {
+		var bits:uint = 0;
+		var texture:Texture = _texture;
+		if (texture.mipMapping) bits |= 1 << 1;
+		if (texture.repeat) bits |= 1 << 2;
+		if (smoothing != TextureSmoothing.BILINEAR) bits |= 1 << (smoothing == TextureSmoothing.TRILINEAR ? 3 : 4);
+		if (texture.format != Context3DTextureFormat.BGRA) bits |= 1 << (texture.format == "compressedAlpha" ? 5 : 6);
+		if (bits == _programBits) return;
+		_programBits = bits;
+
+		var name:String = _programNameCache[bits];
+		if (name == null) {
+			name = "PB_i." + bits.toString(16);
+			_programNameCache[bits] = name;
+		}
+
+		var program:Program3D = Starling.current.getProgram(name);
+		if (!program) {
+			// va0 -> position
+			// va1 -> color
+			// va2 -> texCoords
+			// vc0 -> alpha
+			// vc1 -> mvpMatrix
+			// fs0 -> texture
+			var vertexShader:String = 
+				"m44 op, va0, vc1 \n" + // 4x4 matrix transform to output clipspace
+				"mul v0, va1, vc0 \n" + // multiply alpha (vc0) with color (va1)
+				"mov v1, va2 \n"; // pass texture coordinates to fragment program
+			var flags:String = RenderSupport.getTextureLookupFlags(texture.format, texture.mipMapping, texture.repeat, smoothing);
+			var fragmentShader:String = 
+				"tex ft1, v1, fs0 " + flags + " \n" + // sample texture 0
+				"mul oc, ft1, v0 \n"; // multiply color with texel color
+			Starling.current.registerProgramFromSource(name, vertexShader, fragmentShader);
+		}
+		context.setProgram(program);
+	}
+}
+}

+ 12 - 8
spine-starling/spine-starling/src/spine/starling/SkeletonAnimation.as

@@ -29,23 +29,27 @@
  *****************************************************************************/
 
 package spine.starling {
+import spine.SkeletonData;
 import spine.animation.AnimationState;
 import spine.animation.AnimationStateData;
-import spine.SkeletonData;
 
-public class SkeletonAnimation extends SkeletonSprite {
+import starling.animation.IAnimatable;
+
+public class SkeletonAnimation extends SkeletonSprite implements IAnimatable {
 	public var state:AnimationState;
-	
-	public function SkeletonAnimation (skeletonData:SkeletonData, stateData:AnimationStateData = null) {
-		super(skeletonData);
+	public var timeScale:Number = 1;
+
+	public function SkeletonAnimation (skeletonData:SkeletonData, renderMeshes:Boolean = false, stateData:AnimationStateData = null) {
+		super(skeletonData, renderMeshes);
 		state = new AnimationState(stateData ? stateData : new AnimationStateData(skeletonData));
 	}
-	
-	override public function advanceTime (time:Number) : void {
+
+	public function advanceTime (time:Number) : void {
+		time *= timeScale;
+		skeleton.update(time);
 		state.update(time);
 		state.apply(skeleton);
 		skeleton.updateWorldTransform();
-		super.advanceTime(time);
 	}
 }
 

+ 160 - 93
spine-starling/spine-starling/src/spine/starling/SkeletonSprite.as

@@ -29,6 +29,8 @@
  *****************************************************************************/
 
 package spine.starling {
+import flash.display3D.Context3D;
+import flash.display3D.textures.Texture;
 import flash.geom.Matrix;
 import flash.geom.Point;
 import flash.geom.Rectangle;
@@ -37,79 +39,172 @@ import spine.Bone;
 import spine.Skeleton;
 import spine.SkeletonData;
 import spine.Slot;
-import spine.atlas.AtlasPage;
 import spine.atlas.AtlasRegion;
+import spine.attachments.Attachment;
+import spine.attachments.MeshAttachment;
 import spine.attachments.RegionAttachment;
+import spine.attachments.SkinnedMeshAttachment;
 
-import starling.animation.IAnimatable;
 import starling.core.RenderSupport;
+import starling.core.Starling;
 import starling.display.BlendMode;
 import starling.display.DisplayObject;
 import starling.utils.Color;
 import starling.utils.MatrixUtil;
 import starling.utils.VertexData;
 
-public class SkeletonSprite extends DisplayObject implements IAnimatable {
-	static private var tempPoint:Point = new Point();
-	static private var tempMatrix:Matrix = new Matrix();
-	static private var tempVertices:Vector.<Number> = new Vector.<Number>(8);
+public class SkeletonSprite extends DisplayObject {
+	static private var _tempPoint:Point = new Point();
+	static private var _tempMatrix:Matrix = new Matrix();
+	static private var _tempVertices:Vector.<Number> = new Vector.<Number>(8);
+	static private var _quadTriangles:Vector.<uint> = new <uint>[0, 1, 2, 2, 3, 0];
 
 	private var _skeleton:Skeleton;
+	private var _renderMeshes:Boolean;
+	private var _polygonBatch:PolygonBatch;
+	public var batchable:Boolean = true;
+	private var _batched:Boolean;
 
-	public function SkeletonSprite (skeletonData:SkeletonData) {
+	public function SkeletonSprite (skeletonData:SkeletonData, renderMeshes:Boolean = false) {
 		Bone.yDown = true;
 
+		_renderMeshes = renderMeshes;
+		if (renderMeshes) _polygonBatch = new PolygonBatch();
+
 		_skeleton = new Skeleton(skeletonData);
 		_skeleton.updateWorldTransform();
 	}
 
-	public function advanceTime (delta:Number) : void {
-		_skeleton.update(delta);
-	}
-
 	override public function render (support:RenderSupport, alpha:Number) : void {
 		alpha *= this.alpha * skeleton.a;
+		if (_renderMeshes)
+			renderMeshes(support, alpha);
+		else
+			renderRegions(support, alpha);
+	}
+
+	private function renderMeshes (support:RenderSupport, alpha:Number) : void {
+		if (!batchable) {
+			_polygonBatch.begin(support, alpha, blendMode);
+			addToBatch(_polygonBatch, support, alpha, null);
+			_polygonBatch.end();
+		} else if (!_batched) {
+			support.popMatrix();
+			_polygonBatch.begin(support, alpha, blendMode);
+			addToBatch(_polygonBatch, support, alpha, transformationMatrix);
+			for(var i:int = parent.getChildIndex(this) + 1, n:int = parent.numChildren; i < n; ++i) {
+				var skeletonSprite:SkeletonSprite = parent.getChildAt(i) as SkeletonSprite;
+				if (!skeletonSprite || !skeletonSprite.batchable || skeletonSprite.blendMode != blendMode) break;
+				skeletonSprite._batched = true;
+				skeletonSprite.addToBatch(_polygonBatch, support, alpha, skeletonSprite.transformationMatrix);
+			}
+			_polygonBatch.end();
+			support.pushMatrix();
+			support.transformMatrix(this);
+		} else
+			_batched = false;
+	}
+
+	private function addToBatch (polygonBatch:PolygonBatch, support:RenderSupport, skeletonA:Number, matrix:Matrix) : void {
+		var skeletonR:Number = skeleton.r;
+		var skeletonG:Number = skeleton.g;
+		var skeletonB:Number = skeleton.b;
+		var x:Number = skeleton.x;
+		var y:Number = skeleton.y;
+		var worldVertices:Vector.<Number> = _tempVertices;
+		var drawOrder:Vector.<Slot> = skeleton.drawOrder;
+		for (var i:int = 0, n:int = drawOrder.length; i < n; ++i) {
+			var slot:Slot = drawOrder[i];
+			var attachment:Attachment = slot.attachment;
+			if (!attachment) continue;
+			var image:SkeletonImage, verticesLength:int, uvs:Vector.<Number>, triangles:Vector.<uint>;
+			var r:Number, g:Number, b:Number, a:Number;
+			if (attachment is RegionAttachment) {
+				var region:RegionAttachment = RegionAttachment(slot.attachment);
+				verticesLength = 8;
+				region.computeWorldVertices(x, y, slot.bone, worldVertices);
+				uvs = region.uvs;
+				triangles = _quadTriangles;
+				r = region.r;
+				g = region.g;
+				b = region.b;
+				a = region.a;
+				image = region.rendererObject as SkeletonImage;
+				if (image == null) region.rendererObject = image = SkeletonImage(AtlasRegion(region.rendererObject).rendererObject);
+			} else if (attachment is MeshAttachment) {
+				var mesh:MeshAttachment = MeshAttachment(attachment);
+				verticesLength = mesh.vertices.length;
+				if (worldVertices.length < verticesLength) worldVertices.length = verticesLength;
+				mesh.computeWorldVertices(x, y, slot, worldVertices);
+				uvs = mesh.uvs;
+				triangles = mesh.triangles;
+				r = mesh.r;
+				g = mesh.g;
+				b = mesh.b;
+				a = mesh.a;
+				image = mesh.rendererObject as SkeletonImage;
+				if (image == null) mesh.rendererObject = image = SkeletonImage(AtlasRegion(mesh.rendererObject).rendererObject);
+			} else if (attachment is SkinnedMeshAttachment) {
+				var skinnedMesh:SkinnedMeshAttachment = SkinnedMeshAttachment(attachment);
+				verticesLength = skinnedMesh.uvs.length;
+				if (worldVertices.length < verticesLength) worldVertices.length = verticesLength;
+				skinnedMesh.computeWorldVertices(x, y, slot, worldVertices);
+				uvs = skinnedMesh.uvs;
+				triangles = skinnedMesh.triangles;
+				r = skinnedMesh.r;
+				g = skinnedMesh.g;
+				b = skinnedMesh.b;
+				a = skinnedMesh.a;
+				image = skinnedMesh.rendererObject as SkeletonImage;
+				if (image == null) skinnedMesh.rendererObject = image = SkeletonImage(AtlasRegion(skinnedMesh.rendererObject).rendererObject);
+			}
+			if (image) {
+				a *= skeletonA * slot.a;
+				r *= skeletonR * slot.r * a;
+				g *= skeletonG * slot.g * a;
+				b *= skeletonB * slot.b * a;
+				polygonBatch.add(image.texture, worldVertices, verticesLength, uvs, triangles, r, g, b, a, slot.data.additiveBlending, matrix);
+			}
+		}
+	}
+
+	private function renderRegions (support:RenderSupport, alpha:Number) : void {
 		var r:Number = skeleton.r * 255;
 		var g:Number = skeleton.g * 255;
 		var b:Number = skeleton.b * 255;
 		var x:Number = skeleton.x;
 		var y:Number = skeleton.y;
 		var drawOrder:Vector.<Slot> = skeleton.drawOrder;
-		for (var i:int = 0, n:int = drawOrder.length; i < n; i++) {
+		var worldVertices:Vector.<Number> = _tempVertices;
+		for (var i:int = 0, n:int = drawOrder.length; i < n; ++i) {
 			var slot:Slot = drawOrder[i];
-			var regionAttachment:RegionAttachment = slot.attachment as RegionAttachment;
-			if (regionAttachment != null) {
-				var vertices:Vector.<Number> = tempVertices;
-				regionAttachment.computeWorldVertices(x, y, slot.bone, vertices);
-				var a:Number = slot.a * regionAttachment.a;
+			var region:RegionAttachment = slot.attachment as RegionAttachment;
+			if (region != null) {
+				region.computeWorldVertices(x, y, slot.bone, worldVertices);
+				var a:Number = slot.a * region.a;
 				var rgb:uint = Color.rgb(
-					r * slot.r * regionAttachment.r,
-					g * slot.g * regionAttachment.g,
-					b * slot.b * regionAttachment.b);
+					r * slot.r * region.r,
+					g * slot.g * region.g,
+					b * slot.b * region.b);
 
-				var image:SkeletonImage;
-				image = regionAttachment.rendererObject as SkeletonImage;
-				if (image == null) {
-					image = SkeletonImage(AtlasRegion(regionAttachment.rendererObject).rendererObject);
-					regionAttachment.rendererObject = image;
-				}
+				var image:SkeletonImage = region.rendererObject as SkeletonImage;
+				if (image == null) region.rendererObject = image = SkeletonImage(AtlasRegion(region.rendererObject).rendererObject);
 
 				var vertexData:VertexData = image.vertexData;
-
-				vertexData.setPosition(0, vertices[2], vertices[3]);
+				vertexData.setPosition(0, worldVertices[2], worldVertices[3]);
 				vertexData.setColorAndAlpha(0, rgb, a);
-
-				vertexData.setPosition(1, vertices[4], vertices[5]);
+				
+				vertexData.setPosition(1, worldVertices[4], worldVertices[5]);
 				vertexData.setColorAndAlpha(1, rgb, a);
 				
-				vertexData.setPosition(2, vertices[0], vertices[1]);
+				vertexData.setPosition(2, worldVertices[0], worldVertices[1]);
 				vertexData.setColorAndAlpha(2, rgb, a);
-
-				vertexData.setPosition(3, vertices[6], vertices[7]);
+				
+				vertexData.setPosition(3, worldVertices[6], worldVertices[7]);
 				vertexData.setColorAndAlpha(3, rgb, a);
-
+				
 				image.updateVertices();
-				support.blendMode = slot.data.additiveBlending ? BlendMode.ADD : BlendMode.NORMAL;
+				support.blendMode = slot.data.additiveBlending ? BlendMode.ADD : blendMode;
 				support.batchQuad(image, alpha, image.texture);
 			}
 		}
@@ -122,63 +217,35 @@ public class SkeletonSprite extends DisplayObject implements IAnimatable {
 		var minX:Number = Number.MAX_VALUE, minY:Number = Number.MAX_VALUE;
 		var maxX:Number = Number.MIN_VALUE, maxY:Number = Number.MIN_VALUE;
 		var slots:Vector.<Slot> = skeleton.slots;
-		var value:Number;
-		for (var i:int = 0, n:int = slots.length; i < n; i++) {
+		var worldVertices:Vector.<Number> = _tempVertices;
+		for (var i:int = 0, n:int = slots.length; i < n; ++i) {
 			var slot:Slot = slots[i];
-			var regionAttachment:RegionAttachment = slot.attachment as RegionAttachment;
-			if (!regionAttachment)
+			var attachment:Attachment = slot.attachment;
+			if (!attachment) continue;
+			var verticesLength:int;
+			if (attachment is RegionAttachment) {
+				var region:RegionAttachment = RegionAttachment(slot.attachment);
+				verticesLength = 8;
+				region.computeWorldVertices(0, 0, slot.bone, worldVertices);
+			} else if (attachment is MeshAttachment) {
+				var mesh:MeshAttachment = MeshAttachment(attachment);
+				verticesLength = mesh.vertices.length;
+				if (worldVertices.length < verticesLength) worldVertices.length = verticesLength;
+				mesh.computeWorldVertices(0, 0, slot, worldVertices);
+			} else if (attachment is SkinnedMeshAttachment) {
+				var skinnedMesh:SkinnedMeshAttachment = SkinnedMeshAttachment(attachment);
+				verticesLength = skinnedMesh.uvs.length;
+				if (worldVertices.length < verticesLength) worldVertices.length = verticesLength;
+				skinnedMesh.computeWorldVertices(0, 0, slot, worldVertices);
+			} else
 				continue;
-
-			var vertices:Vector.<Number> = tempVertices;
-			regionAttachment.computeWorldVertices(skeleton.x, skeleton.y, slot.bone, vertices);
-
-			value = vertices[0];
-			if (value < minX)
-				minX = value;
-			if (value > maxX)
-				maxX = value;
-
-			value = vertices[1];
-			if (value < minY)
-				minY = value;
-			if (value > maxY)
-				maxY = value;
-
-			value = vertices[2];
-			if (value < minX)
-				minX = value;
-			if (value > maxX)
-				maxX = value;
-
-			value = vertices[3];
-			if (value < minY)
-				minY = value;
-			if (value > maxY)
-				maxY = value;
-
-			value = vertices[4];
-			if (value < minX)
-				minX = value;
-			if (value > maxX)
-				maxX = value;
-
-			value = vertices[5];
-			if (value < minY)
-				minY = value;
-			if (value > maxY)
-				maxY = value;
-
-			value = vertices[6];
-			if (value < minX)
-				minX = value;
-			if (value > maxX)
-				maxX = value;
-
-			value = vertices[7];
-			if (value < minY)
-				minY = value;
-			if (value > maxY)
-				maxY = value;
+			for (var ii:int = 0; ii < verticesLength; ii += 2) {
+				var x:Number = worldVertices[ii], y:Number = worldVertices[ii + 1];
+				minX = Math.min(minX, x);
+				minY = Math.min(minY, y);
+				maxX = Math.max(maxX, x);
+				maxY = Math.max(maxY, y);
+			}
 		}
 
 		minX *= scaleX;
@@ -211,9 +278,9 @@ public class SkeletonSprite extends DisplayObject implements IAnimatable {
 		else if (targetSpace == parent)
 			resultRect.setTo(x, y, 0, 0);
 		else {
-			getTransformationMatrix(targetSpace, tempMatrix);
-			MatrixUtil.transformCoords(tempMatrix, 0, 0, tempPoint);
-			resultRect.setTo(tempPoint.x, tempPoint.y, 0, 0);
+			getTransformationMatrix(targetSpace, _tempMatrix);
+			MatrixUtil.transformCoords(_tempMatrix, 0, 0, _tempPoint);
+			resultRect.setTo(_tempPoint.x, _tempPoint.y, 0, 0);
 		}
 		return resultRect;
 	}