mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-20 16:56:43 +08:00
[lua] 4.0 port, runs but LOVE is not rendering.
This commit is contained in:
parent
700d2897a8
commit
137c3f69ed
@ -113,8 +113,8 @@ end
|
|||||||
function love.load(arg)
|
function love.load(arg)
|
||||||
if arg[#arg] == "-debug" then require("mobdebug").start() end
|
if arg[#arg] == "-debug" then require("mobdebug").start() end
|
||||||
skeletonRenderer = spine.SkeletonRenderer.new(true)
|
skeletonRenderer = spine.SkeletonRenderer.new(true)
|
||||||
table.insert(skeletons, loadSkeleton("mix-and-match-pro", "mix-and-match", "dance", nil, 0.5, 400, 500))
|
|
||||||
table.insert(skeletons, loadSkeleton("spineboy-pro", "spineboy", "walk", nil, 0.5, 400, 500))
|
table.insert(skeletons, loadSkeleton("spineboy-pro", "spineboy", "walk", nil, 0.5, 400, 500))
|
||||||
|
table.insert(skeletons, loadSkeleton("mix-and-match-pro", "mix-and-match", "dance", nil, 0.5, 400, 500))
|
||||||
table.insert(skeletons, loadSkeleton("stretchyman-pro", "stretchyman", "sneak", nil, 0.5, 200, 500))
|
table.insert(skeletons, loadSkeleton("stretchyman-pro", "stretchyman", "sneak", nil, 0.5, 200, 500))
|
||||||
table.insert(skeletons, loadSkeleton("coin-pro", "coin", "animation", nil, 0.5, 400, 300))
|
table.insert(skeletons, loadSkeleton("coin-pro", "coin", "animation", nil, 0.5, 400, 300))
|
||||||
table.insert(skeletons, loadSkeleton("raptor-pro", "raptor", "walk", nil, 0.3, 400, 500))
|
table.insert(skeletons, loadSkeleton("raptor-pro", "raptor", "walk", nil, 0.3, 400, 500))
|
||||||
|
|||||||
@ -37,7 +37,7 @@ local utils = require "spine-lua.utils"
|
|||||||
local AttachmentType = require "spine-lua.attachments.AttachmentType"
|
local AttachmentType = require "spine-lua.attachments.AttachmentType"
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
local math_floor = math_floor
|
local math_floor = math.floor
|
||||||
local math_abs = math.abs
|
local math_abs = math.abs
|
||||||
local math_signum = utils.signum
|
local math_signum = utils.signum
|
||||||
|
|
||||||
@ -64,14 +64,14 @@ function Animation.new (name, timelines, duration)
|
|||||||
self.timelineIds = {}
|
self.timelineIds = {}
|
||||||
for i,timeline in ipairs(self.timelines) do
|
for i,timeline in ipairs(self.timelines) do
|
||||||
for _,id in ipairs(timeline.propertyIds) do
|
for _,id in ipairs(timeline.propertyIds) do
|
||||||
timelineIds[id] = true
|
self.timelineIds[id] = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function self:hasTimeline (ids)
|
function self:hasTimeline (ids)
|
||||||
for _,id in ipairs(ids) do
|
for _,id in ipairs(ids) do
|
||||||
if timelineIds[id] then return true end
|
if self.timelineIds[id] then return true end
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@ -134,11 +134,28 @@ Animation.Property = {
|
|||||||
}
|
}
|
||||||
local Property = Animation.Property
|
local Property = Animation.Property
|
||||||
|
|
||||||
|
Animation.TimelineType = {
|
||||||
|
rotate = 0,
|
||||||
|
translate = 1, translateX = 2, translateY = 3,
|
||||||
|
scale = 4, scaleX = 5, scaleY = 6,
|
||||||
|
shear = 7, shearX = 8, shearY = 9,
|
||||||
|
rgba = 10, rgb = 11, alpha = 12, rgba2 = 13, rgb2 = 14,
|
||||||
|
attachment = 15,
|
||||||
|
deform = 16,
|
||||||
|
event = 17,
|
||||||
|
drawOrder = 18,
|
||||||
|
ikConstraint = 19,
|
||||||
|
transformConstraint = 20,
|
||||||
|
pathConstraintPosition = 21, pathConstraintSpacing = 22, pathConstraintMix = 23
|
||||||
|
}
|
||||||
|
local TimelineType = Animation.TimelineType
|
||||||
|
|
||||||
Animation.Timeline = {}
|
Animation.Timeline = {}
|
||||||
function Animation.Timeline.new (frameCount, propertyIds)
|
function Animation.Timeline.new (timelineType, frameEntries, frameCount, propertyIds)
|
||||||
local self = {
|
local self = {
|
||||||
|
timelineType = timelineType,
|
||||||
propertyIds = propertyIds,
|
propertyIds = propertyIds,
|
||||||
frames = utils.newNumberArrayZero((frameCount - 1) * self:getFrameEntries())
|
frames = utils.newNumberArrayZero((frameCount - 1) * frameEntries)
|
||||||
}
|
}
|
||||||
|
|
||||||
function self:getFrameEntries ()
|
function self:getFrameEntries ()
|
||||||
@ -158,7 +175,8 @@ end
|
|||||||
|
|
||||||
local function search1 (frames, time)
|
local function search1 (frames, time)
|
||||||
local n = zlen(frames)
|
local n = zlen(frames)
|
||||||
while i <= n do
|
local i = 1
|
||||||
|
while i < n do
|
||||||
if frames[i] > time then return i - 1 end
|
if frames[i] > time then return i - 1 end
|
||||||
i = i + 1
|
i = i + 1
|
||||||
end
|
end
|
||||||
@ -169,7 +187,7 @@ Animation.Timeline.search1 = search1
|
|||||||
local function search (frames, time, step)
|
local function search (frames, time, step)
|
||||||
local n = zlen(frames)
|
local n = zlen(frames)
|
||||||
local i = step
|
local i = step
|
||||||
while i <= n do
|
while i < n do
|
||||||
if frames[i] > time then return i - step end
|
if frames[i] > time then return i - step end
|
||||||
i = i + step
|
i = i + step
|
||||||
end
|
end
|
||||||
@ -182,14 +200,15 @@ local BEZIER = 2
|
|||||||
local BEZIER_SIZE = 18
|
local BEZIER_SIZE = 18
|
||||||
|
|
||||||
Animation.CurveTimeline = {}
|
Animation.CurveTimeline = {}
|
||||||
function Animation.CurveTimeline.new (frameCount, bezierCount, propertyIds)
|
function Animation.CurveTimeline.new (timelineType, frameEntries, frameCount, bezierCount, propertyIds)
|
||||||
local LINEAR = 0
|
local LINEAR = 0
|
||||||
local STEPPED = 1
|
local STEPPED = 1
|
||||||
local BEZIER = 2
|
local BEZIER = 2
|
||||||
local BEZIER_SIZE = 10 * 2 - 1
|
local BEZIER_SIZE = 10 * 2 - 1
|
||||||
|
|
||||||
local self = Animation.Timeline.new(frameCount, propertyIds)
|
local self = Animation.Timeline.new(timelineType, frameEntries, frameCount, propertyIds)
|
||||||
self.curves = utils.newNumberArrayZero(frameCount + bezierCount * BEZIER_SIZE)
|
self.curves = utils.newNumberArrayZero(frameCount + bezierCount * BEZIER_SIZE)
|
||||||
|
self.curves[frameCount - 1] = STEPPED
|
||||||
|
|
||||||
function self:getFrameCount ()
|
function self:getFrameCount ()
|
||||||
return math_floor(zlen(self.curves) / BEZIER_SIZE) + 1
|
return math_floor(zlen(self.curves) / BEZIER_SIZE) + 1
|
||||||
@ -261,11 +280,11 @@ function Animation.CurveTimeline.new (frameCount, bezierCount, propertyIds)
|
|||||||
end
|
end
|
||||||
|
|
||||||
Animation.CurveTimeline1 = {}
|
Animation.CurveTimeline1 = {}
|
||||||
function Animation.CurveTimeline1.new (frameCount, bezierCount, propertyId)
|
function Animation.CurveTimeline1.new (timelineType, frameCount, bezierCount, propertyId)
|
||||||
local ENTRIES = 2
|
local ENTRIES = 2
|
||||||
local VALUE = 1
|
local VALUE = 1
|
||||||
|
|
||||||
local self = Animation.CurveTimeline.new(frameCount, bezierCount, { propertyId })
|
local self = Animation.CurveTimeline.new(timelineType, ENTRIES, frameCount, bezierCount, { propertyId })
|
||||||
|
|
||||||
function self:getFrameEntries ()
|
function self:getFrameEntries ()
|
||||||
return ENTRIES
|
return ENTRIES
|
||||||
@ -303,12 +322,12 @@ function Animation.CurveTimeline1.new (frameCount, bezierCount, propertyId)
|
|||||||
end
|
end
|
||||||
|
|
||||||
Animation.CurveTimeline2 = {}
|
Animation.CurveTimeline2 = {}
|
||||||
function Animation.CurveTimeline2.new (frameCount, bezierCount, propertyId1, propertyId2)
|
function Animation.CurveTimeline2.new (timelineType, frameCount, bezierCount, propertyId1, propertyId2)
|
||||||
local ENTRIES = 3
|
local ENTRIES = 3
|
||||||
local VALUE1 = 1
|
local VALUE1 = 1
|
||||||
local VALUE2 = 2
|
local VALUE2 = 2
|
||||||
|
|
||||||
local self = Animation.CurveTimeline.new(frameCount, bezierCount, { propertyId1, propertyId2 })
|
local self = Animation.CurveTimeline.new(timelineType, ENTRIES, frameCount, bezierCount, { propertyId1, propertyId2 })
|
||||||
|
|
||||||
function self:getFrameEntries ()
|
function self:getFrameEntries ()
|
||||||
return ENTRIES
|
return ENTRIES
|
||||||
@ -326,7 +345,7 @@ end
|
|||||||
|
|
||||||
Animation.RotateTimeline = {}
|
Animation.RotateTimeline = {}
|
||||||
function Animation.RotateTimeline.new (frameCount, bezierCount, boneIndex)
|
function Animation.RotateTimeline.new (frameCount, bezierCount, boneIndex)
|
||||||
local self = Animation.CurveTimeline1.new(frameCount, bezierCount, Property.rotate.."|"..boneIndex)
|
local self = Animation.CurveTimeline1.new(TimelineType.rotate, frameCount, bezierCount, Property.rotate.."|"..boneIndex)
|
||||||
self.boneIndex = boneIndex
|
self.boneIndex = boneIndex
|
||||||
|
|
||||||
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
||||||
@ -358,7 +377,11 @@ end
|
|||||||
|
|
||||||
Animation.TranslateTimeline = {}
|
Animation.TranslateTimeline = {}
|
||||||
function Animation.TranslateTimeline.new (frameCount, bezierCount, boneIndex)
|
function Animation.TranslateTimeline.new (frameCount, bezierCount, boneIndex)
|
||||||
local self = Animation.CurveTimeline2.new(frameCount, bezierCount,
|
local ENTRIES = 3
|
||||||
|
local VALUE1 = 1
|
||||||
|
local VALUE2 = 2
|
||||||
|
|
||||||
|
local self = Animation.CurveTimeline2.new(TimelineType.translate, frameCount, bezierCount,
|
||||||
Property.x.."|"..boneIndex,
|
Property.x.."|"..boneIndex,
|
||||||
Property.y.."|"..boneIndex
|
Property.y.."|"..boneIndex
|
||||||
)
|
)
|
||||||
@ -382,7 +405,7 @@ function Animation.TranslateTimeline.new (frameCount, bezierCount, boneIndex)
|
|||||||
|
|
||||||
local x = 0
|
local x = 0
|
||||||
local y = 0
|
local y = 0
|
||||||
local frame = search2(frames, time, ENTRIES)
|
local i = search(frames, time, ENTRIES)
|
||||||
local curveType = self.curves[math_floor(i / ENTRIES)]
|
local curveType = self.curves[math_floor(i / ENTRIES)]
|
||||||
if curveType == LINEAR then
|
if curveType == LINEAR then
|
||||||
local before = frames[i]
|
local before = frames[i]
|
||||||
@ -416,7 +439,7 @@ end
|
|||||||
|
|
||||||
Animation.TranslateXTimeline = {}
|
Animation.TranslateXTimeline = {}
|
||||||
function Animation.TranslateXTimeline.new (frameCount, bezierCount, boneIndex)
|
function Animation.TranslateXTimeline.new (frameCount, bezierCount, boneIndex)
|
||||||
local self = Animation.CurveTimeline1.new(frameCount, bezierCount, Property.x.."|"..boneIndex)
|
local self = Animation.CurveTimeline1.new(TimelineType.translateX, frameCount, bezierCount, Property.x.."|"..boneIndex)
|
||||||
self.boneIndex = boneIndex
|
self.boneIndex = boneIndex
|
||||||
|
|
||||||
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
||||||
@ -448,7 +471,7 @@ end
|
|||||||
|
|
||||||
Animation.TranslateYTimeline = {}
|
Animation.TranslateYTimeline = {}
|
||||||
function Animation.TranslateYTimeline.new (frameCount, bezierCount, boneIndex)
|
function Animation.TranslateYTimeline.new (frameCount, bezierCount, boneIndex)
|
||||||
local self = Animation.CurveTimeline1.new(frameCount, bezierCount, Property.x.."|"..boneIndex)
|
local self = Animation.CurveTimeline1.new(TimelineType.translateY, frameCount, bezierCount, Property.x.."|"..boneIndex)
|
||||||
self.boneIndex = boneIndex
|
self.boneIndex = boneIndex
|
||||||
|
|
||||||
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
||||||
@ -480,7 +503,11 @@ end
|
|||||||
|
|
||||||
Animation.ScaleTimeline = {}
|
Animation.ScaleTimeline = {}
|
||||||
function Animation.ScaleTimeline.new (frameCount, bezierCount, boneIndex)
|
function Animation.ScaleTimeline.new (frameCount, bezierCount, boneIndex)
|
||||||
local self = Animation.CurveTimeline2.new(frameCount, bezierCount,
|
local ENTRIES = 3
|
||||||
|
local VALUE1 = 1
|
||||||
|
local VALUE2 = 2
|
||||||
|
|
||||||
|
local self = Animation.CurveTimeline2.new(TimelineType.scale, frameCount, bezierCount,
|
||||||
Property.scaleX.."|"..boneIndex,
|
Property.scaleX.."|"..boneIndex,
|
||||||
Property.scaleY.."|"..boneIndex
|
Property.scaleY.."|"..boneIndex
|
||||||
)
|
)
|
||||||
@ -504,7 +531,7 @@ function Animation.ScaleTimeline.new (frameCount, bezierCount, boneIndex)
|
|||||||
|
|
||||||
local x = 0
|
local x = 0
|
||||||
local y = 0
|
local y = 0
|
||||||
local i = search2(frames, time, ENTRIES)
|
local i = search(frames, time, ENTRIES)
|
||||||
local curveType = self.curves[math_floor(i / ENTRIES)]
|
local curveType = self.curves[math_floor(i / ENTRIES)]
|
||||||
if curveType == LINEAR then
|
if curveType == LINEAR then
|
||||||
local before = frames[i]
|
local before = frames[i]
|
||||||
@ -577,7 +604,7 @@ end
|
|||||||
|
|
||||||
Animation.ScaleXTimeline = {}
|
Animation.ScaleXTimeline = {}
|
||||||
function Animation.ScaleXTimeline.new (frameCount, bezierCount, boneIndex)
|
function Animation.ScaleXTimeline.new (frameCount, bezierCount, boneIndex)
|
||||||
local self = Animation.CurveTimeline1.new(frameCount, bezierCount, Property.scaleX.."|"..boneIndex)
|
local self = Animation.CurveTimeline1.new(TimelineType.scaleX, frameCount, bezierCount, Property.scaleX.."|"..boneIndex)
|
||||||
self.boneIndex = boneIndex
|
self.boneIndex = boneIndex
|
||||||
|
|
||||||
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
||||||
@ -634,7 +661,7 @@ end
|
|||||||
|
|
||||||
Animation.ScaleYTimeline = {}
|
Animation.ScaleYTimeline = {}
|
||||||
function Animation.ScaleYTimeline.new (frameCount, bezierCount, boneIndex)
|
function Animation.ScaleYTimeline.new (frameCount, bezierCount, boneIndex)
|
||||||
local self = Animation.CurveTimeline1.new(frameCount, bezierCount, Property.scaleY.."|"..boneIndex)
|
local self = Animation.CurveTimeline1.new(TimelineType.scaleY, frameCount, bezierCount, Property.scaleY.."|"..boneIndex)
|
||||||
self.boneIndex = boneIndex
|
self.boneIndex = boneIndex
|
||||||
|
|
||||||
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
||||||
@ -690,8 +717,12 @@ function Animation.ScaleYTimeline.new (frameCount, bezierCount, boneIndex)
|
|||||||
end
|
end
|
||||||
|
|
||||||
Animation.ShearTimeline = {}
|
Animation.ShearTimeline = {}
|
||||||
function Animation.ShearTimeline.new (frameCount)
|
function Animation.ShearTimeline.new (frameCount, bezierCount, boneIndex)
|
||||||
local self = Animation.CurveTimeline2.new(frameCount, bezierCount,
|
local ENTRIES = 3
|
||||||
|
local VALUE1 = 1
|
||||||
|
local VALUE2 = 2
|
||||||
|
|
||||||
|
local self = Animation.CurveTimeline2.new(TimelineType.shear, frameCount, bezierCount,
|
||||||
Property.shearX.."|"..boneIndex,
|
Property.shearX.."|"..boneIndex,
|
||||||
Property.shearY.."|"..boneIndex
|
Property.shearY.."|"..boneIndex
|
||||||
)
|
)
|
||||||
@ -715,7 +746,7 @@ function Animation.ShearTimeline.new (frameCount)
|
|||||||
|
|
||||||
local x = 0
|
local x = 0
|
||||||
local y = 0
|
local y = 0
|
||||||
local i = search2(frames, time, ENTRIES)
|
local i = search(frames, time, ENTRIES)
|
||||||
local curveType = self.curves[math_floor(i / ENTRIES)]
|
local curveType = self.curves[math_floor(i / ENTRIES)]
|
||||||
if curveType == LINEAR then
|
if curveType == LINEAR then
|
||||||
local before = frames[i]
|
local before = frames[i]
|
||||||
@ -748,8 +779,8 @@ function Animation.ShearTimeline.new (frameCount)
|
|||||||
end
|
end
|
||||||
|
|
||||||
Animation.ShearXTimeline = {}
|
Animation.ShearXTimeline = {}
|
||||||
function Animation.ShearXTimeline.new (frameCount)
|
function Animation.ShearXTimeline.new (frameCount, bezierCount, boneIndex)
|
||||||
local self = Animation.CurveTimeline1.new(frameCount, bezierCount, Property.shearX.."|"..boneIndex)
|
local self = Animation.CurveTimeline1.new(TimelineType.shearX, frameCount, bezierCount, Property.shearX.."|"..boneIndex)
|
||||||
self.boneIndex = boneIndex
|
self.boneIndex = boneIndex
|
||||||
|
|
||||||
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
||||||
@ -780,8 +811,8 @@ function Animation.ShearXTimeline.new (frameCount)
|
|||||||
end
|
end
|
||||||
|
|
||||||
Animation.ShearYTimeline = {}
|
Animation.ShearYTimeline = {}
|
||||||
function Animation.ShearYTimeline.new (frameCount)
|
function Animation.ShearYTimeline.new (frameCount, bezierCount, boneIndex)
|
||||||
local self = Animation.CurveTimeline1.new(frameCount, bezierCount, Property.shearY.."|"..boneIndex)
|
local self = Animation.CurveTimeline1.new(TimelineType.shearY, frameCount, bezierCount, Property.shearY.."|"..boneIndex)
|
||||||
self.boneIndex = boneIndex
|
self.boneIndex = boneIndex
|
||||||
|
|
||||||
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
||||||
@ -819,7 +850,7 @@ function Animation.RGBATimeline.new (frameCount, bezierCount, slotIndex)
|
|||||||
local B = 3
|
local B = 3
|
||||||
local A = 4
|
local A = 4
|
||||||
|
|
||||||
local self = Animation.CurveTimeline.new(frameCount, bezierCount, {
|
local self = Animation.CurveTimeline.new(TimelineType.rgba, ENTRIES, frameCount, bezierCount, {
|
||||||
Property.rgb.."|"..slotIndex,
|
Property.rgb.."|"..slotIndex,
|
||||||
Property.alpha.."|"..slotIndex
|
Property.alpha.."|"..slotIndex
|
||||||
})
|
})
|
||||||
@ -856,7 +887,7 @@ function Animation.RGBATimeline.new (frameCount, bezierCount, slotIndex)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local r, g, b, a
|
local r, g, b, a
|
||||||
local i = search2(frames, time, ENTRIES)
|
local i = search(frames, time, ENTRIES)
|
||||||
local curveType = self.curves[i / ENTRIES]
|
local curveType = self.curves[i / ENTRIES]
|
||||||
if curveType == LINEAR then
|
if curveType == LINEAR then
|
||||||
local before = frames[i]
|
local before = frames[i]
|
||||||
@ -899,7 +930,7 @@ function Animation.RGBTimeline.new (frameCount, bezierCount, slotIndex)
|
|||||||
local G = 2
|
local G = 2
|
||||||
local B = 3
|
local B = 3
|
||||||
|
|
||||||
local self = Animation.CurveTimeline.new(frameCount, bezierCount, { Property.rgb.."|"..slotIndex })
|
local self = Animation.CurveTimeline.new(TimelineType.rgb, ENTRIES, frameCount, bezierCount, { Property.rgb.."|"..slotIndex })
|
||||||
self.slotIndex = slotIndex
|
self.slotIndex = slotIndex
|
||||||
|
|
||||||
function self:getFrameEntries ()
|
function self:getFrameEntries ()
|
||||||
@ -935,7 +966,7 @@ function Animation.RGBTimeline.new (frameCount, bezierCount, slotIndex)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local r, g, b
|
local r, g, b
|
||||||
local i = search2(frames, time, ENTRIES)
|
local i = search(frames, time, ENTRIES)
|
||||||
local curveType = self.curves[i / ENTRIES]
|
local curveType = self.curves[i / ENTRIES]
|
||||||
if curveType == LINEAR then
|
if curveType == LINEAR then
|
||||||
local before = frames[i]
|
local before = frames[i]
|
||||||
@ -978,7 +1009,7 @@ end
|
|||||||
|
|
||||||
Animation.AlphaTimeline = {}
|
Animation.AlphaTimeline = {}
|
||||||
function Animation.AlphaTimeline.new (frameCount, bezierCount, slotIndex)
|
function Animation.AlphaTimeline.new (frameCount, bezierCount, slotIndex)
|
||||||
local self = Animation.CurveTimeline1.new(frameCount, bezierCount, Property.alpha.."|"..slotIndex)
|
local self = Animation.CurveTimeline1.new(TimelineType.alpha, frameCount, bezierCount, Property.alpha.."|"..slotIndex)
|
||||||
self.slotIndex = slotIndex
|
self.slotIndex = slotIndex
|
||||||
|
|
||||||
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
||||||
@ -1020,7 +1051,7 @@ function Animation.RGBA2Timeline.new (frameCount, bezierCount, slotIndex)
|
|||||||
local G2 = 6
|
local G2 = 6
|
||||||
local B2 = 7
|
local B2 = 7
|
||||||
|
|
||||||
local self = Animation.CurveTimeline.new(frameCount, bezierCount, {
|
local self = Animation.CurveTimeline.new(TimelineType.rgba2, ENTRIES, frameCount, bezierCount, {
|
||||||
Property.rgb.."|"..slotIndex,
|
Property.rgb.."|"..slotIndex,
|
||||||
Property.alpha.."|"..slotIndex,
|
Property.alpha.."|"..slotIndex,
|
||||||
Property.rgb2.."|"..slotIndex
|
Property.rgb2.."|"..slotIndex
|
||||||
@ -1069,7 +1100,7 @@ function Animation.RGBA2Timeline.new (frameCount, bezierCount, slotIndex)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local r, g, b, a, r2, g2, b2
|
local r, g, b, a, r2, g2, b2
|
||||||
local i = search2(frames, time, ENTRIES)
|
local i = search(frames, time, ENTRIES)
|
||||||
local curveType = self.curves[math_floor(i / ENTRIES)]
|
local curveType = self.curves[math_floor(i / ENTRIES)]
|
||||||
if curveType == LINEAR then
|
if curveType == LINEAR then
|
||||||
local before = frames[i]
|
local before = frames[i]
|
||||||
@ -1139,7 +1170,7 @@ function Animation.RGB2Timeline.new (frameCount, bezierCount, slotIndex)
|
|||||||
local G2 = 5
|
local G2 = 5
|
||||||
local B2 = 6
|
local B2 = 6
|
||||||
|
|
||||||
local self = Animation.CurveTimeline.new(frameCount, bezierCount, {
|
local self = Animation.CurveTimeline.new(TimelineType.rgb2, ENTRIES, frameCount, bezierCount, {
|
||||||
Property.rgb.."|"..slotIndex,
|
Property.rgb.."|"..slotIndex,
|
||||||
Property.rgb2.."|"..slotIndex
|
Property.rgb2.."|"..slotIndex
|
||||||
})
|
})
|
||||||
@ -1189,7 +1220,7 @@ function Animation.RGB2Timeline.new (frameCount, bezierCount, slotIndex)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local r, g, b, r2, g2, b2
|
local r, g, b, r2, g2, b2
|
||||||
local i = search2(frames, time, ENTRIES)
|
local i = search(frames, time, ENTRIES)
|
||||||
local curveType = self.curves[math_floor(i / ENTRIES)]
|
local curveType = self.curves[math_floor(i / ENTRIES)]
|
||||||
if curveType == LINEAR then
|
if curveType == LINEAR then
|
||||||
local before = frames[i]
|
local before = frames[i]
|
||||||
@ -1254,7 +1285,7 @@ end
|
|||||||
|
|
||||||
Animation.AttachmentTimeline = {}
|
Animation.AttachmentTimeline = {}
|
||||||
function Animation.AttachmentTimeline.new (frameCount, bezierCount, slotIndex)
|
function Animation.AttachmentTimeline.new (frameCount, bezierCount, slotIndex)
|
||||||
local self = Animation.Timeline.new(frameCount, { Property.attachment + "|" + slotIndex })
|
local self = Animation.Timeline.new(TimelineType.attachment, 1, frameCount, { Property.attachment.."|"..slotIndex })
|
||||||
self.slotIndex = slotIndex
|
self.slotIndex = slotIndex
|
||||||
self.attachmentNames = {}
|
self.attachmentNames = {}
|
||||||
|
|
||||||
@ -1311,7 +1342,7 @@ end
|
|||||||
|
|
||||||
Animation.DeformTimeline = {}
|
Animation.DeformTimeline = {}
|
||||||
function Animation.DeformTimeline.new (frameCount, bezierCount, slotIndex, attachment)
|
function Animation.DeformTimeline.new (frameCount, bezierCount, slotIndex, attachment)
|
||||||
local self = Animation.CurveTimeline.new(frameCount, bezierCount, { Property.deform + "|" + slotIndex + "|" + attachment.id })
|
local self = Animation.CurveTimeline.new(TimelineType.deform, 1, frameCount, bezierCount, { Property.deform.."|"..slotIndex.."|"..attachment.id })
|
||||||
self.slotIndex = slotIndex
|
self.slotIndex = slotIndex
|
||||||
self.attachment = attachment
|
self.attachment = attachment
|
||||||
self.vertices = {}
|
self.vertices = {}
|
||||||
@ -1353,7 +1384,7 @@ function Animation.DeformTimeline.new (frameCount, bezierCount, slotIndex, attac
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function getCurvePercent (time, frame)
|
function self:getCurvePercent (time, frame)
|
||||||
local curves = self.curves
|
local curves = self.curves
|
||||||
local i = curves[frame]
|
local i = curves[frame]
|
||||||
if i == LINEAR then
|
if i == LINEAR then
|
||||||
@ -1387,7 +1418,7 @@ function Animation.DeformTimeline.new (frameCount, bezierCount, slotIndex, attac
|
|||||||
if not slot.bone.active then return end
|
if not slot.bone.active then return end
|
||||||
|
|
||||||
local vertexAttachment = slot.attachment
|
local vertexAttachment = slot.attachment
|
||||||
if not vertexAttachment or not vertexAttachment.vertexAttachment or vertexAttachment.deformAttachment ~= self.attachment then return end
|
if not vertexAttachment or not vertexAttachment.isVertexAttachment or vertexAttachment.deformAttachment ~= self.attachment then return end
|
||||||
|
|
||||||
local frames = self.frames
|
local frames = self.frames
|
||||||
local deform = slot.deform
|
local deform = slot.deform
|
||||||
@ -1604,7 +1635,7 @@ end
|
|||||||
Animation.EventTimeline = {}
|
Animation.EventTimeline = {}
|
||||||
local eventPropertyIds = { Property.event }
|
local eventPropertyIds = { Property.event }
|
||||||
function Animation.EventTimeline.new (frameCount)
|
function Animation.EventTimeline.new (frameCount)
|
||||||
local self = Animation.Timeline.new(frameCount, eventPropertyIds)
|
local self = Animation.Timeline.new(TimelineType.event, 1, frameCount, eventPropertyIds)
|
||||||
self.events = {}
|
self.events = {}
|
||||||
|
|
||||||
function self:getFrameCount ()
|
function self:getFrameCount ()
|
||||||
@ -1635,7 +1666,7 @@ function Animation.EventTimeline.new (frameCount)
|
|||||||
if lastTime < frames[0] then
|
if lastTime < frames[0] then
|
||||||
i = 0
|
i = 0
|
||||||
else
|
else
|
||||||
i = binarySearch1(frames, lastTime)
|
i = search1(frames, lastTime) + 1
|
||||||
local i = frames[i]
|
local i = frames[i]
|
||||||
while i > 0 do -- Fire multiple events with the same frame.
|
while i > 0 do -- Fire multiple events with the same frame.
|
||||||
if frames[i - 1] ~= i then break end
|
if frames[i - 1] ~= i then break end
|
||||||
@ -1654,7 +1685,7 @@ end
|
|||||||
Animation.DrawOrderTimeline = {}
|
Animation.DrawOrderTimeline = {}
|
||||||
local drawOrderPropertyIds = { Property.drawOrder }
|
local drawOrderPropertyIds = { Property.drawOrder }
|
||||||
function Animation.DrawOrderTimeline.new (frameCount)
|
function Animation.DrawOrderTimeline.new (frameCount)
|
||||||
local self = Animation.Timeline.new(frameCount, drawOrderPropertyIds)
|
local self = Animation.Timeline.new(TimelineType.drawOrder, 1, frameCount, drawOrderPropertyIds)
|
||||||
self.drawOrders = {}
|
self.drawOrders = {}
|
||||||
|
|
||||||
function self:getFrameCount ()
|
function self:getFrameCount ()
|
||||||
@ -1667,6 +1698,9 @@ function Animation.DrawOrderTimeline.new (frameCount)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
||||||
|
local drawOrder = skeleton.drawOrder
|
||||||
|
local slots = skeleton.slots
|
||||||
|
|
||||||
if direction == MixDirection.mixOut then
|
if direction == MixDirection.mixOut then
|
||||||
if blend == MixBlend.setup then
|
if blend == MixBlend.setup then
|
||||||
for i,slot in ipairs(slots) do
|
for i,slot in ipairs(slots) do
|
||||||
@ -1691,8 +1725,6 @@ function Animation.DrawOrderTimeline.new (frameCount)
|
|||||||
drawOrder[i] = slots[i]
|
drawOrder[i] = slots[i]
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local drawOrder = skeleton.drawOrder
|
|
||||||
local slots = skeleton.slots
|
|
||||||
for i,setupIndex in ipairs(drawOrderToSetupIndex) do
|
for i,setupIndex in ipairs(drawOrderToSetupIndex) do
|
||||||
drawOrder[i] = skeleton.slots[setupIndex]
|
drawOrder[i] = skeleton.slots[setupIndex]
|
||||||
end
|
end
|
||||||
@ -1711,7 +1743,7 @@ function Animation.IkConstraintTimeline.new (frameCount, bezierCount, ikConstrai
|
|||||||
local COMPRESS = 4
|
local COMPRESS = 4
|
||||||
local STRETCH = 5
|
local STRETCH = 5
|
||||||
|
|
||||||
local self = Animation.CurveTimeline.new(frameCount, bezierCount, { Property.ikConstraint + "|" + ikConstraintIndex })
|
local self = Animation.CurveTimeline.new(TimelineType.ikConstraint, ENTRIES, frameCount, bezierCount, { Property.ikConstraint.."|"..ikConstraintIndex })
|
||||||
self.ikConstraintIndex = ikConstraintIndex
|
self.ikConstraintIndex = ikConstraintIndex
|
||||||
|
|
||||||
function self:getFrameEntries ()
|
function self:getFrameEntries ()
|
||||||
@ -1804,7 +1836,7 @@ function Animation.IkConstraintTimeline.new (frameCount, bezierCount, ikConstrai
|
|||||||
end
|
end
|
||||||
|
|
||||||
Animation.TransformConstraintTimeline = {}
|
Animation.TransformConstraintTimeline = {}
|
||||||
function Animation.TransformConstraintTimeline.new (frameCount, transformConstraintIndex)
|
function Animation.TransformConstraintTimeline.new (frameCount, bezierCount, transformConstraintIndex)
|
||||||
local ENTRIES = 7
|
local ENTRIES = 7
|
||||||
local ROTATE = 1
|
local ROTATE = 1
|
||||||
local X = 2
|
local X = 2
|
||||||
@ -1813,7 +1845,7 @@ function Animation.TransformConstraintTimeline.new (frameCount, transformConstra
|
|||||||
local SCALEY = 5
|
local SCALEY = 5
|
||||||
local SHEARY = 6
|
local SHEARY = 6
|
||||||
|
|
||||||
local self = Animation.CurveTimeline.new(frameCount, bezierCount, { Property.transformConstraint + "|" + transformConstraintIndex })
|
local self = Animation.CurveTimeline.new(TimelineType.transformConstraint, ENTRIES, frameCount, bezierCount, { Property.transformConstraint.."|"..transformConstraintIndex })
|
||||||
self.transformConstraintIndex = transformConstraintIndex
|
self.transformConstraintIndex = transformConstraintIndex
|
||||||
|
|
||||||
function self:getFrameEntries ()
|
function self:getFrameEntries ()
|
||||||
@ -1918,7 +1950,7 @@ end
|
|||||||
|
|
||||||
Animation.PathConstraintPositionTimeline = {}
|
Animation.PathConstraintPositionTimeline = {}
|
||||||
function Animation.PathConstraintPositionTimeline.new (frameCount, bezierCount, pathConstraintIndex)
|
function Animation.PathConstraintPositionTimeline.new (frameCount, bezierCount, pathConstraintIndex)
|
||||||
local self = Animation.CurveTimeline1.new(frameCount, bezierCount, Property.pathConstraintPosition.."|"..pathConstraintIndex)
|
local self = Animation.CurveTimeline1.new(TimelineType.pathConstraintPosition, frameCount, bezierCount, Property.pathConstraintPosition.."|"..pathConstraintIndex)
|
||||||
self.pathConstraintIndex = pathConstraintIndex
|
self.pathConstraintIndex = pathConstraintIndex
|
||||||
|
|
||||||
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
||||||
@ -1948,7 +1980,7 @@ end
|
|||||||
|
|
||||||
Animation.PathConstraintSpacingTimeline = {}
|
Animation.PathConstraintSpacingTimeline = {}
|
||||||
function Animation.PathConstraintSpacingTimeline.new (frameCount, bezierCount, pathConstraintIndex)
|
function Animation.PathConstraintSpacingTimeline.new (frameCount, bezierCount, pathConstraintIndex)
|
||||||
local self = Animation.CurveTimeline1.new(frameCount, bezierCount, Property.pathConstraintSpacing.."|"..pathConstraintIndex)
|
local self = Animation.CurveTimeline1.new(TimelineType.pathConstraintSpacing, frameCount, bezierCount, Property.pathConstraintSpacing.."|"..pathConstraintIndex)
|
||||||
self.pathConstraintIndex = pathConstraintIndex
|
self.pathConstraintIndex = pathConstraintIndex
|
||||||
|
|
||||||
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
function self:apply (skeleton, lastTime, time, events, alpha, blend, direction)
|
||||||
@ -1983,7 +2015,7 @@ function Animation.PathConstraintMixTimeline.new (frameCount, bezierCount, pathC
|
|||||||
local X = 2
|
local X = 2
|
||||||
local Y = 3
|
local Y = 3
|
||||||
|
|
||||||
local self = Animation.CurveTimeline.new(frameCount, bezierCount, Property.pathConstraintMix.."|"..pathConstraintIndex)
|
local self = Animation.CurveTimeline.new(TimelineType.pathConstraintMix, ENTRIES, frameCount, bezierCount, Property.pathConstraintMix.."|"..pathConstraintIndex)
|
||||||
self.pathConstraintIndex = pathConstraintIndex
|
self.pathConstraintIndex = pathConstraintIndex
|
||||||
|
|
||||||
function self:getFrameEntries ()
|
function self:getFrameEntries ()
|
||||||
@ -2006,13 +2038,13 @@ function Animation.PathConstraintMixTimeline.new (frameCount, bezierCount, pathC
|
|||||||
local frames = self.frames
|
local frames = self.frames
|
||||||
if time < frames[0] then
|
if time < frames[0] then
|
||||||
if blend == MixBlend.setup then
|
if blend == MixBlend.setup then
|
||||||
constraint.mixRotate = constraint.data.mixRotate;
|
constraint.mixRotate = constraint.data.mixRotate
|
||||||
constraint.mixX = constraint.data.mixX;
|
constraint.mixX = constraint.data.mixX
|
||||||
constraint.mixY = constraint.data.mixY;
|
constraint.mixY = constraint.data.mixY
|
||||||
elseif blend == MixBlend.first then
|
elseif blend == MixBlend.first then
|
||||||
constraint.mixRotate = constraint.mixRotate + (constraint.data.mixRotate - constraint.mixRotate) * alpha;
|
constraint.mixRotate = constraint.mixRotate + (constraint.data.mixRotate - constraint.mixRotate) * alpha
|
||||||
constraint.mixX = constraint.mixX + (constraint.data.mixX - constraint.mixX) * alpha;
|
constraint.mixX = constraint.mixX + (constraint.data.mixX - constraint.mixX) * alpha
|
||||||
constraint.mixY = constraint.mixY + (constraint.data.mixY - constraint.mixY) * alpha;
|
constraint.mixY = constraint.mixY + (constraint.data.mixY - constraint.mixY) * alpha
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -2020,36 +2052,36 @@ function Animation.PathConstraintMixTimeline.new (frameCount, bezierCount, pathC
|
|||||||
local rotate
|
local rotate
|
||||||
local x
|
local x
|
||||||
local y
|
local y
|
||||||
local i = search(frames, time, ENTRIES);
|
local i = search(frames, time, ENTRIES)
|
||||||
local curveType = self.curves[math_floor(i / 4)];
|
local curveType = self.curves[math_floor(i / 4)]
|
||||||
if curveType == LINEAR then
|
if curveType == LINEAR then
|
||||||
local before = frames[i];
|
local before = frames[i]
|
||||||
rotate = frames[i + ROTATE];
|
rotate = frames[i + ROTATE]
|
||||||
x = frames[i + X];
|
x = frames[i + X]
|
||||||
y = frames[i + Y];
|
y = frames[i + Y]
|
||||||
local t = (time - before) / (frames[i + ENTRIES] - before);
|
local t = (time - before) / (frames[i + ENTRIES] - before)
|
||||||
rotate = rotate + (frames[i + ENTRIES + ROTATE] - rotate) * t;
|
rotate = rotate + (frames[i + ENTRIES + ROTATE] - rotate) * t
|
||||||
x = x + (frames[i + ENTRIES + X] - x) * t;
|
x = x + (frames[i + ENTRIES + X] - x) * t
|
||||||
y = y + (frames[i + ENTRIES + Y] - y) * t;
|
y = y + (frames[i + ENTRIES + Y] - y) * t
|
||||||
elseif curveType == STEPPED then
|
elseif curveType == STEPPED then
|
||||||
rotate = frames[i + ROTATE];
|
rotate = frames[i + ROTATE]
|
||||||
x = frames[i + X];
|
x = frames[i + X]
|
||||||
y = frames[i + Y];
|
y = frames[i + Y]
|
||||||
else
|
else
|
||||||
rotate = this.getBezierValue(time, i, ROTATE, curveType - BEZIER);
|
rotate = this.getBezierValue(time, i, ROTATE, curveType - BEZIER)
|
||||||
x = this.getBezierValue(time, i, X, curveType + BEZIER_SIZE - BEZIER);
|
x = this.getBezierValue(time, i, X, curveType + BEZIER_SIZE - BEZIER)
|
||||||
y = this.getBezierValue(time, i, Y, curveType + BEZIER_SIZE * 2 - BEZIER);
|
y = this.getBezierValue(time, i, Y, curveType + BEZIER_SIZE * 2 - BEZIER)
|
||||||
end
|
end
|
||||||
|
|
||||||
if blend == MixBlend.setup then
|
if blend == MixBlend.setup then
|
||||||
local data = constraint.data;
|
local data = constraint.data
|
||||||
constraint.mixRotate = data.mixRotate + (rotate - data.mixRotate) * alpha;
|
constraint.mixRotate = data.mixRotate + (rotate - data.mixRotate) * alpha
|
||||||
constraint.mixX = data.mixX + (x - data.mixX) * alpha;
|
constraint.mixX = data.mixX + (x - data.mixX) * alpha
|
||||||
constraint.mixY = data.mixY + (y - data.mixY) * alpha;
|
constraint.mixY = data.mixY + (y - data.mixY) * alpha
|
||||||
else
|
else
|
||||||
constraint.mixRotate = constraint.mixRotate + (rotate - constraint.mixRotate) * alpha;
|
constraint.mixRotate = constraint.mixRotate + (rotate - constraint.mixRotate) * alpha
|
||||||
constraint.mixX = constraint.mixX + (x - constraint.mixX) * alpha;
|
constraint.mixX = constraint.mixX + (x - constraint.mixX) * alpha
|
||||||
constraint.mixY = constraint.mixY + (y - constraint.mixY) * alpha;
|
constraint.mixY = constraint.mixY + (y - constraint.mixY) * alpha
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -198,12 +198,22 @@ function TrackEntry:getAnimationTime ()
|
|||||||
return math_min(self.trackTime + self.animationStart, self.animationEnd)
|
return math_min(self.trackTime + self.animationStart, self.animationEnd)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function TrackEntry:getTrackComplete ()
|
||||||
|
local duration = self.animationEnd - self.animationStart
|
||||||
|
if duration ~= 0 then
|
||||||
|
if self.loop then return duration * (1 + math_floor(self.trackTime / duration)) end -- Completion of next loop.
|
||||||
|
if self.trackTime < duration then return duration end -- Before duration.
|
||||||
|
end
|
||||||
|
return self.trackTime -- Next update.
|
||||||
|
end
|
||||||
|
|
||||||
function TrackEntry:resetRotationDirections ()
|
function TrackEntry:resetRotationDirections ()
|
||||||
self.timelinesRotation = {}
|
self.timelinesRotation = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
local AnimationState = {}
|
local AnimationState = {}
|
||||||
AnimationState.__index = AnimationState
|
AnimationState.__index = AnimationState
|
||||||
|
AnimationState.TrackEntry = TrackEntry
|
||||||
|
|
||||||
function AnimationState.new (data)
|
function AnimationState.new (data)
|
||||||
if not data then error("data cannot be nil", 2) end
|
if not data then error("data cannot be nil", 2) end
|
||||||
@ -225,8 +235,6 @@ function AnimationState.new (data)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
AnimationState.TrackEntry = TrackEntry
|
|
||||||
|
|
||||||
function AnimationState:update (delta)
|
function AnimationState:update (delta)
|
||||||
delta = delta * self.timeScale
|
delta = delta * self.timeScale
|
||||||
local tracks = self.tracks
|
local tracks = self.tracks
|
||||||
@ -359,31 +367,35 @@ function AnimationState:apply (skeleton)
|
|||||||
-- Apply current entry.
|
-- Apply current entry.
|
||||||
local animationLast = current.animationLast
|
local animationLast = current.animationLast
|
||||||
local animationTime = current:getAnimationTime()
|
local animationTime = current:getAnimationTime()
|
||||||
|
local applyTime = animationTime
|
||||||
|
local applyEvents = self.events
|
||||||
|
if current.reverse then
|
||||||
|
applyTime = current.animation.duration - applyTime
|
||||||
|
applyEvents = nil
|
||||||
|
end
|
||||||
local timelines = current.animation.timelines
|
local timelines = current.animation.timelines
|
||||||
if (i == 0 and mix == 1) or blend == MixBlend.add then
|
if (i == 0 and mix == 1) or blend == MixBlend.add then
|
||||||
for i,timeline in ipairs(timelines) do
|
for i,timeline in ipairs(timelines) do
|
||||||
if timeline.type == Animation.TimelineType.attachment then
|
if timeline.type == Animation.TimelineType.attachment then
|
||||||
self:applyAttachmentTimeline(timeline, skeleton, animationTime, blend, true)
|
self:applyAttachmentTimeline(timeline, skeleton, applyTime, blend, true)
|
||||||
else
|
else
|
||||||
timeline:apply(skeleton, animationLast, animationTime, self.events, mix, blend, MixDirection.mixIn)
|
timeline:apply(skeleton, animationLast, applyTime, applyEvents, mix, blend, MixDirection.mixIn)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local timelineMode = current.timelineMode
|
local timelineMode = current.timelineMode
|
||||||
local firstFrame = #current.timelinesRotation == 0
|
local firstFrame = #current.timelinesRotation ~= #timelines * 2
|
||||||
local timelinesRotation = current.timelinesRotation
|
|
||||||
|
|
||||||
for ii,timeline in ipairs(timelines) do
|
for ii,timeline in ipairs(timelines) do
|
||||||
local timelineBlend = MixBlend.setup
|
local timelineBlend = MixBlend.setup
|
||||||
if timelineMode[ii] == SUBSEQUENT then timelineBlend = blend end
|
if timelineMode[ii] == SUBSEQUENT then timelineBlend = blend end
|
||||||
|
|
||||||
if timeline.type == Animation.TimelineType.rotate then
|
if timeline.type == Animation.TimelineType.rotate then
|
||||||
self:applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii * 2,
|
self:applyRotateTimeline(timeline, skeleton, applyTime, mix, timelineBlend, current.timelinesRotation, ii * 2, firstFrame)
|
||||||
firstFrame)
|
|
||||||
elseif timeline.type == Animation.TimelineType.attachment then
|
elseif timeline.type == Animation.TimelineType.attachment then
|
||||||
self:applyAttachmentTimeline(timeline, skeleton, animationTime, timelineBlend, true)
|
self:applyAttachmentTimeline(timeline, skeleton, applyTime, timelineBlend, true)
|
||||||
else
|
else
|
||||||
timeline:apply(skeleton, animationLast, animationTime, self.events, mix, timelineBlend, MixDirection.mixIn)
|
timeline:apply(skeleton, animationLast, applyTime, applyEvents, mix, timelineBlend, MixDirection.mixIn)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -401,7 +413,7 @@ function AnimationState:apply (skeleton)
|
|||||||
-- the time is before the first key).
|
-- the time is before the first key).
|
||||||
local setupState = self.unkeyedState + SETUP
|
local setupState = self.unkeyedState + SETUP
|
||||||
local slots = skeleton.slots
|
local slots = skeleton.slots
|
||||||
for _, slot in ipairs(slots) do
|
for _,slot in ipairs(slots) do
|
||||||
if slot.attachmentState == setupState then
|
if slot.attachmentState == setupState then
|
||||||
local attachmentName = slot.data.attachmentName
|
local attachmentName = slot.data.attachmentName
|
||||||
if attachmentName == nil then
|
if attachmentName == nil then
|
||||||
@ -432,25 +444,31 @@ function AnimationState:applyMixingFrom (to, skeleton, blend)
|
|||||||
if blend ~= MixBlend.first then blend = from.mixBlend end
|
if blend ~= MixBlend.first then blend = from.mixBlend end
|
||||||
end
|
end
|
||||||
|
|
||||||
local events = nil
|
|
||||||
if mix < from.eventThreshold then events = self.events end
|
|
||||||
local attachments = mix < from.attachmentThreshold
|
local attachments = mix < from.attachmentThreshold
|
||||||
local drawOrder = mix < from.drawOrderThreshold
|
local drawOrder = mix < from.drawOrderThreshold
|
||||||
local animationLast = from.animationLast
|
|
||||||
local animationTime = from:getAnimationTime()
|
|
||||||
local timelines = from.animation.timelines
|
local timelines = from.animation.timelines
|
||||||
local alphaHold = from.alpha * to.interruptAlpha
|
local alphaHold = from.alpha * to.interruptAlpha
|
||||||
local alphaMix = alphaHold * (1 - mix)
|
local alphaMix = alphaHold * (1 - mix)
|
||||||
|
local animationLast = from.animationLast
|
||||||
|
local animationTime = from:getAnimationTime()
|
||||||
|
local applyTime = animationTime
|
||||||
|
local events = nil
|
||||||
|
if from.reverse then
|
||||||
|
applyTime = from.animation.duration - applyTime
|
||||||
|
elseif mix < from.eventThreshold then
|
||||||
|
events = self.events
|
||||||
|
end
|
||||||
|
|
||||||
if blend == MixBlend.add then
|
if blend == MixBlend.add then
|
||||||
for i,timeline in ipairs(timelines) do
|
for i,timeline in ipairs(timelines) do
|
||||||
timeline:apply(skeleton, animationLast, animationTime, events, alphaMix, blend, MixDirection.mixOut)
|
timeline:apply(skeleton, animationLast, applyTime, events, alphaMix, blend, MixDirection.mixOut)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local timelineMode = from.timelineMode
|
local timelineMode = from.timelineMode
|
||||||
local timelineHoldMix = from.timelineHoldMix
|
local timelineHoldMix = from.timelineHoldMix
|
||||||
|
|
||||||
local firstFrame = #from.timelinesRotation == 0
|
local firstFrame = #from.timelinesRotation ~= #timelines
|
||||||
local timelinesRotation = from.timelinesRotation
|
local timelinesRotation = from.timelinesRotation
|
||||||
|
|
||||||
from.totalAlpha = 0
|
from.totalAlpha = 0
|
||||||
@ -473,7 +491,7 @@ function AnimationState:applyMixingFrom (to, skeleton, blend)
|
|||||||
elseif timelineMode[i] == HOLD_FIRST then
|
elseif timelineMode[i] == HOLD_FIRST then
|
||||||
timelineBlend = MixBlend.setup
|
timelineBlend = MixBlend.setup
|
||||||
alpha = alphaHold
|
alpha = alphaHold
|
||||||
else
|
else -- HOLD_MIX
|
||||||
timelineBlend = MixBlend.setup
|
timelineBlend = MixBlend.setup
|
||||||
local holdMix = timelineHoldMix[i]
|
local holdMix = timelineHoldMix[i]
|
||||||
alpha = alphaHold * math_max(0, 1 - holdMix.mixtime / holdMix.mixDuration)
|
alpha = alphaHold * math_max(0, 1 - holdMix.mixtime / holdMix.mixDuration)
|
||||||
@ -482,14 +500,14 @@ function AnimationState:applyMixingFrom (to, skeleton, blend)
|
|||||||
if not skipSubsequent then
|
if not skipSubsequent then
|
||||||
from.totalAlpha = from.totalAlpha + alpha
|
from.totalAlpha = from.totalAlpha + alpha
|
||||||
if timeline.type == Animation.TimelineType.rotate then
|
if timeline.type == Animation.TimelineType.rotate then
|
||||||
self:applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i * 2, firstFrame)
|
self:applyRotateTimeline(timeline, skeleton, applyTime, alpha, timelineBlend, timelinesRotation, i * 2, firstFrame)
|
||||||
elseif timeline.type == Animation.TimelineType.attachment then
|
elseif timeline.type == Animation.TimelineType.attachment then
|
||||||
self:applyAttachmentTimeline(timeline, skeleton, animationTime, timelineBlend, attachments)
|
self:applyAttachmentTimeline(timeline, skeleton, applyTime, timelineBlend, attachments)
|
||||||
else
|
else
|
||||||
if drawOrder and timeline.type == Animation.TimelineType.drawOrder and timelineBlend == MixBlend.setup then
|
if drawOrder and timeline.type == Animation.TimelineType.drawOrder and timelineBlend == MixBlend.setup then
|
||||||
direction = MixDirection.mixIn
|
direction = MixDirection.mixIn
|
||||||
end
|
end
|
||||||
timeline:apply(skeleton, animationLast, animationTime, self.events, alpha, timelineBlend, direction)
|
timeline:apply(skeleton, animationLast, applyTime, events, alpha, timelineBlend, direction)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -509,19 +527,12 @@ function AnimationState:applyAttachmentTimeline(timeline, skeleton, time, blend,
|
|||||||
local slot = skeleton.slots[timeline.slotIndex]
|
local slot = skeleton.slots[timeline.slotIndex]
|
||||||
if slot.bone.active == false then return end
|
if slot.bone.active == false then return end
|
||||||
|
|
||||||
local frames = timeline.frames
|
if time < timeline.frames[0] then -- Time is before first frame.
|
||||||
if time < frames[0] then -- Time is before first frame.
|
|
||||||
if blend == MixBlend.setup or blend == MixBlend.first then
|
if blend == MixBlend.setup or blend == MixBlend.first then
|
||||||
self:setAttachment(skeleton, slot, slot.data.attachmentName, attachments)
|
self:setAttachment(skeleton, slot, slot.data.attachmentName, attachments)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local frameIndex = 0
|
self:setAttachment(skeleton, slot, timeline.attachmentNames[Timeline.search1(timeline.frames, time)], attachments)
|
||||||
if time >= frames[zlen(frames) - 1] then -- Time is after last frame.
|
|
||||||
frameIndex = zlen(frames) - 1
|
|
||||||
else
|
|
||||||
frameIndex = Animation.binarySearch(frames, time, 1) - 1
|
|
||||||
end
|
|
||||||
self:setAttachment(skeleton, slot, timeline.attachmentNames[frameIndex], attachments)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- If an attachment wasn't set (ie before the first frame or attachments is false), set the setup attachment later.
|
-- If an attachment wasn't set (ie before the first frame or attachments is false), set the setup attachment later.
|
||||||
@ -548,10 +559,9 @@ function AnimationState:applyRotateTimeline (timeline, skeleton, time, alpha, bl
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local rotateTimeline = timeline
|
local bone = skeleton.bones[timeline.boneIndex]
|
||||||
local frames = rotateTimeline.frames
|
|
||||||
local bone = skeleton.bones[rotateTimeline.boneIndex]
|
|
||||||
if not bone.active then return end
|
if not bone.active then return end
|
||||||
|
local frames = timeline.frames
|
||||||
local r1 = 0
|
local r1 = 0
|
||||||
local r2 = 0
|
local r2 = 0
|
||||||
if time < frames[0] then
|
if time < frames[0] then
|
||||||
@ -570,21 +580,7 @@ function AnimationState:applyRotateTimeline (timeline, skeleton, time, alpha, bl
|
|||||||
else
|
else
|
||||||
r1 = bone.rotation
|
r1 = bone.rotation
|
||||||
end
|
end
|
||||||
if time >= frames[zlen(frames) - Animation.RotateTimeline.ENTRIES] then -- Time is after last frame.
|
r2 = bone.data.rotation + timeline:getCurveValue(time)
|
||||||
r2 = bone.data.rotation + frames[zlen(frames) + Animation.RotateTimeline.PREV_ROTATION]
|
|
||||||
else
|
|
||||||
-- Interpolate between the previous frame and the current frame.
|
|
||||||
local frame = Animation.binarySearch(frames, time, Animation.RotateTimeline.ENTRIES)
|
|
||||||
local prevRotation = frames[frame + Animation.RotateTimeline.PREV_ROTATION]
|
|
||||||
local frameTime = frames[frame]
|
|
||||||
local percent = rotateTimeline:getCurvePercent(math_floor(frame / 2) - 1,
|
|
||||||
1 - (time - frameTime) / (frames[frame + Animation.RotateTimeline.PREV_TIME] - frameTime))
|
|
||||||
|
|
||||||
r2 = frames[frame + Animation.RotateTimeline.ROTATION] - prevRotation
|
|
||||||
r2 = r2 - (16384 - math_floor(16384.499999999996 - r2 / 360)) * 360
|
|
||||||
r2 = prevRotation + r2 * percent + bone.data.rotation
|
|
||||||
r2 = r2 - (16384 - math_floor(16384.499999999996 - r2 / 360)) * 360
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Mix between rotations using the direction of the shortest route on the first frame while detecting crosses.
|
-- Mix between rotations using the direction of the shortest route on the first frame while detecting crosses.
|
||||||
@ -616,8 +612,7 @@ function AnimationState:applyRotateTimeline (timeline, skeleton, time, alpha, bl
|
|||||||
timelinesRotation[i] = total
|
timelinesRotation[i] = total
|
||||||
end
|
end
|
||||||
timelinesRotation[i + 1] = diff
|
timelinesRotation[i + 1] = diff
|
||||||
r1 = r1 + total * alpha
|
bone.rotation = r1 + total * alpha
|
||||||
bone.rotation = r1 - (16384 - math_floor(16384.499999999996 - r1 / 360)) * 360
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function AnimationState:queueEvents (entry, animationTime)
|
function AnimationState:queueEvents (entry, animationTime)
|
||||||
@ -654,7 +649,7 @@ function AnimationState:queueEvents (entry, animationTime)
|
|||||||
-- Queue events after complete.
|
-- Queue events after complete.
|
||||||
while i <= n do
|
while i <= n do
|
||||||
local event = events[i]
|
local event = events[i]
|
||||||
if not (event.time < animationStart) then --// Discard events outside animation start/end.
|
if event.time >= animationStart then -- Discard events outside animation start/end.
|
||||||
queue:event(entry, event)
|
queue:event(entry, event)
|
||||||
end
|
end
|
||||||
i = i + 1
|
i = i + 1
|
||||||
@ -701,14 +696,17 @@ function AnimationState:clearTrack (trackIndex)
|
|||||||
queue:drain()
|
queue:drain()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function AnimationState:clearNext (entry)
|
||||||
|
self:disposeNext(entry.next)
|
||||||
|
end
|
||||||
|
|
||||||
function AnimationState:setCurrent (index, current, interrupt)
|
function AnimationState:setCurrent (index, current, interrupt)
|
||||||
local from = self:expandToIndex(index)
|
local from = self:expandToIndex(index)
|
||||||
local tracks = self.tracks
|
self.tracks[index] = current
|
||||||
local queue = self.queue
|
current.previous = nil
|
||||||
tracks[index] = current
|
|
||||||
|
|
||||||
if from then
|
if from then
|
||||||
if interrupt then queue:interrupt(from) end
|
if interrupt then self.queue:interrupt(from) end
|
||||||
current.mixingFrom = from
|
current.mixingFrom = from
|
||||||
from.mixingTo = current
|
from.mixingTo = current
|
||||||
current.mixTime = 0
|
current.mixTime = 0
|
||||||
@ -720,7 +718,7 @@ function AnimationState:setCurrent (index, current, interrupt)
|
|||||||
from.timelinesRotation = {}
|
from.timelinesRotation = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
queue:start(current)
|
self.queue:start(current)
|
||||||
end
|
end
|
||||||
|
|
||||||
function AnimationState:setAnimationByName (trackIndex, animationName, loop)
|
function AnimationState:setAnimationByName (trackIndex, animationName, loop)
|
||||||
@ -779,19 +777,8 @@ function AnimationState:addAnimation (trackIndex, animation, loop, delay)
|
|||||||
queue:drain()
|
queue:drain()
|
||||||
else
|
else
|
||||||
last.next = entry
|
last.next = entry
|
||||||
if delay <= 0 then
|
entry.previous = last
|
||||||
local duration = last.animationEnd - last.animationStart
|
if delay <= 0 then delay = delay + last:getTrackComplete() - entry.mixDuration end
|
||||||
if duration ~= 0 then
|
|
||||||
if last.loop then
|
|
||||||
delay = delay + duration * (1 + math_floor(last.trackTime / duration))
|
|
||||||
else
|
|
||||||
delay = delay + math_max(duration, last.trackTime)
|
|
||||||
end
|
|
||||||
delay = delay - data:getMix(last.animation, animation)
|
|
||||||
else
|
|
||||||
delay = last.trackTime
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
entry.delay = delay
|
entry.delay = delay
|
||||||
@ -806,10 +793,14 @@ function AnimationState:setEmptyAnimation (trackIndex, mixDuration)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function AnimationState:addEmptyAnimation (trackIndex, mixDuration, delay)
|
function AnimationState:addEmptyAnimation (trackIndex, mixDuration, delay)
|
||||||
if delay <= 0 then delay = delay - mixDuration end
|
local addDelay = 1
|
||||||
local entry = self:addAnimation(trackIndex, EMPTY_ANIMATION, false, delay)
|
if delay > 0 then addDelay = delay end
|
||||||
|
local entry = self:addAnimation(trackIndex, EMPTY_ANIMATION, false, addDelay)
|
||||||
entry.mixDuration = mixDuration
|
entry.mixDuration = mixDuration
|
||||||
entry.trackEnd = mixDuration
|
entry.trackEnd = mixDuration
|
||||||
|
if delay <= 0 and entry.previous then
|
||||||
|
entry.delay = entry.previous:getTrackComplete() - entry.mixDuration + delay
|
||||||
|
end
|
||||||
return entry
|
return entry
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -895,28 +886,19 @@ function AnimationState:_animationsChanged ()
|
|||||||
self.animationsChanged = false
|
self.animationsChanged = false
|
||||||
|
|
||||||
self.propertyIDs = {}
|
self.propertyIDs = {}
|
||||||
|
|
||||||
local highestIndex = -1
|
|
||||||
local tracks = self.tracks
|
local tracks = self.tracks
|
||||||
local numTracks = getNumTracks(tracks)
|
|
||||||
local i = 0
|
local i = 0
|
||||||
while i <= numTracks do
|
local n = zlen(tracks)
|
||||||
entry = tracks[i]
|
while i < n do
|
||||||
|
local entry = tracks[i]
|
||||||
if entry then
|
if entry then
|
||||||
if i > highestIndex then highestIndex = i end
|
while entry.mixingFrom do
|
||||||
|
entry = entry.mixingFrom
|
||||||
if entry then
|
|
||||||
while entry.mixingFrom do
|
|
||||||
entry = entry.mixingFrom
|
|
||||||
end
|
|
||||||
|
|
||||||
repeat
|
|
||||||
if entry.mixingTo == nil or entry.mixBlend ~= MixBlend.add then
|
|
||||||
self:computeHold(entry)
|
|
||||||
end
|
|
||||||
entry = entry.mixingTo
|
|
||||||
until (entry == nil)
|
|
||||||
end
|
end
|
||||||
|
repeat
|
||||||
|
if not entry.mixingTo or entry.mixBlend ~= MixBlend.add then self:computeHold(entry) end
|
||||||
|
entry = entry.mixingTo
|
||||||
|
until not entry
|
||||||
end
|
end
|
||||||
i = i + 1
|
i = i + 1
|
||||||
end
|
end
|
||||||
@ -925,57 +907,57 @@ end
|
|||||||
function AnimationState:computeHold(entry)
|
function AnimationState:computeHold(entry)
|
||||||
local to = entry.mixingTo
|
local to = entry.mixingTo
|
||||||
local timelines = entry.animation.timelines
|
local timelines = entry.animation.timelines
|
||||||
local timelinesCount = #entry.animation.timelines
|
|
||||||
local timelineMode = entry.timelineMode
|
local timelineMode = entry.timelineMode
|
||||||
local timelineHoldMix = entry.timelineHoldMix
|
local timelineHoldMix = entry.timelineHoldMix
|
||||||
local propertyIDs = self.propertyIDs
|
local propertyIDs = self.propertyIDs
|
||||||
|
|
||||||
if to and to.holdPrevious then
|
if to and to.holdPrevious then
|
||||||
local i = 1
|
for i,timeline in ipairs(timelines) do
|
||||||
while i <= timelinesCount do
|
local mode = HOLD_SUBSEQUENT
|
||||||
local id = "" .. timelines[i]:getPropertyId()
|
for _,id in ipairs(timeline.propertyIds) do
|
||||||
if propertyIDs[id] == nil then
|
if not propertyIDs[id] then
|
||||||
propertyIDs[id] = id
|
propertyIDs[id] = true
|
||||||
timelineMode[i] = HOLD_FIRST
|
mode = HOLD_FIRST
|
||||||
else
|
end
|
||||||
timelineMode[i] = HOLD_SUBSEQUENT
|
|
||||||
end
|
end
|
||||||
|
timelineMode[i] = mode
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local i = 1
|
for i,timeline in ipairs(timelines) do
|
||||||
local skip
|
local ids = timeline.propertyIds
|
||||||
while i <= timelinesCount do
|
local added = false
|
||||||
local id = "" .. timelines[i]:getPropertyId()
|
for _,id in ipairs(ids) do
|
||||||
if propertyIDs[id] then
|
if not propertyIDs[id] then
|
||||||
timelineMode[i] = SUBSEQUENT
|
propertyIDs[id] = true
|
||||||
else
|
added = true
|
||||||
propertyIDs[id] = id
|
|
||||||
local timeline = timelines[i]
|
|
||||||
if to == nil or timeline.type == Animation.TimelineType.attachment
|
|
||||||
or timeline.type == Animation.TimelineType.drawOrder
|
|
||||||
or timeline.type == Animation.TimelineType.event
|
|
||||||
or not to.animation:hasTimeline(id) then
|
|
||||||
timelineMode[i] = FIRST
|
|
||||||
else
|
|
||||||
local next = to.mixingTo
|
|
||||||
skip = false
|
|
||||||
while next do
|
|
||||||
if not next.animation:hasTimeline(id) then
|
|
||||||
if entry.mixDuration > 0 then
|
|
||||||
timelineMode[i] = HOLD_MIX
|
|
||||||
timelineHoldMix[i] = next
|
|
||||||
skip = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
next = next.mixingTo
|
|
||||||
end
|
|
||||||
if not skip then timelineMode[i] = HOLD_FIRST end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
i = i + 1
|
if not added then
|
||||||
|
timelineMode[i] = SUBSEQUENT
|
||||||
|
elseif not to
|
||||||
|
or timeline.type == Animation.TimelineType.attachment
|
||||||
|
or timeline.type == Animation.TimelineType.drawOrder
|
||||||
|
or timeline.type == Animation.TimelineType.event
|
||||||
|
or not to.animation:hasTimeline(ids) then
|
||||||
|
timelineMode[i] = FIRST
|
||||||
|
else
|
||||||
|
local next = to.mixingTo
|
||||||
|
local set
|
||||||
|
while next do
|
||||||
|
if not next.animation:hasTimeline(ids) then
|
||||||
|
if next.mixDuration > 0 then
|
||||||
|
timelineMode[i] = HOLD_MIX
|
||||||
|
timelineHoldMix[i] = next
|
||||||
|
set = true
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
next = next.mixingTo
|
||||||
|
end
|
||||||
|
if not set then timelineMode[i] = HOLD_FIRST end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1,104 +0,0 @@
|
|||||||
-------------------------------------------------------------------------------
|
|
||||||
-- Spine Runtimes License Agreement
|
|
||||||
-- Last updated January 1, 2020. Replaces all prior versions.
|
|
||||||
--
|
|
||||||
-- Copyright (c) 2013-2020, Esoteric Software LLC
|
|
||||||
--
|
|
||||||
-- Integration of the Spine Runtimes into software or otherwise creating
|
|
||||||
-- derivative works of the Spine Runtimes is permitted under the terms and
|
|
||||||
-- conditions of Section 2 of the Spine Editor License Agreement:
|
|
||||||
-- http://esotericsoftware.com/spine-editor-license
|
|
||||||
--
|
|
||||||
-- Otherwise, it is permitted to integrate the Spine Runtimes into software
|
|
||||||
-- or otherwise create derivative works of the Spine Runtimes (collectively,
|
|
||||||
-- "Products"), provided that each user of the Products must obtain their own
|
|
||||||
-- Spine Editor license and redistribution of the Products in any form must
|
|
||||||
-- include this license and copyright notice.
|
|
||||||
--
|
|
||||||
-- THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "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 LLC 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
|
|
||||||
-- THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
local Atlas = {}
|
|
||||||
|
|
||||||
function Atlas.parse(atlasPath, atlasBase)
|
|
||||||
local function parseIntTuple4( l )
|
|
||||||
local a,b,c,d = string.match( l , " ? ?%a+: ([+-]?%d+), ?([+-]?%d+), ?([+-]?%d+), ?([+-]?%d+)" )
|
|
||||||
a,b,c,d = tonumber( a ), tonumber( b ), tonumber( c ), tonumber( d )
|
|
||||||
return a and b and c and d and {a, b, c ,d}
|
|
||||||
end
|
|
||||||
|
|
||||||
local function parseIntTuple2( l )
|
|
||||||
local a,b = string.match( l , " ? ?%a+: ([+-]?%d+), ?([+-]?%d+)" )
|
|
||||||
a,b = tonumber( a ), tonumber( b )
|
|
||||||
return a and b and {a, b}
|
|
||||||
end
|
|
||||||
|
|
||||||
if not atlasPath then
|
|
||||||
error("Error: " .. atlasPath .. ".atlas" .. " doesn't exist!", 2)
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local atlasLines = spine.utils.readFile( atlasPath, atlasBase )
|
|
||||||
if not atlasLines then
|
|
||||||
error("Error: " .. atlasPath .. ".atlas" .. " unable to read!", 2)
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local pages = {}
|
|
||||||
|
|
||||||
|
|
||||||
local it = string.gmatch(atlasLines, "(.-)\r?\n") -- iterate over lines
|
|
||||||
for l in it do
|
|
||||||
if #l == 0 then
|
|
||||||
l = it()
|
|
||||||
if l then
|
|
||||||
local page = { name = l }
|
|
||||||
l = it()
|
|
||||||
page.size = parseIntTuple2( l )
|
|
||||||
if page.size then
|
|
||||||
l = it()
|
|
||||||
end
|
|
||||||
page.format = string.match( l, "%a+: (.+)" )
|
|
||||||
page.filter = {string.match( it(), "%a+: (.+),(.+)" )}
|
|
||||||
page.wrap = string.match( it(), "%a+: (.+)" )
|
|
||||||
page.regions = {}
|
|
||||||
table.insert( pages, page )
|
|
||||||
else
|
|
||||||
break
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local region = {name = l}
|
|
||||||
|
|
||||||
region.rotate = string.match( it(), "%a+: (.+)" ) == "true"
|
|
||||||
region.xy = parseIntTuple2( it() )
|
|
||||||
region.size = parseIntTuple2( it() )
|
|
||||||
l = it()
|
|
||||||
region.splits = parseIntTuple4(l)
|
|
||||||
if region.splits then
|
|
||||||
l = it()
|
|
||||||
region.pad = parseIntTuple4(l)
|
|
||||||
if region.pad then
|
|
||||||
l = it()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
region.orig = parseIntTuple2( l )
|
|
||||||
region.offset = parseIntTuple2( it() )
|
|
||||||
region.index = tonumber( string.match( it() , "%a+: ([+-]?%d+)" ) )
|
|
||||||
|
|
||||||
table.insert( pages[#pages].regions, region )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return pages
|
|
||||||
end
|
|
||||||
|
|
||||||
return Atlas
|
|
||||||
@ -27,6 +27,8 @@
|
|||||||
-- THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
-- THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
local TransformMode = require "spine-lua.TransformMode"
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
local math_rad = math.rad
|
local math_rad = math.rad
|
||||||
local math_deg = math.deg
|
local math_deg = math.deg
|
||||||
@ -37,19 +39,6 @@ local math_sqrt = math.sqrt
|
|||||||
local math_abs = math.abs
|
local math_abs = math.abs
|
||||||
local math_pi = math.pi
|
local math_pi = math.pi
|
||||||
|
|
||||||
local TransformMode = require "spine-lua.TransformMode"
|
|
||||||
|
|
||||||
function math.sign(x)
|
|
||||||
if x < 0 then
|
|
||||||
return -1
|
|
||||||
elseif x > 0 then
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
local math_sign = math.sign
|
|
||||||
|
|
||||||
local Bone = {}
|
local Bone = {}
|
||||||
Bone.__index = Bone
|
Bone.__index = Bone
|
||||||
|
|
||||||
@ -64,7 +53,6 @@ function Bone.new (data, skeleton, parent)
|
|||||||
children = { },
|
children = { },
|
||||||
x = 0, y = 0, rotation = 0, scaleX = 1, scaleY = 1, shearX = 0, shearY = 0,
|
x = 0, y = 0, rotation = 0, scaleX = 1, scaleY = 1, shearX = 0, shearY = 0,
|
||||||
ax = 0, ay = 0, arotation = 0, ascaleX = 0, ascaleY = 0, ashearX = 0, ashearY = 0,
|
ax = 0, ay = 0, arotation = 0, ascaleX = 0, ascaleY = 0, ashearX = 0, ashearY = 0,
|
||||||
appliedValid = false,
|
|
||||||
|
|
||||||
a = 0, b = 0, worldX = 0, -- a b x
|
a = 0, b = 0, worldX = 0, -- a b x
|
||||||
c = 0, d = 0, worldY = 0, -- c d y
|
c = 0, d = 0, worldY = 0, -- c d y
|
||||||
@ -78,7 +66,7 @@ function Bone.new (data, skeleton, parent)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Bone:update ()
|
function Bone:update ()
|
||||||
self:updateWorldTransformWith(self.x, self.y, self.rotation, self.scaleX, self.scaleY, self.shearX, self.shearY)
|
self:updateWorldTransformWith(self.ax, self.ay, self.arotation, self.ascaleX, self.ascaleY, self.ashearX, self.ashearY)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Bone:updateWorldTransform ()
|
function Bone:updateWorldTransform ()
|
||||||
@ -93,13 +81,12 @@ function Bone:updateWorldTransformWith (x, y, rotation, scaleX, scaleY, shearX,
|
|||||||
self.ascaleY = scaleY
|
self.ascaleY = scaleY
|
||||||
self.ashearX = shearX
|
self.ashearX = shearX
|
||||||
self.ashearY = shearY
|
self.ashearY = shearY
|
||||||
self.appliedValid = true
|
|
||||||
|
|
||||||
local sx = self.skeleton.scaleX
|
local sx = self.skeleton.scaleX
|
||||||
local sy = self.skeleton.scaleY
|
local sy = self.skeleton.scaleY
|
||||||
|
|
||||||
local parent = self.parent
|
local parent = self.parent
|
||||||
if parent == nil then
|
if not parent then
|
||||||
local rotationY = rotation + 90 + shearY
|
local rotationY = rotation + 90 + shearY
|
||||||
local rotationRad = math_rad(rotation + shearX)
|
local rotationRad = math_rad(rotation + shearX)
|
||||||
local rotationYRad = math_rad(rotationY)
|
local rotationYRad = math_rad(rotationY)
|
||||||
@ -225,7 +212,7 @@ end
|
|||||||
|
|
||||||
function Bone:updateAppliedTransform ()
|
function Bone:updateAppliedTransform ()
|
||||||
local parent = self.parent
|
local parent = self.parent
|
||||||
if parent == nil then
|
if not parent then
|
||||||
self.ax = self.worldX
|
self.ax = self.worldX
|
||||||
self.ay = self.worldY
|
self.ay = self.worldY
|
||||||
self.arotation = math_deg(math_atan2(self.c, self.a))
|
self.arotation = math_deg(math_atan2(self.c, self.a))
|
||||||
@ -268,15 +255,11 @@ function Bone:updateAppliedTransform ()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Bone:worldToLocal (world)
|
function Bone:worldToLocal (world)
|
||||||
local a = self.a
|
local invDet = 1 / (self.a * self.d - self.b * self.c)
|
||||||
local b = self.b
|
|
||||||
local c = self.c
|
|
||||||
local d = self.d
|
|
||||||
local invDet = 1 / (a * d - b * c)
|
|
||||||
local x = world[1] - self.worldX
|
local x = world[1] - self.worldX
|
||||||
local y = world[2] - self.worldY
|
local y = world[2] - self.worldY
|
||||||
world[1] = (x * d * invDet - y * b * invDet)
|
world[1] = x * self.d * invDet - y * self.b * invDet
|
||||||
world[2] = (y * a * invDet - x * c * invDet)
|
world[2] = y * self.a * invDet - x * self.c * invDet
|
||||||
return world
|
return world
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -313,7 +296,6 @@ function Bone:rotateWorld (degrees)
|
|||||||
self.b = cos * b - sin * d
|
self.b = cos * b - sin * d
|
||||||
self.c = sin * a + cos * c
|
self.c = sin * a + cos * c
|
||||||
self.d = sin * b + cos * d
|
self.d = sin * b + cos * d
|
||||||
self.appliedValid = false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return Bone
|
return Bone
|
||||||
|
|||||||
@ -76,6 +76,7 @@ function IkConstraint:apply ()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function IkConstraint:update ()
|
function IkConstraint:update ()
|
||||||
|
if self.mix == 0 then return end
|
||||||
local target = self.target
|
local target = self.target
|
||||||
local bones = self.bones
|
local bones = self.bones
|
||||||
local boneCount = #bones
|
local boneCount = #bones
|
||||||
@ -87,9 +88,7 @@ function IkConstraint:update ()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function IkConstraint:apply1 (bone, targetX, targetY, compress, stretch, uniform, alpha)
|
function IkConstraint:apply1 (bone, targetX, targetY, compress, stretch, uniform, alpha)
|
||||||
if not bone.appliedValid then bone:updateAppliedTransform() end
|
|
||||||
local p = bone.parent
|
local p = bone.parent
|
||||||
|
|
||||||
local pa = p.a
|
local pa = p.a
|
||||||
local pb = p.b
|
local pb = p.b
|
||||||
local pc = p.c
|
local pc = p.c
|
||||||
@ -148,12 +147,6 @@ function IkConstraint:apply1 (bone, targetX, targetY, compress, stretch, uniform
|
|||||||
end
|
end
|
||||||
|
|
||||||
function IkConstraint:apply2 (parent, child, targetX, targetY, bendDir, stretch, softness, alpha)
|
function IkConstraint:apply2 (parent, child, targetX, targetY, bendDir, stretch, softness, alpha)
|
||||||
if alpha == 0 then
|
|
||||||
child:updateWorldTransform()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if not parent.appliedValid then parent:updateAppliedTransform() end
|
|
||||||
if not child.appliedValid then child:updateAppliedTransform() end
|
|
||||||
local px = parent.ax
|
local px = parent.ax
|
||||||
local py = parent.ay
|
local py = parent.ay
|
||||||
local psx = parent.ascaleX
|
local psx = parent.ascaleX
|
||||||
|
|||||||
@ -36,7 +36,7 @@ local AttachmentType = require "spine-lua.attachments.AttachmentType"
|
|||||||
local PathConstraintData = require "spine-lua.PathConstraintData"
|
local PathConstraintData = require "spine-lua.PathConstraintData"
|
||||||
local utils = require "spine-lua.utils"
|
local utils = require "spine-lua.utils"
|
||||||
local math_pi = math.pi
|
local math_pi = math.pi
|
||||||
local math_pi2 = math.pi * 2
|
local math_pi2 = math_pi * 2
|
||||||
local math_atan2 = math.atan2
|
local math_atan2 = math.atan2
|
||||||
local math_sqrt = math.sqrt
|
local math_sqrt = math.sqrt
|
||||||
local math_acos = math.acos
|
local math_acos = math.acos
|
||||||
@ -51,10 +51,10 @@ local math_max = math.max
|
|||||||
local PathConstraint = {}
|
local PathConstraint = {}
|
||||||
PathConstraint.__index = PathConstraint
|
PathConstraint.__index = PathConstraint
|
||||||
|
|
||||||
PathConstraint.NONE = -1
|
local NONE = -1
|
||||||
PathConstraint.BEFORE = -2
|
local BEFORE = -2
|
||||||
PathConstraint.AFTER = -3
|
local AFTER = -3
|
||||||
PathConstraint.epsilon = 0.00001
|
local epsilon = 0.00001
|
||||||
|
|
||||||
function PathConstraint.new (data, skeleton)
|
function PathConstraint.new (data, skeleton)
|
||||||
if not data then error("data cannot be nil", 2) end
|
if not data then error("data cannot be nil", 2) end
|
||||||
@ -66,8 +66,9 @@ function PathConstraint.new (data, skeleton)
|
|||||||
target = skeleton:findSlot(data.target.name),
|
target = skeleton:findSlot(data.target.name),
|
||||||
position = data.position,
|
position = data.position,
|
||||||
spacing = data.spacing,
|
spacing = data.spacing,
|
||||||
rotateMix = data.rotateMix,
|
mixRotate = data.mixRotate,
|
||||||
translateMix = data.translateMix,
|
mixX = data.mixX,
|
||||||
|
mixY = data.mixY,
|
||||||
spaces = {},
|
spaces = {},
|
||||||
positions = {},
|
positions = {},
|
||||||
world = {},
|
world = {},
|
||||||
@ -85,81 +86,113 @@ function PathConstraint.new (data, skeleton)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function PathConstraint:apply ()
|
|
||||||
self:update()
|
|
||||||
end
|
|
||||||
|
|
||||||
function PathConstraint:update ()
|
function PathConstraint:update ()
|
||||||
local attachment = self.target.attachment
|
local attachment = self.target.attachment
|
||||||
if not attachment or not (attachment.type == AttachmentType.path) then return end
|
if not attachment or attachment.type ~= AttachmentType.path then return end
|
||||||
|
|
||||||
local rotateMix = self.rotateMix
|
|
||||||
local translateMix = self.translateMix
|
|
||||||
local translate = translateMix > 0
|
|
||||||
local rotate = rotateMix > 0
|
|
||||||
if not translate and not rotate then return end
|
|
||||||
|
|
||||||
|
local mixRotate = self.mixRotate
|
||||||
|
local mixX = self.mixX
|
||||||
|
local mixY = self.mixY
|
||||||
|
if mixRotate == 0 and mixX == 0 and mixY == 0 then return end
|
||||||
|
|
||||||
local data = self.data
|
local data = self.data
|
||||||
local percentSpacing = data.spacingMode == PathConstraintData.SpacingMode.percent
|
|
||||||
local rotateMode = data.rotateMode
|
|
||||||
local tangents = rotateMode == PathConstraintData.RotateMode.tangent
|
local tangents = rotateMode == PathConstraintData.RotateMode.tangent
|
||||||
local scale = rotateMode == PathConstraintData.RotateMode.chainscale
|
local scale = rotateMode == PathConstraintData.RotateMode.chainscale
|
||||||
|
|
||||||
local bones = self.bones
|
local bones = self.bones
|
||||||
local boneCount = #bones
|
local boneCount = #bones
|
||||||
local spacesCount = boneCount + 1
|
local spacesCount = boneCount
|
||||||
if tangents then spacesCount = boneCount end
|
if tangents then spacesCount = spacesCount + 1 end
|
||||||
local spaces = utils.setArraySize(self.spaces, spacesCount)
|
local spaces = utils.setArraySize(self.spaces, spacesCount)
|
||||||
local lengths = nil
|
local lengths = nil
|
||||||
|
if scale then lengths = Utils.setArraySize(this.lengths, boneCount) end
|
||||||
local spacing = self.spacing
|
local spacing = self.spacing
|
||||||
if scale or not percentSpacing then
|
|
||||||
if scale then lengths = utils.setArraySize(self.lengths, boneCount) end
|
if data.spacingMode == PathConstraintData.SpacingMode.percent then
|
||||||
local lengthSpacing = data.spacingMode == PathConstraintData.SpacingMode.length
|
if scale then
|
||||||
local i = 0
|
local i = 0
|
||||||
local n = spacesCount - 1
|
local n = spacesCount - 1
|
||||||
while i < n do
|
while i < n do
|
||||||
local bone = bones[i + 1]
|
local bone = bones[i]
|
||||||
local setupLength = bone.data.length
|
local setupLength = bone.data.length
|
||||||
if setupLength < PathConstraint.epsilon then
|
if setupLength < epsilon then
|
||||||
if scale then lengths[i + 1] = 0 end
|
lengths[i] = 0
|
||||||
i = i + 1
|
else
|
||||||
spaces[i + 1] = 0
|
|
||||||
elseif percentSpacing then
|
|
||||||
if scale then
|
|
||||||
local x = setupLength * bone.a
|
local x = setupLength * bone.a
|
||||||
local y = setupLength * bone.c
|
local y = setupLength * bone.c
|
||||||
local length = math_sqrt(x * x + y * y)
|
lengths[i] = math_sqrt(x * x + y * y)
|
||||||
lengths[i + 1] = length
|
|
||||||
end
|
end
|
||||||
i = i + 1
|
i = i + 1
|
||||||
spaces[i + 1] = spacing
|
end
|
||||||
|
end
|
||||||
|
local i = 1
|
||||||
|
while i < spacesCount do
|
||||||
|
spaces[i] = spacing
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
elseif data.spacingMode == PathConstraintData.SpacingMode.proportional then
|
||||||
|
local sum = 0
|
||||||
|
local i = 0
|
||||||
|
while i < boneCount do
|
||||||
|
local bone = bones[i]
|
||||||
|
local setupLength = bone.data.length
|
||||||
|
if setupLength < epsilon then
|
||||||
|
if scale then lengths[i] = 0 end
|
||||||
|
i = i + 1
|
||||||
|
spaces[i] = spacing
|
||||||
else
|
else
|
||||||
local x = setupLength * bone.a
|
local x = setupLength * bone.a
|
||||||
local y = setupLength * bone.c
|
local y = setupLength * bone.c
|
||||||
local length = math_sqrt(x * x + y * y)
|
local length = math_sqrt(x * x + y * y)
|
||||||
if scale then lengths[i + 1] = length end
|
if scale then lengths[i] = length end
|
||||||
|
i = i + 1
|
||||||
|
spaces[i] = length
|
||||||
|
sum = sum + length
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if sum > 0 then
|
||||||
|
sum = spacesCount / sum * spacing
|
||||||
|
local i = 1
|
||||||
|
while i < spacesCount do
|
||||||
|
spaces[i] = spaces[i] * sum
|
||||||
i = i + 1
|
i = i + 1
|
||||||
if lengthSpacing then
|
|
||||||
spaces[i + 1] = (setupLength + spacing) * length / setupLength
|
|
||||||
else
|
|
||||||
spaces[i + 1] = spacing * length / setupLength
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
local lengthSpacing = data.spacingMode == PathConstraintData.SpacingMode.length
|
||||||
local i = 1
|
local i = 1
|
||||||
while i < spacesCount do
|
local n = spacesCount - 1
|
||||||
spaces[i + 1] = spacing
|
while i < n do
|
||||||
i = i + 1
|
local bone = bones[i]
|
||||||
|
local setupLength = bone.data.length
|
||||||
|
if setupLength < epsilon then
|
||||||
|
if scale then lengths[i] = 0 end
|
||||||
|
i = i + 1
|
||||||
|
spaces[i] = spacing
|
||||||
|
else
|
||||||
|
local x = setupLength * bone.a
|
||||||
|
local y = setupLength * bone.c
|
||||||
|
local length = math_sqrt(x * x + y * y)
|
||||||
|
if scale then lengths[i] = length end
|
||||||
|
i = i + 1
|
||||||
|
local s
|
||||||
|
if lengthSpacing then
|
||||||
|
s = setupLength + spacing
|
||||||
|
else
|
||||||
|
s = spacing
|
||||||
|
end
|
||||||
|
spaces[i] = s * length / setupLength
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local positions = self:computeWorldPositions(attachment, spacesCount, tangents, data.positionMode == PathConstraintData.PositionMode.percent, percentSpacing)
|
local positions = self:computeWorldPositions(attachment, spacesCount, tangents)
|
||||||
local boneX = positions[1]
|
local boneX = positions[1]
|
||||||
local boneY = positions[2]
|
local boneY = positions[2]
|
||||||
local offsetRotation = data.offsetRotation
|
local offsetRotation = data.offsetRotation
|
||||||
local tip = false
|
local tip = false
|
||||||
if offsetRotation == 0 then
|
if offsetRotation == 0 then
|
||||||
tip = rotateMode == PathConstraintData.RotateMode.chain
|
tip = data.rotateMode == PathConstraintData.RotateMode.chain
|
||||||
else
|
else
|
||||||
tip = false
|
tip = false
|
||||||
local p = self.target.bone
|
local p = self.target.bone
|
||||||
@ -174,8 +207,8 @@ function PathConstraint:update ()
|
|||||||
local p = 3
|
local p = 3
|
||||||
while i < boneCount do
|
while i < boneCount do
|
||||||
local bone = bones[i + 1]
|
local bone = bones[i + 1]
|
||||||
bone.worldX = bone.worldX + (boneX - bone.worldX) * translateMix
|
bone.worldX = bone.worldX + (boneX - bone.worldX) * mixX
|
||||||
bone.worldY = bone.worldY + (boneY - bone.worldY) * translateMix
|
bone.worldY = bone.worldY + (boneY - bone.worldY) * mixY
|
||||||
local x = positions[p + 1]
|
local x = positions[p + 1]
|
||||||
local y = positions[p + 2]
|
local y = positions[p + 2]
|
||||||
local dx = x - boneX
|
local dx = x - boneX
|
||||||
@ -183,14 +216,14 @@ function PathConstraint:update ()
|
|||||||
if scale then
|
if scale then
|
||||||
local length = lengths[i + 1]
|
local length = lengths[i + 1]
|
||||||
if length ~= 0 then
|
if length ~= 0 then
|
||||||
local s = (math_sqrt(dx * dx + dy * dy) / length - 1) * rotateMix + 1
|
local s = (math_sqrt(dx * dx + dy * dy) / length - 1) * mixRotate + 1
|
||||||
bone.a = bone.a * s
|
bone.a = bone.a * s
|
||||||
bone.c = bone.c * s
|
bone.c = bone.c * s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
boneX = x
|
boneX = x
|
||||||
boneY = y
|
boneY = y
|
||||||
if rotate then
|
if mixRotate then
|
||||||
local a = bone.a
|
local a = bone.a
|
||||||
local b = bone.b
|
local b = bone.b
|
||||||
local c = bone.c
|
local c = bone.c
|
||||||
@ -210,8 +243,8 @@ function PathConstraint:update ()
|
|||||||
cos = math_cos(r)
|
cos = math_cos(r)
|
||||||
sin = math_sin(r)
|
sin = math_sin(r)
|
||||||
local length = bone.data.length
|
local length = bone.data.length
|
||||||
boneX = boneX + (length * (cos * a - sin * c) - dx) * rotateMix
|
boneX = boneX + (length * (cos * a - sin * c) - dx) * mixRotate
|
||||||
boneY = boneY + (length * (sin * a + cos * c) - dy) * rotateMix
|
boneY = boneY + (length * (sin * a + cos * c) - dy) * mixRotate
|
||||||
else
|
else
|
||||||
r = r + offsetRotation
|
r = r + offsetRotation
|
||||||
end
|
end
|
||||||
@ -220,21 +253,21 @@ function PathConstraint:update ()
|
|||||||
elseif r < -math_pi then
|
elseif r < -math_pi then
|
||||||
r = r + math_pi2
|
r = r + math_pi2
|
||||||
end
|
end
|
||||||
r = r * rotateMix
|
r = r * mixRotate
|
||||||
cos = math_cos(r)
|
cos = math_cos(r)
|
||||||
sin = math.sin(r)
|
sin = math_sin(r)
|
||||||
bone.a = cos * a - sin * c
|
bone.a = cos * a - sin * c
|
||||||
bone.b = cos * b - sin * d
|
bone.b = cos * b - sin * d
|
||||||
bone.c = sin * a + cos * c
|
bone.c = sin * a + cos * c
|
||||||
bone.d = sin * b + cos * d
|
bone.d = sin * b + cos * d
|
||||||
end
|
end
|
||||||
bone.appliedValid = false
|
bone:updateAppliedTransform()
|
||||||
i = i + 1
|
i = i + 1
|
||||||
p = p + 3
|
p = p + 3
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function PathConstraint:computeWorldPositions (path, spacesCount, tangents, percentPosition, percentSpacing)
|
function PathConstraint:computeWorldPositions (path, spacesCount, tangents)
|
||||||
local target = self.target
|
local target = self.target
|
||||||
local position = self.position
|
local position = self.position
|
||||||
local spaces = self.spaces
|
local spaces = self.spaces
|
||||||
@ -250,20 +283,20 @@ function PathConstraint:computeWorldPositions (path, spacesCount, tangents, perc
|
|||||||
local lengths = path.lengths
|
local lengths = path.lengths
|
||||||
if closed then curveCount = curveCount - 1 else curveCount = curveCount - 2 end
|
if closed then curveCount = curveCount - 1 else curveCount = curveCount - 2 end
|
||||||
local pathLength = lengths[curveCount + 1]
|
local pathLength = lengths[curveCount + 1]
|
||||||
if percentPosition then position = position * pathLength end
|
if self.data.positionMode == PathConstraintData.PositionMode.percent then position = position * pathLength end
|
||||||
if percentSpacing then
|
|
||||||
i = 1
|
local multiplier = 1
|
||||||
while i < spacesCount do
|
if self.data.spacingMode == PathConstraintData.SpacingMode.percent then
|
||||||
spaces[i + 1] = spaces[i + 1] * pathLength
|
multiplier = pathLength
|
||||||
i = i + 1
|
elseif self.data.spacingMode == PathConstraintData.SpacingMode.proportional then
|
||||||
end
|
multiplier = pathLength / spacesCount
|
||||||
end
|
end
|
||||||
world = utils.setArraySize(self.world, 8)
|
world = utils.setArraySize(self.world, 8)
|
||||||
i = 0
|
i = 0
|
||||||
local o = 0
|
local o = 0
|
||||||
local curve = 0
|
local curve = 0
|
||||||
while i < spacesCount do
|
while i < spacesCount do
|
||||||
local space = spaces[i + 1]
|
local space = spaces[i + 1] * multiplier
|
||||||
position = position + space
|
position = position + space
|
||||||
local p = position
|
local p = position
|
||||||
|
|
||||||
@ -389,17 +422,14 @@ function PathConstraint:computeWorldPositions (path, spacesCount, tangents, perc
|
|||||||
i = i + 1
|
i = i + 1
|
||||||
w = w + 6
|
w = w + 6
|
||||||
end
|
end
|
||||||
if percentPosition then
|
|
||||||
position = position * pathLength
|
if self.data.positionMode == PathConstraintData.PositionMode.percent then position = position * pathLength end
|
||||||
else
|
|
||||||
position = position * pathLength / path.lengths[curveCount]
|
local multiplier = 1
|
||||||
end
|
if self.data.spacingMode == PathConstraintData.SpacingMode.percent then
|
||||||
if percentSpacing then
|
multiplier = pathLength
|
||||||
i = 1
|
elseif self.data.spacingMode == PathConstraintData.SpacingMode.proportional then
|
||||||
while i < spacesCount do
|
multiplier = pathLength / spacesCount
|
||||||
spaces[i + 1] = spaces[i + 1] * pathLength
|
|
||||||
i = i + 1
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local segments = self.segments
|
local segments = self.segments
|
||||||
@ -409,7 +439,7 @@ function PathConstraint:computeWorldPositions (path, spacesCount, tangents, perc
|
|||||||
local curve = 0
|
local curve = 0
|
||||||
local segment = 0
|
local segment = 0
|
||||||
while i < spacesCount do
|
while i < spacesCount do
|
||||||
local space = spaces[i + 1]
|
local space = spaces[i + 1] * multiplier
|
||||||
position = position + space
|
position = position + space
|
||||||
local p = position
|
local p = position
|
||||||
|
|
||||||
|
|||||||
@ -43,8 +43,9 @@ function PathConstraintData.new (name)
|
|||||||
offsetRotation = 0,
|
offsetRotation = 0,
|
||||||
position = 0,
|
position = 0,
|
||||||
spacing = 0,
|
spacing = 0,
|
||||||
rotateMix = 0,
|
mixRotate = 0,
|
||||||
translateMix = 0
|
mixX = 0,
|
||||||
|
mixY = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@ -58,7 +59,8 @@ PathConstraintData.PositionMode = {
|
|||||||
PathConstraintData.SpacingMode = {
|
PathConstraintData.SpacingMode = {
|
||||||
length = 0,
|
length = 0,
|
||||||
fixed = 1,
|
fixed = 1,
|
||||||
percent = 2
|
percent = 2,
|
||||||
|
proportional = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
PathConstraintData.RotateMode = {
|
PathConstraintData.RotateMode = {
|
||||||
|
|||||||
@ -59,7 +59,6 @@ function Skeleton.new (data)
|
|||||||
transformConstraints = {},
|
transformConstraints = {},
|
||||||
pathConstraints = {},
|
pathConstraints = {},
|
||||||
_updateCache = {},
|
_updateCache = {},
|
||||||
updateCacheReset = {},
|
|
||||||
skin = nil,
|
skin = nil,
|
||||||
color = Color.newWith(1, 1, 1, 1),
|
color = Color.newWith(1, 1, 1, 1),
|
||||||
time = 0,
|
time = 0,
|
||||||
@ -110,7 +109,6 @@ end
|
|||||||
function Skeleton:updateCache ()
|
function Skeleton:updateCache ()
|
||||||
local updateCache = {}
|
local updateCache = {}
|
||||||
self._updateCache = updateCache
|
self._updateCache = updateCache
|
||||||
self.updateCacheReset = {}
|
|
||||||
|
|
||||||
local bones = self.bones
|
local bones = self.bones
|
||||||
for _, bone in ipairs(bones) do
|
for _, bone in ipairs(bones) do
|
||||||
@ -122,11 +120,11 @@ function Skeleton:updateCache ()
|
|||||||
local skinBones = self.skin.bones
|
local skinBones = self.skin.bones
|
||||||
for i, boneData in ipairs(skinBones) do
|
for i, boneData in ipairs(skinBones) do
|
||||||
local bone = bones[boneData.index]
|
local bone = bones[boneData.index]
|
||||||
while bone do
|
repeat
|
||||||
bone.sorted = false
|
bone.sorted = false
|
||||||
bone.active = true
|
bone.active = true
|
||||||
bone = bone.parent
|
bone = bone.parent
|
||||||
end
|
until not bone
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -196,22 +194,18 @@ function Skeleton:sortIkConstraint (constraint)
|
|||||||
local parent = constrained[1]
|
local parent = constrained[1]
|
||||||
self:sortBone(parent)
|
self:sortBone(parent)
|
||||||
|
|
||||||
if #constrained > 1 then
|
if #constrained == 1 then
|
||||||
|
table_insert(self._updateCache, constraint)
|
||||||
|
self:sortReset(parent.children)
|
||||||
|
else
|
||||||
local child = constrained[#constrained]
|
local child = constrained[#constrained]
|
||||||
local contains = false
|
self:sortBone(child)
|
||||||
for _, updatable in ipairs(self._updateCache) do
|
|
||||||
if updatable == child then
|
table_insert(self._updateCache, constraint)
|
||||||
contains = true
|
|
||||||
break
|
self:sortReset(parent.children)
|
||||||
end
|
child.sorted = true
|
||||||
end
|
|
||||||
if not contains then table_insert(self.updateCacheReset, child) end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
table_insert(self._updateCache, constraint)
|
|
||||||
|
|
||||||
self:sortReset(parent.children)
|
|
||||||
constrained[#constrained].sorted = true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Skeleton:sortPathConstraint(constraint)
|
function Skeleton:sortPathConstraint(constraint)
|
||||||
@ -266,7 +260,7 @@ function Skeleton:sortTransformConstraint(constraint)
|
|||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not contains then table_insert(self.updateCacheReset, child) end
|
self:sortBone(child)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
for _,bone in ipairs(constrained) do
|
for _,bone in ipairs(constrained) do
|
||||||
@ -279,7 +273,6 @@ function Skeleton:sortTransformConstraint(constraint)
|
|||||||
for _,bone in ipairs(constrained) do
|
for _,bone in ipairs(constrained) do
|
||||||
self:sortReset(bone.children)
|
self:sortReset(bone.children)
|
||||||
end
|
end
|
||||||
|
|
||||||
for _,bone in ipairs(constrained) do
|
for _,bone in ipairs(constrained) do
|
||||||
bone.sorted = true
|
bone.sorted = true
|
||||||
end
|
end
|
||||||
@ -333,8 +326,7 @@ end
|
|||||||
|
|
||||||
-- Updates the world transform for each bone and applies IK constraints.
|
-- Updates the world transform for each bone and applies IK constraints.
|
||||||
function Skeleton:updateWorldTransform ()
|
function Skeleton:updateWorldTransform ()
|
||||||
local updateCacheReset = self.updateCacheReset
|
for _,bone in ipairs(self.bones) do
|
||||||
for _,bone in ipairs(updateCacheReset) do
|
|
||||||
bone.ax = bone.x
|
bone.ax = bone.x
|
||||||
bone.ay = bone.y
|
bone.ay = bone.y
|
||||||
bone.arotation = bone.rotation
|
bone.arotation = bone.rotation
|
||||||
@ -342,11 +334,9 @@ function Skeleton:updateWorldTransform ()
|
|||||||
bone.ascaleY = bone.scaleY
|
bone.ascaleY = bone.scaleY
|
||||||
bone.ashearX = bone.shearX
|
bone.ashearX = bone.shearX
|
||||||
bone.ashearY = bone.shearY
|
bone.ashearY = bone.shearY
|
||||||
bone.appliedValid = true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local updateCache = self._updateCache
|
for _, updatable in ipairs(self._updateCache) do
|
||||||
for _, updatable in ipairs(updateCache) do
|
|
||||||
updatable:update()
|
updatable:update()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -372,10 +362,12 @@ function Skeleton:setBonesToSetupPose ()
|
|||||||
local transformConstraints = self.transformConstraints
|
local transformConstraints = self.transformConstraints
|
||||||
for _, constraint in ipairs(transformConstraints) do
|
for _, constraint in ipairs(transformConstraints) do
|
||||||
local data = constraint.data
|
local data = constraint.data
|
||||||
constraint.rotateMix = data.rotateMix
|
constraint.mixRotate = data.mixRotate
|
||||||
constraint.translateMix = data.translateMix
|
constraint.mixX = data.mixX
|
||||||
constraint.scaleMix = data.scaleMix
|
constraint.mixY = data.mixY
|
||||||
constraint.shearMix = data.shearMix
|
constraint.mixScaleX = data.mixScaleX
|
||||||
|
constraint.mixScaleY = data.mixScaleY
|
||||||
|
constraint.mixShearY = data.mixShearY
|
||||||
end
|
end
|
||||||
|
|
||||||
local pathConstraints = self.pathConstraints
|
local pathConstraints = self.pathConstraints
|
||||||
@ -383,8 +375,9 @@ function Skeleton:setBonesToSetupPose ()
|
|||||||
local data = constraint.data
|
local data = constraint.data
|
||||||
constraint.position = data.position
|
constraint.position = data.position
|
||||||
constraint.spacing = data.spacing
|
constraint.spacing = data.spacing
|
||||||
constraint.rotateMix = data.rotateMix
|
constraint.mixRotate = data.mixRotate
|
||||||
constraint.translateMix = data.translateMix
|
constraint.mixX = data.mixX
|
||||||
|
constraint.mixY = data.mixY
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -558,9 +558,9 @@ function SkeletonJson.new (attachmentLoader)
|
|||||||
for timelineName,timelineMap in pairs(slotMap) do
|
for timelineName,timelineMap in pairs(slotMap) do
|
||||||
if not timelineMap then
|
if not timelineMap then
|
||||||
elseif timelineName == "attachment" then
|
elseif timelineName == "attachment" then
|
||||||
local timeline = Animation.AttachmentTimeline.new(#timelineMap, slotIndex)
|
local timeline = Animation.AttachmentTimeline.new(#timelineMap, #timelineMap, slotIndex)
|
||||||
for i,keyMap in ipairs(timelineMap) do
|
for i,keyMap in ipairs(timelineMap) do
|
||||||
timeline:setFrame(i + 1, getValue(keyMap, "time", 0), keyMap["name"])
|
timeline:setFrame(i - 1, getValue(keyMap, "time", 0), keyMap["name"])
|
||||||
end
|
end
|
||||||
table_insert(timelines, timeline)
|
table_insert(timelines, timeline)
|
||||||
elseif timelineName == "rgba" then
|
elseif timelineName == "rgba" then
|
||||||
@ -765,7 +765,7 @@ function SkeletonJson.new (attachmentLoader)
|
|||||||
table_insert(timelines, readTimeline1(timelineMap, timeline, 0, scale))
|
table_insert(timelines, readTimeline1(timelineMap, timeline, 0, scale))
|
||||||
elseif timelineName == "scale" then
|
elseif timelineName == "scale" then
|
||||||
local timeline = Animation.ScaleTimeline.new(#timelineMap, #timelineMap * 2, boneIndex)
|
local timeline = Animation.ScaleTimeline.new(#timelineMap, #timelineMap * 2, boneIndex)
|
||||||
table_insert(timelines, readTimeline2(timelineMap, "x", "y", 1, 1))
|
table_insert(timelines, readTimeline2(timelineMap, timeline, "x", "y", 1, 1))
|
||||||
elseif timelineName == "scalex" then
|
elseif timelineName == "scalex" then
|
||||||
local timeline = Animation.ScaleXTimeline.new(#timelineMap, #timelineMap, boneIndex)
|
local timeline = Animation.ScaleXTimeline.new(#timelineMap, #timelineMap, boneIndex)
|
||||||
table_insert(timelines, readTimeline1(timelineMap, timeline, 1, 1))
|
table_insert(timelines, readTimeline1(timelineMap, timeline, 1, 1))
|
||||||
@ -774,7 +774,7 @@ function SkeletonJson.new (attachmentLoader)
|
|||||||
table_insert(timelines, readTimeline1(timelineMap, timeline, 1, 1))
|
table_insert(timelines, readTimeline1(timelineMap, timeline, 1, 1))
|
||||||
elseif timelineName == "shear" then
|
elseif timelineName == "shear" then
|
||||||
local timeline = Animation.ShearTimeline.new(#timelineMap, #timelineMap * 2, boneIndex)
|
local timeline = Animation.ShearTimeline.new(#timelineMap, #timelineMap * 2, boneIndex)
|
||||||
table_insert(timelines, readTimeline2(timelineMap, "x", "y", 0, 1))
|
table_insert(timelines, readTimeline2(timelineMap, timeline, "x", "y", 0, 1))
|
||||||
elseif timelineName == "shearx" then
|
elseif timelineName == "shearx" then
|
||||||
local timeline = Animation.ShearXTimeline.new(#timelineMap, #timelineMap, boneIndex)
|
local timeline = Animation.ShearXTimeline.new(#timelineMap, #timelineMap, boneIndex)
|
||||||
table_insert(timelines, readTimeline1(timelineMap, timeline, 0, 1))
|
table_insert(timelines, readTimeline1(timelineMap, timeline, 0, 1))
|
||||||
@ -901,7 +901,7 @@ function SkeletonJson.new (attachmentLoader)
|
|||||||
if map.path then
|
if map.path then
|
||||||
for constraintName,constraintMap in pairs(map.path) do
|
for constraintName,constraintMap in pairs(map.path) do
|
||||||
local constraint, constraintIndex = -1
|
local constraint, constraintIndex = -1
|
||||||
for i,other in pairs(skeletonData.transformConstraints) do
|
for i,other in pairs(skeletonData.pathConstraints) do
|
||||||
if other.name == constraintName then
|
if other.name == constraintName then
|
||||||
constraintIndex = i
|
constraintIndex = i
|
||||||
constraint = other
|
constraint = other
|
||||||
@ -914,12 +914,12 @@ function SkeletonJson.new (attachmentLoader)
|
|||||||
if timelineName == "position" then
|
if timelineName == "position" then
|
||||||
local timeline = Animation.PathConstraintPositionTimeline.new(#timelineMap, #timelineMap, constraintIndex)
|
local timeline = Animation.PathConstraintPositionTimeline.new(#timelineMap, #timelineMap, constraintIndex)
|
||||||
local timelineScale = 1
|
local timelineScale = 1
|
||||||
if constraint.positionMode == PositionMode.fixed then timelineScale = scale end
|
if constraint.positionMode == PathConstraintData.PositionMode.fixed then timelineScale = scale end
|
||||||
table_insert(timelines, readTimeline1(timelineMap, timeline, 0, timelineScale))
|
table_insert(timelines, readTimeline1(timelineMap, timeline, 0, timelineScale))
|
||||||
elseif timelineName == "spacing" then
|
elseif timelineName == "spacing" then
|
||||||
local timeline = Animation.PathConstraintSpacingTimeline.new(#timelineMap, #timelineMap, constraintIndex)
|
local timeline = Animation.PathConstraintSpacingTimeline.new(#timelineMap, #timelineMap, constraintIndex)
|
||||||
local timelineScale = 1
|
local timelineScale = 1
|
||||||
if data.spacingMode == SpacingMode.Length or data.spacingMode == SpacingMode.Fixed then timelineScale = scale end
|
if data.spacingMode == PathConstraintData.SpacingMode.Length or data.spacingMode == PathConstraintData.SpacingMode.Fixed then timelineScale = scale end
|
||||||
table_insert(timelines, readTimeline1(timelineMap, timeline, 0, timelineScale))
|
table_insert(timelines, readTimeline1(timelineMap, timeline, 0, timelineScale))
|
||||||
elseif timelineName == "mix" then
|
elseif timelineName == "mix" then
|
||||||
local timeline = Animation.PathConstraintMixTimeline.new(#timelineMap, #timelineMap * 3, constraintIndex)
|
local timeline = Animation.PathConstraintMixTimeline.new(#timelineMap, #timelineMap * 3, constraintIndex)
|
||||||
@ -978,6 +978,7 @@ function SkeletonJson.new (attachmentLoader)
|
|||||||
if weighted then deformLength = math_floor(deformLength / 3) * 2 end
|
if weighted then deformLength = math_floor(deformLength / 3) * 2 end
|
||||||
|
|
||||||
local timeline = Animation.DeformTimeline.new(#timelineMap, #timelineMap, slotIndex, attachment)
|
local timeline = Animation.DeformTimeline.new(#timelineMap, #timelineMap, slotIndex, attachment)
|
||||||
|
local time = getValue(keyMap, "time", 0)
|
||||||
local bezier = 0
|
local bezier = 0
|
||||||
for i,keyMap in ipairs(timelineMap) do
|
for i,keyMap in ipairs(timelineMap) do
|
||||||
local deform = nil
|
local deform = nil
|
||||||
@ -1007,7 +1008,7 @@ function SkeletonJson.new (attachmentLoader)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
local frame = i - 1
|
local frame = i - 1
|
||||||
timeline:setFrame(frame, time, mixRotate, mixX, mixY)
|
timeline:setFrame(frame, time, deform)
|
||||||
local nextMap = timelineMap[frame + 1]
|
local nextMap = timelineMap[frame + 1]
|
||||||
if not nextMap then
|
if not nextMap then
|
||||||
timeline:shrink(bezier)
|
timeline:shrink(bezier)
|
||||||
@ -1172,15 +1173,15 @@ function SkeletonJson.new (attachmentLoader)
|
|||||||
|
|
||||||
readCurve = function (curve, timeline, bezier, frame, value, time1, time2, value1, value2, scale)
|
readCurve = function (curve, timeline, bezier, frame, value, time1, time2, value1, value2, scale)
|
||||||
if curve == "stepped" then
|
if curve == "stepped" then
|
||||||
if value ~= 0 then timeline.setStepped(frame) end
|
if value ~= 0 then timeline:setStepped(frame) end
|
||||||
return bezier
|
return bezier
|
||||||
end
|
end
|
||||||
local i = value * 4
|
local i = value * 4 + 1
|
||||||
local cx1 = curve[i]
|
local cx1 = curve[i]
|
||||||
local cy1 = curve[i + 1] * scale
|
local cy1 = curve[i + 1] * scale
|
||||||
local cx2 = curve[i + 2]
|
local cx2 = curve[i + 2]
|
||||||
local cy2 = curve[i + 3] * scale
|
local cy2 = curve[i + 3] * scale
|
||||||
timeline.setBezier(bezier, frame, value, time1, value1, cx1, cy1, cx2, cy2, time2, value2)
|
timeline:setBezier(bezier, frame, value, time1, value1, cx1, cy1, cx2, cy2, time2, value2)
|
||||||
return bezier + 1
|
return bezier + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -60,9 +60,16 @@ end
|
|||||||
|
|
||||||
function Slot:setAttachment (attachment)
|
function Slot:setAttachment (attachment)
|
||||||
if self.attachment == attachment then return end
|
if self.attachment == attachment then return end
|
||||||
|
if not attachment
|
||||||
|
or not attachment.isVertexAttachment
|
||||||
|
or not self.attachment
|
||||||
|
or not self.attachment.isVertexAttachment
|
||||||
|
or attachment.deformAttachment ~= self.attachment.deformAttachment
|
||||||
|
then
|
||||||
|
self.deform = {}
|
||||||
|
end
|
||||||
self.attachment = attachment
|
self.attachment = attachment
|
||||||
self.attachmentTime = self.bone.skeleton.time
|
self.attachmentTime = self.bone.skeleton.time
|
||||||
self.deform = {}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Slot:setAttachmentTime (time)
|
function Slot:setAttachmentTime (time)
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
-- Integration of the Spine Runtimes into software or otherwise creating
|
-- Integration of the Spine Runtimes into software or otherwise creating
|
||||||
-- derivative works of the Spine Runtimes is permitted under the terms and
|
-- derivative works of the Spine Runtimes is permitted under the terms and
|
||||||
-- conditions of Section 2 of the Spine Editor License Agreement:
|
-- conditions of Section 2 of the Spine Editor License Agreement:
|
||||||
-- http://esotericsoftware.com/spine-editor-license
|
-- http:--esotericsoftware.com/spine-editor-license
|
||||||
--
|
--
|
||||||
-- Otherwise, it is permitted to integrate the Spine Runtimes into software
|
-- Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||||
-- or otherwise create derivative works of the Spine Runtimes (collectively,
|
-- or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||||
@ -28,6 +28,7 @@
|
|||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
local tonumber = tonumber
|
||||||
local table_insert = table.insert
|
local table_insert = table.insert
|
||||||
local math_abs = math.abs
|
local math_abs = math.abs
|
||||||
|
|
||||||
@ -47,7 +48,8 @@ function TextureAtlasPage.new ()
|
|||||||
vWrap = nil,
|
vWrap = nil,
|
||||||
texture = nil,
|
texture = nil,
|
||||||
width = 0,
|
width = 0,
|
||||||
height = 0
|
height = 0,
|
||||||
|
pma = false
|
||||||
}
|
}
|
||||||
setmetatable(self, TextureAtlasPage)
|
setmetatable(self, TextureAtlasPage)
|
||||||
return self
|
return self
|
||||||
@ -73,168 +75,178 @@ function TextureAtlas:parse (atlasContent, imageLoader)
|
|||||||
if not atlasContent then error("atlasContent cannot be nil.", 2) end
|
if not atlasContent then error("atlasContent cannot be nil.", 2) end
|
||||||
if not imageLoader then error("imageLoader cannot be nil.", 2) end
|
if not imageLoader then error("imageLoader cannot be nil.", 2) end
|
||||||
|
|
||||||
function lineIterator(s)
|
local readLine = atlasContent:gmatch("[ \t]*(.-)[ \t]*\r?\n")
|
||||||
if s:sub(-1)~="\n" then s=s.."\n" end
|
|
||||||
return s:gmatch("(.-)\n")
|
local trim = function (value)
|
||||||
|
return value:match("^%s*(.-)%s*$")
|
||||||
end
|
end
|
||||||
|
|
||||||
local lines = {}
|
local entry = {}
|
||||||
local index = 0
|
local readEntry = function (entry, line)
|
||||||
local numLines = 0
|
if not line then return 0 end
|
||||||
for line in lineIterator(atlasContent) do
|
if line:len() == 0 then return 0 end
|
||||||
lines[numLines] = line
|
|
||||||
numLines = numLines + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
local readLine = function ()
|
local colon = line:find(":")
|
||||||
if index >= numLines then return nil end
|
if not colon then return 0 end
|
||||||
local line = lines[index]
|
entry[0] = trim(line:sub(1, colon))
|
||||||
index = index + 1
|
local lastMatch = colon + 1
|
||||||
return line
|
|
||||||
end
|
|
||||||
|
|
||||||
local readValue = function ()
|
|
||||||
local line = readLine()
|
|
||||||
local idx = line:find(":")
|
|
||||||
if not idx then error("Invalid line: " .. line, 2) end
|
|
||||||
return line:sub(idx + 1):match'^%s*(.*%S)' or ''
|
|
||||||
end
|
|
||||||
|
|
||||||
local readTuple = function ()
|
|
||||||
local line = readLine()
|
|
||||||
local idx = line:find(":")
|
|
||||||
if not idx then
|
|
||||||
error("Invalid line: " .. line, 2)
|
|
||||||
end
|
|
||||||
local i = 1
|
local i = 1
|
||||||
local lastMatch = idx + 1
|
while true do
|
||||||
local tuple = {}
|
|
||||||
while i <= 3 do
|
|
||||||
local comma = line:find(",", lastMatch)
|
local comma = line:find(",", lastMatch)
|
||||||
if not comma then break end
|
if not comma then
|
||||||
tuple[i] = line:sub(lastMatch, comma - 1):match'^%s*(.*%S)' or ''
|
entry[i] = trim(line:sub(lastMatch))
|
||||||
|
return i
|
||||||
|
end
|
||||||
|
entry[i] = trim(line:sub(lastMatch, comma - lastMatch))
|
||||||
lastMatch = comma + 1
|
lastMatch = comma + 1
|
||||||
|
if i == 4 then return 4 end
|
||||||
i = i + 1
|
i = i + 1
|
||||||
end
|
end
|
||||||
tuple[i] = line:sub(lastMatch):match'^%s*(.*%S)' or ''
|
|
||||||
return tuple
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local parseInt = function (str)
|
local page
|
||||||
return tonumber(str)
|
local region
|
||||||
|
|
||||||
|
local pageFields = {}
|
||||||
|
pageFields["size"] = function ()
|
||||||
|
page.width = tonumber(entry[1])
|
||||||
|
page.height = tonumber(entry[2])
|
||||||
|
end
|
||||||
|
pageFields["format"] = function ()
|
||||||
|
-- page.format = Format[tuple[0]] we don't need format in Lua
|
||||||
|
end
|
||||||
|
pageFields["filter"] = function ()
|
||||||
|
page.minFilter = TextureFilter[entry[1]]
|
||||||
|
page.magFilter = TextureFilter[entry[2]]
|
||||||
|
end
|
||||||
|
pageFields["repeat"] = function ()
|
||||||
|
if entry[1]:find("x") then page.uWrap = TextureWrap.Repeat end
|
||||||
|
if entry[1]:find("y") then page.vWrap = TextureWrap.Repeat end
|
||||||
|
end
|
||||||
|
pageFields["pma"] = function ()
|
||||||
|
page.pma = entry[1] == "true"
|
||||||
end
|
end
|
||||||
|
|
||||||
local filterFromString = function (str)
|
local regionFields = {}
|
||||||
str = str:lower()
|
regionFields["xy"] = function () -- Deprecated, use bounds.
|
||||||
if str == "nearest" then return TextureFilter.Nearest
|
region.x = tonumber(entry[1])
|
||||||
elseif str == "linear" then return TextureFilter.Linear
|
region.y = tonumber(entry[2])
|
||||||
elseif str == "mipmap" then return TextureFilter.MipMap
|
end
|
||||||
elseif str == "mipmapnearestnearest" then return TextureFilter.MipMapNearestNearest
|
regionFields["size"] = function () -- Deprecated, use bounds.
|
||||||
elseif str == "mipmaplinearnearest" then return TextureFilter.MipMapLinearNearest
|
region.width = tonumber(entry[1])
|
||||||
elseif str == "mipmapnearestlinear" then return TextureFilter.MipMapNearestLinear
|
region.height = tonumber(entry[2])
|
||||||
elseif str == "mipmaplinearlinear" then return TextureFilter.MipMapLinearLinear
|
end
|
||||||
else error("Unknown texture wrap: " .. str, 2)
|
regionFields["bounds"] = function ()
|
||||||
|
region.x = tonumber(entry[1])
|
||||||
|
region.y = tonumber(entry[2])
|
||||||
|
region.width = tonumber(entry[3])
|
||||||
|
region.height = tonumber(entry[4])
|
||||||
|
end
|
||||||
|
regionFields["offset"] = function () -- Deprecated, use offsets.
|
||||||
|
region.offsetX = tonumber(entry[1])
|
||||||
|
region.offsetY = tonumber(entry[2])
|
||||||
|
end
|
||||||
|
regionFields["orig"] = function () -- Deprecated, use offsets.
|
||||||
|
region.originalWidth = tonumber(entry[1])
|
||||||
|
region.originalHeight = tonumber(entry[2])
|
||||||
|
end
|
||||||
|
regionFields["offsets"] = function ()
|
||||||
|
region.offsetX = tonumber(entry[1])
|
||||||
|
region.offsetY = tonumber(entry[2])
|
||||||
|
region.originalWidth = tonumber(entry[3])
|
||||||
|
region.originalHeight = tonumber(entry[4])
|
||||||
|
end
|
||||||
|
regionFields["rotate"] = function ()
|
||||||
|
local value = entry[1]
|
||||||
|
if value == "true" then
|
||||||
|
region.degrees = 90
|
||||||
|
elseif value ~= "false" then
|
||||||
|
region.degrees = tonumber(value)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
regionFields["index"] = function ()
|
||||||
|
region.index = tonumber(entry[1])
|
||||||
|
end
|
||||||
|
|
||||||
local page = nil
|
local line = readLine()
|
||||||
|
-- Ignore empty lines before first entry.
|
||||||
|
while line and line:len() == 0 do
|
||||||
|
line = readLine()
|
||||||
|
end
|
||||||
|
-- Header entries.
|
||||||
|
while true do
|
||||||
|
if not line or line:len() == 0 then break end
|
||||||
|
if readEntry(entry, line) == 0 then break end -- Silently ignore all header fields.
|
||||||
|
line = readLine()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Page and region entries.
|
||||||
|
local names
|
||||||
|
local values
|
||||||
while true do
|
while true do
|
||||||
local line = readLine()
|
|
||||||
if not line then break end
|
if not line then break end
|
||||||
line = line:match'^%s*(.*%S)' or ''
|
|
||||||
if line:len() == 0 then
|
if line:len() == 0 then
|
||||||
page = nil
|
page = nil
|
||||||
|
line = readLine()
|
||||||
elseif not page then
|
elseif not page then
|
||||||
page = TextureAtlasPage.new()
|
page = TextureAtlasPage.new()
|
||||||
page.name = line
|
page.name = trim(line)
|
||||||
|
while true do
|
||||||
local tuple = readTuple()
|
line = readLine()
|
||||||
if #tuple == 2 then
|
if readEntry(entry, line) == 0 then break end
|
||||||
page.width = parseInt(tuple[1])
|
local field = pageFields[entry[0]]
|
||||||
page.height = parseInt(tuple[2])
|
if field then field() end
|
||||||
tuple = readTuple()
|
|
||||||
else
|
|
||||||
-- We only support atlases that have the page width/height
|
|
||||||
-- encoded in them. That way we don't rely on any special
|
|
||||||
-- wrapper objects for images to get the page size from
|
|
||||||
error("Atlas must specify page width/height. Please export to the latest atlas format", 2)
|
|
||||||
end
|
end
|
||||||
|
page.texture = imageLoader(page.name)
|
||||||
tuple = readTuple()
|
-- FIXME - Apply the filter and wrap settings to the texture.
|
||||||
page.minFilter = filterFromString(tuple[1])
|
-- page.texture:setFilters(page.minFilter, page.magFilter)
|
||||||
page.magFilter = filterFromString(tuple[2])
|
-- page.texture:setWraps(page.uWrap, page.vWrap)
|
||||||
|
|
||||||
local direction = readValue()
|
|
||||||
page.uWrap = TextureWrap.ClampToEdge
|
|
||||||
page.vWrap = TextureWrap.ClampToEdge
|
|
||||||
if direction == "x" then
|
|
||||||
page.uWrap = TextureWrap.Repeat
|
|
||||||
elseif direction == "y" then
|
|
||||||
page.vWrap = TextureWrap.Repeat
|
|
||||||
elseif direction == "xy" then
|
|
||||||
page.uWrap = TextureWrap.Repeat
|
|
||||||
page.vWrap = TextureWrap.Repeat
|
|
||||||
end
|
|
||||||
|
|
||||||
page.texture = imageLoader(line)
|
|
||||||
-- FIXME page.texture:setFilters(page.minFilter, page.magFilter)
|
|
||||||
-- FIXME page.texture:setWraps(page.uWrap, page.vWrap)
|
|
||||||
table_insert(self.pages, page)
|
table_insert(self.pages, page)
|
||||||
else
|
else
|
||||||
local region = TextureAtlasRegion.new()
|
region = TextureAtlasRegion.new()
|
||||||
region.name = line
|
|
||||||
region.page = page
|
region.page = page
|
||||||
|
region.name = line
|
||||||
local rotateValue = readValue()
|
while true do
|
||||||
if rotateValue == "true" then
|
line = readLine()
|
||||||
region.degrees = 90
|
local count = readEntry(entry, line)
|
||||||
elseif rotateValue == "false" then
|
if count == 0 then break end
|
||||||
region.degrees = 0
|
local field = regionFields[entry[0]]
|
||||||
else
|
if field then
|
||||||
region.degrees = tonumber(rotateValue)
|
field()
|
||||||
end
|
else
|
||||||
if region.degrees == 90 then region.rotate = true end
|
if not names then
|
||||||
|
names = {}
|
||||||
local tuple = readTuple()
|
values = {}
|
||||||
local x = parseInt(tuple[1])
|
end
|
||||||
local y = parseInt(tuple[2])
|
table_insert(names, entry[0])
|
||||||
|
local entryValues = {}
|
||||||
tuple = readTuple()
|
local i = 0
|
||||||
local width = parseInt(tuple[1])
|
while i < count do
|
||||||
local height = parseInt(tuple[2])
|
table_insert(entryValues, tonumber(entry[i + 1]))
|
||||||
|
i = i + 1
|
||||||
region.u = x / page.width
|
end
|
||||||
region.v = y / page.height
|
table_insert(values, entryValues)
|
||||||
if region.rotate then
|
|
||||||
region.u2 = (x + height) / page.width
|
|
||||||
region.v2 = (y + width) / page.height
|
|
||||||
else
|
|
||||||
region.u2 = (x + width) / page.width
|
|
||||||
region.v2 = (y + height) / page.height
|
|
||||||
end
|
|
||||||
|
|
||||||
region.x = x
|
|
||||||
region.y = y
|
|
||||||
region.width = math_abs(width)
|
|
||||||
region.height = math_abs(height)
|
|
||||||
|
|
||||||
-- Read and skip optional splits
|
|
||||||
tuple = readTuple()
|
|
||||||
if #tuple == 4 then
|
|
||||||
tuple = readTuple()
|
|
||||||
if #tuple == 4 then
|
|
||||||
readTuple()
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if region.originalWidth == 0 and region.originalHeight == 0 then
|
||||||
region.originalWidth = parseInt(tuple[1])
|
region.originalWidth = region.width
|
||||||
region.originalHeight = parseInt(tuple[2])
|
region.originalHeight = region.height
|
||||||
|
end
|
||||||
tuple = readTuple()
|
if names and #names > 0 then
|
||||||
region.offsetX = parseInt(tuple[1])
|
region.names = names
|
||||||
region.offsetY = parseInt(tuple[2])
|
region.values = values
|
||||||
|
names = nil
|
||||||
region.index = parseInt(readValue())
|
values = nil
|
||||||
|
end
|
||||||
|
region.u = region.x / page.width
|
||||||
|
region.v = region.y / page.height
|
||||||
|
if region.degrees == 90 then
|
||||||
|
region.u2 = (region.x + region.height) / page.width
|
||||||
|
region.v2 = (region.y + region.width) / page.height
|
||||||
|
else
|
||||||
|
region.u2 = (region.x + region.width) / page.width
|
||||||
|
region.v2 = (region.y + region.height) / page.height
|
||||||
|
end
|
||||||
region.texture = page.texture
|
region.texture = page.texture
|
||||||
table_insert(self.regions, region)
|
table_insert(self.regions, region)
|
||||||
end
|
end
|
||||||
|
|||||||
@ -42,9 +42,10 @@ function TextureAtlasRegion.new ()
|
|||||||
self.x = 0
|
self.x = 0
|
||||||
self.y = 0
|
self.y = 0
|
||||||
self.index = 0
|
self.index = 0
|
||||||
self.rotate = false
|
|
||||||
self.degrees = 0
|
self.degrees = 0
|
||||||
self.texture = nil
|
self.texture = nil
|
||||||
|
self.names = nil
|
||||||
|
self.values = nil
|
||||||
setmetatable(self, TextureAtlasRegion)
|
setmetatable(self, TextureAtlasRegion)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|||||||
@ -53,7 +53,7 @@ function TransformConstraint.new (data, skeleton)
|
|||||||
data = data,
|
data = data,
|
||||||
bones = {},
|
bones = {},
|
||||||
target = nil,
|
target = nil,
|
||||||
rotateMix = data.rotateMix, translateMix = data.translateMix, scaleMix = data.scaleMix, shearMix = data.shearMix,
|
mixRotate = data.mixRotate, mixX = data.mixX, mixY = data.mixY, mixScaleX = data.mixScaleX, mixScaleY = data.mixScaleY, mixShearY = data.mixShearY,
|
||||||
temp = { 0, 0 },
|
temp = { 0, 0 },
|
||||||
active = false
|
active = false
|
||||||
}
|
}
|
||||||
@ -67,11 +67,9 @@ function TransformConstraint.new (data, skeleton)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function TransformConstraint:apply ()
|
|
||||||
self:update()
|
|
||||||
end
|
|
||||||
|
|
||||||
function TransformConstraint:update ()
|
function TransformConstraint:update ()
|
||||||
|
if self.mixRotate == 0 and self.mixX == 0 and self.mixY == 0 and self.mixScaleX == 0 and self.mixScaleX == 0 and self.mixShearY == 0 then return end
|
||||||
|
|
||||||
if self.data.local_ then
|
if self.data.local_ then
|
||||||
if self.data.relative then
|
if self.data.relative then
|
||||||
self:applyRelativeLocal()
|
self:applyRelativeLocal()
|
||||||
@ -88,10 +86,14 @@ function TransformConstraint:update ()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function TransformConstraint:applyAbsoluteWorld ()
|
function TransformConstraint:applyAbsoluteWorld ()
|
||||||
local rotateMix = self.rotateMix
|
local mixRotate = self.mixRotate
|
||||||
local translateMix = self.translateMix
|
local mixX = self.mixX
|
||||||
local scaleMix = self.scaleMix
|
local mixY = self.mixY
|
||||||
local shearMix = self.shearMix
|
local mixScaleX = self.mixScaleX
|
||||||
|
local mixScaleY = self.mixScaleY
|
||||||
|
local mixShearY = self.mixShearY
|
||||||
|
local translate = mixX ~= 0 or mixY ~= 0
|
||||||
|
|
||||||
local target = self.target
|
local target = self.target
|
||||||
local ta = target.a
|
local ta = target.a
|
||||||
local tb = target.b
|
local tb = target.b
|
||||||
@ -101,10 +103,10 @@ function TransformConstraint:applyAbsoluteWorld ()
|
|||||||
if ta * td - tb * tc > 0 then degRadReflect = utils.degRad else degRadReflect = -utils.degRad end
|
if ta * td - tb * tc > 0 then degRadReflect = utils.degRad else degRadReflect = -utils.degRad end
|
||||||
local offsetRotation = self.data.offsetRotation * degRadReflect
|
local offsetRotation = self.data.offsetRotation * degRadReflect
|
||||||
local offsetShearY = self.data.offsetShearY * degRadReflect
|
local offsetShearY = self.data.offsetShearY * degRadReflect
|
||||||
|
|
||||||
local bones = self.bones
|
local bones = self.bones
|
||||||
for _, bone in ipairs(bones) do
|
for _, bone in ipairs(bones) do
|
||||||
local modified = false
|
if mixRotate ~= 0 then
|
||||||
if rotateMix ~= 0 then
|
|
||||||
local a = bone.a
|
local a = bone.a
|
||||||
local b = bone.b
|
local b = bone.b
|
||||||
local c = bone.c
|
local c = bone.c
|
||||||
@ -115,45 +117,38 @@ function TransformConstraint:applyAbsoluteWorld ()
|
|||||||
elseif r < -math_pi then
|
elseif r < -math_pi then
|
||||||
r = r + math_pi2
|
r = r + math_pi2
|
||||||
end
|
end
|
||||||
r = r * rotateMix
|
r = r * mixRotate
|
||||||
local cos = math_cos(r)
|
local cos = math_cos(r)
|
||||||
local sin = math_sin(r)
|
local sin = math_sin(r)
|
||||||
bone.a = cos * a - sin * c
|
bone.a = cos * a - sin * c
|
||||||
bone.b = cos * b - sin * d
|
bone.b = cos * b - sin * d
|
||||||
bone.c = sin * a + cos * c
|
bone.c = sin * a + cos * c
|
||||||
bone.d = sin * b + cos * d
|
bone.d = sin * b + cos * d
|
||||||
modified = true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if translateMix ~= 0 then
|
if translate then
|
||||||
local temp = self.temp
|
local temp = self.temp
|
||||||
temp[1] = self.data.offsetX
|
temp[1] = self.data.offsetX
|
||||||
temp[2] = self.data.offsetY
|
temp[2] = self.data.offsetY
|
||||||
target:localToWorld(temp)
|
target:localToWorld(temp)
|
||||||
bone.worldX = bone.worldX + (temp[1] - bone.worldX) * translateMix
|
bone.worldX = bone.worldX + (temp[1] - bone.worldX) * mixX
|
||||||
bone.worldY = bone.worldY + (temp[2] - bone.worldY) * translateMix
|
bone.worldY = bone.worldY + (temp[2] - bone.worldY) * mixY
|
||||||
modified = true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if scaleMix > 0 then
|
if mixScaleX ~= 0 then
|
||||||
local s = math_sqrt(bone.a * bone.a + bone.c * bone.c)
|
local s = math_sqrt(bone.a * bone.a + bone.c * bone.c)
|
||||||
local ts = math_sqrt(ta * ta + tc * tc)
|
if s ~= 0 then s = (s + (math_sqrt(ta * ta + tc * tc) - s + self.data.offsetScaleX) * mixScaleX) / s end
|
||||||
if s > 0.00001 then
|
|
||||||
s = (s + (ts - s + self.data.offsetScaleX) * scaleMix) / s
|
|
||||||
end
|
|
||||||
bone.a = bone.a * s
|
bone.a = bone.a * s
|
||||||
bone.c = bone.c * s
|
bone.c = bone.c * s
|
||||||
s = math_sqrt(bone.b * bone.b + bone.d * bone.d)
|
end
|
||||||
ts = math_sqrt(tb * tb + td * td)
|
if mixScaleY ~= 0 then
|
||||||
if s > 0.00001 then
|
local s = math_sqrt(bone.b * bone.b + bone.d * bone.d)
|
||||||
s = (s + (ts - s + self.data.offsetScaleY) * scaleMix) / s
|
if s ~= 0 then s = (s + (math_sqrt(tb * tb + td * td) - s + self.data.offsetScaleY) * mixScaleY) / s end
|
||||||
end
|
|
||||||
bone.b = bone.b * s
|
bone.b = bone.b * s
|
||||||
bone.d = bone.d * s
|
bone.d = bone.d * s
|
||||||
modified = true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if shearMix > 0 then
|
if mixShearY > 0 then
|
||||||
local b = bone.b
|
local b = bone.b
|
||||||
local d = bone.d
|
local d = bone.d
|
||||||
local by = math_atan2(d, b)
|
local by = math_atan2(d, b)
|
||||||
@ -163,22 +158,25 @@ function TransformConstraint:applyAbsoluteWorld ()
|
|||||||
elseif r < -math_pi then
|
elseif r < -math_pi then
|
||||||
r = r + math_pi2
|
r = r + math_pi2
|
||||||
end
|
end
|
||||||
r = by + (r + offsetShearY) * shearMix
|
r = by + (r + offsetShearY) * mixShearY
|
||||||
local s = math_sqrt(b * b + d * d)
|
local s = math_sqrt(b * b + d * d)
|
||||||
bone.b = math_cos(r) * s
|
bone.b = math_cos(r) * s
|
||||||
bone.d = math_sin(r) * s
|
bone.d = math_sin(r) * s
|
||||||
modified = true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if modified then bone.appliedValid = false end
|
bone:updateAppliedTransform()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function TransformConstraint:applyRelativeWorld ()
|
function TransformConstraint:applyRelativeWorld ()
|
||||||
local rotateMix = self.rotateMix
|
local mixRotate = self.mixRotate
|
||||||
local translateMix = self.translateMix
|
local mixX = self.mixX
|
||||||
local scaleMix = self.scaleMix
|
local mixY = self.mixY
|
||||||
local shearMix = self.shearMix
|
local mixScaleX = self.mixScaleX
|
||||||
|
local mixScaleY = self.mixScaleY
|
||||||
|
local mixShearY = self.mixShearY
|
||||||
|
local translate = mixX ~= 0 or mixY ~= 0
|
||||||
|
|
||||||
local target = self.target
|
local target = self.target
|
||||||
local ta = target.a
|
local ta = target.a
|
||||||
local tb = target.b
|
local tb = target.b
|
||||||
@ -188,11 +186,12 @@ function TransformConstraint:applyRelativeWorld ()
|
|||||||
if ta * td - tb * tc > 0 then degRadReflect = utils.degRad else degRadReflect = -utils.degRad end
|
if ta * td - tb * tc > 0 then degRadReflect = utils.degRad else degRadReflect = -utils.degRad end
|
||||||
local offsetRotation = self.data.offsetRotation * degRadReflect
|
local offsetRotation = self.data.offsetRotation * degRadReflect
|
||||||
local offsetShearY = self.data.offsetShearY * degRadReflect
|
local offsetShearY = self.data.offsetShearY * degRadReflect
|
||||||
|
|
||||||
local bones = self.bones
|
local bones = self.bones
|
||||||
for _, bone in ipairs(bones) do
|
for _, bone in ipairs(bones) do
|
||||||
local modified = false
|
local modified = false
|
||||||
|
|
||||||
if rotateMix ~= 0 then
|
if mixRotate ~= 0 then
|
||||||
local a = bone.a
|
local a = bone.a
|
||||||
local b = bone.b
|
local b = bone.b
|
||||||
local c = bone.c
|
local c = bone.c
|
||||||
@ -203,37 +202,36 @@ function TransformConstraint:applyRelativeWorld ()
|
|||||||
elseif r < -math_pi then
|
elseif r < -math_pi then
|
||||||
r = r + math_pi2
|
r = r + math_pi2
|
||||||
end
|
end
|
||||||
r = r * rotateMix
|
r = r * mixRotate
|
||||||
local cos = math_cos(r)
|
local cos = math_cos(r)
|
||||||
local sin = math_sin(r)
|
local sin = math_sin(r)
|
||||||
bone.a = cos * a - sin * c
|
bone.a = cos * a - sin * c
|
||||||
bone.b = cos * b - sin * d
|
bone.b = cos * b - sin * d
|
||||||
bone.c = sin * a + cos * c
|
bone.c = sin * a + cos * c
|
||||||
bone.d = sin * b + cos * d
|
bone.d = sin * b + cos * d
|
||||||
modified = true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if translateMix ~= 0 then
|
if translate then
|
||||||
local temp = self.temp
|
local temp = self.temp
|
||||||
temp[1] = self.data.offsetX
|
temp[1] = self.data.offsetX
|
||||||
temp[2] = self.data.offsetY
|
temp[2] = self.data.offsetY
|
||||||
target:localToWorld(temp)
|
target:localToWorld(temp)
|
||||||
bone.worldX = bone.worldX + temp[1] * translateMix
|
bone.worldX = bone.worldX + temp[1] * mixX
|
||||||
bone.worldY = bone.worldY + temp[2] * translateMix
|
bone.worldY = bone.worldY + temp[2] * mixY
|
||||||
modified = true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if scaleMix > 0 then
|
if mixScaleX ~= 0 then
|
||||||
local s = (math_sqrt(ta * ta + tc * tc) - 1 + self.data.offsetScaleX) * scaleMix + 1
|
local s = (math_sqrt(ta * ta + tc * tc) - 1 + self.data.offsetScaleX) * mixScaleX + 1
|
||||||
bone.a = bone.a * s
|
bone.a = bone.a * s
|
||||||
bone.c = bone.c * s
|
bone.c = bone.c * s
|
||||||
s = (math_sqrt(tb * tb + td * td) - 1 + self.data.offsetScaleY) * scaleMix + 1
|
end
|
||||||
|
if mixScaleY ~= 0 then
|
||||||
|
local s = (math_sqrt(tb * tb + td * td) - 1 + self.data.offsetScaleY) * mixScaleY + 1
|
||||||
bone.b = bone.b * s
|
bone.b = bone.b * s
|
||||||
bone.d = bone.d * s
|
bone.d = bone.d * s
|
||||||
modified = true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if shearMix > 0 then
|
if mixShearY > 0 then
|
||||||
local r = math_atan2(td, tb) - math_atan2(tc, ta)
|
local r = math_atan2(td, tb) - math_atan2(tc, ta)
|
||||||
if r > math_pi then
|
if r > math_pi then
|
||||||
r = r - math_pi2
|
r = r - math_pi2
|
||||||
@ -242,59 +240,54 @@ function TransformConstraint:applyRelativeWorld ()
|
|||||||
end
|
end
|
||||||
local b = bone.b
|
local b = bone.b
|
||||||
local d = bone.d
|
local d = bone.d
|
||||||
r = math_atan2(d, b) + (r - math_pi / 2 + offsetShearY) * shearMix
|
r = math_atan2(d, b) + (r - math_pi / 2 + offsetShearY) * mixShearY
|
||||||
local s = math_sqrt(b * b + d * d)
|
local s = math_sqrt(b * b + d * d)
|
||||||
bone.b = math_cos(r) * s
|
bone.b = math_cos(r) * s
|
||||||
bone.d = math_sin(r) * s
|
bone.d = math_sin(r) * s
|
||||||
modified = true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if modified then bone.appliedValid = false end
|
bone:updateAppliedTransform()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function TransformConstraint:applyAbsoluteLocal ()
|
function TransformConstraint:applyAbsoluteLocal ()
|
||||||
local rotateMix = self.rotateMix
|
local mixRotate = self.mixRotate
|
||||||
local translateMix = self.translateMix
|
local mixX = self.mixX
|
||||||
local scaleMix = self.scaleMix
|
local mixY = self.mixY
|
||||||
local shearMix = self.shearMix
|
local mixScaleX = self.mixScaleX
|
||||||
|
local mixScaleY = self.mixScaleY
|
||||||
|
local mixShearY = self.mixShearY
|
||||||
|
|
||||||
local target = self.target
|
local target = self.target
|
||||||
if not target.appliedValid then target:updatedAppliedTransform() end
|
if not target.appliedValid then target:updatedAppliedTransform() end
|
||||||
local bones = self.bones
|
local bones = self.bones
|
||||||
for _, bone in ipairs(bones) do
|
for _, bone in ipairs(bones) do
|
||||||
local modified = false
|
|
||||||
if not bone.appliedValid then bone:updateAppliedTransform() end
|
|
||||||
|
|
||||||
local rotation = bone.arotation
|
local rotation = bone.arotation
|
||||||
if rotateMix ~= 0 then
|
if mixRotate ~= 0 then
|
||||||
local r = target.arotation - rotation + self.data.offsetRotation
|
local r = target.arotation - rotation + self.data.offsetRotation
|
||||||
r = r - (16384 - math_floor(16384.499999999996 - r / 360)) * 360
|
r = r - (16384 - math_floor(16384.499999999996 - r / 360)) * 360
|
||||||
rotation = rotation + r * rotateMix
|
rotation = rotation + r * mixRotate
|
||||||
end
|
end
|
||||||
|
|
||||||
local x = bone.ax
|
local x = bone.ax
|
||||||
local y = bone.ay
|
local y = bone.ay
|
||||||
if translateMix ~= 0 then
|
x = x + (target.ax - x + self.data.offsetX) * mixX
|
||||||
x = x + (target.ax - x + self.data.offsetX) * translateMix
|
y = x + (target.ay - y + self.data.offsetY) * mixX
|
||||||
y = x + (target.ay - y + self.data.offsetY) * translateMix
|
|
||||||
end
|
|
||||||
|
|
||||||
local scaleX = bone.ascaleX
|
local scaleX = bone.ascaleX
|
||||||
local scaleY = bone.ascaleY
|
local scaleY = bone.ascaleY
|
||||||
if scaleMix ~= 0 then
|
if mixScaleX ~= 0 and scaleX ~= 0 then
|
||||||
if scaleX > 0.00001 then
|
scaleX = (scaleX + (target.ascaleX - scaleX + self.data.offsetScaleX) * mixScaleX) / scaleX
|
||||||
scaleX = (scaleX + (target.ascaleX - scaleX + self.data.offsetScaleX) * scaleMix) / scaleX
|
end
|
||||||
end
|
if mixScaleY ~= 0 and scaleY ~= 0 then
|
||||||
if scaleY > 0.00001 then
|
scaleY = (scaleY + (target.ascaleY - scaleY + self.data.offsetScaleY) * mixScaleY) / scaleY
|
||||||
scaleY = (scaleY + (target.ascaleY - scaleY + self.data.offsetScaleY) * scaleMix) / scaleY
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local shearY = bone.ashearY
|
local shearY = bone.ashearY
|
||||||
if shearMix ~= 0 then
|
if mixShearY ~= 0 then
|
||||||
local r = target.ashearY - shearY + self.data.offsetShearY
|
local r = target.ashearY - shearY + self.data.offsetShearY
|
||||||
r = r - (16384 - math_floor(16384.499999999996 - r / 360)) * 360
|
r = r - (16384 - math_floor(16384.499999999996 - r / 360)) * 360
|
||||||
bone.shearY = bone.shearY + r * shearMix
|
bone.shearY = bone.shearY + r * mixShearY
|
||||||
end
|
end
|
||||||
|
|
||||||
bone:updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY)
|
bone:updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY)
|
||||||
@ -302,40 +295,23 @@ function TransformConstraint:applyAbsoluteLocal ()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function TransformConstraint:applyRelativeLocal ()
|
function TransformConstraint:applyRelativeLocal ()
|
||||||
local rotateMix = self.rotateMix
|
local mixRotate = self.mixRotate
|
||||||
local translateMix = self.translateMix
|
local mixX = self.mixX
|
||||||
local scaleMix = self.scaleMix
|
local mixY = self.mixY
|
||||||
local shearMix = self.shearMix
|
local mixScaleX = self.mixScaleX
|
||||||
|
local mixScaleY = self.mixScaleY
|
||||||
|
local mixShearY = self.mixShearY
|
||||||
|
|
||||||
local target = self.target
|
local target = self.target
|
||||||
if not target.appliedValid then target:updateAppliedTransform() end
|
|
||||||
local bones = self.bones
|
local bones = self.bones
|
||||||
for _, bone in ipairs(bones) do
|
for _, bone in ipairs(bones) do
|
||||||
if not bone.appliedValid then bone:updateAppliedTransform() end
|
local rotation = bone.arotation + (target.arotation + this.data.offsetRotation) * mixRotate
|
||||||
|
local x = bone.ax + (target.ax + this.data.offsetX) * mixX
|
||||||
local rotation = bone.arotation
|
local y = bone.ay + (target.ay + this.data.offsetY) * mixY
|
||||||
if rotateMix ~= 0 then rotation = rotation + (target.arotation + self.data.offsetRotation) * rotateMix end
|
local scaleX = (bone.ascaleX * ((target.ascaleX - 1 + this.data.offsetScaleX) * mixScaleX) + 1)
|
||||||
|
local scaleY = (bone.ascaleY * ((target.ascaleY - 1 + this.data.offsetScaleY) * mixScaleY) + 1)
|
||||||
local x = bone.ax
|
local shearY = bone.ashearY + (target.ashearY + this.data.offsetShearY) * mixShearY
|
||||||
local y = bone.ay
|
|
||||||
if translateMix ~= 0 then
|
|
||||||
x = x + (target.ax + self.data.offsetX) * translateMix
|
|
||||||
y = y + (target.ay + self.data.offsetY) * translateMix
|
|
||||||
end
|
|
||||||
|
|
||||||
local scaleX = bone.ascaleX
|
|
||||||
local scaleY = bone.ascaleY
|
|
||||||
if scaleMix ~= 0 then
|
|
||||||
if scaleX > 0.00001 then
|
|
||||||
scaleX = scaleX * (((target.ascaleX - 1 + self.data.offsetScaleX) * scaleMix) + 1)
|
|
||||||
end
|
|
||||||
if scaleY > 0.00001 then
|
|
||||||
scaleY = scaleY * (((target.ascaleY - 1 + self.data.offsetScaleY) * scaleMix) + 1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local shearY = bone.ashearY
|
|
||||||
if shearMix ~= 0 then shearY = shearY + (target.ashearY + self.data.offsetShearY) * shearMix end
|
|
||||||
|
|
||||||
bone:updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY)
|
bone:updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -37,7 +37,7 @@ function TransformConstraintData.new (name)
|
|||||||
skinRequired = false,
|
skinRequired = false,
|
||||||
bones = {},
|
bones = {},
|
||||||
target = nil,
|
target = nil,
|
||||||
rotateMix = 0, translateMix = 0, scaleMix = 0, shearMix = 0,
|
mixRotate = 0, mixX = 0, mixY = 0, mixScaleX = 0, mixScaleY = 0, mixShearY = 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,
|
relative = false,
|
||||||
local_ = false
|
local_ = false
|
||||||
|
|||||||
@ -37,7 +37,6 @@ local AttachmentType = require "spine-lua.attachments.AttachmentType"
|
|||||||
local Attachment = require "spine-lua.attachments.Attachment"
|
local Attachment = require "spine-lua.attachments.Attachment"
|
||||||
|
|
||||||
local nextID = 0
|
local nextID = 0
|
||||||
local SHL_11 = 2048
|
|
||||||
|
|
||||||
local VertexAttachment = {}
|
local VertexAttachment = {}
|
||||||
VertexAttachment.__index = VertexAttachment
|
VertexAttachment.__index = VertexAttachment
|
||||||
@ -45,16 +44,16 @@ setmetatable(VertexAttachment, { __index = Attachment })
|
|||||||
|
|
||||||
function VertexAttachment.new (name, attachmentType)
|
function VertexAttachment.new (name, attachmentType)
|
||||||
local self = Attachment.new(name, attachmentType)
|
local self = Attachment.new(name, attachmentType)
|
||||||
self.vertexAttachment = true
|
|
||||||
|
self.id = nextID
|
||||||
|
nextID = nextID + 1
|
||||||
|
|
||||||
|
self.isVertexAttachment = true
|
||||||
self.bones = nil
|
self.bones = nil
|
||||||
self.vertices = nil
|
self.vertices = nil
|
||||||
self.worldVerticesLength = 0
|
self.worldVerticesLength = 0
|
||||||
while nextID > 65535 do
|
|
||||||
nextID = nextID - 65535
|
|
||||||
end
|
|
||||||
self.id = nextID * SHL_11
|
|
||||||
self.deformAttachment = self
|
self.deformAttachment = self
|
||||||
nextID = nextID + 1
|
|
||||||
setmetatable(self, VertexAttachment)
|
setmetatable(self, VertexAttachment)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user