소스 검색

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

NathanSweet 10 년 전
부모
커밋
59204db7f8
32개의 변경된 파일281개의 추가작업 그리고 331개의 파일을 삭제
  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)
 	skeleton:updateWorldTransform()
 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)

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 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.dragon"
+require "examples.hero"

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

@@ -128,10 +128,11 @@ function spine.Skeleton.new (skeletonData, group)
 				end
 				-- Position image based on attachment and bone.
 				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
 						image.x, image.y = 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.
 					local rotation = math.abs(attachment.rotation) % 180
 					if (rotation == 90) then
-						xScale = xScale * slot.bone.worldScaleY
-						yScale = yScale * slot.bone.worldScaleX
+						xScale = xScale * bone.worldScaleY
+						yScale = yScale * bone.worldScaleX
 					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
 							image.rotationWarning = true
 							print("WARNING: Non-uniform bone scaling with attachments not rotated to\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
 					if not image.lastScaleX then
@@ -165,7 +166,7 @@ function spine.Skeleton.new (skeletonData, group)
 						image.lastScaleX, image.lastScaleY = xScale, yScale
 					end
 
-					rotation = -(slot.bone.worldRotation + attachment.rotation) * flipX * flipY
+					rotation = -(bone.worldRotation + attachment.rotation) * flipX * flipY
 					if not image.lastRotation then
 						image.rotation = rotation
 						image.lastRotation = rotation
@@ -199,13 +200,13 @@ function spine.Skeleton.new (skeletonData, group)
 				bone.line.x = bone.worldX
 				bone.line.y = -bone.worldY
 				bone.line.rotation = -bone.worldRotation
-				if self.flipX then
+				if bone.worldFlipX then
 					bone.line.xScale = -1
 					bone.line.rotation = -bone.line.rotation
 				else
 					bone.line.xScale = 1
 				end
-				if self.flipY then
+				if bone.worldFlipY then
 					bone.line.yScale = -1
 					bone.line.rotation = -bone.line.rotation
 				else

+ 162 - 3
spine-lua/Animation.lua

@@ -83,6 +83,22 @@ local function binarySearch (values, target, step)
 	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)
 	for i = 0, #values, step do
 		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.
 			frameIndex = #frames
 		else
-			frameIndex = binarySearch(frames, time, 1) - 1
+			frameIndex = binarySearch1(frames, time) - 1
 		end
 
 		local attachmentName = self.attachmentNames[frameIndex]
@@ -477,7 +493,7 @@ function Animation.EventTimeline.new ()
 		if lastTime < frames[0] then
 			frameIndex = 0
 		else
-			frameIndex = binarySearch(frames, lastTime, 1)
+			frameIndex = binarySearch1(frames, lastTime)
 			local frame = frames[frameIndex]
 			while frameIndex > 0 do -- Fire multiple events with the same frame.
 				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.
 			frameIndex = #frames
 		else
-			frameIndex = binarySearch(frames, time, 1) - 1
+			frameIndex = binarySearch1(frames, time) - 1
 		end
 
 		local drawOrder = skeleton.drawOrder
@@ -542,4 +558,147 @@ function Animation.DrawOrderTimeline.new ()
 	return self
 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

+ 27 - 14
spine-lua/Bone.lua

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

+ 3 - 3
spine-lua/Skeleton.lua

@@ -51,7 +51,7 @@ function Skeleton.new (skeletonData)
 
 	function self:updateWorldTransform ()
 		for i,bone in ipairs(self.bones) do
-			bone:updateWorldTransform(self.flipX, self.flipY)
+			bone:updateWorldTransform()
 		end
 	end
 
@@ -165,12 +165,12 @@ function Skeleton.new (skeletonData)
 	for i,boneData in ipairs(skeletonData.bones) do
 		local parent
 		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
 
 	for i,slotData in ipairs(skeletonData.slots) do
 		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)
 		self.slotsByName[slot.data.name] = slot
 		table.insert(self.drawOrder, slot)

+ 23 - 0
spine-lua/SkeletonJson.lua

@@ -86,6 +86,8 @@ function SkeletonJson.new (attachmentLoader)
 			else
 				boneData.scaleY = 1
 			end
+			boneData.flipX = boneMap["flipX"] or false
+			boneData.flipY = boneMap["flipY"] or false
 			if boneMap["inheritScale"] == false then
 				boneData.inheritScale = false
 			else
@@ -375,6 +377,27 @@ function SkeletonJson.new (attachmentLoader)
 						table.insert(timelines, timeline)
 						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
 						error("Invalid timeline type for a bone: " .. timelineName .. " (" .. boneName .. ")")
 					end

+ 8 - 8
spine-lua/Slot.lua

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

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.