2
0
Zachary Pavlov 16 жил өмнө
parent
commit
3e2f301fb7

+ 183 - 0
direct/src/interval/AnimControlInterval.py

@@ -0,0 +1,183 @@
+"""AnimControlInterval module: contains the AnimControlInterval class"""
+
+__all__ = ['AnimControlInterval']
+
+from pandac.PandaModules import *
+from direct.directnotify.DirectNotifyGlobal import *
+import Interval
+import math
+from direct.showbase import LerpBlendHelpers
+
+class AnimControlInterval(Interval.Interval):
+
+    # create AnimControlInterval DirectNotify category
+    notify = directNotify.newCategory('AnimControlInterval')
+
+    # Name counter
+    animNum = 1
+    # Class methods
+
+    # Plays an animation.  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.
+
+    # this class requires either an AnimControl, or an AnimControlCollection
+    # (in which case, each anim control must be the same length)
+
+    # 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.
+
+    # loop = 1 implies a loop within the entire range of animation,
+    # while constrainedLoop = 1 implies a loop within startFrame and
+    # endFrame only.
+    
+    def __init__(self, controls, loop=0, constrainedLoop=0,
+                 duration=None, startTime=None, endTime=None,
+                 startFrame=None, endFrame=None,
+                 playRate=1.0, name=None):
+        # Generate unique id
+        id = 'AnimControl-%d' % (AnimControlInterval.animNum)
+        AnimControlInterval.animNum += 1
+        # Record class specific variables
+        if(isinstance(controls, AnimControlCollection)):
+            self.controls = controls
+            checkSz = self.controls.getAnim(0).getNumFrames()
+            for i in range(1,self.controls.getNumAnims()):
+                if(checkSz != self.controls.getAnim(i).getNumFrames()):
+                    self.notify.error("anim controls don't have the same number of frames!")
+        elif(isinstance(controls, AnimControl)):
+            self.controls = AnimControlCollection()
+            self.controls.storeAnim(controls,"")
+        else:
+            self.notify.error("invalid input control(s) for AnimControlInterval")
+            
+        self.loopAnim = loop
+        self.constrainedLoop = constrainedLoop
+        self.playRate = playRate
+
+        # If no name specified, use id as name
+        if (name == None):
+            name = id
+
+        self.frameRate = self.controls.getAnim(0).getFrameRate() * abs(playRate)
+        # Compute start and end frames.
+        if startFrame != None:
+            self.startFrame = startFrame
+        elif startTime != None:
+            self.startFrame = startTime * self.frameRate
+        else:
+            self.startFrame = 0
+            
+        if endFrame != None:
+            self.endFrame = endFrame
+        elif endTime != None:
+            self.endFrame = endTime * self.frameRate
+        elif duration != None:
+            if startTime == None:
+                startTime = float(self.startFrame) / float(self.frameRate)
+            endTime = startTime + duration
+            self.endFrame = duration * self.frameRate
+        else:
+            # No end frame specified.  Choose the maximum of all
+            # of the controls' numbers of frames.
+            numFrames = self.controls.getAnim(0).getNumFrames()
+            self.endFrame = numFrames - 1
+
+        print self.startFrame, self.endFrame
+
+        # Must we play the animation backwards?  We play backwards if
+        # either (or both) of the following is true: the playRate is
+        # negative, or endFrame is before startFrame.
+        self.reverse = (playRate < 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) / self.frameRate
+
+        # Initialize superclass
+        Interval.Interval.__init__(self, name, duration)
+
+    def getCurrentFrame(self):
+        """Calculate the current frame playing in this interval.
+
+        returns a float value between startFrame and endFrame, inclusive
+        returns None if there are any problems
+        """
+        retval = None
+        if not self.isStopped():
+            framesPlayed = self.numFrames * self.currT
+            retval = self.startFrame + framesPlayed
+        return retval
+
+    def privStep(self, t):
+        frameCount = t * self.frameRate
+        if self.constrainedLoop:
+            frameCount = frameCount % self.numFrames
+            
+        if self.reverse:
+            absFrame = self.endFrame - frameCount
+        else:
+            absFrame = self.startFrame + frameCount
+
+        # Calc integer frame number
+        intFrame = int(math.floor(absFrame + 0.0001))
+
+        # Pose anim
+
+        # We use our pre-computed list of animControls for
+        # efficiency's sake, rather than going through the relatively
+        # expensive Actor interface every frame.
+
+        # Each animControl might have a different number of frames.
+        numFrames = self.controls.getAnim(0).getNumFrames()
+        if self.loopAnim:
+            frame = (intFrame % numFrames) + (absFrame - intFrame)
+        else:
+            frame = max(min(absFrame, numFrames - 1), 0)
+            
+        self.controls.poseAll(frame)
+
+        self.state = CInterval.SStarted
+        self.currT = t
+
+    def privFinalize(self):
+        if self.implicitDuration and not self.loopAnim:
+            # 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.  We don't do this in the case of a
+            # looping animation, however, because this would introduce
+            # a hitch in the animation when it plays back-to-back with
+            # the next cycle.
+            if self.reverse:
+                self.controls.poseAll(self.startFrame)
+            else:
+                self.controls.poseAll(self.endFrame)
+
+        else:
+            # Otherwise, the user-specified duration determines which
+            # is our final frame.
+            self.privStep(self.getDuration())
+            
+        self.state = CInterval.SFinal
+        self.intervalDone()
+