mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-22 02:06:03 +08:00
Meshes, FFD and skinning for spine-lua.
This commit is contained in:
parent
c1a9b502bd
commit
81ae526a7b
@ -12,8 +12,8 @@ function skeleton:createImage (attachment)
|
|||||||
-- Customize where images are loaded.
|
-- Customize where images are loaded.
|
||||||
return display.newImage("examples/spineboy/images/" .. attachment.name .. ".png")
|
return display.newImage("examples/spineboy/images/" .. attachment.name .. ".png")
|
||||||
end
|
end
|
||||||
skeleton.group.x = 150
|
skeleton.group.x = display.contentWidth * 0.5
|
||||||
skeleton.group.y = 325
|
skeleton.group.y = display.contentHeight * 0.9
|
||||||
skeleton.flipX = false
|
skeleton.flipX = false
|
||||||
skeleton.flipY = false
|
skeleton.flipY = false
|
||||||
skeleton.debug = true -- Omit or set to false to not draw debug lines on top of the images.
|
skeleton.debug = true -- Omit or set to false to not draw debug lines on top of the images.
|
||||||
|
|||||||
@ -37,6 +37,8 @@ spine.BoneData = require "spine-lua.BoneData"
|
|||||||
spine.SlotData = require "spine-lua.SlotData"
|
spine.SlotData = require "spine-lua.SlotData"
|
||||||
spine.Skin = require "spine-lua.Skin"
|
spine.Skin = require "spine-lua.Skin"
|
||||||
spine.RegionAttachment = require "spine-lua.RegionAttachment"
|
spine.RegionAttachment = require "spine-lua.RegionAttachment"
|
||||||
|
spine.MeshAttachment = require "spine-lua.MeshAttachment"
|
||||||
|
spine.SkinnedMeshAttachment = require "spine-lua.SkinnedMeshAttachment"
|
||||||
spine.Skeleton = require "spine-lua.Skeleton"
|
spine.Skeleton = require "spine-lua.Skeleton"
|
||||||
spine.Bone = require "spine-lua.Bone"
|
spine.Bone = require "spine-lua.Bone"
|
||||||
spine.Slot = require "spine-lua.Slot"
|
spine.Slot = require "spine-lua.Slot"
|
||||||
|
|||||||
@ -356,17 +356,13 @@ function Animation.ColorTimeline.new ()
|
|||||||
local frames = self.frames
|
local frames = self.frames
|
||||||
if time < frames[0] then return end -- Time is before first frame.
|
if time < frames[0] then return end -- Time is before first frame.
|
||||||
|
|
||||||
local slot = skeleton.slots[self.slotIndex]
|
local r, g, b, a
|
||||||
|
|
||||||
if time >= frames[#frames - 4] then -- Time is after last frame.
|
if time >= frames[#frames - 4] then -- Time is after last frame.
|
||||||
local r = frames[#frames - 3]
|
r = frames[#frames - 3]
|
||||||
local g = frames[#frames - 2]
|
g = frames[#frames - 2]
|
||||||
local b = frames[#frames - 1]
|
b = frames[#frames - 1]
|
||||||
local a = frames[#frames]
|
a = frames[#frames]
|
||||||
slot:setColor(r, g, b, a)
|
else
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Interpolate between the last frame and the current frame.
|
-- Interpolate between the last frame and the current frame.
|
||||||
local frameIndex = binarySearch(frames, time, 5)
|
local frameIndex = binarySearch(frames, time, 5)
|
||||||
local lastFrameR = frames[frameIndex - 4]
|
local lastFrameR = frames[frameIndex - 4]
|
||||||
@ -378,10 +374,12 @@ function Animation.ColorTimeline.new ()
|
|||||||
if percent < 0 then percent = 0 elseif percent > 255 then percent = 255 end
|
if percent < 0 then percent = 0 elseif percent > 255 then percent = 255 end
|
||||||
percent = self:getCurvePercent(frameIndex / 5 - 1, percent)
|
percent = self:getCurvePercent(frameIndex / 5 - 1, percent)
|
||||||
|
|
||||||
local r = lastFrameR + (frames[frameIndex + FRAME_R] - lastFrameR) * percent
|
r = lastFrameR + (frames[frameIndex + FRAME_R] - lastFrameR) * percent
|
||||||
local g = lastFrameG + (frames[frameIndex + FRAME_G] - lastFrameG) * percent
|
g = lastFrameG + (frames[frameIndex + FRAME_G] - lastFrameG) * percent
|
||||||
local b = lastFrameB + (frames[frameIndex + FRAME_B] - lastFrameB) * percent
|
b = lastFrameB + (frames[frameIndex + FRAME_B] - lastFrameB) * percent
|
||||||
local a = lastFrameA + (frames[frameIndex + FRAME_A] - lastFrameA) * percent
|
a = lastFrameA + (frames[frameIndex + FRAME_A] - lastFrameA) * percent
|
||||||
|
end
|
||||||
|
local slot = skeleton.slots[self.slotIndex]
|
||||||
if alpha < 1 then
|
if alpha < 1 then
|
||||||
slot:setColor(slot.r + (r - slot.r) * alpha, slot.g + (g - slot.g) * alpha, slot.b + (b - slot.b) * alpha, slot.a + (a - slot.a) * alpha)
|
slot:setColor(slot.r + (r - slot.r) * alpha, slot.g + (g - slot.g) * alpha, slot.b + (b - slot.b) * alpha, slot.a + (a - slot.a) * alpha)
|
||||||
else
|
else
|
||||||
|
|||||||
@ -75,11 +75,11 @@ function AnimationState.new (data)
|
|||||||
for i = 0, self.trackCount do
|
for i = 0, self.trackCount do
|
||||||
local current = self.tracks[i]
|
local current = self.tracks[i]
|
||||||
if current then
|
if current then
|
||||||
local trackDelta = delta * current.timeScale
|
current.time = current.time + delta * current.timeScale
|
||||||
current.time = current.time + trackDelta
|
|
||||||
if current.previous then
|
if current.previous then
|
||||||
current.previous.time = current.previous.time + trackDelta
|
local previousDelta = delta * current.previous.timeScale
|
||||||
current.mixTime = current.mixTime + trackDelta
|
current.previous.time = current.previous.time + previousDelta
|
||||||
|
current.mixTime = current.mixTime + previousDelta
|
||||||
end
|
end
|
||||||
|
|
||||||
local next = current.next
|
local next = current.next
|
||||||
|
|||||||
@ -34,8 +34,8 @@ function AnimationStateData.new (skeletonData)
|
|||||||
if not skeletonData then error("skeletonData cannot be nil", 2) end
|
if not skeletonData then error("skeletonData cannot be nil", 2) end
|
||||||
|
|
||||||
local self = {
|
local self = {
|
||||||
animationToMixTime = {},
|
|
||||||
skeletonData = skeletonData,
|
skeletonData = skeletonData,
|
||||||
|
animationToMixTime = {},
|
||||||
defaultMix = 0
|
defaultMix = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -32,20 +32,24 @@ local AttachmentType = require "spine-lua.AttachmentType"
|
|||||||
local RegionAttachment = require "spine-lua.RegionAttachment"
|
local RegionAttachment = require "spine-lua.RegionAttachment"
|
||||||
local BoundingBoxAttachment = require "spine-lua.BoundingBoxAttachment"
|
local BoundingBoxAttachment = require "spine-lua.BoundingBoxAttachment"
|
||||||
|
|
||||||
local AttachmentLoader = {
|
local AttachmentLoader = {}
|
||||||
failed = {}
|
|
||||||
}
|
|
||||||
function AttachmentLoader.new ()
|
function AttachmentLoader.new ()
|
||||||
local self = {}
|
local self = {}
|
||||||
|
|
||||||
function self:newAttachment (type, name)
|
function self:newRegionAttachment (skin, name, path)
|
||||||
if type == AttachmentType.region then
|
|
||||||
return RegionAttachment.new(name)
|
return RegionAttachment.new(name)
|
||||||
end
|
end
|
||||||
if type == AttachmentType.boundingbox then
|
|
||||||
return BoundingBoxAttachment.new(name)
|
function self:newMeshAttachment (skin, name, path)
|
||||||
|
return MeshAttachment.new(name)
|
||||||
end
|
end
|
||||||
error("Unknown attachment type: " .. type .. " (" .. name .. ")")
|
|
||||||
|
function self:newSkinningMeshAttachment (skin, name, path)
|
||||||
|
return SkinningMeshAttachment.new(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
function self:newBoundingBoxAttachment (skin, name)
|
||||||
|
return BoundingBoxAttachment.new(name)
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|||||||
@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
local AttachmentType = {
|
local AttachmentType = {
|
||||||
region = 0,
|
region = 0,
|
||||||
boundingbox = 1
|
boundingbox = 1,
|
||||||
|
mesh = 2,
|
||||||
|
skinnedmesh = 3
|
||||||
}
|
}
|
||||||
return AttachmentType
|
return AttachmentType
|
||||||
|
|||||||
93
spine-lua/MeshAttachment.lua
Normal file
93
spine-lua/MeshAttachment.lua
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Spine Runtimes Software License
|
||||||
|
-- Version 2.1
|
||||||
|
--
|
||||||
|
-- Copyright (c) 2013, Esoteric Software
|
||||||
|
-- All rights reserved.
|
||||||
|
--
|
||||||
|
-- You are granted a perpetual, non-exclusive, non-sublicensable and
|
||||||
|
-- non-transferable license to install, execute and perform the Spine Runtimes
|
||||||
|
-- Software (the "Software") solely for internal use. Without the written
|
||||||
|
-- permission of Esoteric Software (typically granted by licensing Spine), you
|
||||||
|
-- may not (a) modify, translate, adapt or otherwise create derivative works,
|
||||||
|
-- improvements of the Software or develop new applications using the Software
|
||||||
|
-- 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 SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
-- OR BUSINESS INTERRUPTION) 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.AttachmentType"
|
||||||
|
|
||||||
|
local MeshAttachment = {}
|
||||||
|
function MeshAttachment.new (name)
|
||||||
|
if not name then error("name cannot be nil", 2) end
|
||||||
|
|
||||||
|
local self = {
|
||||||
|
name = name,
|
||||||
|
type = AttachmentType.mesh,
|
||||||
|
vertices = nil,
|
||||||
|
uvs = nil,
|
||||||
|
regionUVs = nil,
|
||||||
|
triangles = nil,
|
||||||
|
hullLength = 0,
|
||||||
|
r = 1, g = 1, b = 1, a = 1,
|
||||||
|
path = nil,
|
||||||
|
rendererObject = nil,
|
||||||
|
regionU = 0, regionV = 0, regionU2 = 0, regionV2 = 0, regionRotate = false,
|
||||||
|
regionOffsetX = 0, regionOffsetY = 0,
|
||||||
|
regionWidth = 0, regionHeight = 0,
|
||||||
|
regionOriginalWidth = 0, regionOriginalHeight = 0,
|
||||||
|
edges = nil,
|
||||||
|
width = 0, height = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function self:updateUVs ()
|
||||||
|
local width, height = self.regionU2 - self.regionU, self.regionV2 - self.regionV
|
||||||
|
local n = #self.regionUVs
|
||||||
|
if not self.uvs or #self.uvs ~= n then
|
||||||
|
self.uvs = {}
|
||||||
|
end
|
||||||
|
if self.regionRotate then
|
||||||
|
for i = 1, n, 2 do
|
||||||
|
self.uvs[i] = self.regionU + self.regionUVs[i + 1] * width
|
||||||
|
self.uvs[i + 1] = self.regionV + height - self.regionUVs[i] * height
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for i = 1, n, 2 do
|
||||||
|
self.uvs[i] = self.regionU + self.regionUVs[i] * width
|
||||||
|
self.uvs[i + 1] = self.regionV + self.regionUVs[i + 1] * height
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function self:computeWorldVertices (x, y, slot, worldVertices)
|
||||||
|
local bone = slot.bone
|
||||||
|
x = x + bone.worldX
|
||||||
|
y = y + bone.worldY
|
||||||
|
local m00, m01, m10, m11 = bone.m00, bone.m01, bone.m10, bone.m11
|
||||||
|
local vertices = self.vertices
|
||||||
|
local verticesCount = vertices.length
|
||||||
|
if #slot.attachmentVertices == verticesCount then vertices = slot.attachmentVertices end
|
||||||
|
for i = 1, verticesCount, 2 do
|
||||||
|
local vx = vertices[i]
|
||||||
|
local vy = vertices[i + 1]
|
||||||
|
worldVertices[i] = vx * m00 + vy * m01 + x
|
||||||
|
worldVertices[i + 1] = vx * m10 + vy * m11 + y
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
return MeshAttachment
|
||||||
@ -36,9 +36,65 @@ function RegionAttachment.new (name)
|
|||||||
|
|
||||||
local self = {
|
local self = {
|
||||||
name = name,
|
name = name,
|
||||||
type = AttachmentType.region
|
type = AttachmentType.region,
|
||||||
|
x = 0, y = 0,
|
||||||
|
rotation = 0,
|
||||||
|
scaleX = 1, scaleY = 1,
|
||||||
|
width = 0, height = 0,
|
||||||
|
offset = {},
|
||||||
|
uvs = {},
|
||||||
|
r = 1, g = 1, b = 1, a = 1,
|
||||||
|
path = null,
|
||||||
|
rendererObject = null,
|
||||||
|
regionOffsetX = 0, regionOffsetY = 0,
|
||||||
|
regionWidth = 0, regionHeight = 0,
|
||||||
|
regionOriginalWidth = 0, regionOriginalHeight = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function self:updateOffset ()
|
||||||
|
local regionScaleX = self.width / self.regionOriginalWidth * self.scaleX
|
||||||
|
local regionScaleY = self.height / self.regionOriginalHeight * self.scaleY
|
||||||
|
local localX = -self.width / 2 * self.scaleX + self.regionOffsetX * regionScaleX
|
||||||
|
local localY = -self.height / 2 * self.scaleY + self.regionOffsetY * regionScaleY
|
||||||
|
local localX2 = localX + self.regionWidth * regionScaleX
|
||||||
|
local localY2 = localY + self.regionHeight * regionScaleY
|
||||||
|
local radians = self.rotation * math.pi / 180
|
||||||
|
local cos = math.cos(radians)
|
||||||
|
local sin = math.sin(radians)
|
||||||
|
local localXCos = localX * cos + self.x
|
||||||
|
local localXSin = localX * sin
|
||||||
|
local localYCos = localY * cos + self.y
|
||||||
|
local localYSin = localY * sin
|
||||||
|
local localX2Cos = localX2 * cos + self.x
|
||||||
|
local localX2Sin = localX2 * sin
|
||||||
|
local localY2Cos = localY2 * cos + self.y
|
||||||
|
local localY2Sin = localY2 * sin
|
||||||
|
local offset = self.offset
|
||||||
|
offset[0] = localXCos - localYSin -- X1
|
||||||
|
offset[1] = localYCos + localXSin -- Y1
|
||||||
|
offset[2] = localXCos - localY2Sin -- X2
|
||||||
|
offset[3] = localY2Cos + localXSin -- Y2
|
||||||
|
offset[4] = localX2Cos - localY2Sin -- X3
|
||||||
|
offset[5] = localY2Cos + localX2Sin -- Y3
|
||||||
|
offset[6] = localX2Cos - localYSin -- X4
|
||||||
|
offset[7] = localYCos + localX2Sin -- Y4
|
||||||
|
end
|
||||||
|
|
||||||
|
function self:computeWorldVertices (x, y, bone, worldVertices)
|
||||||
|
x = x + bone.worldX
|
||||||
|
y = y + bone.worldY
|
||||||
|
local m00, m01, m10, m11 = bone.m00, bone.m01, bone.m10, bone.m11
|
||||||
|
local offset = self.offset
|
||||||
|
vertices[0] = offset[0] * m00 + offset[1] * m01 + x
|
||||||
|
vertices[1] = offset[0] * m10 + offset[1] * m11 + y
|
||||||
|
vertices[2] = offset[2] * m00 + offset[3] * m01 + x
|
||||||
|
vertices[3] = offset[2] * m10 + offset[3] * m11 + y
|
||||||
|
vertices[4] = offset[4] * m00 + offset[5] * m01 + x
|
||||||
|
vertices[5] = offset[4] * m10 + offset[5] * m11 + y
|
||||||
|
vertices[6] = offset[6] * m00 + offset[7] * m01 + x
|
||||||
|
vertices[7] = offset[6] * m10 + offset[7] * m11 + y
|
||||||
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
return RegionAttachment
|
return RegionAttachment
|
||||||
|
|||||||
@ -43,7 +43,10 @@ function Skeleton.new (skeletonData)
|
|||||||
slotsByName = {},
|
slotsByName = {},
|
||||||
drawOrder = {},
|
drawOrder = {},
|
||||||
r = 1, g = 1, b = 1, a = 1,
|
r = 1, g = 1, b = 1, a = 1,
|
||||||
x = 0, y = 0
|
x = 0, y = 0,
|
||||||
|
skin = nil,
|
||||||
|
flipX = false, flipY = false,
|
||||||
|
time = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
function self:updateWorldTransform ()
|
function self:updateWorldTransform ()
|
||||||
@ -65,6 +68,7 @@ function Skeleton.new (skeletonData)
|
|||||||
|
|
||||||
function self:setSlotsToSetupPose ()
|
function self:setSlotsToSetupPose ()
|
||||||
for i,slot in ipairs(self.slots) do
|
for i,slot in ipairs(self.slots) do
|
||||||
|
self.drawOrder[i] = slot
|
||||||
slot:setToSetupPose()
|
slot:setToSetupPose()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -90,7 +94,7 @@ function Skeleton.new (skeletonData)
|
|||||||
local newSkin
|
local newSkin
|
||||||
if skinName then
|
if skinName then
|
||||||
newSkin = self.data:findSkin(skinName)
|
newSkin = self.data:findSkin(skinName)
|
||||||
if not newSkin then error("Skin not found: " .. skinName, 2) end
|
if not newSkin then error("Skin not found = " .. skinName, 2) end
|
||||||
if self.skin then
|
if self.skin then
|
||||||
-- Attach all attachments from the new skin if the corresponding attachment from the old skin is currently attached.
|
-- Attach all attachments from the new skin if the corresponding attachment from the old skin is currently attached.
|
||||||
for k,v in pairs(self.skin.attachments) do
|
for k,v in pairs(self.skin.attachments) do
|
||||||
@ -103,6 +107,15 @@ function Skeleton.new (skeletonData)
|
|||||||
if newAttachment then slot:setAttachment(newAttachment) end
|
if newAttachment then slot:setAttachment(newAttachment) end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
-- No previous skin, attach setup pose attachments.
|
||||||
|
for i,slot in ipairs(self.slots) do
|
||||||
|
local name = slot.data.attachmentName
|
||||||
|
if name then
|
||||||
|
local attachment = newSkin:getAttachment(i, name)
|
||||||
|
if attachment then slot:setAttachment(attachment) end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self.skin = newSkin
|
self.skin = newSkin
|
||||||
@ -112,7 +125,7 @@ function Skeleton.new (skeletonData)
|
|||||||
if not slotName then error("slotName cannot be nil.", 2) end
|
if not slotName then error("slotName cannot be nil.", 2) end
|
||||||
if not attachmentName then error("attachmentName cannot be nil.", 2) end
|
if not attachmentName then error("attachmentName cannot be nil.", 2) end
|
||||||
local slotIndex = skeletonData.slotNameIndices[slotName]
|
local slotIndex = skeletonData.slotNameIndices[slotName]
|
||||||
if slotIndex == -1 then error("Slot not found: " .. slotName, 2) end
|
if slotIndex == -1 then error("Slot not found = " .. slotName, 2) end
|
||||||
if self.skin then
|
if self.skin then
|
||||||
local attachment = self.skin:getAttachment(slotIndex, attachmentName)
|
local attachment = self.skin:getAttachment(slotIndex, attachmentName)
|
||||||
if attachment then return attachment end
|
if attachment then return attachment end
|
||||||
@ -135,13 +148,20 @@ function Skeleton.new (skeletonData)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
error("Slot not found: " .. slotName, 2)
|
error("Slot not found = " .. slotName, 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
function self:update (delta)
|
function self:update (delta)
|
||||||
self.time = self.time + delta
|
self.time = self.time + delta
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function self:setColor (r, g, b, a)
|
||||||
|
self.r = r
|
||||||
|
self.g = g
|
||||||
|
self.b = b
|
||||||
|
self.a = a
|
||||||
|
end
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@ -36,7 +36,8 @@ function SkeletonData.new ()
|
|||||||
slotNameIndices = {},
|
slotNameIndices = {},
|
||||||
skins = {},
|
skins = {},
|
||||||
events = {},
|
events = {},
|
||||||
animations = {}
|
animations = {},
|
||||||
|
defaultSkin = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
function self:findBone (boneName)
|
function self:findBone (boneName)
|
||||||
|
|||||||
@ -75,8 +75,16 @@ function SkeletonJson.new (attachmentLoader)
|
|||||||
boneData.x = (boneMap["x"] or 0) * self.scale
|
boneData.x = (boneMap["x"] or 0) * self.scale
|
||||||
boneData.y = (boneMap["y"] or 0) * self.scale
|
boneData.y = (boneMap["y"] or 0) * self.scale
|
||||||
boneData.rotation = (boneMap["rotation"] or 0)
|
boneData.rotation = (boneMap["rotation"] or 0)
|
||||||
boneData.scaleX = (boneMap["scaleX"] or 1)
|
if boneMap["scaleX"] ~= nil then
|
||||||
boneData.scaleY = (boneMap["scaleY"] or 1)
|
boneData.scaleX = boneMap["scaleX"]
|
||||||
|
else
|
||||||
|
boneData.scaleX = 1
|
||||||
|
end
|
||||||
|
if boneMap["scaleY"] ~= nil then
|
||||||
|
boneData.scaleY = boneMap["scaleY"]
|
||||||
|
else
|
||||||
|
boneData.scaleY = 1
|
||||||
|
end
|
||||||
if boneMap["inheritScale"] == false then
|
if boneMap["inheritScale"] == false then
|
||||||
boneData.inheritScale = false
|
boneData.inheritScale = false
|
||||||
else
|
else
|
||||||
@ -124,7 +132,7 @@ function SkeletonJson.new (attachmentLoader)
|
|||||||
for slotName,slotMap in pairs(skinMap) do
|
for slotName,slotMap in pairs(skinMap) do
|
||||||
local slotIndex = skeletonData.slotNameIndices[slotName]
|
local slotIndex = skeletonData.slotNameIndices[slotName]
|
||||||
for attachmentName,attachmentMap in pairs(slotMap) do
|
for attachmentName,attachmentMap in pairs(slotMap) do
|
||||||
local attachment = readAttachment(attachmentName, attachmentMap, self.scale)
|
local attachment = readAttachment(attachmentName, attachmentMap)
|
||||||
if attachment then
|
if attachment then
|
||||||
skin:addAttachment(slotIndex, attachmentName, attachment)
|
skin:addAttachment(slotIndex, attachmentName, attachment)
|
||||||
end
|
end
|
||||||
@ -159,35 +167,171 @@ function SkeletonJson.new (attachmentLoader)
|
|||||||
return skeletonData
|
return skeletonData
|
||||||
end
|
end
|
||||||
|
|
||||||
readAttachment = function (name, map, scale)
|
readAttachment = function (name, map)
|
||||||
name = map["name"] or name
|
name = map["name"] or name
|
||||||
local attachment
|
|
||||||
local type = AttachmentType[map["type"] or "region"]
|
|
||||||
attachment = attachmentLoader:newAttachment(type, name)
|
|
||||||
if not attachment then return nil end
|
|
||||||
|
|
||||||
|
local type = AttachmentType[map["type"] or "region"]
|
||||||
|
local path = map["path"] or name
|
||||||
|
|
||||||
|
local scale = self.scale
|
||||||
if type == AttachmentType.region then
|
if type == AttachmentType.region then
|
||||||
attachment.x = (map["x"] or 0) * scale
|
local region = attachmentLoader:newRegionAttachment(type, name, path)
|
||||||
attachment.y = (map["y"] or 0) * scale
|
if not region then return nil end
|
||||||
attachment.scaleX = (map["scaleX"] or 1)
|
region.x = (map["x"] or 0) * scale
|
||||||
attachment.scaleY = (map["scaleY"] or 1)
|
region.y = (map["y"] or 0) * scale
|
||||||
attachment.rotation = (map["rotation"] or 0)
|
if map["scaleX"] ~= nil then
|
||||||
attachment.width = map["width"] * scale
|
region.scaleX = map["scaleX"]
|
||||||
attachment.height = map["height"] * scale
|
else
|
||||||
|
region.scaleX = 1
|
||||||
|
end
|
||||||
|
if map["scaleY"] ~= nil then
|
||||||
|
region.scaleY = map["scaleY"]
|
||||||
|
else
|
||||||
|
region.scaleY = 1
|
||||||
|
end
|
||||||
|
region.rotation = (map["rotation"] or 0)
|
||||||
|
region.width = map["width"] * scale
|
||||||
|
region.height = map["height"] * scale
|
||||||
|
|
||||||
|
local color = map["color"]
|
||||||
|
if color then
|
||||||
|
region.r = tonumber(color:sub(1, 2), 16) / 255
|
||||||
|
region.g = tonumber(color:sub(3, 4), 16) / 255
|
||||||
|
region.b = tonumber(color:sub(5, 6), 16) / 255
|
||||||
|
region.a = tonumber(color:sub(7, 8), 16) / 255
|
||||||
|
end
|
||||||
|
|
||||||
|
region:updateOffset()
|
||||||
|
return region
|
||||||
|
|
||||||
|
elseif type == AttachmentType.mesh then
|
||||||
|
local mesh = attachmentLoader:newMeshAttachment(skin, name, path)
|
||||||
|
if not mesh then return null end
|
||||||
|
mesh.path = path
|
||||||
|
mesh.vertices = getFloatArray(map, "vertices", scale)
|
||||||
|
mesh.triangles = getIntArray(map, "triangles")
|
||||||
|
mesh.regionUVs = getFloatArray(map, "uvs", 1)
|
||||||
|
mesh:updateUVs()
|
||||||
|
|
||||||
|
local color = map["color"]
|
||||||
|
if color then
|
||||||
|
mesh.r = tonumber(color:sub(1, 2), 16) / 255
|
||||||
|
mesh.g = tonumber(color:sub(3, 4), 16) / 255
|
||||||
|
mesh.b = tonumber(color:sub(5, 6), 16) / 255
|
||||||
|
mesh.a = tonumber(color:sub(7, 8), 16) / 255
|
||||||
|
end
|
||||||
|
|
||||||
|
mesh.hullLength = (map["hull"] or 0) * 2
|
||||||
|
if map["edges"] then mesh.edges = getIntArray(map, "edges") end
|
||||||
|
mesh.width = (map["width"] or 0) * scale
|
||||||
|
mesh.height = (map["height"] or 0) * scale
|
||||||
|
return mesh
|
||||||
|
|
||||||
|
elseif type == AttachmentType.skinnedmesh then
|
||||||
|
local mesh = self.attachmentLoader.newSkinnedMeshAttachment(skin, name, path)
|
||||||
|
if not mesh then return null end
|
||||||
|
mesh.path = path
|
||||||
|
|
||||||
|
local uvs = getFloatArray(map, "uvs", 1)
|
||||||
|
vertices = getFloatArray(map, "vertices", 1)
|
||||||
|
local weights = {}
|
||||||
|
local bones = {}
|
||||||
|
for i = 1, vertices do
|
||||||
|
local boneCount = vertices[i]
|
||||||
|
i = i + 1
|
||||||
|
table.insert(bones, boneCount)
|
||||||
|
for ii = 1, i + boneCount * 4 do
|
||||||
|
table.insert(bones, vertices[i])
|
||||||
|
table.insert(weights, vertices[i + 1] * scale)
|
||||||
|
table.insert(weights, vertices[i + 2] * scale)
|
||||||
|
table.insert(weights, vertices[i + 3])
|
||||||
|
i = i + 4
|
||||||
|
end
|
||||||
|
end
|
||||||
|
mesh.bones = bones
|
||||||
|
mesh.weights = weights
|
||||||
|
mesh.triangles = getIntArray(map, "triangles")
|
||||||
|
mesh.regionUVs = uvs
|
||||||
|
mesh:updateUVs()
|
||||||
|
|
||||||
|
local color = map["color"]
|
||||||
|
if color then
|
||||||
|
mesh.r = tonumber(color:sub(1, 2), 16) / 255
|
||||||
|
mesh.g = tonumber(color:sub(3, 4), 16) / 255
|
||||||
|
mesh.b = tonumber(color:sub(5, 6), 16) / 255
|
||||||
|
mesh.a = tonumber(color:sub(7, 8), 16) / 255
|
||||||
|
end
|
||||||
|
|
||||||
|
mesh.hullLength = (map["hull"] or 0) * 2
|
||||||
|
if map["edges"] then mesh.edges = getIntArray(map, "edges") end
|
||||||
|
mesh.width = (map["width"] or 0) * scale
|
||||||
|
mesh.height = (map["height"] or 0) * scale
|
||||||
|
return mesh
|
||||||
|
|
||||||
elseif type == AttachmentType.boundingbox then
|
elseif type == AttachmentType.boundingbox then
|
||||||
|
local box = attachmentLoader:newBoundingBoxAttachment(type, name)
|
||||||
|
if not box then return nil end
|
||||||
local vertices = map["vertices"]
|
local vertices = map["vertices"]
|
||||||
for i,point in ipairs(vertices) do
|
for i,point in ipairs(vertices) do
|
||||||
table.insert(attachment.vertices, vertices[i] * scale)
|
table.insert(box.vertices, vertices[i] * scale)
|
||||||
end
|
end
|
||||||
|
return box
|
||||||
end
|
end
|
||||||
|
|
||||||
return attachment
|
error("Unknown attachment type: " .. type .. " (" .. name .. ")")
|
||||||
end
|
end
|
||||||
|
|
||||||
readAnimation = function (name, map, skeletonData)
|
readAnimation = function (name, map, skeletonData)
|
||||||
local timelines = {}
|
local timelines = {}
|
||||||
local duration = 0
|
local duration = 0
|
||||||
|
|
||||||
|
local slotsMap = map["slots"]
|
||||||
|
if slotsMap then
|
||||||
|
for slotName,timelineMap in pairs(slotsMap) do
|
||||||
|
local slotIndex = skeletonData.slotNameIndices[slotName]
|
||||||
|
|
||||||
|
for timelineName,values in pairs(timelineMap) do
|
||||||
|
if timelineName == "color" then
|
||||||
|
local timeline = Animation.ColorTimeline.new()
|
||||||
|
timeline.slotIndex = slotIndex
|
||||||
|
|
||||||
|
local frameIndex = 0
|
||||||
|
for i,valueMap in ipairs(values) do
|
||||||
|
local color = valueMap["color"]
|
||||||
|
timeline:setFrame(
|
||||||
|
frameIndex, valueMap["time"],
|
||||||
|
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
|
||||||
|
)
|
||||||
|
readCurve(timeline, frameIndex, valueMap)
|
||||||
|
frameIndex = frameIndex + 1
|
||||||
|
end
|
||||||
|
table.insert(timelines, timeline)
|
||||||
|
duration = math.max(duration, timeline:getDuration())
|
||||||
|
|
||||||
|
elseif timelineName == "attachment" then
|
||||||
|
local timeline = Animation.AttachmentTimeline.new()
|
||||||
|
timeline.slotName = slotName
|
||||||
|
|
||||||
|
local frameIndex = 0
|
||||||
|
for i,valueMap in ipairs(values) do
|
||||||
|
local attachmentName = valueMap["name"]
|
||||||
|
if not attachmentName then attachmentName = nil end
|
||||||
|
timeline:setFrame(frameIndex, valueMap["time"], attachmentName)
|
||||||
|
frameIndex = frameIndex + 1
|
||||||
|
end
|
||||||
|
table.insert(timelines, timeline)
|
||||||
|
duration = math.max(duration, timeline:getDuration())
|
||||||
|
|
||||||
|
else
|
||||||
|
error("Invalid frame type for a slot: " .. timelineName .. " (" .. slotName .. ")")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local bonesMap = map["bones"]
|
local bonesMap = map["bones"]
|
||||||
if bonesMap then
|
if bonesMap then
|
||||||
for boneName,timelineMap in pairs(bonesMap) do
|
for boneName,timelineMap in pairs(bonesMap) do
|
||||||
@ -199,12 +343,11 @@ function SkeletonJson.new (attachmentLoader)
|
|||||||
local timeline = Animation.RotateTimeline.new()
|
local timeline = Animation.RotateTimeline.new()
|
||||||
timeline.boneIndex = boneIndex
|
timeline.boneIndex = boneIndex
|
||||||
|
|
||||||
local keyframeIndex = 0
|
local frameIndex = 0
|
||||||
for i,valueMap in ipairs(values) do
|
for i,valueMap in ipairs(values) do
|
||||||
local time = valueMap["time"]
|
timeline:setFrame(frameIndex, valueMap["time"], valueMap["angle"])
|
||||||
timeline:setFrame(keyframeIndex, time, valueMap["angle"])
|
readCurve(timeline, frameIndex, valueMap)
|
||||||
readCurve(timeline, keyframeIndex, valueMap)
|
frameIndex = frameIndex + 1
|
||||||
keyframeIndex = keyframeIndex + 1
|
|
||||||
end
|
end
|
||||||
table.insert(timelines, timeline)
|
table.insert(timelines, timeline)
|
||||||
duration = math.max(duration, timeline:getDuration())
|
duration = math.max(duration, timeline:getDuration())
|
||||||
@ -220,14 +363,13 @@ function SkeletonJson.new (attachmentLoader)
|
|||||||
end
|
end
|
||||||
timeline.boneIndex = boneIndex
|
timeline.boneIndex = boneIndex
|
||||||
|
|
||||||
local keyframeIndex = 0
|
local frameIndex = 0
|
||||||
for i,valueMap in ipairs(values) do
|
for i,valueMap in ipairs(values) do
|
||||||
local time = valueMap["time"]
|
|
||||||
local x = (valueMap["x"] or 0) * timelineScale
|
local x = (valueMap["x"] or 0) * timelineScale
|
||||||
local y = (valueMap["y"] or 0) * timelineScale
|
local y = (valueMap["y"] or 0) * timelineScale
|
||||||
timeline:setFrame(keyframeIndex, time, x, y)
|
timeline:setFrame(frameIndex, valueMap["time"], x, y)
|
||||||
readCurve(timeline, keyframeIndex, valueMap)
|
readCurve(timeline, frameIndex, valueMap)
|
||||||
keyframeIndex = keyframeIndex + 1
|
frameIndex = frameIndex + 1
|
||||||
end
|
end
|
||||||
table.insert(timelines, timeline)
|
table.insert(timelines, timeline)
|
||||||
duration = math.max(duration, timeline:getDuration())
|
duration = math.max(duration, timeline:getDuration())
|
||||||
@ -239,72 +381,70 @@ function SkeletonJson.new (attachmentLoader)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local slotsMap = map["slots"]
|
local ffd = map["ffd"]
|
||||||
if slotsMap then
|
if ffd then
|
||||||
for slotName,timelineMap in pairs(slotsMap) do
|
for skinName,slotMap in pairs(ffd) do
|
||||||
local slotIndex = skeletonData.slotNameIndices[slotName]
|
local skin = skeletonData.findSkin(skinName)
|
||||||
|
for slotName,meshMap in pairs(slotMap) do
|
||||||
for timelineName,values in pairs(timelineMap) do
|
local slotIndex = skeletonData.findSlotIndex(slotName)
|
||||||
if timelineName == "color" then
|
for meshName,values in pairs(meshMap) do
|
||||||
local timeline = Animation.ColorTimeline.new()
|
local timeline = Animation.FfdTimeline.new()
|
||||||
|
local attachment = skin:getAttachment(slotIndex, meshName)
|
||||||
|
if not attachment then error("FFD attachment not found: " .. meshName) end
|
||||||
timeline.slotIndex = slotIndex
|
timeline.slotIndex = slotIndex
|
||||||
|
timeline.attachment = attachment
|
||||||
|
|
||||||
local keyframeIndex = 0
|
local isMesh = attachment.type == AttachmentType.mesh
|
||||||
for i,valueMap in ipairs(values) do
|
local vertexCount
|
||||||
local time = valueMap["time"]
|
if isMesh then
|
||||||
local color = valueMap["color"]
|
vertexCount = attachment.vertices.length
|
||||||
timeline:setFrame(
|
|
||||||
keyframeIndex, time,
|
|
||||||
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
|
|
||||||
)
|
|
||||||
readCurve(timeline, keyframeIndex, valueMap)
|
|
||||||
keyframeIndex = keyframeIndex + 1
|
|
||||||
end
|
|
||||||
table.insert(timelines, timeline)
|
|
||||||
duration = math.max(duration, timeline:getDuration())
|
|
||||||
|
|
||||||
elseif timelineName == "attachment" then
|
|
||||||
local timeline = Animation.AttachmentTimeline.new()
|
|
||||||
timeline.slotName = slotName
|
|
||||||
|
|
||||||
local frameIndex = 0
|
|
||||||
for i,valueMap in ipairs(values) do
|
|
||||||
local time = valueMap["time"]
|
|
||||||
local attachmentName = valueMap["name"]
|
|
||||||
if not attachmentName then attachmentName = nil end
|
|
||||||
timeline:setFrame(frameIndex, time, attachmentName)
|
|
||||||
frameIndex = frameIndex + 1
|
|
||||||
end
|
|
||||||
table.insert(timelines, timeline)
|
|
||||||
duration = math.max(duration, timeline:getDuration())
|
|
||||||
|
|
||||||
else
|
else
|
||||||
error("Invalid frame type for a slot: " .. timelineName .. " (" .. slotName .. ")")
|
vertexCount = attachment.weights.length / 3 * 2
|
||||||
|
end
|
||||||
|
|
||||||
|
local frameIndex = 0
|
||||||
|
for i,valueMap in ipairs(values) do
|
||||||
|
local vertices
|
||||||
|
if not valueMap["vertices"] then
|
||||||
|
if isMesh then
|
||||||
|
vertices = attachment.vertices
|
||||||
|
else
|
||||||
|
vertices = {}
|
||||||
|
vertices.length = vertexCount
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local verticesValue = valueMap["vertices"]
|
||||||
|
local vertices = {}
|
||||||
|
local start = valueMap["offset"] or 0
|
||||||
|
if scale == 1 then
|
||||||
|
for ii = 1, #verticesValue do
|
||||||
|
vertices[ii + start] = verticesValue[ii]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for ii = 1, #verticesValue do
|
||||||
|
vertices[ii + start] = verticesValue[ii] * scale
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if isMesh then
|
||||||
|
local meshVertices = attachment.vertices
|
||||||
|
for ii = 1, vertexCount do
|
||||||
|
vertices[ii] = vertices[ii] + meshVertices[ii]
|
||||||
|
end
|
||||||
|
elseif #verticesValue < vertexCount then
|
||||||
|
vertices[vertexCount] = 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local events = map["events"]
|
timeline:setFrame(frameIndex, valueMap["time"], vertices)
|
||||||
if events then
|
readCurve(timeline, frameIndex, valueMap)
|
||||||
local timeline = Animation.EventTimeline.new(#events)
|
|
||||||
local frameIndex = 0
|
|
||||||
for i,eventMap in ipairs(events) do
|
|
||||||
local eventData = skeletonData:findEvent(eventMap["name"])
|
|
||||||
if not eventData then error("Event not found: " .. eventMap["name"]) end
|
|
||||||
local event = Event.new(eventData)
|
|
||||||
event.intValue = eventMap["int"] or eventData.intValue
|
|
||||||
event.floatValue = eventMap["float"] or eventData.floatValue
|
|
||||||
event.stringValue = eventMap["string"] or eventData.stringValue
|
|
||||||
timeline:setFrame(frameIndex, eventMap["time"], event)
|
|
||||||
frameIndex = frameIndex + 1
|
frameIndex = frameIndex + 1
|
||||||
end
|
end
|
||||||
table.insert(timelines, timeline)
|
table.insert(timelines, timeline)
|
||||||
duration = math.max(duration, timeline:getDuration())
|
duration = math.max(duration, timeline:getDuration())
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local drawOrderValues = map["draworder"]
|
local drawOrderValues = map["draworder"]
|
||||||
if drawOrderValues then
|
if drawOrderValues then
|
||||||
@ -353,6 +493,36 @@ function SkeletonJson.new (attachmentLoader)
|
|||||||
duration = math.max(duration, timeline:getDuration())
|
duration = math.max(duration, timeline:getDuration())
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local events = map["events"]
|
||||||
|
if events then
|
||||||
|
local timeline = Animation.EventTimeline.new(#events)
|
||||||
|
local frameIndex = 0
|
||||||
|
for i,eventMap in ipairs(events) do
|
||||||
|
local eventData = skeletonData:findEvent(eventMap["name"])
|
||||||
|
if not eventData then error("Event not found: " .. eventMap["name"]) end
|
||||||
|
local event = Event.new(eventData)
|
||||||
|
if eventMap["int"] ~= nil then
|
||||||
|
event.intValue = eventMap["int"]
|
||||||
|
else
|
||||||
|
event.intValue = eventData.intValue
|
||||||
|
end
|
||||||
|
if eventMap["float"] ~= nil then
|
||||||
|
event.floatValue = eventMap["float"]
|
||||||
|
else
|
||||||
|
event.floatValue = eventData.floatValue
|
||||||
|
end
|
||||||
|
if eventMap["string"] ~= nil then
|
||||||
|
event.stringValue = eventMap["string"]
|
||||||
|
else
|
||||||
|
event.stringValue = eventData.stringValue
|
||||||
|
end
|
||||||
|
timeline:setFrame(frameIndex, eventMap["time"], event)
|
||||||
|
frameIndex = frameIndex + 1
|
||||||
|
end
|
||||||
|
table.insert(timelines, timeline)
|
||||||
|
duration = math.max(duration, timeline:getDuration())
|
||||||
|
end
|
||||||
|
|
||||||
table.insert(skeletonData.animations, Animation.new(name, timelines, duration))
|
table.insert(skeletonData.animations, Animation.new(name, timelines, duration))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
131
spine-lua/SkinnedMeshAttachment.lua
Normal file
131
spine-lua/SkinnedMeshAttachment.lua
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Spine Runtimes Software License
|
||||||
|
-- Version 2.1
|
||||||
|
--
|
||||||
|
-- Copyright (c) 2013, Esoteric Software
|
||||||
|
-- All rights reserved.
|
||||||
|
--
|
||||||
|
-- You are granted a perpetual, non-exclusive, non-sublicensable and
|
||||||
|
-- non-transferable license to install, execute and perform the Spine Runtimes
|
||||||
|
-- Software (the "Software") solely for internal use. Without the written
|
||||||
|
-- permission of Esoteric Software (typically granted by licensing Spine), you
|
||||||
|
-- may not (a) modify, translate, adapt or otherwise create derivative works,
|
||||||
|
-- improvements of the Software or develop new applications using the Software
|
||||||
|
-- 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 SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
-- OR BUSINESS INTERRUPTION) 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.AttachmentType"
|
||||||
|
|
||||||
|
local SkinnedMeshAttachment = {}
|
||||||
|
function SkinnedMeshAttachment.new (name)
|
||||||
|
if not name then error("name cannot be nil", 2) end
|
||||||
|
|
||||||
|
local self = {
|
||||||
|
name = name,
|
||||||
|
type = AttachmentType.mesh,
|
||||||
|
bones = nil,
|
||||||
|
weights = nil,
|
||||||
|
uvs = nil,
|
||||||
|
regionUVs = nil,
|
||||||
|
triangles = nil,
|
||||||
|
hullLength = 0,
|
||||||
|
r = 1, g = 1, b = 1, a = 1,
|
||||||
|
path = nil,
|
||||||
|
rendererObject = nil,
|
||||||
|
regionU = 0, regionV = 0, regionU2 = 0, regionV2 = 0, regionRotate = false,
|
||||||
|
regionOffsetX = 0, regionOffsetY = 0,
|
||||||
|
regionWidth = 0, regionHeight = 0,
|
||||||
|
regionOriginalWidth = 0, regionOriginalHeight = 0,
|
||||||
|
edges = nil,
|
||||||
|
width = 0, height = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function self:updateUVs ()
|
||||||
|
local width, height = self.regionU2 - self.regionU, self.regionV2 - self.regionV
|
||||||
|
local n = #self.regionUVs
|
||||||
|
if not self.uvs or #self.uvs ~= n then
|
||||||
|
self.uvs = {}
|
||||||
|
end
|
||||||
|
if self.regionRotate then
|
||||||
|
for i = 1, n, 2 do
|
||||||
|
self.uvs[i] = self.regionU + self.regionUVs[i + 1] * width
|
||||||
|
self.uvs[i + 1] = self.regionV + height - self.regionUVs[i] * height
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for i = 1, n, 2 do
|
||||||
|
self.uvs[i] = self.regionU + self.regionUVs[i] * width
|
||||||
|
self.uvs[i + 1] = self.regionV + self.regionUVs[i + 1] * height
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function self:computeWorldVertices (x, y, slot, worldVertices)
|
||||||
|
local skeletonBones = slot.skeleton.bones
|
||||||
|
local weights = self.weights
|
||||||
|
local bones = self.bones
|
||||||
|
|
||||||
|
local w, v, b, f = 0, 0, 0, 0
|
||||||
|
local n = bones.length
|
||||||
|
local wx, wy, bone, vx, vy, weight
|
||||||
|
if #slot.attachmentVertices == 0 then
|
||||||
|
while v < n do
|
||||||
|
wx = 0
|
||||||
|
wy = 0
|
||||||
|
local nn = bones[v] + v
|
||||||
|
v = v + 1
|
||||||
|
while v <= nn do
|
||||||
|
bone = skeletonBones[bones[v]]
|
||||||
|
vx = weights[b]
|
||||||
|
vy = weights[b + 1]
|
||||||
|
weight = weights[b + 2]
|
||||||
|
wx = wx + (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight
|
||||||
|
wy = wy + (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight
|
||||||
|
v = v + 1
|
||||||
|
b = b + 3
|
||||||
|
end
|
||||||
|
worldVertices[w] = wx + x
|
||||||
|
worldVertices[w + 1] = wy + y
|
||||||
|
w = w + 2
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local ffd = slot.attachmentVertices
|
||||||
|
while v < n do
|
||||||
|
wx = 0
|
||||||
|
wy = 0
|
||||||
|
local nn = bones[v] + v
|
||||||
|
v = v + 1
|
||||||
|
while v <= nn do
|
||||||
|
bone = skeletonBones[bones[v]]
|
||||||
|
vx = weights[b] + ffd[f]
|
||||||
|
vy = weights[b + 1] + ffd[f + 1]
|
||||||
|
weight = weights[b + 2]
|
||||||
|
wx = wx + (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight
|
||||||
|
wy = wy + (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight
|
||||||
|
v = v + 1
|
||||||
|
b = b + 3
|
||||||
|
f = f + 2
|
||||||
|
end
|
||||||
|
worldVertices[w] = wx + x
|
||||||
|
worldVertices[w + 1] = wy + y
|
||||||
|
w = w + 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
return MeshAttachment
|
||||||
@ -38,7 +38,10 @@ function Slot.new (slotData, skeleton, bone)
|
|||||||
data = slotData,
|
data = slotData,
|
||||||
skeleton = skeleton,
|
skeleton = skeleton,
|
||||||
bone = bone,
|
bone = bone,
|
||||||
r = 1, g = 1, b = 1, a = 1
|
r = 1, g = 1, b = 1, a = 1,
|
||||||
|
attachment = nil,
|
||||||
|
attachmentTime = 0,
|
||||||
|
attachmentVertices = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
function self:setColor (r, g, b, a)
|
function self:setColor (r, g, b, a)
|
||||||
|
|||||||
@ -36,7 +36,9 @@ function SlotData.new (name, boneData)
|
|||||||
local self = {
|
local self = {
|
||||||
name = name,
|
name = name,
|
||||||
boneData = boneData,
|
boneData = boneData,
|
||||||
r = 1, g = 1, b = 1, a = 1
|
r = 1, g = 1, b = 1, a = 1,
|
||||||
|
attachmentName = nil,
|
||||||
|
additiveBlending = false
|
||||||
}
|
}
|
||||||
|
|
||||||
function self:setColor (r, g, b, a)
|
function self:setColor (r, g, b, a)
|
||||||
@ -46,6 +48,6 @@ function SlotData.new (name, boneData)
|
|||||||
self.a = a
|
self.a = a
|
||||||
end
|
end
|
||||||
|
|
||||||
return self;
|
return self
|
||||||
end
|
end
|
||||||
return SlotData
|
return SlotData
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user