"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 TkGlobal import * from tkSimpleDialog import askfloat import string import math import types import Task FRAMES = 0 SECONDS = 1 class AnimPanel(AppShell): # Override class variables appname = 'Anim Panel' frameWidth = 675 frameHeight = 250 usecommandarea = 0 usestatusarea = 0 index = 0 def __init__(self, aList = [], parent = None, **kw): INITOPT = Pmw.INITOPT if ((type(aList) == types.ListType) or (type(aList) == types.TupleType)): kw['actorList'] = aList else: kw['actorList'] = [aList] optiondefs = ( ('title', self.appname, None), ('actorList', [], None), ('Actor_label_width', 12, None), ) 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) # Execute option callbacks self.initialiseoptions(AnimPanel) def createInterface(self): # Handle to the toplevels interior interior = self.interior() menuBar = self.menuBar menuBar.addmenu('AnimPanel', 'Anim Panel Operations') # Actor control status menuBar.addcascademenu('AnimPanel', 'Control Status', 'Enable/disable actor control panels') menuBar.addmenuitem('Control Status', 'command', 'Enable all actor controls', label = 'Enable all', command = self.enableActorControls) menuBar.addmenuitem('Control Status', 'command', 'Disable all actor controls', label = 'Disable all', command = self.disableActorControls) # Frame Slider units menuBar.addcascademenu('AnimPanel', 'Display Units', 'Select display units') menuBar.addmenuitem('Display Units', 'command', 'Display frame counts', label = 'Frame count', command = self.displayFrameCounts) menuBar.addmenuitem('Display Units', 'command', 'Display seconds', label = 'Seconds', command = self.displaySeconds) # Reset all actor controls menuBar.addmenuitem('AnimPanel', 'command', 'Set actor controls to t = 0.0', label = 'Jump all to zero', command = self.resetAllToZero) menuBar.addmenuitem('AnimPanel', 'command', 'Set Actor controls to end time', label = 'Jump all to end time', command = self.resetAllToEnd) # Add some buttons to update all Actor Controls self.fToggleAll = 1 b = self.createcomponent( 'toggleEnableButton', (), None, Button, (self.menuFrame,), text = 'Toggle Enable', command = self.toggleAllControls) b.pack(side = RIGHT, expand = 0) b = self.createcomponent( 'showSecondsButton', (), None, Button, (self.menuFrame,), text = 'Show Seconds', command = self.displaySeconds) b.pack(side = RIGHT, expand = 0) b = self.createcomponent( 'showFramesButton', (), None, Button, (self.menuFrame,), text = 'Show Frames', command = self.displayFrameCounts) b.pack(side = RIGHT, expand = 0) # Create a frame to hold all the actor controls actorFrame = Frame(interior) # Create a control for each actor index = 0 self.actorControlList = [] for actor in self['actorList']: anims = actor.getAnimNames() topAnims = [] if 'neutral' in anims: i = anims.index('neutral') del(anims[i]) topAnims.append('neutral') if 'walk' in anims: i = anims.index('walk') del(anims[i]) topAnims.append('walk') if 'run' in anims: i = anims.index('run') del(anims[i]) topAnims.append('run') anims.sort() anims = topAnims + anims ac = self.createcomponent( 'actorControl%d' % index, (), 'Actor', ActorControl, (actorFrame,), animPanel = self, text = actor.getName(), animList = anims, actor = actor) ac.pack(expand = 1, fill = X) self.actorControlList.append(ac) index = index + 1 # Now pack the actor frame actorFrame.pack(expand = 1, fill = BOTH) # Create a frame to hold the playback controls controlFrame = Frame(interior) self.toStartButton = self.createcomponent( 'toStart', (), None, Button, (controlFrame,), text = '<<', width = 8, command = self.resetAllToZero) self.toStartButton.pack(side = LEFT, expand = 1, fill = X) self.playButton = self.createcomponent( 'playButton', (), None, Button, (controlFrame,), text = 'Play', width = 8, command = self.playActorControls) self.playButton.pack(side = LEFT, expand = 1, fill = X) self.stopButton = self.createcomponent( 'stopButton', (), None, Button, (controlFrame,), text = 'Stop', width = 8, command = self.stopActorControls) self.stopButton.pack(side = LEFT, expand = 1, fill = X) self.toEndButton = self.createcomponent( 'toEnd', (), None, Button, (controlFrame,), text = '>>', width = 8, command = self.resetAllToEnd) self.toEndButton.pack(side = LEFT, expand = 1, fill = X) self.loopVar = IntVar() self.loopVar.set(0) self.loopButton = self.createcomponent( 'loopButton', (), None, Checkbutton, (controlFrame,), text = 'Loop', width = 8, variable = self.loopVar) self.loopButton.pack(side = LEFT, expand = 1, fill = X) controlFrame.pack(fill = X) def playActorControls(self): self.stopActorControls() self.lastT = globalClock.getFrameTime() self.playList = self.actorControlList[:] taskMgr.add(self.play, self.id + '_UpdateTask') def play(self, task): if not self.playList: return Task.done fLoop = self.loopVar.get() 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): taskMgr.remove(self.id + '_UpdateTask') def getActorControlAt(self, index): return self.actorControlList[index] def enableActorControlAt(self,index): self.getActorControlAt(index).enableControl() def toggleAllControls(self): if self.fToggleAll: self.disableActorControls() else: self.enableActorControls() self.fToggleAll = 1 - self.fToggleAll def enableActorControls(self): for actorControl in self.actorControlList: actorControl.enableControl() def disableActorControls(self): for actorControl in self.actorControlList: actorControl.disableControl() def disableActorControlAt(self,index): self.getActorControlAt(index).disableControl() def displayFrameCounts(self): for actorControl in self.actorControlList: actorControl.displayFrameCounts() def displaySeconds(self): for actorControl in self.actorControlList: actorControl.displaySeconds() def resetAllToZero(self): for actorControl in self.actorControlList: actorControl.resetToZero() def resetAllToEnd(self): for actorControl in self.actorControlList: actorControl.resetToEnd() class ActorControl(Pmw.MegaWidget): def __init__(self, parent = None, **kw): INITOPT = Pmw.INITOPT DEFAULT_FONT = (('MS', 'Sans', 'Serif'), 12, 'bold') DEFAULT_ANIMS = ('neutral', 'run', 'walk') animList = kw.get('animList', DEFAULT_ANIMS) if len(animList) > 0: initActive = animList[0] else: initActive = DEFAULT_ANIMS[0] optiondefs = ( ('text', 'Actor', self._updateLabelText), ('animPanel', None, None), ('actor', None, None), ('animList', DEFAULT_ANIMS, None), ('active', initActive, None), ('sLabel_width', 5, None), ('sLabel_font', DEFAULT_FONT, None), ) self.defineoptions(kw, optiondefs) # Initialize the superclass Pmw.MegaWidget.__init__(self, parent) # Handle to the toplevels hull interior = self.interior() interior.configure(relief = RAISED, bd = 2) # Instance variables self.fps = 24 self.offset = 0.0 self.maxSeconds = 1.0 self.currT = 0.0 self.fScaleCommand = 0 self.fOneShot = 0 # Create component widgets self._label = self.createcomponent( 'label', (), None, Menubutton, (interior,), font=('MSSansSerif', 14, 'bold'), relief = RAISED, bd = 1, activebackground = '#909090', text = self['text']) # Top level menu labelMenu = Menu(self._label, tearoff = 0 ) # Menu to select display mode self.unitsVar = IntVar() self.unitsVar.set(FRAMES) displayMenu = Menu(labelMenu, tearoff = 0 ) displayMenu.add_radiobutton(label = 'Frame count', value = FRAMES, variable = self.unitsVar, command = self.updateDisplay) displayMenu.add_radiobutton(label = 'Seconds', value = SECONDS, variable = self.unitsVar, 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 = '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) # Combo box to select current animation animMenu = self.createcomponent( 'animMenu', (), None, Pmw.ComboBox, (interior,), labelpos = W, label_text = 'Anim:', entry_width = 12, selectioncommand = self.selectAnimNamed, scrolledlist_items = self['animList']) animMenu.selectitem(self['active']) 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 = '%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(strCmp) playRateMenu = self.createcomponent( 'playRateMenu', (), None, Pmw.ComboBox, (interior,), labelpos = W, label_text = 'Play Rate:', entry_width = 4, selectioncommand = self.setPlayRate, scrolledlist_items = playRateList) playRateMenu.selectitem(playRate) playRateMenu.pack(side = LEFT, padx = 5, expand = 0) # Scale to control animation frameFrame = Frame(interior, relief = SUNKEN, bd = 1) self.minLabel = self.createcomponent( 'minLabel', (), 'sLabel', Label, (frameFrame,), text = 0) self.minLabel.pack(side = LEFT) self.frameControl = self.createcomponent( 'scale', (), None, Scale, (frameFrame,), from_ = 0, to = 24, resolution = 1.0, command = self.goTo, orient = HORIZONTAL, showvalue = 1) self.frameControl.pack(side = LEFT, expand = 1) self.frameControl.bind('', self.__onPress) self.frameControl.bind('', self.__onRelease) self.maxLabel = self.createcomponent( 'maxLabel', (), 'sLabel', Label, (frameFrame,), text = 24) self.maxLabel.pack(side = LEFT) frameFrame.pack(side = LEFT, expand = 1, fill = X) # Checkbutton to enable/disable control self.frameActiveVar = IntVar() self.frameActiveVar.set(1) frameActive = self.createcomponent( 'checkbutton', (), None, Checkbutton, (interior,), variable = self.frameActiveVar) frameActive.pack(side = LEFT, expand = 1) # Execute option callbacks self.initialiseoptions(ActorControl) self.updateDisplay() def _updateLabelText(self): self._label['text'] = self['text'] def updateDisplay(self): 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.offset + self.duration # switch between showing frame counts and seconds if self.unitsVar.get() == FRAMES: # 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: 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): # Update active anim self['active'] = name # Reset play rate self.component('playRateMenu').selectitem('1.0') self.setPlayRate('1.0') # Move slider to zero self.resetToZero() def setPlayRate(self, rate): self['actor'].setPlayRate(eval(rate), self['active']) self.updateDisplay() def setOffset(self): newOffset = askfloat(parent = self.interior(), title = self['text'], prompt = 'Start offset (seconds):') if newOffset != None: self.offset = newOffset self.updateDisplay() def enableControl(self): self.frameActiveVar.set(1) def disableControl(self): self.frameActiveVar.set(0) def displayFrameCounts(self): self.unitsVar.set(FRAMES) self.updateDisplay() def displaySeconds(self): self.unitsVar.set(SECONDS) self.updateDisplay() def play(self, deltaT, fLoop): if self.frameActiveVar.get(): # Compute new time self.currT = self.currT + deltaT if fLoop: # If its looping compute modulo loopT = self.currT % self.duration self.goToT(loopT) else: 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 goToF(self, f): if self.unitsVar.get() == FRAMES: self.frameControl.set(f) else: self.frameControl.set(f/self.fps) 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): # This flag forces self.currT to be updated to new value self.fOneShot = 1 self.goToT(0) def resetToEnd(self): # 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() """