Browse Source

Merge branch '3.8' into 3.9-beta

Nathan Sweet 5 years ago
parent
commit
b0407a850c
41 changed files with 348 additions and 451 deletions
  1. BIN
      spine-as3/spine-as3/lib/spine-as3.swc
  2. 10 0
      spine-as3/spine-as3/src/spine/Slot.as
  3. 63 47
      spine-as3/spine-as3/src/spine/animation/AnimationState.as
  4. 7 5
      spine-as3/spine-as3/src/spine/animation/AttachmentTimeline.as
  5. 5 3
      spine-as3/spine-as3/src/spine/animation/DrawOrderTimeline.as
  6. 4 1
      spine-c/spine-c/include/spine/AnimationState.h
  7. 3 1
      spine-c/spine-c/include/spine/Slot.h
  8. 10 8
      spine-c/spine-c/src/spine/Animation.c
  9. 85 49
      spine-c/spine-c/src/spine/AnimationState.c
  10. 2 1
      spine-c/spine-c/src/spine/extension.c
  11. 7 2
      spine-cpp/spine-cpp/include/spine/AnimationState.h
  12. 6 3
      spine-cpp/spine-cpp/include/spine/AttachmentTimeline.h
  13. 5 0
      spine-cpp/spine-cpp/include/spine/Slot.h
  14. 64 49
      spine-cpp/spine-cpp/src/spine/AnimationState.cpp
  15. 9 7
      spine-cpp/spine-cpp/src/spine/AttachmentTimeline.cpp
  16. 7 5
      spine-cpp/spine-cpp/src/spine/DrawOrderTimeline.cpp
  17. 9 0
      spine-cpp/spine-cpp/src/spine/Slot.cpp
  18. 3 34
      spine-csharp/src/AnimationState.cs
  19. 25 17
      spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java
  20. 1 1
      spine-starling/spine-starling-example/.vscode/settings.json
  21. 1 1
      spine-starling/spine-starling/.vscode/settings.json
  22. BIN
      spine-starling/spine-starling/lib/spine-starling.swc
  23. 0 2
      spine-ts/build/spine-all.d.ts
  24. 3 28
      spine-ts/build/spine-all.js
  25. 0 0
      spine-ts/build/spine-all.js.map
  26. 0 2
      spine-ts/build/spine-canvas.d.ts
  27. 3 28
      spine-ts/build/spine-canvas.js
  28. 0 0
      spine-ts/build/spine-canvas.js.map
  29. 0 2
      spine-ts/build/spine-core.d.ts
  30. 3 28
      spine-ts/build/spine-core.js
  31. 0 0
      spine-ts/build/spine-core.js.map
  32. 0 2
      spine-ts/build/spine-player.d.ts
  33. 3 28
      spine-ts/build/spine-player.js
  34. 0 0
      spine-ts/build/spine-player.js.map
  35. 0 2
      spine-ts/build/spine-threejs.d.ts
  36. 3 28
      spine-ts/build/spine-threejs.js
  37. 0 0
      spine-ts/build/spine-threejs.js.map
  38. 0 2
      spine-ts/build/spine-webgl.d.ts
  39. 3 28
      spine-ts/build/spine-webgl.js
  40. 0 0
      spine-ts/build/spine-webgl.js.map
  41. 4 37
      spine-ts/core/src/AnimationState.ts

BIN
spine-as3/spine-as3/lib/spine-as3.swc


+ 10 - 0
spine-as3/spine-as3/src/spine/Slot.as

@@ -37,8 +37,10 @@ package spine {
 		public var darkColor : Color;
 		public var darkColor : Color;
 		internal var _attachment : Attachment;
 		internal var _attachment : Attachment;
 		private var _attachmentTime : Number;
 		private var _attachmentTime : Number;
+		private var _attachmentState : Number;
 		public var deform : Vector.<Number> = new Vector.<Number>();
 		public var deform : Vector.<Number> = new Vector.<Number>();
 
 
+
 		public function Slot(data : SlotData, bone : Bone) {
 		public function Slot(data : SlotData, bone : Bone) {
 			if (data == null) throw new ArgumentError("data cannot be null.");
 			if (data == null) throw new ArgumentError("data cannot be null.");
 			if (bone == null) throw new ArgumentError("bone cannot be null.");
 			if (bone == null) throw new ArgumentError("bone cannot be null.");
@@ -84,6 +86,14 @@ package spine {
 			return _bone._skeleton.time - _attachmentTime;
 			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 {
 		public function setToSetupPose() : void {
 			color.setFromColor(data.color);
 			color.setFromColor(data.color);
 			if (darkColor != null) darkColor.setFromColor(this.data.darkColor);
 			if (darkColor != null) darkColor.setFromColor(this.data.darkColor);

+ 63 - 47
spine-as3/spine-as3/src/spine/animation/AnimationState.as

@@ -34,13 +34,16 @@ package spine.animation {
 	import spine.Pool;
 	import spine.Pool;
 	import spine.Skeleton;
 	import spine.Skeleton;
 	import flash.utils.Dictionary;
 	import flash.utils.Dictionary;
+	import spine.Slot;
 
 
 	public class AnimationState {
 	public class AnimationState {
 		public static var SUBSEQUENT : int = 0;
 		public static var SUBSEQUENT : int = 0;
 		public static var FIRST : int = 1;
 		public static var FIRST : int = 1;
 		public static var HOLD : int = 2;
 		public static var HOLD : int = 2;
 		public static var HOLD_MIX : int = 3;
 		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("<empty>", new Vector.<Timeline>(), 0);
 		internal static var emptyAnimation : Animation = new Animation("<empty>", new Vector.<Timeline>(), 0);
 		public var data : AnimationStateData;
 		public var data : AnimationStateData;
 		public var tracks : Vector.<TrackEntry> = new Vector.<TrackEntry>();
 		public var tracks : Vector.<TrackEntry> = new Vector.<TrackEntry>();
@@ -57,6 +60,7 @@ package spine.animation {
 		internal var animationsChanged : Boolean;
 		internal var animationsChanged : Boolean;
 		public var timeScale : Number = 1;
 		public var timeScale : Number = 1;
 		internal var trackEntryPool : Pool;
 		internal var trackEntryPool : Pool;
+		internal var unkeyedState : int = 0;
 
 
 		public function AnimationState(data : AnimationStateData) {
 		public function AnimationState(data : AnimationStateData) {
 			if (data == null) throw new ArgumentError("data can not be null");
 			if (data == null) throw new ArgumentError("data can not be null");
@@ -178,8 +182,14 @@ package spine.animation {
 				var timelines : Vector.<Timeline> = current.animation.timelines;
 				var timelines : Vector.<Timeline> = current.animation.timelines;
 				var ii : int = 0;
 				var ii : int = 0;
 				if ((i == 0 && 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);
+					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 {
 				} else {
 					var timelineMode : Vector.<int> = current.timelineMode;
 					var timelineMode : Vector.<int> = current.timelineMode;
 
 
@@ -189,9 +199,11 @@ package spine.animation {
 
 
 					for (ii = 0; ii < timelineCount; ii++) {
 					for (ii = 0; ii < timelineCount; ii++) {
 						var timeline : Timeline = timelines[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) {
 						if (timeline is RotateTimeline) {
 							applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
 							applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
+						} else if (timeline is AttachmentTimeline) {
+							applyAttachmentTimeline(AttachmentTimeline(timeline), skeleton, animationTime, timelineBlend, true);
 						} else
 						} else
 							timeline.apply(skeleton, animationLast, animationTime, events, mix, timelineBlend, MixDirection.In);
 							timeline.apply(skeleton, animationLast, animationTime, events, mix, timelineBlend, MixDirection.In);
 					}
 					}
@@ -202,6 +214,20 @@ package spine.animation {
 				current.nextTrackLast = current.trackTime;
 				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.<Slot> = 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();
 			queue.drain();
 			return applied;
 			return applied;
 		}
 		}
@@ -245,14 +271,10 @@ package spine.animation {
 					var direction : MixDirection = MixDirection.Out;
 					var direction : MixDirection = MixDirection.Out;
 					var timelineBlend: MixBlend;
 					var timelineBlend: MixBlend;
 					var alpha : Number = 0;
 					var alpha : Number = 0;
-					switch (timelineMode[i] & (NOT_LAST - 1)) {
+					switch (timelineMode[i]) {
 					case SUBSEQUENT:
 					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;
 						if (!drawOrder && timeline is DrawOrderTimeline) continue;
+						timelineBlend = blend;
 						alpha = alphaMix;
 						alpha = alphaMix;
 						break;
 						break;
 					case FIRST:
 					case FIRST:
@@ -272,14 +294,10 @@ package spine.animation {
 					from.totalAlpha += alpha;
 					from.totalAlpha += alpha;
 					if (timeline is RotateTimeline)
 					if (timeline is RotateTimeline)
 						applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);
 						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);
 						timeline.apply(skeleton, animationLast, animationTime, events, alpha, timelineBlend, direction);
 					}
 					}
 				}
 				}
@@ -293,6 +311,33 @@ package spine.animation {
 			return mix;
 			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.<Number> = 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.<Number>, i : int, firstFrame : Boolean) : void {
 		private function applyRotateTimeline(timeline : Timeline, skeleton : Skeleton, time : Number, alpha : Number, blend : MixBlend, timelinesRotation : Vector.<Number>, i : int, firstFrame : Boolean) : void {
 			if (firstFrame) timelinesRotation[i] = 0;
 			if (firstFrame) timelinesRotation[i] = 0;
 
 
@@ -604,35 +649,6 @@ package spine.animation {
 					entry = entry.mixingTo;
 					entry = entry.mixingTo;
 				} while (entry != null);
 				} 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.<Timeline> = entry.animation.timelines;
-			var timelinesCount : int = entry.animation.timelines.length;
-			var timelineMode : Vector.<int> = 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 {
 		private function computeHold (entry: TrackEntry) : void {

+ 7 - 5
spine-as3/spine-as3/src/spine/animation/AttachmentTimeline.as

@@ -60,16 +60,14 @@ package spine.animation {
 			var attachmentName : String;
 			var attachmentName : String;
 			var slot : Slot = skeleton.slots[slotIndex];
 			var slot : Slot = skeleton.slots[slotIndex];
 			if (!slot.bone.active) return;
 			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;
 				return;
 			}
 			}
 			var frames : Vector.<Number> = this.frames;
 			var frames : Vector.<Number> = this.frames;
 			if (time < frames[0]) {
 			if (time < frames[0]) {
 				if (blend == MixBlend.setup || blend == MixBlend.first) {
 				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;
 				return;
 			}
 			}
@@ -83,5 +81,9 @@ package spine.animation {
 			attachmentName = attachmentNames[frameIndex];
 			attachmentName = attachmentNames[frameIndex];
 			skeleton.slots[slotIndex].attachment = attachmentName == null ? null : skeleton.getAttachmentForSlotIndex(slotIndex, attachmentName);
 			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);
+		}
 	}
 	}
 }
 }

+ 5 - 3
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.<Event>, alpha : Number, blend : MixBlend, direction : MixDirection) : void {
 		public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, 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;
 				return;
 			}
 			}
 
 

+ 4 - 1
spine-c/spine-c/include/spine/AnimationState.h

@@ -107,6 +107,8 @@ struct spAnimationState {
 	void* rendererObject;
 	void* rendererObject;
 	void* userData;
 	void* userData;
 
 
+    int unkeyedState;
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 	spAnimationState() :
 	spAnimationState() :
 		data(0),
 		data(0),
@@ -115,7 +117,8 @@ struct spAnimationState {
 		listener(0),
 		listener(0),
 		timeScale(0),
 		timeScale(0),
 		rendererObject(0),
 		rendererObject(0),
-		userData(0) {
+		userData(0),
+		unkeyedState(0) {
 	}
 	}
 #endif
 #endif
 };
 };

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

@@ -44,7 +44,8 @@ typedef struct spSlot {
 	spBone* const bone;
 	spBone* const bone;
 	spColor color;
 	spColor color;
 	spColor* darkColor;
 	spColor* darkColor;
-	spAttachment* const attachment;
+	spAttachment* attachment;
+	int attachmentState;
 
 
 	int deformCapacity;
 	int deformCapacity;
 	int deformCount;
 	int deformCount;
@@ -57,6 +58,7 @@ typedef struct spSlot {
 		color(),
 		color(),
 		darkColor(0),
 		darkColor(0),
 		attachment(0),
 		attachment(0),
+		attachmentState(0),
 		deformCapacity(0),
 		deformCapacity(0),
 		deformCount(0),
 		deformCount(0),
 		deform(0) {
 		deform(0) {

+ 10 - 8
spine-c/spine-c/src/spine/Animation.c

@@ -819,6 +819,10 @@ void spTwoColorTimeline_setFrame (spTwoColorTimeline* self, int frameIndex, floa
 
 
 /**/
 /**/
 
 
+static void _spSetAttachment(spAttachmentTimeline* timeline, spSkeleton* skeleton, spSlot* slot, const char* attachmentName) {
+    slot->attachment = attachmentName == NULL ? NULL : spSkeleton_getAttachmentForSlotIndex(skeleton, timeline->slotIndex, attachmentName);
+}
+
 void _spAttachmentTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time,
 void _spAttachmentTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time,
 		spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
 		spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
 	const char* attachmentName;
 	const char* attachmentName;
@@ -827,17 +831,15 @@ void _spAttachmentTimeline_apply (const spTimeline* timeline, spSkeleton* skelet
 	spSlot* slot = skeleton->slots[self->slotIndex];
 	spSlot* slot = skeleton->slots[self->slotIndex];
 	if (!slot->bone->active) return;
 	if (!slot->bone->active) return;
 
 
-	if (direction == SP_MIX_DIRECTION_OUT && blend == SP_MIX_BLEND_SETUP) {
-		attachmentName = slot->data->attachmentName;
-		spSlot_setAttachment(slot, attachmentName ? spSkeleton_getAttachmentForSlotIndex(skeleton, self->slotIndex, attachmentName) : 0);
+	if (direction == SP_MIX_DIRECTION_OUT) {
+	    if (blend == SP_MIX_BLEND_SETUP)
+	        _spSetAttachment(self, skeleton, slot, slot->data->attachmentName);
 		return;
 		return;
 	}
 	}
 
 
 	if (time < self->frames[0]) {
 	if (time < self->frames[0]) {
 		if (blend == SP_MIX_BLEND_SETUP || blend == SP_MIX_BLEND_FIRST) {
 		if (blend == SP_MIX_BLEND_SETUP || blend == SP_MIX_BLEND_FIRST) {
-			attachmentName = slot->data->attachmentName;
-			spSlot_setAttachment(skeleton->slots[self->slotIndex],
-				attachmentName ? spSkeleton_getAttachmentForSlotIndex(skeleton, self->slotIndex, attachmentName) : 0);
+			_spSetAttachment(self, skeleton, slot, slot->data->attachmentName);
 		}
 		}
 		return;
 		return;
 	}
 	}
@@ -1230,8 +1232,8 @@ void _spDrawOrderTimeline_apply (const spTimeline* timeline, spSkeleton* skeleto
 	const int* drawOrderToSetupIndex;
 	const int* drawOrderToSetupIndex;
 	spDrawOrderTimeline* self = (spDrawOrderTimeline*)timeline;
 	spDrawOrderTimeline* self = (spDrawOrderTimeline*)timeline;
 
 
-	if (direction == SP_MIX_DIRECTION_OUT && blend == SP_MIX_BLEND_SETUP) {
-		memcpy(skeleton->drawOrder, skeleton->slots, self->slotsCount * sizeof(spSlot*));
+	if (direction == SP_MIX_DIRECTION_OUT ) {
+		if (blend == SP_MIX_BLEND_SETUP) memcpy(skeleton->drawOrder, skeleton->slots, self->slotsCount * sizeof(spSlot*));
 		return;
 		return;
 	}
 	}
 
 

+ 85 - 49
spine-c/spine-c/src/spine/AnimationState.c

@@ -35,7 +35,9 @@
 #define FIRST 1
 #define FIRST 1
 #define HOLD 2
 #define HOLD 2
 #define HOLD_MIX 3
 #define HOLD_MIX 3
-#define NOT_LAST 4
+
+#define SETUP 1
+#define CURRENT 2
 
 
 _SP_ARRAY_IMPLEMENT_TYPE(spTrackEntryArray, spTrackEntry*)
 _SP_ARRAY_IMPLEMENT_TYPE(spTrackEntryArray, spTrackEntry*)
 
 
@@ -52,6 +54,7 @@ void _spAnimationState_disposeTrackEntries (spAnimationState* state, spTrackEntr
 int /*boolean*/ _spAnimationState_updateMixingFrom (spAnimationState* self, spTrackEntry* entry, float delta);
 int /*boolean*/ _spAnimationState_updateMixingFrom (spAnimationState* self, spTrackEntry* entry, float delta);
 float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* entry, spSkeleton* skeleton, spMixBlend currentBlend);
 float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* entry, spSkeleton* skeleton, spMixBlend currentBlend);
 void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline* timeline, spSkeleton* skeleton, float time, float alpha, spMixBlend blend, float* timelinesRotation, int i, int /*boolean*/ firstFrame);
 void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline* timeline, spSkeleton* skeleton, float time, float alpha, spMixBlend blend, float* timelinesRotation, int i, int /*boolean*/ firstFrame);
+void _spAnimationState_applyAttachmentTimeline(spAnimationState* self, spTimeline* timeline, spSkeleton* skeleton, float animationTime, spMixBlend blend, int /*bool*/ firstFrame);
 void _spAnimationState_queueEvents (spAnimationState* self, spTrackEntry* entry, float animationTime);
 void _spAnimationState_queueEvents (spAnimationState* self, spTrackEntry* entry, float animationTime);
 void _spAnimationState_setCurrent (spAnimationState* self, int index, spTrackEntry* current, int /*boolean*/ interrupt);
 void _spAnimationState_setCurrent (spAnimationState* self, int index, spTrackEntry* current, int /*boolean*/ interrupt);
 spTrackEntry* _spAnimationState_expandToIndex (spAnimationState* self, int index);
 spTrackEntry* _spAnimationState_expandToIndex (spAnimationState* self, int index);
@@ -63,7 +66,6 @@ int* _spAnimationState_resizeTimelinesFirst(spTrackEntry* entry, int newSize);
 void _spAnimationState_ensureCapacityPropertyIDs(spAnimationState* self, int capacity);
 void _spAnimationState_ensureCapacityPropertyIDs(spAnimationState* self, int capacity);
 int _spAnimationState_addPropertyID(spAnimationState* self, int id);
 int _spAnimationState_addPropertyID(spAnimationState* self, int id);
 void _spTrackEntry_computeHold(spTrackEntry* self, spAnimationState* state);
 void _spTrackEntry_computeHold(spTrackEntry* self, spAnimationState* state);
-void _spTrackEntry_computeNotLast(spTrackEntry* self, spAnimationState* state);
 
 
 _spEventQueue* _spEventQueue_create (_spAnimationState* state) {
 _spEventQueue* _spEventQueue_create (_spAnimationState* state) {
 	_spEventQueue *self = CALLOC(_spEventQueue, 1);
 	_spEventQueue *self = CALLOC(_spEventQueue, 1);
@@ -356,6 +358,10 @@ int spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
 	int applied = 0;
 	int applied = 0;
 	spMixBlend blend;
 	spMixBlend blend;
 	spMixBlend timelineBlend;
 	spMixBlend timelineBlend;
+	int setupState = 0;
+	spSlot** slots = NULL;
+	spSlot* slot = NULL;
+    const char* attachmentName = NULL;
 
 
 	if (internal->animationsChanged) _spAnimationState_animationsChanged(self);
 	if (internal->animationsChanged) _spAnimationState_animationsChanged(self);
 
 
@@ -378,8 +384,14 @@ int spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
 		timelineCount = current->animation->timelinesCount;
 		timelineCount = current->animation->timelinesCount;
 		timelines = current->animation->timelines;
 		timelines = current->animation->timelines;
 		if ((i == 0 && mix == 1) || blend == SP_MIX_BLEND_ADD) {
 		if ((i == 0 && mix == 1) || blend == SP_MIX_BLEND_ADD) {
-			for (ii = 0; ii < timelineCount; ii++)
-				spTimeline_apply(timelines[ii], skeleton, animationLast, animationTime, internal->events, &internal->eventsCount, mix, blend, SP_MIX_DIRECTION_IN);
+			for (ii = 0; ii < timelineCount; ii++) {
+			    if (timeline->type == SP_TIMELINE_ATTACHMENT) {
+                    _spAnimationState_applyAttachmentTimeline(self, timeline, skeleton, animationTime, blend, -1);
+			    } else {
+                    spTimeline_apply(timelines[ii], skeleton, animationLast, animationTime, internal->events,
+                                     &internal->eventsCount, mix, blend, SP_MIX_DIRECTION_IN);
+                }
+            }
 		} else {
 		} else {
 			spIntArray* timelineMode = current->timelineMode;
 			spIntArray* timelineMode = current->timelineMode;
 
 
@@ -389,9 +401,11 @@ int spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
 
 
 			for (ii = 0; ii < timelineCount; ii++) {
 			for (ii = 0; ii < timelineCount; ii++) {
 				timeline = timelines[ii];
 				timeline = timelines[ii];
-				timelineBlend = (timelineMode->items[ii] & (NOT_LAST - 1)) == SUBSEQUENT ? blend : SP_MIX_BLEND_SETUP;
+				timelineBlend = timelineMode->items[ii] == SUBSEQUENT ? blend : SP_MIX_BLEND_SETUP;
 				if (timeline->type == SP_TIMELINE_ROTATE)
 				if (timeline->type == SP_TIMELINE_ROTATE)
 					_spAnimationState_applyRotateTimeline(self, timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
 					_spAnimationState_applyRotateTimeline(self, timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
+				else if (timeline->type == SP_TIMELINE_ATTACHMENT)
+				    _spAnimationState_applyAttachmentTimeline(self, timeline, skeleton, animationTime, timelineBlend, -1);
 				else
 				else
 					spTimeline_apply(timeline, skeleton, animationLast, animationTime, internal->events, &internal->eventsCount, mix, timelineBlend, SP_MIX_DIRECTION_IN);
 					spTimeline_apply(timeline, skeleton, animationLast, animationTime, internal->events, &internal->eventsCount, mix, timelineBlend, SP_MIX_DIRECTION_IN);
 			}
 			}
@@ -402,6 +416,17 @@ int spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
 		current->nextTrackLast = current->trackTime;
 		current->nextTrackLast = current->trackTime;
 	}
 	}
 
 
+	setupState = self->unkeyedState + SETUP;
+    slots = skeleton->slots;
+    for (i = 0, n = skeleton->slotsCount; i < n; i++) {
+        slot = slots[i];
+        if (slot->attachmentState == setupState) {
+            attachmentName = slot->data->attachmentName;
+            slot->attachment = attachmentName == NULL ? NULL : spSkeleton_getAttachmentForSlotIndex(skeleton, slot->data->index, attachmentName);
+        }
+    }
+    self->unkeyedState += 2;
+
 	_spEventQueue_drain(internal->queue);
 	_spEventQueue_drain(internal->queue);
 	return applied;
 	return applied;
 }
 }
@@ -465,14 +490,10 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* t
 			spMixDirection direction = SP_MIX_DIRECTION_OUT;
 			spMixDirection direction = SP_MIX_DIRECTION_OUT;
 			spTimeline *timeline = timelines[i];
 			spTimeline *timeline = timelines[i];
 
 
-			switch (timelineMode->items[i] & (NOT_LAST - 1)) {
+			switch (timelineMode->items[i]) {
 				case SUBSEQUENT:
 				case SUBSEQUENT:
-					timelineBlend = blend;
-					if (!attachments && timeline->type == SP_TIMELINE_ATTACHMENT) {
-						if ((timelineMode->items[i] & NOT_LAST) == NOT_LAST) continue;
-						timelineBlend = SP_MIX_BLEND_SETUP;
-					}
 					if (!drawOrder && timeline->type == SP_TIMELINE_DRAWORDER) continue;
 					if (!drawOrder && timeline->type == SP_TIMELINE_DRAWORDER) continue;
+                    timelineBlend = blend;
 					alpha = alphaMix;
 					alpha = alphaMix;
 					break;
 					break;
 				case FIRST:
 				case FIRST:
@@ -493,15 +514,11 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* t
 			if (timeline->type == SP_TIMELINE_ROTATE)
 			if (timeline->type == SP_TIMELINE_ROTATE)
 				_spAnimationState_applyRotateTimeline(self, timeline, skeleton, animationTime, alpha, timelineBlend,
 				_spAnimationState_applyRotateTimeline(self, timeline, skeleton, animationTime, alpha, timelineBlend,
 					timelinesRotation, i << 1, firstFrame);
 					timelinesRotation, i << 1, firstFrame);
+			else if (timeline->type == SP_TIMELINE_ATTACHMENT)
+			    _spAnimationState_applyAttachmentTimeline(self, timeline, skeleton, animationTime, timelineBlend, attachments);
 			else {
 			else {
-				if (timelineBlend == SP_MIX_BLEND_SETUP) {
-					if (timeline->type == SP_TIMELINE_ATTACHMENT) {
-						if (attachments || (timelineMode->items[i] & NOT_LAST) == NOT_LAST) direction = SP_MIX_DIRECTION_IN;
-					} else if (timeline->type == SP_TIMELINE_DRAWORDER) {
-						if (drawOrder) direction = SP_MIX_DIRECTION_IN;
-					}
-				}
-
+                if (drawOrder && timeline->type == SP_TIMELINE_DRAWORDER && timelineBlend == SP_MIX_BLEND_SETUP)
+                    direction = SP_MIX_DIRECTION_IN;
 				spTimeline_apply(timeline, skeleton, animationLast, animationTime, events, &internal->eventsCount,
 				spTimeline_apply(timeline, skeleton, animationLast, animationTime, events, &internal->eventsCount,
 					alpha, timelineBlend, direction);
 					alpha, timelineBlend, direction);
 			}
 			}
@@ -517,6 +534,55 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* t
 	return mix;
 	return mix;
 }
 }
 
 
+static void _spAnimationState_setAttachment(spAnimationState* self, spSkeleton* skeleton, spSlot* slot, const char* attachmentName, int /*bool*/ attachments) {
+    slot->attachment = attachmentName == NULL ? NULL : spSkeleton_getAttachmentForSlotIndex(skeleton, slot->data->index, attachmentName);
+    if (attachments) slot->attachmentState = self->unkeyedState + CURRENT;
+}
+
+/* @param target After the first and before the last entry. */
+static int binarySearch1 (float *values, int valuesLength, float target) {
+    int low = 0, current;
+    int high = valuesLength - 2;
+    if (high == 0) return 1;
+    current = high >> 1;
+    while (1) {
+        if (values[(current + 1)] <= target)
+            low = current + 1;
+        else
+            high = current;
+        if (low == high) return low + 1;
+        current = (low + high) >> 1;
+    }
+    return 0;
+}
+
+void _spAnimationState_applyAttachmentTimeline(spAnimationState* self, spTimeline* timeline, spSkeleton* skeleton, float time, spMixBlend blend, int /*bool*/ attachments) {
+    spAttachmentTimeline* attachmentTimeline;
+    spSlot* slot;
+    int frameIndex;
+    float* frames;
+
+    attachmentTimeline = SUB_CAST(spAttachmentTimeline, timeline);
+    slot = skeleton->slots[attachmentTimeline->slotIndex];
+    if (!slot->bone->active) return;
+
+    frames = attachmentTimeline->frames;
+    if (time < frames[0]) {
+        if (blend == SP_MIX_BLEND_SETUP || blend == SP_MIX_BLEND_FIRST)
+        _spAnimationState_setAttachment(self, skeleton, slot, slot->data->attachmentName, attachments);
+    }
+    else {
+        if (time >= frames[attachmentTimeline->framesCount - 1])
+            frameIndex = attachmentTimeline->framesCount - 1;
+        else
+            frameIndex = binarySearch1(frames, attachmentTimeline->framesCount, time) - 1;
+        _spAnimationState_setAttachment(self, skeleton, slot, attachmentTimeline->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 <= self->unkeyedState) slot->attachmentState = self->unkeyedState + SETUP;
+}
+
 void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline* timeline, spSkeleton* skeleton, float time,
 void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline* timeline, spSkeleton* skeleton, float time,
 	float alpha, spMixBlend blend, float* timelinesRotation, int i, int /*boolean*/ firstFrame
 	float alpha, spMixBlend blend, float* timelinesRotation, int i, int /*boolean*/ firstFrame
 ) {
 ) {
@@ -874,17 +940,6 @@ void _spAnimationState_animationsChanged (spAnimationState* self) {
 			entry = entry->mixingTo;
 			entry = entry->mixingTo;
 		} while (entry != 0);
 		} while (entry != 0);
 	}
 	}
-
-	internal->propertyIDsCount = 0;
-	i = self->tracksCount - 1;
-	for (; i >= 0; i--) {
-		entry = self->tracks[i];
-		if (!entry) continue;
-		while (entry != 0) {
-			_spTrackEntry_computeNotLast(entry, self);
-			entry = entry->mixingFrom;
-		}
-	}
 }
 }
 
 
 float* _spAnimationState_resizeTimelinesRotation(spTrackEntry* entry, int newSize) {
 float* _spAnimationState_resizeTimelinesRotation(spTrackEntry* entry, int newSize) {
@@ -999,22 +1054,3 @@ void _spTrackEntry_computeHold(spTrackEntry* entry, spAnimationState* state) {
 		}
 		}
 	}
 	}
 }
 }
-
-void _spTrackEntry_computeNotLast(spTrackEntry* entry, spAnimationState* state) {
-	spTimeline** timelines ;
-	int timelinesCount;
-	int* timelineMode;
-	int i;
-
-	timelines = entry->animation->timelines;
-	timelinesCount = entry->animation->timelinesCount;
-	timelineMode = entry->timelineMode->items;
-
-	i = 0;
-	for (; i < timelinesCount; i++) {
-		if (timelines[i]->type == SP_TIMELINE_ATTACHMENT) {
-			spAttachmentTimeline* timeline = SUB_CAST(spAttachmentTimeline, timelines[i]);
-			if (!_spAnimationState_addPropertyID(state, timeline->slotIndex)) timelineMode[i] |= NOT_LAST;
-		}
-	}
-}

+ 2 - 1
spine-c/spine-c/src/spine/extension.c

@@ -84,6 +84,7 @@ void _spSetRandom (float (*random) ()) {
 
 
 char* _spReadFile (const char* path, int* length) {
 char* _spReadFile (const char* path, int* length) {
 	char *data;
 	char *data;
+	size_t result;
 	FILE *file = fopen(path, "rb");
 	FILE *file = fopen(path, "rb");
 	if (!file) return 0;
 	if (!file) return 0;
 
 
@@ -92,7 +93,7 @@ char* _spReadFile (const char* path, int* length) {
 	fseek(file, 0, SEEK_SET);
 	fseek(file, 0, SEEK_SET);
 
 
 	data = MALLOC(char, *length);
 	data = MALLOC(char, *length);
-	size_t result = fread(data, 1, *length, file);
+	result = fread(data, 1, *length, file);
 	UNUSED(result);
 	UNUSED(result);
 	fclose(file);
 	fclose(file);
 
 

+ 7 - 2
spine-cpp/spine-cpp/include/spine/AnimationState.h

@@ -36,6 +36,7 @@
 #include <spine/SpineObject.h>
 #include <spine/SpineObject.h>
 #include <spine/SpineString.h>
 #include <spine/SpineString.h>
 #include <spine/HasRendererObject.h>
 #include <spine/HasRendererObject.h>
+#include "Slot.h"
 
 
 #ifdef SPINE_USE_STD_FUNCTION
 #ifdef SPINE_USE_STD_FUNCTION
 #include <functional>
 #include <functional>
@@ -59,6 +60,7 @@ namespace spine {
 	class AnimationStateData;
 	class AnimationStateData;
 	class Skeleton;
 	class Skeleton;
 	class RotateTimeline;
 	class RotateTimeline;
+	class AttachmentTimeline;
 
 
 #ifdef SPINE_USE_STD_FUNCTION
 #ifdef SPINE_USE_STD_FUNCTION
 	typedef std::function<void (AnimationState* state, EventType type, TrackEntry* entry, Event* event)> AnimationStateListener;
 	typedef std::function<void (AnimationState* state, EventType type, TrackEntry* entry, Event* event)> AnimationStateListener;
@@ -399,11 +401,14 @@ namespace spine {
 		AnimationStateListener _listener;
 		AnimationStateListener _listener;
 		AnimationStateListenerObject* _listenerObject;
 		AnimationStateListenerObject* _listenerObject;
 
 
+		int _unkeyedState;
+
 		float _timeScale;
 		float _timeScale;
 
 
 		static Animation* getEmptyAnimation();
 		static Animation* getEmptyAnimation();
 
 
 		static void applyRotateTimeline(RotateTimeline* rotateTimeline, Skeleton& skeleton, float time, float alpha, MixBlend pose, Vector<float>& timelinesRotation, size_t i, bool firstFrame);
 		static void applyRotateTimeline(RotateTimeline* rotateTimeline, Skeleton& skeleton, float time, float alpha, MixBlend pose, Vector<float>& timelinesRotation, size_t i, bool firstFrame);
+        void applyAttachmentTimeline(AttachmentTimeline* attachmentTimeline, Skeleton& skeleton, float animationTime, MixBlend pose, bool firstFrame);
 
 
 		/// Returns true when all mixing from entries are complete.
 		/// Returns true when all mixing from entries are complete.
 		bool updateMixingFrom(TrackEntry* to, float delta);
 		bool updateMixingFrom(TrackEntry* to, float delta);
@@ -428,8 +433,8 @@ namespace spine {
 
 
 		void computeHold(TrackEntry *entry);
 		void computeHold(TrackEntry *entry);
 
 
-		void computeNotLast(TrackEntry *entry);
-	};
+        void setAttachment(Skeleton &skeleton, spine::Slot &slot, const String &attachmentName, bool attachments);
+    };
 }
 }
 
 
 #endif /* Spine_AnimationState_h */
 #endif /* Spine_AnimationState_h */

+ 6 - 3
spine-cpp/spine-cpp/include/spine/AttachmentTimeline.h

@@ -40,6 +40,7 @@
 namespace spine {
 namespace spine {
 
 
 	class Skeleton;
 	class Skeleton;
+	class Slot;
 	class Event;
 	class Event;
 
 
 	class SP_API AttachmentTimeline : public Timeline {
 	class SP_API AttachmentTimeline : public Timeline {
@@ -60,14 +61,16 @@ namespace spine {
 
 
 		size_t getSlotIndex();
 		size_t getSlotIndex();
 		void setSlotIndex(size_t inValue);
 		void setSlotIndex(size_t inValue);
-		const Vector<float>& getFrames();
-		const Vector<String>& getAttachmentNames();
+		Vector<float>& getFrames();
+		Vector<String>& getAttachmentNames();
 		size_t getFrameCount();
 		size_t getFrameCount();
 	private:
 	private:
 		size_t _slotIndex;
 		size_t _slotIndex;
 		Vector<float> _frames;
 		Vector<float> _frames;
 		Vector<String> _attachmentNames;
 		Vector<String> _attachmentNames;
-	};
+
+        void setAttachment(Skeleton& skeleton, Slot& slot, String* attachmentName);
+    };
 }
 }
 
 
 #endif /* Spine_AttachmentTimeline_h */
 #endif /* Spine_AttachmentTimeline_h */

+ 5 - 0
spine-cpp/spine-cpp/include/spine/Slot.h

@@ -102,6 +102,10 @@ public:
 
 
 	void setAttachment(Attachment *inValue);
 	void setAttachment(Attachment *inValue);
 
 
+	int getAttachmentState();
+
+	void setAttachmentState(int state);
+
 	float getAttachmentTime();
 	float getAttachmentTime();
 
 
 	void setAttachmentTime(float inValue);
 	void setAttachmentTime(float inValue);
@@ -116,6 +120,7 @@ private:
 	Color _darkColor;
 	Color _darkColor;
 	bool _hasDarkColor;
 	bool _hasDarkColor;
 	Attachment *_attachment;
 	Attachment *_attachment;
+	int _attachmentState;
 	float _attachmentTime;
 	float _attachmentTime;
 	Vector<float> _deform;
 	Vector<float> _deform;
 };
 };

+ 64 - 49
spine-cpp/spine-cpp/src/spine/AnimationState.cpp

@@ -43,6 +43,8 @@
 #include <spine/AttachmentTimeline.h>
 #include <spine/AttachmentTimeline.h>
 #include <spine/DrawOrderTimeline.h>
 #include <spine/DrawOrderTimeline.h>
 #include <spine/EventTimeline.h>
 #include <spine/EventTimeline.h>
+#include <spine/Slot.h>
+#include <spine/SlotData.h>
 
 
 #include <float.h>
 #include <float.h>
 
 
@@ -290,7 +292,9 @@ const int Subsequent = 0;
 const int First = 1;
 const int First = 1;
 const int Hold = 2;
 const int Hold = 2;
 const int HoldMix = 3;
 const int HoldMix = 3;
-const int NotLast = 4;
+
+const int Setup = 1;
+const int Current = 2;
 
 
 AnimationState::AnimationState(AnimationStateData *data) :
 AnimationState::AnimationState(AnimationStateData *data) :
 		_data(data),
 		_data(data),
@@ -298,6 +302,7 @@ AnimationState::AnimationState(AnimationStateData *data) :
 		_animationsChanged(false),
 		_animationsChanged(false),
 		_listener(dummyOnAnimationEventFunc),
 		_listener(dummyOnAnimationEventFunc),
 		_listenerObject(NULL),
 		_listenerObject(NULL),
+		_unkeyedState(0),
 		_timeScale(1) {
 		_timeScale(1) {
 }
 }
 
 
@@ -418,8 +423,13 @@ bool AnimationState::apply(Skeleton &skeleton) {
 		size_t timelineCount = current._animation->_timelines.size();
 		size_t timelineCount = current._animation->_timelines.size();
 		Vector<Timeline *> &timelines = current._animation->_timelines;
 		Vector<Timeline *> &timelines = current._animation->_timelines;
 		if ((i == 0 && mix == 1) || blend == MixBlend_Add) {
 		if ((i == 0 && mix == 1) || blend == MixBlend_Add) {
-			for (size_t ii = 0; ii < timelineCount; ++ii)
-				timelines[ii]->apply(skeleton, animationLast, animationTime, &_events, mix, blend, MixDirection_In);
+			for (size_t ii = 0; ii < timelineCount; ++ii) {
+                Timeline *timeline = timelines[ii];
+                if (timeline->getRTTI().isExactly(AttachmentTimeline::rtti))
+                    applyAttachmentTimeline(static_cast<AttachmentTimeline *>(timeline), skeleton, animationTime, blend, true);
+                else
+                    timeline->apply(skeleton, animationLast, animationTime, &_events, mix, blend, MixDirection_In);
+            }
 		} else {
 		} else {
 			Vector<int> &timelineMode = current._timelineMode;
 			Vector<int> &timelineMode = current._timelineMode;
 
 
@@ -431,13 +441,12 @@ bool AnimationState::apply(Skeleton &skeleton) {
 				Timeline *timeline = timelines[ii];
 				Timeline *timeline = timelines[ii];
 				assert(timeline);
 				assert(timeline);
 
 
-				MixBlend timelineBlend = (timelineMode[ii] & (NotLast - 1)) == Subsequent ? blend : MixBlend_Setup;
+				MixBlend timelineBlend = timelineMode[ii] == Subsequent ? blend : MixBlend_Setup;
 
 
-				RotateTimeline *rotateTimeline = NULL;
-				if (timeline->getRTTI().isExactly(RotateTimeline::rtti)) rotateTimeline = static_cast<RotateTimeline *>(timeline);
-
-				if (rotateTimeline != NULL)
-					applyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
+				if (timeline->getRTTI().isExactly(RotateTimeline::rtti))
+					applyRotateTimeline(static_cast<RotateTimeline *>(timeline), skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
+				else if (timeline->getRTTI().isExactly(AttachmentTimeline::rtti))
+                    applyAttachmentTimeline(static_cast<AttachmentTimeline *>(timeline), skeleton, animationTime, timelineBlend, true);
 				else
 				else
 					timeline->apply(skeleton, animationLast, animationTime, &_events, mix, timelineBlend, MixDirection_In);
 					timeline->apply(skeleton, animationLast, animationTime, &_events, mix, timelineBlend, MixDirection_In);
 			}
 			}
@@ -449,6 +458,17 @@ bool AnimationState::apply(Skeleton &skeleton) {
 		current._nextTrackLast = current._trackTime;
 		current._nextTrackLast = current._trackTime;
 	}
 	}
 
 
+    int setupState = _unkeyedState + Setup;
+    Vector<Slot*>& slots = skeleton.getSlots();
+    for (int i = 0, n = slots.size(); i < n; i++) {
+        Slot* slot = slots[i];
+        if (slot->getAttachmentState() == setupState) {
+            const String& attachmentName = slot->getData().getAttachmentName();
+            slot->setAttachment(attachmentName.isEmpty() ? NULL : skeleton.getAttachment(slot->getData().getIndex(), attachmentName));
+        }
+    }
+    _unkeyedState += 2;
+
 	_queue->drain();
 	_queue->drain();
 	return applied;
 	return applied;
 }
 }
@@ -636,6 +656,28 @@ Animation *AnimationState::getEmptyAnimation() {
 	return &ret;
 	return &ret;
 }
 }
 
 
+void AnimationState::applyAttachmentTimeline(AttachmentTimeline* attachmentTimeline, Skeleton& skeleton, float time, MixBlend blend, bool attachments) {
+    Slot* slot = skeleton.getSlots()[attachmentTimeline->getSlotIndex()];
+    if (!slot->getBone().isActive()) return;
+
+    Vector<float>& frames = attachmentTimeline->getFrames();
+    if (time < frames[0]) {
+        if (blend == MixBlend_Setup || blend == MixBlend_First)
+            setAttachment(skeleton, *slot, slot->getData().getAttachmentName(), attachments);
+    } else {
+        int frameIndex = 0;
+        if (time >= frames[attachmentTimeline->getFrames().size() - 1])
+            frameIndex = attachmentTimeline->getFrames().size() - 1;
+        else
+            frameIndex = Animation::binarySearch(frames, time) - 1;
+        setAttachment(skeleton, *slot, attachmentTimeline->getAttachmentNames()[frameIndex], attachments);
+    }
+
+    /* If an attachment wasn't set (ie before the first frame or attachments is false), set the setup attachment later.*/
+    if (slot->getAttachmentState() <= _unkeyedState) slot->setAttachmentState(_unkeyedState + Setup);
+}
+
+
 void AnimationState::applyRotateTimeline(RotateTimeline *rotateTimeline, Skeleton &skeleton, float time, float alpha,
 void AnimationState::applyRotateTimeline(RotateTimeline *rotateTimeline, Skeleton &skeleton, float time, float alpha,
 	MixBlend blend, Vector<float> &timelinesRotation, size_t i, bool firstFrame
 	MixBlend blend, Vector<float> &timelinesRotation, size_t i, bool firstFrame
 ) {
 ) {
@@ -784,14 +826,10 @@ float AnimationState::applyMixingFrom(TrackEntry *to, Skeleton &skeleton, MixBle
 			MixDirection direction = MixDirection_Out;
 			MixDirection direction = MixDirection_Out;
 			MixBlend timelineBlend;
 			MixBlend timelineBlend;
 			float alpha;
 			float alpha;
-			switch (timelineMode[i] & (NotLast - 1)) {
+			switch (timelineMode[i]) {
 				case Subsequent:
 				case Subsequent:
-					timelineBlend = blend;
-					if (!attachments && (timeline->getRTTI().isExactly(AttachmentTimeline::rtti))) {
-						if ((timelineMode[i] & NotLast) == NotLast) continue;
-						timelineBlend = MixBlend_Setup;
-					}
 					if (!drawOrder && (timeline->getRTTI().isExactly(DrawOrderTimeline::rtti))) continue;
 					if (!drawOrder && (timeline->getRTTI().isExactly(DrawOrderTimeline::rtti))) continue;
+                    timelineBlend = blend;
 					alpha = alphaMix;
 					alpha = alphaMix;
 					break;
 					break;
 				case First:
 				case First:
@@ -811,15 +849,12 @@ float AnimationState::applyMixingFrom(TrackEntry *to, Skeleton &skeleton, MixBle
 			from->_totalAlpha += alpha;
 			from->_totalAlpha += alpha;
 			if ((timeline->getRTTI().isExactly(RotateTimeline::rtti))) {
 			if ((timeline->getRTTI().isExactly(RotateTimeline::rtti))) {
 				applyRotateTimeline((RotateTimeline*)timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);
 				applyRotateTimeline((RotateTimeline*)timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);
-			} else {
-				if (timelineBlend == MixBlend_Setup) {
-					if (timeline->getRTTI().isExactly(AttachmentTimeline::rtti)) {
-						if (attachments || (timelineMode[i] & NotLast) == NotLast) direction = MixDirection_In;
-					} else if (timeline->getRTTI().isExactly(DrawOrderTimeline::rtti)) {
-						if (drawOrder) direction = MixDirection_In;
-					}
-				}
-				timeline->apply(skeleton, animationLast, animationTime, eventBuffer, alpha, timelineBlend, direction);
+			} else if (timeline->getRTTI().isExactly(AttachmentTimeline::rtti)) {
+                applyAttachmentTimeline(static_cast<AttachmentTimeline*>(timeline), skeleton, animationTime, timelineBlend, attachments);
+            } else {
+			    if (drawOrder && timeline->getRTTI().isExactly(DrawOrderTimeline::rtti) && timelineBlend == MixBlend_Setup)
+			        direction = MixDirection_In;
+			    timeline->apply(skeleton, animationLast, animationTime, eventBuffer, alpha, timelineBlend, direction);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -835,6 +870,11 @@ float AnimationState::applyMixingFrom(TrackEntry *to, Skeleton &skeleton, MixBle
 	return mix;
 	return mix;
 }
 }
 
 
+void AnimationState::setAttachment(Skeleton& skeleton, Slot& slot, const String& attachmentName, bool attachments) {
+    slot.setAttachment(attachmentName.isEmpty() ? NULL : skeleton.getAttachment(slot.getData().getIndex(), attachmentName));
+    if (attachments) slot.setAttachmentState(_unkeyedState + Current);
+}
+
 void AnimationState::queueEvents(TrackEntry *entry, float animationTime) {
 void AnimationState::queueEvents(TrackEntry *entry, float animationTime) {
 	float animationStart = entry->_animationStart, animationEnd = entry->_animationEnd;
 	float animationStart = entry->_animationStart, animationEnd = entry->_animationEnd;
 	float duration = animationEnd - animationStart;
 	float duration = animationEnd - animationStart;
@@ -953,15 +993,6 @@ void AnimationState::animationsChanged() {
 			entry = entry->_mixingTo;
 			entry = entry->_mixingTo;
 		} while (entry != NULL);
 		} while (entry != NULL);
 	}
 	}
-
-	_propertyIDs.clear();
-	for (int i = (int)_tracks.size() - 1; i >= 0; i--) {
-		TrackEntry *entry = _tracks[i];
-		while (entry) {
-			computeNotLast(entry);
-			entry = entry->_mixingFrom;
-		}
-	}
 }
 }
 
 
 void AnimationState::computeHold(TrackEntry *entry) {
 void AnimationState::computeHold(TrackEntry *entry) {
@@ -1013,19 +1044,3 @@ void AnimationState::computeHold(TrackEntry *entry) {
 		}
 		}
 	}
 	}
 }
 }
-
-void AnimationState::computeNotLast(TrackEntry *entry) {
-	Vector<Timeline *> &timelines = entry->_animation->_timelines;
-	size_t timelinesCount = timelines.size();
-	Vector<int> &timelineMode = entry->_timelineMode;
-
-	for (size_t i = 0; i < timelinesCount; i++) {
-		if (timelines[i]->getRTTI().isExactly(AttachmentTimeline::rtti)) {
-			AttachmentTimeline *timeline = static_cast<AttachmentTimeline *>(timelines[i]);
-			if (!_propertyIDs.containsKey(timeline->getSlotIndex()))
-				_propertyIDs.put(timeline->getSlotIndex(), true);
-			else
-				timelineMode[i] |= NotLast;
-		}
-	}
-}

+ 9 - 7
spine-cpp/spine-cpp/src/spine/AttachmentTimeline.cpp

@@ -57,6 +57,10 @@ AttachmentTimeline::AttachmentTimeline(int frameCount) : Timeline(), _slotIndex(
 	}
 	}
 }
 }
 
 
+void AttachmentTimeline::setAttachment(Skeleton& skeleton, Slot& slot, String* attachmentName) {
+    slot.setAttachment(attachmentName == NULL || attachmentName->isEmpty() ? NULL : skeleton.getAttachment(_slotIndex, *attachmentName));
+}
+
 void AttachmentTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
 void AttachmentTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
 	MixBlend blend, MixDirection direction
 	MixBlend blend, MixDirection direction
 ) {
 ) {
@@ -71,17 +75,15 @@ void AttachmentTimeline::apply(Skeleton &skeleton, float lastTime, float time, V
 	Slot &slot = *slotP;
 	Slot &slot = *slotP;
 	if (!slot._bone.isActive()) return;
 	if (!slot._bone.isActive()) return;
 
 
-	if (direction == MixDirection_Out && blend == MixBlend_Setup) {
-		attachmentName = &slot._data._attachmentName;
-		slot.setAttachment(attachmentName->length() == 0 ? NULL : skeleton.getAttachment(_slotIndex, *attachmentName));
+	if (direction == MixDirection_Out) {
+	    if (blend == MixBlend_Setup) setAttachment(skeleton, slot, &slot._data._attachmentName);
 		return;
 		return;
 	}
 	}
 
 
 	if (time < _frames[0]) {
 	if (time < _frames[0]) {
 		// Time is before first frame.
 		// Time is before first frame.
 		if (blend == MixBlend_Setup || blend == MixBlend_First) {
 		if (blend == MixBlend_Setup || blend == MixBlend_First) {
-			attachmentName = &slot._data._attachmentName;
-			slot.setAttachment(attachmentName->length() == 0 ? NULL : skeleton.getAttachment(_slotIndex, *attachmentName));
+            setAttachment(skeleton, slot, &slot._data._attachmentName);
 		}
 		}
 		return;
 		return;
 	}
 	}
@@ -115,11 +117,11 @@ void AttachmentTimeline::setSlotIndex(size_t inValue) {
 	_slotIndex = inValue;
 	_slotIndex = inValue;
 }
 }
 
 
-const Vector<float> &AttachmentTimeline::getFrames() {
+Vector<float> &AttachmentTimeline::getFrames() {
 	return _frames;
 	return _frames;
 }
 }
 
 
-const Vector<String> &AttachmentTimeline::getAttachmentNames() {
+Vector<String> &AttachmentTimeline::getAttachmentNames() {
 	return _attachmentNames;
 	return _attachmentNames;
 }
 }
 
 

+ 7 - 5
spine-cpp/spine-cpp/src/spine/DrawOrderTimeline.cpp

@@ -66,11 +66,13 @@ void DrawOrderTimeline::apply(Skeleton &skeleton, float lastTime, float time, Ve
 
 
 	Vector<Slot *> &drawOrder = skeleton._drawOrder;
 	Vector<Slot *> &drawOrder = skeleton._drawOrder;
 	Vector<Slot *> &slots = skeleton._slots;
 	Vector<Slot *> &slots = skeleton._slots;
-	if (direction == MixDirection_Out && blend == MixBlend_Setup) {
-		drawOrder.clear();
-		drawOrder.ensureCapacity(slots.size());
-		for (size_t i = 0, n = slots.size(); i < n; ++i)
-			drawOrder.add(slots[i]);
+	if (direction == MixDirection_Out) {
+	    if (blend == MixBlend_Setup) {
+            drawOrder.clear();
+            drawOrder.ensureCapacity(slots.size());
+            for (size_t i = 0, n = slots.size(); i < n; ++i)
+                drawOrder.add(slots[i]);
+        }
 		return;
 		return;
 	}
 	}
 
 

+ 9 - 0
spine-cpp/spine-cpp/src/spine/Slot.cpp

@@ -48,6 +48,7 @@ Slot::Slot(SlotData &data, Bone &bone) :
 		_darkColor(0, 0, 0, 0),
 		_darkColor(0, 0, 0, 0),
 		_hasDarkColor(data.hasDarkColor()),
 		_hasDarkColor(data.hasDarkColor()),
 		_attachment(NULL),
 		_attachment(NULL),
+		_attachmentState(0),
 		_attachmentTime(0) {
 		_attachmentTime(0) {
 	setToSetupPose();
 	setToSetupPose();
 }
 }
@@ -102,6 +103,14 @@ void Slot::setAttachment(Attachment *inValue) {
 	_deform.clear();
 	_deform.clear();
 }
 }
 
 
+int Slot::getAttachmentState() {
+    return _attachmentState;
+}
+
+void Slot::setAttachmentState(int state) {
+    _attachmentState = state;
+}
+
 float Slot::getAttachmentTime() {
 float Slot::getAttachmentTime() {
 	return _skeleton.getTime() - _attachmentTime;
 	return _skeleton.getTime() - _attachmentTime;
 }
 }

+ 3 - 34
spine-csharp/src/AnimationState.cs

@@ -66,10 +66,6 @@ namespace Spine {
 		/// (which affects B and C). Without using D to mix out, A would be applied fully until mixing completes, then snap into
 		/// (which affects B and C). Without using D to mix out, A would be applied fully until mixing completes, then snap into
 		/// place.
 		/// place.
 		internal const int HoldMix = 3;
 		internal const int HoldMix = 3;
-		/// 1) This is the last attachment timeline to set the attachment for a slot.<para />
-		/// Result: Don't apply this timeline when mixing out. Attachment timelines that are not last are applied when mixing out so
-		/// any deform timelines are applied and subsequent entries can mix from that deform.
-		internal const int Last = 4;
 
 
 		internal const int Setup = 1,  Current = 2;
 		internal const int Setup = 1,  Current = 2;
 
 
@@ -244,7 +240,7 @@ namespace Spine {
 
 
 					for (int ii = 0; ii < timelineCount; ii++) {
 					for (int ii = 0; ii < timelineCount; ii++) {
 						Timeline timeline = timelinesItems[ii];
 						Timeline timeline = timelinesItems[ii];
-						MixBlend timelineBlend = (timelineMode[ii] & AnimationState.Last - 1) == AnimationState.Subsequent ? blend : MixBlend.Setup;
+						MixBlend timelineBlend = timelineMode[ii] == AnimationState.Subsequent ? blend : MixBlend.Setup;
 						var rotateTimeline = timeline as RotateTimeline;
 						var rotateTimeline = timeline as RotateTimeline;
 						if (rotateTimeline != null)
 						if (rotateTimeline != null)
 							ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation,
 							ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation,
@@ -318,7 +314,7 @@ namespace Spine {
 					MixDirection direction = MixDirection.Out;
 					MixDirection direction = MixDirection.Out;
 					MixBlend timelineBlend;
 					MixBlend timelineBlend;
 					float alpha;
 					float alpha;
-					switch (timelineMode[i] & AnimationState.Last - 1) {
+					switch (timelineMode[i]) {
 						case AnimationState.Subsequent:
 						case AnimationState.Subsequent:
 							if (!drawOrder && timeline is DrawOrderTimeline) continue;
 							if (!drawOrder && timeline is DrawOrderTimeline) continue;
 							timelineBlend = blend;
 							timelineBlend = blend;
@@ -332,7 +328,7 @@ namespace Spine {
 							timelineBlend = MixBlend.Setup;
 							timelineBlend = MixBlend.Setup;
 							alpha = alphaHold;
 							alpha = alphaHold;
 							break;
 							break;
-						default:
+						default: // HoldMix
 							timelineBlend = MixBlend.Setup;
 							timelineBlend = MixBlend.Setup;
 							TrackEntry holdMix = timelineHoldMix[i];
 							TrackEntry holdMix = timelineHoldMix[i];
 							alpha = alphaHold * Math.Max(0, 1 - holdMix.mixTime / holdMix.mixDuration);
 							alpha = alphaHold * Math.Max(0, 1 - holdMix.mixTime / holdMix.mixDuration);
@@ -344,9 +340,6 @@ namespace Spine {
 						ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation,
 						ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation,
 											i << 1, firstFrame);
 											i << 1, firstFrame);
 					} else if (timeline is AttachmentTimeline) {
 					} else if (timeline is AttachmentTimeline) {
-						// If not showing attachments: do nothing if this is the last timeline, else apply the timeline so
-						// subsequent timelines see any deform, but don't set attachmentState to Current.
-						if (!attachments && (timelineMode[i] & Last) != 0) continue;
 						ApplyAttachmentTimeline((AttachmentTimeline)timeline, skeleton, animationTime, timelineBlend, attachments);
 						ApplyAttachmentTimeline((AttachmentTimeline)timeline, skeleton, animationTime, timelineBlend, attachments);
 					} else {
 					} else {
 						if (drawOrder && timeline is DrawOrderTimeline && timelineBlend == MixBlend.Setup)
 						if (drawOrder && timeline is DrawOrderTimeline && timelineBlend == MixBlend.Setup)
@@ -790,16 +783,6 @@ namespace Spine {
 					entry = entry.mixingTo;
 					entry = entry.mixingTo;
 				} while (entry != null);
 				} while (entry != null);
 			}
 			}
-
-			// Process in the reverse order that animations are applied.
-			propertyIDs.Clear();
-			for (int i = tracks.Count - 1; i >= 0; i--) {
-				TrackEntry entry = tracksItems[i];
-				while (entry != null) {
-					ComputeNotLast(entry);
-					entry = entry.mixingFrom;
-				}
-			}
 		}
 		}
 
 
 		private void ComputeHold (TrackEntry entry) {
 		private void ComputeHold (TrackEntry entry) {
@@ -844,20 +827,6 @@ namespace Spine {
 			}
 			}
 		}
 		}
 
 
-		private void ComputeNotLast (TrackEntry entry) {
-			var timelines = entry.animation.timelines.Items;
-			int timelinesCount = entry.animation.timelines.Count;
-			int[] timelineMode = entry.timelineMode.Items;
-			var propertyIDs = this.propertyIDs;
-
-			for (int i = 0; i < timelinesCount; i++) {
-				if (timelines[i] is AttachmentTimeline) {
-					AttachmentTimeline timeline = (AttachmentTimeline)timelines[i];
-					if (propertyIDs.Add(timeline.slotIndex)) timelineMode[i] |= AnimationState.Last;
-				}
-			}
-		}
-
 		/// <returns>The track entry for the animation currently playing on the track, or null if no animation is currently playing.</returns>
 		/// <returns>The track entry for the animation currently playing on the track, or null if no animation is currently playing.</returns>
 		public TrackEntry GetCurrent (int trackIndex) {
 		public TrackEntry GetCurrent (int trackIndex) {
 			if (trackIndex >= tracks.Count) return null;
 			if (trackIndex >= tracks.Count) return null;

+ 25 - 17
spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java

@@ -94,7 +94,9 @@ public class SkeletonViewer extends ApplicationAdapter {
 	static final float checkModifiedInterval = 0.250f;
 	static final float checkModifiedInterval = 0.250f;
 	static final float reloadDelay = 1;
 	static final float reloadDelay = 1;
 	static float uiScale = 1;
 	static float uiScale = 1;
-	static String[] atlasSuffixes = {".atlas", ".atlas.txt", "-pro.atlas", "-pro.atlas.txt", "-ess.atlas", "-ess.atlas.txt"};
+	static String[] dataSuffixes = {".json", ".skel"};
+	static String[] atlasSuffixes = {".atlas", "-pro.atlas", "-ess.atlas"};
+	static String[] extraSuffixes = {"", ".txt", ".bytes"};
 	static String[] args;
 	static String[] args;
 	static final String version = ""; // Replaced by build.
 	static final String version = ""; // Replaced by build.
 
 
@@ -143,22 +145,27 @@ public class SkeletonViewer extends ApplicationAdapter {
 	}
 	}
 
 
 	FileHandle atlasFile (FileHandle skeletonFile) {
 	FileHandle atlasFile (FileHandle skeletonFile) {
-		String atlasFileName = skeletonFile.nameWithoutExtension();
-		if (atlasFileName.endsWith(".bytes")) atlasFileName = atlasFileName.substring(0, atlasFileName.length() - 6);
-		if (atlasFileName.endsWith(".json") || atlasFileName.endsWith(".skel"))
-			atlasFileName = atlasFileName.substring(0, atlasFileName.length() - 5);
-		if (atlasFileName.endsWith(".bytes")) atlasFileName = atlasFileName.substring(0, atlasFileName.length() - 6);
-		FileHandle atlasFile = skeletonFile.sibling(atlasFileName + ".atlas");
-		if (atlasFile.exists()) atlasFile = skeletonFile.sibling(atlasFileName + ".atlas.txt");
-		if (!atlasFile.exists()) {
-			if (atlasFileName.endsWith("-pro") || atlasFileName.endsWith("-ess"))
-				atlasFileName = atlasFileName.substring(0, atlasFileName.length() - 4);
+		String baseName = skeletonFile.name();
+		for (String extraSuffix : extraSuffixes) {
+			for (String dataSuffix : dataSuffixes) {
+				String suffix = dataSuffix + extraSuffix;
+				if (baseName.endsWith(suffix)) {
+					FileHandle file = atlasFile(skeletonFile, baseName.substring(0, baseName.length() - suffix.length()));
+					if (file != null) return file;
+				}
+			}
+		}
+		return atlasFile(skeletonFile, baseName);
+	}
+
+	private FileHandle atlasFile (FileHandle skeletonFile, String baseName) {
+		for (String extraSuffix : extraSuffixes) {
 			for (String suffix : atlasSuffixes) {
 			for (String suffix : atlasSuffixes) {
-				atlasFile = skeletonFile.sibling(atlasFileName + suffix);
-				if (atlasFile.exists()) break;
+				FileHandle file = skeletonFile.sibling(baseName + suffix + extraSuffix);
+				if (file.exists()) return file;
 			}
 			}
 		}
 		}
-		return atlasFile;
+		return null;
 	}
 	}
 
 
 	void loadSkeleton (final FileHandle skeletonFile) {
 	void loadSkeleton (final FileHandle skeletonFile) {
@@ -174,7 +181,7 @@ public class SkeletonViewer extends ApplicationAdapter {
 			pixmap.dispose();
 			pixmap.dispose();
 
 
 			TextureAtlasData atlasData = null;
 			TextureAtlasData atlasData = null;
-			if (atlasFile.exists()) {
+			if (atlasFile != null) {
 				atlasData = new TextureAtlasData(atlasFile, atlasFile.parent(), false);
 				atlasData = new TextureAtlasData(atlasFile, atlasFile.parent(), false);
 				boolean linear = true;
 				boolean linear = true;
 				for (int i = 0, n = atlasData.getPages().size; i < n; i++) {
 				for (int i = 0, n = atlasData.getPages().size; i < n; i++) {
@@ -238,7 +245,7 @@ public class SkeletonViewer extends ApplicationAdapter {
 
 
 		this.skeletonFile = skeletonFile;
 		this.skeletonFile = skeletonFile;
 		skeletonModified = skeletonFile.lastModified();
 		skeletonModified = skeletonFile.lastModified();
-		atlasModified = atlasFile.lastModified();
+		atlasModified = atlasFile == null ? 0 : atlasFile.lastModified();
 		lastModifiedCheck = checkModifiedInterval;
 		lastModifiedCheck = checkModifiedInterval;
 		prefs.putString("lastFile", skeletonFile.path());
 		prefs.putString("lastFile", skeletonFile.path());
 		prefs.flush();
 		prefs.flush();
@@ -314,7 +321,8 @@ public class SkeletonViewer extends ApplicationAdapter {
 					lastModifiedCheck = checkModifiedInterval;
 					lastModifiedCheck = checkModifiedInterval;
 					long time = skeletonFile.lastModified();
 					long time = skeletonFile.lastModified();
 					if (time != 0 && skeletonModified != time) reloadTimer = reloadDelay;
 					if (time != 0 && skeletonModified != time) reloadTimer = reloadDelay;
-					time = atlasFile(skeletonFile).lastModified();
+					FileHandle atlasFile = atlasFile(skeletonFile);
+					time = atlasFile == null ? 0 : atlasFile.lastModified();
 					if (time != 0 && atlasModified != time) reloadTimer = reloadDelay;
 					if (time != 0 && atlasModified != time) reloadTimer = reloadDelay;
 				}
 				}
 			} else {
 			} else {

+ 1 - 1
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"
 }
 }

+ 1 - 1
spine-starling/spine-starling/.vscode/settings.json

@@ -1,3 +1,3 @@
 {
 {
-    "as3mxml.sdk.framework": "/Applications/air-sdk"
+    "as3mxml.sdk.framework": "/Users/badlogic/workspaces/airsdk"
 }
 }

BIN
spine-starling/spine-starling/lib/spine-starling.swc


+ 0 - 2
spine-ts/build/spine-all.d.ts

@@ -251,7 +251,6 @@ declare module spine {
 		static FIRST: number;
 		static FIRST: number;
 		static HOLD: number;
 		static HOLD: number;
 		static HOLD_MIX: number;
 		static HOLD_MIX: number;
-		static LAST: number;
 		static SETUP: number;
 		static SETUP: number;
 		static CURRENT: number;
 		static CURRENT: number;
 		data: AnimationStateData;
 		data: AnimationStateData;
@@ -288,7 +287,6 @@ declare module spine {
 		disposeNext(entry: TrackEntry): void;
 		disposeNext(entry: TrackEntry): void;
 		_animationsChanged(): void;
 		_animationsChanged(): void;
 		computeHold(entry: TrackEntry): void;
 		computeHold(entry: TrackEntry): void;
-		computeNotLast(entry: TrackEntry): void;
 		getCurrent(trackIndex: number): TrackEntry;
 		getCurrent(trackIndex: number): TrackEntry;
 		addListener(listener: AnimationStateListener): void;
 		addListener(listener: AnimationStateListener): void;
 		removeListener(listener: AnimationStateListener): void;
 		removeListener(listener: AnimationStateListener): void;

+ 3 - 28
spine-ts/build/spine-all.js

@@ -1472,7 +1472,7 @@ var spine;
 					var timelinesRotation = current.timelinesRotation;
 					var timelinesRotation = current.timelinesRotation;
 					for (var ii = 0; ii < timelineCount; ii++) {
 					for (var ii = 0; ii < timelineCount; ii++) {
 						var timeline_1 = timelines[ii];
 						var timeline_1 = timelines[ii];
-						var timelineBlend = (timelineMode[ii] & (AnimationState.LAST - 1)) == AnimationState.SUBSEQUENT ? blend : spine.MixBlend.setup;
+						var timelineBlend = timelineMode[ii] == AnimationState.SUBSEQUENT ? blend : spine.MixBlend.setup;
 						if (timeline_1 instanceof spine.RotateTimeline) {
 						if (timeline_1 instanceof spine.RotateTimeline) {
 							this.applyRotateTimeline(timeline_1, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
 							this.applyRotateTimeline(timeline_1, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
 						}
 						}
@@ -1543,7 +1543,7 @@ var spine;
 					var direction = spine.MixDirection.mixOut;
 					var direction = spine.MixDirection.mixOut;
 					var timelineBlend = void 0;
 					var timelineBlend = void 0;
 					var alpha = 0;
 					var alpha = 0;
-					switch (timelineMode[i] & (AnimationState.LAST - 1)) {
+					switch (timelineMode[i]) {
 						case AnimationState.SUBSEQUENT:
 						case AnimationState.SUBSEQUENT:
 							if (!drawOrder && timeline instanceof spine.DrawOrderTimeline)
 							if (!drawOrder && timeline instanceof spine.DrawOrderTimeline)
 								continue;
 								continue;
@@ -1567,11 +1567,8 @@ var spine;
 					from.totalAlpha += alpha;
 					from.totalAlpha += alpha;
 					if (timeline instanceof spine.RotateTimeline)
 					if (timeline instanceof spine.RotateTimeline)
 						this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);
 						this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);
-					else if (timeline instanceof spine.AttachmentTimeline) {
-						if (!attachments && (timelineMode[i] & AnimationState.LAST) != 0)
-							continue;
+					else if (timeline instanceof spine.AttachmentTimeline)
 						this.applyAttachmentTimeline(timeline, skeleton, animationTime, timelineBlend, attachments);
 						this.applyAttachmentTimeline(timeline, skeleton, animationTime, timelineBlend, attachments);
-					}
 					else {
 					else {
 						spine.Utils.webkit602BugfixHelper(alpha, blend);
 						spine.Utils.webkit602BugfixHelper(alpha, blend);
 						if (drawOrder && timeline instanceof spine.DrawOrderTimeline && timelineBlend == spine.MixBlend.setup)
 						if (drawOrder && timeline instanceof spine.DrawOrderTimeline && timelineBlend == spine.MixBlend.setup)
@@ -1900,14 +1897,6 @@ var spine;
 					entry = entry.mixingTo;
 					entry = entry.mixingTo;
 				} while (entry != null);
 				} while (entry != null);
 			}
 			}
-			this.propertyIDs.clear();
-			for (var i = this.tracks.length - 1; i >= 0; i--) {
-				var entry = this.tracks[i];
-				while (entry != null) {
-					this.computeNotLast(entry);
-					entry = entry.mixingFrom;
-				}
-			}
 		};
 		};
 		AnimationState.prototype.computeHold = function (entry) {
 		AnimationState.prototype.computeHold = function (entry) {
 			var to = entry.mixingTo;
 			var to = entry.mixingTo;
@@ -1948,19 +1937,6 @@ var spine;
 				}
 				}
 			}
 			}
 		};
 		};
-		AnimationState.prototype.computeNotLast = function (entry) {
-			var timelines = entry.animation.timelines;
-			var timelinesCount = entry.animation.timelines.length;
-			var timelineMode = entry.timelineMode;
-			var propertyIDs = this.propertyIDs;
-			for (var i = 0; i < timelinesCount; i++) {
-				if (timelines[i] instanceof spine.AttachmentTimeline) {
-					var timeline = timelines[i];
-					if (!propertyIDs.add(timeline.slotIndex))
-						timelineMode[i] |= AnimationState.LAST;
-				}
-			}
-		};
 		AnimationState.prototype.getCurrent = function (trackIndex) {
 		AnimationState.prototype.getCurrent = function (trackIndex) {
 			if (trackIndex >= this.tracks.length)
 			if (trackIndex >= this.tracks.length)
 				return null;
 				return null;
@@ -1987,7 +1963,6 @@ var spine;
 		AnimationState.FIRST = 1;
 		AnimationState.FIRST = 1;
 		AnimationState.HOLD = 2;
 		AnimationState.HOLD = 2;
 		AnimationState.HOLD_MIX = 3;
 		AnimationState.HOLD_MIX = 3;
-		AnimationState.LAST = 4;
 		AnimationState.SETUP = 1;
 		AnimationState.SETUP = 1;
 		AnimationState.CURRENT = 2;
 		AnimationState.CURRENT = 2;
 		return AnimationState;
 		return AnimationState;

File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-all.js.map


+ 0 - 2
spine-ts/build/spine-canvas.d.ts

@@ -251,7 +251,6 @@ declare module spine {
 		static FIRST: number;
 		static FIRST: number;
 		static HOLD: number;
 		static HOLD: number;
 		static HOLD_MIX: number;
 		static HOLD_MIX: number;
-		static LAST: number;
 		static SETUP: number;
 		static SETUP: number;
 		static CURRENT: number;
 		static CURRENT: number;
 		data: AnimationStateData;
 		data: AnimationStateData;
@@ -288,7 +287,6 @@ declare module spine {
 		disposeNext(entry: TrackEntry): void;
 		disposeNext(entry: TrackEntry): void;
 		_animationsChanged(): void;
 		_animationsChanged(): void;
 		computeHold(entry: TrackEntry): void;
 		computeHold(entry: TrackEntry): void;
-		computeNotLast(entry: TrackEntry): void;
 		getCurrent(trackIndex: number): TrackEntry;
 		getCurrent(trackIndex: number): TrackEntry;
 		addListener(listener: AnimationStateListener): void;
 		addListener(listener: AnimationStateListener): void;
 		removeListener(listener: AnimationStateListener): void;
 		removeListener(listener: AnimationStateListener): void;

+ 3 - 28
spine-ts/build/spine-canvas.js

@@ -1472,7 +1472,7 @@ var spine;
 					var timelinesRotation = current.timelinesRotation;
 					var timelinesRotation = current.timelinesRotation;
 					for (var ii = 0; ii < timelineCount; ii++) {
 					for (var ii = 0; ii < timelineCount; ii++) {
 						var timeline_1 = timelines[ii];
 						var timeline_1 = timelines[ii];
-						var timelineBlend = (timelineMode[ii] & (AnimationState.LAST - 1)) == AnimationState.SUBSEQUENT ? blend : spine.MixBlend.setup;
+						var timelineBlend = timelineMode[ii] == AnimationState.SUBSEQUENT ? blend : spine.MixBlend.setup;
 						if (timeline_1 instanceof spine.RotateTimeline) {
 						if (timeline_1 instanceof spine.RotateTimeline) {
 							this.applyRotateTimeline(timeline_1, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
 							this.applyRotateTimeline(timeline_1, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
 						}
 						}
@@ -1543,7 +1543,7 @@ var spine;
 					var direction = spine.MixDirection.mixOut;
 					var direction = spine.MixDirection.mixOut;
 					var timelineBlend = void 0;
 					var timelineBlend = void 0;
 					var alpha = 0;
 					var alpha = 0;
-					switch (timelineMode[i] & (AnimationState.LAST - 1)) {
+					switch (timelineMode[i]) {
 						case AnimationState.SUBSEQUENT:
 						case AnimationState.SUBSEQUENT:
 							if (!drawOrder && timeline instanceof spine.DrawOrderTimeline)
 							if (!drawOrder && timeline instanceof spine.DrawOrderTimeline)
 								continue;
 								continue;
@@ -1567,11 +1567,8 @@ var spine;
 					from.totalAlpha += alpha;
 					from.totalAlpha += alpha;
 					if (timeline instanceof spine.RotateTimeline)
 					if (timeline instanceof spine.RotateTimeline)
 						this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);
 						this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);
-					else if (timeline instanceof spine.AttachmentTimeline) {
-						if (!attachments && (timelineMode[i] & AnimationState.LAST) != 0)
-							continue;
+					else if (timeline instanceof spine.AttachmentTimeline)
 						this.applyAttachmentTimeline(timeline, skeleton, animationTime, timelineBlend, attachments);
 						this.applyAttachmentTimeline(timeline, skeleton, animationTime, timelineBlend, attachments);
-					}
 					else {
 					else {
 						spine.Utils.webkit602BugfixHelper(alpha, blend);
 						spine.Utils.webkit602BugfixHelper(alpha, blend);
 						if (drawOrder && timeline instanceof spine.DrawOrderTimeline && timelineBlend == spine.MixBlend.setup)
 						if (drawOrder && timeline instanceof spine.DrawOrderTimeline && timelineBlend == spine.MixBlend.setup)
@@ -1900,14 +1897,6 @@ var spine;
 					entry = entry.mixingTo;
 					entry = entry.mixingTo;
 				} while (entry != null);
 				} while (entry != null);
 			}
 			}
-			this.propertyIDs.clear();
-			for (var i = this.tracks.length - 1; i >= 0; i--) {
-				var entry = this.tracks[i];
-				while (entry != null) {
-					this.computeNotLast(entry);
-					entry = entry.mixingFrom;
-				}
-			}
 		};
 		};
 		AnimationState.prototype.computeHold = function (entry) {
 		AnimationState.prototype.computeHold = function (entry) {
 			var to = entry.mixingTo;
 			var to = entry.mixingTo;
@@ -1948,19 +1937,6 @@ var spine;
 				}
 				}
 			}
 			}
 		};
 		};
-		AnimationState.prototype.computeNotLast = function (entry) {
-			var timelines = entry.animation.timelines;
-			var timelinesCount = entry.animation.timelines.length;
-			var timelineMode = entry.timelineMode;
-			var propertyIDs = this.propertyIDs;
-			for (var i = 0; i < timelinesCount; i++) {
-				if (timelines[i] instanceof spine.AttachmentTimeline) {
-					var timeline = timelines[i];
-					if (!propertyIDs.add(timeline.slotIndex))
-						timelineMode[i] |= AnimationState.LAST;
-				}
-			}
-		};
 		AnimationState.prototype.getCurrent = function (trackIndex) {
 		AnimationState.prototype.getCurrent = function (trackIndex) {
 			if (trackIndex >= this.tracks.length)
 			if (trackIndex >= this.tracks.length)
 				return null;
 				return null;
@@ -1987,7 +1963,6 @@ var spine;
 		AnimationState.FIRST = 1;
 		AnimationState.FIRST = 1;
 		AnimationState.HOLD = 2;
 		AnimationState.HOLD = 2;
 		AnimationState.HOLD_MIX = 3;
 		AnimationState.HOLD_MIX = 3;
-		AnimationState.LAST = 4;
 		AnimationState.SETUP = 1;
 		AnimationState.SETUP = 1;
 		AnimationState.CURRENT = 2;
 		AnimationState.CURRENT = 2;
 		return AnimationState;
 		return AnimationState;

File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-canvas.js.map


+ 0 - 2
spine-ts/build/spine-core.d.ts

@@ -251,7 +251,6 @@ declare module spine {
 		static FIRST: number;
 		static FIRST: number;
 		static HOLD: number;
 		static HOLD: number;
 		static HOLD_MIX: number;
 		static HOLD_MIX: number;
-		static LAST: number;
 		static SETUP: number;
 		static SETUP: number;
 		static CURRENT: number;
 		static CURRENT: number;
 		data: AnimationStateData;
 		data: AnimationStateData;
@@ -288,7 +287,6 @@ declare module spine {
 		disposeNext(entry: TrackEntry): void;
 		disposeNext(entry: TrackEntry): void;
 		_animationsChanged(): void;
 		_animationsChanged(): void;
 		computeHold(entry: TrackEntry): void;
 		computeHold(entry: TrackEntry): void;
-		computeNotLast(entry: TrackEntry): void;
 		getCurrent(trackIndex: number): TrackEntry;
 		getCurrent(trackIndex: number): TrackEntry;
 		addListener(listener: AnimationStateListener): void;
 		addListener(listener: AnimationStateListener): void;
 		removeListener(listener: AnimationStateListener): void;
 		removeListener(listener: AnimationStateListener): void;

+ 3 - 28
spine-ts/build/spine-core.js

@@ -1472,7 +1472,7 @@ var spine;
 					var timelinesRotation = current.timelinesRotation;
 					var timelinesRotation = current.timelinesRotation;
 					for (var ii = 0; ii < timelineCount; ii++) {
 					for (var ii = 0; ii < timelineCount; ii++) {
 						var timeline_1 = timelines[ii];
 						var timeline_1 = timelines[ii];
-						var timelineBlend = (timelineMode[ii] & (AnimationState.LAST - 1)) == AnimationState.SUBSEQUENT ? blend : spine.MixBlend.setup;
+						var timelineBlend = timelineMode[ii] == AnimationState.SUBSEQUENT ? blend : spine.MixBlend.setup;
 						if (timeline_1 instanceof spine.RotateTimeline) {
 						if (timeline_1 instanceof spine.RotateTimeline) {
 							this.applyRotateTimeline(timeline_1, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
 							this.applyRotateTimeline(timeline_1, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
 						}
 						}
@@ -1543,7 +1543,7 @@ var spine;
 					var direction = spine.MixDirection.mixOut;
 					var direction = spine.MixDirection.mixOut;
 					var timelineBlend = void 0;
 					var timelineBlend = void 0;
 					var alpha = 0;
 					var alpha = 0;
-					switch (timelineMode[i] & (AnimationState.LAST - 1)) {
+					switch (timelineMode[i]) {
 						case AnimationState.SUBSEQUENT:
 						case AnimationState.SUBSEQUENT:
 							if (!drawOrder && timeline instanceof spine.DrawOrderTimeline)
 							if (!drawOrder && timeline instanceof spine.DrawOrderTimeline)
 								continue;
 								continue;
@@ -1567,11 +1567,8 @@ var spine;
 					from.totalAlpha += alpha;
 					from.totalAlpha += alpha;
 					if (timeline instanceof spine.RotateTimeline)
 					if (timeline instanceof spine.RotateTimeline)
 						this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);
 						this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);
-					else if (timeline instanceof spine.AttachmentTimeline) {
-						if (!attachments && (timelineMode[i] & AnimationState.LAST) != 0)
-							continue;
+					else if (timeline instanceof spine.AttachmentTimeline)
 						this.applyAttachmentTimeline(timeline, skeleton, animationTime, timelineBlend, attachments);
 						this.applyAttachmentTimeline(timeline, skeleton, animationTime, timelineBlend, attachments);
-					}
 					else {
 					else {
 						spine.Utils.webkit602BugfixHelper(alpha, blend);
 						spine.Utils.webkit602BugfixHelper(alpha, blend);
 						if (drawOrder && timeline instanceof spine.DrawOrderTimeline && timelineBlend == spine.MixBlend.setup)
 						if (drawOrder && timeline instanceof spine.DrawOrderTimeline && timelineBlend == spine.MixBlend.setup)
@@ -1900,14 +1897,6 @@ var spine;
 					entry = entry.mixingTo;
 					entry = entry.mixingTo;
 				} while (entry != null);
 				} while (entry != null);
 			}
 			}
-			this.propertyIDs.clear();
-			for (var i = this.tracks.length - 1; i >= 0; i--) {
-				var entry = this.tracks[i];
-				while (entry != null) {
-					this.computeNotLast(entry);
-					entry = entry.mixingFrom;
-				}
-			}
 		};
 		};
 		AnimationState.prototype.computeHold = function (entry) {
 		AnimationState.prototype.computeHold = function (entry) {
 			var to = entry.mixingTo;
 			var to = entry.mixingTo;
@@ -1948,19 +1937,6 @@ var spine;
 				}
 				}
 			}
 			}
 		};
 		};
-		AnimationState.prototype.computeNotLast = function (entry) {
-			var timelines = entry.animation.timelines;
-			var timelinesCount = entry.animation.timelines.length;
-			var timelineMode = entry.timelineMode;
-			var propertyIDs = this.propertyIDs;
-			for (var i = 0; i < timelinesCount; i++) {
-				if (timelines[i] instanceof spine.AttachmentTimeline) {
-					var timeline = timelines[i];
-					if (!propertyIDs.add(timeline.slotIndex))
-						timelineMode[i] |= AnimationState.LAST;
-				}
-			}
-		};
 		AnimationState.prototype.getCurrent = function (trackIndex) {
 		AnimationState.prototype.getCurrent = function (trackIndex) {
 			if (trackIndex >= this.tracks.length)
 			if (trackIndex >= this.tracks.length)
 				return null;
 				return null;
@@ -1987,7 +1963,6 @@ var spine;
 		AnimationState.FIRST = 1;
 		AnimationState.FIRST = 1;
 		AnimationState.HOLD = 2;
 		AnimationState.HOLD = 2;
 		AnimationState.HOLD_MIX = 3;
 		AnimationState.HOLD_MIX = 3;
-		AnimationState.LAST = 4;
 		AnimationState.SETUP = 1;
 		AnimationState.SETUP = 1;
 		AnimationState.CURRENT = 2;
 		AnimationState.CURRENT = 2;
 		return AnimationState;
 		return AnimationState;

File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-core.js.map


+ 0 - 2
spine-ts/build/spine-player.d.ts

@@ -251,7 +251,6 @@ declare module spine {
 		static FIRST: number;
 		static FIRST: number;
 		static HOLD: number;
 		static HOLD: number;
 		static HOLD_MIX: number;
 		static HOLD_MIX: number;
-		static LAST: number;
 		static SETUP: number;
 		static SETUP: number;
 		static CURRENT: number;
 		static CURRENT: number;
 		data: AnimationStateData;
 		data: AnimationStateData;
@@ -288,7 +287,6 @@ declare module spine {
 		disposeNext(entry: TrackEntry): void;
 		disposeNext(entry: TrackEntry): void;
 		_animationsChanged(): void;
 		_animationsChanged(): void;
 		computeHold(entry: TrackEntry): void;
 		computeHold(entry: TrackEntry): void;
-		computeNotLast(entry: TrackEntry): void;
 		getCurrent(trackIndex: number): TrackEntry;
 		getCurrent(trackIndex: number): TrackEntry;
 		addListener(listener: AnimationStateListener): void;
 		addListener(listener: AnimationStateListener): void;
 		removeListener(listener: AnimationStateListener): void;
 		removeListener(listener: AnimationStateListener): void;

+ 3 - 28
spine-ts/build/spine-player.js

@@ -1472,7 +1472,7 @@ var spine;
 					var timelinesRotation = current.timelinesRotation;
 					var timelinesRotation = current.timelinesRotation;
 					for (var ii = 0; ii < timelineCount; ii++) {
 					for (var ii = 0; ii < timelineCount; ii++) {
 						var timeline_1 = timelines[ii];
 						var timeline_1 = timelines[ii];
-						var timelineBlend = (timelineMode[ii] & (AnimationState.LAST - 1)) == AnimationState.SUBSEQUENT ? blend : spine.MixBlend.setup;
+						var timelineBlend = timelineMode[ii] == AnimationState.SUBSEQUENT ? blend : spine.MixBlend.setup;
 						if (timeline_1 instanceof spine.RotateTimeline) {
 						if (timeline_1 instanceof spine.RotateTimeline) {
 							this.applyRotateTimeline(timeline_1, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
 							this.applyRotateTimeline(timeline_1, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
 						}
 						}
@@ -1543,7 +1543,7 @@ var spine;
 					var direction = spine.MixDirection.mixOut;
 					var direction = spine.MixDirection.mixOut;
 					var timelineBlend = void 0;
 					var timelineBlend = void 0;
 					var alpha = 0;
 					var alpha = 0;
-					switch (timelineMode[i] & (AnimationState.LAST - 1)) {
+					switch (timelineMode[i]) {
 						case AnimationState.SUBSEQUENT:
 						case AnimationState.SUBSEQUENT:
 							if (!drawOrder && timeline instanceof spine.DrawOrderTimeline)
 							if (!drawOrder && timeline instanceof spine.DrawOrderTimeline)
 								continue;
 								continue;
@@ -1567,11 +1567,8 @@ var spine;
 					from.totalAlpha += alpha;
 					from.totalAlpha += alpha;
 					if (timeline instanceof spine.RotateTimeline)
 					if (timeline instanceof spine.RotateTimeline)
 						this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);
 						this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);
-					else if (timeline instanceof spine.AttachmentTimeline) {
-						if (!attachments && (timelineMode[i] & AnimationState.LAST) != 0)
-							continue;
+					else if (timeline instanceof spine.AttachmentTimeline)
 						this.applyAttachmentTimeline(timeline, skeleton, animationTime, timelineBlend, attachments);
 						this.applyAttachmentTimeline(timeline, skeleton, animationTime, timelineBlend, attachments);
-					}
 					else {
 					else {
 						spine.Utils.webkit602BugfixHelper(alpha, blend);
 						spine.Utils.webkit602BugfixHelper(alpha, blend);
 						if (drawOrder && timeline instanceof spine.DrawOrderTimeline && timelineBlend == spine.MixBlend.setup)
 						if (drawOrder && timeline instanceof spine.DrawOrderTimeline && timelineBlend == spine.MixBlend.setup)
@@ -1900,14 +1897,6 @@ var spine;
 					entry = entry.mixingTo;
 					entry = entry.mixingTo;
 				} while (entry != null);
 				} while (entry != null);
 			}
 			}
-			this.propertyIDs.clear();
-			for (var i = this.tracks.length - 1; i >= 0; i--) {
-				var entry = this.tracks[i];
-				while (entry != null) {
-					this.computeNotLast(entry);
-					entry = entry.mixingFrom;
-				}
-			}
 		};
 		};
 		AnimationState.prototype.computeHold = function (entry) {
 		AnimationState.prototype.computeHold = function (entry) {
 			var to = entry.mixingTo;
 			var to = entry.mixingTo;
@@ -1948,19 +1937,6 @@ var spine;
 				}
 				}
 			}
 			}
 		};
 		};
-		AnimationState.prototype.computeNotLast = function (entry) {
-			var timelines = entry.animation.timelines;
-			var timelinesCount = entry.animation.timelines.length;
-			var timelineMode = entry.timelineMode;
-			var propertyIDs = this.propertyIDs;
-			for (var i = 0; i < timelinesCount; i++) {
-				if (timelines[i] instanceof spine.AttachmentTimeline) {
-					var timeline = timelines[i];
-					if (!propertyIDs.add(timeline.slotIndex))
-						timelineMode[i] |= AnimationState.LAST;
-				}
-			}
-		};
 		AnimationState.prototype.getCurrent = function (trackIndex) {
 		AnimationState.prototype.getCurrent = function (trackIndex) {
 			if (trackIndex >= this.tracks.length)
 			if (trackIndex >= this.tracks.length)
 				return null;
 				return null;
@@ -1987,7 +1963,6 @@ var spine;
 		AnimationState.FIRST = 1;
 		AnimationState.FIRST = 1;
 		AnimationState.HOLD = 2;
 		AnimationState.HOLD = 2;
 		AnimationState.HOLD_MIX = 3;
 		AnimationState.HOLD_MIX = 3;
-		AnimationState.LAST = 4;
 		AnimationState.SETUP = 1;
 		AnimationState.SETUP = 1;
 		AnimationState.CURRENT = 2;
 		AnimationState.CURRENT = 2;
 		return AnimationState;
 		return AnimationState;

File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-player.js.map


+ 0 - 2
spine-ts/build/spine-threejs.d.ts

@@ -251,7 +251,6 @@ declare module spine {
 		static FIRST: number;
 		static FIRST: number;
 		static HOLD: number;
 		static HOLD: number;
 		static HOLD_MIX: number;
 		static HOLD_MIX: number;
-		static LAST: number;
 		static SETUP: number;
 		static SETUP: number;
 		static CURRENT: number;
 		static CURRENT: number;
 		data: AnimationStateData;
 		data: AnimationStateData;
@@ -288,7 +287,6 @@ declare module spine {
 		disposeNext(entry: TrackEntry): void;
 		disposeNext(entry: TrackEntry): void;
 		_animationsChanged(): void;
 		_animationsChanged(): void;
 		computeHold(entry: TrackEntry): void;
 		computeHold(entry: TrackEntry): void;
-		computeNotLast(entry: TrackEntry): void;
 		getCurrent(trackIndex: number): TrackEntry;
 		getCurrent(trackIndex: number): TrackEntry;
 		addListener(listener: AnimationStateListener): void;
 		addListener(listener: AnimationStateListener): void;
 		removeListener(listener: AnimationStateListener): void;
 		removeListener(listener: AnimationStateListener): void;

+ 3 - 28
spine-ts/build/spine-threejs.js

@@ -1472,7 +1472,7 @@ var spine;
 					var timelinesRotation = current.timelinesRotation;
 					var timelinesRotation = current.timelinesRotation;
 					for (var ii = 0; ii < timelineCount; ii++) {
 					for (var ii = 0; ii < timelineCount; ii++) {
 						var timeline_1 = timelines[ii];
 						var timeline_1 = timelines[ii];
-						var timelineBlend = (timelineMode[ii] & (AnimationState.LAST - 1)) == AnimationState.SUBSEQUENT ? blend : spine.MixBlend.setup;
+						var timelineBlend = timelineMode[ii] == AnimationState.SUBSEQUENT ? blend : spine.MixBlend.setup;
 						if (timeline_1 instanceof spine.RotateTimeline) {
 						if (timeline_1 instanceof spine.RotateTimeline) {
 							this.applyRotateTimeline(timeline_1, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
 							this.applyRotateTimeline(timeline_1, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
 						}
 						}
@@ -1543,7 +1543,7 @@ var spine;
 					var direction = spine.MixDirection.mixOut;
 					var direction = spine.MixDirection.mixOut;
 					var timelineBlend = void 0;
 					var timelineBlend = void 0;
 					var alpha = 0;
 					var alpha = 0;
-					switch (timelineMode[i] & (AnimationState.LAST - 1)) {
+					switch (timelineMode[i]) {
 						case AnimationState.SUBSEQUENT:
 						case AnimationState.SUBSEQUENT:
 							if (!drawOrder && timeline instanceof spine.DrawOrderTimeline)
 							if (!drawOrder && timeline instanceof spine.DrawOrderTimeline)
 								continue;
 								continue;
@@ -1567,11 +1567,8 @@ var spine;
 					from.totalAlpha += alpha;
 					from.totalAlpha += alpha;
 					if (timeline instanceof spine.RotateTimeline)
 					if (timeline instanceof spine.RotateTimeline)
 						this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);
 						this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);
-					else if (timeline instanceof spine.AttachmentTimeline) {
-						if (!attachments && (timelineMode[i] & AnimationState.LAST) != 0)
-							continue;
+					else if (timeline instanceof spine.AttachmentTimeline)
 						this.applyAttachmentTimeline(timeline, skeleton, animationTime, timelineBlend, attachments);
 						this.applyAttachmentTimeline(timeline, skeleton, animationTime, timelineBlend, attachments);
-					}
 					else {
 					else {
 						spine.Utils.webkit602BugfixHelper(alpha, blend);
 						spine.Utils.webkit602BugfixHelper(alpha, blend);
 						if (drawOrder && timeline instanceof spine.DrawOrderTimeline && timelineBlend == spine.MixBlend.setup)
 						if (drawOrder && timeline instanceof spine.DrawOrderTimeline && timelineBlend == spine.MixBlend.setup)
@@ -1900,14 +1897,6 @@ var spine;
 					entry = entry.mixingTo;
 					entry = entry.mixingTo;
 				} while (entry != null);
 				} while (entry != null);
 			}
 			}
-			this.propertyIDs.clear();
-			for (var i = this.tracks.length - 1; i >= 0; i--) {
-				var entry = this.tracks[i];
-				while (entry != null) {
-					this.computeNotLast(entry);
-					entry = entry.mixingFrom;
-				}
-			}
 		};
 		};
 		AnimationState.prototype.computeHold = function (entry) {
 		AnimationState.prototype.computeHold = function (entry) {
 			var to = entry.mixingTo;
 			var to = entry.mixingTo;
@@ -1948,19 +1937,6 @@ var spine;
 				}
 				}
 			}
 			}
 		};
 		};
-		AnimationState.prototype.computeNotLast = function (entry) {
-			var timelines = entry.animation.timelines;
-			var timelinesCount = entry.animation.timelines.length;
-			var timelineMode = entry.timelineMode;
-			var propertyIDs = this.propertyIDs;
-			for (var i = 0; i < timelinesCount; i++) {
-				if (timelines[i] instanceof spine.AttachmentTimeline) {
-					var timeline = timelines[i];
-					if (!propertyIDs.add(timeline.slotIndex))
-						timelineMode[i] |= AnimationState.LAST;
-				}
-			}
-		};
 		AnimationState.prototype.getCurrent = function (trackIndex) {
 		AnimationState.prototype.getCurrent = function (trackIndex) {
 			if (trackIndex >= this.tracks.length)
 			if (trackIndex >= this.tracks.length)
 				return null;
 				return null;
@@ -1987,7 +1963,6 @@ var spine;
 		AnimationState.FIRST = 1;
 		AnimationState.FIRST = 1;
 		AnimationState.HOLD = 2;
 		AnimationState.HOLD = 2;
 		AnimationState.HOLD_MIX = 3;
 		AnimationState.HOLD_MIX = 3;
-		AnimationState.LAST = 4;
 		AnimationState.SETUP = 1;
 		AnimationState.SETUP = 1;
 		AnimationState.CURRENT = 2;
 		AnimationState.CURRENT = 2;
 		return AnimationState;
 		return AnimationState;

File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-threejs.js.map


+ 0 - 2
spine-ts/build/spine-webgl.d.ts

@@ -251,7 +251,6 @@ declare module spine {
 		static FIRST: number;
 		static FIRST: number;
 		static HOLD: number;
 		static HOLD: number;
 		static HOLD_MIX: number;
 		static HOLD_MIX: number;
-		static LAST: number;
 		static SETUP: number;
 		static SETUP: number;
 		static CURRENT: number;
 		static CURRENT: number;
 		data: AnimationStateData;
 		data: AnimationStateData;
@@ -288,7 +287,6 @@ declare module spine {
 		disposeNext(entry: TrackEntry): void;
 		disposeNext(entry: TrackEntry): void;
 		_animationsChanged(): void;
 		_animationsChanged(): void;
 		computeHold(entry: TrackEntry): void;
 		computeHold(entry: TrackEntry): void;
-		computeNotLast(entry: TrackEntry): void;
 		getCurrent(trackIndex: number): TrackEntry;
 		getCurrent(trackIndex: number): TrackEntry;
 		addListener(listener: AnimationStateListener): void;
 		addListener(listener: AnimationStateListener): void;
 		removeListener(listener: AnimationStateListener): void;
 		removeListener(listener: AnimationStateListener): void;

+ 3 - 28
spine-ts/build/spine-webgl.js

@@ -1472,7 +1472,7 @@ var spine;
 					var timelinesRotation = current.timelinesRotation;
 					var timelinesRotation = current.timelinesRotation;
 					for (var ii = 0; ii < timelineCount; ii++) {
 					for (var ii = 0; ii < timelineCount; ii++) {
 						var timeline_1 = timelines[ii];
 						var timeline_1 = timelines[ii];
-						var timelineBlend = (timelineMode[ii] & (AnimationState.LAST - 1)) == AnimationState.SUBSEQUENT ? blend : spine.MixBlend.setup;
+						var timelineBlend = timelineMode[ii] == AnimationState.SUBSEQUENT ? blend : spine.MixBlend.setup;
 						if (timeline_1 instanceof spine.RotateTimeline) {
 						if (timeline_1 instanceof spine.RotateTimeline) {
 							this.applyRotateTimeline(timeline_1, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
 							this.applyRotateTimeline(timeline_1, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
 						}
 						}
@@ -1543,7 +1543,7 @@ var spine;
 					var direction = spine.MixDirection.mixOut;
 					var direction = spine.MixDirection.mixOut;
 					var timelineBlend = void 0;
 					var timelineBlend = void 0;
 					var alpha = 0;
 					var alpha = 0;
-					switch (timelineMode[i] & (AnimationState.LAST - 1)) {
+					switch (timelineMode[i]) {
 						case AnimationState.SUBSEQUENT:
 						case AnimationState.SUBSEQUENT:
 							if (!drawOrder && timeline instanceof spine.DrawOrderTimeline)
 							if (!drawOrder && timeline instanceof spine.DrawOrderTimeline)
 								continue;
 								continue;
@@ -1567,11 +1567,8 @@ var spine;
 					from.totalAlpha += alpha;
 					from.totalAlpha += alpha;
 					if (timeline instanceof spine.RotateTimeline)
 					if (timeline instanceof spine.RotateTimeline)
 						this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);
 						this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);
-					else if (timeline instanceof spine.AttachmentTimeline) {
-						if (!attachments && (timelineMode[i] & AnimationState.LAST) != 0)
-							continue;
+					else if (timeline instanceof spine.AttachmentTimeline)
 						this.applyAttachmentTimeline(timeline, skeleton, animationTime, timelineBlend, attachments);
 						this.applyAttachmentTimeline(timeline, skeleton, animationTime, timelineBlend, attachments);
-					}
 					else {
 					else {
 						spine.Utils.webkit602BugfixHelper(alpha, blend);
 						spine.Utils.webkit602BugfixHelper(alpha, blend);
 						if (drawOrder && timeline instanceof spine.DrawOrderTimeline && timelineBlend == spine.MixBlend.setup)
 						if (drawOrder && timeline instanceof spine.DrawOrderTimeline && timelineBlend == spine.MixBlend.setup)
@@ -1900,14 +1897,6 @@ var spine;
 					entry = entry.mixingTo;
 					entry = entry.mixingTo;
 				} while (entry != null);
 				} while (entry != null);
 			}
 			}
-			this.propertyIDs.clear();
-			for (var i = this.tracks.length - 1; i >= 0; i--) {
-				var entry = this.tracks[i];
-				while (entry != null) {
-					this.computeNotLast(entry);
-					entry = entry.mixingFrom;
-				}
-			}
 		};
 		};
 		AnimationState.prototype.computeHold = function (entry) {
 		AnimationState.prototype.computeHold = function (entry) {
 			var to = entry.mixingTo;
 			var to = entry.mixingTo;
@@ -1948,19 +1937,6 @@ var spine;
 				}
 				}
 			}
 			}
 		};
 		};
-		AnimationState.prototype.computeNotLast = function (entry) {
-			var timelines = entry.animation.timelines;
-			var timelinesCount = entry.animation.timelines.length;
-			var timelineMode = entry.timelineMode;
-			var propertyIDs = this.propertyIDs;
-			for (var i = 0; i < timelinesCount; i++) {
-				if (timelines[i] instanceof spine.AttachmentTimeline) {
-					var timeline = timelines[i];
-					if (!propertyIDs.add(timeline.slotIndex))
-						timelineMode[i] |= AnimationState.LAST;
-				}
-			}
-		};
 		AnimationState.prototype.getCurrent = function (trackIndex) {
 		AnimationState.prototype.getCurrent = function (trackIndex) {
 			if (trackIndex >= this.tracks.length)
 			if (trackIndex >= this.tracks.length)
 				return null;
 				return null;
@@ -1987,7 +1963,6 @@ var spine;
 		AnimationState.FIRST = 1;
 		AnimationState.FIRST = 1;
 		AnimationState.HOLD = 2;
 		AnimationState.HOLD = 2;
 		AnimationState.HOLD_MIX = 3;
 		AnimationState.HOLD_MIX = 3;
-		AnimationState.LAST = 4;
 		AnimationState.SETUP = 1;
 		AnimationState.SETUP = 1;
 		AnimationState.CURRENT = 2;
 		AnimationState.CURRENT = 2;
 		return AnimationState;
 		return AnimationState;

File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-webgl.js.map


+ 4 - 37
spine-ts/core/src/AnimationState.ts

@@ -65,13 +65,6 @@ module spine {
 		 * (which affects B and C). Without using D to mix out, A would be applied fully until mixing completes, then snap into
 		 * (which affects B and C). Without using D to mix out, A would be applied fully until mixing completes, then snap into
 		 * place. */
 		 * place. */
 		static HOLD_MIX = 3;
 		static HOLD_MIX = 3;
-		/** 1. An attachment timeline in a subsequent track entry sets the attachment for the same slot as this attachment
-		 * timeline.
-		 *
-		 * Result: This attachment timeline will not use MixDirection.out, which would otherwise show the setup mode attachment (or
-		 * none if not visible in setup mode). This allows deform timelines to be applied for the subsequent entry to mix from, rather
-		 * than mixing from the setup pose. */
-		static LAST = 4;
 
 
 		static SETUP = 1;
 		static SETUP = 1;
 		static CURRENT = 2;
 		static CURRENT = 2;
@@ -235,7 +228,7 @@ module spine {
 
 
 					for (let ii = 0; ii < timelineCount; ii++) {
 					for (let ii = 0; ii < timelineCount; ii++) {
 						let timeline = timelines[ii];
 						let timeline = timelines[ii];
-						let timelineBlend = (timelineMode[ii] & (AnimationState.LAST - 1)) == AnimationState.SUBSEQUENT ? blend : MixBlend.setup;
+						let timelineBlend = timelineMode[ii]  == AnimationState.SUBSEQUENT ? blend : MixBlend.setup;
 						if (timeline instanceof RotateTimeline) {
 						if (timeline instanceof RotateTimeline) {
 							this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
 							this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
 						} else if (timeline instanceof AttachmentTimeline) {
 						} else if (timeline instanceof AttachmentTimeline) {
@@ -308,7 +301,7 @@ module spine {
 					let direction = MixDirection.mixOut;
 					let direction = MixDirection.mixOut;
 					let timelineBlend: MixBlend;
 					let timelineBlend: MixBlend;
 					let alpha = 0;
 					let alpha = 0;
-					switch (timelineMode[i] & (AnimationState.LAST - 1)) {
+					switch (timelineMode[i]) {
 					case AnimationState.SUBSEQUENT:
 					case AnimationState.SUBSEQUENT:
 						if (!drawOrder && timeline instanceof DrawOrderTimeline) continue;
 						if (!drawOrder && timeline instanceof DrawOrderTimeline) continue;
 						timelineBlend = blend;
 						timelineBlend = blend;
@@ -332,12 +325,9 @@ module spine {
 
 
 					if (timeline instanceof RotateTimeline)
 					if (timeline instanceof RotateTimeline)
 						this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);
 						this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);
-					else if (timeline instanceof AttachmentTimeline) {
-						// If not showing attachments: do nothing if this is the last timeline, else apply the timeline so
-						// subsequent timelines see any deform, but don't set attachmentState to Current.
-						if (!attachments && (timelineMode[i] & AnimationState.LAST) != 0) continue;
+					else if (timeline instanceof AttachmentTimeline)
 						this.applyAttachmentTimeline(timeline, skeleton, animationTime, timelineBlend, attachments);
 						this.applyAttachmentTimeline(timeline, skeleton, animationTime, timelineBlend, attachments);
-					else {
+					else {
 						// This fixes the WebKit 602 specific issue described at http://esotericsoftware.com/forum/iOS-10-disappearing-graphics-10109
 						// This fixes the WebKit 602 specific issue described at http://esotericsoftware.com/forum/iOS-10-disappearing-graphics-10109
 						Utils.webkit602BugfixHelper(alpha, blend);
 						Utils.webkit602BugfixHelper(alpha, blend);
 						if (drawOrder && timeline instanceof DrawOrderTimeline && timelineBlend == MixBlend.setup)
 						if (drawOrder && timeline instanceof DrawOrderTimeline && timelineBlend == MixBlend.setup)
@@ -755,15 +745,6 @@ module spine {
 					entry = entry.mixingTo;
 					entry = entry.mixingTo;
 				} while (entry != null)
 				} while (entry != null)
 			}
 			}
-
-			this.propertyIDs.clear();
-			for (let i = this.tracks.length - 1; i >= 0; i--) {
-				let entry = this.tracks[i];
-				while (entry != null) {
-					this.computeNotLast(entry);
-					entry = entry.mixingFrom;
-				}
-			}
 		}
 		}
 
 
 		computeHold (entry: TrackEntry) {
 		computeHold (entry: TrackEntry) {
@@ -807,20 +788,6 @@ module spine {
 			}
 			}
 		}
 		}
 
 
-		computeNotLast (entry: TrackEntry) {
-			let timelines = entry.animation.timelines;
-			let timelinesCount = entry.animation.timelines.length;
-			let timelineMode = entry.timelineMode;
-			let propertyIDs = this.propertyIDs;
-
-			for (let i = 0; i < timelinesCount; i++) {
-				if (timelines[i] instanceof AttachmentTimeline) {
-					let timeline = timelines[i] as AttachmentTimeline;
-					if (!propertyIDs.add(timeline.slotIndex)) timelineMode[i] |= AnimationState.LAST;
-				}
-			}
-		}
-
 		/** Returns the track entry for the animation currently playing on the track, or null if no animation is currently playing. */
 		/** Returns the track entry for the animation currently playing on the track, or null if no animation is currently playing. */
 		getCurrent (trackIndex: number) {
 		getCurrent (trackIndex: number) {
 			if (trackIndex >= this.tracks.length) return null;
 			if (trackIndex >= this.tracks.length) return null;

Some files were not shown because too many files changed in this diff