diff --git a/spine-as3/spine-as3-example/lib/spine-as3.swc b/spine-as3/spine-as3-example/lib/spine-as3.swc index d889ea6f5..0c56bafa6 100644 Binary files a/spine-as3/spine-as3-example/lib/spine-as3.swc and b/spine-as3/spine-as3-example/lib/spine-as3.swc differ diff --git a/spine-as3/spine-as3/src/spine/animation/AnimationState.as b/spine-as3/spine-as3/src/spine/animation/AnimationState.as index 2ab546f56..2bdfbe18b 100644 --- a/spine-as3/spine-as3/src/spine/animation/AnimationState.as +++ b/spine-as3/spine-as3/src/spine/animation/AnimationState.as @@ -38,8 +38,8 @@ package spine.animation { public class AnimationState { public static var SUBSEQUENT : int = 0; public static var FIRST : int = 1; - public static var DIP : int = 2; - public static var DIP_MIX : int = 3; + public static var HOLD : int = 2; + public static var HOLD_MIX : int = 3; internal static var emptyAnimation : Animation = new Animation("", new Vector.(), 0); public var data : AnimationStateData; public var tracks : Vector. = new Vector.(); @@ -112,6 +112,7 @@ package spine.animation { // End mixing from entries once all have completed. var from : TrackEntry = current.mixingFrom; current.mixingFrom = null; + if (from != null) from.mixingTo = null; while (from != null) { queue.end(from); from = from.mixingFrom; @@ -138,6 +139,7 @@ package spine.animation { // Require totalAlpha == 0 to ensure mixing is complete, unless mixDuration == 0 (the transition is a single frame). if (from.totalAlpha == 0 || to.mixDuration == 0) { to.mixingFrom = from.mixingFrom; + if (from.mixingFrom != null) from.mixingFrom.mixingTo = to; to.interruptAlpha = from.interruptAlpha; queue.end(from); } @@ -174,11 +176,11 @@ package spine.animation { var timelineCount : int = current.animation.timelines.length; var timelines : Vector. = current.animation.timelines; var ii : int = 0; - if (mix == 1 || blend == MixBlend.add) { + if (i == 0 && (mix == 1 || blend == MixBlend.add)) { for (ii = 0; ii < timelineCount; ii++) Timeline(timelines[ii]).apply(skeleton, animationLast, animationTime, events, mix, blend, MixDirection.In); } else { - var timelineData : Vector. = current.timelineData; + var timelineMode : Vector. = current.timelineMode; var firstFrame : Boolean = current.timelinesRotation.length == 0; if (firstFrame) current.timelinesRotation.length = timelineCount << 1; @@ -186,7 +188,7 @@ package spine.animation { for (ii = 0; ii < timelineCount; ii++) { var timeline : Timeline = timelines[ii]; - var timelineBlend : MixBlend = timelineData[ii] == AnimationState.SUBSEQUENT ? blend : MixBlend.setup; + var timelineBlend : MixBlend = timelineMode[ii] == AnimationState.SUBSEQUENT ? blend : MixBlend.setup; if (timeline is RotateTimeline) { applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame); } else @@ -222,15 +224,15 @@ package spine.animation { var animationLast : Number = from.animationLast, animationTime : Number = from.getAnimationTime(); var timelineCount : int = from.animation.timelines.length; var timelines : Vector. = from.animation.timelines; - var alphaDip : Number = from.alpha * to.interruptAlpha; - var alphaMix : Number = alphaDip * (1 - mix); + var alphaHold : Number = from.alpha * to.interruptAlpha; + var alphaMix : Number = alphaHold * (1 - mix); var i : int = 0; if (blend == MixBlend.add) { for (i = 0; i < timelineCount; i++) timelines[i].apply(skeleton, animationLast, animationTime, events, alphaMix, blend, MixDirection.Out); } else { - var timelineData : Vector. = from.timelineData; - var timelineDipMix : Vector. = from.timelineDipMix; + var timelineMode : Vector. = from.timelineMode; + var timelineHoldMix : Vector. = from.timelineHoldMix; var firstFrame : Boolean = from.timelinesRotation.length == 0; if (firstFrame) from.timelinesRotation.length = timelineCount << 1; @@ -241,7 +243,7 @@ package spine.animation { var timeline : Timeline = timelines[i]; var timelineBlend: MixBlend; var alpha : Number = 0; - switch (timelineData[i]) { + switch (timelineMode[i]) { case SUBSEQUENT: if (!attachments && timeline is AttachmentTimeline) continue; if (!drawOrder && timeline is DrawOrderTimeline) continue; @@ -252,14 +254,14 @@ package spine.animation { timelineBlend = MixBlend.setup; alpha = alphaMix; break; - case DIP: + case HOLD: timelineBlend = MixBlend.setup; - alpha = alphaDip; + alpha = alphaHold; break; default: timelineBlend = MixBlend.setup; - var dipMix : TrackEntry = timelineDipMix[i]; - alpha = alphaDip * Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration); + var holdMix : TrackEntry = timelineHoldMix[i]; + alpha = alphaHold * Math.max(0, 1 - holdMix.mixTime / holdMix.mixDuration); break; } from.totalAlpha += alpha; @@ -399,6 +401,7 @@ package spine.animation { if (from == null) break; queue.end(from); entry.mixingFrom = null; + entry.mixingTo = null; entry = from; } @@ -414,6 +417,7 @@ package spine.animation { if (from != null) { if (interrupt) queue.interrupt(from); current.mixingFrom = from; + from.mixingTo = current; current.mixTime = 0; // Store the interrupted mix percentage. @@ -529,6 +533,7 @@ package spine.animation { entry.trackIndex = trackIndex; entry.animation = animation; entry.loop = loop; + entry.holdPrevious = false; entry.eventThreshold = 0; entry.attachmentThreshold = 0; @@ -565,14 +570,69 @@ package spine.animation { private function _animationsChanged() : void { animationsChanged = false; - var propertyIDs : Dictionary = this.propertyIDs = new Dictionary(); - var mixingTo : Vector. = this.mixingTo; + propertyIDs = new Dictionary(); + for (var i : int = 0, n : int = tracks.length; i < n; i++) { var entry : TrackEntry = tracks[i]; - if (entry != null && (i == 0 || entry.mixBlend != MixBlend.add)) - entry.setTimelineData(null, mixingTo, propertyIDs); + if (entry == null) continue; + while (entry.mixingFrom != null) + entry = entry.mixingFrom; + do { + if (entry.mixingTo == null || entry.mixBlend != MixBlend.add) setTimelineModes(entry); + entry = entry.mixingTo; + } while (entry != null); } } + + private function setTimelineModes (entry: TrackEntry) { + var to: TrackEntry = entry.mixingTo; + var timelines : Vector. = entry.animation.timelines; + var timelinesCount : int = entry.animation.timelines.length; + var timelineMode : Vector. = entry.timelineMode; + timelineMode.length = timelinesCount; + var timelineHoldMix : Vector. = entry.timelineHoldMix; + timelineHoldMix.length = 0; + var propertyIDs: Dictionary = this.propertyIDs; + + if (to != null && to.holdPrevious) { + for (var i : int = 0; i < timelinesCount; i++) { + propertyIDs[timelines[i].getPropertyId().toString()] = true; + timelineMode[i] = HOLD; + } + return; + } + + outer: + for (var i : int = 0; i < timelinesCount; i++) { + var intId : int = timelines[i].getPropertyId(); + var id : String = intId.toString(); + var contained: Object = propertyIDs[id]; + propertyIDs[id] = true; + if (contained != null) { + timelineMode[i] = AnimationState.SUBSEQUENT; + } else if (to == null || !hasTimeline(to, intId)) { + timelineMode[i] = AnimationState.FIRST; + } else { + for (var next : TrackEntry = to.mixingTo; next != null; next = next.mixingTo) { + if (hasTimeline(next, intId)) continue; + if (entry.mixDuration > 0) { + timelineMode[i] = AnimationState.HOLD_MIX; + timelineHoldMix[i] = entry; + continue outer; + } + break; + } + timelineMode[i] = AnimationState.HOLD; + } + } + } + + private static function hasTimeline (entry: TrackEntry, id : int) : Boolean { + var timelines : Vector. = entry.animation.timelines; + for (var i : int = 0, n : int = entry.animation.timelines.length; i < n; i++) + if (timelines[i].getPropertyId() == id) return true; + return false; + } public function getCurrent(trackIndex : int) : TrackEntry { if (trackIndex >= tracks.length) return null; diff --git a/spine-as3/spine-as3/src/spine/animation/TrackEntry.as b/spine-as3/spine-as3/src/spine/animation/TrackEntry.as index 3bd11d235..b053c31db 100644 --- a/spine-as3/spine-as3/src/spine/animation/TrackEntry.as +++ b/spine-as3/spine-as3/src/spine/animation/TrackEntry.as @@ -34,7 +34,7 @@ package spine.animation { public class TrackEntry implements Poolable { public var animation : Animation; - public var next : TrackEntry, mixingFrom : TrackEntry; + public var next : TrackEntry, mixingFrom : TrackEntry, mixingTo: TrackEntry; public var onStart : Listeners = new Listeners(); public var onInterrupt : Listeners = new Listeners(); public var onEnd : Listeners = new Listeners(); @@ -42,14 +42,14 @@ package spine.animation { public var onComplete : Listeners = new Listeners(); public var onEvent : Listeners = new Listeners(); public var trackIndex : int; - public var loop : Boolean; + public var loop : Boolean, holdPrevious: Boolean; public var eventThreshold : Number, attachmentThreshold : Number, drawOrderThreshold : Number; public var animationStart : Number, animationEnd : Number, animationLast : Number, nextAnimationLast : Number; public var delay : Number, trackTime : Number, trackLast : Number, nextTrackLast : Number, trackEnd : Number, timeScale : Number; public var alpha : Number, mixTime : Number, mixDuration : Number, interruptAlpha : Number, totalAlpha : Number = 0; public var mixBlend: MixBlend = MixBlend.replace; - public var timelineData : Vector. = new Vector.(); - public var timelineDipMix : Vector. = new Vector.(); + public var timelineMode : Vector. = new Vector.(); + public var timelineHoldMix : Vector. = new Vector.(); public var timelinesRotation : Vector. = new Vector.(); public function TrackEntry() { @@ -67,6 +67,7 @@ package spine.animation { public function reset() : void { next = null; mixingFrom = null; + mixingTo = null; animation = null; onStart.listeners.length = 0; onInterrupt.listeners.length = 0; @@ -74,60 +75,10 @@ package spine.animation { onDispose.listeners.length = 0; onComplete.listeners.length = 0; onEvent.listeners.length = 0; - timelineData.length = 0; - timelineDipMix.length = 0; + timelineMode.length = 0; + timelineHoldMix.length = 0; timelinesRotation.length = 0; - } - - public function setTimelineData (to: TrackEntry, mixingToArray : Vector., propertyIDs : Dictionary) : TrackEntry { - if (to != null) mixingToArray.push(to); - var lastEntry : TrackEntry = mixingFrom != null ? mixingFrom.setTimelineData(this, mixingToArray, propertyIDs) : this; - if (to != null) mixingToArray.pop(); - - var mixingTo : Vector. = mixingToArray; - var mixingToLast : int = mixingToArray.length - 1; - var timelines : Vector. = animation.timelines; - var timelinesCount : int = animation.timelines.length; - var timelineData : Vector. = this.timelineData; - timelineData.length = timelinesCount; - this.timelineDipMix.length = 0; - var timelineDipMix : Vector. = this.timelineDipMix; - timelineDipMix.length = timelinesCount; - - outer: - for (var i : int = 0; i < timelinesCount; i++) { - var intId : int = timelines[i].getPropertyId(); - var id : String = intId.toString(); - var contained: Object = propertyIDs[id]; - propertyIDs[id] = true; - if (contained != null) { - timelineData[i] = AnimationState.SUBSEQUENT; - } else if (to == null || !to.hasTimeline(intId)) { - timelineData[i] = AnimationState.FIRST; - } else { - for (var ii : int = mixingToLast; ii >= 0; ii--) { - var entry : TrackEntry = mixingTo[ii]; - if (!entry.hasTimeline(intId)) { - if (entry.mixDuration > 0) { - timelineData[i] = AnimationState.DIP_MIX; - timelineDipMix[i] = entry; - continue outer; - } - break; - } - } - timelineData[i] = AnimationState.DIP; - } - } - return lastEntry; - } - - private function hasTimeline (id : int) : Boolean { - var timelines : Vector. = animation.timelines; - for (var i : int = 0, n : int = animation.timelines.length; i < n; i++) - if (timelines[i].getPropertyId() == id) return true; - return false; - } + } public function resetRotationDirection() : void { timelinesRotation.length = 0; diff --git a/spine-starling/spine-starling-example/lib/spine-as3.swc b/spine-starling/spine-starling-example/lib/spine-as3.swc index 742e85aab..41e3bbd62 100644 Binary files a/spine-starling/spine-starling-example/lib/spine-as3.swc and b/spine-starling/spine-starling-example/lib/spine-as3.swc differ diff --git a/spine-starling/spine-starling-example/src/spine/examples/SpineboyExample.as b/spine-starling/spine-starling-example/src/spine/examples/SpineboyExample.as index 869420299..ade06cb1c 100644 --- a/spine-starling/spine-starling-example/src/spine/examples/SpineboyExample.as +++ b/spine-starling/spine-starling-example/src/spine/examples/SpineboyExample.as @@ -69,6 +69,7 @@ package spine.examples { var skeletonData : SkeletonData = json.readSkeletonData(new SpineboyJson()); var stateData : AnimationStateData = new AnimationStateData(skeletonData); + stateData.setMixByName("walk", "run", 0.4); stateData.setMixByName("run", "jump", 0.4); stateData.setMixByName("jump", "run", 0.4); stateData.setMixByName("jump", "jump", 0.4); diff --git a/spine-starling/spine-starling/lib/spine-as3.swc b/spine-starling/spine-starling/lib/spine-as3.swc index 742e85aab..41e3bbd62 100644 Binary files a/spine-starling/spine-starling/lib/spine-as3.swc and b/spine-starling/spine-starling/lib/spine-as3.swc differ