################################################################# # collisionWindow.py # Written by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004 ################################################################# # Import Tkinter, Pmw, and the floater code from this directory tree. from direct.tkwidgets.AppShell import * from direct.showbase.TkGlobal import * from tkSimpleDialog import askfloat import string import math import types from direct.task import Task FRAMES = 0 SECONDS = 1 ##################################################################################### # BlendAnimPanel(AppShell) # This Panel will allow user to blend tow animations # that have already been loaded for this actor. # user can play and manipulate this blended animation # just like in the animation panel. And, they can save this blended animation. ##################################################################################### class BlendAnimPanel(AppShell): # Override class variables appname = 'Blend Anim Panel' frameWidth = 575 frameHeight = 450 usecommandarea = 0 usestatusarea = 0 index = 0 dragMode = False blendRatio = 0 rateList= ['1/24.0', '0.1', '0.5', '1.0', '2.0', '5.0' , '10.0'] enableBlend = False currentBlendName = None def __init__(self, aNode = None, blendDict={}, parent = None, **kw): INITOPT = Pmw.INITOPT self.id = 'BlendAnimPanel '+ aNode.getName() self.appname = self.id self.actorNode = aNode self.blendDict = blendDict.copy() if len(blendDict)>0: self.blendList = blendDict.keys() else: self.blendList = [] optiondefs = ( ('title', self.appname, None), ('actor', aNode, None), ('animList', [], None), ('blendAnimList', self.blendList, None), ) self.defineoptions(kw, optiondefs) self.id = 'Blend AnimPanel '+ aNode.getName() self.nodeName = aNode.getName() # Initialize the superclass AppShell.__init__(self) # Execute option callbacks self.initialiseoptions(BlendAnimPanel) self.currTime = 0.0 self.animNameA = None self.animNameB = None self.parent.resizable(False,False) ## Disable the ability to resize for this Window. def createInterface(self): # Handle to the toplevels interior interior = self.interior() self.menuBar.destroy() # show the actor's name actorFrame = Frame(interior) name_label = Label(actorFrame, text= self.nodeName,font=('MSSansSerif', 14), relief = SUNKEN, borderwidth=3) name_label.pack(side = TOP, expand = False) actorFrame.pack(side = TOP, expand = False, fill = X) # Create a frame to show is there any ore-blended animation and save, edit, rename button. group = Pmw.Group(interior, tag_pyclass=None) actorFrame = group.interior() group.pack(side = TOP, expand = False, fill = X) Label(actorFrame, text= "Blended:", font=('MSSansSerif', 10)).pack(side=LEFT) self.blendAnimEntry = self.createcomponent( 'Blended Animation', (), None, Pmw.ComboBox, (actorFrame,), labelpos = W, entry_width = 20, selectioncommand = self.setBlendAnim, scrolledlist_items = self['blendAnimList']) self.blendAnimEntry.pack(side=LEFT) Label(actorFrame, text= " ", font=('MSSansSerif', 10)).pack(side=LEFT) button = Button(actorFrame, text="Save", font=('MSSansSerif', 10),width = 12, command = self.saveButtonPushed).pack(side=LEFT) button = Button(actorFrame, text="Remove", font=('MSSansSerif', 10),width = 12, command = self.removeButtonPushed).pack(side=LEFT) button = Button(actorFrame, text="Rename", font=('MSSansSerif', 10),width = 12, command = self.renameButtonPushed).pack(side=LEFT) actorFrame.pack(side = TOP, expand = False, fill = X) # Create a frame to hold all the animation setting group = Pmw.Group(interior, tag_pyclass=None) actorFrame = group.interior() group.pack(side = TOP, expand = False, fill = X) Label(actorFrame, text= "Animation A:", font=('MSSansSerif', 10)).pack(side=LEFT) self['animList'] = self['actor'].getAnimNames() self.AnimEntryA = self.createcomponent( 'AnimationMenuA', (), None, Pmw.ComboBox, (actorFrame,), labelpos = W, entry_width = 20, entry_state = DISABLED, selectioncommand = lambda name, a = 'a' : self.setAnimation(name, AB=a), scrolledlist_items = self['animList']) self.AnimEntryA.pack(side=LEFT) Label(actorFrame, text= " ", font=('MSSansSerif', 10)).pack(side=LEFT,) Label(actorFrame, text= "Animation B:", font=('MSSansSerif', 10)).pack(side=LEFT) self['animList'] = self['actor'].getAnimNames() self.AnimEntryB = self.createcomponent( 'AnimationMenuB', (), None, Pmw.ComboBox, (actorFrame,), labelpos = W, entry_width = 20, entry_state = DISABLED, selectioncommand = lambda name, a = 'b' : self.setAnimation(name, AB=a), scrolledlist_items = self['animList']) self.AnimEntryB.pack(side=LEFT) actorFrame.pack(side = TOP, expand = False, fill = X) ### Blend Enable checkbox actorFrame = Frame(interior, relief = SUNKEN, bd = 1) Label(actorFrame, text= "Enable Blending:", font=('MSSansSerif', 10)).pack(side=LEFT,) self.blendVar = IntVar() self.blendVar.set(0) self.blendButton = self.createcomponent( 'blendButton', (), None, Checkbutton, (actorFrame,), variable = self.blendVar, command = self.toggleBlend) self.blendButton.pack(side=LEFT) actorFrame.pack(side = TOP, expand = False, fill = X) ## Ratio control actorFrame = Frame(interior) frameFrame = Frame(actorFrame, relief = SUNKEN, bd = 1) minRatioLabel = self.createcomponent( 'minRatioLabel', (), 'sLabel', Label, (frameFrame,), text = 0.00) minRatioLabel.pack(side = LEFT) self.ratioControl = self.createcomponent( 'ratio', (), None, Scale, (frameFrame,), from_ = 0.0, to = 1.0, resolution = 0.01, command = self.setRatio, length = 500, orient = HORIZONTAL, showvalue = 1) self.ratioControl.pack(side = LEFT, expand = 1) self.ratioControl.set(1.0) self.maxRatioLabel = self.createcomponent( 'maxRatioLabel', (), 'sLabel', Label, (frameFrame,), text = 1.00) self.maxRatioLabel.pack(side = LEFT) frameFrame.pack(side = LEFT, expand = 1, fill = X) actorFrame.pack(side = TOP, expand = True, fill = X) ################################################################################### ################################################################################### actorFrame = Frame(interior) Label(actorFrame, text= "Play Rate:", font=('MSSansSerif', 10)).pack(side=LEFT) self.playRateEntry = self.createcomponent( 'playRateMenu', (), None, Pmw.ComboBox, (actorFrame,), labelpos = W, entry_width = 20, selectioncommand = self.setPlayRate, scrolledlist_items = self.rateList) self.playRateEntry.pack(side=LEFT) self.playRateEntry.selectitem('1.0') ### Loop checkbox Label(actorFrame, text= " ", font=('MSSansSerif', 10)).pack(side=LEFT,) Label(actorFrame, text= "Loop:", font=('MSSansSerif', 10)).pack(side=LEFT,) self.loopVar = IntVar() self.loopVar.set(0) self.loopButton = self.createcomponent( 'loopButton', (), None, Checkbutton, (actorFrame,), variable = self.loopVar) self.loopButton.pack(side=LEFT) actorFrame.pack(side = TOP, expand = True, fill = X) ### Display Frames/Seconds actorFrame = Frame(interior) Label(actorFrame, text= "Frame/Second:", font=('MSSansSerif', 10)).pack(side=LEFT) self.unitsVar = IntVar() self.unitsVar.set(FRAMES) self.displayButton = self.createcomponent( 'displayButton', (), None, Checkbutton, (actorFrame,), command = self.updateDisplay, variable = self.unitsVar) self.displayButton.pack(side=LEFT) actorFrame.pack(side = TOP, expand = True, fill = X) ## scale control actorFrame = Frame(interior) frameFrame = Frame(actorFrame, 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, length = 500, 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) actorFrame.pack(side = TOP, expand = True, fill = X) ## button contorl actorFrame = Frame(interior) ButtomFrame = Frame(actorFrame, relief = SUNKEN, bd = 1,borderwidth=5) self.toStartButton = self.createcomponent( 'toStart', (), None, Button, (ButtomFrame,), text = '<<', width = 8, command = self.resetAllToZero) self.toStartButton.pack(side = LEFT, expand = 1, fill = X) self.playButton = self.createcomponent( 'playButton', (), None, Button, (ButtomFrame,), text = 'Play', width = 8, command = self.play) self.playButton.pack(side = LEFT, expand = 1, fill = X) self.stopButton = self.createcomponent( 'stopButton', (), None, Button, (ButtomFrame,), text = 'Stop', width = 8, state=DISABLED, command = self.stop) self.stopButton.pack(side = LEFT, expand = 1, fill = X) self.toEndButton = self.createcomponent( 'toEnd', (), None, Button, (ButtomFrame,), text = '>>', width = 8, command = self.resetAllToEnd) self.toEndButton.pack(side = LEFT, expand = 1, fill = X) ButtomFrame.pack(side = TOP, expand = True, fill = X) actorFrame.pack(expand = 1, fill = BOTH) def updateList(self): ################################################################# # updateList(self) # This will reset the list of all animations that this actor has # to the animation entry A and B. ################################################################# self['animList'] = self['actor'].getAnimNames() animL = self['actor'].getAnimNames() self.AnimEntryA.setlist(animL) self.AnimEntryB.setlist(animL) def play(self): ################################################################# # play(self) # It works pretty much like what we have in the Animation Panel. # The only different now is that we set two "pose" here. # When you do the blending animation by setPose, you don't have # to set them simultaneously. ################################################################# self.animNameA = self.AnimEntryA.get() self.animNameB = self.AnimEntryB.get() if (self.animNameA in self['animList'])and(self.animNameB in self['animList']): self.playButton.config(state=DISABLED) self.lastT = globalClock.getFrameTime() taskMgr.add(self.playTask, self.id + '_UpdateTask') self.stopButton.config(state=NORMAL) else: print '----Illegal Animaion name!!', self.animNameA + ', '+ self.animNameB return def playTask(self, task): ################################################################# # playTask(self, task) # see play(self) ################################################################# fLoop = self.loopVar.get() currT = globalClock.getFrameTime() deltaT = currT - self.lastT self.lastT = currT if self.dragMode: return Task.cont self.currTime = self.currTime + deltaT if (self.currTime > self.maxSeconds): if fLoop: self.currTime = self.currTime%self.duration self.gotoT(self.currTime) else: self.currTime = 0.0 self.gotoT(0.0) self.playButton.config(state=NORMAL) self.stopButton.config(state=DISABLED) return Task.done else: self.gotoT(self.currTime) return Task.cont def stop(self): ################################################################# # stop(self) # see play(self) ################################################################# taskMgr.remove(self.id + '_UpdateTask') self.playButton.config(state=NORMAL) self.stopButton.config(state=DISABLED) return def setAnimation(self, animation, AB = 'a'): ################################################################# # setAnimation(self, animation, AB = 'a') # see play(self) ################################################################# print 'OK!!!' if AB == 'a': if self.animNameA != None: self['actor'].setControlEffect(self.animNameA, 1.0, 'modelRoot','lodRoot') self.animNameA = self.AnimEntryA.get() else: if self.animNameB != None: self['actor'].setControlEffect(self.animNameB, 1.0, 'modelRoot','lodRoot') self.animNameB = self.AnimEntryB.get() self.currTime = 0.0 self.frameControl.set(0) self.updateDisplay() self.setRatio(self.blendRatio) return def setPlayRate(self,rate): ################################################################# # setPlayRate(self,rate) # see play(self) ################################################################# self.animNameA = self.AnimEntryA.get() if self.animNameA in self['animList']: self['actor'].setPlayRate(eval(rate), self.animNameA) self.updateDisplay() if self.animNameB in self['animList']: self['actor'].setPlayRate(eval(rate), self.animNameB) self.updateDisplay() return def updateDisplay(self): ################################################################# # updateDisplay(self) # see play(self) ################################################################# if not (self.animNameA in self['animList']): return self.fps = self['actor'].getFrameRate(self.animNameA) self.duration = self['actor'].getDuration(self.animNameA) self.maxFrame = self['actor'].getNumFrames(self.animNameA) - 1 if not (self.animNameB in self['animList']): return if self.duration > self['actor'].getDuration(self.animNameB): self.duration = self['actor'].getDuration(self.animNameB) if self.maxFrame > self['actor'].getNumFrames(self.animNameB) - 1: self.maxFrame = self['actor'].getNumFrames(self.animNameB) - 1 self.maxSeconds = self.duration if self.unitsVar.get() == FRAMES: 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 gotoT(self,time): ################################################################# # gotoT(self,time) # see play(self) ################################################################# if self.unitsVar.get() == FRAMES: self.frameControl.set(time * self.fps) else: self.frameControl.set(time) return def goTo(self,frame): ################################################################# # goTo(self,frame) # see play(self) ################################################################# if (self.animNameA in self['animList'])and(self.animNameB in self['animList']): # Convert scale value to float frame = string.atof(frame) # Now convert t to seconds for offset calculations if self.unitsVar.get() == FRAMES: frame = frame / self.fps if self.dragMode: self.currTime = frame self['actor'].pose(self.animNameA, min(self.maxFrame, int(frame * self.fps))) self['actor'].pose(self.animNameB, min(self.maxFrame, int(frame * self.fps))) return def onRelease(self,frame): ################################################################# # onRelease(self,frame) # see play(self) ################################################################# self.dragMode = False return def onPress(self,frame): ################################################################# # onPress(self,frame) # see play(self) ################################################################# self.dragMode = True return def resetAllToZero(self): ################################################################# # resetAllToZero(self) # see play(self) ################################################################# self.currTime = 0.0 self.gotoT(0) return def resetAllToEnd(self): ################################################################# # resetAllToEnd(self) # see play(self) ################################################################# self.currTime = self.maxSeconds self.gotoT(self.duration) return def toggleBlend(self): ################################################################# # toggleBlend(self) # This function will enable the blending option for the actor. # and call set ratio function to set the blending animation mixing in # current ratio. # # This blending enable will not be keep when you close the window! # ################################################################# if self.blendVar.get(): self.enableBlend = True self['actor'].enableBlend() self.setRatio(self.blendRatio) else: self.enableBlend = False self['actor'].disableBlend() return def setRatio(self, ratio): ################################################################# # setRatio(self, ratio) # callback funtion # This one will be called each time when user drag the blend ratio # slider on the panel. This will set the blening ratio to both animation. # (Which is "setControlEffect") ################################################################# self.blendRatio = float(ratio) if self.enableBlend: if self.animNameA in self['animList']: self['actor'].setControlEffect(self.animNameA, self.blendRatio, 'modelRoot','lodRoot') if self.animNameB in self['animList']: self['actor'].setControlEffect(self.animNameB, 1-self.blendRatio, 'modelRoot','lodRoot') return def setBlendAnim(self, name): ################################################################# # setBlendAnim(self, name) # This function will be called each time when user try to select # a existing blending animation from the comboBox on the panel # This function will re-set every varaibles on the panel to what # it should be. For example, when user choose blending anim "R," # which was blended by anim "a" and "b" with ratio "c," # then this function will set Animation A to "a" and animation B # to "b" and set the ratio slider to "c" position. ################################################################# if self.blendDict.has_key(name): self.currentBlendName = name animA = self.blendDict[name][0] animB = self.blendDict[name][1] ratio = self.blendDict[name][2] self.AnimEntryA.selectitem(animA) self.AnimEntryB.selectitem(animB) self.setAnimation(animA, AB = 'a') self.setAnimation(animB, AB = 'b') self.ratioControl.set(ratio) return def setBlendAnimList(self, dict, select=False): ################################################################# # setBlendAnimList(self, dict, select=False) # This function will be called when we need to reset the dropdown list # of "Blend Anim." # About "selec" option, this now is mainly used when we remove # a blended animation from the actor. When it has been specified to True, # the function will not only reset the list, but will also automatically # select one from the top of list, if it is not empty. ################################################################# self.blendDict.clear() del self.blendDict self.blendDict = dict.copy() print self.blendDict if len(self.blendDict)>0: self.blendList = self.blendDict.keys() else: self.blendList = [] self.blendAnimEntry.setlist(self.blendList) if select: if len(self.blendList)>0: self.blendAnimEntry.selectitem(self.blendList[0]) self.setBlendAnim(self.blendList[0]) self.currentBlendName = self.blendList[0] else: self.blendAnimEntry.clear() self.currentBlendName = None return def saveButtonPushed(self): ################################################################# # saveButtonPushed(self) # This function will be called when user clicked on the "Save" button # This functiont will collect all data on the panel and send them with # a message to sceneEditor to save the current blending animation # into the dataHolder. ################################################################# name = self.blendAnimEntry.get() if name=='': Pmw.MessageDialog(None, title='Caution!', message_text = 'You have to give the blending animation a name first!', iconpos='s', defaultbutton = 'Close' ) return elif (not(self.animNameA in self['animList']))or(not(self.animNameB in self['animList'])): Pmw.MessageDialog(None, title='Caution!', message_text = 'The Animations you have selected are not exist!', iconpos='s', defaultbutton = 'Close' ) return else: messenger.send('BAW_saveBlendAnim', [self['actor'].getName(), name, self.animNameA, self.animNameB, self.blendRatio]) self.currentBlendName = name return def removeButtonPushed(self): ################################################################# # removeButtonPushed(self) # remove the current seleted blended animation from the actor. # This will send out a message to sceneEditor to delete the data inside # the dataHolder and then reset the list of here. ################################################################# name = self.blendAnimEntry.get() messenger.send('BAW_removeBlendAnim', [self['actor'].getName(),name]) return def renameButtonPushed(self): ################################################################# # renameButtonPushed(self) # this function will be called when user click on the "Rename" button. # This function will collect all data on the panel and send them out # with a message to sceneEditor to rename and re-save all setting about # current animation. ################################################################# oName = self.currentBlendName name = self.blendAnimEntry.get() if self.currentBlendName == None: Pmw.MessageDialog(None, title='Caution!', message_text = "You haven't select any blended animation!!", iconpos='s', defaultbutton = 'Close' ) return elif name=='': Pmw.MessageDialog(None, title='Caution!', message_text = 'You have to give the blending animation a name first!', iconpos='s', defaultbutton = 'Close' ) return elif (not(self.animNameA in self['animList']))or(not(self.animNameB in self['animList'])): Pmw.MessageDialog(None, title='Caution!', message_text = 'The Animations you have selected are not exist!', iconpos='s', defaultbutton = 'Close' ) return else: messenger.send('BAW_renameBlendAnim', [self['actor'].getName(), name, oName, self.animNameA, self.animNameB, self.blendRatio] ) self.currentBlendName = name return def onDestroy(self, event): ################################################################# # onDestroy(self, event) # This function will be call when user try to close the window. # In here we will stop all tasks we have opend and disable the # blend setting of actor. # If we didn't disable the blend option, the next time you play # the animation via animation panel will cause some error. ################################################################# if taskMgr.hasTaskNamed(self.id + '_UpdateTask'): taskMgr.remove(self.id + '_UpdateTask') messenger.send('BAW_close',[self.nodeName]) self.actorNode.setControlEffect(self.animNameA, 1.0, 'modelRoot','lodRoot') self.actorNode.setControlEffect(self.animNameB, 1.0, 'modelRoot','lodRoot') self.actorNode.disableBlend() ''' If you have open any thing, please rewrite here! ''' pass