diff --git a/spine-lua/AnimationState.lua b/spine-lua/AnimationState.lua index 10b1d28f0..59120f77d 100644 --- a/spine-lua/AnimationState.lua +++ b/spine-lua/AnimationState.lua @@ -41,6 +41,9 @@ local math_signum = utils.signum local math_floor = math.floor local math_ceil = math.ceil local math_mod = utils.mod +local testBit = utils.testBit +local setBit = utils.setBit +local clearBit = utils.clearBit local function zlen(array) return #array + 1 @@ -50,7 +53,8 @@ local EMPTY_ANIMATION = Animation.new("", {}, 0) local SUBSEQUENT = 0 local FIRST = 1 local HOLD = 2 -local HOLD_MIX = 3; +local HOLD_MIX = 3 +local NOT_LAST = 4 local EventType = { start = 0, @@ -357,7 +361,7 @@ function AnimationState:apply (skeleton) for ii,timeline in ipairs(timelines) do local timelineBlend = MixBlend.setup - if timelineMode[ii] == SUBSEQUENT then timelineBlend = blend end + if clearBit(timelineMode[ii], NOT_LAST) == SUBSEQUENT then timelineBlend = blend end if timeline.type == Animation.TimelineType.rotate then self:applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii * 2, @@ -421,15 +425,21 @@ function AnimationState:applyMixingFrom (to, skeleton, blend) local direction = MixDirection.out; local timelineBlend = MixBlend.setup local alpha = 0 - if timelineMode[i] == SUBSEQUENT then - if not attachments and timeline.type == Animation.TimelineType.attachment then skipSubsequent = true end + if clearBit(timelineMode[i], NOT_LAST) == SUBSEQUENT then + if not attachments and timeline.type == Animation.TimelineType.attachment then + if testBit(timelineMode[i], NOT_LAST) then + skipSubsequent = true + else + blend = MixBlend.setup + end + end if not drawOrder and timeline.type == Animation.TimelineType.drawOrder then skipSubsequent = true end timelineBlend = blend alpha = alphaMix - elseif timelineMode[i] == FIRST then + elseif clearBit(timelineMode[i], NOT_LAST) == FIRST then timelineBlend = MixBlend.setup alpha = alphaMix - elseif timelineMode[i] == HOLD then + elseif clearBit(timelineMode[i], NOT_LAST) == HOLD then timelineBlend = MixBlend.setup alpha = alphaHold else @@ -445,7 +455,7 @@ function AnimationState:applyMixingFrom (to, skeleton, blend) else if timelineBlend == MixBlend.setup then if timeline.type == Animation.TimelineType.attachment then - if attachments then direction = MixDirection._in end + 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 @@ -803,7 +813,10 @@ function AnimationState:_animationsChanged () self.propertyIDs = {} + local highestIndex = -1 for i, entry in pairs(self.tracks) do + if i > highestIndex then highestIndex = i end + if entry then while entry.mixingFrom do entry = entry.mixingFrom @@ -811,15 +824,45 @@ function AnimationState:_animationsChanged () repeat if (entry.mixingTo == nil or entry.mixBlend ~= MixBlend.add) then - self:setTimelineModes(entry) + self:computeHold(entry) end entry = entry.mixingTo until (entry == nil) 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:setTimelineModes(entry) +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 + +function AnimationState:computeHold(entry) local to = entry.mixingTo local timelines = entry.animation.timelines local timelinesCount = #entry.animation.timelines @@ -847,7 +890,11 @@ function AnimationState:setTimelineModes(entry) timelineMode[i] = SUBSEQUENT else propertyIDs[id] = id - if to == nil or not self:hasTimeline(to, id) then + 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 self:hasTimeline(to, id) then timelineMode[i] = FIRST else local next = to.mixingTo diff --git a/spine-lua/utils.lua b/spine-lua/utils.lua index 7d281d155..38ff98b0c 100644 --- a/spine-lua/utils.lua +++ b/spine-lua/utils.lua @@ -166,4 +166,22 @@ function utils.randomTriangularWith(min, max, mode) return max - math_sqrt((1 - u) * d * (max - mode)) end +function utils.testBit(value, bit) + return value % (2 * bit) >= bit +end + +function utils.setBit(value, bit) + if value % (2 * bit) >= bit then + return value + end + return value + bit +end + +function utils.clearBit(value, bit) + if value % (2 * bit) >= bit then + return value - bit + end + return value +end + return utils