diff --git a/spine-as3/spine-as3/lib/spine-as3.swc b/spine-as3/spine-as3/lib/spine-as3.swc index a12763387..f99cc195f 100644 Binary files a/spine-as3/spine-as3/lib/spine-as3.swc and b/spine-as3/spine-as3/lib/spine-as3.swc differ diff --git a/spine-as3/spine-as3/src/spine/Slot.as b/spine-as3/spine-as3/src/spine/Slot.as index 9af450503..ac25f6515 100644 --- a/spine-as3/spine-as3/src/spine/Slot.as +++ b/spine-as3/spine-as3/src/spine/Slot.as @@ -37,8 +37,10 @@ package spine { public var darkColor : Color; internal var _attachment : Attachment; private var _attachmentTime : Number; + private var _attachmentState : Number; public var deform : Vector. = new Vector.(); + public function Slot(data : SlotData, bone : Bone) { if (data == null) throw new ArgumentError("data cannot be null."); if (bone == null) throw new ArgumentError("bone cannot be null."); @@ -84,6 +86,14 @@ package spine { return _bone._skeleton.time - _attachmentTime; } + public function get attachmentState() : Number { + return _attachmentState; + } + + public function set attachmentState(state : Number) : void { + _attachmentState = state; + } + public function setToSetupPose() : void { color.setFromColor(data.color); if (darkColor != null) darkColor.setFromColor(this.data.darkColor); diff --git a/spine-as3/spine-as3/src/spine/animation/AnimationState.as b/spine-as3/spine-as3/src/spine/animation/AnimationState.as index 3153b3f9b..d051ee4ae 100644 --- a/spine-as3/spine-as3/src/spine/animation/AnimationState.as +++ b/spine-as3/spine-as3/src/spine/animation/AnimationState.as @@ -34,13 +34,16 @@ package spine.animation { import spine.Pool; import spine.Skeleton; import flash.utils.Dictionary; + import spine.Slot; public class AnimationState { public static var SUBSEQUENT : int = 0; public static var FIRST : int = 1; public static var HOLD : int = 2; public static var HOLD_MIX : int = 3; - public static var NOT_LAST : int = 4; + public static var SETUP : int = 1; + public static var CURRENT : int = 2; + internal static var emptyAnimation : Animation = new Animation("", new Vector.(), 0); public var data : AnimationStateData; public var tracks : Vector. = new Vector.(); @@ -57,6 +60,7 @@ package spine.animation { internal var animationsChanged : Boolean; public var timeScale : Number = 1; internal var trackEntryPool : Pool; + internal var unkeyedState : int = 0; public function AnimationState(data : AnimationStateData) { if (data == null) throw new ArgumentError("data can not be null"); @@ -178,8 +182,14 @@ package spine.animation { var timelines : Vector. = current.animation.timelines; var ii : int = 0; 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); + for (ii = 0; ii < timelineCount; ii++) { + var timeline : Timeline = timelines[ii]; + if (timeline is AttachmentTimeline) { + applyAttachmentTimeline(AttachmentTimeline(timeline), skeleton, animationTime, blend, true); + } else { + timeline.apply(skeleton, animationLast, animationTime, events, mix, blend, MixDirection.In); + } + } } else { var timelineMode : Vector. = current.timelineMode; @@ -189,9 +199,11 @@ package spine.animation { for (ii = 0; ii < timelineCount; ii++) { var timeline : Timeline = timelines[ii]; - var timelineBlend : MixBlend = (timelineMode[ii] & (NOT_LAST - 1)) == SUBSEQUENT ? blend : MixBlend.setup; + var timelineBlend : MixBlend = timelineMode[ii] == SUBSEQUENT ? blend : MixBlend.setup; if (timeline is RotateTimeline) { applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame); + } else if (timeline is AttachmentTimeline) { + applyAttachmentTimeline(AttachmentTimeline(timeline), skeleton, animationTime, timelineBlend, true); } else timeline.apply(skeleton, animationLast, animationTime, events, mix, timelineBlend, MixDirection.In); } @@ -202,6 +214,20 @@ package spine.animation { current.nextTrackLast = current.trackTime; } + // Set slots attachments to the setup pose, if needed. This occurs if an animation that is mixing out sets attachments so + // subsequent timelines see any deform, but the subsequent timelines don't set an attachment (eg they are also mixing out or + // the time is before the first key). + var setupState : int = unkeyedState + SETUP; + var slots : Vector. = skeleton.slots; + for (var i : int = 0, n : int = skeleton.slots.length; i < n; i++) { + var slot : Slot = slots[i]; + if (slot.attachmentState == setupState) { + var attachmentName : String = slot.data.attachmentName; + slot.attachment = (attachmentName == null ? null : skeleton.getAttachmentForSlotIndex(slot.data.index, attachmentName)); + } + } + this.unkeyedState += 2; // Increasing after each use avoids the need to reset attachmentState for every slot. + queue.drain(); return applied; } @@ -245,14 +271,10 @@ package spine.animation { var direction : MixDirection = MixDirection.Out; var timelineBlend: MixBlend; var alpha : Number = 0; - switch (timelineMode[i] & (NOT_LAST - 1)) { + switch (timelineMode[i]) { case SUBSEQUENT: - timelineBlend = blend; - if (!attachments && timeline is AttachmentTimeline) { - if ((timelineMode[i] & NOT_LAST) == NOT_LAST) continue; - timelineBlend = MixBlend.setup; - } if (!drawOrder && timeline is DrawOrderTimeline) continue; + timelineBlend = blend; alpha = alphaMix; break; case FIRST: @@ -272,14 +294,10 @@ package spine.animation { from.totalAlpha += alpha; if (timeline is RotateTimeline) applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame); - else { - if (timelineBlend == MixBlend.setup) { - if (timeline is AttachmentTimeline) { - if (attachments || ((timelineMode[i] & NOT_LAST) == NOT_LAST)) direction = MixDirection.In; - } else if (timeline is DrawOrderTimeline) { - if (drawOrder) direction = MixDirection.In; - } - } + else if (timeline is AttachmentTimeline) { + applyAttachmentTimeline(AttachmentTimeline(timeline), skeleton, animationTime, timelineBlend, attachments); + } else { + if (drawOrder && timeline is DrawOrderTimeline && timelineBlend == MixBlend.setup) direction = MixDirection.In; timeline.apply(skeleton, animationLast, animationTime, events, alpha, timelineBlend, direction); } } @@ -293,6 +311,33 @@ package spine.animation { return mix; } + private function applyAttachmentTimeline (timeline: AttachmentTimeline, skeleton: Skeleton, time: Number, blend: MixBlend, attachments: Boolean) : void { + var slot : Slot = skeleton.slots[timeline.slotIndex]; + if (!slot.bone.active) return; + + var frames : Vector. = timeline.frames; + if (time < frames[0]) { // Time is before first frame. + if (blend == MixBlend.setup || blend == MixBlend.first) + setAttachment(skeleton, slot, slot.data.attachmentName, attachments); + } + else { + var frameIndex : Number; + if (time >= frames[frames.length - 1]) // Time is after last frame. + frameIndex = frames.length - 1; + else + frameIndex = Animation.binarySearch1(frames, time) - 1; + setAttachment(skeleton, slot, timeline.attachmentNames[frameIndex], attachments); + } + + // If an attachment wasn't set (ie before the first frame or attachments is false), set the setup attachment later. + if (slot.attachmentState <= unkeyedState) slot.attachmentState = unkeyedState + SETUP; + } + + private function setAttachment (skeleton: Skeleton, slot: Slot, attachmentName: String, attachments: Boolean) : void { + slot.attachment = attachmentName == null ? null : skeleton.getAttachmentForSlotIndex(slot.data.index, attachmentName); + if (attachments) slot.attachmentState = unkeyedState + CURRENT; + } + private function applyRotateTimeline(timeline : Timeline, skeleton : Skeleton, time : Number, alpha : Number, blend : MixBlend, timelinesRotation : Vector., i : int, firstFrame : Boolean) : void { if (firstFrame) timelinesRotation[i] = 0; @@ -604,35 +649,6 @@ package spine.animation { entry = entry.mixingTo; } while (entry != null); } - - propertyIDs = new Dictionary(); - for (i = tracks.length - 1; i >= 0; i--) { - entry = tracks[i]; - while (entry != null) { - computeNotLast(entry); - entry = entry.mixingFrom; - } - } - } - - private function computeNotLast (entry: TrackEntry) : void { - var timelines : Vector. = entry.animation.timelines; - var timelinesCount : int = entry.animation.timelines.length; - var timelineMode : Vector. = entry.timelineMode; - var propertyIDs : Dictionary = this.propertyIDs; - - for (var i : int = 0; i < timelinesCount; i++) { - if (timelines[i] is AttachmentTimeline) { - var timeline : AttachmentTimeline = AttachmentTimeline(timelines[i]); - var intId : int = timeline.slotIndex; - var id : String = intId.toString(); - var contained : Object = propertyIDs[id]; - propertyIDs[id] = true; - if (contained != null) { - timelineMode[i] |= NOT_LAST; - } - } - } } private function computeHold (entry: TrackEntry) : void { diff --git a/spine-as3/spine-as3/src/spine/animation/AttachmentTimeline.as b/spine-as3/spine-as3/src/spine/animation/AttachmentTimeline.as index ba2a7422a..df3d8d89d 100644 --- a/spine-as3/spine-as3/src/spine/animation/AttachmentTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/AttachmentTimeline.as @@ -60,16 +60,14 @@ package spine.animation { var attachmentName : String; var slot : Slot = skeleton.slots[slotIndex]; if (!slot.bone.active) return; - if (direction == MixDirection.Out && blend == MixBlend.setup) { - attachmentName = slot.data.attachmentName; - slot.attachment = attachmentName == null ? null : skeleton.getAttachmentForSlotIndex(slotIndex, attachmentName); + if (direction == MixDirection.Out) { + if (blend == MixBlend.setup) setAttachment(skeleton, slot, slot.data.attachmentName); return; } var frames : Vector. = this.frames; if (time < frames[0]) { if (blend == MixBlend.setup || blend == MixBlend.first) { - attachmentName = slot.data.attachmentName; - slot.attachment = attachmentName == null ? null : skeleton.getAttachmentForSlotIndex(slotIndex, attachmentName); + setAttachment(skeleton, slot, slot.data.attachmentName); } return; } @@ -83,5 +81,9 @@ package spine.animation { attachmentName = attachmentNames[frameIndex]; skeleton.slots[slotIndex].attachment = attachmentName == null ? null : skeleton.getAttachmentForSlotIndex(slotIndex, attachmentName); } + + private function setAttachment(skeleton: Skeleton, slot: Slot, attachmentName: String) : void { + slot.attachment = attachmentName == null ? null : skeleton.getAttachmentForSlotIndex(slotIndex, attachmentName); + } } } diff --git a/spine-as3/spine-as3/src/spine/animation/DrawOrderTimeline.as b/spine-as3/spine-as3/src/spine/animation/DrawOrderTimeline.as index c59aae3f8..e07b4f13a 100644 --- a/spine-as3/spine-as3/src/spine/animation/DrawOrderTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/DrawOrderTimeline.as @@ -56,9 +56,11 @@ package spine.animation { } public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector., alpha : Number, blend : MixBlend, direction : MixDirection) : void { - if (direction == MixDirection.Out && blend == MixBlend.setup) { - for (var ii : int = 0, n : int = skeleton.slots.length; ii < n; ii++) - skeleton.drawOrder[ii] = skeleton.slots[ii]; + if (direction == MixDirection.Out) { + if (blend == MixBlend.setup) { + for (var ii : int = 0, n : int = skeleton.slots.length; ii < n; ii++) + skeleton.drawOrder[ii] = skeleton.slots[ii]; + } return; } diff --git a/spine-starling/spine-starling-example/.vscode/settings.json b/spine-starling/spine-starling-example/.vscode/settings.json index 14d49200d..b2b814096 100644 --- a/spine-starling/spine-starling-example/.vscode/settings.json +++ b/spine-starling/spine-starling-example/.vscode/settings.json @@ -1,3 +1,3 @@ { - "as3mxml.sdk.framework": "/Applications/air-sdk" + "as3mxml.sdk.framework": "/Users/badlogic/workspaces/airsdk" } \ No newline at end of file diff --git a/spine-starling/spine-starling/.vscode/settings.json b/spine-starling/spine-starling/.vscode/settings.json index 14d49200d..b2b814096 100644 --- a/spine-starling/spine-starling/.vscode/settings.json +++ b/spine-starling/spine-starling/.vscode/settings.json @@ -1,3 +1,3 @@ { - "as3mxml.sdk.framework": "/Applications/air-sdk" + "as3mxml.sdk.framework": "/Users/badlogic/workspaces/airsdk" } \ No newline at end of file diff --git a/spine-starling/spine-starling/lib/spine-starling.swc b/spine-starling/spine-starling/lib/spine-starling.swc index edaa380d6..f314b21a8 100644 Binary files a/spine-starling/spine-starling/lib/spine-starling.swc and b/spine-starling/spine-starling/lib/spine-starling.swc differ