|
@@ -50,8 +50,8 @@ end
|
|
|
local EMPTY_ANIMATION = Animation.new("<empty>", {}, 0)
|
|
|
local SUBSEQUENT = 0
|
|
|
local FIRST = 1
|
|
|
-local DIP = 2
|
|
|
-local DIP_MIX = 3;
|
|
|
+local HOLD = 2
|
|
|
+local HOLD_MIX = 3;
|
|
|
|
|
|
local EventType = {
|
|
|
start = 0,
|
|
@@ -167,75 +167,23 @@ TrackEntry.__index = TrackEntry
|
|
|
function TrackEntry.new ()
|
|
|
local self = {
|
|
|
animation = nil,
|
|
|
- next = nil, mixingFrom = nil,
|
|
|
+ next = nil, mixingFrom = nil, mixingTo = nil,
|
|
|
onStart = nil, onInterrupt = nil, onEnd = nil, onDispose = nil, onComplete = nil, onEvent = nil,
|
|
|
trackIndex = 0,
|
|
|
- loop = false,
|
|
|
+ loop = false, holdPrevious = false,
|
|
|
eventThreshold = 0, attachmentThreshold = 0, drawOrderThreshold = 0,
|
|
|
animationStart = 0, animationEnd = 0, animationLast = 0, nextAnimationLast = 0,
|
|
|
delay = 0, trackTime = 0, trackLast = 0, nextTrackLast = 0, trackEnd = 0, timeScale = 0,
|
|
|
alpha = 0, mixTime = 0, mixDuration = 0, interruptAlpha = 0, totalAlpha = 0,
|
|
|
mixBlend = MixBlend.replace,
|
|
|
- timelineData = {},
|
|
|
- timelineDipMix = {},
|
|
|
+ timelineMode = {},
|
|
|
+ timelineHoldMix = {},
|
|
|
timelinesRotation = {}
|
|
|
}
|
|
|
setmetatable(self, TrackEntry)
|
|
|
return self
|
|
|
end
|
|
|
|
|
|
-function TrackEntry:setTimelineData(to, mixingToArray, propertyIDs)
|
|
|
- if to then table_insert(mixingToArray, to) end
|
|
|
- local lastEntry = self
|
|
|
- if self.mixingFrom then lastEntry = self.mixingFrom:setTimelineData(self, mixingToArray, propertyIDs) end
|
|
|
- if to then mixingToArray[#mixingToArray] = nil end
|
|
|
-
|
|
|
- local mixingTo = mixingToArray
|
|
|
- local mixingToLast = #mixingToArray
|
|
|
- local timelines = self.animation.timelines
|
|
|
- local timelinesCount = #self.animation.timelines
|
|
|
- local timelineData = self.timelineData
|
|
|
- local timelineDipMix = self.timelineDipMix
|
|
|
-
|
|
|
- local i = 1
|
|
|
- local skip
|
|
|
- while i <= timelinesCount do
|
|
|
- local id = "" .. timelines[i]:getPropertyId()
|
|
|
- if not (propertyIDs[id] == nil) then
|
|
|
- timelineData[i] = SUBSEQUENT
|
|
|
- elseif (to == nil or not to:hasTimeline(id)) then
|
|
|
- timelineData[i] = FIRST
|
|
|
- else
|
|
|
- local ii = mixingToLast
|
|
|
- while ii > 0 do
|
|
|
- local entry = mixingTo[ii]
|
|
|
- skip = false
|
|
|
- if not entry:hasTimeline(id) then
|
|
|
- if entry.mixDuration > 0 then
|
|
|
- timelineData[i] = DIP_MIX
|
|
|
- timelineDipMix[i] = entry
|
|
|
- skip = true
|
|
|
- break
|
|
|
- end
|
|
|
- break;
|
|
|
- end
|
|
|
- ii = ii - 1
|
|
|
- end
|
|
|
- if not skip then timelineData[i] = DIP end
|
|
|
- end
|
|
|
- i = i + 1
|
|
|
- end
|
|
|
- return lastEntry
|
|
|
-end
|
|
|
-
|
|
|
-function TrackEntry:hasTimeline(id)
|
|
|
- local timelines = self.animation.timelines
|
|
|
- for i,timeline in ipairs(timelines) do
|
|
|
- if timeline:getPropertyId() == id then return true end
|
|
|
- end
|
|
|
- return false
|
|
|
-end
|
|
|
-
|
|
|
function TrackEntry:getAnimationTime ()
|
|
|
if self.loop then
|
|
|
local duration = self.animationEnd - self.animationStart
|
|
@@ -325,6 +273,7 @@ function AnimationState:update (delta)
|
|
|
-- End mixing from entries once all have completed.
|
|
|
local from = current.mixingFrom
|
|
|
current.mixingFrom = nil
|
|
|
+ if from then from.mixingTo = nil end
|
|
|
while from do
|
|
|
queue:_end(from)
|
|
|
from = from.mixingFrom
|
|
@@ -354,6 +303,7 @@ function AnimationState:updateMixingFrom (to, delta)
|
|
|
-- Require totalAlpha == 0 to ensure mixing is complete, unless mixDuration == 0 (the transition is a single frame).
|
|
|
if (from.totalAlpha == 0 or to.mixDuration == 0) then
|
|
|
to.mixingFrom = from.mixingFrom
|
|
|
+ if from.mixingFrom then from.mixingFrom.mixingTo = to end
|
|
|
to.interruptAlpha = from.interruptAlpha
|
|
|
self.queue:_end(from)
|
|
|
end
|
|
@@ -393,18 +343,18 @@ function AnimationState:apply (skeleton)
|
|
|
local animationLast = current.animationLast
|
|
|
local animationTime = current:getAnimationTime()
|
|
|
local timelines = current.animation.timelines
|
|
|
- if 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
|
|
|
timeline:apply(skeleton, animationLast, animationTime, events, mix, blend, MixDirection._in)
|
|
|
end
|
|
|
else
|
|
|
- local timelineData = current.timelineData
|
|
|
+ local timelineMode = current.timelineMode
|
|
|
local firstFrame = #current.timelinesRotation == 0
|
|
|
local timelinesRotation = current.timelinesRotation
|
|
|
|
|
|
for ii,timeline in ipairs(timelines) do
|
|
|
local timelineBlend = MixBlend.setup
|
|
|
- if timelineData[ii] == SUBSEQUENT then timelineBlend = blend end
|
|
|
+ if timelineMode[ii] == SUBSEQUENT then timelineBlend = blend end
|
|
|
|
|
|
if timeline.type == Animation.TimelineType.rotate then
|
|
|
self:applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii * 2,
|
|
@@ -446,16 +396,16 @@ function AnimationState:applyMixingFrom (to, skeleton, blend)
|
|
|
local animationLast = from.animationLast
|
|
|
local animationTime = from:getAnimationTime()
|
|
|
local timelines = from.animation.timelines
|
|
|
- local alphaDip = from.alpha * to.interruptAlpha
|
|
|
- local alphaMix = alphaDip * (1 - mix)
|
|
|
+ local alphaHold = from.alpha * to.interruptAlpha
|
|
|
+ local alphaMix = alphaHold * (1 - mix)
|
|
|
|
|
|
if blend == MixBlend.add then
|
|
|
for i,timeline in ipairs(timelines) do
|
|
|
timeline:apply(skeleton, animationLast, animationTime, events, alphaMix, blend, MixDirection.out)
|
|
|
end
|
|
|
else
|
|
|
- local timelineData = from.timelineData
|
|
|
- local timelineDipMix = from.timelineDipMix
|
|
|
+ local timelineMode = from.timelineMode
|
|
|
+ local timelineHoldMix = from.timelineHoldMix
|
|
|
|
|
|
local firstFrame = #from.timelinesRotation == 0
|
|
|
local timelinesRotation = from.timelinesRotation
|
|
@@ -466,21 +416,21 @@ function AnimationState:applyMixingFrom (to, skeleton, blend)
|
|
|
local skipSubsequent = false;
|
|
|
local timelineBlend = MixBlend.setup
|
|
|
local alpha = 0
|
|
|
- if timelineData[i] == SUBSEQUENT then
|
|
|
+ if timelineMode[i] == SUBSEQUENT then
|
|
|
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
|
|
|
timelineBlend = blend
|
|
|
alpha = alphaMix
|
|
|
- elseif timelineData[i] == FIRST then
|
|
|
+ elseif timelineMode[i] == FIRST then
|
|
|
timelineBlend = MixBlend.setup
|
|
|
alpha = alphaMix
|
|
|
- elseif timelineData[i] == DIP then
|
|
|
+ elseif timelineMode[i] == HOLD then
|
|
|
timelineBlend = MixBlend.setup
|
|
|
- alpha = alphaDip
|
|
|
+ alpha = alphaHold
|
|
|
else
|
|
|
timelineBlend = MixBlend.setup
|
|
|
- local dipMix = timelineDipMix[i]
|
|
|
- alpha = alphaDip * math_max(0, 1 - dipMix.mixtime / dipMix.mixDuration)
|
|
|
+ local holdMix = timelineHoldMix[i]
|
|
|
+ alpha = alphaHold * math_max(0, 1 - holdMix.mixtime / holdMix.mixDuration)
|
|
|
end
|
|
|
|
|
|
if not skipSubsequent then
|
|
@@ -643,6 +593,7 @@ function AnimationState:clearTrack (trackIndex)
|
|
|
if from == nil then break end
|
|
|
queue:_end(from)
|
|
|
entry.mixingFrom = nil
|
|
|
+ entry.mixingTo = nil
|
|
|
entry = from
|
|
|
end
|
|
|
|
|
@@ -660,6 +611,7 @@ function AnimationState:setCurrent (index, current, interrupt)
|
|
|
if from then
|
|
|
if interrupt then queue:interrupt(from) end
|
|
|
current.mixingFrom = from
|
|
|
+ from.mixingTo = current
|
|
|
current.mixTime = 0
|
|
|
|
|
|
if from.mixingFrom and from.mixDuration > 0 then
|
|
@@ -783,6 +735,7 @@ function AnimationState:trackEntry (trackIndex, animation, loop, last)
|
|
|
entry.trackIndex = trackIndex
|
|
|
entry.animation = animation
|
|
|
entry.loop = loop
|
|
|
+ entry.holdPrevious = false
|
|
|
|
|
|
entry.eventThreshold = 0
|
|
|
entry.attachmentThreshold = 0
|
|
@@ -826,16 +779,82 @@ function AnimationState:_animationsChanged ()
|
|
|
self.animationsChanged = false
|
|
|
|
|
|
self.propertyIDs = {}
|
|
|
+
|
|
|
+ for i, entry in pairs(self.tracks) do
|
|
|
+ if entry then
|
|
|
+ while entry.mixingFrom do
|
|
|
+ entry = entry.mixingFrom
|
|
|
+ end
|
|
|
+
|
|
|
+ repeat
|
|
|
+ if (entry.mixingTo == nil or entry.mixBlend ~= MixBlend.add) then
|
|
|
+ self:setTimelineModes(entry)
|
|
|
+ end
|
|
|
+ entry = entry.mixingTo
|
|
|
+ until (entry == nil)
|
|
|
+ end
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+function AnimationState:setTimelineModes(entry)
|
|
|
+ local to = entry.mixingTo
|
|
|
+ local timelines = entry.animation.timelines
|
|
|
+ local timelinesCount = #entry.animation.timelines
|
|
|
+ local timelineMode = entry.timelineMode
|
|
|
+ local timelineHoldMix = entry.timelineHoldMix
|
|
|
local propertyIDs = self.propertyIDs
|
|
|
- local mixingTo = self.mixingTo
|
|
|
+
|
|
|
+ if (to and to.holdPrevious) then
|
|
|
+ local i = 1
|
|
|
+ while i <= timelinesCount do
|
|
|
+ local id = "" .. timelines[i]:getPropertyId()
|
|
|
+ if propertyIDs[id] == nil then
|
|
|
+ propertyIDs[id] = id
|
|
|
+ end
|
|
|
+ timelineMode[i] = HOLD
|
|
|
+ end
|
|
|
+ return
|
|
|
+ end
|
|
|
|
|
|
- for i, entry in pairs(self.tracks) do
|
|
|
- if entry and (i == 0 or entry.mixBlend ~= MixBlend.add) then
|
|
|
- entry:setTimelineData(nil, mixingTo, propertyIDs)
|
|
|
+ local i = 1
|
|
|
+ local skip
|
|
|
+ while i <= timelinesCount do
|
|
|
+ local id = "" .. timelines[i]:getPropertyId()
|
|
|
+ if not (propertyIDs[id] == nil) then
|
|
|
+ timelineMode[i] = SUBSEQUENT
|
|
|
+ else
|
|
|
+ propertyIDs[id] = id
|
|
|
+ if (to == nil or not self:hasTimeline(to, id)) then
|
|
|
+ timelineMode[i] = FIRST
|
|
|
+ else
|
|
|
+ local next = to.mixingTo
|
|
|
+ while next do
|
|
|
+ skip = false
|
|
|
+ if not self: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 end
|
|
|
+ end
|
|
|
end
|
|
|
+ i = i + 1
|
|
|
end
|
|
|
end
|
|
|
|
|
|
+function AnimationState:hasTimeline(entry, id)
|
|
|
+ local timelines = entry.animation.timelines
|
|
|
+ for i,timeline in ipairs(timelines) do
|
|
|
+ if timeline:getPropertyId() == id then return true end
|
|
|
+ end
|
|
|
+ return false
|
|
|
+end
|
|
|
+
|
|
|
function AnimationState:getCurrent (trackIndex)
|
|
|
return self.tracks[trackIndex]
|
|
|
end
|