Browse Source

[lua] Ported holdPrevious in AnimationState. See #1169.

badlogic 7 years ago
parent
commit
44dd0cfa2b
1 changed files with 94 additions and 75 deletions
  1. 94 75
      spine-lua/AnimationState.lua

+ 94 - 75
spine-lua/AnimationState.lua

@@ -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