robustify edge conditions

This commit is contained in:
David Rose 2003-08-17 01:18:36 +00:00
parent 677aaa7a93
commit 6e1cdc100a
1 changed files with 85 additions and 73 deletions

View File

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