robustify edge conditions
This commit is contained in:
parent
677aaa7a93
commit
6e1cdc100a
|
|
@ -14,17 +14,27 @@ class ActorInterval(Interval.Interval):
|
|||
# Name counter
|
||||
animNum = 1
|
||||
# Class methods
|
||||
# Interval used to play an animation. If loop = 0, animation is
|
||||
# played only once and the pose of the anim depends on t passed
|
||||
# into the setT method every frame. If loop = 1, the animation is
|
||||
# started and plays on its own and stopped when t >= duration or
|
||||
# playback stop event occurs. If no duration is specified, interval
|
||||
# duration defaults to be equal to the length of the animation.
|
||||
# Note: if loop == 0 and duration > anim duration then the animation
|
||||
# will play once and then nothing will happen for the remainder of the
|
||||
# interval
|
||||
def __init__(self, actor, animName, loop=0, duration=0.0,
|
||||
startTime=0.0, endTime=None, playRate=1.0, name=None):
|
||||
|
||||
# Plays an animation on an Actor. The subrange of the animation
|
||||
# to be played may be specified via frames (startFrame up to and
|
||||
# including endFrame) or seconds (startTime up to and including
|
||||
# endTime). If neither is specified, the default is the entire
|
||||
# range of the animation.
|
||||
|
||||
# The duration may be implicit or explicit. If it is omitted, it
|
||||
# is taken to be endTime - startTime. There's not much point in
|
||||
# specifying otherwise unless you also specify loop=1, which will
|
||||
# loop the animation over its frame range during the duration of
|
||||
# the interval.
|
||||
|
||||
# Note: if loop == 0 and duration > anim duration then the
|
||||
# animation will play once and then hold its final pose for the
|
||||
# remainder of the interval.
|
||||
|
||||
def __init__(self, actor, animName, loop=0, duration=None,
|
||||
startTime=None, endTime=None,
|
||||
startFrame=None, endFrame=None,
|
||||
playRate=1.0, name=None):
|
||||
"""__init__(name)
|
||||
"""
|
||||
# Generate unique id
|
||||
|
|
@ -34,58 +44,67 @@ class ActorInterval(Interval.Interval):
|
|||
self.actor = actor
|
||||
self.animName = animName
|
||||
self.controls = self.actor.getAnimControls(self.animName)
|
||||
assert(len(self.controls) > 0)
|
||||
self.loopAnim = loop
|
||||
self.frameRate = self.controls[0].getAnim().getBaseFrameRate() * playRate
|
||||
self.numFrames = self.controls[0].getNumFrames()
|
||||
# Compute start time
|
||||
self.startTime = startTime
|
||||
|
||||
# If no name specified, use id as name
|
||||
if (name == None):
|
||||
name = id
|
||||
# Compute duration if no duration specified
|
||||
self.reverse = 0
|
||||
if duration == 0.0:
|
||||
if (endTime == None):
|
||||
duration = max(self.actor.getDuration(self.animName) - \
|
||||
startTime, 0.0)
|
||||
else:
|
||||
duration = endTime - startTime
|
||||
if (duration < 0.0):
|
||||
duration = -duration
|
||||
if (endTime == None):
|
||||
self.finishTime = self.startTime + duration
|
||||
|
||||
if len(self.controls) == 0:
|
||||
self.notify.warning("Unknown animation for actor: %s" % (self.animName))
|
||||
self.frameRate = 1.0
|
||||
self.startFrame = 0
|
||||
self.endFrame = 0
|
||||
else:
|
||||
self.finishTime = endTime
|
||||
if (self.startTime > self.finishTime):
|
||||
|
||||
self.frameRate = self.controls[0].getAnim().getBaseFrameRate() * abs(playRate)
|
||||
# Compute start and end frames.
|
||||
if startFrame != None:
|
||||
self.startFrame = startFrame
|
||||
elif startTime != None:
|
||||
self.startFrame = int(math.floor(startTime * self.frameRate + 0.0001))
|
||||
else:
|
||||
self.startFrame = 0
|
||||
|
||||
if endFrame != None:
|
||||
self.endFrame = endFrame
|
||||
elif endTime != None:
|
||||
self.endFrame = int(math.floor(endTime * self.frameRate + 0.0001))
|
||||
else:
|
||||
self.endFrame = self.controls[0].getNumFrames() - 1
|
||||
|
||||
# Must we play the animation backwards?
|
||||
self.reverse = 0
|
||||
if self.endFrame < self.startFrame:
|
||||
self.reverse = 1
|
||||
t = self.endFrame
|
||||
self.endFrame = self.startFrame
|
||||
self.startFrame = t
|
||||
|
||||
self.numFrames = self.endFrame - self.startFrame + 1
|
||||
|
||||
# Compute duration if no duration specified
|
||||
self.implicitDuration = 0
|
||||
if duration == None:
|
||||
self.implicitDuration = 1
|
||||
duration = float(self.numFrames - 1) / self.frameRate
|
||||
|
||||
# Initialize superclass
|
||||
Interval.Interval.__init__(self, name, duration)
|
||||
|
||||
def calcFrame(self, t):
|
||||
segmentLength = abs(self.finishTime - self.startTime)
|
||||
if segmentLength == 0:
|
||||
offset = 0
|
||||
else:
|
||||
offset = t % segmentLength
|
||||
# Handle boundary case where we want to set the final frame
|
||||
if (t == self.getDuration() and offset < 0.0001):
|
||||
offset = segmentLength
|
||||
# Compute current frame based upon current time
|
||||
if (self.reverse == 0):
|
||||
floatFrame = self.frameRate * (self.startTime + offset)
|
||||
else:
|
||||
negOffset = (self.startTime - self.finishTime) - offset
|
||||
floatFrame = self.frameRate * (self.finishTime + negOffset)
|
||||
# Need max to avoid frame = -1 when t = 0
|
||||
frame = max(0, int(math.ceil(floatFrame)) - 1)
|
||||
# Modulo in case of looping anim
|
||||
return frame % self.numFrames
|
||||
|
||||
def goToT(self, t):
|
||||
def privStep(self, t):
|
||||
# Calc integer frame number
|
||||
frame = self.calcFrame(t)
|
||||
frame = int(math.floor(t * self.frameRate + 0.0001))
|
||||
if self.loopAnim:
|
||||
frame = frame % self.numFrames
|
||||
else:
|
||||
frame = max(min(frame, self.numFrames - 1), 0)
|
||||
|
||||
if self.reverse:
|
||||
frame = self.endFrame - frame
|
||||
else:
|
||||
frame = self.startFrame + frame
|
||||
|
||||
# Pose anim
|
||||
|
||||
# We use our pre-computed list of animControls for
|
||||
|
|
@ -94,33 +113,26 @@ class ActorInterval(Interval.Interval):
|
|||
for control in self.controls:
|
||||
control.pose(frame)
|
||||
|
||||
return frame
|
||||
|
||||
def privInitialize(self, t):
|
||||
self.state = CInterval.SStarted
|
||||
self.goToT(t)
|
||||
if self.loopAnim:
|
||||
self.actor.loop(self.animName, restart = 0)
|
||||
self.currT = t
|
||||
|
||||
def privFinalize(self):
|
||||
if self.loopAnim:
|
||||
self.actor.stop()
|
||||
if self.implicitDuration:
|
||||
# As a special case, we ensure we end up posed to the last
|
||||
# frame of the animation if the original duration was
|
||||
# implicit. This is necessary only to guard against
|
||||
# possible roundoff error in computing the final frame
|
||||
# from the duration.
|
||||
for control in self.controls:
|
||||
control.pose(self.endFrame)
|
||||
|
||||
else:
|
||||
self.goToT(self.getDuration())
|
||||
self.currT = self.getDuration()
|
||||
self.state = CInterval.SFinal
|
||||
# Otherwise, the user-specified duration determines which
|
||||
# is our final frame.
|
||||
self.privStep(self.getDuration())
|
||||
|
||||
def privStep(self, t):
|
||||
if not self.loopAnim:
|
||||
self.goToT(t)
|
||||
|
||||
self.state = CInterval.SStarted
|
||||
self.currT = t
|
||||
|
||||
def privInterrupt(self):
|
||||
if self.loopAnim:
|
||||
self.actor.stop
|
||||
self.state = CInterval.SFinal
|
||||
self.intervalDone()
|
||||
|
||||
|
||||
class LerpAnimInterval(CLerpAnimEffectInterval):
|
||||
|
|
|
|||
Loading…
Reference in New Issue