Эх сурвалжийг харах

[lua][corona] Ported 3.6 changes except TransformConstraint update

badlogic 8 жил өмнө
parent
commit
0a2ca732cd

+ 9 - 0
spine-corona/main.lua

@@ -75,6 +75,7 @@ function loadSkeleton(atlasFile, jsonFile, x, y, scale, animation, skin)
 	return { skeleton = skeleton, state = animationState }
 end
 
+table.insert(skeletons, loadSkeleton("test.atlas", "test.json", 240, 300, 0.4, "animation"))
 table.insert(skeletons, loadSkeleton("spineboy.atlas", "spineboy.json", 240, 300, 0.4, "walk"))
 table.insert(skeletons, loadSkeleton("raptor.atlas", "raptor.json", 200, 300, 0.25, "walk"))
 table.insert(skeletons, loadSkeleton("goblins.atlas", "goblins-mesh.json", 240, 300, 0.8, "walk", "goblin"))
@@ -82,6 +83,14 @@ table.insert(skeletons, loadSkeleton("stretchyman.atlas", "stretchyman.json", 40
 table.insert(skeletons, loadSkeleton("tank.atlas", "tank.json", 400, 300, 0.2, "drive"))
 table.insert(skeletons, loadSkeleton("vine.atlas", "vine.json", 240, 300, 0.3, "animation"))
 
+local bounds = spine.SkeletonBounds.new()
+skeletons[1].skeleton:updateWorldTransform()
+bounds:update(skeletons[1].skeleton, true)
+
+local offset = {}
+local size = {}
+skeletons[1].skeleton:getBounds(offset, size)
+
 display.setDefault("background", 0.2, 0.2, 0.2, 1)
 
 Runtime:addEventListener("enterFrame", function (event)

+ 83 - 14
spine-corona/spine-corona/spine.lua

@@ -43,6 +43,7 @@ spine.RegionAttachment = require "spine-lua.attachments.RegionAttachment"
 spine.MeshAttachment = require "spine-lua.attachments.MeshAttachment"
 spine.VertexAttachment = require "spine-lua.attachments.VertexAttachment"
 spine.PathAttachment = require "spine-lua.attachments.PathAttachment"
+spine.PointAttachment = require "spine-lua.attachments.PointAttachment"
 spine.Skeleton = require "spine-lua.Skeleton"
 spine.Bone = require "spine-lua.Bone"
 spine.Slot = require "spine-lua.Slot"
@@ -86,6 +87,7 @@ spine.Skeleton.new = function(skeletonData, group)
 	self.drawingGroup = nil
 	self.premultipliedAlpha = false
 	self.batches = 0
+	self.tempColor = spine.Color.newWith(1, 1, 1, 1)
 	return self
 end
 
@@ -108,6 +110,8 @@ local function toCoronaBlendMode(blendMode)
 	end
 end
 
+local worldVertices = spine.utils.newNumberArray(10000 * 8)
+
 function spine.Skeleton:updateWorldTransform()
 	spine.Skeleton.updateWorldTransform_super(self)
 	local premultipliedAlpha = self.premultipliedAlpha
@@ -125,7 +129,7 @@ function spine.Skeleton:updateWorldTransform()
 	local groupVertices = {}
 	local groupIndices = {}
 	local groupUvs = {}
-	local color = nil
+	local color = self.tempColor
 	local lastColor = nil
 	local texture = nil
 	local lastTexture = nil
@@ -134,19 +138,20 @@ function spine.Skeleton:updateWorldTransform()
 	for i,slot in ipairs(drawOrder) do
 		local attachment = slot.attachment
 		local vertices = nil
+		local numVertices = 0
 		local indices = nil
 		if attachment then
 			if attachment.type == spine.AttachmentType.region then
-				vertices = attachment:updateWorldVertices(slot, premultipliedAlpha)
+				numVertices = 4
+				vertices = self:computeRegionVertices(slot, attachment, premultipliedAlpha, color)
 				indices = QUAD_TRIANGLES
-				texture = attachment.region.renderObject.texture
-				color = { vertices[5], vertices[6], vertices[7], vertices[8]}
+				texture = attachment.region.renderObject.texture				
 				blendMode = toCoronaBlendMode(slot.data.blendMode)
 			elseif attachment.type == spine.AttachmentType.mesh then
-				vertices = attachment:updateWorldVertices(slot, premultipliedAlpha)
+				numVertices = attachment.worldVerticesLength / 2
+				vertices = self:computeMeshVertices(slot, attachment, premultipliedAlpha, color)
 				indices = attachment.triangles
 				texture = attachment.region.renderObject.texture
-				color = { vertices[5], vertices[6], vertices[7], vertices[8] }
 				blendMode = toCoronaBlendMode(slot.data.blendMode)
 			end
 
@@ -165,7 +170,7 @@ function spine.Skeleton:updateWorldTransform()
 					groupIndices = {}
 				end
 
-				self:batch(vertices, indices, groupVertices, groupUvs, groupIndices)
+				self:batch(vertices, numVertices, indices, groupVertices, groupUvs, groupIndices)
 			end
 		end
 	end
@@ -175,22 +180,87 @@ function spine.Skeleton:updateWorldTransform()
 	end
 end
 
+function spine.Skeleton:computeRegionVertices(slot, region, pma, color)
+	local skeleton = slot.bone.skeleton
+	local skeletonColor = skeleton.color
+	local slotColor = slot.color
+	local regionColor = region.color
+	local alpha = skeletonColor.a * slotColor.a * regionColor.a
+	local multiplier = alpha
+	if pma then multiplier = 1 end
+	color:set(skeletonColor.r * slotColor.r * regionColor.r * multiplier,
+				skeletonColor.g * slotColor.g * regionColor.g * multiplier,
+				skeletonColor.b * slotColor.b * regionColor.b * multiplier,
+				alpha)
+
+	local vertices = worldVertices
+	region:computeWorldVertices(slot.bone, vertices, 0, 4)
+
+	local uvs = region.uvs
+
+	vertices[3] = uvs[1]
+	vertices[4] = uvs[2]
+
+	vertices[7] = uvs[3]
+	vertices[8] = uvs[4]
+
+	vertices[11] = uvs[5]
+	vertices[12] = uvs[6]
+
+	vertices[15] = uvs[7]
+	vertices[16] = uvs[8]
+
+	return vertices
+end
+
+function spine.Skeleton:computeMeshVertices(slot, mesh, pma, color)
+	local skeleton = slot.bone.skeleton
+	local skeletonColor = skeleton.color
+	local slotColor = slot.color
+	local meshColor = mesh.color
+	local alpha = skeletonColor.a * slotColor.a * meshColor.a
+	local multiplier = alpha
+	if pma then multiplier = 1 end
+	color:set(skeletonColor.r * slotColor.r * meshColor.r * multiplier,
+				skeletonColor.g * slotColor.g * meshColor.g * multiplier,
+				skeletonColor.b * slotColor.b * meshColor.b * multiplier,
+				alpha)
+			
+	local numVertices = mesh.worldVerticesLength / 2
+	local vertices = worldVertices
+	mesh:computeWorldVertices(slot, 0, mesh.worldVerticesLength, vertices, 0, 4)
+	
+	local uvs = mesh.uvs
+	local i = 1
+	local n = numVertices + 1
+	local u = 1
+	local v = 3
+	while i < n do
+		vertices[v] = uvs[u]
+		vertices[v + 1] = uvs[u + 1]
+		i = i + 1
+		u = u + 2
+		v = v + 4
+	end
+	return vertices
+end
+
 function spine.Skeleton:flush(groupVertices, groupUvs, groupIndices, texture, color, blendMode, drawingGroup)
-	mesh = display.newMesh(drawingGroup, 0, 0, {
+	local mesh = display.newMesh(drawingGroup, 0, 0, {
 			mode = "indexed",
 			vertices = groupVertices,
 			uvs = groupUvs,
 			indices = groupIndices
 	})
 	mesh.fill = texture
-	mesh:setFillColor(color[1], color[2], color[3])
-	mesh.alpha = color[4]
+	mesh:setFillColor(color.r, color.g, color.b)
+	mesh.alpha = color.a
 	mesh.blendMode = blendMode
 	mesh:translate(mesh.path:getVertexOffset())
 	self.batches = self.batches + 1
 end
 
-function spine.Skeleton:batch(vertices, indices, groupVertices, groupUvs, groupIndices)
+function spine.Skeleton:batch(vertices, numVertices, indices, groupVertices, groupUvs, groupIndices)
 	local numIndices = #indices
 	local i = 1
 	local indexStart = #groupIndices + 1
@@ -204,16 +274,15 @@ function spine.Skeleton:batch(vertices, indices, groupVertices, groupUvs, groupI
 	end
 
 	i = 1
-	local numVertices = #vertices
 	local vertexStart = #groupVertices + 1
-	local vertexEnd = vertexStart + numVertices / 4
+	local vertexEnd = vertexStart + numVertices * 2
 	while vertexStart < vertexEnd do
 		groupVertices[vertexStart] = vertices[i]
 		groupVertices[vertexStart+1] = vertices[i+1]
 		groupUvs[vertexStart] = vertices[i+2]
 		groupUvs[vertexStart+1] = vertices[i+3]
 		vertexStart = vertexStart + 2
-		i = i + 8
+		i = i + 4
 	end
 end
 

+ 104 - 1
spine-lua/Animation.lua

@@ -118,7 +118,8 @@ Animation.TimelineType = {
 	attachment = 4, color = 5, deform = 6,
 	event = 7, drawOrder = 8,
 	ikConstraint = 9, transformConstraint = 10,
-	pathConstraintPosition = 11, pathConstraintSpacing = 12, pathConstraintMix = 13
+	pathConstraintPosition = 11, pathConstraintSpacing = 12, pathConstraintMix = 13,
+	twoColor = 14
 }
 local TimelineType = Animation.TimelineType
 local SHL_24 = 16777216
@@ -562,6 +563,108 @@ function Animation.ColorTimeline.new (frameCount)
 	return self
 end
 
+Animation.TwoColorTimeline = {}
+Animation.TwoColorTimeline.ENTRIES = 8
+function Animation.TwoColorTimeline.new (frameCount)
+	local ENTRIES = Animation.TwoColorTimeline.ENTRIES
+	local PREV_TIME = -8
+	local PREV_R = -7
+	local PREV_G = -6
+	local PREV_B = -5
+	local PREV_A = -4
+	local PREV_R2 = -3
+	local PREV_G2 = -2
+	local PREV_B2 = -1
+	local R = 1
+	local G = 2
+	local B = 3
+	local A = 4
+	local R2 = 5
+	local G2 = 6
+	local B2 = 7
+
+	local self = Animation.CurveTimeline.new(frameCount)
+	self.frames = utils.newNumberArrayZero(frameCount * ENTRIES)
+	self.slotIndex = -1
+	self.type = TimelineType.twoColor
+	
+	function self:getPropertyId ()
+		return TimelineType.twoColor * SHL_24 + self.slotIndex
+	end
+
+	function self:setFrame (frameIndex, time, r, g, b, a, r2, g2, b2)
+		frameIndex = frameIndex * ENTRIES
+		self.frames[frameIndex] = time
+		self.frames[frameIndex + R] = r
+		self.frames[frameIndex + G] = g
+		self.frames[frameIndex + B] = b
+		self.frames[frameIndex + A] = a
+		self.frames[frameIndex + R2] = r2
+		self.frames[frameIndex + G2] = g2
+		self.frames[frameIndex + B2] = b2
+	end
+
+	function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut)
+		local frames = self.frames
+		local slot = skeleton.slots[self.slotIndex]
+		if time < frames[0] then 
+			if setupPose then
+				slot.color:setFrom(slot.data.color)
+				slot.darkColor:setFrom(slot.data.darkColor)
+			end
+			return
+		end
+
+		local r, g, b, a, r2, g2, b2
+		if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame.
+			local i = zlen(frames)
+			r = frames[i + PREV_R]
+			g = frames[i + PREV_G]
+			b = frames[i + PREV_B]
+			a = frames[i + PREV_A]
+			r2 = frames[i + PREV_R2]
+			g2 = frames[i + PREV_G2]
+			b2 = frames[i + PREV_B2]
+		else
+			-- Interpolate between the last frame and the current frame.
+			local frame = binarySearch(frames, time, ENTRIES)
+			r = frames[frame + PREV_R]
+			g = frames[frame + PREV_G]
+			b = frames[frame + PREV_B]
+			a = frames[frame + PREV_A]
+			r2 = frames[frame + PREV_R2]
+			g2 = frames[frame + PREV_G2]
+			b2 = frames[frame + PREV_B2]
+			local frameTime = frames[frame]
+			local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1,
+					1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime))
+
+			r = r + (frames[frame + R] - r) * percent
+			g = g + (frames[frame + G] - g) * percent
+			b = b + (frames[frame + B] - b) * percent
+			a = a + (frames[frame + A] - a) * percent
+			r2 = r2 + (frames[frame + R2] - r2) * percent
+			g2 = g2 + (frames[frame + G2] - g2) * percent
+			b2 = b2 + (frames[frame + B2] - b2) * percent
+		end
+		if alpha == 1 then
+			slot.color:set(r, g, b, a)
+			slot.darkColor:set(r2, g2, b2, 1)
+		else
+			local light = slot.color
+			local dark = slot.darkColor
+			if setupPose then 
+				light:setFrom(slot.data.color)
+				dark:setFrom(slot.data.darkColor)
+			end
+			light:add((r - light.r) * alpha, (g - light.g) * alpha, (b - light.b) * alpha, (a - light.a) * alpha)
+			dark:add((r2 - dark.r) * alpha, (g2 - dark.g) * alpha, (b2 - dark.b) * alpha, 0)
+		end
+	end
+
+	return self
+end
+
 Animation.AttachmentTimeline = {}
 function Animation.AttachmentTimeline.new (frameCount)
 	local self = {

+ 5 - 0
spine-lua/AtlasAttachmentLoader.lua

@@ -35,6 +35,7 @@ local RegionAttachment = require "spine-lua.attachments.RegionAttachment"
 local BoundingBoxAttachment = require "spine-lua.attachments.BoundingBoxAttachment"
 local MeshAttachment = require "spine-lua.attachments.MeshAttachment"
 local PathAttachment = require "spine-lua.attachments.PathAttachment"
+local PointAttachment = require "spine-lua.attachments.PointAttachment"
 local TextureAtlas = require "spine-lua.TextureAtlas"
 
 local AtlasAttachmentLoader = {}
@@ -79,4 +80,8 @@ function AtlasAttachmentLoader:newPathAttachment(skin, name)
 	return PathAttachment.new(name)
 end
 
+function AtlasAttachmentLoader:newPointAttachment(skin, name)
+	return PointAttachment.new(name)
+end
+
 return AtlasAttachmentLoader

+ 5 - 0
spine-lua/AttachmentLoader.lua

@@ -33,6 +33,7 @@ local RegionAttachment = require "spine-lua.attachments.RegionAttachment"
 local BoundingBoxAttachment = require "spine-lua.attachments.BoundingBoxAttachment"
 local MeshAttachment = require "spine-lua.attachments.MeshAttachment"
 local PathAttachment = require "spine-lua.attachments.PathAttachment"
+local PointAttachment = require "spine-lua.attachments.PointAttachment"
 
 local AttachmentLoader = {}
 function AttachmentLoader.new ()
@@ -57,6 +58,10 @@ function AttachmentLoader.new ()
 	function self:newPathAttachment(skin, name)
 		return PathAttachment.new(name)
 	end
+	
+	function self:newPointAttachment(skin, name)
+		return PointAttachment.new(name)
+	end
 
 	return self
 end

+ 27 - 39
spine-lua/Bone.lua

@@ -240,45 +240,6 @@ function Bone:getWorldScaleY ()
 	return math_sqrt(self.b * self.b + self.d * self.d)
 end
 
-function Bone:worldToLocalRotationX ()
-	local parent = self.parent
-	if parent == nil then return self.arotation end
-	local pa = parent.a
-	local pb = parent.b
-	local pc = parent.c
-	local pd = parent.d
-	local a = self.a
-	local c = self.c
-	return math_deg(math_atan2(pa * c - pc * a, pd * a - pb * c))
-end
-
-function Bone:worldToLocalRotationY ()
-	local parent = self.parent
-	if parent == nil then return self.rotation end
-	local pa = parent.a
-	local pb = parent.b
-	local pc = parent.c
-	local pd = parent.d
-	local b = self.b
-	local d = self.d
-	return math_deg(math_atan2(pa * d - pc * b, pd * b - pb * d))
-end
-
-function Bone:rotateWorld (degrees)
-	local a = self.a
-	local b = self.b
-	local c = self.c
-	local d = self.d
-	local degreesRad = math_rad(degrees)
-	local cos = math_cos(degreesRad)
-	local sin = math_sin(degreesRad)
-	self.a = cos * a - sin * c
-	self.b = cos * b - sin * d
-	self.c = sin * a + cos * c
-	self.d = sin * b + cos * d
-	self.appliedValid = false
-end
-
 function updateAppliedTransform ()
 	local parent = self.parent
 	if parent == nil then
@@ -344,4 +305,31 @@ function Bone:localToWorld (localCoords)
 	return localCoords
 end
 
+function Bone:worldToLocalRotation (worldRotation)
+	local sin = math_sin(math_rad(worldRotation))
+	local cos = math_cos(math_rad(worldRotation))
+	return math_deg(math_atan2(self.a * sin - self.c * cos, self.d * cos - self.b * sin))
+end
+
+function Bone:localToWorldRotation (localRotation)
+	local sin = math_sin(math_rad(localRotation))
+	local cos = math_cos(math_rad(localRotation))
+	return math_deg(math_atan2(cos * self.c + sin * self.d, cos * self.a + sin * self.b))
+end
+
+function Bone:rotateWorld (degrees)
+	local a = self.a
+	local b = self.b
+	local c = self.c
+	local d = self.d
+	local degreesRad = math_rad(degrees)
+	local cos = math_cos(degreesRad)
+	local sin = math_sin(degreesRad)
+	self.a = cos * a - sin * c
+	self.b = cos * b - sin * d
+	self.c = sin * a + cos * c
+	self.d = sin * b + cos * d
+	self.appliedValid = false
+end
+
 return Bone

+ 13 - 13
spine-lua/PathConstraint.lua

@@ -117,13 +117,13 @@ function PathConstraint:update ()
 		local n = spacesCount - 1
 		while i < n do
 			local bone = bones[i + 1];
-			local length = bone.data.length
-			local x = length * bone.a
-			local y = length * bone.c
-			length = math_sqrt(x * x + y * y)
+			local setupLength = bone.data.length
+			local x = setupLength * bone.a
+			local y = setupLength * bone.c
+			local length = math_sqrt(x * x + y * y)
 			if scale then lengths[i + 1] = length end
 			i = i + 1
-			if lengthSpacing then spaces[i + 1] = math_max(0, length + spacing) else spaces[i + 1] = spacing end
+			if lengthSpacing then spaces[i + 1] = (setupLength + spacing) * length / setupLength else spaces[i + 1] = spacing * length / setupLength end
 		end
 	else
 		local i = 1
@@ -254,14 +254,14 @@ function PathConstraint:computeWorldPositions (path, spacesCount, tangents, perc
 			elseif p < 0 then
 				if prevCurve ~= PathConstraint.BEFORE then
 					prevCurve = PathConstraint.BEFORE
-					path:computeWorldVerticesWith(target, 2, 4, world, 0)
+					path:computeWorldVertices(target, 2, 4, world, 0, 2)
 				end
 				self:addBeforePosition(p, world, 0, out, o)
 				skip = true
 			elseif p > pathLength then
 				if prevCurve ~= PathConstraint.AFTER then
 					prevCurve = PathConstraint.AFTER
-					path:computeWorldVerticesWith(target, verticesLength - 6, 4, world, 0)
+					path:computeWorldVertices(target, verticesLength - 6, 4, world, 0, 2)
 				end
 				self:addAfterPosition(p - pathLength, world, 0, out, o)
 				skip = true
@@ -285,10 +285,10 @@ function PathConstraint:computeWorldPositions (path, spacesCount, tangents, perc
 				if curve ~= prevCurve then
 					prevCurve = curve
 					if closed and curve == curveCount then
-						path:computeWorldVerticesWith(target, verticesLength - 4, 4, world, 0)
-						path:computeWorldVerticesWith(target, 0, 4, world, 4)
+						path:computeWorldVertices(target, verticesLength - 4, 4, world, 0, 2)
+						path:computeWorldVertices(target, 0, 4, world, 4, 2)
 					else
-						path:computeWorldVerticesWith(target, curve * 6 + 2, 8, world, 0)
+						path:computeWorldVertices(target, curve * 6 + 2, 8, world, 0, 2)
 					end
 				end
 				self:addCurvePosition(p, world[1], world[2], world[3], world[4], world[5], world[6], world[7], world[8], out, o, tangents or (i > 0 and space == 0))
@@ -304,15 +304,15 @@ function PathConstraint:computeWorldPositions (path, spacesCount, tangents, perc
 	if closed then
 		verticesLength = verticesLength + 2
 		world = utils.setArraySize(self.world, verticesLength)
-		path:computeWorldVerticesWith(target, 2, verticesLength - 4, world, 0)
-		path:computeWorldVerticesWith(target, 0, 2, world, verticesLength - 4)
+		path:computeWorldVertices(target, 2, verticesLength - 4, world, 0, 2)
+		path:computeWorldVertices(target, 0, 2, world, verticesLength - 4, 2)
 		world[verticesLength - 2 + 1] = world[0 + 1]
 		world[verticesLength - 1 + 1] = world[1 + 1]
 	else
 		curveCount = curveCount - 1
 		verticesLength = verticesLength - 4;
 		world = utils.setArraySize(self.world, verticesLength)
-		path:computeWorldVerticesWith(target, 2, verticesLength, world, 0)
+		path:computeWorldVertices(target, 2, verticesLength, world, 0, 2)
 	end
 
 	-- Curve lengths.

+ 29 - 10
spine-lua/Skeleton.lua

@@ -206,7 +206,7 @@ function Skeleton:sortPathConstraint(constraint)
 	if self.data.defaultSkin and not (self.data.defaultSkin == skin) then
 		self:sortPathConstraintAttachment(self.data.defaultSkin, slotIndex, slotBone)
 	end
-	for ii,skin in ipairs(self.data.skins) do
+	for i,skin in ipairs(self.data.skins) do
 		self:sortPathConstraintAttachment(skin, slotIndex, slotBone)
 	end
 	
@@ -214,7 +214,7 @@ function Skeleton:sortPathConstraint(constraint)
 	if attachment.type == AttachmentType.path then self:sortPathConstraintAttachmentWith(attachment, slotBone) end
 	
 	local constrained = constraint.bones
-	for ii,bone in ipairs(constrained) do
+	for i,bone in ipairs(constrained) do
 		self:sortBone(bone)
 	end
 	
@@ -232,9 +232,24 @@ end
 function Skeleton:sortTransformConstraint(constraint)
 	self:sortBone(constraint.target)
 	
-	local constrained = constraint.bones
-	for ii,bone in ipairs(constrained) do
-		self:sortBone(bone)
+	local constrained = constraint.bones	
+	if constraint.data.local_ then
+		for i,bone in ipairs(constrained) do
+			local child = constrained[#constrained]
+			local contains = false
+			sortBone(child.parent)
+			for i,updatable in ipairs(self._updateCache) do
+				if updatable == child then
+					contains = true
+					break
+				end
+			end
+			if not contains then table_insert(self.updateCacheReset, child) end
+		end
+	else
+		for i,bone in ipairs(constrained) do
+			self:sortBone(bone)
+		end
 	end
 	
 	table_insert(self._updateCache, constraint)
@@ -482,12 +497,16 @@ function Skeleton:getBounds(offset, size)
 			local maxX = -99999999
 			local maxY = -99999999
 			for i, slot in ipairs(drawOrder) do
-				local vertices = nil
+				local vertices = {}
 				local attachment = slot.attachment
-				if attachment and (attachment.type == AttachmentType.region or attachment.type == AttachmentType.mesh) then
-					vertices = attachment:updateWorldVertices(slot, false);
+				if attachment then
+					if attachment.type == AttachmentType.region then
+						attachment:computeWorldVertices(slot.bone, vertices, 0, 2)
+					elseif attachment.type == AttachmentType.mesh then
+						attachment:computeWorldVertices(slot, 0, attachment.worldVerticesLength, vertices, 0, 2)
+					end
 				end
-				if vertices then
+				if #vertices > 0 then
 					local nn = #vertices
 					local ii = 1
 					while ii <= nn do
@@ -497,7 +516,7 @@ function Skeleton:getBounds(offset, size)
 						minY = math_min(minY, y)
 						maxX = math_max(maxX, x)
 						maxY = math_max(maxY, y)
-						ii = ii + 8
+						ii = ii + 2
 					end
 				end
 			end

+ 1 - 1
spine-lua/SkeletonBounds.lua

@@ -68,7 +68,7 @@ function SkeletonBounds:update (skeleton, updateAabb)
 			local polygon = {}
 			table_insert(polygons, polygon)
 
-			boundingBox:computeWorldVertices(slot, polygon)
+			boundingBox:computeWorldVertices(slot, 0, boundingBox.worldVerticesLength, polygon, 0, 2)
 		end
 	end
 

+ 26 - 0
spine-lua/SkeletonJson.lua

@@ -131,6 +131,15 @@ function SkeletonJson.new (attachmentLoader)
 					               tonumber(color:sub(7, 8), 16) / 255)
 				end
 
+				local dark = slotMap["dark"]
+				if dark then
+					data.darkColor = Color.newWith(1, 1, 1, 1)
+					data.darkColor:set(tonumber(dark:sub(1, 2), 16) / 255,
+					               tonumber(dark:sub(3, 4), 16) / 255,
+					               tonumber(dark:sub(5, 6), 16) / 255,
+					               tonumber(dark:sub(7, 8), 16) / 255)
+				end
+
 				data.attachmentName = getValue(slotMap, "attachment", nil)
 				data.blendMode = BlendMode[getValue(slotMap, "blend", "normal")]
 
@@ -380,6 +389,23 @@ function SkeletonJson.new (attachmentLoader)
 				               tonumber(color:sub(7, 8), 16) / 255)
 			end
 			return path;
+		
+		elseif type == AttachmentType.point then
+			local point = self.attachmentLoader:newPointAttachment(skin, name)
+			if not point then return nil end
+			point.x = getValue(map, "x", 0) * scale
+			point.y = getValue(map, "y", 0) * scale
+			point.rotation = getValue(map, "rotation", 0)
+			
+			local color = map.color
+			if color then
+				path.color:set(tonumber(color:sub(1, 2), 16) / 255,
+				               tonumber(color:sub(3, 4), 16) / 255,
+				               tonumber(color:sub(5, 6), 16) / 255,
+				               tonumber(color:sub(7, 8), 16) / 255)
+			end
+			return point
+		
 		end
 
 		error("Unknown attachment type: " .. type .. " (" .. name .. ")")

+ 5 - 1
spine-lua/Slot.lua

@@ -43,12 +43,15 @@ function Slot.new (data, bone)
 		data = data,
 		bone = bone,
 		color = Color.newWith(1, 1, 1, 1),
+		darkColor = nil,
 		attachment = nil,
 		attachmentTime = 0,
 		attachmentVertices = {},
 		attachmentVerticesCount = 0
-	}
+	}	
 	setmetatable(self, Slot)
+	
+	if data.darkColor then self.darkColor = Color.newWith(1, 1, 1, 1) end
 
 	self:setToSetupPose()
 
@@ -74,6 +77,7 @@ function Slot:setToSetupPose ()
 	local data = self.data
 
 	self.color:setFrom(data.color)
+	if self.darkColor then self.darkColor:setFrom(data.darkColor) end
 
 	local attachment = nil
 	if data.attachmentName then

+ 1 - 0
spine-lua/SlotData.lua

@@ -46,6 +46,7 @@ function SlotData.new (index, name, boneData)
 		name = name,
 		boneData = boneData,
 		color = Color.newWith(1, 1, 1, 1),
+		darkColor = nil,
 		attachmentName = nil,
 		blendMode = BlendMode.normal
 	}

+ 3 - 1
spine-lua/TransformConstraintData.lua

@@ -38,7 +38,9 @@ function TransformConstraintData.new (name)
 		bones = {},
 		target = nil,
 		rotateMix = 0, translateMix = 0, scaleMix = 0, shearMix = 0,
-		offsetRotation = 0, offsetX = 0, offsetY = 0, offsetScaleX = 0, offsetScaleY = 0, offsetShearY = 0
+		offsetRotation = 0, offsetX = 0, offsetY = 0, offsetScaleX = 0, offsetScaleY = 0, offsetShearY = 0,
+		relative = false,
+		local_ = false
 	}
 
 	return self

+ 2 - 1
spine-lua/attachments/AttachmentType.lua

@@ -33,6 +33,7 @@ local AttachmentType = {
 	boundingbox = 1,
 	mesh = 2,
 	linkedmesh = 3,
-	path = 4
+	path = 4,
+	point = 5
 }
 return AttachmentType

+ 12 - 131
spine-lua/attachments/MeshAttachment.lua

@@ -45,7 +45,7 @@ function MeshAttachment.new (name)
 	self.region = nil
 	self.path = nil
 	self.regionUVs = nil
-	self.worldVertices = nil
+	self.uvs = nil
 	self.triangles = nil
 	self.color = Color.newWith(1, 1, 1, 1)
 	self.hullLength = 0
@@ -57,13 +57,6 @@ function MeshAttachment.new (name)
 end
 
 function MeshAttachment:updateUVs ()
-	local regionUVs = self.regionUVs
-	local verticesLength = #regionUVs
-	local worldVerticesLength = (verticesLength / 2) * 8
-	if not self.worldVertices or #self.worldVertices ~= worldVerticesLength then
-		self.worldVertices = utils.newNumberArray(worldVerticesLength)
-	end
-
 	local u = 0
 	local v = 0
 	local width = 0
@@ -79,137 +72,26 @@ function MeshAttachment:updateUVs ()
 		width = self.region.u2 - u;
 		height = self.region.v2 - v;
 	end
+	local regionUVs = self.regionUVs
+	if not self.uvs or (#self.uvs ~= #regionUVs) then self.uvs = utils.newNumberArray(#regionUVs) end
+	local uvs = self.uvs
 	if self.region and self.region.rotate then
 		local i = 0
-		local w = 2
-		while i < verticesLength do
-			self.worldVertices[w + 1] = u + regionUVs[i + 2] * width;
-			self.worldVertices[w + 2] = v + height - regionUVs[i + 1] * height;
+		local n = #uvs
+		while i < n do
+			uvs[i + 1] = u + regionUVs[i + 2] * width;
+			uvs[i + 2] = v + height - regionUVs[i + 1] * height;
 			i = i + 2
-			w = w + 8
 		end
 	else
 		local i = 0
-		local w = 2
-		while i < verticesLength do
-			self.worldVertices[w + 1] = u + regionUVs[i + 1] * width;
-			self.worldVertices[w + 2] = v + regionUVs[i + 2] * height;
+		local n = #uvs
+		while i < n do
+			uvs[i + 1] = u + regionUVs[i + 1] * width;
+			uvs[i + 2] = v + regionUVs[i + 2] * height;
 			i = i + 2
-			w = w + 8
-		end
-	end
-end
-
-function MeshAttachment:updateWorldVertices(slot, premultipliedAlpha)
-	local skeleton = slot.bone.skeleton
-	local skeletonColor = skeleton.color
-	local slotColor = slot.color
-	local meshColor = self.color
-
-	local alpha = skeletonColor.a * slotColor.a * meshColor.a
-	local multiplier = 1
-	if premultipliedAlpha then multiplier = alpha end
-	local color = self.tempColor
-	color:set(skeletonColor.r * slotColor.r * meshColor.r * multiplier,
-		skeletonColor.g * slotColor.g * meshColor.g * multiplier,
-		skeletonColor.b * slotColor.b * meshColor.b * multiplier,
-		alpha)
-
-	local deformArray = slot.attachmentVertices
-	local vertices = self.vertices
-	local worldVertices = self.worldVertices
-	local bones = self.bones
-	if not bones then
-		local verticesLength = #vertices
-		if #deformArray > 0 then vertices = deformArray end
-		local bone = slot.bone;
-		local x = bone.worldX
-		local y = bone.worldY
-		local a = bone.a
-		local b = bone.b
-		local c = bone.c
-		local d = bone.d
-		local v = 0
-		local w = 0
-		while v < verticesLength do
-			local vx = vertices[v + 1]
-			local vy = vertices[v + 2]
-			worldVertices[w + 1] = vx * a + vy * b + x
-			worldVertices[w + 2] = vx * c + vy * d + y
-			worldVertices[w + 5] = color.r
-			worldVertices[w + 6] = color.g
-			worldVertices[w + 7] = color.b
-			worldVertices[w + 8] = color.a
-			v = v + 2
-			w = w + 8
-		end
-		return worldVertices
-	end
-
-	local skeletonBones = skeleton.bones
-	if #deformArray == 0 then
-		local w = 0
-		local v = 0
-		local b = 0
-		local n = #bones
-		while v < n do
-			local wx = 0
-			local wy = 0
-			local nn = bones[v + 1];
-			v = v + 1
-			nn = nn + v
-			while v < nn do
-				local bone = skeletonBones[bones[v + 1]];
-				local vx = vertices[b + 1]
-				local vy = vertices[b + 2]
-				local weight = vertices[b + 3]
-				wx = wx + (vx * bone.a + vy * bone.b + bone.worldX) * weight
-				wy = wy + (vx * bone.c + vy * bone.d + bone.worldY) * weight
-				v = v + 1
-				b = b + 3
-			end
-			worldVertices[w + 1] = wx
-			worldVertices[w + 2] = wy
-			worldVertices[w + 5] = color.r
-			worldVertices[w + 6] = color.g
-			worldVertices[w + 7] = color.b
-			worldVertices[w + 8] = color.a
-			w = w + 8
-		end
-	else
-		local deform = deformArray;
-		local w = 0
-		local v = 0
-		local b = 0
-		local f = 0
-		local n = #bones
-		while v < n do
-			local wx = 0
-			local wy = 0
-			local nn = bones[v + 1]
-			v = v + 1
-			nn = nn + v
-			while v < nn do
-				local bone = skeletonBones[bones[v + 1]];
-				local vx = vertices[b + 1] + deform[f + 1]
-				local vy = vertices[b + 2] + deform[f + 2]
-				local weight = vertices[b + 3]
-				wx = wx + (vx * bone.a + vy * bone.b + bone.worldX) * weight
-				wy = wy + (vx * bone.c + vy * bone.d + bone.worldY) * weight
-				b = b + 3
-				f = f + 2
-				v = v + 1
-			end
-			worldVertices[w + 1] = wx;
-			worldVertices[w + 2] = wy;
-			worldVertices[w + 5] = color.r;
-			worldVertices[w + 6] = color.g;
-			worldVertices[w + 7] = color.b;
-			worldVertices[w + 8] = color.a;
-			w = w + 8
 		end
 	end
-	return worldVertices;
 end
 
 function MeshAttachment:applyDeform (sourceAttachment)
@@ -224,7 +106,6 @@ function MeshAttachment:setParentMesh (parentMesh)
 		self.regionUVs = parentMesh.regionUVs
 		self.triangles = parentMesh.triangles
 		self.hullLength = parentMesh.hullLength
-    self.worldVerticesLength = parentMesh.worldVerticesLength
 	end
 end
 

+ 68 - 0
spine-lua/attachments/PointAttachment.lua

@@ -0,0 +1,68 @@
+-------------------------------------------------------------------------------
+-- Spine Runtimes Software License v2.5
+--
+-- Copyright (c) 2013-2016, Esoteric Software
+-- All rights reserved.
+--
+-- You are granted a perpetual, non-exclusive, non-sublicensable, and
+-- non-transferable license to use, install, execute, and perform the Spine
+-- Runtimes software and derivative works solely for personal or internal
+-- use. Without the written permission of Esoteric Software (see Section 2 of
+-- the Spine Software License Agreement), you may not (a) modify, translate,
+-- adapt, or develop new applications using the Spine Runtimes or otherwise
+-- create derivative works or improvements of the Spine Runtimes or (b) remove,
+-- delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+-- or other intellectual property or proprietary rights notices on or in the
+-- Software, including any copy thereof. Redistributions in binary or source
+-- form must include this license and terms.
+--
+-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
+-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+-- POSSIBILITY OF SUCH DAMAGE.
+-------------------------------------------------------------------------------
+
+local AttachmentType = require "spine-lua.attachments.AttachmentType"
+local VertexAttachment = require "spine-lua.attachments.VertexAttachment"
+local Color = require "spine-lua.Color"
+
+local math_cos = math.cos
+local math_sin = math.sin
+
+local PointAttachment = {}
+PointAttachment.__index = PointAttachment
+setmetatable(PointAttachment, { __index = VertexAttachment })
+
+function PointAttachment.new (name)
+	if not name then error("name cannot be nil", 2) end
+
+	local self = VertexAttachment.new(name, AttachmentType.point)
+	self.x = 0
+	self.y = 0
+	self.rotation = 0
+	self.color = Color.newWith(0.38, 0.94, 0, 1)
+	setmetatable(self, BoundingBoxAttachment)
+	return self
+end
+
+function PointAttachment:computeWorldPosition(bone, point)
+	point.x = self.x * bone.a + self.y * bone.b + bone.worldX
+	point.y = self.x * bone.c + self.y * bone.d + bone.worldY
+	return point
+end
+
+function PointAttachment:computeWorldRotation(bone)
+	local cos = math_cos(math_rad(self.rotation))
+	local sin = math_sin(math_rad(self.rotation))
+	local x = cos * bone.a + sin * bone.b
+	local y = cos * bone.c + sin * bone.d
+	return math_deg(math_atan2(y, x))
+end
+
+return PointAttachment

+ 94 - 78
spine-lua/attachments/RegionAttachment.lua

@@ -86,6 +86,51 @@ local C4A = 32
 local RegionAttachment = {}
 RegionAttachment.__index = RegionAttachment
 setmetatable(RegionAttachment, { __index = Attachment })
+ 
+RegionAttachment.OX1 = 1
+RegionAttachment.OY1 = 2
+RegionAttachment.OX2 = 3
+RegionAttachment.OY2 = 4
+RegionAttachment.OX3 = 5
+RegionAttachment.OY3 = 6
+RegionAttachment.OX4 = 7
+RegionAttachment.OY4 = 8
+
+RegionAttachment.X1 = 1
+RegionAttachment.Y1 = 2
+RegionAttachment.U1 = 3
+RegionAttachment.V1 = 4
+RegionAttachment.C1R = 5
+RegionAttachment.C1G = 6
+RegionAttachment.C1B = 7
+RegionAttachment.C1A = 8
+
+RegionAttachment.X2 = 9
+RegionAttachment.Y2 = 10
+RegionAttachment.U2 = 11
+RegionAttachment.V2 = 12
+RegionAttachment.C2R = 13
+RegionAttachment.C2G = 14
+RegionAttachment.C2B = 15
+RegionAttachment.C2A = 16
+
+RegionAttachment.X3 = 17
+RegionAttachment.Y3 = 18
+RegionAttachment.U3 = 19
+RegionAttachment.V3 = 20
+RegionAttachment.C3R = 21
+RegionAttachment.C3G = 22
+RegionAttachment.C3B = 23
+RegionAttachment.C3A = 24
+
+RegionAttachment.X4 = 25
+RegionAttachment.Y4 = 26
+RegionAttachment.U4 = 27
+RegionAttachment.V4 = 28
+RegionAttachment.C4R = 29
+RegionAttachment.C4G = 30
+RegionAttachment.C4B = 31
+RegionAttachment.C4A = 32
 
 function RegionAttachment.new (name)
 	if not name then error("name cannot be nil", 2) end
@@ -103,36 +148,13 @@ function RegionAttachment.new (name)
 	self.rendererObject = nil
 	self.region = nil
 	self.offset = Utils.newNumberArray(8)
-	self.vertices = Utils.newNumberArray(8 * 4)
+	self.uvs = Utils.newNumberArray(8)
 	self.tempColor = Color.newWith(1, 1, 1, 1)
 	setmetatable(self, RegionAttachment)
 
 	return self
 end
 
-function RegionAttachment:setRegion (region)
-	local vertices = self.vertices
-	if region.rotate then
-		vertices[U2] = region.u
-		vertices[V2] = region.v2
-		vertices[U3] = region.u
-		vertices[V3] = region.v
-		vertices[U4] = region.u2
-		vertices[V4] = region.v
-		vertices[U1] = region.u2
-		vertices[V1] = region.v2
-	else
-		vertices[U1] = region.u
-		vertices[V1] = region.v2
-		vertices[U2] = region.u
-		vertices[V2] = region.v
-		vertices[U3] = region.u2
-		vertices[V3] = region.v
-		vertices[U4] = region.u2
-		vertices[V4] = region.v2
-	end
-end
-
 function RegionAttachment:updateOffset ()
 	local regionScaleX = self.width / self.region.originalWidth * self.scaleX
 	local regionScaleY = self.height / self.region.originalHeight * self.scaleY
@@ -162,23 +184,32 @@ function RegionAttachment:updateOffset ()
 	offset[OY4] = localYCos + localX2Sin
 end
 
-function RegionAttachment:updateWorldVertices (slot, premultipliedAlpha)
-	local skeleton = slot.bone.skeleton
-	local skeletonColor = skeleton.color
-	local slotColor = slot.color
-	local regionColor = self.color
-	local alpha = skeletonColor.a * slotColor.a * regionColor.a
-	local multiplier = alpha
-	if premultipliedAlpha then multiplier = 1 end
-	local color = self.tempColor
-	color:set(skeletonColor.r * slotColor.r * regionColor.r * multiplier,
-		skeletonColor.g * slotColor.g * regionColor.g * multiplier,
-		skeletonColor.b * slotColor.b * regionColor.b * multiplier,
-		alpha)
-
-	local vertices = self.vertices
-	local offset = self.offset
-	local bone = slot.bone
+function RegionAttachment:setRegion (region)
+	local uvs = self.uvs
+	if region.rotate then
+		uvs[3] = region.u
+		uvs[4] = region.v2
+		uvs[5] = region.u
+		uvs[6] = region.v
+		uvs[7] = region.u2
+		uvs[8] = region.v
+		uvs[1] = region.u2
+		uvs[2] = region.v2
+	else
+		uvs[1] = region.u
+		uvs[2] = region.v2
+		uvs[3] = region.u
+		uvs[4] = region.v
+		uvs[5] = region.u2
+		uvs[6] = region.v
+		uvs[7] = region.u2
+		uvs[8] = region.v2
+	end
+end
+
+function RegionAttachment:computeWorldVertices (bone, worldVertices, offset, stride)
+	offset = offset + 1
+	local vertexOffset = self.offset
 	local x = bone.worldX
 	local y = bone.worldY
 	local a = bone.a
@@ -188,43 +219,28 @@ function RegionAttachment:updateWorldVertices (slot, premultipliedAlpha)
 	local offsetX = 0
 	local offsetY = 0
 
-	offsetX = offset[OX1]
-	offsetY = offset[OY1]
-	vertices[X1] = offsetX * a + offsetY * b + x -- br
-	vertices[Y1] = offsetX * c + offsetY * d + y
-	vertices[C1R] = color.r
-	vertices[C1G] = color.g
-	vertices[C1B] = color.b
-	vertices[C1A] = color.a
-
-	offsetX = offset[OX2]
-	offsetY = offset[OY2]
-	vertices[X2] = offsetX * a + offsetY * b + x -- bl
-	vertices[Y2] = offsetX * c + offsetY * d + y
-	vertices[C2R] = color.r
-	vertices[C2G] = color.g
-	vertices[C2B] = color.b
-	vertices[C2A] = color.a
-
-	offsetX = offset[OX3]
-	offsetY = offset[OY3]
-	vertices[X3] = offsetX * a + offsetY * b + x -- ul
-	vertices[Y3] = offsetX * c + offsetY * d + y
-	vertices[C3R] = color.r
-	vertices[C3G] = color.g
-	vertices[C3B] = color.b
-	vertices[C3A] = color.a
-
-	offsetX = offset[OX4]
-	offsetY = offset[OY4]
-	vertices[X4] = offsetX * a + offsetY * b + x -- ur
-	vertices[Y4] = offsetX * c + offsetY * d + y
-	vertices[C4R] = color.r
-	vertices[C4G] = color.g
-	vertices[C4B] = color.b
-	vertices[C4A] = color.a
-
-	return vertices
+	offsetX = vertexOffset[OX1]
+	offsetY = vertexOffset[OY1]
+	worldVertices[offset] = offsetX * a + offsetY * b + x -- br
+	worldVertices[offset + 1] = offsetX * c + offsetY * d + y
+	offset = offset + stride
+
+	offsetX = vertexOffset[OX2]
+	offsetY = vertexOffset[OY2]
+	worldVertices[offset] = offsetX * a + offsetY * b + x -- bl
+	worldVertices[offset + 1] = offsetX * c + offsetY * d + y
+	offset = offset + stride
+
+	offsetX = vertexOffset[OX3]
+	offsetY = vertexOffset[OY3]
+	worldVertices[offset] = offsetX * a + offsetY * b + x -- ul
+	worldVertices[offset + 1] = offsetX * c + offsetY * d + y
+	offset = offset + stride
+
+	offsetX = vertexOffset[OX4]
+	offsetY = vertexOffset[OY4]
+	worldVertices[offset] = offsetX * a + offsetY * b + x -- ur
+	worldVertices[offset + 1] = offsetX * c + offsetY * d + y
 end
 
 return RegionAttachment

+ 5 - 9
spine-lua/attachments/VertexAttachment.lua

@@ -50,12 +50,8 @@ function VertexAttachment.new (name, attachmentType)
 	return self
 end
 
-function VertexAttachment:computeWorldVertices (slot, worldVertices)
-	self:computeWorldVerticesWith(slot, 0, self.worldVerticesLength, worldVertices, 0)
-end
-
-function VertexAttachment:computeWorldVerticesWith (slot, start, count, worldVertices, offset)
-	count = count + offset
+function VertexAttachment:computeWorldVertices (slot, start, count, worldVertices, offset, stride)
+	count = offset + (count / 2) * stride
 	local skeleton = slot.bone.skeleton
 	local deformArray = slot.attachmentVertices
 	local vertices = self.vertices
@@ -77,7 +73,7 @@ function VertexAttachment:computeWorldVerticesWith (slot, start, count, worldVer
 			worldVertices[w + 1] = vx * a + vy * b + x
 			worldVertices[w + 2] = vx * c + vy * d + y
 			v = v + 2
-			w = w + 2
+			w = w + stride
 		end
 		return
 	end
@@ -112,7 +108,7 @@ function VertexAttachment:computeWorldVerticesWith (slot, start, count, worldVer
 			end
 			worldVertices[w + 1] = wx
 			worldVertices[w + 2] = wy
-			w = w + 2
+			w = w + stride
 		end
 	else
 		local deform = deformArray
@@ -139,7 +135,7 @@ function VertexAttachment:computeWorldVerticesWith (slot, start, count, worldVer
 			end
 			worldVertices[w + 1] = wx
 			worldVertices[w + 2] = wy
-			w = w + 2
+			w = w + stride
 		end
 	end
 end