Browse Source

[lua] Ported Animation/Timeline changes

badlogic 8 years ago
parent
commit
2a973da308
4 changed files with 169 additions and 86 deletions
  1. 4 0
      CHANGELOG.md
  2. 123 61
      spine-lua/Animation.lua
  3. 34 25
      spine-lua/AnimationState.lua
  4. 8 0
      spine-lua/attachments/VertexAttachment.lua

+ 4 - 0
CHANGELOG.md

@@ -45,6 +45,7 @@
   * Added `spClippingAttachment` and respective enum.
   * Added `spClippingAttachment` and respective enum.
   * Added `spSkeletonClipper` and `spTriangulator`, used to implement software clipping of attachments.
   * Added `spSkeletonClipper` and `spTriangulator`, used to implement software clipping of attachments.
   * `AnimationState#apply` returns boolean indicating if any timeline was applied or not.
   * `AnimationState#apply` returns boolean indicating if any timeline was applied or not.
+  * `Animation#apply` and `Timeline#apply`` now take enums `MixPose` and `MixDirection` instead of booleans
 
 
 ### Cocos2d-X
 ### Cocos2d-X
  * Fixed renderer to work with 3.6 changes
  * Fixed renderer to work with 3.6 changes
@@ -76,6 +77,7 @@
    *  `MeshAttachment.parentMesh` is now a private field to enforce using the `.ParentMesh` setter property in external code. The `MeshAttachment.ParentMesh` property is an appropriate replacement wherever `.parentMesh` was used.
    *  `MeshAttachment.parentMesh` is now a private field to enforce using the `.ParentMesh` setter property in external code. The `MeshAttachment.ParentMesh` property is an appropriate replacement wherever `.parentMesh` was used.
  * **Additions**
  * **Additions**
    * `AnimationState#apply` returns boolean indicating if any timeline was applied or not.
    * `AnimationState#apply` returns boolean indicating if any timeline was applied or not.
+   * `Animation#apply` and `Timeline#apply`` now take enums `MixPose` and `MixDirection` instead of booleans
 
 
 ### Unity
 ### Unity
  * Refactored renderer to work with new 3.6 features.
  * Refactored renderer to work with new 3.6 features.
@@ -133,6 +135,7 @@
   * Added `ClippingAttachment`, additional method `newClippingAttachment` in `AttachmentLoader` interface.
   * Added `ClippingAttachment`, additional method `newClippingAttachment` in `AttachmentLoader` interface.
   * Added `SkeletonClipper` and `Triangulator`, used to implement software clipping of attachments.
   * Added `SkeletonClipper` and `Triangulator`, used to implement software clipping of attachments.
   * `AnimationState#apply` returns boolean indicating if any timeline was applied or not.
   * `AnimationState#apply` returns boolean indicating if any timeline was applied or not.
+  * `Animation#apply` and `Timeline#apply`` now take enums `MixPose` and `MixDirection` instead of booleans
 
 
 ### libGDX
 ### libGDX
  * Fixed renderer to work with 3.6 changes
  * Fixed renderer to work with 3.6 changes
@@ -154,6 +157,7 @@
   * Added `ClippingAttachment`, additional method `newClippingAttachment` in `AttachmentLoader` interface.
   * Added `ClippingAttachment`, additional method `newClippingAttachment` in `AttachmentLoader` interface.
   * Added `SkeletonClipper` and `Triangulator`, used to implement software clipping of attachments.
   * Added `SkeletonClipper` and `Triangulator`, used to implement software clipping of attachments.
   * `AnimationState#apply` returns boolean indicating if any timeline was applied or not.
   * `AnimationState#apply` returns boolean indicating if any timeline was applied or not.
+  * `Animation#apply` and `Timeline#apply`` now take enums `MixPose` and `MixDirection` instead of booleans
 
 
 ### Love2D
 ### Love2D
   * Fixed renderer to work with 3.6 changes
   * Fixed renderer to work with 3.6 changes

+ 123 - 61
spine-lua/Animation.lua

@@ -54,7 +54,7 @@ function Animation.new (name, timelines, duration)
 		duration = duration
 		duration = duration
 	}
 	}
 
 
-	function self:apply (skeleton, lastTime, time, loop, events, alpha, setupPose, mixingOut)
+	function self:apply (skeleton, lastTime, time, loop, events, alpha, pose, direction)
 		if not skeleton then error("skeleton cannot be nil.", 2) end
 		if not skeleton then error("skeleton cannot be nil.", 2) end
 
 
 		if loop and duration > 0 then
 		if loop and duration > 0 then
@@ -63,7 +63,7 @@ function Animation.new (name, timelines, duration)
 		end
 		end
 
 
 		for i,timeline in ipairs(self.timelines) do
 		for i,timeline in ipairs(self.timelines) do
-			timeline:apply(skeleton, lastTime, time, events, alpha, setupPose, mixingOut)
+			timeline:apply(skeleton, lastTime, time, events, alpha, pose, direction)
 		end
 		end
 	end
 	end
 
 
@@ -113,6 +113,18 @@ local function linearSearch (values, target, step)
 	return -1
 	return -1
 end
 end
 
 
+Animation.MixPose = {
+	setup = 0,
+	current = 1,
+	currentLayered = 2
+}
+local MixPose = Animation.MixPose
+
+Animation.MixDirection = {
+	_in = 0, out = 1
+}
+local MixDirection = Animation.MixDirection
+
 Animation.TimelineType = {
 Animation.TimelineType = {
 	rotate = 0, translate = 1, scale = 2, shear = 3,
 	rotate = 0, translate = 1, scale = 2, shear = 3,
 	attachment = 4, color = 5, deform = 6,
 	attachment = 4, color = 5, deform = 6,
@@ -123,6 +135,7 @@ Animation.TimelineType = {
 }
 }
 local TimelineType = Animation.TimelineType
 local TimelineType = Animation.TimelineType
 local SHL_24 = 16777216
 local SHL_24 = 16777216
+local SHL_27 = 134217728
 
 
 Animation.CurveTimeline = {}
 Animation.CurveTimeline = {}
 function Animation.CurveTimeline.new (frameCount)
 function Animation.CurveTimeline.new (frameCount)
@@ -242,19 +255,23 @@ function Animation.RotateTimeline.new (frameCount)
 		self.frames[frameIndex + ROTATION] = degrees
 		self.frames[frameIndex + ROTATION] = degrees
 	end
 	end
 
 
-	function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut)
+	function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
 		local frames = self.frames
 		local frames = self.frames
 
 
 		local bone = skeleton.bones[self.boneIndex]
 		local bone = skeleton.bones[self.boneIndex]
 		if time < frames[0] then
 		if time < frames[0] then
-			if setupPose then
+			if pose == MixPose.setup then
 				bone.rotation = bone.data.rotation
 				bone.rotation = bone.data.rotation
+			elseif pose == MixPose.current then
+				local r = bone.data.rotation - bone.rotation
+				r = r - (16384 - math_floor(16384.499999999996 - r / 360)) * 360 -- Wrap within -180 and 180.
+				bone.rotation = bone.rotation + r * alpha
 			end
 			end
 			return
 			return
 		end
 		end
 
 
 		if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame.
 		if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame.
-			if setupPose then
+			if pose == MixPose.setup then
 				bone.rotation = bone.data.rotation + frames[zlen(frames) + PREV_ROTATION] * alpha
 				bone.rotation = bone.data.rotation + frames[zlen(frames) + PREV_ROTATION] * alpha
 			else
 			else
 				local r = bone.data.rotation + frames[zlen(frames) + PREV_ROTATION] - bone.rotation
 				local r = bone.data.rotation + frames[zlen(frames) + PREV_ROTATION] - bone.rotation
@@ -273,7 +290,7 @@ function Animation.RotateTimeline.new (frameCount)
 		local r = frames[frame + ROTATION] - prevRotation
 		local r = frames[frame + ROTATION] - prevRotation
 		r = r - (16384 - math_floor(16384.499999999996 - r / 360)) * 360
 		r = r - (16384 - math_floor(16384.499999999996 - r / 360)) * 360
 		r = prevRotation + r * percent
 		r = prevRotation + r * percent
-		if setupPose then
+		if pose == MixPose.setup then
 			r = r - (16384 - math_floor(16384.499999999996 - r / 360)) * 360
 			r = r - (16384 - math_floor(16384.499999999996 - r / 360)) * 360
 			bone.rotation = bone.data.rotation + r * alpha
 			bone.rotation = bone.data.rotation + r * alpha
 		else
 		else
@@ -312,14 +329,17 @@ function Animation.TranslateTimeline.new (frameCount)
 		self.frames[frameIndex + Y] = y
 		self.frames[frameIndex + Y] = y
 	end
 	end
 
 
-	function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut)
+	function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
 		local frames = self.frames
 		local frames = self.frames
 
 
 		local bone = skeleton.bones[self.boneIndex]
 		local bone = skeleton.bones[self.boneIndex]
 		if time < frames[0] then 
 		if time < frames[0] then 
-			if (setupPose) then
+			if pose == MixPose.setup then
 				bone.x = bone.data.x
 				bone.x = bone.data.x
 				bone.y = bone.data.y
 				bone.y = bone.data.y
+			elseif pose == MixPose.current then
+				bone.x = bone.x + (bone.data.x - bone.x) * alpha
+				bone.y = bone.y + (bone.data.y - bone.y) * alpha
 			end
 			end
 			return
 			return
 		end
 		end
@@ -341,7 +361,7 @@ function Animation.TranslateTimeline.new (frameCount)
 			x = x + (frames[frame + X] - x) * percent
 			x = x + (frames[frame + X] - x) * percent
 			y = y + (frames[frame + Y] - y) * percent
 			y = y + (frames[frame + Y] - y) * percent
 		end
 		end
-		if setupPose then
+		if pose == MixPose.setup then
 			bone.x = bone.data.x + x * alpha
 			bone.x = bone.data.x + x * alpha
 			bone.y = bone.data.y + y * alpha
 			bone.y = bone.data.y + y * alpha
 		else
 		else
@@ -370,14 +390,17 @@ function Animation.ScaleTimeline.new (frameCount)
 		return TimelineType.scale * SHL_24 + self.boneIndex
 		return TimelineType.scale * SHL_24 + self.boneIndex
 	end
 	end
 
 
-	function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut)
+	function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
 		local frames = self.frames
 		local frames = self.frames
 
 
 		local bone = skeleton.bones[self.boneIndex]
 		local bone = skeleton.bones[self.boneIndex]
 		if time < frames[0] then
 		if time < frames[0] then
-			if setupPose then
+			if pose == MixPose.setup then
 				bone.scaleX = bone.data.scaleX
 				bone.scaleX = bone.data.scaleX
 				bone.scaleY = bone.data.scaleY
 				bone.scaleY = bone.data.scaleY
+			elseif pose == MixPose.current then
+				bone.scaleX = bone.scaleX + (bone.data.scaleX - bone.scaleX) * alpha
+				bone.scaleY = bone.scaleY + (bone.data.scaleY - bone.scaleY) * alpha
 			end
 			end
 			return
 			return
 		end
 		end
@@ -405,7 +428,7 @@ function Animation.ScaleTimeline.new (frameCount)
 		else
 		else
 			local bx = 0
 			local bx = 0
 			local by = 0
 			local by = 0
-			if setupPose then
+			if pose == MixPose.setup then
 				bx = bone.data.scaleX
 				bx = bone.data.scaleX
 				by = bone.data.scaleY
 				by = bone.data.scaleY
 			else
 			else
@@ -413,7 +436,7 @@ function Animation.ScaleTimeline.new (frameCount)
 				by = bone.scaleY
 				by = bone.scaleY
 			end
 			end
 			-- Mixing out uses sign of setup or current pose, else use sign of key.
 			-- Mixing out uses sign of setup or current pose, else use sign of key.
-			if mixingOut then
+			if direction == MixDirection.out then
 				x = math_abs(x) * math_signum(bx)
 				x = math_abs(x) * math_signum(bx)
 				y = math_abs(y) * math_signum(by)
 				y = math_abs(y) * math_signum(by)
 			else
 			else
@@ -445,14 +468,17 @@ function Animation.ShearTimeline.new (frameCount)
 		return TimelineType.shear * SHL_24 + self.boneIndex
 		return TimelineType.shear * SHL_24 + self.boneIndex
 	end
 	end
 
 
-	function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut)
+	function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
 		local frames = self.frames
 		local frames = self.frames
 
 
 		local bone = skeleton.bones[self.boneIndex]
 		local bone = skeleton.bones[self.boneIndex]
 		if time < frames[0] then
 		if time < frames[0] then
-			if setupPose then
+			if pose == MixPose.setup then
 				bone.shearX = bone.data.shearX
 				bone.shearX = bone.data.shearX
 				bone.shearY = bone.data.shearY
 				bone.shearY = bone.data.shearY
+			elseif pose == MixPose.current then
+				bone.shearX = bone.shearX + (bone.data.shearX - bone.shearX) * alpha
+				bone.shearY = bone.shearX + (bone.data.shearY - bone.shearY) * alpha
 			end
 			end
 			return
 			return
 		end
 		end
@@ -474,7 +500,7 @@ function Animation.ShearTimeline.new (frameCount)
 			x = x + (frames[frame + X] - x) * percent
 			x = x + (frames[frame + X] - x) * percent
 			y = y + (frames[frame + Y] - y) * percent
 			y = y + (frames[frame + Y] - y) * percent
 		end
 		end
-		if setupPose then
+		if pose == MixPose.setup then
 			bone.shearX = bone.data.shearX + x * alpha
 			bone.shearX = bone.data.shearX + x * alpha
 			bone.shearY = bone.data.shearY + y * alpha
 			bone.shearY = bone.data.shearY + y * alpha
 		else
 		else
@@ -518,12 +544,17 @@ function Animation.ColorTimeline.new (frameCount)
 		self.frames[frameIndex + A] = a
 		self.frames[frameIndex + A] = a
 	end
 	end
 
 
-	function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut)
+	function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
 		local frames = self.frames
 		local frames = self.frames
 		local slot = skeleton.slots[self.slotIndex]
 		local slot = skeleton.slots[self.slotIndex]
 		if time < frames[0] then 
 		if time < frames[0] then 
-			if setupPose then
+			if pose == MixPose.setup then
 				slot.color:setFrom(slot.data.color)
 				slot.color:setFrom(slot.data.color)
+			elseif pose == MixPose.current then
+				local color = slot.color
+				local setup = slot.data.color
+				color:add((setup.r - color.r) * alpha, (setup.g - color.g) * alpha, (setup.b - color.b) * alpha,
+						(setup.a - color.a) * alpha)
 			end
 			end
 			return
 			return
 		end
 		end
@@ -555,7 +586,7 @@ function Animation.ColorTimeline.new (frameCount)
 			slot.color:set(r, g, b, a)
 			slot.color:set(r, g, b, a)
 		else
 		else
 			local color = slot.color
 			local color = slot.color
-			if setupPose then color:setFrom(slot.data.color) end
+			if pose == MixPose.setup then color:setFrom(slot.data.color) end
 			color:add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha)
 			color:add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha)
 		end
 		end
 	end
 	end
@@ -604,13 +635,21 @@ function Animation.TwoColorTimeline.new (frameCount)
 		self.frames[frameIndex + B2] = b2
 		self.frames[frameIndex + B2] = b2
 	end
 	end
 
 
-	function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut)
+	function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
 		local frames = self.frames
 		local frames = self.frames
 		local slot = skeleton.slots[self.slotIndex]
 		local slot = skeleton.slots[self.slotIndex]
 		if time < frames[0] then 
 		if time < frames[0] then 
-			if setupPose then
+			if pose == MixPose.setup then
 				slot.color:setFrom(slot.data.color)
 				slot.color:setFrom(slot.data.color)
 				slot.darkColor:setFrom(slot.data.darkColor)
 				slot.darkColor:setFrom(slot.data.darkColor)
+			elseif pose == MixPose.current then
+				local light = slot.color
+				local dark = slot.darkColor
+				local setupLight = slot.data.color
+				local setupDark = slot.data.darkColor
+				light:add((setupLight.r - light.r) * alpha, (setupLight.g - light.g) * alpha, (setupLight.b - light.b) * alpha,
+					(setupLight.a - light.a) * alpha)
+				dark:add((setupDark.r - dark.r) * alpha, (setupDark.g - dark.g) * alpha, (setupDark.b - dark.b) * alpha, 0)
 			end
 			end
 			return
 			return
 		end
 		end
@@ -653,7 +692,7 @@ function Animation.TwoColorTimeline.new (frameCount)
 		else
 		else
 			local light = slot.color
 			local light = slot.color
 			local dark = slot.darkColor
 			local dark = slot.darkColor
-			if setupPose then 
+			if pose == MixPose.setup then 
 				light:setFrom(slot.data.color)
 				light:setFrom(slot.data.color)
 				dark:setFrom(slot.data.darkColor)
 				dark:setFrom(slot.data.darkColor)
 			end
 			end
@@ -687,10 +726,10 @@ function Animation.AttachmentTimeline.new (frameCount)
 		return TimelineType.attachment * SHL_24 + self.slotIndex
 		return TimelineType.attachment * SHL_24 + self.slotIndex
 	end
 	end
 
 
-	function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut)
+	function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
 		local slot = skeleton.slots[self.slotIndex]
 		local slot = skeleton.slots[self.slotIndex]
 		local attachmentName
 		local attachmentName
-		if mixingOut and setupPose then
+		if direction == MixDirection.out and pose == MixPose.setup then
 			attachmentName = slot.data.attachmentName
 			attachmentName = slot.data.attachmentName
 			if not attachmentName then
 			if not attachmentName then
 				slot:setAttachment(nil)
 				slot:setAttachment(nil)
@@ -702,7 +741,7 @@ function Animation.AttachmentTimeline.new (frameCount)
 		
 		
 		local frames = self.frames
 		local frames = self.frames
 		if time < frames[0] then 
 		if time < frames[0] then 
-			if setupPose then
+			if pose == MixPose.setup then
 				attachmentName = slot.data.attachmentName
 				attachmentName = slot.data.attachmentName
 				if not attachmentName then
 				if not attachmentName then
 					slot:setAttachment(nil)
 					slot:setAttachment(nil)
@@ -741,7 +780,7 @@ function Animation.DeformTimeline.new (frameCount)
 	self.type = TimelineType.deform
 	self.type = TimelineType.deform
 
 
 	function self:getPropertyId ()
 	function self:getPropertyId ()
-		return TimelineType.deform * SHL_24 + self.slotIndex
+		return TimelineType.deform * SHL_27 + self.attachment.id + self.slotIndex
 	end
 	end
 
 
 	function self:setFrame (frameIndex, time, vertices)
 	function self:setFrame (frameIndex, time, vertices)
@@ -749,7 +788,7 @@ function Animation.DeformTimeline.new (frameCount)
 		self.frameVertices[frameIndex] = vertices
 		self.frameVertices[frameIndex] = vertices
 	end
 	end
 
 
-	function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut)
+	function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
 		local slot = skeleton.slots[self.slotIndex]
 		local slot = skeleton.slots[self.slotIndex]
 		local slotAttachment = slot.attachment
 		local slotAttachment = slot.attachment
 		if not slotAttachment then return end
 		if not slotAttachment then return end
@@ -758,19 +797,27 @@ function Animation.DeformTimeline.new (frameCount)
 
 
 		local frames = self.frames
 		local frames = self.frames
 		local verticesArray = slot.attachmentVertices
 		local verticesArray = slot.attachmentVertices
-		if time < frames[0] then
-			if setupPose then
-				verticesArray = {}
-				slot.attachmentVertices = verticesArray
-			end
-			return
-		end
 
 
 		local frameVertices = self.frameVertices
 		local frameVertices = self.frameVertices
 		local vertexCount = #(frameVertices[0])
 		local vertexCount = #(frameVertices[0])
 
 
 		if (#verticesArray ~= vertexCount and not setupPose) then alpha = 1 end -- Don't mix from uninitialized slot vertices.
 		if (#verticesArray ~= vertexCount and not setupPose) then alpha = 1 end -- Don't mix from uninitialized slot vertices.
 		local vertices = utils.setArraySize(verticesArray, vertexCount)
 		local vertices = utils.setArraySize(verticesArray, vertexCount)
+		
+		if time < frames[0] then
+			if pose == MixPose.setup then
+				verticesArray = {}
+				slot.attachmentVertices = verticesArray
+			elseif pose == MixPose.current then
+				alpha = 1 - alpha
+				local i = 1
+				while i <= vertexCount do
+					vertices[i] = vertices[i] * alpha
+					i = i + 1
+				end
+			end
+			return
+		end
 
 
 		if time >= frames[zlen(frames) - 1] then -- Time is after last frame.
 		if time >= frames[zlen(frames) - 1] then -- Time is after last frame.
 			local lastVertices = frameVertices[zlen(frames) - 1]
 			local lastVertices = frameVertices[zlen(frames) - 1]
@@ -781,7 +828,7 @@ function Animation.DeformTimeline.new (frameCount)
 					vertices[i] = lastVertices[i]
 					vertices[i] = lastVertices[i]
 					i = i + 1
 					i = i + 1
 				end
 				end
-			elseif setupPose then
+			elseif pose == MixPose.setup then
 				local vertexAttachment = slotAttachment
 				local vertexAttachment = slotAttachment
 				if vertexAttachment.bones == nil then
 				if vertexAttachment.bones == nil then
 					-- Unweighted vertex positions, with alpha.
 					-- Unweighted vertex positions, with alpha.
@@ -826,7 +873,7 @@ function Animation.DeformTimeline.new (frameCount)
 				vertices[i] = prev + (nextVertices[i] - prev) * percent
 				vertices[i] = prev + (nextVertices[i] - prev) * percent
 				i = i + 1
 				i = i + 1
 			end
 			end
-		elseif setupPose then
+		elseif pose == MixPose.setup then
 			local vertexAttachment = slotAttachment
 			local vertexAttachment = slotAttachment
 			if vertexAttachment.bones == nil then
 			if vertexAttachment.bones == nil then
 				-- Unweighted vertex positions, with alpha.
 				-- Unweighted vertex positions, with alpha.
@@ -883,14 +930,14 @@ function Animation.EventTimeline.new (frameCount)
 	end
 	end
 
 
 	-- Fires events for frames > lastTime and <= time.
 	-- Fires events for frames > lastTime and <= time.
-	function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut)
+	function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
 		if not firedEvents then return end
 		if not firedEvents then return end
 
 
 		local frames = self.frames
 		local frames = self.frames
 		local frameCount = zlen(frames)
 		local frameCount = zlen(frames)
 
 
 		if lastTime > time then -- Fire events after last time for looped animations.
 		if lastTime > time then -- Fire events after last time for looped animations.
-			self:apply(skeleton, lastTime, 999999, firedEvents, alpha, setupPose, mixingOut)
+			self:apply(skeleton, lastTime, 999999, firedEvents, alpha, pose, direction)
 			lastTime = -1
 			lastTime = -1
 		elseif lastTime >= frames[frameCount - 1] then -- Last time is after last frame.
 		elseif lastTime >= frames[frameCount - 1] then -- Last time is after last frame.
 			return
 			return
@@ -939,7 +986,7 @@ function Animation.DrawOrderTimeline.new (frameCount)
 		self.drawOrders[frameIndex] = drawOrder
 		self.drawOrders[frameIndex] = drawOrder
 	end
 	end
 
 
-	function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut)
+	function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
 		local drawOrder = skeleton.drawOrder
 		local drawOrder = skeleton.drawOrder
 		local slots = skeleton.slots
 		local slots = skeleton.slots
 		if mixingOut and setupPose then
 		if mixingOut and setupPose then
@@ -950,7 +997,7 @@ function Animation.DrawOrderTimeline.new (frameCount)
 		end
 		end
 		local frames = self.frames
 		local frames = self.frames
 		if time < frames[0] then 
 		if time < frames[0] then 
-			if setupPose then
+			if pose == MixPose.setup then
 				for i,slot in ipairs(slots) do
 				for i,slot in ipairs(slots) do
 					drawOrder[i] = slots[i]
 					drawOrder[i] = slots[i]
 				end
 				end
@@ -1006,29 +1053,32 @@ function Animation.IkConstraintTimeline.new (frameCount)
 		self.frames[frameIndex + BEND_DIRECTION] = bendDirection
 		self.frames[frameIndex + BEND_DIRECTION] = bendDirection
 	end
 	end
 
 
-	function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut)
+	function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
 		local frames = self.frames
 		local frames = self.frames
 
 
 		local constraint = skeleton.ikConstraints[self.ikConstraintIndex]
 		local constraint = skeleton.ikConstraints[self.ikConstraintIndex]
 		if time < frames[0] then
 		if time < frames[0] then
-			if setupPose then
+			if pose == MixPose.setup then
 				constraint.mix = constraint.data.mix
 				constraint.mix = constraint.data.mix
 				constraint.bendDirection = constraint.data.bendDirection
 				constraint.bendDirection = constraint.data.bendDirection
+			elseif pose == MixPose.current then
+				constraint.mix = constraint.mix + (constraint.data.mix - constraint.mix) * alpha
+				constraint.bendDirection = constraint.data.bendDirection
 			end
 			end
 			return
 			return
 		end
 		end
 
 
 		if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame.
 		if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame.
-			if setupPose then
+			if pose == MixPose.setup then
 				constraint.mix = constraint.data.mix + (frames[zlen(frames) + PREV_MIX] - constraint.data.mix) * alpha
 				constraint.mix = constraint.data.mix + (frames[zlen(frames) + PREV_MIX] - constraint.data.mix) * alpha
-				if mixingOut then 
+				if direction == MixDirection.out then 
 					constraint.bendDirection = constraint.data.bendDirection
 					constraint.bendDirection = constraint.data.bendDirection
 				else
 				else
 					constraint.bendDirection = math_floor(frames[zlen(frames) + PREV_BEND_DIRECTION]);
 					constraint.bendDirection = math_floor(frames[zlen(frames) + PREV_BEND_DIRECTION]);
 				end
 				end
 			else
 			else
 				constraint.mix = constraint.mix + (frames[frames.length + PREV_MIX] - constraint.mix) * alpha;
 				constraint.mix = constraint.mix + (frames[frames.length + PREV_MIX] - constraint.mix) * alpha;
-				if not mixingOut then constraint.bendDirection = math_floor(frames[zlen(frames) + PREV_BEND_DIRECTION]) end
+				if direction == MixDirection._in then constraint.bendDirection = math_floor(frames[zlen(frames) + PREV_BEND_DIRECTION]) end
 			end
 			end
 			return
 			return
 		end
 		end
@@ -1040,16 +1090,16 @@ function Animation.IkConstraintTimeline.new (frameCount)
 		local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1,
 		local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1,
 				1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime))
 				1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime))
 
 
-		if setupPose then
+		if pose == MixPose.setup then
 			constraint.mix = constraint.data.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.data.mix) * alpha
 			constraint.mix = constraint.data.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.data.mix) * alpha
-			if mixingOut then
+			if direction == MixDirection.out then
 				constraint.bendDirection = constraint.data.bendDirection
 				constraint.bendDirection = constraint.data.bendDirection
 			else
 			else
 				constraint.bendDirection = math_floor(frames[frame + PREV_BEND_DIRECTION])
 				constraint.bendDirection = math_floor(frames[frame + PREV_BEND_DIRECTION])
 			end
 			end
 		else
 		else
 			constraint.mix = constraint.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha;
 			constraint.mix = constraint.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha;
-			if not mixingOut then constraint.bendDirection = math_floor(frames[frame + PREV_BEND_DIRECTION]) end
+			if direction == MixDirection._in then constraint.bendDirection = math_floor(frames[frame + PREV_BEND_DIRECTION]) end
 		end
 		end
 	end
 	end
 
 
@@ -1088,17 +1138,22 @@ function Animation.TransformConstraintTimeline.new (frameCount)
 		self.frames[frameIndex + SHEAR] = shearMix
 		self.frames[frameIndex + SHEAR] = shearMix
 	end
 	end
 
 
-	function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut)
+	function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
 		local frames = self.frames
 		local frames = self.frames
 
 
 		local constraint = skeleton.transformConstraints[self.transformConstraintIndex]
 		local constraint = skeleton.transformConstraints[self.transformConstraintIndex]
 		if time < frames[0] then
 		if time < frames[0] then
-			if setupPose then
-				local data = constraint.data
+			local data = constraint.data
+			if pose == MixPose.setup then
 				constraint.rotateMix = data.rotateMix
 				constraint.rotateMix = data.rotateMix
 				constraint.translateMix = data.translateMix
 				constraint.translateMix = data.translateMix
 				constraint.scaleMix = data.scaleMix
 				constraint.scaleMix = data.scaleMix
 				constraint.shearMix = data.shearMix
 				constraint.shearMix = data.shearMix
+			elseif pose == MixPose.current then
+				constraint.rotateMix = constraint.rotateMix + (data.rotateMix - constraint.rotateMix) * alpha
+				constraint.translateMix = constraint.translateMix + (data.translateMix - constraint.translateMix) * alpha
+				constraint.scaleMix = constraint.scaleMix + (data.scaleMix - constraint.scaleMix) * alpha
+				constraint.shearMix = constraint.shearMix + (data.shearMix - constraint.shearMix) * alpha
 			end
 			end
 			return
 			return
 		end
 		end
@@ -1129,7 +1184,7 @@ function Animation.TransformConstraintTimeline.new (frameCount)
 			scale = scale + (frames[frame + SCALE] - scale) * percent
 			scale = scale + (frames[frame + SCALE] - scale) * percent
 			shear = shear + (frames[frame + SHEAR] - shear) * percent
 			shear = shear + (frames[frame + SHEAR] - shear) * percent
 		end
 		end
-		if setupPose then
+		if pose == MixPose.setup then
 			local data = constraint.data
 			local data = constraint.data
 			constraint.rotateMix = data.rotateMix + (rotate - data.rotateMix) * alpha
 			constraint.rotateMix = data.rotateMix + (rotate - data.rotateMix) * alpha
 			constraint.translateMix = data.translateMix + (translate - data.translateMix) * alpha
 			constraint.translateMix = data.translateMix + (translate - data.translateMix) * alpha
@@ -1169,13 +1224,15 @@ function Animation.PathConstraintPositionTimeline.new (frameCount)
 		self.frames[frameIndex + VALUE] = value
 		self.frames[frameIndex + VALUE] = value
 	end
 	end
 
 
-	function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut)
+	function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
 		local frames = self.frames
 		local frames = self.frames
 
 
 		local constraint = skeleton.pathConstraints[self.pathConstraintIndex]
 		local constraint = skeleton.pathConstraints[self.pathConstraintIndex]
 		if (time < frames[0]) then
 		if (time < frames[0]) then
-			if setupPose then
+			if pose == MixPose.setup then
 				constraint.position = constraint.data.position	
 				constraint.position = constraint.data.position	
+			elseif pose == MixPose.current then
+				constraint.position = constraint.position + (constraint.data.position - constraint.position) * alpha
 			end
 			end
 			return
 			return
 		end
 		end
@@ -1193,7 +1250,7 @@ function Animation.PathConstraintPositionTimeline.new (frameCount)
 
 
 			position = position + (frames[frame + VALUE] - position) * percent
 			position = position + (frames[frame + VALUE] - position) * percent
 		end
 		end
-		if setupPose then
+		if pose == MixPose.setup then
 			constraint.position = constraint.data.position + (position - constraint.data.position) * alpha
 			constraint.position = constraint.data.position + (position - constraint.data.position) * alpha
 		else
 		else
 			constraint.position = constraint.position + (position - constraint.position) * alpha
 			constraint.position = constraint.position + (position - constraint.position) * alpha
@@ -1226,13 +1283,15 @@ function Animation.PathConstraintSpacingTimeline.new (frameCount)
 		self.frames[frameIndex + VALUE] = value
 		self.frames[frameIndex + VALUE] = value
 	end
 	end
 
 
-	function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut)
+	function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
 		local frames = self.frames
 		local frames = self.frames
 
 
 		local constraint = skeleton.pathConstraints[self.pathConstraintIndex]
 		local constraint = skeleton.pathConstraints[self.pathConstraintIndex]
 		if (time < frames[0]) then
 		if (time < frames[0]) then
-			if setupPose then
+			if pose == MixPose.setup then
 				constraint.spacing = constraint.data.spacing
 				constraint.spacing = constraint.data.spacing
+			elseif pose == MixPose.current then
+				constraint.spacing = constraint.spacing + (constraint.data.spacing - constraint.spacing) * alpha
 			end
 			end
 			return
 			return
 		end
 		end
@@ -1251,7 +1310,7 @@ function Animation.PathConstraintSpacingTimeline.new (frameCount)
 			spacing = spacing + (frames[frame + VALUE] - spacing) * percent
 			spacing = spacing + (frames[frame + VALUE] - spacing) * percent
 		end
 		end
 
 
-		if setupPose then
+		if pose == MixPose.setup then
 			constraint.spacing = constraint.data.spacing + (spacing - constraint.data.spacing) * alpha
 			constraint.spacing = constraint.data.spacing + (spacing - constraint.data.spacing) * alpha
 		else
 		else
 			constraint.spacing = constraint.spacing + (spacing - constraint.spacing) * alpha
 			constraint.spacing = constraint.spacing + (spacing - constraint.spacing) * alpha
@@ -1287,14 +1346,17 @@ function Animation.PathConstraintMixTimeline.new (frameCount)
 		self.frames[frameIndex + TRANSLATE] = translateMix
 		self.frames[frameIndex + TRANSLATE] = translateMix
 	end
 	end
 
 
-	function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut)
+	function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
 		local frames = self.frames
 		local frames = self.frames
 
 
 		local constraint = skeleton.pathConstraints[self.pathConstraintIndex]
 		local constraint = skeleton.pathConstraints[self.pathConstraintIndex]
 		if (time < frames[0]) then
 		if (time < frames[0]) then
-			if setupPose then
+			if pose == MixPose.setup then
 				constraint.rotateMix = constraint.data.rotateMix
 				constraint.rotateMix = constraint.data.rotateMix
 				constraint.translateMix = constraint.data.translateMix
 				constraint.translateMix = constraint.data.translateMix
+			elseif pose == MixPose.current then
+				constraint.rotateMix = constraint.rotateMix + (constraint.data.rotateMix - constraint.rotateMix) * alpha
+				constraint.translateMix = constraint.translateMix + (constraint.data.translateMix - constraint.translateMix) * alpha
 			end
 			end
 			return
 			return
 		end
 		end
@@ -1317,7 +1379,7 @@ function Animation.PathConstraintMixTimeline.new (frameCount)
 			translate = translate + (frames[frame + TRANSLATE] - translate) * percent
 			translate = translate + (frames[frame + TRANSLATE] - translate) * percent
 		end
 		end
 
 
-		if setupPose then
+		if pose == MixPose.setup then
 			constraint.rotateMix = constraint.data.rotateMix + (rotate - constraint.data.rotateMix) * alpha
 			constraint.rotateMix = constraint.data.rotateMix + (rotate - constraint.data.rotateMix) * alpha
 			constraint.translateMix = constraint.data.translateMix + (translate - constraint.data.translateMix) * alpha
 			constraint.translateMix = constraint.data.translateMix + (translate - constraint.data.translateMix) * alpha
 		else
 		else

+ 34 - 25
spine-lua/AnimationState.lua

@@ -32,6 +32,8 @@ local setmetatable = setmetatable
 local table_insert = table.insert
 local table_insert = table.insert
 local utils = require "spine-lua.utils"
 local utils = require "spine-lua.utils"
 local Animation = require "spine-lua.Animation"
 local Animation = require "spine-lua.Animation"
+local MixPose = Animation.MixPose
+local MixDirection = Animation.MixDirection
 local AnimationStateData = require "spine-lua.AnimationStateData"
 local AnimationStateData = require "spine-lua.AnimationStateData"
 local math_min = math.min
 local math_min = math.min
 local math_max = math.max
 local math_max = math.max
@@ -371,10 +373,13 @@ function AnimationState:apply (skeleton)
 	for i,current in pairs(tracks) do
 	for i,current in pairs(tracks) do
 		if not (current == nil or current.delay > 0) then
 		if not (current == nil or current.delay > 0) then
       applied = true
       applied = true
+			local currrentPose = MixPose.currentLayered
+			if i == 0 then currentPose = MixPose.current end
+			
 			-- Apply mixing from entries first.
 			-- Apply mixing from entries first.
 			local mix = current.alpha
 			local mix = current.alpha
 			if current.mixingFrom then 
 			if current.mixingFrom then 
-				mix = mix * self:applyMixingFrom(current, skeleton)
+				mix = mix * self:applyMixingFrom(current, skeleton, currentPose)
 			elseif current.trackTime >= current.trackEnd and current.next == nil then
 			elseif current.trackTime >= current.trackEnd and current.next == nil then
 				mix = 0
 				mix = 0
 			end
 			end
@@ -385,7 +390,7 @@ function AnimationState:apply (skeleton)
 			local timelines = current.animation.timelines
 			local timelines = current.animation.timelines
 			if mix == 1 then
 			if mix == 1 then
 				for i,timeline in ipairs(timelines) do
 				for i,timeline in ipairs(timelines) do
-					timeline:apply(skeleton, animationLast, animationTime, events, 1, true, false)
+					timeline:apply(skeleton, animationLast, animationTime, events, 1, MixPose.setup, MixDirection._in)
 				end
 				end
 			else
 			else
 				local timelineData = current.timelineData
 				local timelineData = current.timelineData
@@ -393,11 +398,14 @@ function AnimationState:apply (skeleton)
 				local timelinesRotation = current.timelinesRotation
 				local timelinesRotation = current.timelinesRotation
 
 
 				for i,timeline in ipairs(timelines) do
 				for i,timeline in ipairs(timelines) do
+					local pose = MixPose.currentPose
+					if timelineData[i] >= FIRST then pose = MixPose.setup end
+					
 					if timeline.type == Animation.TimelineType.rotate then
 					if timeline.type == Animation.TimelineType.rotate then
-						self:applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineData[i] >= FIRST, timelinesRotation, i * 2,
+						self:applyRotateTimeline(timeline, skeleton, animationTime, mix, pose, timelinesRotation, i * 2,
 							firstFrame) -- FIXME passing ii * 2, indexing correct?
 							firstFrame) -- FIXME passing ii * 2, indexing correct?
 					else
 					else
-						timeline:apply(skeleton, animationLast, animationTime, events, mix, timelineData[i] >= FIRST, false)
+						timeline:apply(skeleton, animationLast, animationTime, events, mix, pose, MixDirection._in)
 					end
 					end
 				end
 				end
 			end
 			end
@@ -412,9 +420,9 @@ function AnimationState:apply (skeleton)
   return applied
   return applied
 end
 end
 
 
-function AnimationState:applyMixingFrom (to, skeleton)
+function AnimationState:applyMixingFrom (to, skeleton, currentPose)
 	local from = to.mixingFrom
 	local from = to.mixingFrom
-	if from.mixingFrom then self:applyMixingFrom(from, skeleton) end
+	if from.mixingFrom then self:applyMixingFrom(from, skeleton, currentPose) end
 
 
 	local mix = 0
 	local mix = 0
 	if to.mixDuration == 0 then -- Single frame mix to undo mixingFrom changes.
 	if to.mixDuration == 0 then -- Single frame mix to undo mixingFrom changes.
@@ -437,38 +445,39 @@ function AnimationState:applyMixingFrom (to, skeleton)
 	local firstFrame = #from.timelinesRotation == 0
 	local firstFrame = #from.timelinesRotation == 0
 	local timelinesRotation = from.timelinesRotation
 	local timelinesRotation = from.timelinesRotation
 
 
-	local first = false
+	local pose = MixPose.setup
 	local alphaDip = from.alpha * to.interruptAlpha
 	local alphaDip = from.alpha * to.interruptAlpha
 	local alphaMix = alphaDip * (1 - mix)
 	local alphaMix = alphaDip * (1 - mix)
 	local alpha = 0
 	local alpha = 0
 	from.totalAlpha = 0;
 	from.totalAlpha = 0;
-	local skip = false
+
 	for i,timeline in ipairs(timelines) do
 	for i,timeline in ipairs(timelines) do
-		
+		local skipSubsequent = false;
 		if timelineData[i] == SUBSEQUENT then
 		if timelineData[i] == SUBSEQUENT then
-			first = false
+			if not attachments and timeline.type == Animation.TimelineType.attachment then skipSubsequent = true end
+			if not drawOrder and timeline.type == Animation.TimelineType.drawOrder then skipSubsequent = true end
+			pose = currentPose
 			alpha = alphaMix
 			alpha = alphaMix
 		elseif timelineData[i] == FIRST then
 		elseif timelineData[i] == FIRST then
-			first = true
+			pose = MixPose.setup
 			alpha = alphaMix
 			alpha = alphaMix
 		elseif timelineData[i] == DIP then
 		elseif timelineData[i] == DIP then
-			first = true
+			pose = MixPose.setup
 			alpha = alphaDip
 			alpha = alphaDip
 		else
 		else
-			first = true
+			pose = MixPose.setup
 			alpha = alphaDip
 			alpha = alphaDip
 			local dipMix = timelineDipMix[i]
 			local dipMix = timelineDipMix[i]
 			alpha = alpha * math_max(0, 1 - dipMix.mixtime / dipMix.mixDuration)
 			alpha = alpha * math_max(0, 1 - dipMix.mixtime / dipMix.mixDuration)
 		end
 		end
-		from.totalAlpha = from.totalAlpha + alpha
-		if timeline.type == Animation.TimelineType.rotate then
-			self:applyRotateTimeline(timeline, skeleton, animationTime, alpha, first, timelinesRotation, i * 2, firstFrame)
-		else
-			if not first then
-				if not attachments and timeline.type == Animation.TimelineType.attackment then skip = true end
-				if not drawOrder and timeline.type == Animation.TimelineType.drawOrder then skip = true end
+		
+		if not skipSubsequent then
+			from.totalAlpha = from.totalAlpha + alpha
+			if timeline.type == Animation.TimelineType.rotate then
+				self:applyRotateTimeline(timeline, skeleton, animationTime, alpha, pose, timelinesRotation, i * 2, firstFrame)
+			else
+				timeline:apply(skeleton, animationLast, animationTime, events, alpha, pose, MixDirection.out)
 			end
 			end
-			if not skip then timeline:apply(skeleton, animationLast, animationTime, events, alpha, first, true) end
 		end
 		end
 	end
 	end
 
 
@@ -480,14 +489,14 @@ function AnimationState:applyMixingFrom (to, skeleton)
 	return mix
 	return mix
 end
 end
 
 
-function AnimationState:applyRotateTimeline (timeline, skeleton, time, alpha, setupPose, timelinesRotation, i, firstFrame)
+function AnimationState:applyRotateTimeline (timeline, skeleton, time, alpha, pose, timelinesRotation, i, firstFrame)
 	if firstFrame then 
 	if firstFrame then 
 		timelinesRotation[i] = 0
 		timelinesRotation[i] = 0
 		timelinesRotation[i+1] = 0
 		timelinesRotation[i+1] = 0
 	end
 	end
 	
 	
   if alpha == 1 then
   if alpha == 1 then
-    timeline:apply(skeleton, 0, time, nil, 1, setupPose, false)
+    timeline:apply(skeleton, 0, time, nil, 1, pose, MixDirection._in)
     return
     return
   end
   end
 
 
@@ -495,7 +504,7 @@ function AnimationState:applyRotateTimeline (timeline, skeleton, time, alpha, se
   local frames = rotateTimeline.frames
   local frames = rotateTimeline.frames
   local bone = skeleton.bones[rotateTimeline.boneIndex]
   local bone = skeleton.bones[rotateTimeline.boneIndex]
   if time < frames[0] then
   if time < frames[0] then
-		if setupPose then bone.rotation = bone.data.rotation end
+		if pose == MixPose.setup then bone.rotation = bone.data.rotation end
 		return
 		return
 	end
 	end
 
 
@@ -518,7 +527,7 @@ function AnimationState:applyRotateTimeline (timeline, skeleton, time, alpha, se
 
 
   -- Mix between rotations using the direction of the shortest route on the first frame while detecting crosses.
   -- Mix between rotations using the direction of the shortest route on the first frame while detecting crosses.
   local r1 = bone.rotation
   local r1 = bone.rotation
-  if setupPose then r1 = bone.data.rotation end
+  if pose == MixPose.setup then r1 = bone.data.rotation end
   local total = 0
   local total = 0
   local diff = r2 - r1
   local diff = r2 - r1
   if diff == 0 then
   if diff == 0 then

+ 8 - 0
spine-lua/attachments/VertexAttachment.lua

@@ -37,6 +37,9 @@ local setmetatable = setmetatable
 local AttachmentType = require "spine-lua.attachments.AttachmentType"
 local AttachmentType = require "spine-lua.attachments.AttachmentType"
 local Attachment = require "spine-lua.attachments.Attachment"
 local Attachment = require "spine-lua.attachments.Attachment"
 
 
+local nextID = 0;
+local SHL_11 = 2048;
+
 local VertexAttachment = {}
 local VertexAttachment = {}
 VertexAttachment.__index = VertexAttachment
 VertexAttachment.__index = VertexAttachment
 setmetatable(VertexAttachment, { __index = Attachment })
 setmetatable(VertexAttachment, { __index = Attachment })
@@ -46,6 +49,11 @@ function VertexAttachment.new (name, attachmentType)
 	self.bones = nil
 	self.bones = nil
 	self.vertices = nil
 	self.vertices = nil
 	self.worldVerticesLength = 0
 	self.worldVerticesLength = 0
+	while nextID > 65535 do
+		nextID = nextID - 65535
+	end
+	self.id = nextID * SHL_11
+	nextID = nextID + 1
 	setmetatable(self, VertexAttachment)
 	setmetatable(self, VertexAttachment)
 	return self
 	return self
 end
 end