Forráskód Böngészése

Flip timelines for spine-as3 and spine-starling.

NathanSweet 10 éve
szülő
commit
efae035f18

+ 24 - 5
spine-as3/spine-as3/src/spine/Bone.as

@@ -42,6 +42,8 @@ public class Bone {
 	public var rotationIK:Number;
 	public var scaleX:Number
 	public var scaleY:Number;
+	public var flipX:Boolean;
+	public var flipY:Boolean;
 
 	internal var _m00:Number;
 	internal var _m01:Number;
@@ -52,6 +54,8 @@ public class Bone {
 	internal var _worldRotation:Number;
 	internal var _worldScaleX:Number;
 	internal var _worldScaleY:Number;
+	internal var _worldFlipX:Boolean;
+	internal var _worldFlipY:Boolean;
 
 	/** @param parent May be null. */
 	public function Bone (data:BoneData, skeleton:Skeleton, parent:Bone) {
@@ -77,24 +81,29 @@ public class Bone {
 				_worldScaleY = scaleY;
 			}
 			_worldRotation = _data.inheritRotation ? parent._worldRotation + rotationIK : rotationIK;
+			_worldFlipX = parent._worldFlipX != flipX;
+			_worldFlipY = parent._worldFlipY != flipY;
 		} else {
-			_worldX = _skeleton.flipX ? -x : x;
-			_worldY = _skeleton.flipY != yDown ? -y : y;
+			var skeletonFlipX:Boolean = _skeleton.flipX, skeletonFlipY:Boolean = _skeleton.flipY;
+			_worldX = skeletonFlipX ? -x : x;
+			_worldY = skeletonFlipY != yDown ? -y : y;
 			_worldScaleX = scaleX;
 			_worldScaleY = scaleY;
 			_worldRotation = rotationIK;
+			_worldFlipX = skeletonFlipX != flipX;
+			_worldFlipY = skeletonFlipY != flipY;
 		}
 		var radians:Number = _worldRotation * (Math.PI / 180);
 		var cos:Number = Math.cos(radians);
 		var sin:Number = Math.sin(radians);
-		if (skeleton.flipX) {
+		if (_worldFlipX) {
 			_m00 = -cos * _worldScaleX;
 			_m01 = sin * _worldScaleY;
 		} else {
 			_m00 = cos * _worldScaleX;
 			_m01 = -sin * _worldScaleY;
 		}
-		if (_skeleton.flipY != yDown) {
+		if (_worldFlipY != yDown) {
 			_m10 = -sin * _worldScaleX;
 			_m11 = -cos * _worldScaleY;
 		} else {
@@ -110,6 +119,8 @@ public class Bone {
 		rotationIK = rotation;
 		scaleX = _data.scaleX;
 		scaleY = _data.scaleY;
+		flipX = _data.flipX;
+		flipY = _data.flipY;
 	}
 
 	public function get data () : BoneData {
@@ -159,11 +170,19 @@ public class Bone {
 	public function get worldScaleY () : Number {
 		return _worldScaleY;
 	}
+	
+	public function get worldFlipX () : Boolean {
+		return _worldFlipX;
+	}
+	
+	public function get worldFlipY () : Boolean {
+		return _worldFlipY;
+	}
 
 	public function worldToLocal (world:Vector.<Number>) : void {
 		var dx:Number = world[0] - _worldX, dy:Number = world[1] - _worldY;
 		var m00:Number = _m00, m10:Number = _m10, m01:Number = _m01, m11:Number = _m11;
-		if (_skeleton.flipX != (_skeleton.flipY != yDown)) {
+		if (_worldFlipX != (_worldFlipY != yDown)) {
 			m00 = -m00;
 			m11 = -m11;
 		}

+ 2 - 0
spine-as3/spine-as3/src/spine/BoneData.as

@@ -41,6 +41,8 @@ public class BoneData {
 	public var scaleY:Number = 1;
 	public var inheritScale:Boolean = true;
 	public var inheritRotation:Boolean = true;
+	public var flipX:Boolean;
+	public var flipY:Boolean;
 
 	/** @param parent May be null. */
 	public function BoneData (name:String, parent:BoneData) {

+ 24 - 12
spine-as3/spine-as3/src/spine/SkeletonJson.as

@@ -38,6 +38,8 @@ import spine.animation.CurveTimeline;
 import spine.animation.DrawOrderTimeline;
 import spine.animation.EventTimeline;
 import spine.animation.FfdTimeline;
+import spine.animation.FlipXTimeline;
+import spine.animation.FlipYTimeline;
 import spine.animation.IkConstraintTimeline;
 import spine.animation.RotateTimeline;
 import spine.animation.ScaleTimeline;
@@ -52,12 +54,6 @@ import spine.attachments.RegionAttachment;
 import spine.attachments.SkinnedMeshAttachment;
 
 public class SkeletonJson {
-	static public const TIMELINE_SCALE:String = "scale";
-	static public const TIMELINE_ROTATE:String = "rotate";
-	static public const TIMELINE_TRANSLATE:String = "translate";
-	static public const TIMELINE_ATTACHMENT:String = "attachment";
-	static public const TIMELINE_COLOR:String = "color";
-
 	public var attachmentLoader:AttachmentLoader;
 	public var scale:Number = 1;
 
@@ -107,6 +103,8 @@ public class SkeletonJson {
 			boneData.rotation = (boneMap["rotation"] || 0);
 			boneData.scaleX = boneMap.hasOwnProperty("scaleX") ? boneMap["scaleX"] : 1;
 			boneData.scaleY = boneMap.hasOwnProperty("scaleY") ? boneMap["scaleY"] : 1;
+			boneData.flipX = boneMap.hasOwnProperty("flipX") ? boneMap["flipX"] : false;
+			boneData.flipY = boneMap.hasOwnProperty("flipY") ? boneMap["flipY"] : false;
 			boneData.inheritScale = boneMap.hasOwnProperty("inheritScale") ? boneMap["inheritScale"] : true;
 			boneData.inheritRotation = boneMap.hasOwnProperty("inheritRotation") ? boneMap["inheritRotation"] : true;
 			skeletonData.bones[skeletonData.bones.length] = boneData;
@@ -312,7 +310,7 @@ public class SkeletonJson {
 
 			for (timelineName in slotMap) {
 				values = slotMap[timelineName];
-				if (timelineName == TIMELINE_COLOR) {
+				if (timelineName == "color") {
 					var colorTimeline:ColorTimeline = new ColorTimeline(values.length);
 					colorTimeline.slotIndex = slotIndex;
 					
@@ -330,7 +328,7 @@ public class SkeletonJson {
 					timelines[timelines.length] = colorTimeline;
 					duration = Math.max(duration, colorTimeline.frames[colorTimeline.frameCount * 5 - 5]);
 					
-				} else if (timelineName == TIMELINE_ATTACHMENT) {
+				} else if (timelineName == "attachment") {
 					var attachmentTimeline:AttachmentTimeline = new AttachmentTimeline(values.length);
 					attachmentTimeline.slotIndex = slotIndex;
 					
@@ -339,7 +337,7 @@ public class SkeletonJson {
 						attachmentTimeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]);
 					timelines[timelines.length] = attachmentTimeline;
 					duration = Math.max(duration, attachmentTimeline.frames[attachmentTimeline.frameCount - 1]);
-					
+
 				} else
 					throw new Error("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")");
 			}
@@ -353,7 +351,7 @@ public class SkeletonJson {
 
 			for (timelineName in boneMap) {
 				values = boneMap[timelineName];
-				if (timelineName == TIMELINE_ROTATE) {
+				if (timelineName == "rotate") {
 					var rotateTimeline:RotateTimeline = new RotateTimeline(values.length);
 					rotateTimeline.boneIndex = boneIndex;
 
@@ -366,10 +364,10 @@ public class SkeletonJson {
 					timelines[timelines.length] = rotateTimeline;
 					duration = Math.max(duration, rotateTimeline.frames[rotateTimeline.frameCount * 2 - 2]);
 
-				} else if (timelineName == TIMELINE_TRANSLATE || timelineName == TIMELINE_SCALE) {
+				} else if (timelineName == "translate" || timelineName == "scale") {
 					var timeline:TranslateTimeline;
 					var timelineScale:Number = 1;
-					if (timelineName == TIMELINE_SCALE)
+					if (timelineName == "scale")
 						timeline = new ScaleTimeline(values.length);
 					else {
 						timeline = new TranslateTimeline(values.length);
@@ -388,6 +386,20 @@ public class SkeletonJson {
 					timelines[timelines.length] = timeline;
 					duration = Math.max(duration, timeline.frames[timeline.frameCount * 3 - 3]);
 
+				} else if (timelineName == "flipX" || timelineName == "flipY") {
+					var flipX:Boolean = timelineName == "flipX";
+					var flipTimeline:FlipXTimeline = flipX ? new FlipXTimeline(values.length) : new FlipYTimeline(values.length);
+					flipTimeline.boneIndex = boneIndex;
+					
+					var field:String = flipX ? "x" : "y";
+					frameIndex = 0;
+					for each (valueMap in values) {
+						flipTimeline.setFrame(frameIndex, valueMap["time"], valueMap.hasOwnProperty(field) ? valueMap[field] : false);
+						frameIndex++;
+					}
+					timelines[timelines.length] = flipTimeline;
+					duration = Math.max(duration, flipTimeline.frames[flipTimeline.frameCount * 3 - 3]);
+
 				} else
 					throw new Error("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")");
 			}

+ 73 - 0
spine-as3/spine-as3/src/spine/animation/FlipXTimeline.as

@@ -0,0 +1,73 @@
+/******************************************************************************
+ * 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.animation {
+import spine.Bone;
+import spine.Event;
+import spine.Skeleton;
+
+public class FlipXTimeline implements Timeline {
+	public var boneIndex:int;
+	public var frames:Vector.<Number>; // time, flip, ...
+
+	public function FlipXTimeline (frameCount:int) {
+		frames = new Vector.<Number>(frameCount * 2, true);
+	}
+
+	public function get frameCount () : int {
+		return frames.length / 2;
+	}
+
+	/** Sets the time and angle of the specified keyframe. */
+	public function setFrame (frameIndex:int, time:Number, flip:Boolean) : void {
+		frameIndex *= 2;
+		frames[frameIndex] = time;
+		frames[int(frameIndex + 1)] = flip ? 1 : 0;
+	}
+
+	public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector.<Event>, alpha:Number) : void {
+		if (time < frames[0]) {
+			if (lastTime > time) apply(skeleton, lastTime, int.MAX_VALUE, null, 0);
+			return;
+		} else if (lastTime > time) //
+			lastTime = -1;
+
+		var frameIndex:int = (time >= frames[frames.length - 2] ? frames.length : Animation.binarySearch(frames, time, 2)) - 2;
+		if (frames[frameIndex] < lastTime) return;
+
+		setFlip(skeleton.bones[boneIndex], frames[frameIndex + 1] != 0);
+	}
+
+	protected function setFlip (bone:Bone, flip:Boolean) : void {
+		bone.flipX = flip;
+	}
+}
+
+}

+ 44 - 0
spine-as3/spine-as3/src/spine/animation/FlipYTimeline.as

@@ -0,0 +1,44 @@
+/******************************************************************************
+ * 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.animation {
+import spine.Bone;
+
+public class FlipYTimeline extends FlipXTimeline {
+	public function FlipYTimeline (frameCount:int) {
+		super(frameCount);
+	}
+
+	override protected function setFlip (bone:Bone, flip:Boolean) : void {
+		bone.flipY = flip;
+	}
+}
+
+}

+ 4 - 1
spine-as3/spine-as3/src/spine/flash/SkeletonSprite.as

@@ -97,6 +97,7 @@ public class SkeletonSprite extends Sprite {
 					bitmap.rotation = -regionAttachment.rotation;
 					bitmap.scaleX = regionAttachment.scaleX * (regionAttachment.width / region.width);
 					bitmap.scaleY = regionAttachment.scaleY * (regionAttachment.height / region.height);
+					
 
 					// Position using attachment translation, shifted as if scale and rotation were at image center.
 					var radians:Number = -regionAttachment.rotation * Math.PI / 180;
@@ -127,10 +128,12 @@ public class SkeletonSprite extends Sprite {
 				colorTransform.alphaMultiplier = skeleton.a * slot.a * regionAttachment.a;
 				wrapper.transform.colorTransform = colorTransform;
 
+				var bone:Bone = slot.bone;
 				var flipX:int = skeleton.flipX ? -1 : 1;
 				var flipY:int = skeleton.flipY ? -1 : 1;
+				if (bone.worldFlipX) flipX = -flipX;
+				if (bone.worldFlipY) flipY = -flipY;
 
-				var bone:Bone = slot.bone;
 				wrapper.x = bone.worldX;
 				wrapper.y = bone.worldY;
 				wrapper.rotation = -bone.worldRotation * flipX * flipY;