瀏覽代碼

*** empty log message ***

Mark Mine 24 年之前
父節點
當前提交
2bd032230e
共有 2 個文件被更改,包括 202 次插入51 次删除
  1. 13 0
      direct/src/actor/Actor.py
  2. 189 51
      direct/src/tkpanels/AnimPanel.py

+ 13 - 0
direct/src/actor/Actor.py

@@ -255,6 +255,12 @@ class Actor(PandaObject, NodePath):
         self.removeNode()
         
     # accessing
+
+    def getAnimControlDict(self):
+        return self.__animControlDict
+
+    def getPartBundleDict(self):
+        return self.__partBundleDict
     
     def getLODNames(self):
         """getLODNames(self):
@@ -805,6 +811,13 @@ class Actor(PandaObject, NodePath):
                     
 
     # actions
+    def animPanel(self):
+        base.wantDIRECT = 1
+        base.wantTk = 1
+        from ShowBaseGlobal import *
+        import TkGlobal
+        import AnimPanel
+        return AnimPanel.AnimPanel(self)
     
     def stop(self, animName=None, partName=None):
         """stop(self, string=None, string=None)

+ 189 - 51
direct/src/tkpanels/AnimPanel.py

@@ -1,5 +1,7 @@
 "DIRECT Animation Control Panel"
 
+### SEE END OF FILE FOR EXAMPLE USEAGE ###
+
 # Import Tkinter, Pmw, and the floater code from this directory tree.
 from AppShell import *
 from Tkinter import *
@@ -19,6 +21,7 @@ class AnimPanel(AppShell):
     frameHeight = 250
     usecommandarea = 0
     usestatusarea  = 0
+    index = 0
 
     def __init__(self, aList =  [], parent = None, **kw):
         INITOPT = Pmw.INITOPT
@@ -35,6 +38,9 @@ class AnimPanel(AppShell):
         self.defineoptions(kw, optiondefs)
 
         self.frameHeight = 60 + (50 * len(self['actorList']))
+        self.playList =  []
+        self.id = 'AnimPanel_%d' % AnimPanel.index
+        AnimPanel.index += 1
         # Initialize the superclass
         AppShell.__init__(self)
 
@@ -69,12 +75,12 @@ class AnimPanel(AppShell):
                             command = self.displaySeconds)
         # Reset all actor controls
         menuBar.addmenuitem('AnimPanel', 'command',
-                            'Reset Actor controls to zero',
-                            label = 'Reset all to zero',
+                            'Set actor controls to t = 0.0',
+                            label = 'Jump all to zero',
                             command = self.resetAllToZero)
         menuBar.addmenuitem('AnimPanel', 'command',
-                            'Reset Actor controls to end time',
-                            label = 'Reset all to end time',
+                            'Set Actor controls to end time',
+                            label = 'Jump all to end time',
                             command = self.resetAllToEnd)
 
         # Add some buttons to update all Actor Controls
@@ -110,6 +116,7 @@ class AnimPanel(AppShell):
             ac = self.createcomponent(
                 'actorControl%d' % index, (), 'Actor',
                 ActorControl, (actorFrame,),
+                animPanel = self,
                 text = actor.getName(),
                 animList = actor.getAnimNames(),
                 actor = actor)
@@ -131,14 +138,14 @@ class AnimPanel(AppShell):
         self.toStartButton.pack(side = LEFT, expand = 1, fill = X)
         
         self.playButton = self.createcomponent(
-            'playPause', (), None,
+            'playButton', (), None,
             Button, (controlFrame,),
             text = 'Play', width = 8,
             command = self.playActorControls)
         self.playButton.pack(side = LEFT, expand = 1, fill = X)
 
         self.stopButton = self.createcomponent(
-            'playPause', (), None,
+            'stopButton', (), None,
             Button, (controlFrame,),
             text = 'Stop', width = 8,
             command = self.stopActorControls)
@@ -164,13 +171,24 @@ class AnimPanel(AppShell):
         controlFrame.pack(fill = X)
 
     def playActorControls(self):
+        self.stopActorControls()
+        self.lastT = globalClock.getFrameTime()
+        self.playList = self.actorControlList[:]
+        taskMgr.spawnMethodNamed(self.play, self.id + '_UpdateTask')
+
+    def play(self, task):
+        if not self.playList:
+            return Task.done
         fLoop = self.loopVar.get()
-        for actorControl in self.actorControlList:
-            actorControl.play(fLoop)
+        currT = globalClock.getFrameTime()
+        deltaT = currT - self.lastT
+        self.lastT = currT
+        for actorControl in self.playList:
+            actorControl.play(deltaT, fLoop)
+        return Task.cont
 
     def stopActorControls(self):
-        for actorControl in self.actorControlList:
-            actorControl.stop()
+        taskMgr.removeTasksNamed(self.id + '_UpdateTask')
 
     def getActorControlAt(self, index):
         return self.actorControlList[index]
@@ -225,6 +243,7 @@ class ActorControl(Pmw.MegaWidget):
             initActive = DEFAULT_ANIMS[0]
         optiondefs = (
             ('text',            'Actor',            self._updateLabelText),
+            ('animPanel',       None,               None),
             ('actor',           None,               None),
             ('animList',        DEFAULT_ANIMS,      None),
             ('active',          initActive,         None),
@@ -241,8 +260,12 @@ class ActorControl(Pmw.MegaWidget):
         interior.configure(relief = RAISED, bd = 2)
 
         # Instance variables
+        self.fps = 24
         self.offset = 0.0
-        self.maxFrame = 1.0
+        self.maxSeconds = 1.0
+        self.currT = 0.0
+        self.fScaleCommand = 0
+        self.fOneShot = 0
 
         # Create component widgets
         self._label = self.createcomponent(
@@ -269,8 +292,11 @@ class ActorControl(Pmw.MegaWidget):
                                     command = self.updateDisplay)
         # Items for top level menu
         labelMenu.add_cascade(label = 'Display Units', menu = displayMenu)
-        labelMenu.add_command(label = 'Set Offset', command = self.setOffset)
-        labelMenu.add_command(label = 'Reset', command = self.resetToZero)
+        # labelMenu.add_command(label = 'Set Offset', command = self.setOffset)
+        labelMenu.add_command(label = 'Jump To Zero',
+                              command = self.resetToZero)
+        labelMenu.add_command(label = 'Jump To End Time',
+                              command = self.resetToEnd)
         # Now associate menu with menubutton
         self._label['menu'] = labelMenu
         self._label.pack(side = LEFT, fill = X)
@@ -286,24 +312,22 @@ class ActorControl(Pmw.MegaWidget):
         animMenu.pack(side = 'left', padx = 5, expand = 0)
 
         # Combo box to select frame rate
-        playRateList = [1/24.0, 0.1, 0.5, 1.0, 2.0,5.0,10.0]
-        playRate = self['actor'].getPlayRate(self['active'])
+        playRateList = ['1/24.0', '0.1', '0.5', '1.0', '2.0', '5.0' , '10.0']
+        playRate = '%0.1f' % self['actor'].getPlayRate(self['active'])
         if playRate not in playRateList:
+            def strCmp(a, b):
+                return cmp(eval(a), eval(b))
             playRateList.append(playRate)
-            playRateList.sort
+            playRateList.sort(strCmp)
         playRateMenu = self.createcomponent(
             'playRateMenu', (), None,
             Pmw.ComboBox, (interior,),
-            labelpos = W, label_text = 'X',
+            labelpos = W, label_text = 'Play Rate:',
             entry_width = 4, selectioncommand = self.setPlayRate,
             scrolledlist_items = playRateList)
-        playRateMenu.selectitem(`playRate`)
+        playRateMenu.selectitem(playRate)
         playRateMenu.pack(side = LEFT, padx = 5, expand = 0)
 
-        # A label
-        playRateLabel = Label(interior, text = 'speed')
-        playRateLabel.pack(side = LEFT)
-
         # Scale to control animation
         frameFrame = Frame(interior, relief = SUNKEN, bd = 1)
         self.minLabel = self.createcomponent(
@@ -315,15 +339,17 @@ class ActorControl(Pmw.MegaWidget):
         self.frameControl = self.createcomponent(
             'scale', (), None,
             Scale, (frameFrame,),
-            from_ = 0.0, to = self.maxFrame, resolution = 1.0,
+            from_ = 0, to = 24, resolution = 1.0,
             command = self.goTo,
             orient = HORIZONTAL, showvalue = 1)
         self.frameControl.pack(side = LEFT, expand = 1)
+        self.frameControl.bind('<Button-1>', self.__onPress)
+        self.frameControl.bind('<ButtonRelease-1>', self.__onRelease)
 
         self.maxLabel = self.createcomponent(
             'maxLabel', (), 'sLabel',
             Label, (frameFrame,),
-            text = self.maxFrame)
+            text = 24)
         self.maxLabel.pack(side = LEFT)
         frameFrame.pack(side = LEFT, expand = 1, fill = X)
 
@@ -347,21 +373,33 @@ class ActorControl(Pmw.MegaWidget):
         actor = self['actor']
         active = self['active']
         self.fps = actor.getFrameRate(active)
+        self.duration = actor.getDuration(active)
         self.maxFrame = actor.getNumFrames(active) - 1
-        self.maxSeconds = self.maxFrame / self.fps
-        # Switch between showing frame counts and seconds
+        self.maxSeconds = self.offset + self.duration
+        # switch between showing frame counts and seconds
         if self.unitsVar.get() == FRAMES:
-            newMin = int(math.floor(self.offset * self.fps))
-            newMax = int(math.ceil(self.offset * self.fps)) + self.maxFrame
-            self.minLabel['text'] = newMin
-            self.maxLabel['text'] = newMax
-            self.frameControl.configure(to = newMax, resolution = 1.0)
+            # these are approximate due to discrete frame size
+            fromFrame = 0
+            toFrame = self.maxFrame
+            self.minLabel['text'] = fromFrame
+            self.maxLabel['text'] = toFrame
+            self.frameControl.configure(from_ = fromFrame,
+                                        to = toFrame,
+                                        resolution = 1.0)
         else:
-            newMin = self.offset
-            newMax = self.offset + self.maxSeconds
-            self.minLabel['text'] = "%.1f" % newMin
-            self.maxLabel['text'] = "%.1f" % newMax
-            self.frameControl.configure(to = newMax, resolution = 0.01)
+            self.minLabel['text'] = '0.0'
+            self.maxLabel['text'] = "%.2f" % self.duration
+            self.frameControl.configure(from_ = 0.0, 
+                                        to = self.duration,
+                                        resolution = 0.01)
+
+    def __onPress(self, event):
+        # Enable slider command
+        self.fScaleCommand = 1
+
+    def __onRelease(self, event):
+        # Disable slider command
+        self.fScaleCommand = 0
 
     def selectAnimNamed(self, name):
         self['active'] = name
@@ -393,31 +431,131 @@ class ActorControl(Pmw.MegaWidget):
         self.unitsVar.set(SECONDS)
         self.updateDisplay()
 
-    def play(self, fLoop):
+    def play(self, deltaT, fLoop):
         if self.frameActiveVar.get():
+            # Compute new time
+            self.currT = self.currT + deltaT
             if fLoop:
-                self['actor'].loop(self['active'])
+                # If its looping compute modulo
+                loopT = self.currT % self.duration
+                self.goToT(loopT)
             else:
-                self['actor'].play(self['active'])
+                if (self.currT > self.maxSeconds):
+                    # Clear this actor control from play list
+                    self['animPanel'].playList.remove(self)
+                else:
+                    self.goToT(self.currT)
+        else:
+            # Clear this actor control from play list
+            self['animPanel'].playList.remove(self)
 
-    def goTo(self, t):
+    def goToF(self, f):
         if self.unitsVar.get() == FRAMES:
-            self['actor'].pose(self['active'], string.atoi(t))
+            self.frameControl.set(f)
         else:
-            self['actor'].pose(self['active'], int(string.atof(t) * self.fps))
+            self.frameControl.set(f/self.fps)
 
-    def stop(self):
-        if self.frameActiveVar.get():
-            self['actor'].stop()
+    def goToT(self, t):
+        if self.unitsVar.get() == FRAMES:
+            self.frameControl.set(t * self.fps)
+        else:
+            self.frameControl.set(t)
+
+    def goTo(self, t):
+        # Convert scale value to float
+        t = string.atof(t)
+        # Now convert t to seconds for offset calculations
+        if self.unitsVar.get() == FRAMES:
+            t = t / self.fps
+        # Update currT
+        if self.fScaleCommand or self.fOneShot:
+            self.currT = t
+            self.fOneShot = 0
+        # Now update actor (pose specifed as frame count)
+        self['actor'].pose(self['active'],
+                           min(self.maxFrame, int(t * self.fps)))
 
     def resetToZero(self):
-        self.frameControl.set(0.0)
+        # This flag forces self.currT to be updated to new value
+        self.fOneShot = 1
+        self.goToT(0)
         
     def resetToEnd(self):
-        if self.unitsVar.get() == FRAMES:
-            t = self.maxFrame
-        else:
-            t = self.maxFrame / self.fps
-        self.frameControl.set(t)
+        # This flag forces self.currT to be updated to new value
+        self.fOneShot = 1
+        self.goToT(self.duration)
         
         
+"""
+# EXAMPLE CODE
+import Actor
+import AnimPanel
+
+a = Actor.Actor({250:{"head":"phase_3/models/char/dogMM_Shorts-head-250",
+                      "torso":"phase_3/models/char/dogMM_Shorts-torso-250",
+                      "legs":"phase_3/models/char/dogMM_Shorts-legs-250"},
+                 500:{"head":"phase_3/models/char/dogMM_Shorts-head-500",
+                      "torso":"phase_3/models/char/dogMM_Shorts-torso-500",
+                      "legs":"phase_3/models/char/dogMM_Shorts-legs-500"},
+                 1000:{"head":"phase_3/models/char/dogMM_Shorts-head-1000",
+                      "torso":"phase_3/models/char/dogMM_Shorts-torso-1000",
+                      "legs":"phase_3/models/char/dogMM_Shorts-legs-1000"}},
+                {"head":{"walk":"phase_3/models/char/dogMM_Shorts-head-walk", \
+                         "run":"phase_3/models/char/dogMM_Shorts-head-run"}, \
+                 "torso":{"walk":"phase_3/models/char/dogMM_Shorts-torso-walk", \
+                          "run":"phase_3/models/char/dogMM_Shorts-torso-run"}, \
+                 "legs":{"walk":"phase_3/models/char/dogMM_Shorts-legs-walk", \
+                         "run":"phase_3/models/char/dogMM_Shorts-legs-run"}})
+a.attach("head", "torso", "joint-head", 250)
+a.attach("torso", "legs", "joint-hips", 250)
+a.attach("head", "torso", "joint-head", 500)
+a.attach("torso", "legs", "joint-hips", 500)
+a.attach("head", "torso", "joint-head", 1000)
+a.attach("torso", "legs", "joint-hips", 1000)
+a.drawInFront("joint-pupil?", "eyes*", -1, lodName=250)
+a.drawInFront("joint-pupil?", "eyes*", -1, lodName=500)
+a.drawInFront("joint-pupil?", "eyes*", -1, lodName=1000)
+a.setLOD(250, 250, 75)
+a.setLOD(500, 75, 15)
+a.setLOD(1000, 15, 1)
+a.fixBounds()
+a.reparentTo(render)
+
+
+a2 = Actor.Actor({250:{"head":"phase_3/models/char/dogMM_Shorts-head-250",
+                      "torso":"phase_3/models/char/dogMM_Shorts-torso-250",
+                      "legs":"phase_3/models/char/dogMM_Shorts-legs-250"},
+                 500:{"head":"phase_3/models/char/dogMM_Shorts-head-500",
+                      "torso":"phase_3/models/char/dogMM_Shorts-torso-500",
+                      "legs":"phase_3/models/char/dogMM_Shorts-legs-500"},
+                 1000:{"head":"phase_3/models/char/dogMM_Shorts-head-1000",
+                      "torso":"phase_3/models/char/dogMM_Shorts-torso-1000",
+                      "legs":"phase_3/models/char/dogMM_Shorts-legs-1000"}},
+                {"head":{"walk":"phase_3/models/char/dogMM_Shorts-head-walk", \
+                         "run":"phase_3/models/char/dogMM_Shorts-head-run"}, \
+                 "torso":{"walk":"phase_3/models/char/dogMM_Shorts-torso-walk", \
+                          "run":"phase_3/models/char/dogMM_Shorts-torso-run"}, \
+                 "legs":{"walk":"phase_3/models/char/dogMM_Shorts-legs-walk", \
+                         "run":"phase_3/models/char/dogMM_Shorts-legs-run"}})
+a2.attach("head", "torso", "joint-head", 250)
+a2.attach("torso", "legs", "joint-hips", 250)
+a2.attach("head", "torso", "joint-head", 500)
+a2.attach("torso", "legs", "joint-hips", 500)
+a2.attach("head", "torso", "joint-head", 1000)
+a2.attach("torso", "legs", "joint-hips", 1000)
+a2.drawInFront("joint-pupil?", "eyes*", -1, lodName=250)
+a2.drawInFront("joint-pupil?", "eyes*", -1, lodName=500)
+a2.drawInFront("joint-pupil?", "eyes*", -1, lodName=1000)
+a2.setLOD(250, 250, 75)
+a2.setLOD(500, 75, 15)
+a2.setLOD(1000, 15, 1)
+a2.fixBounds()
+a2.reparentTo(render)
+
+ap = AnimPanel.AnimPanel([a, a2])
+
+# Alternately
+ap = a.animPanel()
+ap2 = a2.animPanel()
+
+"""