mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
[lua] Port AnimationState deform mixing while attachment timelines mix out. See #1653.
This commit is contained in:
parent
049adf7e2b
commit
993e59f6bd
@ -775,16 +775,22 @@ function Animation.AttachmentTimeline.new (frameCount)
|
|||||||
return TimelineType.attachment * SHL_24 + self.slotIndex
|
return TimelineType.attachment * SHL_24 + self.slotIndex
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function self:setAttachment(skeleton, slot, attachmentName)
|
||||||
|
attachmentName = slot.data.attachmentName
|
||||||
|
if not attachmentName then
|
||||||
|
slot:setAttachment(nil)
|
||||||
|
else
|
||||||
|
slot:setAttachment(skeleton:getAttachmentByIndex(self.slotIndex, attachmentName))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function self:apply (skeleton, lastTime, time, firedEvents, alpha, blend, direction)
|
function self:apply (skeleton, lastTime, time, firedEvents, alpha, blend, direction)
|
||||||
local slot = skeleton.slots[self.slotIndex]
|
local slot = skeleton.slots[self.slotIndex]
|
||||||
if not slot.bone.active then return end
|
if not slot.bone.active then return end
|
||||||
local attachmentName
|
local attachmentName
|
||||||
if direction == MixDirection.out and blend == MixBlend.setup then
|
if direction == MixDirection.out then
|
||||||
attachmentName = slot.data.attachmentName
|
if blend == MixBlend.setup then
|
||||||
if not attachmentName then
|
self:setAttachment(skeleton, slot, slot.data.attachmentName)
|
||||||
slot:setAttachment(nil)
|
|
||||||
else
|
|
||||||
slot:setAttachment(skeleton:getAttachmentByIndex(self.slotIndex, attachmentName))
|
|
||||||
end
|
end
|
||||||
return;
|
return;
|
||||||
end
|
end
|
||||||
@ -792,12 +798,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 blend == MixBlend.setup or blend == MixBlend.first then
|
if blend == MixBlend.setup or blend == MixBlend.first then
|
||||||
attachmentName = slot.data.attachmentName
|
self:setAttachment(skeleton, slot, slot.data.attachmentName)
|
||||||
if not attachmentName then
|
|
||||||
slot:setAttachment(nil)
|
|
||||||
else
|
|
||||||
slot:setAttachment(skeleton:getAttachmentByIndex(self.slotIndex, attachmentName))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -1150,9 +1151,11 @@ function Animation.DrawOrderTimeline.new (frameCount)
|
|||||||
function self:apply (skeleton, lastTime, time, firedEvents, alpha, blend, direction)
|
function self:apply (skeleton, lastTime, time, firedEvents, alpha, blend, direction)
|
||||||
local drawOrder = skeleton.drawOrder
|
local drawOrder = skeleton.drawOrder
|
||||||
local slots = skeleton.slots
|
local slots = skeleton.slots
|
||||||
if direction == MixDirection.out and blend == MixBlend.setup then
|
if direction == MixDirection.out then
|
||||||
for i,slot in ipairs(slots) do
|
if blend == MixBlend.setup then
|
||||||
drawOrder[i] = slots[i]
|
for i,slot in ipairs(slots) do
|
||||||
|
drawOrder[i] = slots[i]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return;
|
return;
|
||||||
end
|
end
|
||||||
|
|||||||
@ -54,7 +54,9 @@ local SUBSEQUENT = 0
|
|||||||
local FIRST = 1
|
local FIRST = 1
|
||||||
local HOLD = 2
|
local HOLD = 2
|
||||||
local HOLD_MIX = 3
|
local HOLD_MIX = 3
|
||||||
local NOT_LAST = 4
|
|
||||||
|
local SETUP = 1
|
||||||
|
local CURRENT = 2
|
||||||
|
|
||||||
local EventType = {
|
local EventType = {
|
||||||
start = 0,
|
start = 0,
|
||||||
@ -214,7 +216,8 @@ function AnimationState.new (data)
|
|||||||
propertyIDs = {},
|
propertyIDs = {},
|
||||||
animationsChanged = false,
|
animationsChanged = false,
|
||||||
timeScale = 1,
|
timeScale = 1,
|
||||||
mixingTo = {}
|
mixingTo = {},
|
||||||
|
unkeyedState = 0
|
||||||
}
|
}
|
||||||
self.queue = EventQueue.new(self)
|
self.queue = EventQueue.new(self)
|
||||||
setmetatable(self, AnimationState)
|
setmetatable(self, AnimationState)
|
||||||
@ -358,7 +361,11 @@ function AnimationState:apply (skeleton)
|
|||||||
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
|
||||||
timeline:apply(skeleton, animationLast, animationTime, self.events, mix, blend, MixDirection._in)
|
if timeline.type == Animation.TimelineType.attachment then
|
||||||
|
self:applyAttachmentTimeline(timeline, skeleton, animationTime, blend, true)
|
||||||
|
else
|
||||||
|
timeline:apply(skeleton, animationLast, animationTime, self.events, mix, blend, MixDirection._in)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local timelineMode = current.timelineMode
|
local timelineMode = current.timelineMode
|
||||||
@ -367,11 +374,13 @@ function AnimationState:apply (skeleton)
|
|||||||
|
|
||||||
for ii,timeline in ipairs(timelines) do
|
for ii,timeline in ipairs(timelines) do
|
||||||
local timelineBlend = MixBlend.setup
|
local timelineBlend = MixBlend.setup
|
||||||
if clearBit(timelineMode[ii], NOT_LAST) == 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, animationTime, mix, timelineBlend, timelinesRotation, ii * 2,
|
||||||
firstFrame)
|
firstFrame)
|
||||||
|
elseif timeline.type == Animation.TimelineType.attachment then
|
||||||
|
self:applyAttachmentTimeline(skeleton, animationTime, timelineBlend, true)
|
||||||
else
|
else
|
||||||
timeline:apply(skeleton, animationLast, animationTime, self.events, mix, timelineBlend, MixDirection._in)
|
timeline:apply(skeleton, animationLast, animationTime, self.events, mix, timelineBlend, MixDirection._in)
|
||||||
end
|
end
|
||||||
@ -386,6 +395,24 @@ function AnimationState:apply (skeleton)
|
|||||||
i = i + 1
|
i = i + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Set slots attachments to the setup pose, if needed. This occurs if an animation that is mixing out sets attachments so
|
||||||
|
-- subsequent timelines see any deform, but the subsequent timelines don't set an attachment (eg they are also mixing out or
|
||||||
|
-- the time is before the first key).
|
||||||
|
local setupState = self.unkeyedState + SETUP
|
||||||
|
local slots = skeleton.slots;
|
||||||
|
for _, slot in ipairs(slots) do
|
||||||
|
if slot.attachmentState == setupState then
|
||||||
|
local attachmentName = slot.data.attachmentName
|
||||||
|
if attachmentName == nil then
|
||||||
|
slot.attachment = nil
|
||||||
|
else
|
||||||
|
slot.attachment = skeleton:getAttachmentByIndex(slot.data.index, attachmentName)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.unkeyedState = self.unkeyedState + 2; -- Increasing after each use avoids the need to reset attachmentState for every slot.
|
||||||
|
|
||||||
|
|
||||||
queue:drain()
|
queue:drain()
|
||||||
return applied
|
return applied
|
||||||
end
|
end
|
||||||
@ -432,21 +459,14 @@ function AnimationState:applyMixingFrom (to, skeleton, blend)
|
|||||||
local direction = MixDirection.out;
|
local direction = MixDirection.out;
|
||||||
local timelineBlend = MixBlend.setup
|
local timelineBlend = MixBlend.setup
|
||||||
local alpha = 0
|
local alpha = 0
|
||||||
if clearBit(timelineMode[i], NOT_LAST) == SUBSEQUENT then
|
if timelineMode[i] == SUBSEQUENT then
|
||||||
timelineBlend = blend
|
|
||||||
if not attachments and timeline.type == Animation.TimelineType.attachment then
|
|
||||||
if testBit(timelineMode[i], NOT_LAST) then
|
|
||||||
skipSubsequent = true
|
|
||||||
else
|
|
||||||
timelineBlend = MixBlend.setup
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if not drawOrder and timeline.type == Animation.TimelineType.drawOrder then skipSubsequent = true end
|
if not drawOrder and timeline.type == Animation.TimelineType.drawOrder then skipSubsequent = true end
|
||||||
|
timelineBlend = blend
|
||||||
alpha = alphaMix
|
alpha = alphaMix
|
||||||
elseif clearBit(timelineMode[i], NOT_LAST) == FIRST then
|
elseif timelineMode[i] == FIRST then
|
||||||
timelineBlend = MixBlend.setup
|
timelineBlend = MixBlend.setup
|
||||||
alpha = alphaMix
|
alpha = alphaMix
|
||||||
elseif clearBit(timelineMode[i], NOT_LAST) == HOLD then
|
elseif timelineMode[i] == HOLD then
|
||||||
timelineBlend = MixBlend.setup
|
timelineBlend = MixBlend.setup
|
||||||
alpha = alphaHold
|
alpha = alphaHold
|
||||||
else
|
else
|
||||||
@ -459,13 +479,11 @@ function AnimationState:applyMixingFrom (to, skeleton, blend)
|
|||||||
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, animationTime, alpha, timelineBlend, timelinesRotation, i * 2, firstFrame)
|
||||||
|
elseif timeline.type == Animation.TimelineType.attachment then
|
||||||
|
self:applyAttachmentTimeline(timeline, skeleton, animationTime, timelineBlend, attachments)
|
||||||
else
|
else
|
||||||
if timelineBlend == MixBlend.setup then
|
if (drawOrder and timeline.type == Animation.TimelineType.drawOrder and timelineBlend == MixBlend.setup) then
|
||||||
if timeline.type == Animation.TimelineType.attachment then
|
direction = MixDirection._in
|
||||||
if attachments or testBit(timelineMode[i], NOT_LAST) then direction = MixDirection._in end
|
|
||||||
elseif timeline.type == Animation.TimelineType.drawOrder then
|
|
||||||
if drawOrder then direction = MixDirection._in end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
timeline:apply(skeleton, animationLast, animationTime, self.events, alpha, timelineBlend, direction)
|
timeline:apply(skeleton, animationLast, animationTime, self.events, alpha, timelineBlend, direction)
|
||||||
end
|
end
|
||||||
@ -483,6 +501,38 @@ function AnimationState:applyMixingFrom (to, skeleton, blend)
|
|||||||
return mix
|
return mix
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function AnimationState:applyAttachmentTimeline(timeline, skeleton, time, blend, attachments)
|
||||||
|
local slot = skeleton.slots[timeline.slotIndex];
|
||||||
|
if slot.bone.active == false then return end
|
||||||
|
|
||||||
|
local frames = timeline.frames
|
||||||
|
if time < frames[0] then -- Time is before first frame.
|
||||||
|
if blend == MixBlend.setup or blend == MixBlend.first then
|
||||||
|
self:setAttachment(skeleton, slot, slot.data.attachmentName, attachments);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local frameIndex = 0
|
||||||
|
if (time >= frames[zlen(frames) - 1]) then -- Time is after last frame.
|
||||||
|
frameIndex = zlen(frames) - 1;
|
||||||
|
else
|
||||||
|
frameIndex = Animation.binarySearch(frames, time, 1) - 1;
|
||||||
|
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 slot.attachmentState <= self.unkeyedState then slot.attachmentState = self.unkeyedState + SETUP end
|
||||||
|
end
|
||||||
|
|
||||||
|
function AnimationState:setAttachment(skeleton, slot, attachmentName, attachments)
|
||||||
|
if (attachmentName == nil) then
|
||||||
|
slot.attachment = nil
|
||||||
|
else
|
||||||
|
slot.attachment = skeleton:getAttachmentByIndex(slot.data.index, attachmentName)
|
||||||
|
end
|
||||||
|
if attachments then slot.attachmentState = self.unkeyedState + CURRENT end
|
||||||
|
end
|
||||||
|
|
||||||
function AnimationState:applyRotateTimeline (timeline, skeleton, time, alpha, blend, timelinesRotation, i, firstFrame)
|
function AnimationState:applyRotateTimeline (timeline, skeleton, time, alpha, blend, timelinesRotation, i, firstFrame)
|
||||||
if firstFrame then
|
if firstFrame then
|
||||||
timelinesRotation[i] = 0
|
timelinesRotation[i] = 0
|
||||||
@ -866,36 +916,6 @@ function AnimationState:_animationsChanged ()
|
|||||||
end
|
end
|
||||||
i = i + 1
|
i = i + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
self.propertyIDs = {}
|
|
||||||
for i = highestIndex, 0, -1 do
|
|
||||||
entry = self.tracks[i]
|
|
||||||
while entry do
|
|
||||||
self:computeNotLast(entry)
|
|
||||||
entry = entry.mixingFrom
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function AnimationState:computeNotLast(entry)
|
|
||||||
local timelines = entry.animation.timelines
|
|
||||||
local timelinesCount = #entry.animation.timelines
|
|
||||||
local timelineMode = entry.timelineMode
|
|
||||||
local propertyIDs = self.propertyIDs
|
|
||||||
|
|
||||||
local i = 1
|
|
||||||
while i <= timelinesCount do
|
|
||||||
local timeline = timelines[i]
|
|
||||||
if (timeline.type == Animation.TimelineType.attachment) then
|
|
||||||
local slotIndex = timeline.slotIndex
|
|
||||||
if not (propertyIDs[slotIndex] == nil) then
|
|
||||||
timelineMode[i] = setBit(timelineMode[i], NOT_LAST)
|
|
||||||
else
|
|
||||||
propertyIDs[slotIndex] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
i = i + 1
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function AnimationState:computeHold(entry)
|
function AnimationState:computeHold(entry)
|
||||||
|
|||||||
@ -45,6 +45,7 @@ function Slot.new (data, bone)
|
|||||||
darkColor = nil,
|
darkColor = nil,
|
||||||
attachment = nil,
|
attachment = nil,
|
||||||
attachmentTime = 0,
|
attachmentTime = 0,
|
||||||
|
attachmentState = 0,
|
||||||
deform = {}
|
deform = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user