[lua] Ported Animation/Timeline changes

This commit is contained in:
badlogic 2017-06-14 14:59:24 +02:00
parent 060c846f75
commit 2a973da308
4 changed files with 169 additions and 86 deletions

View File

@ -45,6 +45,7 @@
* Added `spClippingAttachment` and respective enum. * Added `spClippingAttachment` and respective enum.
* Added `spSkeletonClipper` and `spTriangulator`, used to implement software clipping of attachments. * Added `spSkeletonClipper` and `spTriangulator`, used to implement software clipping of attachments.
* `AnimationState#apply` returns boolean indicating if any timeline was applied or not. * `AnimationState#apply` returns boolean indicating if any timeline was applied or not.
* `Animation#apply` and `Timeline#apply`` now take enums `MixPose` and `MixDirection` instead of booleans
### Cocos2d-X ### Cocos2d-X
* Fixed renderer to work with 3.6 changes * Fixed renderer to work with 3.6 changes
@ -76,6 +77,7 @@
* `MeshAttachment.parentMesh` is now a private field to enforce using the `.ParentMesh` setter property in external code. The `MeshAttachment.ParentMesh` property is an appropriate replacement wherever `.parentMesh` was used. * `MeshAttachment.parentMesh` is now a private field to enforce using the `.ParentMesh` setter property in external code. The `MeshAttachment.ParentMesh` property is an appropriate replacement wherever `.parentMesh` was used.
* **Additions** * **Additions**
* `AnimationState#apply` returns boolean indicating if any timeline was applied or not. * `AnimationState#apply` returns boolean indicating if any timeline was applied or not.
* `Animation#apply` and `Timeline#apply`` now take enums `MixPose` and `MixDirection` instead of booleans
### Unity ### Unity
* Refactored renderer to work with new 3.6 features. * Refactored renderer to work with new 3.6 features.
@ -133,6 +135,7 @@
* Added `ClippingAttachment`, additional method `newClippingAttachment` in `AttachmentLoader` interface. * Added `ClippingAttachment`, additional method `newClippingAttachment` in `AttachmentLoader` interface.
* Added `SkeletonClipper` and `Triangulator`, used to implement software clipping of attachments. * Added `SkeletonClipper` and `Triangulator`, used to implement software clipping of attachments.
* `AnimationState#apply` returns boolean indicating if any timeline was applied or not. * `AnimationState#apply` returns boolean indicating if any timeline was applied or not.
* `Animation#apply` and `Timeline#apply`` now take enums `MixPose` and `MixDirection` instead of booleans
### libGDX ### libGDX
* Fixed renderer to work with 3.6 changes * Fixed renderer to work with 3.6 changes
@ -154,6 +157,7 @@
* Added `ClippingAttachment`, additional method `newClippingAttachment` in `AttachmentLoader` interface. * Added `ClippingAttachment`, additional method `newClippingAttachment` in `AttachmentLoader` interface.
* Added `SkeletonClipper` and `Triangulator`, used to implement software clipping of attachments. * Added `SkeletonClipper` and `Triangulator`, used to implement software clipping of attachments.
* `AnimationState#apply` returns boolean indicating if any timeline was applied or not. * `AnimationState#apply` returns boolean indicating if any timeline was applied or not.
* `Animation#apply` and `Timeline#apply`` now take enums `MixPose` and `MixDirection` instead of booleans
### Love2D ### Love2D
* Fixed renderer to work with 3.6 changes * Fixed renderer to work with 3.6 changes

View File

@ -54,7 +54,7 @@ function Animation.new (name, timelines, duration)
duration = duration duration = duration
} }
function self:apply (skeleton, lastTime, time, loop, events, alpha, setupPose, mixingOut) function self:apply (skeleton, lastTime, time, loop, events, alpha, pose, direction)
if not skeleton then error("skeleton cannot be nil.", 2) end if not skeleton then error("skeleton cannot be nil.", 2) end
if loop and duration > 0 then if loop and duration > 0 then
@ -63,7 +63,7 @@ function Animation.new (name, timelines, duration)
end end
for i,timeline in ipairs(self.timelines) do for i,timeline in ipairs(self.timelines) do
timeline:apply(skeleton, lastTime, time, events, alpha, setupPose, mixingOut) timeline:apply(skeleton, lastTime, time, events, alpha, pose, direction)
end end
end end
@ -113,6 +113,18 @@ local function linearSearch (values, target, step)
return -1 return -1
end end
Animation.MixPose = {
setup = 0,
current = 1,
currentLayered = 2
}
local MixPose = Animation.MixPose
Animation.MixDirection = {
_in = 0, out = 1
}
local MixDirection = Animation.MixDirection
Animation.TimelineType = { Animation.TimelineType = {
rotate = 0, translate = 1, scale = 2, shear = 3, rotate = 0, translate = 1, scale = 2, shear = 3,
attachment = 4, color = 5, deform = 6, attachment = 4, color = 5, deform = 6,
@ -123,6 +135,7 @@ Animation.TimelineType = {
} }
local TimelineType = Animation.TimelineType local TimelineType = Animation.TimelineType
local SHL_24 = 16777216 local SHL_24 = 16777216
local SHL_27 = 134217728
Animation.CurveTimeline = {} Animation.CurveTimeline = {}
function Animation.CurveTimeline.new (frameCount) function Animation.CurveTimeline.new (frameCount)
@ -242,19 +255,23 @@ function Animation.RotateTimeline.new (frameCount)
self.frames[frameIndex + ROTATION] = degrees self.frames[frameIndex + ROTATION] = degrees
end end
function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut) function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
local frames = self.frames local frames = self.frames
local bone = skeleton.bones[self.boneIndex] local bone = skeleton.bones[self.boneIndex]
if time < frames[0] then if time < frames[0] then
if setupPose then if pose == MixPose.setup then
bone.rotation = bone.data.rotation bone.rotation = bone.data.rotation
elseif pose == MixPose.current then
local r = bone.data.rotation - bone.rotation
r = r - (16384 - math_floor(16384.499999999996 - r / 360)) * 360 -- Wrap within -180 and 180.
bone.rotation = bone.rotation + r * alpha
end end
return return
end end
if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame.
if setupPose then if pose == MixPose.setup then
bone.rotation = bone.data.rotation + frames[zlen(frames) + PREV_ROTATION] * alpha bone.rotation = bone.data.rotation + frames[zlen(frames) + PREV_ROTATION] * alpha
else else
local r = bone.data.rotation + frames[zlen(frames) + PREV_ROTATION] - bone.rotation local r = bone.data.rotation + frames[zlen(frames) + PREV_ROTATION] - bone.rotation
@ -273,7 +290,7 @@ function Animation.RotateTimeline.new (frameCount)
local r = frames[frame + ROTATION] - prevRotation local r = frames[frame + ROTATION] - prevRotation
r = r - (16384 - math_floor(16384.499999999996 - r / 360)) * 360 r = r - (16384 - math_floor(16384.499999999996 - r / 360)) * 360
r = prevRotation + r * percent r = prevRotation + r * percent
if setupPose then if pose == MixPose.setup then
r = r - (16384 - math_floor(16384.499999999996 - r / 360)) * 360 r = r - (16384 - math_floor(16384.499999999996 - r / 360)) * 360
bone.rotation = bone.data.rotation + r * alpha bone.rotation = bone.data.rotation + r * alpha
else else
@ -312,14 +329,17 @@ function Animation.TranslateTimeline.new (frameCount)
self.frames[frameIndex + Y] = y self.frames[frameIndex + Y] = y
end end
function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut) function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
local frames = self.frames local frames = self.frames
local bone = skeleton.bones[self.boneIndex] local bone = skeleton.bones[self.boneIndex]
if time < frames[0] then if time < frames[0] then
if (setupPose) then if pose == MixPose.setup then
bone.x = bone.data.x bone.x = bone.data.x
bone.y = bone.data.y bone.y = bone.data.y
elseif pose == MixPose.current then
bone.x = bone.x + (bone.data.x - bone.x) * alpha
bone.y = bone.y + (bone.data.y - bone.y) * alpha
end end
return return
end end
@ -341,7 +361,7 @@ function Animation.TranslateTimeline.new (frameCount)
x = x + (frames[frame + X] - x) * percent x = x + (frames[frame + X] - x) * percent
y = y + (frames[frame + Y] - y) * percent y = y + (frames[frame + Y] - y) * percent
end end
if setupPose then if pose == MixPose.setup then
bone.x = bone.data.x + x * alpha bone.x = bone.data.x + x * alpha
bone.y = bone.data.y + y * alpha bone.y = bone.data.y + y * alpha
else else
@ -370,14 +390,17 @@ function Animation.ScaleTimeline.new (frameCount)
return TimelineType.scale * SHL_24 + self.boneIndex return TimelineType.scale * SHL_24 + self.boneIndex
end end
function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut) function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
local frames = self.frames local frames = self.frames
local bone = skeleton.bones[self.boneIndex] local bone = skeleton.bones[self.boneIndex]
if time < frames[0] then if time < frames[0] then
if setupPose then if pose == MixPose.setup then
bone.scaleX = bone.data.scaleX bone.scaleX = bone.data.scaleX
bone.scaleY = bone.data.scaleY bone.scaleY = bone.data.scaleY
elseif pose == MixPose.current then
bone.scaleX = bone.scaleX + (bone.data.scaleX - bone.scaleX) * alpha
bone.scaleY = bone.scaleY + (bone.data.scaleY - bone.scaleY) * alpha
end end
return return
end end
@ -405,7 +428,7 @@ function Animation.ScaleTimeline.new (frameCount)
else else
local bx = 0 local bx = 0
local by = 0 local by = 0
if setupPose then if pose == MixPose.setup then
bx = bone.data.scaleX bx = bone.data.scaleX
by = bone.data.scaleY by = bone.data.scaleY
else else
@ -413,7 +436,7 @@ function Animation.ScaleTimeline.new (frameCount)
by = bone.scaleY by = bone.scaleY
end end
-- Mixing out uses sign of setup or current pose, else use sign of key. -- Mixing out uses sign of setup or current pose, else use sign of key.
if mixingOut then if direction == MixDirection.out then
x = math_abs(x) * math_signum(bx) x = math_abs(x) * math_signum(bx)
y = math_abs(y) * math_signum(by) y = math_abs(y) * math_signum(by)
else else
@ -445,14 +468,17 @@ function Animation.ShearTimeline.new (frameCount)
return TimelineType.shear * SHL_24 + self.boneIndex return TimelineType.shear * SHL_24 + self.boneIndex
end end
function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut) function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
local frames = self.frames local frames = self.frames
local bone = skeleton.bones[self.boneIndex] local bone = skeleton.bones[self.boneIndex]
if time < frames[0] then if time < frames[0] then
if setupPose then if pose == MixPose.setup then
bone.shearX = bone.data.shearX bone.shearX = bone.data.shearX
bone.shearY = bone.data.shearY bone.shearY = bone.data.shearY
elseif pose == MixPose.current then
bone.shearX = bone.shearX + (bone.data.shearX - bone.shearX) * alpha
bone.shearY = bone.shearX + (bone.data.shearY - bone.shearY) * alpha
end end
return return
end end
@ -474,7 +500,7 @@ function Animation.ShearTimeline.new (frameCount)
x = x + (frames[frame + X] - x) * percent x = x + (frames[frame + X] - x) * percent
y = y + (frames[frame + Y] - y) * percent y = y + (frames[frame + Y] - y) * percent
end end
if setupPose then if pose == MixPose.setup then
bone.shearX = bone.data.shearX + x * alpha bone.shearX = bone.data.shearX + x * alpha
bone.shearY = bone.data.shearY + y * alpha bone.shearY = bone.data.shearY + y * alpha
else else
@ -518,12 +544,17 @@ function Animation.ColorTimeline.new (frameCount)
self.frames[frameIndex + A] = a self.frames[frameIndex + A] = a
end end
function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut) function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
local frames = self.frames local frames = self.frames
local slot = skeleton.slots[self.slotIndex] local slot = skeleton.slots[self.slotIndex]
if time < frames[0] then if time < frames[0] then
if setupPose then if pose == MixPose.setup then
slot.color:setFrom(slot.data.color) slot.color:setFrom(slot.data.color)
elseif pose == MixPose.current then
local color = slot.color
local setup = slot.data.color
color:add((setup.r - color.r) * alpha, (setup.g - color.g) * alpha, (setup.b - color.b) * alpha,
(setup.a - color.a) * alpha)
end end
return return
end end
@ -555,7 +586,7 @@ function Animation.ColorTimeline.new (frameCount)
slot.color:set(r, g, b, a) slot.color:set(r, g, b, a)
else else
local color = slot.color local color = slot.color
if setupPose then color:setFrom(slot.data.color) end if pose == MixPose.setup then color:setFrom(slot.data.color) end
color:add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha) color:add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha)
end end
end end
@ -604,13 +635,21 @@ function Animation.TwoColorTimeline.new (frameCount)
self.frames[frameIndex + B2] = b2 self.frames[frameIndex + B2] = b2
end end
function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut) function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
local frames = self.frames local frames = self.frames
local slot = skeleton.slots[self.slotIndex] local slot = skeleton.slots[self.slotIndex]
if time < frames[0] then if time < frames[0] then
if setupPose then if pose == MixPose.setup then
slot.color:setFrom(slot.data.color) slot.color:setFrom(slot.data.color)
slot.darkColor:setFrom(slot.data.darkColor) slot.darkColor:setFrom(slot.data.darkColor)
elseif pose == MixPose.current then
local light = slot.color
local dark = slot.darkColor
local setupLight = slot.data.color
local setupDark = slot.data.darkColor
light:add((setupLight.r - light.r) * alpha, (setupLight.g - light.g) * alpha, (setupLight.b - light.b) * alpha,
(setupLight.a - light.a) * alpha)
dark:add((setupDark.r - dark.r) * alpha, (setupDark.g - dark.g) * alpha, (setupDark.b - dark.b) * alpha, 0)
end end
return return
end end
@ -653,7 +692,7 @@ function Animation.TwoColorTimeline.new (frameCount)
else else
local light = slot.color local light = slot.color
local dark = slot.darkColor local dark = slot.darkColor
if setupPose then if pose == MixPose.setup then
light:setFrom(slot.data.color) light:setFrom(slot.data.color)
dark:setFrom(slot.data.darkColor) dark:setFrom(slot.data.darkColor)
end end
@ -687,10 +726,10 @@ function Animation.AttachmentTimeline.new (frameCount)
return TimelineType.attachment * SHL_24 + self.slotIndex return TimelineType.attachment * SHL_24 + self.slotIndex
end end
function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut) function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
local slot = skeleton.slots[self.slotIndex] local slot = skeleton.slots[self.slotIndex]
local attachmentName local attachmentName
if mixingOut and setupPose then if direction == MixDirection.out and pose == MixPose.setup then
attachmentName = slot.data.attachmentName attachmentName = slot.data.attachmentName
if not attachmentName then if not attachmentName then
slot:setAttachment(nil) slot:setAttachment(nil)
@ -702,7 +741,7 @@ function Animation.AttachmentTimeline.new (frameCount)
local frames = self.frames local frames = self.frames
if time < frames[0] then if time < frames[0] then
if setupPose then if pose == MixPose.setup then
attachmentName = slot.data.attachmentName attachmentName = slot.data.attachmentName
if not attachmentName then if not attachmentName then
slot:setAttachment(nil) slot:setAttachment(nil)
@ -741,7 +780,7 @@ function Animation.DeformTimeline.new (frameCount)
self.type = TimelineType.deform self.type = TimelineType.deform
function self:getPropertyId () function self:getPropertyId ()
return TimelineType.deform * SHL_24 + self.slotIndex return TimelineType.deform * SHL_27 + self.attachment.id + self.slotIndex
end end
function self:setFrame (frameIndex, time, vertices) function self:setFrame (frameIndex, time, vertices)
@ -749,7 +788,7 @@ function Animation.DeformTimeline.new (frameCount)
self.frameVertices[frameIndex] = vertices self.frameVertices[frameIndex] = vertices
end end
function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut) function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
local slot = skeleton.slots[self.slotIndex] local slot = skeleton.slots[self.slotIndex]
local slotAttachment = slot.attachment local slotAttachment = slot.attachment
if not slotAttachment then return end if not slotAttachment then return end
@ -758,13 +797,6 @@ function Animation.DeformTimeline.new (frameCount)
local frames = self.frames local frames = self.frames
local verticesArray = slot.attachmentVertices local verticesArray = slot.attachmentVertices
if time < frames[0] then
if setupPose then
verticesArray = {}
slot.attachmentVertices = verticesArray
end
return
end
local frameVertices = self.frameVertices local frameVertices = self.frameVertices
local vertexCount = #(frameVertices[0]) local vertexCount = #(frameVertices[0])
@ -772,6 +804,21 @@ function Animation.DeformTimeline.new (frameCount)
if (#verticesArray ~= vertexCount and not setupPose) then alpha = 1 end -- Don't mix from uninitialized slot vertices. if (#verticesArray ~= vertexCount and not setupPose) then alpha = 1 end -- Don't mix from uninitialized slot vertices.
local vertices = utils.setArraySize(verticesArray, vertexCount) local vertices = utils.setArraySize(verticesArray, vertexCount)
if time < frames[0] then
if pose == MixPose.setup then
verticesArray = {}
slot.attachmentVertices = verticesArray
elseif pose == MixPose.current then
alpha = 1 - alpha
local i = 1
while i <= vertexCount do
vertices[i] = vertices[i] * alpha
i = i + 1
end
end
return
end
if time >= frames[zlen(frames) - 1] then -- Time is after last frame. if time >= frames[zlen(frames) - 1] then -- Time is after last frame.
local lastVertices = frameVertices[zlen(frames) - 1] local lastVertices = frameVertices[zlen(frames) - 1]
if alpha == 1 then if alpha == 1 then
@ -781,7 +828,7 @@ function Animation.DeformTimeline.new (frameCount)
vertices[i] = lastVertices[i] vertices[i] = lastVertices[i]
i = i + 1 i = i + 1
end end
elseif setupPose then elseif pose == MixPose.setup then
local vertexAttachment = slotAttachment local vertexAttachment = slotAttachment
if vertexAttachment.bones == nil then if vertexAttachment.bones == nil then
-- Unweighted vertex positions, with alpha. -- Unweighted vertex positions, with alpha.
@ -826,7 +873,7 @@ function Animation.DeformTimeline.new (frameCount)
vertices[i] = prev + (nextVertices[i] - prev) * percent vertices[i] = prev + (nextVertices[i] - prev) * percent
i = i + 1 i = i + 1
end end
elseif setupPose then elseif pose == MixPose.setup then
local vertexAttachment = slotAttachment local vertexAttachment = slotAttachment
if vertexAttachment.bones == nil then if vertexAttachment.bones == nil then
-- Unweighted vertex positions, with alpha. -- Unweighted vertex positions, with alpha.
@ -883,14 +930,14 @@ function Animation.EventTimeline.new (frameCount)
end end
-- Fires events for frames > lastTime and <= time. -- Fires events for frames > lastTime and <= time.
function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut) function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
if not firedEvents then return end if not firedEvents then return end
local frames = self.frames local frames = self.frames
local frameCount = zlen(frames) local frameCount = zlen(frames)
if lastTime > time then -- Fire events after last time for looped animations. if lastTime > time then -- Fire events after last time for looped animations.
self:apply(skeleton, lastTime, 999999, firedEvents, alpha, setupPose, mixingOut) self:apply(skeleton, lastTime, 999999, firedEvents, alpha, pose, direction)
lastTime = -1 lastTime = -1
elseif lastTime >= frames[frameCount - 1] then -- Last time is after last frame. elseif lastTime >= frames[frameCount - 1] then -- Last time is after last frame.
return return
@ -939,7 +986,7 @@ function Animation.DrawOrderTimeline.new (frameCount)
self.drawOrders[frameIndex] = drawOrder self.drawOrders[frameIndex] = drawOrder
end end
function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut) function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
local drawOrder = skeleton.drawOrder local drawOrder = skeleton.drawOrder
local slots = skeleton.slots local slots = skeleton.slots
if mixingOut and setupPose then if mixingOut and setupPose then
@ -950,7 +997,7 @@ function Animation.DrawOrderTimeline.new (frameCount)
end end
local frames = self.frames local frames = self.frames
if time < frames[0] then if time < frames[0] then
if setupPose then if pose == MixPose.setup then
for i,slot in ipairs(slots) do for i,slot in ipairs(slots) do
drawOrder[i] = slots[i] drawOrder[i] = slots[i]
end end
@ -1006,29 +1053,32 @@ function Animation.IkConstraintTimeline.new (frameCount)
self.frames[frameIndex + BEND_DIRECTION] = bendDirection self.frames[frameIndex + BEND_DIRECTION] = bendDirection
end end
function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut) function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
local frames = self.frames local frames = self.frames
local constraint = skeleton.ikConstraints[self.ikConstraintIndex] local constraint = skeleton.ikConstraints[self.ikConstraintIndex]
if time < frames[0] then if time < frames[0] then
if setupPose then if pose == MixPose.setup then
constraint.mix = constraint.data.mix constraint.mix = constraint.data.mix
constraint.bendDirection = constraint.data.bendDirection constraint.bendDirection = constraint.data.bendDirection
elseif pose == MixPose.current then
constraint.mix = constraint.mix + (constraint.data.mix - constraint.mix) * alpha
constraint.bendDirection = constraint.data.bendDirection
end end
return return
end end
if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame.
if setupPose then if pose == MixPose.setup then
constraint.mix = constraint.data.mix + (frames[zlen(frames) + PREV_MIX] - constraint.data.mix) * alpha constraint.mix = constraint.data.mix + (frames[zlen(frames) + PREV_MIX] - constraint.data.mix) * alpha
if mixingOut then if direction == MixDirection.out then
constraint.bendDirection = constraint.data.bendDirection constraint.bendDirection = constraint.data.bendDirection
else else
constraint.bendDirection = math_floor(frames[zlen(frames) + PREV_BEND_DIRECTION]); constraint.bendDirection = math_floor(frames[zlen(frames) + PREV_BEND_DIRECTION]);
end end
else else
constraint.mix = constraint.mix + (frames[frames.length + PREV_MIX] - constraint.mix) * alpha; constraint.mix = constraint.mix + (frames[frames.length + PREV_MIX] - constraint.mix) * alpha;
if not mixingOut then constraint.bendDirection = math_floor(frames[zlen(frames) + PREV_BEND_DIRECTION]) end if direction == MixDirection._in then constraint.bendDirection = math_floor(frames[zlen(frames) + PREV_BEND_DIRECTION]) end
end end
return return
end end
@ -1040,16 +1090,16 @@ function Animation.IkConstraintTimeline.new (frameCount)
local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1,
1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime))
if setupPose then if pose == MixPose.setup then
constraint.mix = constraint.data.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.data.mix) * alpha constraint.mix = constraint.data.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.data.mix) * alpha
if mixingOut then if direction == MixDirection.out then
constraint.bendDirection = constraint.data.bendDirection constraint.bendDirection = constraint.data.bendDirection
else else
constraint.bendDirection = math_floor(frames[frame + PREV_BEND_DIRECTION]) constraint.bendDirection = math_floor(frames[frame + PREV_BEND_DIRECTION])
end end
else else
constraint.mix = constraint.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha; constraint.mix = constraint.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha;
if not mixingOut then constraint.bendDirection = math_floor(frames[frame + PREV_BEND_DIRECTION]) end if direction == MixDirection._in then constraint.bendDirection = math_floor(frames[frame + PREV_BEND_DIRECTION]) end
end end
end end
@ -1088,17 +1138,22 @@ function Animation.TransformConstraintTimeline.new (frameCount)
self.frames[frameIndex + SHEAR] = shearMix self.frames[frameIndex + SHEAR] = shearMix
end end
function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut) function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
local frames = self.frames local frames = self.frames
local constraint = skeleton.transformConstraints[self.transformConstraintIndex] local constraint = skeleton.transformConstraints[self.transformConstraintIndex]
if time < frames[0] then if time < frames[0] then
if setupPose then
local data = constraint.data local data = constraint.data
if pose == MixPose.setup then
constraint.rotateMix = data.rotateMix constraint.rotateMix = data.rotateMix
constraint.translateMix = data.translateMix constraint.translateMix = data.translateMix
constraint.scaleMix = data.scaleMix constraint.scaleMix = data.scaleMix
constraint.shearMix = data.shearMix constraint.shearMix = data.shearMix
elseif pose == MixPose.current then
constraint.rotateMix = constraint.rotateMix + (data.rotateMix - constraint.rotateMix) * alpha
constraint.translateMix = constraint.translateMix + (data.translateMix - constraint.translateMix) * alpha
constraint.scaleMix = constraint.scaleMix + (data.scaleMix - constraint.scaleMix) * alpha
constraint.shearMix = constraint.shearMix + (data.shearMix - constraint.shearMix) * alpha
end end
return return
end end
@ -1129,7 +1184,7 @@ function Animation.TransformConstraintTimeline.new (frameCount)
scale = scale + (frames[frame + SCALE] - scale) * percent scale = scale + (frames[frame + SCALE] - scale) * percent
shear = shear + (frames[frame + SHEAR] - shear) * percent shear = shear + (frames[frame + SHEAR] - shear) * percent
end end
if setupPose then if pose == MixPose.setup then
local data = constraint.data local data = constraint.data
constraint.rotateMix = data.rotateMix + (rotate - data.rotateMix) * alpha constraint.rotateMix = data.rotateMix + (rotate - data.rotateMix) * alpha
constraint.translateMix = data.translateMix + (translate - data.translateMix) * alpha constraint.translateMix = data.translateMix + (translate - data.translateMix) * alpha
@ -1169,13 +1224,15 @@ function Animation.PathConstraintPositionTimeline.new (frameCount)
self.frames[frameIndex + VALUE] = value self.frames[frameIndex + VALUE] = value
end end
function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut) function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
local frames = self.frames local frames = self.frames
local constraint = skeleton.pathConstraints[self.pathConstraintIndex] local constraint = skeleton.pathConstraints[self.pathConstraintIndex]
if (time < frames[0]) then if (time < frames[0]) then
if setupPose then if pose == MixPose.setup then
constraint.position = constraint.data.position constraint.position = constraint.data.position
elseif pose == MixPose.current then
constraint.position = constraint.position + (constraint.data.position - constraint.position) * alpha
end end
return return
end end
@ -1193,7 +1250,7 @@ function Animation.PathConstraintPositionTimeline.new (frameCount)
position = position + (frames[frame + VALUE] - position) * percent position = position + (frames[frame + VALUE] - position) * percent
end end
if setupPose then if pose == MixPose.setup then
constraint.position = constraint.data.position + (position - constraint.data.position) * alpha constraint.position = constraint.data.position + (position - constraint.data.position) * alpha
else else
constraint.position = constraint.position + (position - constraint.position) * alpha constraint.position = constraint.position + (position - constraint.position) * alpha
@ -1226,13 +1283,15 @@ function Animation.PathConstraintSpacingTimeline.new (frameCount)
self.frames[frameIndex + VALUE] = value self.frames[frameIndex + VALUE] = value
end end
function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut) function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
local frames = self.frames local frames = self.frames
local constraint = skeleton.pathConstraints[self.pathConstraintIndex] local constraint = skeleton.pathConstraints[self.pathConstraintIndex]
if (time < frames[0]) then if (time < frames[0]) then
if setupPose then if pose == MixPose.setup then
constraint.spacing = constraint.data.spacing constraint.spacing = constraint.data.spacing
elseif pose == MixPose.current then
constraint.spacing = constraint.spacing + (constraint.data.spacing - constraint.spacing) * alpha
end end
return return
end end
@ -1251,7 +1310,7 @@ function Animation.PathConstraintSpacingTimeline.new (frameCount)
spacing = spacing + (frames[frame + VALUE] - spacing) * percent spacing = spacing + (frames[frame + VALUE] - spacing) * percent
end end
if setupPose then if pose == MixPose.setup then
constraint.spacing = constraint.data.spacing + (spacing - constraint.data.spacing) * alpha constraint.spacing = constraint.data.spacing + (spacing - constraint.data.spacing) * alpha
else else
constraint.spacing = constraint.spacing + (spacing - constraint.spacing) * alpha constraint.spacing = constraint.spacing + (spacing - constraint.spacing) * alpha
@ -1287,14 +1346,17 @@ function Animation.PathConstraintMixTimeline.new (frameCount)
self.frames[frameIndex + TRANSLATE] = translateMix self.frames[frameIndex + TRANSLATE] = translateMix
end end
function self:apply (skeleton, lastTime, time, firedEvents, alpha, setupPose, mixingOut) function self:apply (skeleton, lastTime, time, firedEvents, alpha, pose, direction)
local frames = self.frames local frames = self.frames
local constraint = skeleton.pathConstraints[self.pathConstraintIndex] local constraint = skeleton.pathConstraints[self.pathConstraintIndex]
if (time < frames[0]) then if (time < frames[0]) then
if setupPose then if pose == MixPose.setup then
constraint.rotateMix = constraint.data.rotateMix constraint.rotateMix = constraint.data.rotateMix
constraint.translateMix = constraint.data.translateMix constraint.translateMix = constraint.data.translateMix
elseif pose == MixPose.current then
constraint.rotateMix = constraint.rotateMix + (constraint.data.rotateMix - constraint.rotateMix) * alpha
constraint.translateMix = constraint.translateMix + (constraint.data.translateMix - constraint.translateMix) * alpha
end end
return return
end end
@ -1317,7 +1379,7 @@ function Animation.PathConstraintMixTimeline.new (frameCount)
translate = translate + (frames[frame + TRANSLATE] - translate) * percent translate = translate + (frames[frame + TRANSLATE] - translate) * percent
end end
if setupPose then if pose == MixPose.setup then
constraint.rotateMix = constraint.data.rotateMix + (rotate - constraint.data.rotateMix) * alpha constraint.rotateMix = constraint.data.rotateMix + (rotate - constraint.data.rotateMix) * alpha
constraint.translateMix = constraint.data.translateMix + (translate - constraint.data.translateMix) * alpha constraint.translateMix = constraint.data.translateMix + (translate - constraint.data.translateMix) * alpha
else else

View File

@ -32,6 +32,8 @@ local setmetatable = setmetatable
local table_insert = table.insert local table_insert = table.insert
local utils = require "spine-lua.utils" local utils = require "spine-lua.utils"
local Animation = require "spine-lua.Animation" local Animation = require "spine-lua.Animation"
local MixPose = Animation.MixPose
local MixDirection = Animation.MixDirection
local AnimationStateData = require "spine-lua.AnimationStateData" local AnimationStateData = require "spine-lua.AnimationStateData"
local math_min = math.min local math_min = math.min
local math_max = math.max local math_max = math.max
@ -371,10 +373,13 @@ function AnimationState:apply (skeleton)
for i,current in pairs(tracks) do for i,current in pairs(tracks) do
if not (current == nil or current.delay > 0) then if not (current == nil or current.delay > 0) then
applied = true applied = true
local currrentPose = MixPose.currentLayered
if i == 0 then currentPose = MixPose.current end
-- Apply mixing from entries first. -- Apply mixing from entries first.
local mix = current.alpha local mix = current.alpha
if current.mixingFrom then if current.mixingFrom then
mix = mix * self:applyMixingFrom(current, skeleton) mix = mix * self:applyMixingFrom(current, skeleton, currentPose)
elseif current.trackTime >= current.trackEnd and current.next == nil then elseif current.trackTime >= current.trackEnd and current.next == nil then
mix = 0 mix = 0
end end
@ -385,7 +390,7 @@ function AnimationState:apply (skeleton)
local timelines = current.animation.timelines local timelines = current.animation.timelines
if mix == 1 then if mix == 1 then
for i,timeline in ipairs(timelines) do for i,timeline in ipairs(timelines) do
timeline:apply(skeleton, animationLast, animationTime, events, 1, true, false) timeline:apply(skeleton, animationLast, animationTime, events, 1, MixPose.setup, MixDirection._in)
end end
else else
local timelineData = current.timelineData local timelineData = current.timelineData
@ -393,11 +398,14 @@ function AnimationState:apply (skeleton)
local timelinesRotation = current.timelinesRotation local timelinesRotation = current.timelinesRotation
for i,timeline in ipairs(timelines) do for i,timeline in ipairs(timelines) do
local pose = MixPose.currentPose
if timelineData[i] >= FIRST then pose = MixPose.setup end
if timeline.type == Animation.TimelineType.rotate then if timeline.type == Animation.TimelineType.rotate then
self:applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineData[i] >= FIRST, timelinesRotation, i * 2, self:applyRotateTimeline(timeline, skeleton, animationTime, mix, pose, timelinesRotation, i * 2,
firstFrame) -- FIXME passing ii * 2, indexing correct? firstFrame) -- FIXME passing ii * 2, indexing correct?
else else
timeline:apply(skeleton, animationLast, animationTime, events, mix, timelineData[i] >= FIRST, false) timeline:apply(skeleton, animationLast, animationTime, events, mix, pose, MixDirection._in)
end end
end end
end end
@ -412,9 +420,9 @@ function AnimationState:apply (skeleton)
return applied return applied
end end
function AnimationState:applyMixingFrom (to, skeleton) function AnimationState:applyMixingFrom (to, skeleton, currentPose)
local from = to.mixingFrom local from = to.mixingFrom
if from.mixingFrom then self:applyMixingFrom(from, skeleton) end if from.mixingFrom then self:applyMixingFrom(from, skeleton, currentPose) end
local mix = 0 local mix = 0
if to.mixDuration == 0 then -- Single frame mix to undo mixingFrom changes. if to.mixDuration == 0 then -- Single frame mix to undo mixingFrom changes.
@ -437,38 +445,39 @@ function AnimationState:applyMixingFrom (to, skeleton)
local firstFrame = #from.timelinesRotation == 0 local firstFrame = #from.timelinesRotation == 0
local timelinesRotation = from.timelinesRotation local timelinesRotation = from.timelinesRotation
local first = false local pose = MixPose.setup
local alphaDip = from.alpha * to.interruptAlpha local alphaDip = from.alpha * to.interruptAlpha
local alphaMix = alphaDip * (1 - mix) local alphaMix = alphaDip * (1 - mix)
local alpha = 0 local alpha = 0
from.totalAlpha = 0; from.totalAlpha = 0;
local skip = false
for i,timeline in ipairs(timelines) do
for i,timeline in ipairs(timelines) do
local skipSubsequent = false;
if timelineData[i] == SUBSEQUENT then if timelineData[i] == SUBSEQUENT then
first = false if not attachments and timeline.type == Animation.TimelineType.attachment then skipSubsequent = true end
if not drawOrder and timeline.type == Animation.TimelineType.drawOrder then skipSubsequent = true end
pose = currentPose
alpha = alphaMix alpha = alphaMix
elseif timelineData[i] == FIRST then elseif timelineData[i] == FIRST then
first = true pose = MixPose.setup
alpha = alphaMix alpha = alphaMix
elseif timelineData[i] == DIP then elseif timelineData[i] == DIP then
first = true pose = MixPose.setup
alpha = alphaDip alpha = alphaDip
else else
first = true pose = MixPose.setup
alpha = alphaDip alpha = alphaDip
local dipMix = timelineDipMix[i] local dipMix = timelineDipMix[i]
alpha = alpha * math_max(0, 1 - dipMix.mixtime / dipMix.mixDuration) alpha = alpha * math_max(0, 1 - dipMix.mixtime / dipMix.mixDuration)
end end
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, first, timelinesRotation, i * 2, firstFrame) self:applyRotateTimeline(timeline, skeleton, animationTime, alpha, pose, timelinesRotation, i * 2, firstFrame)
else else
if not first then timeline:apply(skeleton, animationLast, animationTime, events, alpha, pose, MixDirection.out)
if not attachments and timeline.type == Animation.TimelineType.attackment then skip = true end
if not drawOrder and timeline.type == Animation.TimelineType.drawOrder then skip = true end
end end
if not skip then timeline:apply(skeleton, animationLast, animationTime, events, alpha, first, true) end
end end
end end
@ -480,14 +489,14 @@ function AnimationState:applyMixingFrom (to, skeleton)
return mix return mix
end end
function AnimationState:applyRotateTimeline (timeline, skeleton, time, alpha, setupPose, timelinesRotation, i, firstFrame) function AnimationState:applyRotateTimeline (timeline, skeleton, time, alpha, pose, timelinesRotation, i, firstFrame)
if firstFrame then if firstFrame then
timelinesRotation[i] = 0 timelinesRotation[i] = 0
timelinesRotation[i+1] = 0 timelinesRotation[i+1] = 0
end end
if alpha == 1 then if alpha == 1 then
timeline:apply(skeleton, 0, time, nil, 1, setupPose, false) timeline:apply(skeleton, 0, time, nil, 1, pose, MixDirection._in)
return return
end end
@ -495,7 +504,7 @@ function AnimationState:applyRotateTimeline (timeline, skeleton, time, alpha, se
local frames = rotateTimeline.frames local frames = rotateTimeline.frames
local bone = skeleton.bones[rotateTimeline.boneIndex] local bone = skeleton.bones[rotateTimeline.boneIndex]
if time < frames[0] then if time < frames[0] then
if setupPose then bone.rotation = bone.data.rotation end if pose == MixPose.setup then bone.rotation = bone.data.rotation end
return return
end end
@ -518,7 +527,7 @@ function AnimationState:applyRotateTimeline (timeline, skeleton, time, alpha, se
-- 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.
local r1 = bone.rotation local r1 = bone.rotation
if setupPose then r1 = bone.data.rotation end if pose == MixPose.setup then r1 = bone.data.rotation end
local total = 0 local total = 0
local diff = r2 - r1 local diff = r2 - r1
if diff == 0 then if diff == 0 then

View File

@ -37,6 +37,9 @@ local setmetatable = setmetatable
local AttachmentType = require "spine-lua.attachments.AttachmentType" 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 SHL_11 = 2048;
local VertexAttachment = {} local VertexAttachment = {}
VertexAttachment.__index = VertexAttachment VertexAttachment.__index = VertexAttachment
setmetatable(VertexAttachment, { __index = Attachment }) setmetatable(VertexAttachment, { __index = Attachment })
@ -46,6 +49,11 @@ function VertexAttachment.new (name, attachmentType)
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
nextID = nextID + 1
setmetatable(self, VertexAttachment) setmetatable(self, VertexAttachment)
return self return self
end end