From 6e1cdc100a4e08f89869d57bb25b39c98066a369 Mon Sep 17 00:00:00 2001 From: David Rose Date: Sun, 17 Aug 2003 01:18:36 +0000 Subject: [PATCH] robustify edge conditions --- direct/src/interval/ActorInterval.py | 158 ++++++++++++++------------- 1 file changed, 85 insertions(+), 73 deletions(-) diff --git a/direct/src/interval/ActorInterval.py b/direct/src/interval/ActorInterval.py index 1f2eff6a34..44cb829f52 100644 --- a/direct/src/interval/ActorInterval.py +++ b/direct/src/interval/ActorInterval.py @@ -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):