Procházet zdrojové kódy

Refactoring: changed references to "bind pose" to "setup pose".

This better matches "setup mode" in the editor and we can be consistent in code and docs from now on.
NathanSweet před 12 roky
rodič
revize
7f69300bcc
35 změnil soubory, kde provedl 1203 přidání a 98 odebrání
  1. 2 2
      spine-as3/spine-as3/src/spine/Bone.as
  2. 8 8
      spine-as3/spine-as3/src/spine/Skeleton.as
  3. 1 1
      spine-as3/spine-as3/src/spine/SkeletonData.as
  4. 2 2
      spine-as3/spine-as3/src/spine/Slot.as
  5. 1 1
      spine-c/include/spine/Bone.h
  6. 3 3
      spine-c/include/spine/Skeleton.h
  7. 1 1
      spine-c/include/spine/Slot.h
  8. 1 1
      spine-c/include/spine/SlotData.h
  9. 2 2
      spine-c/src/spine/Bone.c
  10. 7 7
      spine-c/src/spine/Skeleton.c
  11. 2 2
      spine-c/src/spine/Slot.c
  12. 3 3
      spine-cocos2d-iphone/src/spine/CCSkeleton.h
  13. 6 6
      spine-cocos2d-iphone/src/spine/CCSkeleton.m
  14. 6 6
      spine-cocos2dx/src/spine/CCSkeleton.cpp
  15. 3 3
      spine-cocos2dx/src/spine/CCSkeleton.h
  16. 1 1
      spine-corona/main.lua
  17. 2 2
      spine-csharp/src/Bone.cs
  18. 8 8
      spine-csharp/src/Skeleton.cs
  19. 1 1
      spine-csharp/src/SkeletonData.cs
  20. 4 4
      spine-csharp/src/Slot.cs
  21. 1 0
      spine-js/index.html
  22. 1104 0
      spine-js/spine.js
  23. 2 2
      spine-libgdx/src/com/esotericsoftware/spine/Bone.java
  24. 8 8
      spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java
  25. 1 1
      spine-libgdx/src/com/esotericsoftware/spine/SkeletonData.java
  26. 4 4
      spine-libgdx/src/com/esotericsoftware/spine/Slot.java
  27. 1 1
      spine-libgdx/test/com/esotericsoftware/spine/MixTest.java
  28. 2 2
      spine-libgdx/test/com/esotericsoftware/spine/SkeletonTest.java
  29. 1 1
      spine-love/main.lua
  30. 1 1
      spine-lua/Bone.lua
  31. 7 7
      spine-lua/Skeleton.lua
  32. 2 2
      spine-lua/Slot.lua
  33. 2 2
      spine-sfml/example/main.cpp
  34. 2 2
      spine-unity/Assets/Plugins/Spine/SkeletonComponent.cs
  35. 1 1
      spine-xna/example/src/ExampleGame.cs

+ 2 - 2
spine-as3/spine-as3/src/spine/Bone.as

@@ -27,7 +27,7 @@ public class Bone {
 			throw new ArgumentError("data cannot be null.");
 		_data = data;
 		_parent = parent;
-		setToBindPose();
+		setToSetupPose();
 	}
 
 	/** Computes the world SRT using the parent bone and the local SRT. */
@@ -66,7 +66,7 @@ public class Bone {
 		}
 	}
 
-	public function setToBindPose () : void {
+	public function setToSetupPose () : void {
 		x = _data.x;
 		y = _data.y;
 		rotation = _data.rotation;

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

@@ -42,20 +42,20 @@ public class Skeleton {
 			bone.updateWorldTransform(flipX, flipY);
 	}
 
-	/** Sets the bones and slots to their bind pose values. */
-	public function setToBindPose () : void {
-		setBonesToBindPose();
-		setSlotsToBindPose();
+	/** Sets the bones and slots to their setup pose values. */
+	public function setToSetupPose () : void {
+		setBonesToSetupPose();
+		setSlotsToSetupPose();
 	}
 
-	public function setBonesToBindPose () : void {
+	public function setBonesToSetupPose () : void {
 		for each (var bone:Bone in _bones)
-			bone.setToBindPose();
+			bone.setToSetupPose();
 	}
 
-	public function setSlotsToBindPose () : void {
+	public function setSlotsToSetupPose () : void {
 		for each (var slot:Slot in _slots)
-			slot.setToBindPose();
+			slot.setToSetupPose();
 	}
 
 	public function get data () : SkeletonData {

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

@@ -4,7 +4,7 @@ import spine.animation.Animation;
 public class SkeletonData {
 	public var name:String;
 	public var bones:Vector.<BoneData> = new Vector.<BoneData>(); // Ordered parents first.
-	public var slots:Vector.<SlotData> = new Vector.<SlotData>(); // Bind pose draw order.
+	public var slots:Vector.<SlotData> = new Vector.<SlotData>(); // Setup pose draw order.
 	public var skins:Vector.<Skin> = new Vector.<Skin>();
 	public var defaultSkin:Skin;
 	public var animations:Vector.<Animation> = new Vector.<Animation>();

+ 2 - 2
spine-as3/spine-as3/src/spine/Slot.as

@@ -22,7 +22,7 @@ public class Slot {
 		_data = data;
 		_skeleton = skeleton;
 		_bone = bone;
-		setToBindPose();
+		setToSetupPose();
 	}
 
 	public function get data () : SlotData {
@@ -58,7 +58,7 @@ public class Slot {
 		return skeleton.time - _attachmentTime;
 	}
 
-	public function setToBindPose () : void {
+	public function setToSetupPose () : void {
 		var slotIndex:int = skeleton.data.slots.indexOf(data);
 		r = _data.r;
 		g = _data.g;

+ 1 - 1
spine-c/include/spine/Bone.h

@@ -53,7 +53,7 @@ void Bone_setYDown (int/*bool*/yDown);
 Bone* Bone_create (BoneData* data, Bone* parent);
 void Bone_dispose (Bone* self);
 
-void Bone_setToBindPose (Bone* self);
+void Bone_setToSetupPose (Bone* self);
 
 void Bone_updateWorldTransform (Bone* self, int/*bool*/flipX, int/*bool*/flipY);
 

+ 3 - 3
spine-c/include/spine/Skeleton.h

@@ -58,9 +58,9 @@ void Skeleton_dispose (Skeleton* self);
 
 void Skeleton_updateWorldTransform (const Skeleton* self);
 
-void Skeleton_setToBindPose (const Skeleton* self);
-void Skeleton_setBonesToBindPose (const Skeleton* self);
-void Skeleton_setSlotsToBindPose (const Skeleton* self);
+void Skeleton_setToSetupPose (const Skeleton* self);
+void Skeleton_setBonesToSetupPose (const Skeleton* self);
+void Skeleton_setSlotsToSetupPose (const Skeleton* self);
 
 /* Returns 0 if the bone was not found. */
 Bone* Skeleton_findBone (const Skeleton* self, const char* boneName);

+ 1 - 1
spine-c/include/spine/Slot.h

@@ -54,7 +54,7 @@ void Slot_setAttachment (Slot* self, Attachment* attachment);
 void Slot_setAttachmentTime (Slot* self, float time);
 float Slot_getAttachmentTime (const Slot* self);
 
-void Slot_setToBindPose (Slot* self);
+void Slot_setToSetupPose (Slot* self);
 
 #ifdef __cplusplus
 }

+ 1 - 1
spine-c/include/spine/SlotData.h

@@ -43,7 +43,7 @@ typedef struct {
 SlotData* SlotData_create (const char* name, BoneData* boneData);
 void SlotData_dispose (SlotData* self);
 
-/* @param attachmentName May be 0 for no bind pose attachment. */
+/* @param attachmentName May be 0 for no setup pose attachment. */
 void SlotData_setAttachmentName (SlotData* self, const char* attachmentName);
 
 #ifdef __cplusplus

+ 2 - 2
spine-c/src/spine/Bone.c

@@ -41,7 +41,7 @@ Bone* Bone_create (BoneData* data, Bone* parent) {
 	Bone* self = NEW(Bone);
 	CONST_CAST(BoneData*, self->data) = data;
 	CONST_CAST(Bone*, self->parent) = parent;
-	Bone_setToBindPose(self);
+	Bone_setToSetupPose(self);
 	return self;
 }
 
@@ -49,7 +49,7 @@ void Bone_dispose (Bone* self) {
 	FREE(self);
 }
 
-void Bone_setToBindPose (Bone* self) {
+void Bone_setToSetupPose (Bone* self) {
 	self->x = self->data->x;
 	self->y = self->data->y;
 	self->rotation = self->data->rotation;

+ 7 - 7
spine-c/src/spine/Skeleton.c

@@ -104,21 +104,21 @@ void Skeleton_updateWorldTransform (const Skeleton* self) {
 		Bone_updateWorldTransform(self->bones[i], self->flipX, self->flipY);
 }
 
-void Skeleton_setToBindPose (const Skeleton* self) {
-	Skeleton_setBonesToBindPose(self);
-	Skeleton_setSlotsToBindPose(self);
+void Skeleton_setToSetupPose (const Skeleton* self) {
+	Skeleton_setBonesToSetupPose(self);
+	Skeleton_setSlotsToSetupPose(self);
 }
 
-void Skeleton_setBonesToBindPose (const Skeleton* self) {
+void Skeleton_setBonesToSetupPose (const Skeleton* self) {
 	int i;
 	for (i = 0; i < self->boneCount; ++i)
-		Bone_setToBindPose(self->bones[i]);
+		Bone_setToSetupPose(self->bones[i]);
 }
 
-void Skeleton_setSlotsToBindPose (const Skeleton* self) {
+void Skeleton_setSlotsToSetupPose (const Skeleton* self) {
 	int i;
 	for (i = 0; i < self->slotCount; ++i)
-		Slot_setToBindPose(self->slots[i]);
+		Slot_setToSetupPose(self->slots[i]);
 }
 
 Bone* Skeleton_findBone (const Skeleton* self, const char* boneName) {

+ 2 - 2
spine-c/src/spine/Slot.c

@@ -41,7 +41,7 @@ Slot* Slot_create (SlotData* data, Skeleton* skeleton, Bone* bone) {
 	CONST_CAST(SlotData*, self->data) = data;
 	CONST_CAST(Skeleton*, self->skeleton) = skeleton;
 	CONST_CAST(Bone*, self->bone) = bone;
-	Slot_setToBindPose(self);
+	Slot_setToSetupPose(self);
 	return self;
 }
 
@@ -62,7 +62,7 @@ float Slot_getAttachmentTime (const Slot* self) {
 	return self->skeleton->time - SUB_CAST(_Internal, self) ->attachmentTime;
 }
 
-void Slot_setToBindPose (Slot* self) {
+void Slot_setToSetupPose (Slot* self) {
 	Attachment* attachment = 0;
 	self->r = self->data->r;
 	self->g = self->data->g;

+ 3 - 3
spine-cocos2d-iphone/src/spine/CCSkeleton.h

@@ -56,9 +56,9 @@ Draws a skeleton.
 // --- Convenience methods for common Skeleton_* functions.
 - (void) updateWorldTransform;
 
-- (void) setToBindPose;
-- (void) setBonesToBindPose;
-- (void) setSlotsToBindPose;
+- (void) setToSetupPose;
+- (void) setBonesToSetupPose;
+- (void) setSlotsToSetupPose;
 
 /* Returns 0 if the bone was not found. */
 - (Bone*) findBone:(NSString*)boneName;

+ 6 - 6
spine-cocos2d-iphone/src/spine/CCSkeleton.m

@@ -240,14 +240,14 @@
 	Skeleton_updateWorldTransform(_skeleton);
 }
 
-- (void) setToBindPose {
-	Skeleton_setToBindPose(_skeleton);
+- (void) setToSetupPose {
+	Skeleton_setToSetupPose(_skeleton);
 }
-- (void) setBonesToBindPose {
-	Skeleton_setBonesToBindPose(_skeleton);
+- (void) setBonesToSetupPose {
+	Skeleton_setBonesToSetupPose(_skeleton);
 }
-- (void) setSlotsToBindPose {
-	Skeleton_setSlotsToBindPose(_skeleton);
+- (void) setSlotsToSetupPose {
+	Skeleton_setSlotsToSetupPose(_skeleton);
 }
 
 - (Bone*) findBone:(NSString*)boneName {

+ 6 - 6
spine-cocos2dx/src/spine/CCSkeleton.cpp

@@ -229,14 +229,14 @@ void CCSkeleton::updateWorldTransform () {
 	Skeleton_updateWorldTransform(skeleton);
 }
 
-void CCSkeleton::setToBindPose () {
-	Skeleton_setToBindPose(skeleton);
+void CCSkeleton::setToSetupPose () {
+	Skeleton_setToSetupPose(skeleton);
 }
-void CCSkeleton::setBonesToBindPose () {
-	Skeleton_setBonesToBindPose(skeleton);
+void CCSkeleton::setBonesToSetupPose () {
+	Skeleton_setBonesToSetupPose(skeleton);
 }
-void CCSkeleton::setSlotsToBindPose () {
-	Skeleton_setSlotsToBindPose(skeleton);
+void CCSkeleton::setSlotsToSetupPose () {
+	Skeleton_setSlotsToSetupPose(skeleton);
 }
 
 Bone* CCSkeleton::findBone (const char* boneName) const {

+ 3 - 3
spine-cocos2dx/src/spine/CCSkeleton.h

@@ -59,9 +59,9 @@ public:
 	// --- Convenience methods for common Skeleton_* functions.
 	void updateWorldTransform ();
 
-	void setToBindPose ();
-	void setBonesToBindPose ();
-	void setSlotsToBindPose ();
+	void setToSetupPose ();
+	void setBonesToSetupPose ();
+	void setSlotsToSetupPose ();
 
 	/* Returns 0 if the bone was not found. */
 	Bone* findBone (const char* boneName) const;

+ 1 - 1
spine-corona/main.lua

@@ -20,7 +20,7 @@ skeleton.flipX = false
 skeleton.flipY = false
 skeleton.debug = true -- Omit or set to false to not draw debug lines on top of the images.
 if name == "goblins" then skeleton:setSkin("goblingirl") end
-skeleton:setToBindPose()
+skeleton:setToSetupPose()
 
 local lastTime = 0
 local animationTime = 0

+ 2 - 2
spine-csharp/src/Bone.cs

@@ -52,7 +52,7 @@ namespace Spine {
 			if (data == null) throw new ArgumentNullException("data cannot be null.");
 			Data = data;
 			Parent = parent;
-			SetToBindPose();
+			SetToSetupPose();
 		}
 
 		/** Computes the world SRT using the parent bone and the local SRT. */
@@ -92,7 +92,7 @@ namespace Spine {
 			}
 		}
 
-		public void SetToBindPose () {
+		public void SetToSetupPose () {
 			BoneData data = Data;
 			X = data.X;
 			Y = data.Y;

+ 8 - 8
spine-csharp/src/Skeleton.cs

@@ -80,22 +80,22 @@ namespace Spine {
 				bones[i].UpdateWorldTransform(flipX, flipY);
 		}
 
-		/** Sets the bones and slots to their bind pose values. */
-		public void SetToBindPose () {
-			SetBonesToBindPose();
-			SetSlotsToBindPose();
+		/** Sets the bones and slots to their setup pose values. */
+		public void SetToSetupPose () {
+			SetBonesToSetupPose();
+			SetSlotsToSetupPose();
 		}
 
-		public void SetBonesToBindPose () {
+		public void SetBonesToSetupPose () {
 			List<Bone> bones = this.Bones;
 			for (int i = 0, n = bones.Count; i < n; i++)
-				bones[i].SetToBindPose();
+				bones[i].SetToSetupPose();
 		}
 
-		public void SetSlotsToBindPose () {
+		public void SetSlotsToSetupPose () {
 			List<Slot> slots = this.Slots;
 			for (int i = 0, n = slots.Count; i < n; i++)
-				slots[i].SetToBindPose(i);
+				slots[i].SetToSetupPose(i);
 		}
 
 		/** @return May be null. */

+ 1 - 1
spine-csharp/src/SkeletonData.cs

@@ -30,7 +30,7 @@ namespace Spine {
 	public class SkeletonData {
 		public String Name { get; set; }
 		public List<BoneData> Bones { get; private set; } // Ordered parents first.
-		public List<SlotData> Slots { get; private set; } // Bind pose draw order.
+		public List<SlotData> Slots { get; private set; } // Setup pose draw order.
 		public List<Skin> Skins { get; private set; }
 		/** May be null. */
 		public Skin DefaultSkin;

+ 4 - 4
spine-csharp/src/Slot.cs

@@ -64,10 +64,10 @@ namespace Spine {
 			Data = data;
 			Skeleton = skeleton;
 			Bone = bone;
-			SetToBindPose();
+			SetToSetupPose();
 		}
 
-		internal void SetToBindPose (int slotIndex) {
+		internal void SetToSetupPose (int slotIndex) {
 			R = Data.R;
 			G = Data.G;
 			B = Data.B;
@@ -75,8 +75,8 @@ namespace Spine {
 			Attachment = Data.AttachmentName == null ? null : Skeleton.GetAttachment(slotIndex, Data.AttachmentName);
 		}
 
-		public void SetToBindPose () {
-			SetToBindPose(Skeleton.Data.Slots.IndexOf(Data));
+		public void SetToSetupPose () {
+			SetToSetupPose(Skeleton.Data.Slots.IndexOf(Data));
 		}
 
 		override public String ToString () {

+ 1 - 0
spine-js/index.html

@@ -0,0 +1 @@
+<script src="spine.js"></script>

+ 1104 - 0
spine-js/spine.js

@@ -0,0 +1,1104 @@
+
+var spine = {};
+
+spine.BoneData = function (name, parent) {
+	this.name = name;
+	this.parent = parent;
+};
+spine.BoneData.prototype = {
+	length: 0,
+	x: 0, y: 0,
+	rotation: 0,
+	scaleX: 1, scaleY: 1
+};
+
+spine.SlotData = function (name, boneData) {
+	this.name = name;
+	this.boneData = boneData;
+};
+spine.SlotData.prototype = {
+	r: 1, g: 1, b: 1, a: 1,
+	attachmentName: null
+};
+
+spine.Bone = function (boneData, parent) {
+	this.data = boneData;
+	this.parent = parent;
+};
+spine.Bone.yDown = false;
+spine.Bone.prototype = {
+	x: 0, y: 0,
+	rotation: 0,
+	scaleX: 1, scaleY: 1,
+	m00: 0, m01: 0, worldX: 0, // a b x
+	m10: 0, m11: 0, worldY: 0, // c d y
+	worldRotation: 0,
+	worldScaleX: 1, worldScaleY: 1,
+	updateWorldTransform: function (flipX, flipY) {
+		var parent = this.parent;
+		if (parent != null) {
+			this.worldX = this.x * parent.m00 + this.y * parent.m01 + parent.worldX;
+			this.worldY = this.x * parent.m10 + this.y * parent.m11 + parent.worldY;
+			this.worldScaleX = parent.worldScaleX * this.scaleX;
+			this.worldScaleY = parent.worldScaleY * this.scaleY;
+			this.worldRotation = parent.worldRotation + this.rotation;
+		} else {
+			this.worldX = this.x;
+			this.worldY = this.y;
+			this.worldScaleX = this.scaleX;
+			this.worldScaleY = this.scaleY;
+			this.worldRotation = this.rotation;
+		}
+		var cos = worldRotation * Math.PI / 180;
+		var sin = worldRotation * Math.PI / 180;
+		this.m00 = cos * this.worldScaleX;
+		this.m10 = sin * this.worldScaleX;
+		this.m01 = -sin * this.worldScaleY;
+		this.m11 = cos * this.worldScaleY;
+		if (flipX) {
+			this.m00 = -this.m00;
+			this.m01 = -this.m01;
+		}
+		if (flipY) {
+			this.m10 = -this.m10;
+			this.m11 = -this.m11;
+		}
+		if (spine.Bone.yDown) {
+			this.m10 = -this.m10;
+			this.m11 = -this.m11;
+		}
+	},
+	setToSetupPose: function () {
+		var data = this.data;
+		this.x = data.x;
+		this.y = data.y;
+		this.rotation = data.rotation;
+		this.scaleX = data.scaleX;
+		this.scaleY = data.scaleY;
+	}
+};
+
+spine.Slot = function (slotData, skeleton, bone) {
+	this.data = slotData;
+	this.skeleton = skeleton;
+	this.bone = bone;
+};
+spine.Slot.prototype = {
+	r: 1, g: 1, b: 1, a: 1,
+	_attachmentTime: 0,
+	attachment: null,
+	setAttachment: function (attachment) {
+		this.attachment = attachment;
+		this._attachmentTime = this.skeleton.time;
+	},
+	setAttachmentTime: function (time) {
+		this._attachmentTime = this.skeleton.time - time;
+	},
+	getAttachmentTime: function () {
+		return this.skeleton.time - this._attachmentTime;
+	},
+	setToSetupPose: function () {
+		var data = this.data;
+		this.r = data.r;
+		this.g = data.g;
+		this.b = data.b;
+		this.a = data.a;
+		
+		var slots = this.skeleton.slots;
+		for (var i = 0, n = slots.length; i < n; i++) {
+			if (slots[i] == this) {
+				this.setAttachment(!data.attachmentName ? null : this.skeleton.getAttachment(i, data.attachmentName));
+				break;
+			}
+		}
+	}
+};
+
+spine.Skin = function (name) {
+	this.name = name;
+	this.attachments = {};
+};
+spine.Skin.prototype = {
+	addAttachment: function (slotIndex, name, attachment) {
+		attachments[slotIndex + ":" + name] = attachment;
+	},
+	getAttachment: function (slotIndex, name) {
+		return attachments[slotIndex + ":" + name];
+	},
+	_attachAll: function (skeleton, oldSkin) {
+		for (var key in oldSkin.attachments) {
+			var colon = key.indexOf(":");
+			var slotIndex = parseInt(key.substring(0, colon));
+			var name = key.substring(colon + 1);
+			var slot = skeleton.slots[slotIndex];
+			if (slot.attachment.name == name) {
+				var attachment = this.getAttachment(slotIndex, name);
+				if (attachment) slot.setAttachment(attachment);
+			}
+		}
+	}
+};
+
+spine.Animation = function (name, timelines, duration) {
+	this.name = name;
+	this.timelines = timelines;
+	this.duration = duration;
+}
+spine.Animation.prototype = {
+	apply: function (skeleton, time, loop) {
+		if (loop && this.duration != 0) time %= this.duration;
+		for (var i = 0, n = timelines.length; i < n; i++)
+			timelines[i].apply(skeleton, time, 1);
+	},
+	mix: function (skeleton, time, loop, alpha) {
+		if (loop && this.duration != 0) time %= this.duration;
+		for (var i = 0, n = timelines.length; i < n; i++)
+			timelines[i].apply(skeleton, time, alpha);
+	}
+};
+
+spine.binarySearch = function (values, target, step) {
+	var low = 0;
+	var high = Math.floor(values.length / step) - 2;
+	if (high == 0) return step;
+	var current = high >>> 1;
+	while (true) {
+		if (values[(current + 1) * step] <= target)
+			low = current + 1;
+		else
+			high = current;
+		if (low == high) return (low + 1) * step;
+		current = (low + high) >>> 1;
+	}
+}
+spine.linearSearch = function (values, target, step) {
+	for (var i = 0, last = values.length - step; i <= last; i += step)
+		if (values[i] > target) return i;
+	return -1;
+}
+
+spine.Curves = function (frameCount) {
+	this.curves = []; // dfx, dfy, ddfx, ddfy, dddfx, dddfy, ...
+	this.curves.length = (frameCount - 1) * 6;
+}
+spine.Curves.prototype = {
+	setLinear: function (frameIndex) {
+		this.curves[frameIndex * 6] = 0/*LINEAR*/;
+	},
+	setStepped: function (frameIndex) {
+		this.curves[frameIndex * 6] = -1/*STEPPED*/;
+	},
+	/** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next.
+	 * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of
+	 * the difference between the keyframe's values. */
+	setCurve: function (frameIndex, cx1, cy1, cx2, cy2) {
+		var subdiv_step = 1 / 10/*BEZIER_SEGMENTS*/;
+		var subdiv_step2 = subdiv_step * subdiv_step;
+		var subdiv_step3 = subdiv_step2 * subdiv_step;
+		var pre1 = 3 * subdiv_step;
+		var pre2 = 3 * subdiv_step2;
+		var pre4 = 6 * subdiv_step2;
+		var pre5 = 6 * subdiv_step3;
+		var tmp1x = -cx1 * 2 + cx2;
+		var tmp1y = -cy1 * 2 + cy2;
+		var tmp2x = (cx1 - cx2) * 3 + 1;
+		var tmp2y = (cy1 - cy2) * 3 + 1;
+		var i = frameIndex * 6;
+		var curves = this.curves;
+		curves[i] = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3;
+		curves[i + 1] = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3;
+		curves[i + 2] = tmp1x * pre4 + tmp2x * pre5;
+		curves[i + 3] = tmp1y * pre4 + tmp2y * pre5;
+		curves[i + 4] = tmp2x * pre5;
+		curves[i + 5] = tmp2y * pre5;
+	},
+	getCurvePercent: function (frameIndex, percent) {
+		percent = percent < 0 ? 0 : (percent > 1 ? 1 : percent);
+		var curveIndex = frameIndex * 6;
+		var curves = this.curves;
+		var dfx = curves[curveIndex];
+		if (dfx == 0/*LINEAR*/) return percent;
+		if (dfx == -1/*STEPPED*/) return 0;
+		var dfy = curves[curveIndex + 1];
+		var ddfx = curves[curveIndex + 2];
+		var ddfy = curves[curveIndex + 3];
+		var dddfx = curves[curveIndex + 4];
+		var dddfy = curves[curveIndex + 5];
+		var x = dfx, y = dfy;
+		var i = 10/*BEZIER_SEGMENTS*/ - 2;
+		while (true) {
+			if (x >= percent) {
+				var lastX = x - dfx;
+				var lastY = y - dfy;
+				return lastY + (y - lastY) * (percent - lastX) / (x - lastX);
+			}
+			if (i == 0) break;
+			i--;
+			dfx += ddfx;
+			dfy += ddfy;
+			ddfx += dddfx;
+			ddfy += dddfy;
+			x += dfx;
+			y += dfy;
+		}
+		return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1.
+	}
+}
+
+spine.RotateTimeline = function (frameCount) {
+	this.curves = new Curves(frameCount);
+	this.frames = []; // time, angle, ...
+	this.frames.length = frameCount * 2;
+}
+spine.RotateTimeline.prototype = {
+	boneIndex: 0,
+	getFrameCount: function () {
+		return this.frames.length / 2;
+	},
+	setFrame: function (frameIndex, time, angle) {
+		frameIndex *= 2;
+		this.frames[frameIndex] = time;
+		this.frames[frameIndex + 1] = angle;
+	},
+	apply: function (skeleton, time, alpha) {
+		var frames = this.frames;
+		if (time < frames[0]) return; // Time is before first frame.
+
+		var bone = skeleton.bones[this.boneIndex];
+
+		if (time >= frames[frames.length - 2]) { // Time is after last frame.
+			var amount = bone.data.rotation + frames[frames.length - 1] - bone.rotation;
+			while (amount > 180)
+				amount -= 360;
+			while (amount < -180)
+				amount += 360;
+			bone.rotation += amount * alpha;
+			return;
+		}
+
+		// Interpolate between the last frame and the current frame.
+		var frameIndex = spine.binarySearch(frames, time, 2);
+		var lastFrameValue = frames[frameIndex - 1];
+		var frameTime = frames[frameIndex];
+		var percent = 1 - (time - frameTime) / (frames[frameIndex - 2/*LAST_FRAME_TIME*/] - frameTime);
+		percent = this.curves.getCurvePercent(frameIndex / 2 - 1, percent);
+
+		var amount = frames[frameIndex + 1/*FRAME_VALUE*/] - lastFrameValue;
+		while (amount > 180)
+			amount -= 360;
+		while (amount < -180)
+			amount += 360;
+		amount = bone.data.rotation + (lastFrameValue + amount * percent) - bone.rotation;
+		while (amount > 180)
+			amount -= 360;
+		while (amount < -180)
+			amount += 360;
+		bone.rotation += amount * alpha;
+	}
+}
+
+spine.TranslateTimeline = function (frameCount) {
+	this.curves = new Curves(frameCount);
+	this.frames = []; // time, x, y, ...
+	this.frames.length = frameCount * 3;
+}
+spine.TranslateTimeline.prototype = {
+	boneIndex: 0,
+	getFrameCount: function () {
+		return this.frames.length / 3;
+	},
+	setFrame: function (frameIndex, time, x, y) {
+		frameIndex *= 3;
+		this.frames[frameIndex] = time;
+		this.frames[frameIndex + 1] = x;
+		this.frames[frameIndex + 2] = y;
+	},
+	apply: function (skeleton, time, alpha) {
+		var frames = this.frames;
+		if (time < frames[0]) return; // Time is before first frame.
+
+		var bone = skeleton.bones[this.boneIndex];
+
+		if (time >= frames[frames.length - 3]) { // Time is after last frame.
+			bone.x += (bone.data.x + frames[frames.length - 2] - bone.x) * alpha;
+			bone.y += (bone.data.y + frames[frames.length - 1] - bone.y) * alpha;
+			return;
+		}
+
+		// Interpolate between the last frame and the current frame.
+		var frameIndex = spine.binarySearch(frames, time, 3);
+		var lastFrameX = frames[frameIndex - 2];
+		var lastFrameY = frames[frameIndex - 1];
+		var frameTime = frames[frameIndex];
+		var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime);
+		percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent);
+
+		bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha;
+		bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha;
+	}
+}
+
+spine.ScaleTimeline = function (frameCount) {
+	this.curves = new Curves(frameCount);
+	this.frames = []; // time, x, y, ...
+	this.frames.length = frameCount * 3;
+}
+spine.ScaleTimeline.prototype = {
+	boneIndex: 0,
+	getFrameCount: function () {
+		return this.frames.length / 3;
+	},
+	setFrame: function (frameIndex, time, x, y) {
+		frameIndex *= 3;
+		this.frames[frameIndex] = time;
+		this.frames[frameIndex + 1] = x;
+		this.frames[frameIndex + 2] = y;
+	},
+	apply: function (skeleton, time, alpha) {
+		var frames = this.frames;
+		if (time < frames[0]) return; // Time is before first frame.
+
+		var bone = skeleton.bones[this.boneIndex];
+
+		if (time >= frames[frames.length - 3]) { // Time is after last frame.
+			bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha;
+			bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha;
+			return;
+		}
+
+		// Interpolate between the last frame and the current frame.
+		var frameIndex = spine.binarySearch(frames, time, 3);
+		var lastFrameX = frames[frameIndex - 2];
+		var lastFrameY = frames[frameIndex - 1];
+		var frameTime = frames[frameIndex];
+		var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime);
+		percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent);
+
+		bone.scaleX += (bone.data.scaleX - 1 + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.scaleX) * alpha;
+		bone.scaleY += (bone.data.scaleY - 1 + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.scaleY) * alpha;
+	}
+}
+
+spine.ColorTimeline = function (frameCount) {
+	this.curves = new Curves(frameCount);
+	this.frames = []; // time, r, g, b, a, ...
+	this.frames.length = frameCount * 5;
+}
+spine.ColorTimeline.prototype = {
+	slotIndex: 0,
+	getFrameCount: function () {
+		return this.frames.length / 2;
+	},
+	setFrame: function (frameIndex, time, x, y) {
+		frameIndex *= 5;
+		this.frames[frameIndex] = time;
+		this.frames[frameIndex + 1] = r;
+		this.frames[frameIndex + 2] = g;
+		this.frames[frameIndex + 3] = b;
+		this.frames[frameIndex + 4] = a;
+	},
+	apply: function (skeleton, time, alpha) {
+		var frames = this.frames;
+		if (time < frames[0]) return; // Time is before first frame.
+
+		var slot = skeleton.slots[this.slotIndex];
+
+		if (time >= frames[frames.length - 5]) { // Time is after last frame.
+			var i = frames.length - 1;
+			slot.r = frames[i - 3];
+			slot.g = frames[i - 2];
+			slot.b = frames[i - 1];
+			slot.a = frames[i];
+			return;
+		}
+
+		// Interpolate between the last frame and the current frame.
+		var frameIndex = spine.binarySearch(frames, time, 5);
+		var lastFrameR = frames[frameIndex - 4];
+		var lastFrameG = frames[frameIndex - 3];
+		var lastFrameB = frames[frameIndex - 2];
+		var lastFrameA = frames[frameIndex - 1];
+		var frameTime = frames[frameIndex];
+		var percent = 1 - (time - frameTime) / (frames[frameIndex - 5/*LAST_FRAME_TIME*/] - frameTime);
+		percent = this.curves.getCurvePercent(frameIndex / 5 - 1, percent);
+
+		var r = lastFrameR + (frames[frameIndex + 1/*FRAME_R*/] - lastFrameR) * percent;
+		var g = lastFrameG + (frames[frameIndex + 2/*FRAME_G*/] - lastFrameG) * percent;
+		var b = lastFrameB + (frames[frameIndex + 3/*FRAME_B*/] - lastFrameB) * percent;
+		var a = lastFrameA + (frames[frameIndex + 4/*FRAME_A*/] - lastFrameA) * percent;
+		if (alpha < 1) {
+			slot.r += (r - slot.r) * alpha;
+			slot.g += (g - slot.g) * alpha;
+			slot.b += (b - slot.b) * alpha;
+			slot.a += (a - slot.a) * alpha;
+		} else {
+			slot.r = r;
+			slot.g = g;
+			slot.b = b;
+			slot.a = a;
+		}
+	}
+}
+
+spine.AttachmentTimeline = function (frameCount) {
+	this.curves = new Curves(frameCount);
+	this.frames = []; // time, ...
+	this.frames.length = frameCount;
+	this.attachmentNames = []; // time, ...
+	this.attachmentNames.length = frameCount;
+}
+spine.AttachmentTimeline.prototype = {
+	slotIndex: 0,
+	getFrameCount: function () {
+		return this.frames.length / 2;
+	},
+	setFrame: function (frameIndex, time, attachmentName) {
+		this.frames[frameIndex] = time;
+		this.attachmentNames[frameIndex] = attachmentName;
+	},
+	apply: function (skeleton, time, alpha) {
+		var frames = this.frames;
+		if (time < frames[0]) return; // Time is before first frame.
+
+		var frameIndex;
+		if (time >= frames[frames.length - 1]) // Time is after last frame.
+			frameIndex = frames.length - 1;
+		else
+			frameIndex = spine.binarySearch(frames, time, 1) - 1;
+
+		var attachmentName = this.attachmentNames[frameIndex];
+		skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachment(this.slotIndex, attachmentName));
+	}
+}
+
+spine.SkeletonData = function () {
+	this.bones = [];
+	this.slots = [];
+	this.skins = [];
+	this.animations = [];
+}
+spine.SkeletonData.prototype = {
+	defaultSkin: null,
+	/** @return May be null. */
+	findBone: function (boneName) {
+		var bones = this.bones;
+		for (var i = 0, n = bones.length; i < n; i++)
+			if (bones[i] == boneName) return bones[i];
+		return null;
+	},
+	/** @return -1 if the bone was not found. */
+	findBoneIndex: function (boneName) {
+		var bones = this.bones;
+		for (var i = 0, n = bones.length; i < n; i++)
+			if (bones[i] == boneName) return i;
+		return -1;
+	},
+	/** @return May be null. */
+	findSlot: function (slotName) {
+		var slots = this.slots;
+		for (var i = 0, n = slots.length; i < n; i++) {
+			if (slots[i].name == slotName) return slot[i];
+		}
+		return null;
+	},
+	/** @return -1 if the bone was not found. */
+	findSlotIndex: function (slotName) {
+		var slots = this.slots;
+		for (var i = 0, n = slots.length; i < n; i++)
+			if (slots.get(i).name == slotName) return i;
+		return -1;
+	},
+	/** @return May be null. */
+	findSkin: function (skinName) {
+		var skins = this.skins;
+		for (var i = 0, n = skins.length; i < n; i++)
+			if (skins[i].name == skinName) return skins[i];
+		return null;
+	},
+	/** @return May be null. */
+	findAnimation: function (animationName) {
+		var animations = this.animations;
+		for (var i = 0, n = animations.length; i < n; i++)
+			if (animations[i].name == animationName) return animations[i];
+		return null;
+	}
+}
+
+spine.Skeleton = function (skeletonData) {
+	this.data = skeletonData;
+
+	this.bones = [];
+	for (var i = 0, n = skeletonData.bones.length; i < n; i++) {
+		var boneData = skeletonData.bones[i];
+		var parent = !boneData.parent ? null : bones[skeletonData.bones.indexOf(boneData.parent)];
+		bones.push(new Bone(boneData, parent));
+	}
+
+	this.slots = [];
+	this.drawOrder = [];
+	for (var i = 0, n = skeletonData.slots.length; i < n; i++) {
+		var slotData = skeletonData.slots[i];
+		var bone = this.bones[skeletonData.bones.indexOf(slotData.boneData)];
+		var slot = new Slot(slotData, this, bone);
+		slots.push(slot);
+		drawOrder.push(slot);
+	}
+}
+spine.Skeleton.prototype = {
+	skin: null,
+	r: 1, g: 1, b: 1, a: 1,
+	time: 0,
+	flipX: false, flipY: false,
+	/** Updates the world transform for each bone. */
+	updateWorldTransform: function () {
+		var flipX = this.flipX;
+		var flipY = this.flipY;
+		var bones = this.bones;
+		for (var i = 0, n = bones.length; i < n; i++)
+			bones[i].updateWorldTransform(flipX, flipY);
+	},
+	/** Sets the bones and slots to their setup pose values. */
+	setToSetupPose: function () {
+		setBonesToSetupPose();
+		setSlotsToSetupPose();
+	},
+	setBonesToSetupPose: function () {
+		var bones = this.bones;
+		for (var i = 0, n = bones.length; i < n; i++)
+			bones[i].setToSetupPose();
+	},
+	setSlotsToSetupPose: function () {
+		var slots = this.slots;
+		for (var i = 0, n = slots.length; i < n; i++)
+			slots[i].setToSetupPose(i);
+	},
+	/** @return May return null. */
+	getRootBone: function () {
+		return bones.length == 0 ? null : bones[0];
+	},
+	/** @return May be null. */
+	findBone: function (boneName) {
+		var bones = this.bones;
+		for (var i = 0, n = bones.length; i < n; i++)
+			if (bones[i].data.name == boneName) return bones[i];
+		return null;
+	},
+	/** @return -1 if the bone was not found. */
+	findBoneIndex: function (boneName) {
+		var bones = this.bones;
+		for (var i = 0, n = bones.length; i < n; i++)
+			if (bones[i].data.name == boneName) return i;
+		return -1;
+	},
+	/** @return May be null. */
+	findSlot: function (slotName) {
+		var slots = this.slots;
+		for (var i = 0, n = slots.length; i < n; i++)
+			if (slots[i].data.name == slotName) return slots[i];
+		return null;
+	},
+	/** @return -1 if the bone was not found. */
+	findSlotIndex: function (slotName) {
+		var slots = this.slots;
+		for (var i = 0, n = slots.length; i < n; i++)
+			if (slots[i].data.name == slotName) return i;
+		return -1;
+	},
+	setSkinByName: function (skinName) {
+		var skin = this.data.findSkin(skinName);
+		if (!skin) throw "Skin not found: " + skinName;
+		this.setSkin(skin);
+	},
+	/** Sets the skin used to look up attachments not found in the {@link SkeletonData#getDefaultSkin() default skin}. Attachments
+	 * from the new skin are attached if the corresponding attachment from the old skin was attached.
+	 * @param newSkin May be null. */
+	setSkin: function (newSkin) {
+		if (this.skin && newSkin) newSkin._attachAll(this, skin);
+		this.skin = newSkin;
+	},
+	/** @return May be null. */
+	getAttachmentBySlotName: function (slotName, attachmentName) {
+		return this.getAttachment(this.data.findSlotIndex(slotName), attachmentName);
+	},
+	/** @return May be null. */
+	getAttachmentBySlotIndex: function (slotIndex, attachmentName) {
+		if (this.skin) {
+			var attachment = this.skin.getAttachment(slotIndex, attachmentName);
+			if (attachment) return attachment;
+		}
+		if (this.data.defaultSkin) return this.data.defaultSkin.getAttachment(slotIndex, attachmentName);
+		return null;
+	},
+	/** @param attachmentName May be null. */
+	setAttachment: function (slotName, attachmentName) {
+		var slots = this.slots;
+		for (var i = 0, n = slots.size; i < n; i++) {
+			var slot = slots[i];
+			if (slot.data.name == slotName) {
+				var attachment = null;
+				if (attachmentName) {
+					attachment = this.getAttachment(i, attachmentName);
+					if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName;
+				}
+				slot.setAttachment(attachment);
+				return;
+			}
+		}
+		throw "Slot not found: " + slotName;
+	},
+	update: function (delta) {
+		time += delta;
+	}
+}
+
+spine.AttachmentType = {
+	
+};
+public class AttachmentType {
+	public static const region:AttachmentType = new AttachmentType(0, "region");
+	public static const regionSequence:AttachmentType = new AttachmentType(1, "regionSequence");
+
+	public var ordinal:int;
+	public var name:String;
+
+	public function AttachmentType (ordinal:int, name:String) {
+		this.ordinal = ordinal;
+		this.name = name;
+	}
+
+	static public function valueOf (name:String) : AttachmentType {
+		switch (name) {
+		case "region":
+			return region;
+		case "regionSequence":
+			return regionSequence;
+		}
+		return null;
+	}
+}
+
+spine.RegionAttachment = function () {
+	this.offset = [];
+	this.offset.length = 8;
+	this.uvs = [];
+	this.uvs.length = 8;
+}
+spine.RegionAttachment.prototype = {
+	x: 0, y: 0,
+	rotation: 0,
+	scaleX: 1, scaleY: 1,
+	width: 0, height: 0,
+	texture: null,
+	regionOffsetX: 0, regionOffsetY: 0,
+	regionWidth: 0, regionHeight: 0,
+	regionOriginalWidth: 0, regionOriginalHeight: 0,
+	setUVs: function (u, v, u2, v2, rotate) {
+		if (rotate) {
+			uvs[2/*X2*/] = u;
+			uvs[3/*Y2*/] = v2;
+			uvs[4/*X3*/] = u;
+			uvs[5/*Y3*/] = v;
+			uvs[6/*X4*/] = u2;
+			uvs[7/*Y4*/] = v;
+			uvs[0/*X1*/] = u2;
+			uvs[1/*Y1*/] = v2;
+		} else {
+			uvs[0/*X1*/] = u;
+			uvs[1/*Y1*/] = v2;
+			uvs[2/*X2*/] = u;
+			uvs[3/*Y2*/] = v;
+			uvs[4/*X3*/] = u2;
+			uvs[5/*Y3*/] = v;
+			uvs[6/*X4*/] = u2;
+			uvs[7/*Y4*/] = v2;
+		}
+	},
+	updateOffset: function () {
+		var regionScaleX = this.width / regionOriginalWidth * this.scaleX;
+		var regionScaleY = this.height / regionOriginalHeight * this.scaleY;
+		var localX = -this.width / 2 * this.scaleX + regionOffsetX * regionScaleX;
+		var localY = -this.height / 2 * this.scaleY + regionOffsetY * regionScaleY;
+		var localX2 = localX + regionWidth * regionScaleX;
+		var localY2 = localY + regionHeight * regionScaleY;
+		var radians = rotation * Math.PI / 180;
+		var cos = Math.cos(radians);
+		var sin = Math.sin(radians);
+		var localXCos = localX * cos + this.x;
+		var localXSin = localX * sin;
+		var localYCos = localY * cos + this.y;
+		var localYSin = localY * sin;
+		var localX2Cos = localX2 * cos + this.x;
+		var localX2Sin = localX2 * sin;
+		var localY2Cos = localY2 * cos + this.y;
+		var localY2Sin = localY2 * sin;
+		var offset = this.offset;
+		offset[0/*X1*/] = localXCos - localYSin;
+		offset[1/*Y1*/] = localYCos + localXSin;
+		offset[2/*X2*/] = localXCos - localY2Sin;
+		offset[3/*Y2*/] = localY2Cos + localXSin;
+		offset[4/*X3*/] = localX2Cos - localY2Sin;
+		offset[5/*Y3*/] = localY2Cos + localX2Sin;
+		offset[6/*X4*/] = localX2Cos - localYSin;
+		offset[7/*Y4*/] = localYCos + localX2Sin;
+	},
+	updateVertices: function (bone, vertices) {
+		var x = bone.worldX;
+		var y = bone.worldY;
+		var m00 = bone.m00;
+		var m01 = bone.m01;
+		var m10 = bone.m10;
+		var m11 = bone.m11;
+		var vertices = this.vertices;
+		var offset = this.offset;
+		vertices[0/*X1*/] = offset[0/*X1*/] * m00 + offset[1/*Y1*/] * m01 + x;
+		vertices[1/*Y1*/] = offset[0/*X1*/] * m10 + offset[1/*Y1*/] * m11 + y;
+		vertices[2/*X2*/] = offset[2/*X2*/] * m00 + offset[3/*Y2*/] * m01 + x;
+		vertices[3/*Y2*/] = offset[2/*X2*/] * m10 + offset[3/*Y2*/] * m11 + y;
+		vertices[4/*X3*/] = offset[4/*X3*/] * m00 + offset[4/*X3*/] * m01 + x;
+		vertices[4/*X3*/] = offset[4/*X3*/] * m10 + offset[4/*X3*/] * m11 + y;
+		vertices[6/*X4*/] = offset[6/*X4*/] * m00 + offset[7/*Y4*/] * m01 + x;
+		vertices[7/*Y4*/] = offset[6/*X4*/] * m10 + offset[7/*Y4*/] * m11 + y;
+	}
+}
+
+spine.AnimationStateData = function (skeletonData) {
+	this.skeletonData = skeletonData;
+	this.animationToMixTime = {};
+}
+spine.AnimationStateData.prototype = {
+	setMixByName: function (fromName, toName, duration) {
+		var from = this.skeletonData.findAnimation(fromName);
+		if (!from) throw "Animation not found: " + fromName;
+		var to = this.skeletonData.findAnimation(toName);
+		if (!to) throw "Animation not found: " + toName;
+		this.setMix(from, to, duration);
+	},
+	setMix: function (from, to, duration) {
+		animationToMixTime[from.name + ":" + to.name] = duration;
+	},
+	getMix: function (from, to) {
+		var time = animationToMixTime[from.name + ":" + to.name];
+		return time ? time : 0;
+	}
+}
+
+spine.AnimationState = function (stateData) {
+	this.data = stateData;
+	this.queue = [];
+}
+spine.AnimationState.prototype = {
+	current: null,
+	previous: null,
+	currentTime: 0,
+	previousTime: 0,
+	currentLoop: false,
+	previousLoop: false,
+	mixTime: 0,
+	mixDuration: 0,
+	update: function (delta) {
+		this.currentTime += delta;
+		this.previousTime += delta;
+		this.mixTime += delta;
+
+		if (this.queue.length > 0) {
+			var entry = this.queue[0];
+			if (this.currentTime >= entry.delay) {
+				this._setAnimation(entry.animation, entry.loop);
+				this.queue.shift();
+			}
+		}
+	},
+	apply: function (skeleton) {
+		if (!this.current) return;
+		if (this.previous) {
+			this.previous.apply(skeleton, this.previousTime, this.previousLoop);
+			var alpha = this.mixTime / this.mixDuration;
+			if (this.alpha >= 1) {
+				this.alpha = 1;
+				this.previous = null;
+			}
+			this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha);
+		} else
+			this.current.apply(skeleton, this.currentTime, this.currentLoop);
+	},
+	clearAnimation: function () {
+		this.previous = null;
+		this.current = null;
+		this.queue.length = 0;
+	},
+	_setAnimation: function (animation, loop) {
+		this.previous = null;
+		if (animation && this.current) {
+			this.mixDuration = this.data.getMix(this.current, animation);
+			if (this.mixDuration > 0) {
+				this.mixTime = 0;
+				this.previous = this.current;
+				this.previousTime = this.currentTime;
+				this.previousLoop = this.currentLoop;
+			}
+		}
+		this.current = animation;
+		this.currentLoop = loop;
+		this.currentTime = 0;
+	},
+	/** @see #setAnimation(Animation, Boolean) */
+	setAnimationByName: function (animationName, loop) {
+		var animation = this.data.skeletonData.findAnimation(animationName);
+		if (!animation) throw "Animation not found: " + animationName;
+		this.setAnimation(animation, loop);
+	},
+	/** Set the current animation. Any queued animations are cleared and the current animation time is set to 0.
+	 * @param animation May be null. */
+	setAnimation: function (animation, loop) {
+		this.queue.length = 0;
+		this._setAnimation(animation, loop);
+	},
+	/** @see #addAnimation(Animation, Boolean, Number) */
+	addAnimationByName: function (animationName, loop, delay) {
+		var animation = this.data.skeletonData.findAnimation(animationName);
+		if (!animation) throw "Animation not found: " + animationName;
+		this.addAnimation(animation, loop, delay);
+	},
+	/** Adds an animation to be played delay seconds after the current or last queued animation.
+	 * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */
+	addAnimation: function (animation, loop, delay) {
+		var entry = {};
+		entry.animation = animation;
+		entry.loop = loop;
+
+		if (delay <= 0) {
+			var previousAnimation = this.queue.length == 0 ? this.current : this.queue[this.queue.length - 1].animation;
+			if (previousAnimation != null)
+				delay = previousAnimation.duration - this.data.getMix(previousAnimation, animation) + delay;
+			else
+				delay = 0;
+		}
+		entry.delay = delay;
+
+		this.queue.push(entry);
+	},
+	/** Returns true if no animation is set or if the current time is greater than the animation duration, regardless of looping. */
+	isComplete: function () {
+		return !this.current || this.currentTime >= this.current.duration;
+	}
+}
+
+spine.SkeletonJson = function (attachmentLoader) {
+	this.attachmentLoader = attachmentLoader;
+}
+spine.SkeletonJson.prototype = {
+	scale: 1,
+	readSkeletonData: function (json) {
+		var skeletonData = new SkeletonData();
+
+		// Bones.
+		var bones = root["bones"];
+		for (var i = 0, n = bones.length; i < n; i++) {
+			var boneMap = bones[i];
+			var parent = null;
+			if (boneMap["parent"]) {
+				parent = skeletonData.findBone(boneMap["parent"]);
+				if (!parent) throw "Parent bone not found: " + boneMap["parent"];
+			}
+			var boneData = new BoneData(boneMap["name"], parent);
+			boneData.length = (boneMap["length"] || 0) * this.scale;
+			boneData.x = (boneMap["x"] || 0) * this.scale;
+			boneData.y = (boneMap["y"] || 0) * this.scale;
+			boneData.rotation = (boneMap["rotation"] || 0);
+			boneData.scaleX = boneMap["scaleX"] || 1;
+			boneData.scaleY = boneMap["scaleY"] || 1;
+			skeletonData.bones.push(boneData);
+		}
+
+		// Slots.
+		var slots = root["slots"];
+		for (var i = 0, n = slots.length; i < n; i++) {
+			var slotMap = slots[i];
+			var boneData = skeletonData.findBone(slotMap["bone"]);
+			if (!boneData) throw "Slot bone not found: " + slotMap["bone"];
+			var slotData = new SlotData(slotMap["name"], boneData);
+
+			var color = slotMap["color"];
+			if (color) {
+				slotData.r = toColor(color, 0);
+				slotData.g = toColor(color, 1);
+				slotData.b = toColor(color, 2);
+				slotData.a = toColor(color, 3);
+			}
+
+			slotData.attachmentName = slotMap["attachment"];
+
+			skeletonData.addSlot(slotData);
+		}
+
+		// Skins.
+		var skins = root["skins"];
+		for (var skinName in skins) {
+			if (!skins.hasOwnProperty(skinName)) continue;
+			var skinMap = skins[skinName];
+			var skin = new Skin(skinName);
+			for (var slotName in skinMap) {
+				if (!skinMap.hasOwnProperty(slotName)) continue;
+				var slotIndex = skeletonData.findSlotIndex(slotName);
+				var slotEntry = skinMap[slotName];
+				for (var attachmentName in slotEntry) {
+					if (!slotEntry.hasOwnProperty(attachmentName)) continue;
+					var attachment = readAttachment(skin, attachmentName, slotEntry[attachmentName]);
+					if (attachment != null) skin.addAttachment(slotIndex, attachmentName, attachment);
+				}
+			}
+			skeletonData.skins.push(skin);
+			if (skin.name == "default") skeletonData.defaultSkin = skin;
+		}
+
+		// Animations.
+		var animations = root["animations"];
+		for (var animationName in animations) {
+			if (!animations.hasOwnProperty(animationName)) continue;
+			readAnimation(animationName, animations[animationName], skeletonData);
+		}
+
+		return skeletonData;
+	},
+	readAttachment: function (skin, name, map) {
+		name = map["name"] || name;
+
+		var type = AttachmentType.valueOf(map["type"] || "region");
+		var attachment:Attachment = attachmentLoader.newAttachment(skin, type, name);
+
+		if (attachment is RegionAttachment) {
+			var regionAttachment:RegionAttachment = attachment as RegionAttachment;
+			regionAttachment.x = (map["x"] || 0) * scale;
+			regionAttachment.y = (map["y"] || 0) * scale;
+			regionAttachment.scaleX = map["scaleX"] || 1;
+			regionAttachment.scaleY = map["scaleY"] || 1;
+			regionAttachment.rotation = map["rotation"] || 0;
+			regionAttachment.width = (map["width"] || 32) * scale;
+			regionAttachment.height = (map["height"] || 32) * scale;
+			regionAttachment.updateOffset();
+		}
+
+		return attachment;
+	}
+
+	private function readAnimation (name:String, map:Object, skeletonData:SkeletonData) : void {
+		var timelines:Vector.<Timeline> = new Vector.<Timeline>();
+		var duration:Number = 0;
+
+		var bones:Object = map["bones"];
+		for (var boneName:String in bones) {
+			var boneIndex:int = skeletonData.findBoneIndex(boneName);
+			if (boneIndex == -1)
+				throw new Error("Bone not found: " + boneName);
+			var boneMap:Object = bones[boneName];
+
+			for (var timelineName:Object in boneMap) {
+				var timelineMap:Object = boneMap[timelineName];
+				if (timelineName == TIMELINE_ROTATE) {
+					var timeline:RotateTimeline = new RotateTimeline(count(timelineMap));
+					timeline.boneIndex = boneIndex;
+
+					var frameIndex:int = 0;
+					for each (var valueMap:Object in timelineMap) {
+						timeline.setFrame(frameIndex, valueMap["time"], valueMap["angle"]);
+						readCurve(timeline, frameIndex, valueMap);
+						frameIndex++;
+					}
+					timelines.push(timeline);
+					duration = Math.max(duration, timeline.frames[timeline.frameCount * 2 - 2]);
+
+				} else if (timelineName == TIMELINE_TRANSLATE || timelineName == TIMELINE_SCALE) {
+					var timeline1:TranslateTimeline;
+					var timelineScale:Number = 1;
+					if (timelineName == TIMELINE_SCALE)
+						timeline1 = new ScaleTimeline(count(timelineMap));
+					else {
+						timeline1 = new TranslateTimeline(count(timelineMap));
+						timelineScale = scale;
+					}
+					timeline1.boneIndex = boneIndex;
+
+					var frameIndex1:int = 0;
+					for each (var valueMap1:Object in timelineMap) {
+						var x:Number = (valueMap1["x"] || 0) * timelineScale;
+						var y:Number = (valueMap1["y"] || 0) * timelineScale;
+						timeline1.setFrame(frameIndex1, valueMap1["time"], x, y);
+						readCurve(timeline1, frameIndex1, valueMap1);
+						frameIndex1++;
+					}
+					timelines.push(timeline1);
+					duration = Math.max(duration, timeline1.frames[timeline1.frameCount * 3 - 3]);
+
+				} else
+					throw new Error("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")");
+			}
+		}
+
+		var slots:Object = map["slots"];
+		for (var slotName:String in slots) {
+			var slotMap:Object = slots[slotName];
+			var slotIndex:int = skeletonData.findSlotIndex(slotName);
+
+			for (var timelineName2:Object in boneMap) {
+				var timelineMap2:Object = boneMap[timelineName2];
+				if (timelineName2 == TIMELINE_COLOR) {
+					var timeline2:ColorTimeline = new ColorTimeline(count(timelineMap2));
+					timeline2.slotIndex = slotIndex;
+
+					var frameIndex2:int = 0;
+					for each (var valueMap2:Object in timelineMap2) {
+						var color:String = valueMap["color"];
+						var r:Number = toColor(color, 0);
+						var g:Number = toColor(color, 1);
+						var b:Number = toColor(color, 2);
+						var a:Number = toColor(color, 3);
+						timeline2.setFrame(frameIndex2, valueMap2["time"], r, g, b, a);
+						readCurve(timeline2, frameIndex2, valueMap);
+						frameIndex2++;
+					}
+					timelines.push(timeline2);
+					duration = Math.max(duration, timeline2.frames[timeline2.frameCount * 5 - 5]);
+
+				} else if (timelineName2 == TIMELINE_ATTACHMENT) {
+					var timeline3:AttachmentTimeline = new AttachmentTimeline(count(timelineMap2));
+					timeline3.slotIndex = slotIndex;
+
+					var frameIndex3:int = 0;
+					for each (var valueMap3:Object in timelineMap2) {
+						timeline3.setFrame(frameIndex3++, valueMap3["time"], valueMap3["name"]);
+					}
+					timelines.push(timeline);
+					duration = Math.max(duration, timeline3.frames[timeline3.frameCount - 1]);
+
+				} else
+					throw new Error("Invalid timeline type for a slot: " + timelineName2 + " (" + slotName + ")");
+			}
+		}
+
+		skeletonData.addAnimation(new Animation(name, timelines, duration));
+	}
+
+	private function readCurve (timeline:CurveTimeline, frameIndex:int, valueMap:Object) : void {
+		var curve:Object = valueMap["curve"];
+		if (curve == null)
+			return;
+		if (curve == "stepped")
+			timeline.setStepped(frameIndex);
+		else if (curve is Array) {
+			timeline.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]);
+		}
+	}
+
+	static private function toColor (hexString:String, colorIndex:int) : Number {
+		if (hexString.length != 8)
+			throw new ArgumentError("Color hexidecimal length must be 8, recieved: " + hexString);
+		return parseInt(hexString.substring(colorIndex * 2, 2), 16) / 255;
+	}
+
+	static private function count (map:Object) : int {
+		var count:int = 0;
+		for (var key:String in map)
+			count++;
+		return count;
+	}
+}

+ 2 - 2
spine-libgdx/src/com/esotericsoftware/spine/Bone.java

@@ -47,7 +47,7 @@ public class Bone {
 		if (data == null) throw new IllegalArgumentException("data cannot be null.");
 		this.data = data;
 		this.parent = parent;
-		setToBindPose();
+		setToSetupPose();
 	}
 
 	/** Copy constructor.
@@ -95,7 +95,7 @@ public class Bone {
 		}
 	}
 
-	public void setToBindPose () {
+	public void setToSetupPose () {
 		BoneData data = this.data;
 		x = data.x;
 		y = data.y;

+ 8 - 8
spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java

@@ -101,22 +101,22 @@ public class Skeleton {
 			bones.get(i).updateWorldTransform(flipX, flipY);
 	}
 
-	/** Sets the bones and slots to their bind pose values. */
-	public void setToBindPose () {
-		setBonesToBindPose();
-		setSlotsToBindPose();
+	/** Sets the bones and slots to their setup pose values. */
+	public void setToSetupPose () {
+		setBonesToSetupPose();
+		setSlotsToSetupPose();
 	}
 
-	public void setBonesToBindPose () {
+	public void setBonesToSetupPose () {
 		Array<Bone> bones = this.bones;
 		for (int i = 0, n = bones.size; i < n; i++)
-			bones.get(i).setToBindPose();
+			bones.get(i).setToSetupPose();
 	}
 
-	public void setSlotsToBindPose () {
+	public void setSlotsToSetupPose () {
 		Array<Slot> slots = this.slots;
 		for (int i = 0, n = slots.size; i < n; i++)
-			slots.get(i).setToBindPose(i);
+			slots.get(i).setToSetupPose(i);
 	}
 
 	public SkeletonData getData () {

+ 1 - 1
spine-libgdx/src/com/esotericsoftware/spine/SkeletonData.java

@@ -30,7 +30,7 @@ import com.badlogic.gdx.utils.Array;
 public class SkeletonData {
 	String name;
 	final Array<BoneData> bones = new Array(); // Ordered parents first.
-	final Array<SlotData> slots = new Array(); // Bind pose draw order.
+	final Array<SlotData> slots = new Array(); // Setup pose draw order.
 	final Array<Skin> skins = new Array();
 	Skin defaultSkin;
 	final Array<Animation> animations = new Array();

+ 4 - 4
spine-libgdx/src/com/esotericsoftware/spine/Slot.java

@@ -52,7 +52,7 @@ public class Slot {
 		this.skeleton = skeleton;
 		this.bone = bone;
 		color = new Color();
-		setToBindPose();
+		setToSetupPose();
 	}
 
 	/** Copy constructor. */
@@ -105,13 +105,13 @@ public class Slot {
 		return skeleton.time - attachmentTime;
 	}
 
-	void setToBindPose (int slotIndex) {
+	void setToSetupPose (int slotIndex) {
 		color.set(data.color);
 		setAttachment(data.attachmentName == null ? null : skeleton.getAttachment(slotIndex, data.attachmentName));
 	}
 
-	public void setToBindPose () {
-		setToBindPose(skeleton.data.slots.indexOf(data, true));
+	public void setToSetupPose () {
+		setToSetupPose(skeleton.data.slots.indexOf(data, true));
 	}
 
 	public String toString () {

+ 1 - 1
spine-libgdx/test/com/esotericsoftware/spine/MixTest.java

@@ -68,7 +68,7 @@ public class MixTest extends ApplicationAdapter {
 		jumpAnimation = skeletonData.findAnimation("jump");
 
 		skeleton = new Skeleton(skeletonData);
-		skeleton.setToBindPose();
+		skeleton.setToSetupPose();
 
 		final Bone root = skeleton.getRootBone();
 		root.x = -50;

+ 2 - 2
spine-libgdx/test/com/esotericsoftware/spine/SkeletonTest.java

@@ -88,7 +88,7 @@ public class SkeletonTest extends ApplicationAdapter {
 
 		skeleton = new Skeleton(skeletonData);
 		if (name.equals("goblins")) skeleton.setSkin("goblin");
-		skeleton.setToBindPose();
+		skeleton.setToSetupPose();
 		skeleton = new Skeleton(skeleton);
 
 		Bone root = skeleton.getRootBone();
@@ -103,7 +103,7 @@ public class SkeletonTest extends ApplicationAdapter {
 				if (keycode == Keys.SPACE) {
 					if (name.equals("goblins")) {
 						skeleton.setSkin(skeleton.getSkin().getName().equals("goblin") ? "goblingirl" : "goblin");
-						skeleton.setSlotsToBindPose();
+						skeleton.setSlotsToSetupPose();
 					}
 				}
 				return true;

+ 1 - 1
spine-love/main.lua

@@ -41,7 +41,7 @@ skeleton.flipX = false
 skeleton.flipY = false
 skeleton.debugBones = true -- Omit or set to false to not draw debug lines on top of the images.
 skeleton.debugSlots = false
-skeleton:setToBindPose()
+skeleton:setToSetupPose()
 
 local animationTime = 0
 function love.update (delta)

+ 1 - 1
spine-lua/Bone.lua

@@ -65,7 +65,7 @@ function Bone.new (data, parent)
 		end
 	end
 
-	function self:setToBindPose ()
+	function self:setToSetupPose ()
 		local data = self.data
 		self.x = data.x
 		self.y = data.y

+ 7 - 7
spine-lua/Skeleton.lua

@@ -44,20 +44,20 @@ function Skeleton.new (skeletonData)
 		end
 	end
 
-	function self:setToBindPose ()
-		self:setBonesToBindPose()
-		self:setSlotsToBindPose()
+	function self:setToSetupPose ()
+		self:setBonesToSetupPose()
+		self:setSlotsToSetupPose()
 	end
 
-	function self:setBonesToBindPose ()
+	function self:setBonesToSetupPose ()
 		for i,bone in ipairs(self.bones) do
-			bone:setToBindPose()
+			bone:setToSetupPose()
 		end
 	end
 
-	function self:setSlotsToBindPose ()
+	function self:setSlotsToSetupPose ()
 		for i,slot in ipairs(self.slots) do
-			slot:setToBindPose()
+			slot:setToSetupPose()
 		end
 	end
 

+ 2 - 2
spine-lua/Slot.lua

@@ -55,7 +55,7 @@ function Slot.new (slotData, skeleton, bone)
 		return self.skeleton.time - self.attachmentTime
 	end
 
-	function self:setToBindPose ()
+	function self:setToSetupPose ()
 		local data = self.data
 
 		self:setColor(data.r, data.g, data.b, data.a)
@@ -67,7 +67,7 @@ function Slot.new (slotData, skeleton, bone)
 		self:setAttachment(attachment)
 	end
 
-	self:setToBindPose()
+	self:setToSetupPose()
 
 	return self
 end

+ 2 - 2
spine-sfml/example/main.cpp

@@ -50,7 +50,7 @@ void spineboy () {
 	Skeleton* skeleton = drawable->skeleton;
 	skeleton->flipX = false;
 	skeleton->flipY = false;
-	Skeleton_setToBindPose(skeleton);
+	Skeleton_setToSetupPose(skeleton);
 
 	skeleton->root->x = 320;
 	skeleton->root->y = 420;
@@ -108,7 +108,7 @@ void goblins () {
 	skeleton->flipX = false;
 	skeleton->flipY = false;
 	Skeleton_setSkinByName(skeleton, "goblin");
-	Skeleton_setSlotsToBindPose(skeleton);
+	Skeleton_setSlotsToSetupPose(skeleton);
 //	Skeleton_setAttachment(skeleton, "left hand item", "dagger");
 
 	skeleton->root->x = 320;

+ 2 - 2
spine-unity/Assets/Plugins/Spine/SkeletonComponent.cs

@@ -96,11 +96,11 @@ public class SkeletonComponent : MonoBehaviour {
 		if (skinName == null || skinName.Length == 0) {
 			if (skeleton.Skin != null) {
 				skeleton.SetSkin((Skin)null);
-				skeleton.SetSlotsToBindPose();
+				skeleton.SetSlotsToSetupPose();
 			}
 		} else if (skeleton.Skin == null || skinName != skeleton.Skin.Name) {
 			skeleton.SetSkin(skinName);
-			skeleton.SetSlotsToBindPose();
+			skeleton.SetSlotsToSetupPose();
 		}
 
 		UpdateAnimation();

+ 1 - 1
spine-xna/example/src/ExampleGame.cs

@@ -64,7 +64,7 @@ namespace Spine {
 			SkeletonJson json = new SkeletonJson(atlas);
 			skeleton = new Skeleton(json.ReadSkeletonData("data/" + name + ".json"));
 			if (name == "goblins") skeleton.SetSkin("goblingirl");
-			skeleton.SetSlotsToBindPose(); // Without this the skin attachments won't be attached. See SetSkin.
+			skeleton.SetSlotsToSetupPose(); // Without this the skin attachments won't be attached. See SetSkin.
 
 			// Define mixing between animations.
 			AnimationStateData stateData = new AnimationStateData(skeleton.Data);