Browse Source

Flip timelines for spine-lua, spine-corona, spine-love.

NathanSweet 10 years ago
parent
commit
59204db7f8
32 changed files with 281 additions and 331 deletions
  1. 0 1
      spine-corona/examples/dragon.lua
  2. 0 290
      spine-corona/examples/dragon/dragon.atlas
  3. 39 0
      spine-corona/examples/hero.lua
  4. 0 0
      spine-corona/examples/hero/hero.json
  5. BIN
      spine-corona/examples/hero/images/body.png
  6. BIN
      spine-corona/examples/hero/images/cape.png
  7. BIN
      spine-corona/examples/hero/images/eyes.png
  8. BIN
      spine-corona/examples/hero/images/fingers.png
  9. BIN
      spine-corona/examples/hero/images/foot1.png
  10. BIN
      spine-corona/examples/hero/images/foot2.png
  11. BIN
      spine-corona/examples/hero/images/forearm1.png
  12. BIN
      spine-corona/examples/hero/images/forearm2.png
  13. BIN
      spine-corona/examples/hero/images/hand1.png
  14. BIN
      spine-corona/examples/hero/images/hand2.png
  15. BIN
      spine-corona/examples/hero/images/head.png
  16. 5 0
      spine-corona/examples/hero/images/license.txt
  17. BIN
      spine-corona/examples/hero/images/mantles.png
  18. BIN
      spine-corona/examples/hero/images/mouth.png
  19. BIN
      spine-corona/examples/hero/images/shin1.png
  20. BIN
      spine-corona/examples/hero/images/shin2.png
  21. BIN
      spine-corona/examples/hero/images/sword.png
  22. BIN
      spine-corona/examples/hero/images/thigh1.png
  23. BIN
      spine-corona/examples/hero/images/thigh2.png
  24. BIN
      spine-corona/examples/hero/images/upperarm1.png
  25. BIN
      spine-corona/examples/hero/images/upperarm2.png
  26. 2 1
      spine-corona/main.lua
  27. 12 11
      spine-corona/spine-corona/spine.lua
  28. 162 3
      spine-lua/Animation.lua
  29. 27 14
      spine-lua/Bone.lua
  30. 3 3
      spine-lua/Skeleton.lua
  31. 23 0
      spine-lua/SkeletonJson.lua
  32. 8 8
      spine-lua/Slot.lua

+ 0 - 1
spine-corona/examples/dragon.lua

@@ -38,4 +38,3 @@ Runtime:addEventListener("enterFrame", function (event)
 	state:apply(skeleton)
 	state:apply(skeleton)
 	skeleton:updateWorldTransform()
 	skeleton:updateWorldTransform()
 end)
 end)
-

+ 0 - 290
spine-corona/examples/dragon/dragon.atlas

@@ -1,290 +0,0 @@
-
-dragon.png
-format: RGBA4444
-filter: Nearest,Nearest
-repeat: none
-L_rear_thigh
-  rotate: false
-  xy: 895, 20
-  size: 91, 148
-  orig: 91, 149
-  offset: 0, 0
-  index: -1
-L_wing01
-  rotate: false
-  xy: 814, 672
-  size: 191, 256
-  orig: 191, 256
-  offset: 0, 0
-  index: -1
-L_wing02
-  rotate: false
-  xy: 714, 189
-  size: 179, 269
-  orig: 179, 269
-  offset: 0, 0
-  index: -1
-L_wing03
-  rotate: false
-  xy: 785, 463
-  size: 186, 207
-  orig: 186, 207
-  offset: 0, 0
-  index: -1
-L_wing05
-  rotate: true
-  xy: 2, 9
-  size: 218, 213
-  orig: 218, 213
-  offset: 0, 0
-  index: -1
-L_wing06
-  rotate: false
-  xy: 2, 229
-  size: 192, 331
-  orig: 192, 331
-  offset: 0, 0
-  index: -1
-R_wing01
-  rotate: true
-  xy: 502, 709
-  size: 219, 310
-  orig: 219, 310
-  offset: 0, 0
-  index: -1
-R_wing02
-  rotate: true
-  xy: 204, 463
-  size: 203, 305
-  orig: 203, 305
-  offset: 0, 0
-  index: -1
-R_wing03
-  rotate: false
-  xy: 511, 460
-  size: 272, 247
-  orig: 272, 247
-  offset: 0, 0
-  index: -1
-R_wing05
-  rotate: false
-  xy: 196, 232
-  size: 251, 229
-  orig: 251, 229
-  offset: 0, 0
-  index: -1
-R_wing06
-  rotate: false
-  xy: 2, 562
-  size: 200, 366
-  orig: 200, 366
-  offset: 0, 0
-  index: -1
-R_wing07
-  rotate: true
-  xy: 449, 258
-  size: 200, 263
-  orig: 200, 263
-  offset: 0, 0
-  index: -1
-R_wing08
-  rotate: false
-  xy: 467, 2
-  size: 234, 254
-  orig: 234, 254
-  offset: 0, 0
-  index: -1
-R_wing09
-  rotate: false
-  xy: 217, 26
-  size: 248, 204
-  orig: 248, 204
-  offset: 0, 0
-  index: -1
-back
-  rotate: false
-  xy: 703, 2
-  size: 190, 185
-  orig: 190, 185
-  offset: 0, 0
-  index: -1
-chest
-  rotate: true
-  xy: 895, 170
-  size: 136, 122
-  orig: 136, 122
-  offset: 0, 0
-  index: -1
-front_toeA
-  rotate: false
-  xy: 976, 972
-  size: 29, 50
-  orig: 29, 50
-  offset: 0, 0
-  index: -1
-head
-  rotate: false
-  xy: 204, 668
-  size: 296, 260
-  orig: 296, 260
-  offset: 0, 0
-  index: -1
-logo
-  rotate: false
-  xy: 2, 930
-  size: 897, 92
-  orig: 897, 92
-  offset: 0, 0
-  index: -1
-tail01
-  rotate: false
-  xy: 895, 308
-  size: 120, 153
-  orig: 120, 153
-  offset: 0, 0
-  index: -1
-tail03
-  rotate: false
-  xy: 901, 930
-  size: 73, 92
-  orig: 73, 92
-  offset: 0, 0
-  index: -1
-
-dragon2.png
-format: RGBA4444
-filter: Nearest,Nearest
-repeat: none
-L_front_leg
-  rotate: true
-  xy: 391, 141
-  size: 84, 57
-  orig: 84, 57
-  offset: 0, 0
-  index: -1
-L_front_thigh
-  rotate: false
-  xy: 446, 269
-  size: 84, 72
-  orig: 84, 72
-  offset: 0, 0
-  index: -1
-L_rear_leg
-  rotate: true
-  xy: 888, 342
-  size: 168, 132
-  orig: 206, 177
-  offset: 19, 20
-  index: -1
-L_wing04
-  rotate: false
-  xy: 256, 227
-  size: 188, 135
-  orig: 188, 135
-  offset: 0, 0
-  index: -1
-L_wing07
-  rotate: false
-  xy: 2, 109
-  size: 159, 255
-  orig: 159, 255
-  offset: 0, 0
-  index: -1
-L_wing08
-  rotate: true
-  xy: 705, 346
-  size: 164, 181
-  orig: 164, 181
-  offset: 0, 0
-  index: -1
-L_wing09
-  rotate: false
-  xy: 499, 343
-  size: 204, 167
-  orig: 204, 167
-  offset: 0, 0
-  index: -1
-R_front_leg
-  rotate: false
-  xy: 273, 34
-  size: 101, 89
-  orig: 101, 89
-  offset: 0, 0
-  index: -1
-R_front_thigh
-  rotate: false
-  xy: 163, 106
-  size: 108, 108
-  orig: 108, 108
-  offset: 0, 0
-  index: -1
-R_rear_leg
-  rotate: false
-  xy: 273, 125
-  size: 116, 100
-  orig: 116, 100
-  offset: 0, 0
-  index: -1
-R_rear_thigh
-  rotate: false
-  xy: 163, 216
-  size: 91, 148
-  orig: 91, 149
-  offset: 0, 0
-  index: -1
-R_wing04
-  rotate: false
-  xy: 2, 366
-  size: 279, 144
-  orig: 279, 144
-  offset: 0, 0
-  index: -1
-chin
-  rotate: false
-  xy: 283, 364
-  size: 214, 146
-  orig: 214, 146
-  offset: 0, 0
-  index: -1
-front_toeB
-  rotate: false
-  xy: 590, 284
-  size: 56, 57
-  orig: 56, 57
-  offset: 0, 0
-  index: -1
-rear-toe
-  rotate: true
-  xy: 2, 2
-  size: 105, 77
-  orig: 109, 77
-  offset: 0, 0
-  index: -1
-tail02
-  rotate: true
-  xy: 151, 9
-  size: 95, 120
-  orig: 95, 120
-  offset: 0, 0
-  index: -1
-tail04
-  rotate: false
-  xy: 532, 270
-  size: 56, 71
-  orig: 56, 71
-  offset: 0, 0
-  index: -1
-tail05
-  rotate: false
-  xy: 648, 282
-  size: 52, 59
-  orig: 52, 59
-  offset: 0, 0
-  index: -1
-tail06
-  rotate: true
-  xy: 81, 12
-  size: 95, 68
-  orig: 95, 68
-  offset: 0, 0
-  index: -1

+ 39 - 0
spine-corona/examples/hero.lua

@@ -0,0 +1,39 @@
+
+-- This skeleton uses IK for the feet.
+
+local spine = require "spine-corona.spine"
+
+local json = spine.SkeletonJson.new()
+local skeletonData = json:readSkeletonDataFile("examples/hero/hero.json")
+
+local skeleton = spine.Skeleton.new(skeletonData)
+function skeleton:createImage (attachment)
+	return display.newImage("examples/hero/images/" .. attachment.name .. ".png")
+end
+skeleton.group.x = 195
+skeleton.group.y = 385
+skeleton.flipX = false
+skeleton.flipY = false
+skeleton.debug = true -- Omit or set to false to not draw debug lines on top of the images.
+skeleton:setToSetupPose()
+
+-- AnimationStateData defines crossfade durations between animations.
+local stateData = spine.AnimationStateData.new(skeletonData)
+-- AnimationState has a queue of animations and can apply them with crossfading.
+local state = spine.AnimationState.new(stateData)
+--state:setAnimationByName(0, "Idle", true, 0)
+state:setAnimationByName(0, "Walk", true, 0)
+
+local lastTime = 0
+local animationTime = 0
+Runtime:addEventListener("enterFrame", function (event)
+	-- Compute time in seconds since last frame.
+	local currentTime = event.time / 1000
+	local delta = currentTime - lastTime
+	lastTime = currentTime
+
+	-- Update the state with the delta time, apply it, and update the world transforms.
+	state:update(delta)
+	state:apply(skeleton)
+	skeleton:updateWorldTransform()
+end)

File diff suppressed because it is too large
+ 0 - 0
spine-corona/examples/hero/hero.json


BIN
spine-corona/examples/hero/images/body.png


BIN
spine-corona/examples/hero/images/cape.png


BIN
spine-corona/examples/hero/images/eyes.png


BIN
spine-corona/examples/hero/images/fingers.png


BIN
spine-corona/examples/hero/images/foot1.png


BIN
spine-corona/examples/hero/images/foot2.png


BIN
spine-corona/examples/hero/images/forearm1.png


BIN
spine-corona/examples/hero/images/forearm2.png


BIN
spine-corona/examples/hero/images/hand1.png


BIN
spine-corona/examples/hero/images/hand2.png


BIN
spine-corona/examples/hero/images/head.png


+ 5 - 0
spine-corona/examples/hero/images/license.txt

@@ -0,0 +1,5 @@
+Copyright (c) 2014, XDTech
+
+The project file and images in this "Hero" project are provided for
+demonstration purposes only and may not be redistributed for any reason nor
+used as the basis for derivative work.

BIN
spine-corona/examples/hero/images/mantles.png


BIN
spine-corona/examples/hero/images/mouth.png


BIN
spine-corona/examples/hero/images/shin1.png


BIN
spine-corona/examples/hero/images/shin2.png


BIN
spine-corona/examples/hero/images/sword.png


BIN
spine-corona/examples/hero/images/thigh1.png


BIN
spine-corona/examples/hero/images/thigh2.png


BIN
spine-corona/examples/hero/images/upperarm1.png


BIN
spine-corona/examples/hero/images/upperarm2.png


+ 2 - 1
spine-corona/main.lua

@@ -1,4 +1,5 @@
 
 
-require "examples.spineboy"
+-- require "examples.spineboy"
 -- require "examples.goblins"
 -- require "examples.goblins"
 -- require "examples.dragon"
 -- require "examples.dragon"
+require "examples.hero"

+ 12 - 11
spine-corona/spine-corona/spine.lua

@@ -128,10 +128,11 @@ function spine.Skeleton.new (skeletonData, group)
 				end
 				end
 				-- Position image based on attachment and bone.
 				-- Position image based on attachment and bone.
 				if image ~= spine.Skeleton.failed then
 				if image ~= spine.Skeleton.failed then
-					local flipX, flipY = ((self.flipX and -1) or 1), ((self.flipY and -1) or 1)
+					local bone = slot.bone
+					local flipX, flipY = ((bone.worldFlipX and -1) or 1), ((bone.worldFlipY and -1) or 1)
 
 
-					local x = slot.bone.worldX + attachment.x * slot.bone.m00 + attachment.y * slot.bone.m01
-					local y = -(slot.bone.worldY + attachment.x * slot.bone.m10 + attachment.y * slot.bone.m11)
+					local x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01
+					local y = -(bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11)
 					if not image.lastX then
 					if not image.lastX then
 						image.x, image.y = x, y
 						image.x, image.y = x, y
 						image.lastX, image.lastY = x, y
 						image.lastX, image.lastY = x, y
@@ -145,16 +146,16 @@ function spine.Skeleton.new (skeletonData, group)
 					-- Fix scaling when attachment is rotated 90 or -90.
 					-- Fix scaling when attachment is rotated 90 or -90.
 					local rotation = math.abs(attachment.rotation) % 180
 					local rotation = math.abs(attachment.rotation) % 180
 					if (rotation == 90) then
 					if (rotation == 90) then
-						xScale = xScale * slot.bone.worldScaleY
-						yScale = yScale * slot.bone.worldScaleX
+						xScale = xScale * bone.worldScaleY
+						yScale = yScale * bone.worldScaleX
 					else
 					else
-						xScale = xScale * slot.bone.worldScaleX
-						yScale = yScale * slot.bone.worldScaleY
+						xScale = xScale * bone.worldScaleX
+						yScale = yScale * bone.worldScaleY
 						if rotation ~= 0 and xScale ~= yScale and not image.rotationWarning then
 						if rotation ~= 0 and xScale ~= yScale and not image.rotationWarning then
 							image.rotationWarning = true
 							image.rotationWarning = true
 							print("WARNING: Non-uniform bone scaling with attachments not rotated to\n"
 							print("WARNING: Non-uniform bone scaling with attachments not rotated to\n"
 								.."         cardinal angles will not work as expected with Corona.\n"
 								.."         cardinal angles will not work as expected with Corona.\n"
-								.."         Bone: "..slot.bone.data.name..", slot: "..slot.data.name..", attachment: "..attachment.name)
+								.."         Bone: "..bone.data.name..", slot: "..slot.data.name..", attachment: "..attachment.name)
 						end
 						end
 					end
 					end
 					if not image.lastScaleX then
 					if not image.lastScaleX then
@@ -165,7 +166,7 @@ function spine.Skeleton.new (skeletonData, group)
 						image.lastScaleX, image.lastScaleY = xScale, yScale
 						image.lastScaleX, image.lastScaleY = xScale, yScale
 					end
 					end
 
 
-					rotation = -(slot.bone.worldRotation + attachment.rotation) * flipX * flipY
+					rotation = -(bone.worldRotation + attachment.rotation) * flipX * flipY
 					if not image.lastRotation then
 					if not image.lastRotation then
 						image.rotation = rotation
 						image.rotation = rotation
 						image.lastRotation = rotation
 						image.lastRotation = rotation
@@ -199,13 +200,13 @@ function spine.Skeleton.new (skeletonData, group)
 				bone.line.x = bone.worldX
 				bone.line.x = bone.worldX
 				bone.line.y = -bone.worldY
 				bone.line.y = -bone.worldY
 				bone.line.rotation = -bone.worldRotation
 				bone.line.rotation = -bone.worldRotation
-				if self.flipX then
+				if bone.worldFlipX then
 					bone.line.xScale = -1
 					bone.line.xScale = -1
 					bone.line.rotation = -bone.line.rotation
 					bone.line.rotation = -bone.line.rotation
 				else
 				else
 					bone.line.xScale = 1
 					bone.line.xScale = 1
 				end
 				end
-				if self.flipY then
+				if bone.worldFlipY then
 					bone.line.yScale = -1
 					bone.line.yScale = -1
 					bone.line.rotation = -bone.line.rotation
 					bone.line.rotation = -bone.line.rotation
 				else
 				else

+ 162 - 3
spine-lua/Animation.lua

@@ -83,6 +83,22 @@ local function binarySearch (values, target, step)
 	end
 	end
 end
 end
 
 
+local function binarySearch1 (values, target)
+	local low = 0
+	local high = math.floor(#values - 1)
+	if high == 0 then return 1 end
+	local current = math.floor(high / 2)
+	while true do
+		if values[current + 1] <= target then
+			low = current + 1
+		else
+			high = current
+		end
+		if low == high then return low + 1 end
+		current = math.floor((low + high) / 2)
+	end
+end
+
 local function linearSearch (values, target, step)
 local function linearSearch (values, target, step)
 	for i = 0, #values, step do
 	for i = 0, #values, step do
 		if (values[i] > target) then return i end
 		if (values[i] > target) then return i end
@@ -419,7 +435,7 @@ function Animation.AttachmentTimeline.new ()
 		if time >= frames[#frames] then -- Time is after last frame.
 		if time >= frames[#frames] then -- Time is after last frame.
 			frameIndex = #frames
 			frameIndex = #frames
 		else
 		else
-			frameIndex = binarySearch(frames, time, 1) - 1
+			frameIndex = binarySearch1(frames, time) - 1
 		end
 		end
 
 
 		local attachmentName = self.attachmentNames[frameIndex]
 		local attachmentName = self.attachmentNames[frameIndex]
@@ -477,7 +493,7 @@ function Animation.EventTimeline.new ()
 		if lastTime < frames[0] then
 		if lastTime < frames[0] then
 			frameIndex = 0
 			frameIndex = 0
 		else
 		else
-			frameIndex = binarySearch(frames, lastTime, 1)
+			frameIndex = binarySearch1(frames, lastTime)
 			local frame = frames[frameIndex]
 			local frame = frames[frameIndex]
 			while frameIndex > 0 do -- Fire multiple events with the same frame.
 			while frameIndex > 0 do -- Fire multiple events with the same frame.
 				if frames[frameIndex - 1] ~= frame then break end
 				if frames[frameIndex - 1] ~= frame then break end
@@ -522,7 +538,7 @@ function Animation.DrawOrderTimeline.new ()
 		if time >= frames[#frames] then -- Time is after last frame.
 		if time >= frames[#frames] then -- Time is after last frame.
 			frameIndex = #frames
 			frameIndex = #frames
 		else
 		else
-			frameIndex = binarySearch(frames, time, 1) - 1
+			frameIndex = binarySearch1(frames, time) - 1
 		end
 		end
 
 
 		local drawOrder = skeleton.drawOrder
 		local drawOrder = skeleton.drawOrder
@@ -542,4 +558,147 @@ function Animation.DrawOrderTimeline.new ()
 	return self
 	return self
 end
 end
 
 
+Animation.FfdTimeline = {}
+function Animation.FfdTimeline.new ()
+	local self = Animation.CurveTimeline.new()
+	self.frames = {}
+	self.frameVertices = {}
+	self.slotIndex = -1
+
+	function self:getDuration ()
+		return self.frames[#self.frames]
+	end
+
+	function self:getFrameCount ()
+		return #self.frames + 1
+	end
+
+	function self:setFrame (frameIndex, time, vertices)
+		self.frames[frameIndex] = time
+		self.frameVertices[frameIndex] = vertices
+	end
+
+	function self:apply (skeleton, lastTime, time, firedEvents, alpha)
+		local slot = skeleton.slots[self.slotIndex]
+		if slot.attachment ~= attachment then return end
+
+		local frames = self.frames
+		if time < frames[0] then -- Time is before first frame.
+			slot.attachmentVerticesCount = 0
+			return
+		end 
+		
+		local frameVertices = self.frameVertices
+		local vertexCount = #frameVertices[0]
+		local vertices = slot.attachmentVertices
+		if #vertices < vertexCount then
+			vertices = {}
+			vertices[vertexCount] = 0
+			slot.attachmentVertices = vertices
+		elseif #vertices < vertexCount then
+			alpha = 1 -- Don't mix from uninitialized slot vertices.
+		end
+		slot.attachmentVerticesCount = vertexCount
+
+		if time >= frames[#frames] then -- Time is after last frame.
+			local lastVertices = frameVertices[#frames.Length]
+			if alpha < 1 then
+				for i = 0, vertexCount do
+					local vertex = vertices[i]
+					vertices[i] = vertex + (lastVertices[i] - vertex) * alpha
+				end
+			else
+				for i = 0, vertexCount do
+					vertices[i] = lastVertices[i]
+				end
+			end
+			return
+		end
+
+		-- Interpolate between the previous frame and the current frame.
+		local frameIndex = binarySearch1(frames, time)
+		local frameTime = frames[frameIndex]
+		local percent = 1 - (time - frameTime) / (frames[frameIndex - 1] - frameTime)
+		if percent < 0 then percent = 0 elseif percent > 1 then percent = 1 end
+		percent = self:getCurvePercent(frameIndex - 1, percent)
+
+		local prevVertices = frameVertices[frameIndex - 1]
+		local nextVertices = frameVertices[frameIndex]
+
+		if alpha < 1 then
+			for i = 0, vertexCount do
+				local prev = prevVertices[i]
+				local vertices = vertices[i]
+				vertices[i] = vertices + (prev + (nextVertices[i] - prev) * percent - vertices) * alpha
+			end
+		else
+			for i = 0, vertexCount do
+				local prev = prevVertices[i]
+				vertices[i] = prev + (nextVertices[i] - prev) * percent
+			end
+		end
+	end
+
+	return self
+end
+
+Animation.FlipXTimeline = {}
+function Animation.FlipXTimeline.new ()
+	local self = {
+		frames = {}, -- time, flip, ...
+		boneIndex = -1
+	}
+
+	function self:getDuration ()
+		return self.frames[#self.frames - 1]
+	end
+
+	function self:getFrameCount ()
+		return (#self.frames + 1) / 2
+	end
+
+	function self:setFrame (frameIndex, time, flip)
+		frameIndex = frameIndex * 2
+		self.frames[frameIndex] = time
+		self.frames[frameIndex + 1] = flip
+	end
+
+	function self:apply (skeleton, lastTime, time, firedEvents, alpha)
+		local frames = self.frames
+		if time < frames[0] then
+			if lastTime > time then self:apply(skeleton, lastTime, 999999, null, 0) end
+			return
+		elseif lastTime > time then
+			lastTime = -1
+		end
+
+		local frameIndex
+		if time >= frames[#frames - 1] then
+			frameIndex = #frames - 1
+		else
+			frameIndex = binarySearch(frames, time, 2) - 2
+		end
+		if frames[frameIndex] < lastTime then return end
+
+		self:setFlip(skeleton.bones[self.boneIndex], frames[frameIndex + 1])
+	end
+	
+	function self:setFlip (bone, flip)
+		bone.flipX = flip
+	end
+
+	return self
+end
+
+Animation.FlipYTimeline = {}
+function Animation.FlipYTimeline.new ()
+	local self = Animation.FlipXTimeline.new()
+
+	function self:setFlip (bone, flip)
+		bone.flipY = flip
+	end
+
+	return self
+end
+
 return Animation
 return Animation

+ 27 - 14
spine-lua/Bone.lua

@@ -30,19 +30,23 @@
 
 
 local Bone = {}
 local Bone = {}
 
 
-function Bone.new (data, parent)
+function Bone.new (data, skeleton, parent)
 	if not data then error("data cannot be nil", 2) end
 	if not data then error("data cannot be nil", 2) end
-	
+	if not skeleton then error("skeleton cannot be nil", 2) end
+
 	local self = {
 	local self = {
 		data = data,
 		data = data,
+		skeleton = skeleton,
 		parent = parent,
 		parent = parent,
 		x = 0, y = 0,
 		x = 0, y = 0,
 		rotation = 0,
 		rotation = 0,
 		scaleX = 1, scaleY = 1,
 		scaleX = 1, scaleY = 1,
+		flipX = false, flipY = false,
 		m00 = 0, m01 = 0, worldX = 0, -- a b x
 		m00 = 0, m01 = 0, worldX = 0, -- a b x
 		m10 = 0, m11 = 0, worldY = 0, -- c d y
 		m10 = 0, m11 = 0, worldY = 0, -- c d y
 		worldRotation = 0,
 		worldRotation = 0,
 		worldScaleX = 1, worldScaleY = 1,
 		worldScaleX = 1, worldScaleY = 1,
+		worldFlipX = false, worldFlipY = false,
 	}
 	}
 
 
 	function self:updateWorldTransform (flipX, flipY)
 	function self:updateWorldTransform (flipX, flipY)
@@ -62,13 +66,16 @@ function Bone.new (data, parent)
 			else
 			else
 				 self.worldRotation = self.rotation
 				 self.worldRotation = self.rotation
 			end
 			end
+			self.worldFlipX = parent.worldFlipX ~= self.flipX
+			self.worldFlipY = parent.worldFlipY ~= self.flipY
 		else
 		else
-			if flipX then
+			local skeletonFlipX, skeletonFlipY = self.skeleton.flipX, self.skeleton.flipY
+			if skeletonFlipX then
 				self.worldX = -self.x
 				self.worldX = -self.x
 			else
 			else
 				self.worldX = self.x
 				self.worldX = self.x
 			end
 			end
-			if flipY then
+			if skeletonFlipY then
 				self.worldY = -self.y
 				self.worldY = -self.y
 			else
 			else
 				self.worldY = self.y
 				self.worldY = self.y
@@ -76,21 +83,25 @@ function Bone.new (data, parent)
 			self.worldScaleX = self.scaleX
 			self.worldScaleX = self.scaleX
 			self.worldScaleY = self.scaleY
 			self.worldScaleY = self.scaleY
 			self.worldRotation = self.rotation
 			self.worldRotation = self.rotation
+			self.worldFlipX = skeletonFlipX ~= self.flipX
+			self.worldFlipY = skeletonFlipY ~= self.flipY
 		end
 		end
 		local radians = math.rad(self.worldRotation)
 		local radians = math.rad(self.worldRotation)
 		local cos = math.cos(radians)
 		local cos = math.cos(radians)
 		local sin = math.sin(radians)
 		local sin = math.sin(radians)
-		self.m00 = cos * self.worldScaleX
-		self.m10 = sin * self.worldScaleX
-		self.m01 = -sin * self.worldScaleY
-		self.m11 = cos * self.worldScaleY
-		if flipX then
-			self.m00 = -self.m00
-			self.m01 = -self.m01
+		if self.worldFlipX then
+			self.m00 = -cos * self.worldScaleX
+			self.m01 = sin * self.worldScaleY
+		else
+			self.m00 = cos * self.worldScaleX
+			self.m01 = -sin * self.worldScaleY
 		end
 		end
-		if flipY then
-			self.m10 = -self.m10
-			self.m11 = -self.m11
+		if self.worldFlipY then
+			self.m10 = -sin * self.worldScaleX
+			self.m11 = -cos * self.worldScaleY
+		else
+			self.m10 = sin * self.worldScaleX
+			self.m11 = cos * self.worldScaleY
 		end
 		end
 	end
 	end
 
 
@@ -101,6 +112,8 @@ function Bone.new (data, parent)
 		self.rotation = data.rotation
 		self.rotation = data.rotation
 		self.scaleX = data.scaleX
 		self.scaleX = data.scaleX
 		self.scaleY = data.scaleY
 		self.scaleY = data.scaleY
+		self.flipX = data.flipX
+		self.flipY = data.flipY
 	end
 	end
 
 
 	self:setToSetupPose()
 	self:setToSetupPose()

+ 3 - 3
spine-lua/Skeleton.lua

@@ -51,7 +51,7 @@ function Skeleton.new (skeletonData)
 
 
 	function self:updateWorldTransform ()
 	function self:updateWorldTransform ()
 		for i,bone in ipairs(self.bones) do
 		for i,bone in ipairs(self.bones) do
-			bone:updateWorldTransform(self.flipX, self.flipY)
+			bone:updateWorldTransform()
 		end
 		end
 	end
 	end
 
 
@@ -165,12 +165,12 @@ function Skeleton.new (skeletonData)
 	for i,boneData in ipairs(skeletonData.bones) do
 	for i,boneData in ipairs(skeletonData.bones) do
 		local parent
 		local parent
 		if boneData.parent then parent = self.bones[spine.utils.indexOf(skeletonData.bones, boneData.parent)] end
 		if boneData.parent then parent = self.bones[spine.utils.indexOf(skeletonData.bones, boneData.parent)] end
-		table.insert(self.bones, Bone.new(boneData, parent))
+		table.insert(self.bones, Bone.new(boneData, self, parent))
 	end
 	end
 
 
 	for i,slotData in ipairs(skeletonData.slots) do
 	for i,slotData in ipairs(skeletonData.slots) do
 		local bone = self.bones[spine.utils.indexOf(skeletonData.bones, slotData.boneData)]
 		local bone = self.bones[spine.utils.indexOf(skeletonData.bones, slotData.boneData)]
-		local slot = Slot.new(slotData, self, bone)
+		local slot = Slot.new(slotData, bone)
 		table.insert(self.slots, slot)
 		table.insert(self.slots, slot)
 		self.slotsByName[slot.data.name] = slot
 		self.slotsByName[slot.data.name] = slot
 		table.insert(self.drawOrder, slot)
 		table.insert(self.drawOrder, slot)

+ 23 - 0
spine-lua/SkeletonJson.lua

@@ -86,6 +86,8 @@ function SkeletonJson.new (attachmentLoader)
 			else
 			else
 				boneData.scaleY = 1
 				boneData.scaleY = 1
 			end
 			end
+			boneData.flipX = boneMap["flipX"] or false
+			boneData.flipY = boneMap["flipY"] or false
 			if boneMap["inheritScale"] == false then
 			if boneMap["inheritScale"] == false then
 				boneData.inheritScale = false
 				boneData.inheritScale = false
 			else
 			else
@@ -375,6 +377,27 @@ function SkeletonJson.new (attachmentLoader)
 						table.insert(timelines, timeline)
 						table.insert(timelines, timeline)
 						duration = math.max(duration, timeline:getDuration())
 						duration = math.max(duration, timeline:getDuration())
 
 
+					elseif timelineName == "flipX" or timelineName == "flipY" then
+						local x = timelineName == "flipX"
+						local timeline, field
+						if x then
+							timeline = Animation.FlipXTimeline.new()
+							field = "x"
+						else
+							timeline = Animation.FlipYTimeline.new();
+							field = "y"
+						end
+						timeline.boneIndex = boneIndex
+
+						local frameIndex = 0
+						for i,valueMap in ipairs(values) do
+							local flip
+							timeline:setFrame(frameIndex, valueMap["time"], valueMap[field] or false)
+							frameIndex = frameIndex + 1
+						end
+						table.insert(timelines, timeline)
+						duration = math.max(duration, timeline:getDuration())
+
 					else
 					else
 						error("Invalid timeline type for a bone: " .. timelineName .. " (" .. boneName .. ")")
 						error("Invalid timeline type for a bone: " .. timelineName .. " (" .. boneName .. ")")
 					end
 					end

+ 8 - 8
spine-lua/Slot.lua

@@ -29,19 +29,18 @@
 -------------------------------------------------------------------------------
 -------------------------------------------------------------------------------
 
 
 local Slot = {}
 local Slot = {}
-function Slot.new (slotData, skeleton, bone)
+function Slot.new (slotData, bone)
 	if not slotData then error("slotData cannot be nil", 2) end
 	if not slotData then error("slotData cannot be nil", 2) end
-	if not skeleton then error("skeleton cannot be nil", 2) end
 	if not bone then error("bone cannot be nil", 2) end
 	if not bone then error("bone cannot be nil", 2) end
 
 
 	local self = {
 	local self = {
 		data = slotData,
 		data = slotData,
-		skeleton = skeleton,
 		bone = bone,
 		bone = bone,
 		r = 1, g = 1, b = 1, a = 1,
 		r = 1, g = 1, b = 1, a = 1,
 		attachment = nil,
 		attachment = nil,
 		attachmentTime = 0,
 		attachmentTime = 0,
-		attachmentVertices = nil
+		attachmentVertices = nil,
+		attachmentVerticesCount = 0
 	}
 	}
 
 
 	function self:setColor (r, g, b, a)
 	function self:setColor (r, g, b, a)
@@ -53,15 +52,16 @@ function Slot.new (slotData, skeleton, bone)
 
 
 	function self:setAttachment (attachment)
 	function self:setAttachment (attachment)
 		self.attachment = attachment
 		self.attachment = attachment
-		self.attachmentTime = self.skeleton.time
+		self.attachmentTime = self.bone.skeleton.time
+		self.attachmentVerticesCount = 0
 	end
 	end
 
 
 	function self:setAttachmentTime (time)
 	function self:setAttachmentTime (time)
-		self.attachmentTime = self.skeleton.time - time
+		self.attachmentTime = self.bone.skeleton.time - time
 	end
 	end
 
 
 	function self:getAttachmentTime ()
 	function self:getAttachmentTime ()
-		return self.skeleton.time - self.attachmentTime
+		return self.bone.skeleton.time - self.attachmentTime
 	end
 	end
 
 
 	function self:setToSetupPose ()
 	function self:setToSetupPose ()
@@ -71,7 +71,7 @@ function Slot.new (slotData, skeleton, bone)
 
 
 		local attachment
 		local attachment
 		if data.attachmentName then 
 		if data.attachmentName then 
-			attachment = self.skeleton:getAttachment(data.name, data.attachmentName)
+			attachment = self.bone.skeleton:getAttachment(data.name, data.attachmentName)
 		end
 		end
 		self:setAttachment(attachment)
 		self:setAttachment(attachment)
 	end
 	end

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