Эх сурвалжийг харах

[lua] Ported half of AnimationState

badlogic 9 жил өмнө
parent
commit
44f5540d37

+ 17 - 3
spine-lua/Animation.lua

@@ -228,6 +228,7 @@ function Animation.RotateTimeline.new (frameCount)
 	local self = Animation.CurveTimeline.new(frameCount)
 	self.boneIndex = -1
 	self.frames = utils.newNumberArrayZero(frameCount * 2)
+	self.type = TimelineType.rotate
 
 	function self:getPropertyId ()
 		return TimelineType.rotate * SHL_24 + self.boneIndex
@@ -291,6 +292,7 @@ function Animation.TranslateTimeline.new (frameCount)
 	local self = Animation.CurveTimeline.new(frameCount)
 	self.frames = utils.newNumberArrayZero(frameCount * ENTRIES)
 	self.boneIndex = -1
+	self.type = TimelineType.translate
 	
 	function self:getPropertyId ()
 		return TimelineType.translate * SHL_24 + self.boneIndex
@@ -349,6 +351,7 @@ function Animation.ScaleTimeline.new (frameCount)
 	local Y = 2
 
 	local self = Animation.TranslateTimeline.new(frameCount)
+	self.type = TimelineType.scale
 	
 	function self:getPropertyId ()
 		return TimelineType.scale * SHL_24 + self.boneIndex
@@ -417,6 +420,7 @@ function Animation.ShearTimeline.new (frameCount)
 	local Y = 2
 
 	local self = Animation.TranslateTimeline.new(frameCount)
+	self.type = TimelineType.shear
 	
 	function self:getPropertyId ()
 		return TimelineType.shear * SHL_24 + self.boneIndex
@@ -474,6 +478,7 @@ function Animation.ColorTimeline.new (frameCount)
 	local self = Animation.CurveTimeline.new(frameCount)
 	self.frames = utils.newNumberArrayZero(frameCount * ENTRIES)
 	self.slotIndex = -1
+	self.type = TimelineType.color
 	
 	function self:getPropertyId ()
 		return TimelineType.color * SHL_24 + self.slotIndex
@@ -533,7 +538,8 @@ function Animation.AttachmentTimeline.new (frameCount)
 	local self = {
 		frames = utils.newNumberArrayZero(frameCount), -- time, ...
 		attachmentNames = {},
-		slotIndex = -1
+		slotIndex = -1,
+		type = TimelineType.attachment
 	}
 
 	function self:getFrameCount ()
@@ -591,6 +597,7 @@ function Animation.DeformTimeline.new (frameCount)
 	self.frameVertices = utils.newNumberArrayZero(frameCount)
 	self.slotIndex = -1
 	self.attachment = nil
+	self.type = TimelineType.deform
 
 	function self:getPropertyId ()
 		return TimelineType.deform * SHL_24 + self.slotIndex
@@ -711,7 +718,8 @@ Animation.EventTimeline = {}
 function Animation.EventTimeline.new (frameCount)
 	local self = {
 		frames = utils.newNumberArrayZero(frameCount),
-		events = {}
+		events = {},
+		type = TimelineType.event
 	}
 	
 	function self:getPropertyId ()
@@ -767,7 +775,8 @@ Animation.DrawOrderTimeline = {}
 function Animation.DrawOrderTimeline.new (frameCount)
 	local self = {
 		frames = utils.newNumberArrayZero(frameCount),
-		drawOrders = {}
+		drawOrders = {},
+		type = TimelineType.drawOrder
 	}
 	
 	function self:getPropertyId ()
@@ -830,6 +839,7 @@ function Animation.IkConstraintTimeline.new (frameCount)
 	local self = Animation.CurveTimeline.new(frameCount)
 	self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) -- time, mix, bendDirection, ...
 	self.ikConstraintIndex = -1
+	self.type = TimelineType.ikConstraint
 	
 	function self:getPropertyId ()
 		return TimelineType.ikConstraint * SHL_24 + self.ikConstraintIndex
@@ -903,6 +913,7 @@ function Animation.TransformConstraintTimeline.new (frameCount)
 	local self = Animation.CurveTimeline.new(frameCount)
 	self.frames = utils.newNumberArrayZero(frameCount * ENTRIES)
 	self.transformConstraintIndex = -1
+	self.type = TimelineType.transformConstraint
 	
 	function self:getPropertyId ()
 		return TimelineType.transformConstraint * SHL_24 + self.transformConstraintIndex
@@ -977,6 +988,7 @@ function Animation.PathConstraintPositionTimeline.new (frameCount)
 	local self = Animation.CurveTimeline.new(frameCount)
 	self.frames = utils.newNumberArrayZero(frameCount * ENTRIES)
 	self.pathConstraintIndex = -1
+	self.type = TimelineType.pathConstraintPosition
 
 	function self:getPropertyId ()
 		return TimelineType.pathConstraintPosition * SHL_24 + self.pathConstraintIndex
@@ -1028,6 +1040,7 @@ function Animation.PathConstraintSpacingTimeline.new (frameCount)
 	local self = Animation.CurveTimeline.new(frameCount)
 	self.frames = utils.newNumberArrayZero(frameCount * ENTRIES)
 	self.pathConstraintIndex = -1
+	self.type = TimelineType.pathConstraintSpacing
 
 	function self:getPropertyId ()
 		return TimelineType.pathConstraintSpacing * SHL_24 + self.pathConstraintIndex
@@ -1082,6 +1095,7 @@ function Animation.PathConstraintMixTimeline.new (frameCount)
 	local self = Animation.CurveTimeline.new(frameCount)
 	self.frames = utils.newNumberArrayZero(frameCount * ENTRIES)
 	self.pathConstraintIndex = -1
+	self.type = TimelineType.pathConstraintMix
 	
 	function self:getPropertyId ()
 		return TimelineType.pathConstraintMix * SHL_24 + self.pathConstraintIndex

+ 210 - 0
spine-lua/AnimationState.lua

@@ -33,6 +33,9 @@ local table_insert = table.insert
 local utils = require "spine-lua.utils"
 local Animation = require "spine-lua.Animation"
 local AnimationStateData = require "spine-lua.AnimationStateData"
+local math_min = math.min
+local math_abs = math.abs
+local math_signum = utils.signum
 
 local EventType = {
 	start = 0,
@@ -142,6 +145,36 @@ function EventQueue:clear ()
 end
 
 
+local TrackEntry = {}
+TrackEntry.__index = TrackEntry
+
+function TrackEntry.new ()
+	local self = {
+		animation = nil,
+		next = nil, mixingFrom = nil,
+		onStart = nil, onInterrupt = nil, onEnd = nil, onDispose = nil, onComplete = nil, onEvent = nil,
+		trackIndex = 0,
+		loop = 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, mixAlpha = 0,
+		timelinesFirst = {},
+		timelinesRotation = {}
+	}
+	setmetatable(self, TrackEntry)
+	return self
+end
+
+function TrackEntry:getAnimationTime ()
+	if loop then
+		local duration = animationEnd - animationStart
+		if duration == 0 then return animationStart end
+		return (trackTime % duration) + animationStart
+	end
+	return math_min(trackTime + animationStart, animationEnd)
+end
+
 local AnimationState = {}
 AnimationState.__index = AnimationState
 
@@ -163,4 +196,181 @@ function AnimationState.new (data)
 	return self
 end
 
+AnimationState.TrackEntry = TrackEntry
+
+function AnimationState:update (delta)
+	delta = delta * self.timeScale
+	local tracks = self.tracks
+	local queue = self.queue
+	for i,current in pairs(tracks) do
+		if current then
+			current.animationLast = current.nextAnimationLast
+			current.trackLast = current.nextTrackLast
+
+			local currentDelta = delta * current.timeScale
+
+			local skip = false
+			if current.delay > 0 then
+				current.delay = current.delay - currentDelta
+				if current.delay <= 0 then
+					skip = true
+					currentDelta = -current.delay
+					current.delay = 0
+				end
+			end
+			
+			if not skip then
+				local next = current.next
+				if next then
+					-- When the next entry's delay is passed, change to the next entry, preserving leftover time.
+					local nextTime = current.trackLast - next.delay
+					if nextTime >= 0 then
+						next.delay = 0
+						next.trackTime = nextTime + delta * next.timeScale
+						current.trackTime = current.trackTime + currentDelta
+						self:setCurrent(i, next)
+						while next.mixingFrom do
+							next.mixTime = next.mixTime + currentDelta
+							next = next.mixingFrom
+						end
+						skip = true
+					end
+					if not skip then
+						self:updateMixingFrom(current, delta, true);
+					end
+				else
+					self:updateMixingFrom(current, delta, true)
+					-- Clear the track when there is no next entry, the track end time is reached, and there is no mixingFrom.
+					if current.trackLast >= current.trackEnd and current.mixingFrom == nil then
+						tracks[i] = nil
+						queue:_end(current)
+						self:disposeNext(current)
+						skip = true
+					end
+				end
+
+				if not skip then current.trackTime = current.trackTime + currentDelta end
+			end
+		end
+	end
+
+	queue:drain()
+end
+
+function AnimationState:updateMixingFrom (entry, delta, canEnd)
+	local from = entry.mixingFrom
+	if from == nil then return end
+
+	local queue = self.queue
+	if canEnd and entry.mixTime >= entry.mixDuration and entry.mixTime > 0 then
+		queue:_end(from)
+		local newFrom = from.mixingFrom
+		entry.mixingFrom = newFrom
+		if newFrom == nil then return end
+		entry.mixTime = from.mixTime;
+		entry.mixDuration = from.mixDuration;
+		from = newFrom;
+	end
+
+	from.animationLast = from.nextAnimationLast
+	from.trackLast = from.nextTrackLast
+	local mixingFromDelta = delta * from.timeScale
+	from.trackTime = from.trackTime + mixingFromDelta;
+	entry.mixTime = entry.mixtime + mixingFromDelta;
+
+	self:updateMixingFrom(from, delta, canEnd and from.alpha == 1)
+end
+
+function AnimationState:apply (skeleton)
+	if skeleton == nil then error("skeleton cannot be null.", 2) end
+	if self.animationsChanged then self:_animationsChanged() end
+
+	local events = self.events
+	local tracks = self.tracks
+	local queue = self.queue
+
+	for i,current in pairs(tracks) do
+		if not (current == nil or current.delay > 0) then
+			-- Apply mixing from entries first.
+			local mix = current.alpha
+			if current.mixingFrom then mix = mix * applyMixingFrom(current, skeleton) end
+
+			-- Apply current entry.
+			local animationLast = current.animationLast
+			local animationTime = current:getAnimationTime()
+			local timelines = current.animation.timelines
+			if mix == 1 then
+				for i,timeline in ipairs(timelines) do
+					timeline:apply(skeleton, animationLast, animationTime, events, 1, true, false)
+				end
+			else
+				local firstFrame = #current.timelinesRotation == 0
+				local timelinesRotation = current.timelinesRotation;
+				local timelinesFirst = current.timelinesFirst
+				for i,timeline in ipairs(timelines) do
+					if timeline.type == Animation.TimelineType.rotate then
+						self:applyRotateTimeline(timeline, skeleton, animationTime, mix, timelinesFirst[ii], timelinesRotation, ii * 2,
+							firstFrame) -- FIXME passing ii * 2, indexing correct?
+					else
+						timeline:apply(skeleton, animationLast, animationTime, events, mix, timelinesFirst[ii], false)
+					end
+				end
+			end
+			self:queueEvents(current, animationTime)
+			current.nextAnimationLast = animationTime
+			current.nextTrackLast = current.trackTime
+		end
+	end
+
+	queue:drain()
+end
+
+function AnimationState:applyMixingFrom (entry, skeleton)
+	local from = entry.mixingFrom
+	if from.mixingFrom then self:applyMixingFrom(from, skeleton) end
+
+	local mix = 0
+	if entry.mixDuration == 0 then -- Single frame mix to undo mixingFrom changes.
+		mix = 1
+	else
+		mix = entry.mixTime / entry.mixDuration
+		if mix > 1 then mix = 1 end
+	end
+
+	local events = nil
+	if mix < from.eventThreshold then events = self.events end
+	local attachments = mix < from.attachmentThreshold
+	local drawOrder = mix < from.drawOrderThreshold
+	local animationLast = from.animationLast
+	local animationTime = from:getAnimationTime()
+	local timelines = from.animation.timelines
+	local timelinesFirst = from.timelinesFirst;
+	local alpha = from.alpha * entry.mixAlpha * (1 - mix)
+
+	local firstFrame = #from.timelinesRotation.size == 0
+	local timelinesRotation = from.timelinesRotation
+
+	local skip = false
+	for i,timeline in ipairs(timelines) do
+		local setupPose = timelinesFirst[i]
+		if timeline.type == Animation.TimelineType.rotate then
+			self:applyRotateTimeline(timeline, skeleton, animationTime, alpha, setupPose, timelinesRotation, i * 2, firstFrame) -- FIXME passing i * 2, correct indexing?
+		else
+			if not setupPose then
+				if not attachments and timeline.type == Animation.TimelineType.attackment then skip = true end
+				if not drawOrder and timeline.type == Animation.TimelineType.drawOrder then skip = true end
+			end
+			if not skip then timeline:apply(skeleton, animationLast, animationTime, events, alpha, setupPose, true) end
+		end
+	end
+
+	self:queueEvents(from, animationTime)
+	from.nextAnimationLast = animationTime
+	from.nextTrackLast = from.trackTime
+
+	return mix
+end
+
+-- CONTINUE WITH applyRotateTimeline here
+
 return AnimationState