class DirectSession(DirectObject): __module__ = __name__ DIRECTdisablePost = 'disableDIRECT' def __init__(self): __builtins__['direct'] = base.direct = self self.group = render.attachNewNode('DIRECT') self.font = TextNode.getDefaultFont() self.fEnabled = 0 self.fEnabledLight = 0 self.fScaleWidgetByCam = 0 self.fIgnoreDirectOnlyKeyMap = 0 self.drList = DisplayRegionList() self.iRayList = map(lambda x: x.iRay, self.drList) self.dr = self.drList[0] self.win = base.win self.camera = base.camera self.cam = base.cam self.camNode = base.camNode self.trueCamera = self.camera self.iRay = self.dr.iRay self.coaMode = COA_ORIGIN self.cameraControl = DirectCameraControl() self.manipulationControl = DirectManipulationControl() self.useObjectHandles() self.grid = DirectGrid() self.grid.disable() self.lights = DirectLights(base.direct.group) self.lights.createDefaultLights() self.lights.allOff() self.selected = SelectedNodePaths() self.ancestry = [] self.ancestryIndex = 0 self.activeParent = None self.selectedNPReadout = OnscreenText.OnscreenText( pos=(-1.0, -0.9), bg=Vec4(1, 1, 1, 1), scale=0.05, align=TextNode.ALeft, mayChange=1, font=self.font) useDirectRenderStyle(self.selectedNPReadout) self.selectedNPReadout.reparentTo(hidden) self.activeParentReadout = OnscreenText.OnscreenText( pos=(-1.0, -0.975), bg=Vec4(1, 1, 1, 1), scale=0.05, align=TextNode.ALeft, mayChange=1, font=self.font) useDirectRenderStyle(self.activeParentReadout) self.activeParentReadout.reparentTo(hidden) self.directMessageReadout = OnscreenText.OnscreenText( pos=(-1.0, 0.9), bg=Vec4(1, 1, 1, 1), scale=0.05, align=TextNode.ALeft, mayChange=1, font=self.font) useDirectRenderStyle(self.directMessageReadout) self.directMessageReadout.reparentTo(hidden) self.deviceManager = None self.joybox = None self.radamec = None self.fastrak = [] if base.config.GetBool('want-vrpn', 0): from direct.directdevices import DirectDeviceManager self.deviceManager = DirectDeviceManager.DirectDeviceManager() joybox = base.config.GetString('vrpn-joybox-device', '') radamec = base.config.GetString('vrpn-radamec-device', '') fastrak = base.config.GetString('vrpn-fastrak-device', '') if joybox: from direct.directdevices import DirectJoybox self.joybox = DirectJoybox.DirectJoybox(joybox) if radamec: from direct.directdevices import DirectRadamec self.radamec = DirectRadamec.DirectRadamec(radamec) if fastrak: from direct.directdevices import DirectFastrak fastrak = string.split(fastrak) for i in range(len(fastrak))[1:]: self.fastrak.append( DirectFastrak.DirectFastrak(fastrak[0] + ':' + fastrak[i])) self.fControl = 0 self.fAlt = 0 self.fShift = 0 self.fMouse1 = 0 self.fMouse2 = 0 self.fMouse3 = 0 self.pos = VBase3() self.hpr = VBase3() self.scale = VBase3() self.hitPt = Point3(0.0) self.undoList = [] self.redoList = [] self.drList.updateContext() for dr in self.drList: dr.camUpdate() self.actionEvents = [ ['select', self.select], ['DIRECT-select', self.selectCB], ['deselect', self.deselect], ['deselectAll', self.deselectAll], ['DIRECT-preDeselectAll', self.deselectAllCB], ['highlightAll', self.selected.highlightAll], ['preRemoveNodePath', self.deselect], ['SGE_Select', self.select], ['SGE_Deselect', self.deselect], ['SGE_Set Reparent Target', self.setActiveParent], ['SGE_Reparent', self.reparent], ['SGE_WRT Reparent', lambda np, s=self: s.reparent(np, fWrt=1)], ['SGE_Flash', self.flash], ['SGE_Isolate', self.isolate], ['SGE_Toggle Vis', self.toggleVis], ['SGE_Show All', self.showAllDescendants], ['SGE_Fit', self.fitOnNodePath], ['SGE_Delete', self.removeNodePath], ['SGE_Set Name', self.getAndSetName], ['DIRECT-delete', self.removeAllSelected], ['DIRECT-Undo', self.undo], ['DIRECT-Redo', self.redo], ['DIRECT-OOBE', self.oobe], ['DIRECT-toggleWidgetVis', self.toggleWidgetVis], ['DIRECT-toggleWireframe', base.toggleWireframe], ['DIRECT-toggleVisAll', self.selected.toggleVisAll], ['DIRECT-toggleTexture', base.toggleTexture], ['DIRECT-upAncestry', self.upAncestry], ['DIRECT-downAncestry', self.downAncestry], ['DIRECT-toggleBackface', base.toggleBackface], ['DIRECT-flash', self.flash], ['DIRECT-toggleLigths', self.lights.toggle], ['DIRECT-toggleCOALock', self.cameraControl.toggleCOALock], ['DIRECT-setActiveParent', self.doSetActiveParent], ['DIRECT-doWrtReparent', self.doWrtReparent], ['DIRECT-doReparent', self.doReparent], ['DIRECT-doSelect', self.doSelect] ] if base.wantTk: from direct.tkpanels import Placer from direct.tkwidgets import Slider from direct.tkwidgets import SceneGraphExplorer self.actionEvents.extend( [['SGE_Place', Placer.place], ['SGE_Set Color', Slider.rgbPanel], ['SGE_Explore', SceneGraphExplorer.explore]]) self.modifierEvents = [ 'control', 'control-up', 'control-repeat', 'shift', 'shift-up', 'shift-repeat', 'alt', 'alt-up', 'alt-repeat' ] keyList = map(chr, range(97, 123)) keyList.extend(map(chr, range(48, 58))) keyList.extend( ['`', '-', '=', '[', ']', ';', "'", ',', '.', '/', '\\']) self.specialKeys = [ 'escape', 'delete', 'page_up', 'page_down', 'enter' ] def addCtrl(a): return 'control-%s' % a def addShift(a): return 'shift-%s' % a self.keyEvents = keyList[:] self.keyEvents.extend(map(addCtrl, keyList)) self.keyEvents.extend(map(addShift, keyList)) self.keyEvents.extend(self.specialKeys) self.mouseEvents = [ 'mouse1', 'mouse1-up', 'shift-mouse1', 'shift-mouse1-up', 'control-mouse1', 'control-mouse1-up', 'alt-mouse1', 'alt-mouse1-up', 'mouse2', 'mouse2-up', 'shift-mouse2', 'shift-mouse2-up', 'control-mouse2', 'control-mouse2-up', 'alt-mouse2', 'alt-mouse2-up', 'mouse3', 'mouse3-up', 'shift-mouse3', 'shift-mouse3-up', 'control-mouse3', 'control-mouse3-up', 'alt-mouse3', 'alt-mouse3-up' ] self.directOnlyKeyMap = { 'u': ('Orbit Upright Camera', 'DIRECT-orbitUprightCam'), 'shift-u': ('Upright Camera', 'DIRECT-uprightCam'), '1': ('Move Camera to View 1', 'DIRECT-spwanMoveToView-1'), '2': ('Move Camera to View 2', 'DIRECT-spwanMoveToView-2'), '3': ('Move Camera to View 3', 'DIRECT-spwanMoveToView-3'), '4': ('Move Camera to View 4', 'DIRECT-spwanMoveToView-4'), '5': ('Move Camera to View 5', 'DIRECT-spwanMoveToView-5'), '6': ('Move Camera to View 6', 'DIRECT-spwanMoveToView-6'), '7': ('Move Camera to View 7', 'DIRECT-spwanMoveToView-7'), '8': ('Move Camera to View 8', 'DIRECT-spwanMoveToView-8'), '9': ('Rotate Camera About widget 90 degrees Counterclockwise', 'DIRECT-swingCamAboutWidget-0'), '0': ('Rotate Camera About widget 90 degrees Clockwise', 'DIRECT-swingCamAboutWidget-1'), '`': ('Remove ManipulateCameraTask', 'DIRECT-removeManipulateCameraTask'), '=': ('Zoom In', 'DIRECT-zoomInCam'), 'shift-=': ('Zoom In', 'DIRECT-zoomInCam'), 'shift-_': ('Zoom Out', 'DIRECT-zoomOutCam'), '-': ('Zoom Out', 'DIRECT-zoomOutCam'), 'o': ('Toggle OOBE', 'DIRECT-OOBE'), '[': ('DIRECT-Undo', 'DIRECT-Undo'), 'shift-[': ('DIRECT-Undo', 'DIRECT-Undo'), ']': ('DIRECT-Redo', 'DIRECT-Redo'), 'shift-]': ('DIRECT-Redo', 'DIRECT-Redo') } self.hotKeyMap = { 'c': ('Center Camera', 'DIRECT-centerCamIn'), 'f': ('Fit on Widget', 'DIRECT-fitOnWidget'), 'h': ('Move Camera to ', 'DIRECT-homeCam'), 'shift-v': ('Toggle Marker', 'DIRECT-toggleMarkerVis'), 'm': ('Move to fit', 'DIRECT-moveToFit'), 'n': ('Pick Next COA', 'DIRECT-pickNextCOA'), 'delete': ('Delete', 'DIRECT-delete'), '.': ('Scale Up Widget', 'DIRECT-widgetScaleUp'), ',': ('Scale Down Widget', 'DIRECT-widgetScaleDown'), 'page_up': ('Up Ancestry', 'DIRECT-upAncestry'), 'page_down': ('Down Ancestry', 'DIRECT-downAncestry'), 'escape': ('Deselect All', 'deselectAll'), 'v': ('Toggle Manipulating Widget', 'DIRECT-toggleWidgetVis'), 'b': ('Toggle Backface', 'DIRECT-toggleBackface'), 'control-f': ('Flash', 'DIRECT-flash'), 'l': ('Toggle lights', 'DIRECT-toggleLigths'), 'shift-l': ('Toggle COA Lock', 'DIRECT-toggleCOALock'), 'p': ('Set Active Parent', 'DIRECT-setActiveParent'), 'r': ('Wrt Reparent', 'DIRECT-doWrtReparent'), 'shift-r': ('Reparent', 'DIRECT-doReparent'), 's': ('Select', 'DIRECT-doSelect'), 't': ('Toggle Textures', 'DIRECT-toggleTexture'), 'shift-a': ('Toggle Vis all', 'DIRECT-toggleVisAll'), 'w': ('Toggle Wireframe', 'DIRECT-toggleWireframe'), 'control-z': ('Undo', 'LE-Undo'), 'shift-z': ('Redo', 'LE-Redo'), 'control-d': ('Duplicate', 'LE-Duplicate'), 'control-l': ('Make Live', 'LE-MakeLive'), 'control-n': ('New Scene', 'LE-NewScene'), 'control-s': ('Save Scene', 'LE-SaveScene'), 'control-o': ('Open Scene', 'LE-OpenScene'), 'control-q': ('Quit', 'LE-Quit') } self.speicalKeyMap = {'enter': 'DIRECT-enter'} self.passThroughKeys = [ 'v', 'b', 'l', 'p', 'r', 'shift-r', 's', 't', 'shift-a', 'w' ] if base.wantTk: from direct.showbase import TkGlobal from direct.tkpanels import DirectSessionPanel self.panel = DirectSessionPanel.DirectSessionPanel(parent=tkroot) try: self.clusterMode = clusterMode except NameError: self.clusterMode = base.config.GetString('cluster-mode', '') if self.clusterMode == 'client': self.cluster = createClusterClient() elif self.clusterMode == 'server': self.cluster = ClusterServer(base.camera, base.cam) else: self.cluster = DummyClusterClient() __builtins__['cluster'] = self.cluster return None def addPassThroughKey(self, key): self.passThroughKeys.append(key) def enable(self): if bboard.has(DirectSession.DIRECTdisablePost): return if self.fEnabled: return self.disable() self.drList.spawnContextTask() if not self.fEnabledLight: self.cameraControl.enableMouseFly() self.manipulationControl.enableManipulation() self.selected.reset() if not self.fEnabledLight: self.enableKeyEvents() self.enableMouseEvents() self.enableActionEvents() self.enableModifierEvents() self.fEnabled = 1 def enableLight(self): self.fEnabledLight = 1 self.enable() def disable(self): self.drList.removeContextTask() self.cameraControl.disableMouseFly() self.deselectAll() self.manipulationControl.disableManipulation() self.disableKeyEvents() self.disableModifierEvents() self.disableMouseEvents() self.disableActionEvents() taskMgr.remove('flashNodePath') taskMgr.remove('hideDirectMessage') taskMgr.remove('hideDirectMessageLater') self.fEnabled = 0 def toggleDirect(self): if self.fEnabled: self.disable() else: self.enable() def minimumConfiguration(self): self.drList.removeContextTask() self.cameraControl.disableMouseFly() self.disableKeyEvents() self.disableActionEvents() self.enableMouseEvents() self.enableModifierEvents() def oobe(self): try: self.oobeMode except: self.oobeMode = 0 self.oobeCamera = hidden.attachNewNode('oobeCamera') self.oobeVis = loader.loadModel('models/misc/camera') if self.oobeVis: self.oobeVis.node().setFinal(1) if self.oobeMode: base.direct.cameraControl.camManipRef.iPosHpr(self.trueCamera) t = self.oobeCamera.lerpPosHpr( Point3(0), Vec3(0), 2.0, other=base.direct.cameraControl.camManipRef, task='manipulateCamera', blendType='easeInOut') t.setUponDeath(self.endOOBE) else: self.oobeVis.reparentTo(self.trueCamera) self.oobeVis.clearMat() cameraParent = self.camera.getParent() self.oobeCamera.reparentTo(cameraParent) self.oobeCamera.iPosHpr(self.trueCamera) self.cam.reparentTo(self.oobeCamera) base.direct.cameraControl.camManipRef.setPos( self.trueCamera, Vec3(-2, -20, 5)) base.direct.cameraControl.camManipRef.lookAt(self.trueCamera) t = self.oobeCamera.lerpPosHpr( Point3(0), Vec3(0), 2.0, other=base.direct.cameraControl.camManipRef, task='manipulateCamera', blendType='easeInOut') t.setUponDeath(self.beginOOBE) def beginOOBE(self, state): self.oobeCamera.iPosHpr(base.direct.cameraControl.camManipRef) base.direct.camera = self.oobeCamera self.oobeMode = 1 def endOOBE(self, state): self.oobeCamera.iPosHpr(self.trueCamera) self.cam.reparentTo(self.trueCamera) base.direct.camera = self.trueCamera self.oobeVis.reparentTo(hidden) self.oobeCamera.reparentTo(hidden) self.oobeMode = 0 def destroy(self): self.disable() def reset(self): self.enable() def enableActionEvents(self): for event in self.actionEvents: self.accept(event[0], event[1], extraArgs=event[2:]) def enableModifierEvents(self): for event in self.modifierEvents: self.accept(event, self.inputHandler, [event]) def enableKeyEvents(self): for event in self.keyEvents: self.accept(event, self.inputHandler, [event]) def enableMouseEvents(self): for event in self.mouseEvents: self.accept(event, self.inputHandler, [event]) def disableActionEvents(self): for event, method in self.actionEvents: self.ignore(event) def disableModifierEvents(self): for event in self.modifierEvents: self.ignore(event) def disableKeyEvents(self): for event in self.keyEvents: self.ignore(event) def disableMouseEvents(self): for event in self.mouseEvents: self.ignore(event) def inputHandler(self, input): if not hasattr(self, 'oobeMode') or self.oobeMode == 0: if base.direct.manipulationControl.fMultiView: if self.fMouse1 and 'mouse1' not in input or self.fMouse2 and 'mouse2' not in input or self.fMouse3 and 'mouse3' not in input: if input.endswith( '-up') or input not in self.modifierEvents: return if self.fMouse1 == 0 and 'mouse1-up' in input or self.fMouse2 == 0 and 'mouse2-up' in input or self.fMouse3 == 0 and 'mouse3-up' in input: return if (self.fMouse1 or self.fMouse2 or self.fMouse3 ) and input[4:7] != base.direct.camera.getName( )[:3] and input.endswith('-up'): return winCtrl = None possibleWinCtrls = [] for cWinCtrl in base.winControls: if cWinCtrl.mouseWatcher.node().hasMouse(): possibleWinCtrls.append(cWinCtrl) if len(possibleWinCtrls) == 1: winCtrl = possibleWinCtrls[0] elif len(possibleWinCtrls) > 1: for cWinCtrl in possibleWinCtrls: if input.endswith( '-up' ) and input not in self.modifierEvents and input not in self.mouseEvents or input in self.mouseEvents: if input[4:7] == cWinCtrl.camera.getName()[:3]: winCtrl = cWinCtrl elif input[4:7] != cWinCtrl.camera.getName()[:3]: winCtrl = cWinCtrl if winCtrl is None: return if input not in self.modifierEvents: self.win = winCtrl.win self.camera = winCtrl.camera self.trueCamera = self.camera self.cam = NodePath(winCtrl.camNode) self.camNode = winCtrl.camNode if hasattr(winCtrl, 'grid'): base.direct.grid = winCtrl.grid base.direct.dr = base.direct.drList[base.camList.index( NodePath(winCtrl.camNode))] base.direct.iRay = base.direct.dr.iRay base.mouseWatcher = winCtrl.mouseWatcher base.mouseWatcherNode = winCtrl.mouseWatcher.node() base.direct.dr.mouseUpdate() LE_showInOneCam(self.selectedNPReadout, self.camera.getName()) base.direct.widget = base.direct.manipulationControl.widgetList[ base.camList.index(NodePath(winCtrl.camNode))] input = input[8:] if self.fAlt and 'alt' not in input and not input.endswith( '-up'): input = 'alt-' + input if input.endswith('-repeat'): input = input[:-7] if input in self.hotKeyMap.keys(): keyDesc = self.hotKeyMap[input] messenger.send(keyDesc[1]) elif input in self.speicalKeyMap.keys(): messenger.send(self.speicalKeyMap[input]) elif input in self.directOnlyKeyMap.keys(): if self.fIgnoreDirectOnlyKeyMap: return keyDesc = self.directOnlyKeyMap[input] messenger.send(keyDesc[1]) elif input == 'mouse1-up': self.fMouse1 = 0 messenger.send('DIRECT-mouse1Up') elif input.find('mouse1') != -1: self.fMouse1 = 1 modifiers = self.getModifiers(input, 'mouse1') messenger.send('DIRECT-mouse1', sentArgs=[modifiers]) elif input == 'mouse2-up': self.fMouse2 = 0 messenger.send('DIRECT-mouse2Up') elif input.find('mouse2') != -1: self.fMouse2 = 1 modifiers = self.getModifiers(input, 'mouse2') messenger.send('DIRECT-mouse2', sentArgs=[modifiers]) elif input == 'mouse3-up': self.fMouse3 = 0 messenger.send('DIRECT-mouse3Up') elif input.find('mouse3') != -1: self.fMouse3 = 1 modifiers = self.getModifiers(input, 'mouse3') messenger.send('DIRECT-mouse3', sentArgs=[modifiers]) elif input == 'shift': self.fShift = 1 elif input == 'shift-up': self.fShift = 0 elif input == 'control': self.fControl = 1 if self.fMouse1: modifiers = DIRECT_NO_MOD modifiers |= DIRECT_CONTROL_MOD messenger.send('DIRECT-mouse1', sentArgs=[modifiers]) elif input == 'control-up': self.fControl = 0 elif input == 'alt': if self.fAlt: return self.fAlt = 1 if self.fMouse1: modifiers = DIRECT_NO_MOD modifiers |= DIRECT_ALT_MOD messenger.send('DIRECT-mouse1', sentArgs=[modifiers]) elif self.fMouse2: modifiers = DIRECT_NO_MOD modifiers |= DIRECT_ALT_MOD messenger.send('DIRECT-mouse2', sentArgs=[modifiers]) elif self.fMouse3: modifiers = DIRECT_NO_MOD modifiers |= DIRECT_ALT_MOD messenger.send('DIRECT-mouse3', sentArgs=[modifiers]) elif input == 'alt-up': self.fAlt = 0 if self.clusterMode == 'client': if input in self.passThroughKeys: self.cluster('messenger.send("%s")' % input, 0) return def doSetActiveParent(self): if self.selected.last: self.setActiveParent(self.selected.last) def doReparent(self): if self.selected.last: self.reparent(self.selected.last) def doWrtReparent(self): if self.selected.last: self.reparent(self.selected.last, fWrt=1) def doSelect(self): if self.selected.last: self.select(self.selected.last) def getModifiers(self, input, base): modifiers = DIRECT_NO_MOD modifierString = input[:input.find(base)] if modifierString.find('shift') != -1: modifiers |= DIRECT_SHIFT_MOD if modifierString.find('control') != -1: modifiers |= DIRECT_CONTROL_MOD if modifierString.find('alt') != -1: modifiers |= DIRECT_ALT_MOD return modifiers def gotShift(self, modifiers): return modifiers & DIRECT_SHIFT_MOD def gotControl(self, modifiers): return modifiers & DIRECT_CONTROL_MOD def gotAlt(self, modifiers): return modifiers & DIRECT_ALT_MOD def setFScaleWidgetByCam(self, flag): self.fScaleWidgetByCam = flag if flag: taskMgr.add(self.widgetResizeTask, 'DIRECTWidgetResize') else: taskMgr.remove('DIRECTWidgetResize') def widgetResizeTask(self, state): if not taskMgr.hasTaskNamed('resizeObjectHandles'): dnp = self.selected.last if dnp: if self.manipulationControl.fMultiView: for i in range(3): sf = 30.0 * direct.drList[i].orthoFactor self.manipulationControl.widgetList[ i].setDirectScalingFactor(sf) nodeCamDist = Vec3(dnp.getPos(base.camList[3])).length() sf = 0.075 * nodeCamDist * math.tan( deg2Rad(direct.drList[3].fovV)) self.manipulationControl.widgetList[ 3].setDirectScalingFactor(sf) else: nodeCamDist = Vec3(dnp.getPos(direct.camera)).length() sf = 0.075 * nodeCamDist * math.tan( deg2Rad(direct.drList.getCurrentDr().fovV)) self.widget.setDirectScalingFactor(sf) return Task.cont def select(self, nodePath, fMultiSelect=0, fSelectTag=1, fResetAncestry=1, fLEPane=0, fUndo=1): messenger.send('DIRECT-select', [ nodePath, fMultiSelect, fSelectTag, fResetAncestry, fLEPane, fUndo ]) def selectCB(self, nodePath, fMultiSelect=0, fSelectTag=1, fResetAncestry=1, fLEPane=0, fUndo=1): dnp = self.selected.select(nodePath, fMultiSelect, fSelectTag) if dnp: messenger.send('DIRECT_preSelectNodePath', [dnp]) if fResetAncestry: self.ancestry = dnp.getAncestors() self.ancestryIndex = 0 self.selectedNPReadout.reparentTo(aspect2d) self.selectedNPReadout.setText('Selected:' + dnp.getName()) if self.manipulationControl.fMultiView: for widget in self.manipulationControl.widgetList: widget.showWidget() else: self.widget.showWidget() editTypes = self.manipulationControl.getEditTypes([dnp]) if editTypes & EDIT_TYPE_UNEDITABLE == EDIT_TYPE_UNEDITABLE: self.manipulationControl.disableWidgetMove() else: self.manipulationControl.enableWidgetMove() mCoa2Camera = dnp.mCoa2Dnp * dnp.getMat(self.camera) row = mCoa2Camera.getRow(3) coa = Vec3(row[0], row[1], row[2]) self.cameraControl.updateCoa(coa) if not self.fScaleWidgetByCam: if self.manipulationControl.fMultiView: for widget in self.manipulationControl.widgetList: widget.setScalingFactor(dnp.getRadius()) else: self.widget.setScalingFactor(dnp.getRadius()) taskMgr.remove('followSelectedNodePath') t = Task.Task(self.followSelectedNodePathTask) t.dnp = dnp taskMgr.add(t, 'followSelectedNodePath') messenger.send('DIRECT_selectedNodePath', [dnp]) messenger.send('DIRECT_selectedNodePath_fMulti_fTag', [dnp, fMultiSelect, fSelectTag]) messenger.send('DIRECT_selectedNodePath_fMulti_fTag_fLEPane', [dnp, fMultiSelect, fSelectTag, fLEPane]) def followSelectedNodePathTask(self, state): mCoa2Render = state.dnp.mCoa2Dnp * state.dnp.getMat(render) decomposeMatrix(mCoa2Render, self.scale, self.hpr, self.pos, CSDefault) self.widget.setPosHpr(self.pos, self.hpr) return Task.cont def deselect(self, nodePath): dnp = self.selected.deselect(nodePath) if dnp: if self.manipulationControl.fMultiView: for widget in self.manipulationControl.widgetList: widget.hideWidget() else: self.widget.hideWidget() self.selectedNPReadout.reparentTo(hidden) self.selectedNPReadout.setText(' ') taskMgr.remove('followSelectedNodePath') self.ancestry = [] messenger.send('DIRECT_deselectedNodePath', [dnp]) def deselectAll(self): messenger.send('DIRECT-preDeselectAll') def deselectAllCB(self): self.selected.deselectAll() if self.manipulationControl.fMultiView: for widget in self.manipulationControl.widgetList: widget.hideWidget() else: self.widget.hideWidget() self.selectedNPReadout.reparentTo(hidden) self.selectedNPReadout.setText(' ') taskMgr.remove('followSelectedNodePath') messenger.send('DIRECT_deselectAll') def setActiveParent(self, nodePath=None): self.activeParent = nodePath self.activeParentReadout.reparentTo(aspect2d) self.activeParentReadout.setText('Active Reparent Target:' + nodePath.getName()) messenger.send('DIRECT_activeParent', [self.activeParent]) def reparent(self, nodePath=None, fWrt=0): if nodePath and self.activeParent and self.isNotCycle( nodePath, self.activeParent): oldParent = nodePath.getParent() if fWrt: nodePath.wrtReparentTo(self.activeParent) else: nodePath.reparentTo(self.activeParent) messenger.send('DIRECT_reparent', [nodePath, oldParent, self.activeParent]) messenger.send('DIRECT_reparent_fWrt', [nodePath, oldParent, self.activeParent, fWrt]) def isNotCycle(self, nodePath, parent): if nodePath.id() == parent.id(): print 'DIRECT.reparent: Invalid parent' return 0 elif parent.hasParent(): return self.isNotCycle(nodePath, parent.getParent()) else: return 1 def flash(self, nodePath='None Given'): taskMgr.remove('flashNodePath') if nodePath == 'None Given': nodePath = self.selected.last if nodePath: if nodePath.hasColor(): doneColor = nodePath.getColor() flashColor = VBase4(1) - doneColor flashColor.setW(1) else: doneColor = None flashColor = VBase4(1, 0, 0, 1) nodePath.setColor(flashColor) t = taskMgr.doMethodLater(DIRECT_FLASH_DURATION, self.flashDummy, 'flashNodePath') t.nodePath = nodePath t.doneColor = doneColor t.setUponDeath(self.flashDone) return def flashDummy(self, state): return Task.done def flashDone(self, state): if state.nodePath.isEmpty(): return if state.doneColor: state.nodePath.setColor(state.doneColor) else: state.nodePath.clearColor() def fitOnNodePath(self, nodePath='None Given'): if nodePath == 'None Given': nodePath = self.selected.last base.direct.select(nodePath) def fitTask(state, self=self): self.cameraControl.fitOnWidget() return Task.done taskMgr.doMethodLater(0.1, fitTask, 'manipulateCamera') def isolate(self, nodePath='None Given'): taskMgr.remove('flashNodePath') if nodePath == 'None Given': nodePath = self.selected.last if nodePath: self.showAllDescendants(nodePath.getParent()) nodePath.hideSiblings() def toggleVis(self, nodePath='None Given'): taskMgr.remove('flashNodePath') if nodePath == 'None Given': nodePath = self.selected.last if nodePath: nodePath.toggleVis() def removeNodePath(self, nodePath='None Given'): if nodePath == 'None Given': nodePath = self.selected.last if nodePath: nodePath.remove() def removeAllSelected(self): self.selected.removeAll() def showAllDescendants(self, nodePath=render): nodePath.showAllDescendants() nodePath.hideCS() def upAncestry(self): if self.ancestry: l = len(self.ancestry) i = self.ancestryIndex + 1 if i < l: np = self.ancestry[i] name = np.getName() if name != 'render' and name != 'renderTop': self.ancestryIndex = i self.select(np, 0, 0) self.flash(np) def downAncestry(self): if self.ancestry: l = len(self.ancestry) i = self.ancestryIndex - 1 if i >= 0: np = self.ancestry[i] name = np.getName() if name != 'render' and name != 'renderTop': self.ancestryIndex = i self.select(np, 0, 0) self.flash(np) def getAndSetName(self, nodePath): from tkSimpleDialog import askstring newName = askstring('Node Path: ' + nodePath.getName(), 'Enter new name:') if newName: nodePath.setName(newName) messenger.send('DIRECT_nodePathSetName', [nodePath, newName]) def pushUndo(self, nodePathList, fResetRedo=1): undoGroup = [] for nodePath in nodePathList: t = nodePath.getTransform() undoGroup.append([nodePath, t]) self.undoList.append(undoGroup) self.undoList = self.undoList[-25:] messenger.send('DIRECT_pushUndo') if fResetRedo and nodePathList != []: self.redoList = [] messenger.send('DIRECT_redoListEmpty') def popUndoGroup(self): undoGroup = self.undoList[-1] self.undoList = self.undoList[:-1] if not self.undoList: messenger.send('DIRECT_undoListEmpty') return undoGroup def pushRedo(self, nodePathList): redoGroup = [] for nodePath in nodePathList: t = nodePath.getTransform() redoGroup.append([nodePath, t]) self.redoList.append(redoGroup) self.redoList = self.redoList[-25:] messenger.send('DIRECT_pushRedo') def popRedoGroup(self): redoGroup = self.redoList[-1] self.redoList = self.redoList[:-1] if not self.redoList: messenger.send('DIRECT_redoListEmpty') return redoGroup def undo(self): if self.undoList: undoGroup = self.popUndoGroup() nodePathList = map(lambda x: x[0], undoGroup) self.pushRedo(nodePathList) for pose in undoGroup: pose[0].setTransform(pose[1]) messenger.send('DIRECT_undo', [nodePathList]) def redo(self): if self.redoList: redoGroup = self.popRedoGroup() nodePathList = map(lambda x: x[0], redoGroup) self.pushUndo(nodePathList, fResetRedo=0) for pose in redoGroup: pose[0].setTransform(pose[1]) messenger.send('DIRECT_redo', [nodePathList]) def message(self, text): taskMgr.remove('hideDirectMessage') taskMgr.remove('hideDirectMessageLater') self.directMessageReadout.reparentTo(aspect2d) self.directMessageReadout.setText(text) self.hideDirectMessageLater() def hideDirectMessageLater(self): taskMgr.doMethodLater(3.0, self.hideDirectMessage, 'hideDirectMessage') def hideDirectMessage(self, state): self.directMessageReadout.reparentTo(hidden) return Task.done def useObjectHandles(self): self.widget = self.manipulationControl.objectHandles self.widget.reparentTo(base.direct.group) def hideSelectedNPReadout(self): self.selectedNPReadout.reparentTo(hidden) def hideActiveParentReadout(self): self.activeParentReadout.reparentTo(hidden) def toggleWidgetVis(self): self.widget.toggleWidget() def setCOAMode(self, mode): self.coaMode = mode def isEnabled(self): return self.fEnabled def addUnpickable(self, item): for iRay in self.iRayList: iRay.addUnpickable(item) def removeUnpickable(self, item): for iRay in self.iRayList: iRay.removeUnpickable(item)
class DirectSession(DirectObject): # post this to the bboard to make sure DIRECT doesn't turn on DIRECTdisablePost = 'disableDIRECT' def __init__(self): # Establish a global pointer to the direct object early on # so dependant classes can access it in their code __builtins__["direct"] = base.direct = self # These come early since they are used later on self.group = render.attachNewNode('DIRECT') self.font = TextNode.getDefaultFont() self.fEnabled = 0 self.fEnabledLight = 0 self.fScaleWidgetByCam = 0 # [gjeon] flag for scaling widget by distance from the camera self.drList = DisplayRegionList() self.iRayList = map(lambda x: x.iRay, self.drList) self.dr = self.drList[0] self.camera = base.camera self.trueCamera = self.camera self.iRay = self.dr.iRay self.coaMode = COA_ORIGIN self.cameraControl = DirectCameraControl() self.manipulationControl = DirectManipulationControl() self.useObjectHandles() self.grid = DirectGrid() self.grid.disable() self.lights = DirectLights(base.direct.group) # Create some default lights self.lights.createDefaultLights() # But turn them off self.lights.allOff() # Initialize the collection of selected nodePaths self.selected = SelectedNodePaths() # Ancestry of currently selected object self.ancestry = [] self.ancestryIndex = 0 self.activeParent = None self.selectedNPReadout = OnscreenText.OnscreenText( pos=(-1.0, -0.9), bg=Vec4(1, 1, 1, 1), scale=0.05, align=TextNode.ALeft, mayChange=1, font=self.font) # Make sure readout is never lit or drawn in wireframe useDirectRenderStyle(self.selectedNPReadout) self.selectedNPReadout.reparentTo(hidden) self.activeParentReadout = OnscreenText.OnscreenText( pos=(-1.0, -0.975), bg=Vec4(1, 1, 1, 1), scale=0.05, align=TextNode.ALeft, mayChange=1, font=self.font) # Make sure readout is never lit or drawn in wireframe useDirectRenderStyle(self.activeParentReadout) self.activeParentReadout.reparentTo(hidden) self.directMessageReadout = OnscreenText.OnscreenText( pos=(-1.0, 0.9), bg=Vec4(1, 1, 1, 1), scale=0.05, align=TextNode.ALeft, mayChange=1, font=self.font) # Make sure readout is never lit or drawn in wireframe useDirectRenderStyle(self.directMessageReadout) self.directMessageReadout.reparentTo(hidden) # Create a vrpn client vrpn-server or default self.deviceManager = None self.joybox = None self.radamec = None self.fastrak = [] if base.config.GetBool('want-vrpn', 0): from panda3d.direct.directdevices import DirectDeviceManager self.deviceManager = DirectDeviceManager.DirectDeviceManager() # Automatically create any devices specified in config file joybox = base.config.GetString('vrpn-joybox-device', '') radamec = base.config.GetString('vrpn-radamec-device', '') fastrak = base.config.GetString('vrpn-fastrak-device', '') if joybox: from panda3d.direct.directdevices import DirectJoybox self.joybox = DirectJoybox.DirectJoybox(joybox) if radamec: from panda3d.direct.directdevices import DirectRadamec self.radamec = DirectRadamec.DirectRadamec(radamec) if fastrak: from panda3d.direct.directdevices import DirectFastrak # parse string into format device:N where N is the sensor name fastrak = string.split(fastrak) for i in range(len(fastrak))[1:]: self.fastrak.append( DirectFastrak.DirectFastrak(fastrak[0] + ':' + fastrak[i])) self.fControl = 0 self.fAlt = 0 self.fShift = 0 self.fMouse1 = 0 # [gjeon] to update alt key information while mouse1 is pressed self.pos = VBase3() self.hpr = VBase3() self.scale = VBase3() self.hitPt = Point3(0.0) # Lists for managing undo/redo operations self.undoList = [] self.redoList = [] # One run through the context task to init everything self.drList.updateContext() for dr in self.drList: dr.camUpdate() self.actionEvents = [ ['select', self.select], ['deselect', self.deselect], ['deselectAll', self.deselectAll], ['highlightAll', self.selected.highlightAll], ['preRemoveNodePath', self.deselect], # Scene graph explorer functions ['SGE_Select', self.select], ['SGE_Deselect', self.deselect], ['SGE_Set Reparent Target', self.setActiveParent], ['SGE_Reparent', self.reparent], ['SGE_WRT Reparent', lambda np, s=self: s.reparent(np, fWrt=1)], ['SGE_Flash', self.flash], ['SGE_Isolate', self.isolate], ['SGE_Toggle Vis', self.toggleVis], ['SGE_Show All', self.showAllDescendants], ['SGE_Fit', self.fitOnNodePath], ['SGE_Place', Placer.place], ['SGE_Set Color', Slider.rgbPanel], ['SGE_Explore', SceneGraphExplorer.explore], ['SGE_Delete', self.removeNodePath], ['SGE_Set Name', self.getAndSetName], ] self.modifierEvents = [ 'control', 'control-up', 'shift', 'shift-up', 'alt', 'alt-up', ] self.keyEvents = [ 'escape', 'delete', 'page_up', 'page_down', '[', '{', ']', '}', 'shift-a', 'b', 'control-f', 'l', 'shift-l', 'o', 'p', 'r', 'shift-r', 's', 't', 'v', 'w' ] self.mouseEvents = [ 'mouse1', 'mouse1-up', 'shift-mouse1', 'shift-mouse1-up', 'control-mouse1', 'control-mouse1-up', 'alt-mouse1', 'alt-mouse1-up', 'mouse2', 'mouse2-up', 'shift-mouse2', 'shift-mouse2-up', 'control-mouse2', 'control-mouse2-up', 'alt-mouse2', 'alt-mouse2-up', 'mouse3', 'mouse3-up', 'shift-mouse3', 'shift-mouse3-up', 'control-mouse3', 'control-mouse3-up', 'alt-mouse3', 'alt-mouse3-up', ] self.passThroughKeys = [ 'v', 'b', 'l', 'p', 'r', 'shift-r', 's', 't', 'shift-a', 'w' ] if base.wantTk: from panda3d.direct.showbase import TkGlobal from panda3d.direct.tkpanels import DirectSessionPanel self.panel = DirectSessionPanel.DirectSessionPanel(parent=tkroot) try: # Has the clusterMode been set externally (i.e. via the # bootstrap application? self.clusterMode = clusterMode except NameError: # Has the clusterMode been set via a config variable? self.clusterMode = base.config.GetString("cluster-mode", '') if self.clusterMode == 'client': self.cluster = createClusterClient() elif self.clusterMode == 'server': self.cluster = ClusterServer(base.camera, base.cam) else: self.cluster = DummyClusterClient() __builtins__['cluster'] = self.cluster def addPassThroughKey(self, key): self.passThroughKeys.append(key) def enable(self): # don't enable DIRECT if someone has posted DIRECTdisablePost if bboard.has(DirectSession.DIRECTdisablePost): return if self.fEnabled: return # Make sure old tasks are shut down self.disable() # Start all display region context tasks self.drList.spawnContextTask() if not self.fEnabledLight: # Turn on mouse Flying self.cameraControl.enableMouseFly() # Turn on object manipulation self.manipulationControl.enableManipulation() # Make sure list of selected items is reset self.selected.reset() # Accept appropriate hooks if not self.fEnabledLight: self.enableKeyEvents() self.enableMouseEvents() self.enableActionEvents() self.enableModifierEvents() # Set flag self.fEnabled = 1 def enableLight(self): self.fEnabledLight = 1 self.enable() def disable(self): # Shut down all display region context tasks self.drList.removeContextTask() # Turn off camera fly self.cameraControl.disableMouseFly() # Turn off object manipulation self.deselectAll() self.manipulationControl.disableManipulation() self.disableKeyEvents() self.disableModifierEvents() self.disableMouseEvents() self.disableActionEvents() # Kill tasks taskMgr.remove('flashNodePath') taskMgr.remove('hideDirectMessage') taskMgr.remove('hideDirectMessageLater') # Set flag self.fEnabled = 0 def toggleDirect(self): if self.fEnabled: self.disable() else: self.enable() def minimumConfiguration(self): # Remove context task self.drList.removeContextTask() # Turn off camera fly self.cameraControl.disableMouseFly() # Ignore keyboard and action events self.disableKeyEvents() self.disableActionEvents() # But let mouse events pass through self.enableMouseEvents() self.enableModifierEvents() def oobe(self): # If oobeMode was never set, set it to false and create the # structures we need to implement OOBE. try: self.oobeMode except: self.oobeMode = 0 self.oobeCamera = hidden.attachNewNode('oobeCamera') self.oobeVis = loader.loadModel('models/misc/camera') if self.oobeVis: self.oobeVis.node().setFinal(1) if self.oobeMode: # Position a target point to lerp the oobe camera to base.direct.cameraControl.camManipRef.iPosHpr(self.trueCamera) t = self.oobeCamera.lerpPosHpr( Point3(0), Vec3(0), 2.0, other=base.direct.cameraControl.camManipRef, task='manipulateCamera', blendType='easeInOut') # When move is done, switch to oobe mode t.setUponDeath(self.endOOBE) else: # Place camera marker at true camera location self.oobeVis.reparentTo(self.trueCamera) # Remove any transformation on the models arc self.oobeVis.clearMat() # Make oobeCamera be a sibling of wherever camera is now. cameraParent = self.camera.getParent() # Prepare oobe camera self.oobeCamera.reparentTo(cameraParent) self.oobeCamera.iPosHpr(self.trueCamera) # Put camera under new oobe camera base.cam.reparentTo(self.oobeCamera) # Position a target point to lerp the oobe camera to base.direct.cameraControl.camManipRef.setPos( self.trueCamera, Vec3(-2, -20, 5)) base.direct.cameraControl.camManipRef.lookAt(self.trueCamera) t = self.oobeCamera.lerpPosHpr( Point3(0), Vec3(0), 2.0, other=base.direct.cameraControl.camManipRef, task='manipulateCamera', blendType='easeInOut') # When move is done, switch to oobe mode t.setUponDeath(self.beginOOBE) def beginOOBE(self, state): # Make sure we've reached our final destination self.oobeCamera.iPosHpr(base.direct.cameraControl.camManipRef) base.direct.camera = self.oobeCamera self.oobeMode = 1 def endOOBE(self, state): # Make sure we've reached our final destination self.oobeCamera.iPosHpr(self.trueCamera) # Disable OOBE mode. base.cam.reparentTo(self.trueCamera) base.direct.camera = self.trueCamera # Get rid of ancillary node paths self.oobeVis.reparentTo(hidden) self.oobeCamera.reparentTo(hidden) self.oobeMode = 0 def destroy(self): self.disable() def reset(self): self.enable() # EVENT FUNCTIONS def enableActionEvents(self): for event in self.actionEvents: self.accept(event[0], event[1], extraArgs=event[2:]) def enableModifierEvents(self): for event in self.modifierEvents: self.accept(event, self.inputHandler, [event]) def enableKeyEvents(self): for event in self.keyEvents: self.accept(event, self.inputHandler, [event]) def enableMouseEvents(self): for event in self.mouseEvents: self.accept(event, self.inputHandler, [event]) def disableActionEvents(self): for event, method in self.actionEvents: self.ignore(event) def disableModifierEvents(self): for event in self.modifierEvents: self.ignore(event) def disableKeyEvents(self): for event in self.keyEvents: self.ignore(event) def disableMouseEvents(self): for event in self.mouseEvents: self.ignore(event) def inputHandler(self, input): # Deal with keyboard and mouse input if input == 'mouse1-up': self.fMouse1 = 0 # [gjeon] to update alt key information while mouse1 is pressed messenger.send('DIRECT-mouse1Up') elif input.find('mouse1') != -1: self.fMouse1 = 1 # [gjeon] to update alt key information while mouse1 is pressed modifiers = self.getModifiers(input, 'mouse1') messenger.send('DIRECT-mouse1', sentArgs=[modifiers]) elif input == 'mouse2-up': messenger.send('DIRECT-mouse2Up') elif input.find('mouse2') != -1: modifiers = self.getModifiers(input, 'mouse2') messenger.send('DIRECT-mouse2', sentArgs=[modifiers]) elif input == 'mouse3-up': messenger.send('DIRECT-mouse3Up') elif input.find('mouse3') != -1: modifiers = self.getModifiers(input, 'mouse3') messenger.send('DIRECT-mouse3', sentArgs=[modifiers]) elif input == 'shift': self.fShift = 1 elif input == 'shift-up': self.fShift = 0 elif input == 'control': self.fControl = 1 # [gjeon] to update control key information while mouse1 is pressed if self.fMouse1: modifiers = DIRECT_NO_MOD modifiers |= DIRECT_CONTROL_MOD messenger.send('DIRECT-mouse1', sentArgs=[modifiers]) elif input == 'control-up': self.fControl = 0 elif input == 'alt': self.fAlt = 1 # [gjeon] to update alt key information while mouse1 is pressed if self.fMouse1: modifiers = DIRECT_NO_MOD modifiers |= DIRECT_ALT_MOD messenger.send('DIRECT-mouse1', sentArgs=[modifiers]) elif input == 'alt-up': self.fAlt = 0 elif input == 'page_up': self.upAncestry() elif input == 'page_down': self.downAncestry() elif input == 'escape': self.deselectAll() elif input == 'delete': self.removeAllSelected() elif input == 'v': self.toggleWidgetVis() elif input == 'b': base.toggleBackface() elif input == 'control-f': self.flash(last) elif input == 'l': self.lights.toggle() elif input == 'shift-l': self.cameraControl.toggleCOALock() elif input == 'o': self.oobe() elif input == 'p': if self.selected.last: self.setActiveParent(self.selected.last) elif input == 'r': # Do wrt reparent if self.selected.last: self.reparent(self.selected.last, fWrt=1) elif input == 'shift-r': # Do regular reparent if self.selected.last: self.reparent(self.selected.last) elif input == 's': if self.selected.last: self.select(self.selected.last) elif input == 't': base.toggleTexture() elif input == 'shift-a': self.selected.toggleVisAll() elif input == 'w': base.toggleWireframe() elif (input == '[') or (input == '{'): self.undo() elif (input == ']') or (input == '}'): self.redo() #Pass along certain events if this display is a cluster client if self.clusterMode == 'client': if input in self.passThroughKeys: self.cluster('messenger.send("%s")' % input, 0) def getModifiers(self, input, base): modifiers = DIRECT_NO_MOD modifierString = input[:input.find(base)] if modifierString.find('shift') != -1: modifiers |= DIRECT_SHIFT_MOD if modifierString.find('control') != -1: modifiers |= DIRECT_CONTROL_MOD if modifierString.find('alt') != -1: modifiers |= DIRECT_ALT_MOD return modifiers def gotShift(self, modifiers): return modifiers & DIRECT_SHIFT_MOD def gotControl(self, modifiers): return modifiers & DIRECT_CONTROL_MOD def gotAlt(self, modifiers): return modifiers & DIRECT_ALT_MOD def setFScaleWidgetByCam(self, flag): self.fScaleWidgetByCam = flag if flag: taskMgr.add(self.widgetResizeTask, 'DIRECTWidgetResize') else: taskMgr.remove('DIRECTWidgetResize') def widgetResizeTask(self, state): if not taskMgr.hasTaskNamed('resizeObjectHandles'): dnp = self.selected.last if dnp: nodeCamDist = Vec3(dnp.getPos(direct.camera)).length() sf = 0.075 * nodeCamDist * math.tan( deg2Rad(direct.drList.getCurrentDr().fovV)) self.widget.setDirectScalingFactor(sf) return Task.cont def select(self, nodePath, fMultiSelect=0, fSelectTag=1, fResetAncestry=1): dnp = self.selected.select(nodePath, fMultiSelect, fSelectTag) if dnp: messenger.send('DIRECT_preSelectNodePath', [dnp]) if fResetAncestry: # Update ancestry self.ancestry = dnp.getAncestors() self.ancestryIndex = 0 # Update the selectedNPReadout self.selectedNPReadout.reparentTo(aspect2d) self.selectedNPReadout.setText('Selected:' + dnp.getName()) # Show the manipulation widget self.widget.showWidget() editTypes = self.manipulationControl.getEditTypes([dnp]) if (editTypes & EDIT_TYPE_UNEDITABLE == EDIT_TYPE_UNEDITABLE): self.manipulationControl.disableWidgetMove() else: self.manipulationControl.enableWidgetMove() # Update camera controls coa to this point # Coa2Camera = Coa2Dnp * Dnp2Camera mCoa2Camera = dnp.mCoa2Dnp * dnp.getMat(self.camera) row = mCoa2Camera.getRow(3) coa = Vec3(row[0], row[1], row[2]) self.cameraControl.updateCoa(coa) # Adjust widgets size # This uses the additional scaling factor used to grow and # shrink the widget if not self.fScaleWidgetByCam: # [gjeon] for not scaling widget by distance from camera self.widget.setScalingFactor(dnp.getRadius()) # Spawn task to have object handles follow the selected object taskMgr.remove('followSelectedNodePath') t = Task.Task(self.followSelectedNodePathTask) t.dnp = dnp taskMgr.add(t, 'followSelectedNodePath') # Send an message marking the event messenger.send('DIRECT_selectedNodePath', [dnp]) messenger.send('DIRECT_selectedNodePath_fMulti_fTag', [dnp, fMultiSelect, fSelectTag]) def followSelectedNodePathTask(self, state): mCoa2Render = state.dnp.mCoa2Dnp * state.dnp.getMat(render) decomposeMatrix(mCoa2Render, self.scale, self.hpr, self.pos, CSDefault) self.widget.setPosHpr(self.pos, self.hpr) return Task.cont def deselect(self, nodePath): dnp = self.selected.deselect(nodePath) if dnp: # Hide the manipulation widget self.widget.hideWidget() self.selectedNPReadout.reparentTo(hidden) self.selectedNPReadout.setText(' ') taskMgr.remove('followSelectedNodePath') self.ancestry = [] # Send an message marking the event messenger.send('DIRECT_deselectedNodePath', [dnp]) def deselectAll(self): self.selected.deselectAll() # Hide the manipulation widget self.widget.hideWidget() self.selectedNPReadout.reparentTo(hidden) self.selectedNPReadout.setText(' ') taskMgr.remove('followSelectedNodePath') def setActiveParent(self, nodePath=None): # Record new parent self.activeParent = nodePath # Update the activeParentReadout self.activeParentReadout.reparentTo(aspect2d) self.activeParentReadout.setText('Active Reparent Target:' + nodePath.getName()) # Alert everyone else messenger.send('DIRECT_activeParent', [self.activeParent]) def reparent(self, nodePath=None, fWrt=0): if (nodePath and self.activeParent and self.isNotCycle(nodePath, self.activeParent)): oldParent = nodePath.getParent() if fWrt: nodePath.wrtReparentTo(self.activeParent) else: nodePath.reparentTo(self.activeParent) # Alert everyone else messenger.send('DIRECT_reparent', [nodePath, oldParent, self.activeParent]) # [gjeon] for others who needs fWrt information messenger.send('DIRECT_reparent_fWrt', [nodePath, oldParent, self.activeParent, fWrt]) def isNotCycle(self, nodePath, parent): if nodePath.id() == parent.id(): print 'DIRECT.reparent: Invalid parent' return 0 elif parent.hasParent(): return self.isNotCycle(nodePath, parent.getParent()) else: return 1 def flash(self, nodePath='None Given'): """ Highlight an object by setting it red for a few seconds """ # Clean up any existing task taskMgr.remove('flashNodePath') # Spawn new task if appropriate if nodePath == 'None Given': # If nothing specified, try selected node path nodePath = self.selected.last if nodePath: if nodePath.hasColor(): doneColor = nodePath.getColor() flashColor = VBase4(1) - doneColor flashColor.setW(1) else: doneColor = None flashColor = VBase4(1, 0, 0, 1) # Temporarily set node path color nodePath.setColor(flashColor) # Clean up color in a few seconds t = taskMgr.doMethodLater( DIRECT_FLASH_DURATION, # This is just a dummy task self.flashDummy, 'flashNodePath', ) t.nodePath = nodePath t.doneColor = doneColor # This really does all the work t.setUponDeath(self.flashDone) def flashDummy(self, state): # Real work is done in upon death function return Task.done def flashDone(self, state): # Return node Path to original state if state.nodePath.isEmpty(): # Node path doesn't exist anymore, bail return if state.doneColor: state.nodePath.setColor(state.doneColor) else: state.nodePath.clearColor() def fitOnNodePath(self, nodePath='None Given'): if nodePath == 'None Given': # If nothing specified, try selected node path nodePath = self.selected.last base.direct.select(nodePath) def fitTask(state, self=self): self.cameraControl.fitOnWidget() return Task.done taskMgr.doMethodLater(0.1, fitTask, 'manipulateCamera') def isolate(self, nodePath='None Given'): """ Show a node path and hide its siblings """ # First kill the flashing task to avoid complications taskMgr.remove('flashNodePath') # Use currently selected node path if node selected if nodePath == 'None Given': nodePath = self.selected.last # Do we have a node path? if nodePath: # Yes, show everything in level self.showAllDescendants(nodePath.getParent()) # Now hide all of this node path's siblings nodePath.hideSiblings() def toggleVis(self, nodePath='None Given'): """ Toggle visibility of node path """ # First kill the flashing task to avoid complications taskMgr.remove('flashNodePath') if nodePath == 'None Given': # If nothing specified, try selected node path nodePath = self.selected.last if nodePath: # Now toggle node path's visibility state nodePath.toggleVis() def removeNodePath(self, nodePath='None Given'): if nodePath == 'None Given': # If nothing specified, try selected node path nodePath = self.selected.last if nodePath: nodePath.remove() def removeAllSelected(self): self.selected.removeAll() def showAllDescendants(self, nodePath=render): """ Show the level and its descendants """ nodePath.showAllDescendants() nodePath.hideCS() def upAncestry(self): if self.ancestry: l = len(self.ancestry) i = self.ancestryIndex + 1 if i < l: np = self.ancestry[i] name = np.getName() if (name != 'render') and (name != 'renderTop'): self.ancestryIndex = i self.select(np, 0, 0) self.flash(np) def downAncestry(self): if self.ancestry: l = len(self.ancestry) i = self.ancestryIndex - 1 if i >= 0: np = self.ancestry[i] name = np.getName() if (name != 'render') and (name != 'renderTop'): self.ancestryIndex = i self.select(np, 0, 0) self.flash(np) def getAndSetName(self, nodePath): """ Prompt user for new node path name """ from tkSimpleDialog import askstring newName = askstring('Node Path: ' + nodePath.getName(), 'Enter new name:') if newName: nodePath.setName(newName) messenger.send('DIRECT_nodePathSetName', [nodePath, newName]) # UNDO REDO FUNCTIONS def pushUndo(self, nodePathList, fResetRedo=1): # Assemble group of changes undoGroup = [] for nodePath in nodePathList: t = nodePath.getTransform() undoGroup.append([nodePath, t]) # Now record group self.undoList.append(undoGroup) # Truncate list self.undoList = self.undoList[-25:] # Alert anyone who cares messenger.send('DIRECT_pushUndo') if fResetRedo and (nodePathList != []): self.redoList = [] messenger.send('DIRECT_redoListEmpty') def popUndoGroup(self): # Get last item undoGroup = self.undoList[-1] # Strip last item off of undo list self.undoList = self.undoList[:-1] # Update state of undo button if not self.undoList: messenger.send('DIRECT_undoListEmpty') # Return last item return undoGroup def pushRedo(self, nodePathList): # Assemble group of changes redoGroup = [] for nodePath in nodePathList: t = nodePath.getTransform() redoGroup.append([nodePath, t]) # Now record redo group self.redoList.append(redoGroup) # Truncate list self.redoList = self.redoList[-25:] # Alert anyone who cares messenger.send('DIRECT_pushRedo') def popRedoGroup(self): # Get last item redoGroup = self.redoList[-1] # Strip last item off of redo list self.redoList = self.redoList[:-1] # Update state of redo button if not self.redoList: messenger.send('DIRECT_redoListEmpty') # Return last item return redoGroup def undo(self): if self.undoList: # Get last item off of redo list undoGroup = self.popUndoGroup() # Record redo information nodePathList = map(lambda x: x[0], undoGroup) self.pushRedo(nodePathList) # Now undo xform for group for pose in undoGroup: # Undo xform pose[0].setTransform(pose[1]) # Alert anyone who cares messenger.send('DIRECT_undo', [nodePathList]) def redo(self): if self.redoList: # Get last item off of redo list redoGroup = self.popRedoGroup() # Record undo information nodePathList = map(lambda x: x[0], redoGroup) self.pushUndo(nodePathList, fResetRedo=0) # Redo xform for pose in redoGroup: pose[0].setTransform(pose[1]) # Alert anyone who cares messenger.send('DIRECT_redo', [nodePathList]) # UTILITY FUNCTIONS def message(self, text): taskMgr.remove('hideDirectMessage') taskMgr.remove('hideDirectMessageLater') self.directMessageReadout.reparentTo(aspect2d) self.directMessageReadout.setText(text) self.hideDirectMessageLater() def hideDirectMessageLater(self): taskMgr.doMethodLater(3.0, self.hideDirectMessage, 'hideDirectMessage') def hideDirectMessage(self, state): self.directMessageReadout.reparentTo(hidden) return Task.done def useObjectHandles(self): self.widget = self.manipulationControl.objectHandles self.widget.reparentTo(base.direct.group) def hideSelectedNPReadout(self): self.selectedNPReadout.reparentTo(hidden) def hideActiveParentReadout(self): self.activeParentReadout.reparentTo(hidden) def toggleWidgetVis(self): self.widget.toggleWidget() def setCOAMode(self, mode): self.coaMode = mode def isEnabled(self): return self.fEnabled def addUnpickable(self, item): for iRay in self.iRayList: iRay.addUnpickable(item) def removeUnpickable(self, item): for iRay in self.iRayList: iRay.removeUnpickable(item)
class DirectSession(DirectObject): # post this to the bboard to make sure DIRECT doesn't turn on DIRECTdisablePost = 'disableDIRECT' def __init__(self): # Establish a global pointer to the direct object early on # so dependant classes can access it in their code __builtins__["direct"] = base.direct = self # These come early since they are used later on self.group = render.attachNewNode('DIRECT') self.font = TextNode.getDefaultFont() self.fEnabled = 0 self.fEnabledLight = 0 self.drList = DisplayRegionList() self.iRayList = map(lambda x: x.iRay, self.drList) self.dr = self.drList[0] self.camera = base.camera self.trueCamera = self.camera self.iRay = self.dr.iRay self.coaMode = COA_ORIGIN self.cameraControl = DirectCameraControl() self.manipulationControl = DirectManipulationControl() self.useObjectHandles() self.grid = DirectGrid() self.grid.disable() self.lights = DirectLights(base.direct.group) # Create some default lights self.lights.createDefaultLights() # But turn them off self.lights.allOff() # Initialize the collection of selected nodePaths self.selected = SelectedNodePaths() # Ancestry of currently selected object self.ancestry = [] self.ancestryIndex = 0 self.activeParent = None self.selectedNPReadout = OnscreenText.OnscreenText( pos = (-1.0, -0.9), bg=Vec4(1, 1, 1, 1), scale = 0.05, align = TextNode.ALeft, mayChange = 1, font = self.font) # Make sure readout is never lit or drawn in wireframe useDirectRenderStyle(self.selectedNPReadout) self.selectedNPReadout.reparentTo(hidden) self.activeParentReadout = OnscreenText.OnscreenText( pos = (-1.0, -0.975), bg=Vec4(1, 1, 1, 1), scale = 0.05, align = TextNode.ALeft, mayChange = 1, font = self.font) # Make sure readout is never lit or drawn in wireframe useDirectRenderStyle(self.activeParentReadout) self.activeParentReadout.reparentTo(hidden) self.directMessageReadout = OnscreenText.OnscreenText( pos = (-1.0, 0.9), bg=Vec4(1, 1, 1, 1), scale = 0.05, align = TextNode.ALeft, mayChange = 1, font = self.font) # Make sure readout is never lit or drawn in wireframe useDirectRenderStyle(self.directMessageReadout) self.directMessageReadout.reparentTo(hidden) # Create a vrpn client vrpn-server or default self.deviceManager = None self.joybox = None self.radamec = None self.fastrak = [] if base.config.GetBool('want-vrpn', 0): from direct.directdevices import DirectDeviceManager self.deviceManager = DirectDeviceManager.DirectDeviceManager() # Automatically create any devices specified in config file joybox = base.config.GetString('vrpn-joybox-device', '') radamec = base.config.GetString('vrpn-radamec-device', '') fastrak = base.config.GetString('vrpn-fastrak-device', '') if joybox: from direct.directdevices import DirectJoybox self.joybox = DirectJoybox.DirectJoybox(joybox) if radamec: from direct.directdevices import DirectRadamec self.radamec = DirectRadamec.DirectRadamec(radamec) if fastrak: from direct.directdevices import DirectFastrak # parse string into format device:N where N is the sensor name fastrak = string.split(fastrak) for i in range(len(fastrak))[1:]: self.fastrak.append(DirectFastrak.DirectFastrak(fastrak[0] + ':' + fastrak[i])) self.fControl = 0 self.fAlt = 0 self.fShift = 0 self.pos = VBase3() self.hpr = VBase3() self.scale = VBase3() self.hitPt = Point3(0.0) # Lists for managing undo/redo operations self.undoList = [] self.redoList = [] # One run through the context task to init everything self.drList.updateContext() for dr in self.drList: dr.camUpdate() self.actionEvents = [ ['select', self.select], ['deselect', self.deselect], ['deselectAll', self.deselectAll], ['highlightAll', self.selected.highlightAll], ['preRemoveNodePath', self.deselect], # Scene graph explorer functions ['SGE_Select', self.select], ['SGE_Deselect', self.deselect], ['SGE_Set Reparent Target', self.setActiveParent], ['SGE_Reparent', self.reparent], ['SGE_WRT Reparent', lambda np, s=self: s.reparent(np, fWrt = 1)], ['SGE_Flash', self.flash], ['SGE_Isolate', self.isolate], ['SGE_Toggle Vis', self.toggleVis], ['SGE_Show All', self.showAllDescendants], ['SGE_Fit', self.fitOnNodePath], ['SGE_Place', Placer.place], ['SGE_Set Color', Slider.rgbPanel], ['SGE_Explore', SceneGraphExplorer.explore], ['SGE_Delete', self.removeNodePath], ['SGE_Set Name', self.getAndSetName], ] self.modifierEvents = ['control', 'control-up', 'shift', 'shift-up', 'alt', 'alt-up', ] self.keyEvents = ['escape', 'delete', 'page_up', 'page_down', '[', '{', ']', '}', 'shift-a', 'b', 'control-f', 'l', 'shift-l', 'o', 'p', 'r', 'shift-r', 's', 't', 'v', 'w'] self.mouseEvents = ['mouse1', 'mouse1-up', 'shift-mouse1', 'shift-mouse1-up', 'control-mouse1', 'control-mouse1-up', 'alt-mouse1', 'alt-mouse1-up', 'mouse2', 'mouse2-up', 'shift-mouse2', 'shift-mouse2-up', 'control-mouse2', 'control-mouse2-up', 'alt-mouse2', 'alt-mouse2-up', 'mouse3', 'mouse3-up', 'shift-mouse3', 'shift-mouse3-up', 'control-mouse3', 'control-mouse3-up', 'alt-mouse3', 'alt-mouse3-up', ] if base.wantTk: from direct.showbase import TkGlobal from direct.tkpanels import DirectSessionPanel self.panel = DirectSessionPanel.DirectSessionPanel(parent = tkroot) try: # Has the clusterMode been set externally (i.e. via the # bootstrap application? self.clusterMode = clusterMode except NameError: # Has the clusterMode been set via a config variable? self.clusterMode = base.config.GetString("cluster-mode", '') if self.clusterMode == 'client': self.cluster = createClusterClient() elif self.clusterMode == 'server': self.cluster = ClusterServer(base.camera, base.cam) else: self.cluster = DummyClusterClient() __builtins__['cluster'] = self.cluster def enable(self): # don't enable DIRECT if someone has posted DIRECTdisablePost if bboard.has(DirectSession.DIRECTdisablePost): return if self.fEnabled: return # Make sure old tasks are shut down self.disable() # Start all display region context tasks self.drList.spawnContextTask() if not self.fEnabledLight: # Turn on mouse Flying self.cameraControl.enableMouseFly() # Turn on object manipulation self.manipulationControl.enableManipulation() # Make sure list of selected items is reset self.selected.reset() # Accept appropriate hooks if not self.fEnabledLight: self.enableKeyEvents() self.enableMouseEvents() self.enableActionEvents() self.enableModifierEvents() # Set flag self.fEnabled = 1 def enableLight(self): self.fEnabledLight = 1 self.enable() def disable(self): # Shut down all display region context tasks self.drList.removeContextTask() # Turn off camera fly self.cameraControl.disableMouseFly() # Turn off object manipulation self.deselectAll() self.manipulationControl.disableManipulation() self.disableKeyEvents() self.disableModifierEvents() self.disableMouseEvents() self.disableActionEvents() # Kill tasks taskMgr.remove('flashNodePath') taskMgr.remove('hideDirectMessage') taskMgr.remove('hideDirectMessageLater') # Set flag self.fEnabled = 0 def toggleDirect(self): if self.fEnabled: self.disable() else: self.enable() def minimumConfiguration(self): # Remove context task self.drList.removeContextTask() # Turn off camera fly self.cameraControl.disableMouseFly() # Ignore keyboard and action events self.disableKeyEvents() self.disableActionEvents() # But let mouse events pass through self.enableMouseEvents() self.enableModifierEvents() def oobe(self): # If oobeMode was never set, set it to false and create the # structures we need to implement OOBE. try: self.oobeMode except: self.oobeMode = 0 self.oobeCamera = hidden.attachNewNode('oobeCamera') self.oobeVis = loader.loadModelOnce('models/misc/camera') if self.oobeVis: self.oobeVis.node().setFinal(1) if self.oobeMode: # Position a target point to lerp the oobe camera to base.direct.cameraControl.camManipRef.iPosHpr(self.trueCamera) t = self.oobeCamera.lerpPosHpr( Point3(0), Vec3(0), 2.0, other = base.direct.cameraControl.camManipRef, task = 'manipulateCamera', blendType = 'easeInOut') # When move is done, switch to oobe mode t.uponDeath = self.endOOBE else: # Place camera marker at true camera location self.oobeVis.reparentTo(self.trueCamera) # Remove any transformation on the models arc self.oobeVis.clearMat() # Make oobeCamera be a sibling of wherever camera is now. cameraParent = self.camera.getParent() # Prepare oobe camera self.oobeCamera.reparentTo(cameraParent) self.oobeCamera.iPosHpr(self.trueCamera) # Put camera under new oobe camera base.cam.reparentTo(self.oobeCamera) # Position a target point to lerp the oobe camera to base.direct.cameraControl.camManipRef.setPos( self.trueCamera, Vec3(-2, -20, 5)) base.direct.cameraControl.camManipRef.lookAt(self.trueCamera) t = self.oobeCamera.lerpPosHpr( Point3(0), Vec3(0), 2.0, other = base.direct.cameraControl.camManipRef, task = 'manipulateCamera', blendType = 'easeInOut') # When move is done, switch to oobe mode t.uponDeath = self.beginOOBE def beginOOBE(self, state): # Make sure we've reached our final destination self.oobeCamera.iPosHpr(base.direct.cameraControl.camManipRef) base.direct.camera = self.oobeCamera self.oobeMode = 1 def endOOBE(self, state): # Make sure we've reached our final destination self.oobeCamera.iPosHpr(self.trueCamera) # Disable OOBE mode. base.cam.reparentTo(self.trueCamera) base.direct.camera = self.trueCamera # Get rid of ancillary node paths self.oobeVis.reparentTo(hidden) self.oobeCamera.reparentTo(hidden) self.oobeMode = 0 def destroy(self): self.disable() def reset(self): self.enable() # EVENT FUNCTIONS def enableActionEvents(self): for event in self.actionEvents: self.accept(event[0], event[1], extraArgs = event[2:]) def enableModifierEvents(self): for event in self.modifierEvents: self.accept(event, self.inputHandler, [event]) def enableKeyEvents(self): for event in self.keyEvents: self.accept(event, self.inputHandler, [event]) def enableMouseEvents(self): for event in self.mouseEvents: self.accept(event, self.inputHandler, [event]) def disableActionEvents(self): for event, method in self.actionEvents: self.ignore(event) def disableModifierEvents(self): for event in self.modifierEvents: self.ignore(event) def disableKeyEvents(self): for event in self.keyEvents: self.ignore(event) def disableMouseEvents(self): for event in self.mouseEvents: self.ignore(event) def inputHandler(self, input): # Deal with keyboard and mouse input if input == 'mouse1-up': messenger.send('DIRECT-mouse1Up') elif input.find('mouse1') != -1: modifiers = self.getModifiers(input, 'mouse1') messenger.send('DIRECT-mouse1', sentArgs = [modifiers]) elif input == 'mouse2-up': messenger.send('DIRECT-mouse2Up') elif input.find('mouse2') != -1: modifiers = self.getModifiers(input, 'mouse2') messenger.send('DIRECT-mouse2', sentArgs = [modifiers]) elif input == 'mouse3-up': messenger.send('DIRECT-mouse3Up') elif input.find('mouse3') != -1: modifiers = self.getModifiers(input, 'mouse3') messenger.send('DIRECT-mouse3', sentArgs = [modifiers]) elif input == 'shift': self.fShift = 1 elif input == 'shift-up': self.fShift = 0 elif input == 'control': self.fControl = 1 elif input == 'control-up': self.fControl = 0 elif input == 'alt': self.fAlt = 1 elif input == 'alt-up': self.fAlt = 0 elif input == 'page_up': self.upAncestry() elif input == 'page_down': self.downAncestry() elif input == 'escape': self.deselectAll() elif input == 'delete': self.removeAllSelected() elif input == 'v': self.toggleWidgetVis() elif input == 'b': base.toggleBackface() elif input == 'control-f': self.flash(last) elif input == 'l': self.lights.toggle() elif input == 'shift-l': self.cameraControl.toggleCOALock() elif input == 'o': self.oobe() elif input == 'p': if self.selected.last: self.setActiveParent(self.selected.last) elif input == 'r': # Do wrt reparent if self.selected.last: self.reparent(self.selected.last, fWrt = 1) elif input == 'shift-r': # Do regular reparent if self.selected.last: self.reparent(self.selected.last) elif input == 's': if self.selected.last: self.select(self.selected.last) elif input == 't': base.toggleTexture() elif input == 'shift-a': self.selected.toggleVisAll() elif input == 'w': base.toggleWireframe() elif (input == '[') or (input == '{'): self.undo() elif (input == ']') or (input == '}'): self.redo() #Pass along certain events if this display is a cluster client if self.clusterMode == 'client': if input in ('v','b','l','p', 'r', 'shift-r', 's', 't', 'shift-a', 'w'): self.cluster('messenger.send("%s")' % input, 0) def getModifiers(self, input, base): modifiers = DIRECT_NO_MOD modifierString = input[: input.find(base)] if modifierString.find('shift') != -1: modifiers |= DIRECT_SHIFT_MOD if modifierString.find('control') != -1: modifiers |= DIRECT_CONTROL_MOD if modifierString.find('alt') != -1: modifiers |= DIRECT_ALT_MOD return modifiers def gotShift(self, modifiers): return modifiers & DIRECT_SHIFT_MOD def gotControl(self, modifiers): return modifiers & DIRECT_CONTROL_MOD def gotAlt(self, modifiers): return modifiers & DIRECT_ALT_MOD def select(self, nodePath, fMultiSelect = 0, fSelectTag = 1, fResetAncestry = 1): dnp = self.selected.select(nodePath, fMultiSelect, fSelectTag) if dnp: messenger.send('DIRECT_preSelectNodePath', [dnp]) if fResetAncestry: # Update ancestry self.ancestry = dnp.getAncestry() self.ancestry.reverse() self.ancestryIndex = 0 # Update the selectedNPReadout self.selectedNPReadout.reparentTo(aspect2d) self.selectedNPReadout.setText( 'Selected:' + dnp.getName()) # Show the manipulation widget self.widget.showWidget() # Update camera controls coa to this point # Coa2Camera = Coa2Dnp * Dnp2Camera mCoa2Camera = dnp.mCoa2Dnp * dnp.getMat(self.camera) row = mCoa2Camera.getRow(3) coa = Vec3(row[0], row[1], row[2]) self.cameraControl.updateCoa(coa) # Adjust widgets size # This uses the additional scaling factor used to grow and # shrink the widget self.widget.setScalingFactor(dnp.getRadius()) # Spawn task to have object handles follow the selected object taskMgr.remove('followSelectedNodePath') t = Task.Task(self.followSelectedNodePathTask) t.dnp = dnp taskMgr.add(t, 'followSelectedNodePath') # Send an message marking the event messenger.send('DIRECT_selectedNodePath', [dnp]) def followSelectedNodePathTask(self, state): mCoa2Render = state.dnp.mCoa2Dnp * state.dnp.getMat(render) decomposeMatrix(mCoa2Render, self.scale, self.hpr, self.pos, CSDefault) self.widget.setPosHpr(self.pos, self.hpr) return Task.cont def deselect(self, nodePath): dnp = self.selected.deselect(nodePath) if dnp: # Hide the manipulation widget self.widget.hideWidget() self.selectedNPReadout.reparentTo(hidden) self.selectedNPReadout.setText(' ') taskMgr.remove('followSelectedNodePath') self.ancestry = [] # Send an message marking the event messenger.send('DIRECT_deselectedNodePath', [dnp]) def deselectAll(self): self.selected.deselectAll() # Hide the manipulation widget self.widget.hideWidget() self.selectedNPReadout.reparentTo(hidden) self.selectedNPReadout.setText(' ') taskMgr.remove('followSelectedNodePath') def setActiveParent(self, nodePath = None): # Record new parent self.activeParent = nodePath # Update the activeParentReadout self.activeParentReadout.reparentTo(aspect2d) self.activeParentReadout.setText( 'Active Reparent Target:' + nodePath.getName()) # Alert everyone else messenger.send('DIRECT_activeParent', [self.activeParent]) def reparent(self, nodePath = None, fWrt = 0): if (nodePath and self.activeParent and self.isNotCycle(nodePath, self.activeParent)): oldParent = nodePath.getParent() if fWrt: nodePath.wrtReparentTo(self.activeParent) else: nodePath.reparentTo(self.activeParent) # Alert everyone else messenger.send('DIRECT_reparent', [nodePath, oldParent, self.activeParent]) def isNotCycle(self, nodePath, parent): if nodePath.id() == parent.id(): print 'DIRECT.reparent: Invalid parent' return 0 elif parent.hasParent(): return self.isNotCycle(nodePath, parent.getParent()) else: return 1 def flash(self, nodePath = 'None Given'): """ Highlight an object by setting it red for a few seconds """ # Clean up any existing task taskMgr.remove('flashNodePath') # Spawn new task if appropriate if nodePath == 'None Given': # If nothing specified, try selected node path nodePath = self.selected.last if nodePath: if nodePath.hasColor(): doneColor = nodePath.getColor() flashColor = VBase4(1) - doneColor flashColor.setW(1) else: doneColor = None flashColor = VBase4(1, 0, 0, 1) # Temporarily set node path color nodePath.setColor(flashColor) # Clean up color in a few seconds t = taskMgr.doMethodLater(DIRECT_FLASH_DURATION, # This is just a dummy task self.flashDummy, 'flashNodePath') t.nodePath = nodePath t.doneColor = doneColor # This really does all the work t.uponDeath = self.flashDone def flashDummy(self, state): # Real work is done in upon death function return Task.done def flashDone(self, state): # Return node Path to original state if state.nodePath.isEmpty(): # Node path doesn't exist anymore, bail return if state.doneColor: state.nodePath.setColor(state.doneColor) else: state.nodePath.clearColor() def fitOnNodePath(self, nodePath = 'None Given'): if nodePath == 'None Given': # If nothing specified, try selected node path nodePath = self.selected.last base.direct.select(nodePath) def fitTask(state, self = self): self.cameraControl.fitOnWidget() return Task.done taskMgr.doMethodLater(0.1, fitTask, 'manipulateCamera') def isolate(self, nodePath = 'None Given'): """ Show a node path and hide its siblings """ # First kill the flashing task to avoid complications taskMgr.remove('flashNodePath') # Use currently selected node path if node selected if nodePath == 'None Given': nodePath = self.selected.last # Do we have a node path? if nodePath: # Yes, show everything in level self.showAllDescendants(nodePath.getParent()) # Now hide all of this node path's siblings nodePath.hideSiblings() def toggleVis(self, nodePath = 'None Given'): """ Toggle visibility of node path """ # First kill the flashing task to avoid complications taskMgr.remove('flashNodePath') if nodePath == 'None Given': # If nothing specified, try selected node path nodePath = self.selected.last if nodePath: # Now toggle node path's visibility state nodePath.toggleVis() def removeNodePath(self, nodePath = 'None Given'): if nodePath == 'None Given': # If nothing specified, try selected node path nodePath = self.selected.last if nodePath: nodePath.remove() def removeAllSelected(self): self.selected.removeAll() def showAllDescendants(self, nodePath = render): """ Show the level and its descendants """ nodePath.showAllDescendants() nodePath.hideCS() def upAncestry(self): if self.ancestry: l = len(self.ancestry) i = self.ancestryIndex + 1 if i < l: np = self.ancestry[i] name = np.getName() if (name != 'render') and (name != 'renderTop'): self.ancestryIndex = i self.select(np, 0, 0) self.flash(np) def downAncestry(self): if self.ancestry: l = len(self.ancestry) i = self.ancestryIndex - 1 if i >= 0: np = self.ancestry[i] name = np.getName() if (name != 'render') and (name != 'renderTop'): self.ancestryIndex = i self.select(np, 0, 0) self.flash(np) def getAndSetName(self, nodePath): """ Prompt user for new node path name """ from tkSimpleDialog import askstring newName = askstring('Node Path: ' + nodePath.getName(), 'Enter new name:') if newName: nodePath.setName(newName) messenger.send('DIRECT_nodePathSetName', [nodePath, newName]) # UNDO REDO FUNCTIONS def pushUndo(self, nodePathList, fResetRedo = 1): # Assemble group of changes undoGroup = [] for nodePath in nodePathList: t = nodePath.getTransform() undoGroup.append([nodePath, t]) # Now record group self.undoList.append(undoGroup) # Truncate list self.undoList = self.undoList[-25:] # Alert anyone who cares messenger.send('DIRECT_pushUndo') if fResetRedo and (nodePathList != []): self.redoList = [] messenger.send('DIRECT_redoListEmpty') def popUndoGroup(self): # Get last item undoGroup = self.undoList[-1] # Strip last item off of undo list self.undoList = self.undoList[:-1] # Update state of undo button if not self.undoList: messenger.send('DIRECT_undoListEmpty') # Return last item return undoGroup def pushRedo(self, nodePathList): # Assemble group of changes redoGroup = [] for nodePath in nodePathList: t = nodePath.getTransform() redoGroup.append([nodePath, t]) # Now record redo group self.redoList.append(redoGroup) # Truncate list self.redoList = self.redoList[-25:] # Alert anyone who cares messenger.send('DIRECT_pushRedo') def popRedoGroup(self): # Get last item redoGroup = self.redoList[-1] # Strip last item off of redo list self.redoList = self.redoList[:-1] # Update state of redo button if not self.redoList: messenger.send('DIRECT_redoListEmpty') # Return last item return redoGroup def undo(self): if self.undoList: # Get last item off of redo list undoGroup = self.popUndoGroup() # Record redo information nodePathList = map(lambda x: x[0], undoGroup) self.pushRedo(nodePathList) # Now undo xform for group for pose in undoGroup: # Undo xform pose[0].setTransform(pose[1]) # Alert anyone who cares messenger.send('DIRECT_undo', [nodePathList]) def redo(self): if self.redoList: # Get last item off of redo list redoGroup = self.popRedoGroup() # Record undo information nodePathList = map(lambda x: x[0], redoGroup) self.pushUndo(nodePathList, fResetRedo = 0) # Redo xform for pose in redoGroup: pose[0].setTransform(pose[1]) # Alert anyone who cares messenger.send('DIRECT_redo', [nodePathList]) # UTILITY FUNCTIONS def message(self, text): taskMgr.remove('hideDirectMessage') taskMgr.remove('hideDirectMessageLater') self.directMessageReadout.reparentTo(aspect2d) self.directMessageReadout.setText(text) self.hideDirectMessageLater() def hideDirectMessageLater(self): taskMgr.doMethodLater(3.0, self.hideDirectMessage, 'hideDirectMessage') def hideDirectMessage(self, state): self.directMessageReadout.reparentTo(hidden) return Task.done def useObjectHandles(self): self.widget = self.manipulationControl.objectHandles self.widget.reparentTo(base.direct.group) def hideSelectedNPReadout(self): self.selectedNPReadout.reparentTo(hidden) def hideActiveParentReadout(self): self.activeParentReadout.reparentTo(hidden) def toggleWidgetVis(self): self.widget.toggleWidget() def setCOAMode(self, mode): self.coaMode = mode def isEnabled(self): return self.fEnabled def addUnpickable(self, item): for iRay in self.iRayList: iRay.addUnpickable(item) def removeUnpickable(self, item): for iRay in self.iRayList: iRay.removeUnpickable(item)