diff --git a/direct/src/directdevices/DirectJoybox.py b/direct/src/directdevices/DirectJoybox.py index ace0c72ab6..476a4d1091 100644 --- a/direct/src/directdevices/DirectJoybox.py +++ b/direct/src/directdevices/DirectJoybox.py @@ -40,9 +40,7 @@ class DirectJoybox(PandaObject): # Get buttons and analogs self.device = device self.analogs = direct.deviceManager.createAnalogs(self.device) - print 'NUM ANALOGS', len(self.analogs) self.buttons = direct.deviceManager.createButtons(self.device) - print 'NUM BUTTONS', len(self.buttons) self.aList = [0,0,0,0,0,0,0,0] self.bList = [0,0,0,0,0,0,0,0] # For joybox fly mode diff --git a/direct/src/directtools/DirectCameraControl.py b/direct/src/directtools/DirectCameraControl.py index f29a79c88e..a46ee2b4b7 100644 --- a/direct/src/directtools/DirectCameraControl.py +++ b/direct/src/directtools/DirectCameraControl.py @@ -95,7 +95,8 @@ class DirectCameraControl(PandaObject): # Allow intersection with unpickable objects # And then spawn task to determine mouse mode node, hitPt, hitPtDist = direct.iRay.pickGeom( - fIntersectUnpickable = 1, fIgnoreCamera = 1) + fIntersectUnpickable = 1, + fIgnoreCamera = 1 - base.getControl()) self.computeCOA(node, hitPt, hitPtDist) # Record reference point self.coaMarkerRef.iPosHprScale(direct.iRay.collisionRef) @@ -290,7 +291,7 @@ class DirectCameraControl(PandaObject): # Filter out object's under camera node = entry.getIntoNode() nodePath = render.findPathDownTo(node) - if camera not in nodePath.getAncestry(): + if direct.camera not in nodePath.getAncestry(): # Compute hit point # KEH: use current display region ray # hitPt = direct.iRay.parentToHitPt(entry) @@ -398,7 +399,7 @@ class DirectCameraControl(PandaObject): # Record undo point direct.pushUndo([direct.camera]) # Transform camera z axis to render space - mCam2Render = camera.getMat(render) + mCam2Render = direct.camera.getMat(render) zAxis = Vec3(mCam2Render.xformVec(Z_AXIS)) zAxis.normalize() # Compute rotation angle needed to upright cam diff --git a/direct/src/directtools/DirectGeometry.py b/direct/src/directtools/DirectGeometry.py index 8f53cdec8d..6403139133 100644 --- a/direct/src/directtools/DirectGeometry.py +++ b/direct/src/directtools/DirectGeometry.py @@ -13,7 +13,8 @@ UNIT_VEC = Vec3(1) ZERO_POINT = Point3(0) class LineNodePath(NodePath): - def __init__(self, parent = None, **kw): + def __init__(self, parent = None, name = None, + thickness = 1.0, colorVec = VBase4(1)): # Initialize the superclass NodePath.__init__(self) @@ -25,12 +26,14 @@ class LineNodePath(NodePath): # the resulting node path self.lineNode = GeomNode() self.assign(parent.attachNewNode( self.lineNode )) + if name: + self.setName(name) # Create a lineSegs object to hold the line ls = self.lineSegs = LineSegs() # Initialize the lineSegs parameters - ls.setThickness( kw.get('thickness', 1.0) ) - ls.setColor( kw.get('colorVec', VBase4(1.0)) ) + ls.setThickness(thickness) + ls.setColor(colorVec) def moveTo( self, *_args ): apply( self.lineSegs.moveTo, _args ) @@ -95,7 +98,15 @@ class LineNodePath(NodePath): self.drawTo(Point3(ev + Point3(a1x, a1y, z))) self.moveTo(ev) self.drawTo(Point3(ev + Point3(a2x, a2y, z))) - + + def drawLines(self, lineList): + """ + Given a list of lists of points, draw a separate line for each list + """ + for pointList in lineList: + apply(self.moveTo, pointList[0]) + for point in pointList[1:]: + apply(self.drawTo, point) ## ## Given a point in space, and a direction, find the point of intersection diff --git a/direct/src/directtools/DirectManipulation.py b/direct/src/directtools/DirectManipulation.py index 6d235223d2..1791a2a214 100644 --- a/direct/src/directtools/DirectManipulation.py +++ b/direct/src/directtools/DirectManipulation.py @@ -87,7 +87,12 @@ class DirectManipulationControl(PandaObject): # depending on flag..... if self.mode == 'select': # Check for object under mouse - node, hitPt, hitPtDist = direct.iRay.pickGeom() + if direct.fControl: + node, hitPt, hitPtDist = direct.iRay.pickGeom( + fIgnoreCamera = 0) + else: + node, hitPt, hitPtDist = direct.iRay.pickGeom( + fIgnoreCamera = 1) if node: # Record hit point information self.hitPt.assign(hitPt) diff --git a/direct/src/directtools/DirectSelection.py b/direct/src/directtools/DirectSelection.py index 141bb66f89..de2892be04 100644 --- a/direct/src/directtools/DirectSelection.py +++ b/direct/src/directtools/DirectSelection.py @@ -432,7 +432,7 @@ class SelectionRay: # Don't pick hidden nodes if node.isHidden(): pass - elif fIgnoreCamera and (camera in nodePath.getAncestry()): + elif fIgnoreCamera and (direct.camera in nodePath.getAncestry()): # This avoids things parented to a camera. Good idea? pass # Can pick unpickable, use the first visible node diff --git a/direct/src/directtools/DirectSession.py b/direct/src/directtools/DirectSession.py index c9ec5718fa..372569d566 100644 --- a/direct/src/directtools/DirectSession.py +++ b/direct/src/directtools/DirectSession.py @@ -42,6 +42,7 @@ class DirectSession(PandaObject): self.iRayList = map(lambda x: x.iRay, self.drList) self.dr = self.drList[0] self.camera = base.cameraList[0] + self.trueCamera = self.camera self.iRay = self.dr.iRay self.cameraControl = DirectCameraControl() @@ -157,7 +158,7 @@ class DirectSession(PandaObject): 'shift', 'shift-up', 'alt', 'alt-up', 'page_up', 'page_down', '[', '{', ']', '}', - 'A', 'b', 'l', 'L', 'p', 'r', 'R', 's', + 'A', 'b', 'l', 'L', 'o', 'p', 'r', 'R', 's', 't', 'v', 'w'] self.mouseEvents = ['mouse1', 'mouse1-up', 'mouse2', 'mouse2-up', @@ -224,6 +225,72 @@ class DirectSession(PandaObject): # But let mouse events pass through self.enableMouseEvents() + 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.arc().setFinal(1) + + if self.oobeMode: + # Position a target point to lerp the oobe camera to + direct.cameraControl.camManipRef.iPosHpr(self.trueCamera) + t = self.oobeCamera.lerpPosHpr( + Point3(0), Vec3(0), 2.0, + other = 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 = NodePath(self.camera) + cameraParent.shorten(1) + # 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 + direct.cameraControl.camManipRef.setPos( + self.trueCamera, Vec3(-2,-20, 5)) + direct.cameraControl.camManipRef.lookAt(self.trueCamera) + t = self.oobeCamera.lerpPosHpr( + Point3(0), Vec3(0), 2.0, + other = 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(direct.cameraControl.camManipRef) + 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) + 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() @@ -297,6 +364,8 @@ class DirectSession(PandaObject): self.lights.toggle() elif input == 'L': self.cameraControl.toggleCOALock() + elif input == 'o': + self.oobe() elif input == 'p': if self.selected.last: self.setActiveParent(self.selected.last) diff --git a/direct/src/extensions/NodePath-extensions.py b/direct/src/extensions/NodePath-extensions.py index 36355da0f1..dc18fa6f44 100644 --- a/direct/src/extensions/NodePath-extensions.py +++ b/direct/src/extensions/NodePath-extensions.py @@ -53,8 +53,10 @@ """Toggles visibility of a nodePath""" if self.isHidden(): self.show() + return 1 else: self.hide() + return 0 def showSiblings(self): """Show all the siblings of a node path""" @@ -110,6 +112,13 @@ else: return [self] + def getTightBounds(self): + from PandaObject import * + v1 = Point3(0) + v2 = Point3(0) + self.calcTightBounds(v1,v2) + return v1, v2 + def pprintPos(self, other = None, sd = 2): """ Pretty print a node path's pos """ from PandaObject import * diff --git a/direct/src/gui/DirectGuiBase.py b/direct/src/gui/DirectGuiBase.py index dbb34f4939..89591570cd 100644 --- a/direct/src/gui/DirectGuiBase.py +++ b/direct/src/gui/DirectGuiBase.py @@ -611,7 +611,7 @@ class DirectGuiBase(PandaObject.PandaObject): del(self._hookDict) del(self.__componentInfo) - def bind(self, event, command): + def bind(self, event, command, extraArgs = []): """ Bind the command (which should expect one arg) to the specified event (such as ENTER, EXIT, B1PRESS, B1CLICK, etc.) @@ -619,7 +619,7 @@ class DirectGuiBase(PandaObject.PandaObject): """ # Need to tack on gui item specific id gEvent = event + self.guiId - self.accept(gEvent, command) + self.accept(gEvent, command, extraArgs = extraArgs) # Keep track of all events you're accepting self._hookDict[gEvent] = command @@ -679,13 +679,17 @@ class DirectGuiWidget(DirectGuiBase, NodePath): ('borderWidth', (.1,.1), self.setBorderWidth), ('frameSize', None, self.setFrameSize), ('frameColor', (.8,.8,.8,1), self.setFrameColor), - ('pad', (0,0), self.resetFrameSize), + ('pad', (0,0), self.resetFrameSize), # Override button id (beware! your name may not be unique!) ('guiId', None, INITOPT), # Initial pos/scale of the widget ('pos', None, INITOPT), ('scale', None, INITOPT), ('color', None, INITOPT), + # Do events pass through this widget? + ('suppressMouse', 1, INITOPT), + ('suppressKeys', 0, INITOPT), + ('enableEdit', 1, INITOPT), ) # Merge keyword options with default options self.defineoptions(kw, optiondefs) @@ -740,9 +744,18 @@ class DirectGuiWidget(DirectGuiBase, NodePath): self.ur = Point3(0) # Is drag and drop enabled? - if self.guiEdit: + if self['enableEdit'] and self.guiEdit: self.enableEdit() + # Set up event handling + suppressFlags = 0 + if self['suppressMouse']: + suppressFlags |= MouseWatcherRegion.SFMouseButton + suppressFlags |= MouseWatcherRegion.SFMousePosition + if self['suppressKeys']: + suppressFlags |= MouseWatcherRegion.SFOtherButton + self.guiItem.setSuppressFlags(suppressFlags) + # Bind destroy hook self.bind(DESTROY, self.destroy) @@ -759,17 +772,19 @@ class DirectGuiWidget(DirectGuiBase, NodePath): self.bind(B2PRESS, self.editStart) self.bind(B2RELEASE, self.editStop) self.bind(PRINT, self.printConfig) - mb = base.mouseWatcherNode.getModifierButtons() - mb.addButton(KeyboardButton.control()) - base.mouseWatcherNode.setModifierButtons(mb) + # Can we move this to showbase + # Certainly we don't need to do this for every button! + #mb = base.mouseWatcherNode.getModifierButtons() + #mb.addButton(KeyboardButton.control()) + #base.mouseWatcherNode.setModifierButtons(mb) def disableEdit(self): self.unbind(B2PRESS) self.unbind(B2RELEASE) self.unbind(PRINT) - mb = base.mouseWatcherNode.getModifierButtons() - mb.removeButton(KeyboardButton.control()) - base.mouseWatcherNode.setModifierButtons(mb) + #mb = base.mouseWatcherNode.getModifierButtons() + #mb.removeButton(KeyboardButton.control()) + #base.mouseWatcherNode.setModifierButtons(mb) def editStart(self, event): taskMgr.removeTasksNamed('guiEditTask') diff --git a/direct/src/gui/OnscreenGeom.py b/direct/src/gui/OnscreenGeom.py index d021b41690..d8580bd489 100644 --- a/direct/src/gui/OnscreenGeom.py +++ b/direct/src/gui/OnscreenGeom.py @@ -40,6 +40,7 @@ class OnscreenGeom(PandaObject, NodePath): """ # We ARE a node path. Initially, we're an empty node path. NodePath.__init__(self) + self.parent = parent # Assign geometry self.sort = sort if isinstance(geom, NodePath): @@ -81,10 +82,10 @@ class OnscreenGeom(PandaObject, NodePath): self.removeNode() # Assign geometry if isinstance(geom, NodePath): - self.assign(geom.copyTo(parent)) + self.assign(geom.copyTo(self.parent)) elif type(geom) == type(''): self.assign(loader.loadModelCopy(geom)) - self.reparentTo(parent) + self.reparentTo(self.parent) def getGeom(self): return self diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index d9a30c59b8..087147d726 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -152,6 +152,11 @@ class ShowBase: self.mak = self.dataRoot.attachNewNode(MouseAndKeyboard(self.win, 0, 'mak')) self.mouseWatcherNode = MouseWatcher('mouseWatcher') self.mouseWatcher = self.mak.attachNewNode(self.mouseWatcherNode) + mb = self.mouseWatcherNode.getModifierButtons() + mb.addButton(KeyboardButton.shift()) + mb.addButton(KeyboardButton.control()) + mb.addButton(KeyboardButton.alt()) + self.mouseWatcherNode.setModifierButtons(mb) # We also create a DataValve object above the trackball/drive # interface, which will allow us to switch some of the mouse @@ -240,7 +245,18 @@ class ShowBase: if self.oldexitfunc: self.oldexitfunc() - + + def getAlt(self): + return base.mouseWatcherNode.getModifierButtons().isDown( + KeyboardButton.alt()) + + def getShift(self): + return base.mouseWatcherNode.getModifierButtons().isDown( + KeyboardButton.shift()) + + def getControl(self): + return base.mouseWatcherNode.getModifierButtons().isDown( + KeyboardButton.control()) def addAngularIntegrator(self): """addAngularIntegrator(self)"""