From 44dd0cfa2bca85e3802b6da1c3d113c43f53956f Mon Sep 17 00:00:00 2001 From: badlogic Date: Tue, 11 Sep 2018 16:11:40 +0200 Subject: [PATCH] [lua] Ported holdPrevious in AnimationState. See #1169. --- spine-lua/AnimationState.lua | 171 +++++++++++++++++++---------------- 1 file changed, 95 insertions(+), 76 deletions(-) diff --git a/spine-lua/AnimationState.lua b/spine-lua/AnimationState.lua index eb34ad584..3889ec59a 100644 --- a/spine-lua/AnimationState.lua +++ b/spine-lua/AnimationState.lua @@ -50,8 +50,8 @@ end local EMPTY_ANIMATION = Animation.new("", {}, 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 = {} - local propertyIDs = self.propertyIDs - local mixingTo = self.mixingTo - for i, entry in pairs(self.tracks) do - if entry and (i == 0 or entry.mixBlend ~= MixBlend.add) then - entry:setTimelineData(nil, mixingTo, 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 + + 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 + + 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