From dc229aacb824319b7eff6794a70eba764ff647af Mon Sep 17 00:00:00 2001 From: Mark Mine Date: Fri, 20 Oct 2000 18:33:49 +0000 Subject: [PATCH] *** empty log message *** --- direct/src/directscripts/python-mode.el | 2 +- direct/src/directutil/DirectCameraControl.py | 328 ++++++++++++++ .../directutil/DirectCameraManipulation.py | 307 ------------- direct/src/directutil/DirectGeometry.py | 5 +- direct/src/directutil/DirectGrid.py | 4 +- direct/src/directutil/DirectSelection.py | 65 ++- direct/src/directutil/DirectSession.py | 415 +++++++++++++++--- direct/src/extensions/NodePath-extensions.py | 6 + direct/src/showbase/ShowBase.py | 3 +- direct/src/showbase/ShowBaseGlobal.py | 9 + direct/src/showbase/Task.py | 2 + 11 files changed, 752 insertions(+), 394 deletions(-) create mode 100644 direct/src/directutil/DirectCameraControl.py delete mode 100644 direct/src/directutil/DirectCameraManipulation.py diff --git a/direct/src/directscripts/python-mode.el b/direct/src/directscripts/python-mode.el index 4763b59f67..0b1a495a58 100644 --- a/direct/src/directscripts/python-mode.el +++ b/direct/src/directscripts/python-mode.el @@ -3161,7 +3161,7 @@ These are Python temporary files awaiting execution." (end-of-buffer) (insert "run()") (newline 1) - (py-execute-string "try:\n\trun()\nexcept:\n\tpass")) + (py-execute-string "try:\n\trun()\nexcept NameError,e:\n\tif e.__str__() == 'run':\n\t\tpass\n\telse:\n\t\traise\nexcept:\n\traise")) (provide 'python-mode) ;;; python-mode.el ends here diff --git a/direct/src/directutil/DirectCameraControl.py b/direct/src/directutil/DirectCameraControl.py new file mode 100644 index 0000000000..1e8524b7af --- /dev/null +++ b/direct/src/directutil/DirectCameraControl.py @@ -0,0 +1,328 @@ +from PandaObject import * + +CAM_MOVE_DURATION = 1.0 + +class DirectCameraControl(PandaObject): + def __init__(self, direct): + # Create the grid + self.direct = direct + self.defChan = direct.chanCenter + self.orthoViewRoll = 0.0 + self.lastView = 0 + self.coa = Point3(0) + self.relNodePath = render.attachNewNode(NamedNode('targetNode')) + self.zeroBaseVec = VBase3(0) + self.zeroVector = Vec3(0) + self.centerVec = Vec3(0, 1, 0) + self.zeroPoint = Point3(0) + + def mouseFlyStart(self, chan): + # Record starting mouse positions + self.initMouseX = chan.mouseX + self.initMouseY = chan.mouseY + # Where are we in the channel? + if ((abs(self.initMouseX) < 0.9) & (abs(self.initMouseY) < 0.9)): + # Mouse is in central region + # First compute a hit point based on current mouse position + if(self.direct.iRay.pick(render, chan.mouseX, chan.mouseY)): + # Find hit point in camera's space + self.coa = self.direct.iRay.hitPt(0) + # Handle case of bad coa point (too close or too far) + self.coaDist = Vec3(self.coa - self.zeroPoint).length() + if ((self.coaDist < (1.1 * self.defChan.near)) | + (self.coaDist > self.defChan.far)): + # Put it out in front of the camera + self.coa.set(0,10,0) + self.coaDist = 10 + else: + # If no intersection point: + # Put coa out in front of the camera + self.coa.set(0,10,0) + self.coaDist = 10 + # Now spawn task to determine mouse fly mode + self.determineMouseFlyMode() + else: + # Mouse is in outer frame, spawn mouseRotateTask + self.spawnMouseRotateTask() + + def mouseFlyStop(self): + taskMgr.removeTasksNamed('determineMouseFlyMode') + taskMgr.removeTasksNamed('manipulateCamera') + + def determineMouseFlyMode(self): + if (self.direct.fShift): + # If shift key is pressed: + self.spawnHPPan() + else: + # Otherwise, determine mouse fly mode + t = Task.Task(self.determineMouseFlyModeTask) + taskMgr.spawnTaskNamed(t, 'determineMouseFlyMode') + + def determineMouseFlyModeTask(self, state): + deltaX = self.defChan.mouseX - self.initMouseX + deltaY = self.defChan.mouseY - self.initMouseY + if ((abs(deltaX) < 0.1) & (abs(deltaY) < 0.1)): + return Task.cont + else: + if (abs(deltaY) > 0.1): + self.spawnHPanYZoom() + else: + self.spawnXZTranslate() + return Task.done + + def homeCam(self, chan): + chan.camera.setMat(Mat4.identMat()) + + def uprightCam(self, chan): + taskMgr.removeTasksNamed('manipulateCamera') + currH = chan.camera.getH() + chan.camera.lerpHpr(currH, 0, 0, + CAM_MOVE_DURATION, + other = render, + blendType = 'easeInOut', + task = 'manipulateCamera') + + def centerCam(self, chan): + # Chan is a display region context + self.centerCamIn(chan, 1.0) + + def centerCamNow(self, chan): + self.centerCamIn(chan, 0.) + + def centerCamIn(self, chan,t): + # Chan is a display region context + taskMgr.removeTasksNamed('manipulateCamera') + widgetToCam = self.direct.widget.getPos( chan.camera ) + dist = Vec3(widgetToCam - self.zeroPoint).length() + scaledCenterVec = self.centerVec * dist + delta = widgetToCam - scaledCenterVec + self.relNodePath.setPosHpr(chan.camera, Point3(0), Point3(0)) + chan.camera.lerpPos(self.relNodePath, + Point3(delta), + CAM_MOVE_DURATION, + blendType = 'easeInOut', + task = 'manipulateCamera') + + def zoomCam(self, chan, zoomFactor, t): + taskMgr.removeTasksNamed('manipulateCamera') + # Find a point zoom factor times the current separation + # of the widget and cam + zoomPtToCam = self.direct.widget.getPos(chan.camera) * zoomFactor + # Put a target nodePath there + self.relNodePath.setPos(chan.camera, zoomPtToCam) + # Move to that point + chan.camera.lerpPos(self.zeroPoint, + CAM_MOVE_DURATION, + other = self.relNodePath, + blendType = 'easeInOut', + task = 'manipulateCamera') + + def SpawnMoveToView(self, chan, view): + # Kill any existing tasks + taskMgr.removeTasksNamed('manipulateCamera') + # Calc hprOffset + hprOffset = VBase3() + if view == 1: + hprOffset.set(180., 0., 0.) + elif view == 2: + hprOffset.set(0., 0., 0.) + elif view == 3: + hprOffset.set(90., 0., 0.) + elif view == 4: + hprOffset.set(-90., 0., 0.) + elif view == 5: + hprOffset.set(0., -90., 0.) + elif view == 6: + hprOffset.set(0., 90., 0.) + elif view == 7: + hprOffset.set(135., -35.264, 0.) + # Position target + self.relNodePath.setPosHpr(self.direct.widget, + self.zeroBaseVec, + hprOffset) + # Scale center vec by current distance to target + offsetDistance = Vec3(chan.camera.getPos(self.relNodePath) - + self.zeroPoint).length() + scaledCenterVec = self.centerVec * (-1.0 * offsetDistance) + + # Now put the relNodePath at that point + self.relNodePath.setPosHpr(self.relNodePath, + scaledCenterVec, + self.zeroBaseVec) + + # Start off with best view if change is to new view + if (view != self.lastView): + self.orthoViewRoll = 0.0 + self.lastView = view + chan.camera.lerpPosHpr(self.zeroPoint, + VBase3(0,0,self.orthoViewRoll), + CAM_MOVE_DURATION, + other = self.relNodePath, + blendType = 'easeInOut', + task = 'manipulateCamera') + + # Try another roll next time + self.orthoViewRoll = (self.orthoViewRoll + 90.0) % 360.0 + + def swingCamAboutWidget(self, chan, degrees, t): + # Remove existing camera manipulation task + taskMgr.removeTasksNamed('manipulateCamera') + + # Coincident with widget + self.relNodePath.setPos(self.direct.widget, self.zeroPoint) + # But aligned with render space + self.relNodePath.setHpr(self.zeroPoint) + + parent = self.defChan.camera.getParent + self.defChan.camera.wrtReparentTo(self.relNodePath) + + self.relNodePath.lerpHpr(VBase3(degrees,0,0), + CAM_MOVE_DURATION, + blendType = 'easeInOut', + task = 'manipulateCamera') + # TODO: Convert this to an upon death + reparentTask = Task.Task(self.reparentCam) + reparentTask.parent = parent + reparentLater = Task.doLater(CAM_MOVE_DURATION, + reparentTask, + 'manipulateCamera') + taskMgr.spawnTaskNamed(reparentLater, 'manipulateCamera') + + def reparentCam(self, state): + self.defChan.camera.wrtReparentTo(state.parent) + return Task.done + + def spawnHPanYZoom(self): + # Negate vec to give it the correct sense for mouse motion below + targetVector = self.coa * -1 + t = Task.Task(self.HPanYZoomTask) + t.targetVector = targetVector + taskMgr.spawnTaskNamed(t, 'manipulateCamera') + + def HPanYZoomTask(self,state): + targetVector = state.targetVector + distToMove = targetVector * self.defChan.mouseDeltaY + self.defChan.camera.setPosHpr(self.defChan.camera, + distToMove[0], + distToMove[1], + distToMove[2], + (0.5 * self.defChan.mouseDeltaX * + self.defChan.fovH), + 0.0, 0.0) + return Task.cont + + + def spawnXZTranslateOrHPPan(self): + t = Task.Task(self.XZTranslateOrHPPanTask) + t.scaleFactor = (self.coaDist / self.defChan.near) + taskMgr.spawnTaskNamed(t, 'manipulateCamera') + + def XZTranslateOrHPPanTask(self, state): + if self.direct.fShift: + self.defChan.camera.setHpr(self.defChan.camera, + (0.5 * self.defChan.mouseDeltaX * + self.defChan.fovH), + (-0.5 * self.defChan.mouseDeltaY * + self.defChan.fovV), + 0.0) + else: + self.defChan.camera.setPos(self.defChan.camera, + (-0.5 * self.defChan.mouseDeltaX * + self.defChan.nearWidth * + state.scaleFactor), + 0.0, + (-0.5 * self.defChan.mouseDeltaY * + self.defChan.nearHeight * + state.scaleFactor)) + return Task.cont + + def spawnXZTranslate(self): + t = Task.Task(self.XZTranslateTask) + t.scaleFactor = (self.coaDist / self.defChan.near) + taskMgr.spawnTaskNamed(t, 'manipulateCamera') + + def XZTranslateTask(self,state): + self.defChan.camera.setPos(self.defChan.camera, + (-0.5 * self.defChan.mouseDeltaX * + self.defChan.nearWidth * + state.scaleFactor), + 0.0, + (-0.5 * self.defChan.mouseDeltaY * + self.defChan.nearHeight * + state.scaleFactor)) + return Task.cont + + def spawnMouseRotateTask(self): + self.relNodePath.setPos(self.coa) + self.relNodePath.setHpr(self.defChan.camera, self.zeroPoint) + t = Task.Task(self.mouseRotateTask) + t.wrtMat = self.defChan.camera.getMat( self.relNodePath ) + taskMgr.spawnTaskNamed(t, 'manipulateCamera') + + def mouseRotateTask(self, state): + wrtMat = state.wrtMat + self.relNodePath.setHpr(self.relNodePath, + (-0.5 * self.defChan.mouseDeltaX * 180.0), + (0.5 * self.defChan.mouseDeltaY * 180.0), + 0.0) + self.defChan.camera.setMat(self.relNodePath, wrtMat) + return Task.cont + + def spawnHPPan(self): + t = Task.Task(self.HPPanTask) + taskMgr.spawnTaskNamed(t, 'manipulateCamera') + + def HPPanTask(self, state): + self.defChan.camera.setHpr(self.defChan.camera, + (0.5 * self.defChan.mouseDeltaX * + self.defChan.fovH), + (-0.5 * self.defChan.mouseDeltaY * + self.defChan.fovV), + 0.0) + return Task.cont + + def enableMouseFly(self): + self.enableMouseInteraction() + self.enableHotKeys() + + def enableMouseInteraction(self): + # disable C++ fly interface + base.disableMouse() + # Accept middle mouse events + self.accept('mouse2', self.mouseFlyStart, [self.defChan]) + self.accept('mouse2-up', self.mouseFlyStop) + + def enableHotKeys(self): + t = CAM_MOVE_DURATION + self.accept('u', self.uprightCam, [self.defChan]) + self.accept('c', self.centerCamIn, [self.defChan, 0.5]) + self.accept('h', self.homeCam, [self.defChan]) + for i in range(1,8): + self.accept(`i`, self.SpawnMoveToView, [self.defChan, i]) + self.accept('9', self.swingCamAboutWidget, [self.defChan, -90.0, t]) + self.accept('0', self.swingCamAboutWidget, [self.defChan, 90.0, t]) + self.accept('8', self.removeManipulateCameraTask) + self.accept('=', self.zoomCam, [self.defChan, 0.5, t]) + self.accept('+', self.zoomCam, [self.defChan, 0.5, t]) + self.accept('-', self.zoomCam, [self.defChan, -2.0, t]) + self.accept('_', self.zoomCam, [self.defChan, -2.0, t]) + + def disableMouseFly(self): + # Accept middle mouse events + self.ignore('mouse2') + self.ignore('mouse2-up') + self.ignore('u') + self.ignore('c') + self.ignore('h') + for i in range(0,10): + self.ignore(`i`) + self.ignore('=') + self.ignore('+') + self.ignore('-') + self.ignore('=') + + def removeManipulateCameraTask(self): + taskMgr.removeTasksNamed('manipulateCamera') + + + diff --git a/direct/src/directutil/DirectCameraManipulation.py b/direct/src/directutil/DirectCameraManipulation.py deleted file mode 100644 index 79ae804654..0000000000 --- a/direct/src/directutil/DirectCameraManipulation.py +++ /dev/null @@ -1,307 +0,0 @@ -from PandaObject import * -from DirectGrid import DirectGrid - -class DirectCameraManipulation(PandaObject): - def __init__(): - # Create the grid - self.grid = DirectGrid(render) - self.grid.hide() - self.hitPt = Point3(0) - self.iPoint = Point3(0) - self.centerOfRotation = render.attachNewNode( NamedNode() ) - self.centerOfRotation.node().setName( 'centerOfRotation' ) - self.centerOfRotation.setPosHpr(Vec3(0), Vec3(0)) - self.orthoViewRoll = 0.0 - self.lastView = 0 - self.targetNodePath = render.attachNewNode(NamedNode('targetNode')) - self.zeroBaseVec = VBase3(0) - self.zeroVector = Vec3(0) - self.centerVec = Vec3(0., 1., 0.) - self.zeroPoint = Point3(0) - - def centerCam(chan): - # Chan is a display region context - self.centerCamIn(chan, 1.0) - - def centerCamNow(chan): - self.centerCamIn(chan, 0.) - - def centerCamIn(chan,t): - # Chan is a display region context - taskMgr.removeTasksNamed('manipulateCamera') - widgetToCam = direct.widget.getPos( chan.camera ) - dist = Vec3(widgetToCam - zeroPoint).length() - scaledCenterVec = centerVec * dist. - delta = widgetToCam - scaledCenterVec. - relNodePath = render.attachNewNode(Node()) - relNodePath.setPosHpr(chan.camera, Point3(0), Point3(0)) - ### - [ chan camera setPos: relNodePath pos: delta t: t. - ] spawnTaskNamed: 'manipulateCamera' - uponDeath: [ relNodePath removeNode. ] - ### - - def homeCam(chan): - chan.camera.setMat(Mat4.identMat()) - - - def mouseFlyStart(chan): - # Record starting mouse positions - initMouseX = chan.mouseX - initMouseY = chan.mouseY - - # Where are we in the channel? - if ((initMouseX abs < 0.9) & (initMouseY abs < 0.9)): - # Mouse is in central region - # spawn task to determine mouse fly mode" - self.determineMouseFlyMode() - else: - #Mouse is in outer frame, spawn mouseRotateTask - self.spawnMouseRotateTask() - - def mouseFlyStop(): - taskMgr.removeTasksNamed('determineMouseFlyMode') - taskMgr.removeTasksNamed('manipulateCamera') - - def removeManipulateCameraTask(): - taskMgr.removeTasksNamed('manipulateCamera') - - def enableMouseFly(): - self.enableMouseInteraction() - self.enableHotKeys() - - def enableMouseInteraction(): - # disable C++ fly interface - base.disableMouse() - # Accept middle mouse events - self.accept('mouse2', self.mouseFlyStart, [chanCenter]) - self.accept('mouse2-up' self.mouseFlyStop) - - def disableMouseFly(): - # Accept middle mouse events - self.ignore('mouse2') - self.ignore:'mouse2-up') - self.ignore('u') - self.ignore('c') - self.ignore('h') - for i in range(0,10): - self.ignore(`i`) - self.ignore('=') - self.ignore('+') - self.ignore('-') - self.ignore('=') - - def enableHotKeys(): - self.accept('u', self.uprightCam, [chanCenter]) - self.accept('c', self.centerCamIn, [chanCenter, 0.5]) - self.accept('h', self.homeCam, [chanCenter]) - for i in range(1,8): - self.accept(`i`, self.moveToView, [chanCenter, i]) - self.accept('9', self.swingCamAboutWidget, [chanCenter, -90.0, 1.0]) - self.accept('0', self.swingCamAboutWidget, [chanCenter, 90.0, 1.0]) - self.accept('8', self.removeManipulateCameraTask) - self.accept('=', self.zoomCam, [chanCenter, 0.5, 1.0]) - self.accept('+', self.zoomCam, [chanCenter, 0.5, 1.0]) - self.accept('-', self.zoomCam, [chanCenter, -2.0, 1.0]) - self.accept('=', self.zoomCam, [chanCenter, -2.0, 1.0]) - - def SpawnMoveToView(chan, view): - # Kill any existing tasks - taskMgr.removeTasksNamed('manipulateCamera') - # Calc hprOffset - hprOffset = VBase3() - if view = 1: - hprOffset.set(180., 0., 0.) - elif view = 2: - hprOffset set(0., 0., 0.) - elif view = 3: - hprOffset set(90., 0., 0.) - elif view = 4: - hprOffset set(-90., 0., 0.) - elif view = 5: - hprOffset set(0., -90., 0.) - elif view = 6: - hprOffset set(0., 90., 0.) - elif view = 7: - hprOffset set(135., -35.264, 0.) - # Position target - targetNodePath.setPosHpr(direct.widget, - self.zeroBaseVec, - hprOffset) - # Scale center vec by current distance to target - offsetDistance = Vec3(chan.camera.getPos(targetNodePath) - \ - zeroPoint).length() - scaledCenterVec = centerVec * (-1.0 * offsetDistance). - - # Now put the targetNodePath at that point - targetNodePath.setPosHpr(targetNodePath, - scaledCenterVec, - zeroBaseVec) - - # Start off with best view if change is to new view - if (view != lastView): - orthoViewRoll = 0.0 - lastView = view. - - [ chan camera setPosHpr: targetNodePath pos: zeroBaseVec - hpr: (VBase3 new: 0.0 y: 0.0 z: orthoViewRoll) - t: 1.0. - "Try another roll next time" - orthoViewRoll = (orthoViewRoll + 90.0) rem: 360.0.] - spawnTaskNamed: #manipulateCamera. - - - def determineMouseFlyMode(): - # Get mouse intersection point - # TBS - - # Find this point to camera space - gridToCamera = grid getMat: chanCenter camera. - hitPt operatorAssign: (gridToCamera xformPoint: iPoint). - "Make sure hitPt is in front of the camera" - hitPt setY: (hitPt at: 1) abs. - - "Handle case of bad hit point (too close or too far)" - hitDistance = (hitPt - zeroPoint) length. - ((hitDistance < (1.1 * chanCenter near)) | (hitDistance > chanCenter far)) ifTrue: [ - "Just use grid origin" - "hitPt operatorAssign: centerVec * (0.5 * (chanCenter far + chanCenter near))" - hitPt operatorAssign: (grid getPos: chanCenter camera). - ]. - - (direct fShift) ifTrue: [ self.spawnHPPan. ] - ifFalse: [ - [[deltaX = chanCenter mouseX - initMouseX. - deltaY = chanCenter mouseY - initMouseY. - ((deltaX abs < 0.1) & (deltaY abs < 0.1))] taskWhileTrue: [ nil ] - ] spawnTaskNamed: #determineMouseFlyMode - uponDeath: [ - (deltaY abs > 0.1) ifTrue: [ - self.spawnHPanYZoom] - ifFalse: [ - self.spawnXZTranslate ]. - ]. - ]. -! ! - - - -!DirectCameraManipulation methodsFor: 'event handling' stamp: 'panda 00/00/0000 00:00'! -spawnHPPan - [[true] taskWhileTrue: - [ chanCenter camera setHpr: chanCenter camera - h: (0.5 * chanCenter mouseDeltaX * chanCenter fovH) - p: (-0.5 * chanCenter mouseDeltaY * chanCenter fovV) - r: 0.0 ]] - spawnTaskNamed: #manipulateCamera. -! ! - -!DirectCameraManipulation methodsFor: 'event handling' stamp: 'panda 00/00/0000 00:00'! -spawnHPanYZoom - | targetVector distToMove | - targetVector = Vec3 new: (hitPt at: 0) y: (hitPt at: 1) z: (hitPt at: 2). - [[true] taskWhileTrue: - [ distToMove = targetVector * (-1.0 * chanCenter mouseDeltaY). - chanCenter camera setPosHpr: chanCenter camera - x: (distToMove at: 0) - y: (distToMove at: 1) - z: (distToMove at: 2) - h: (0.5 * chanCenter mouseDeltaX * chanCenter fovH) - p: 0.0 r: 0.0. ]] - spawnTaskNamed: #manipulateCamera. -! ! - -!DirectCameraManipulation methodsFor: 'event handling' stamp: 'panda 00/00/0000 00:00'! -spawnMouseRotateTask - | wrtMat | - centerOfRotation setPos: grid pos: iPoint. - centerOfRotation setHpr: chanCenter camera h: 0.0 p: 0.0 r: 0.0. - - wrtMat = chanCenter camera getMat: centerOfRotation. - - [[true] taskWhileTrue: - [ centerOfRotation setHpr: centerOfRotation - h: (-0.5 * chanCenter mouseDeltaX * 180.0) - p: (0.5 * chanCenter mouseDeltaY * 180.0) - r: 0.0. - chanCenter camera setMat: centerOfRotation mat: wrtMat. ]] - spawnTaskNamed: #manipulateCamera. -! ! - -!DirectCameraManipulation methodsFor: 'event handling' stamp: 'panda 00/00/0000 00:00'! -spawnXZTranslate - | scaleFactor | - scaleFactor = ((hitPt at: 1) / chanCenter near). - [[true] taskWhileTrue: - [ chanCenter camera setPos: chanCenter camera - x: (-0.5 * chanCenter mouseDeltaX * chanCenter nearWidth * scaleFactor) - y: 0.0 - z: (-0.5 * chanCenter mouseDeltaY * chanCenter nearHeight * scaleFactor) ] ] - spawnTaskNamed: #manipulateCamera. -! ! - -!DirectCameraManipulation methodsFor: 'event handling' stamp: 'panda 00/00/0000 00:00'! -spawnXZTranslateOrHPPan - | scaleFactor | - scaleFactor = ((hitPt at: 1) / chanCenter near). - [[true] taskWhileTrue: - [ direct fShift - ifTrue: [ chanCenter camera setHpr: chanCenter camera - h: (0.5 * chanCenter mouseDeltaX * chanCenter fovH) - p: (-0.5 * chanCenter mouseDeltaY * chanCenter fovV) - r: 0.0 ] - ifFalse: [ chanCenter camera setPos: chanCenter camera - x: (-0.5 * chanCenter mouseDeltaX * chanCenter nearWidth * scaleFactor) - y: 0.0 - z: (-0.5 * chanCenter mouseDeltaY * chanCenter nearHeight * scaleFactor)] - ]] - spawnTaskNamed: #manipulateCamera. -! ! - -!DirectCameraManipulation methodsFor: 'event handling' stamp: 'panda 00/00/0000 00:00'! -swingCamAboutWidget: chan deg: degrees in: t - | relNodePath parent | - - Task removeTasksNamed: #manipulateCamera. - - relNodePath = showBase render attachNewNode: (Node new). - "Coincident with widget" - relNodePath setPos: direct widget pos: (Point3 zero). - "But aligned with render space" - relNodePath setHpr: (Point3 zero). - - parent = chanCenter camera getParent. - chanCenter camera wrtReparentTo: relNodePath. - - [ relNodePath setHpr: (VBase3 new: degrees y: 0.0 z: 0.0) t: t. ] - spawnTaskNamed: #manipulateCamera - uponDeath: [ - chanCenter camera wrtReparentTo: parent. - relNodePath reparentTo: showBase hidden. - relNodePath removeNode. - ].! ! - -!DirectCameraManipulation methodsFor: 'event handling' stamp: 'panda 00/00/0000 00:00'! -uprightCam: chan - | currH | - Task removeTasksNamed: #manipulateCamera. - currH = chan camera getH. - [ chan camera setHpr: showBase render h: currH p: 0.0 r: 0.0 t: 1.0. - ] spawnTaskNamed: #manipulateCamera.! ! - -!DirectCameraManipulation methodsFor: 'event handling' stamp: 'panda 00/00/0000 00:00'! -zoomCam: chan zoom: zoom in: t - | relNodePath zoomPtToCam | - Task removeTasksNamed: #manipulateCamera. - "Find a point zoom factor times the current separation of the widget and cam" - zoomPtToCam = (direct widget getPos: chan camera) * zoom. - - "Put a target nodePath there" - relNodePath = showBase render attachNewNode: (Node new). - relNodePath setPos: chanCenter camera pos: zoomPtToCam. - - "Move to that point" - [ chan camera setPos: relNodePath pos: (Point3 zero) t: t. ] - spawnTaskNamed: #manipulateCamera - uponDeath: [ relNodePath removeNode. ].! ! - diff --git a/direct/src/directutil/DirectGeometry.py b/direct/src/directutil/DirectGeometry.py index 5689a2fea4..de3e05df56 100644 --- a/direct/src/directutil/DirectGeometry.py +++ b/direct/src/directutil/DirectGeometry.py @@ -2,11 +2,14 @@ from PandaObject import * import math class LineNodePath(NodePath): - def __init__(self, parent = hidden, **kw): + def __init__(self, parent = None, **kw): # Initialize the superclass NodePath.__init__(self) + if parent is None: + parent = hidden + # Attach a geomNode to the parent and set self to be # the resulting node path self.lineNode = GeomNode() diff --git a/direct/src/directutil/DirectGrid.py b/direct/src/directutil/DirectGrid.py index f32f050748..c4ecbf491f 100644 --- a/direct/src/directutil/DirectGrid.py +++ b/direct/src/directutil/DirectGrid.py @@ -1,7 +1,9 @@ from PandaObject import * class DirectGrid(NodePath): - def __init__(self, parent = hidden): + def __init__(self, parent = None): NodePath.__init__(self) + if parent is None: + parent = hidden self.assign(parent.attachNewNode( NamedNode('grid') )) diff --git a/direct/src/directutil/DirectSelection.py b/direct/src/directutil/DirectSelection.py index 4f69bab8aa..1ae9015999 100644 --- a/direct/src/directutil/DirectSelection.py +++ b/direct/src/directutil/DirectSelection.py @@ -1,31 +1,58 @@ +from PandaObject import * + +class SelectionRay: + def __init__(self, camera, fGeom = 1): + # Record the camera associated with this selection ray + self.camera = camera + # Create a collision node + self.rayCollisionNodePath = camera.attachNewNode( CollisionNode() ) + rayCollisionNode = self.rayCollisionNodePath.node() + # Specify if this ray collides with geometry + rayCollisionNode.setCollideGeom(fGeom) + # Create a collision ray + self.ray = CollisionRay() + # Add the ray to the collision Node + rayCollisionNode.addSolid( self.ray ) + # Create a queue to hold the collision results + self.cq = CollisionHandlerQueue() + self.numEntries = 0 + # And a traverser to do the actual collision tests + self.ct = CollisionTraverser( RenderRelation.getClassType() ) + # Let the traverser know about the queue and the collision node + self.ct.addCollider(rayCollisionNode, self.cq ) + + def pick(self, targetNodePath, mouseX, mouseY): + # Determine ray direction based upon the mouse coordinates + # Note! This has to be a cam object (of type ProjectionNode) + self.ray.setProjection( base.cam.node(), mouseX, mouseY ) + self.ct.traverse( targetNodePath.node() ) + self.numEntries = self.cq.getNumEntries() + return self.numEntries + + def localHitPt(self, index): + return self.cq.getEntry(index).getIntoIntersectionPoint() + + def hitPt(self, index): + entry = self.cq.getEntry(index) + hitPt = entry.getIntoIntersectionPoint() + return entry.getWrtSpace().xformPoint(hitPt) + +""" dd = loader.loadModel(r"I:\beta\toons\install\neighborhoods\donalds_dock") dd.reparentTo(render) -cam = base.cam.node() -rNode = camera.attachNewNode( CollisionNode() ) -rNode.node().setCollideGeom(1) -ray = CollisionRay() -rNode.node().addSolid( ray ) -cq = CollisionHandlerQueue() -ct = CollisionTraverser( ) -# Optionally -# ct = CollisionTraverser( RenderRelation.getClassType() ) -ct.addCollider(rNode.node(), cq ) -# These are the mouse coordinates -ray.setProjection( cam, 0, 0 ) -ct.traverse( render.node() ) - # Operations on cq cq.getNumEntries() cq.getEntry(0).getIntoNode() cq.getEntry(0).getIntoNode().getName() print cq.getEntry(i).getIntoIntersectionPoint() -for i in range(0,cq.getNumEntries()): - name = cq.getEntry(i).getIntoNode().getName() +for i in range(0,bobo.cq.getNumEntries()): + name = bobo.cq.getEntry(i).getIntoNode().getName() if not name: name = "" print name - print cq.getEntry(i).getIntoIntersectionPoint()[0], - print cq.getEntry(i).getIntoIntersectionPoint()[1], - print cq.getEntry(i).getIntoIntersectionPoint()[2] + print bobo.cq.getEntry(i).getIntoIntersectionPoint()[0], + print bobo.cq.getEntry(i).getIntoIntersectionPoint()[1], + print bobo.cq.getEntry(i).getIntoIntersectionPoint()[2] +""" diff --git a/direct/src/directutil/DirectSession.py b/direct/src/directutil/DirectSession.py index bf74c1f63b..14edeaab00 100644 --- a/direct/src/directutil/DirectSession.py +++ b/direct/src/directutil/DirectSession.py @@ -1,84 +1,321 @@ from PandaObject import * from DirectGeometry import * +from DirectSelection import * +from DirectCameraControl import * import OnscreenText import math -class DisplayRegionContext(PandaObject): - def __init__(self, win, camera): - self.win = win - self.camera = camera - self.cam = camera.getChild(0) - self.camNode = self.cam.getNode(0) - self.mouseData = win.getMouseData(0) - self.mouseX = 0.0 - self.mouseY = 0.0 - - def __getitem__(self,key): - return self.__dict__[key] - - def start(self): - # First shutdown any existing task - self.stop() - # Start a new context task - self.spawnContextTask() - - def stop(self): - # Kill the existing context task - taskMgr.removeTasksNamed('DIRECTContextTask') - - def spawnContextTask(self): - taskMgr.spawnTaskNamed(Task.Task(self.contextTask), - 'DIRECTContextTask') - - def contextTask(self, state): - # Window Data - self.width = self.win.getWidth() - self.height = self.win.getHeight() - self.near = self.camNode.getNear() - self.far = self.camNode.getFar() - self.fovH = self.camNode.getHfov() - self.fovV = self.camNode.getVfov() - self.nearWidth = math.tan(deg2Rad(self.fovH / 2.0)) * self.near * 2.0 - self.nearHeight = math.tan(deg2Rad(self.fovV / 2.0)) * self.near * 2.0 - # Mouse Data - # Last frame - self.mouseLastX = self.mouseX - self.mouseLastY = self.mouseY - # This frame - self.mousePixelX = self.mouseData.getX() - self.mousePixelY = self.mouseData.getY() - self.mouseX = ((self.mousePixelX / float(self.width)) * 2.0) - 1.0 - self.mouseY = ((self.mousePixelY / float(self.height)) * -2.0) + 1.0 - self.mouseDeltaX = self.mouseX - self.mouseLastX - self.mouseDeltaY = self.mouseY - self.mouseLastY - # Continue the task - return Task.cont - class DirectSession(PandaObject): + def __init__(self): self.contextList = [] + self.iRayList = [] for camera in base.cameraList: self.contextList.append(DisplayRegionContext(base.win, camera)) + self.iRayList.append(SelectionRay(camera)) + self.chanCenter = self.getChanData(0) + + self.cameraControls = DirectCameraControl(self) # Initialize the collection of selected nodePaths self.selectedNodePaths = {} + self.selectedNodePath = None self.lastSelected = None self.readout = OnscreenText.OnscreenText( '', 0.1, -0.95 ) # self.readout.textNode.setCardColor(0.5, 0.5, 0.5, 0.5) self.readout.reparentTo( hidden ) - self.createBBox() - - # self.createObjectHandles() - # self.useObjectHandles() + self.createObjectHandles() + self.useObjectHandles() + self.createBBox() self.bboxList = [] self.fControl = 0 self.fAlt = 0 self.fShift = 0 - + self.in2DWidget = 0 + + self.iRay = self.iRayList[0] + self.hitPt = Point3(0.0) + + self.actionEvents = [('selectNodePath', self.selectNodePath), + ('deselectNodePath', self.deselectNodePath), + ('deselectAll', self.deselectAll), + ('highlightNodePath', self.highlightNodePath), + ('removeNodePath', self.removeNodePath), + ('in2DWidget', self.in2DWidget)] + self.keyEvents = ['left', 'right', 'up', 'down', + 'escape', 'space', 'delete', + 'shift', 'shift-up', 'alt', 'alt-up', + 'control', 'control-up', + 'b', 'c', 'f', 'l', 't', 'v', 'w'] + + self.mouseEvents = ['mouse1', 'mouse1-up', + 'mouse2', 'mouse2-up', + 'mouse3', 'mouse3-up'] + + def selectNodePath(self, aNodePath, multiSelect = 0): + self.lastSelected = aNodePath + + # Do nothing if nothing selected + if not aNodePath: + print 'Nothing selected!!' + return 0 + + # Reset selected objects and highlight if multiSelect is false + if not multiSelect: + self.deselectAll() + + # Record newly selected object + # Use this pointer as an index + self.selectedNodePaths[aNodePath.this] = aNodePath + self.highlightNodePath(aNodePath) + self.readout.reparentTo(render2d) + self.readout.setText(self.getNodeName(aNodePath)) + + def getNodeName(self, aNodePath): + node = aNodePath.node() + name = '' + if issubclass(node.__class__, NamedNode): + namableName = node.getName() + if len(namableName) != 0: + name = namableName + return name + + def in2DWidget(self): + self.in2DWidget = 1 + + def deselectNodePath(self, aNodePath): + # remove nodePath from selectedNodePaths dictionary if it exists + key = aNodePath.this + if self.selectedNodePaths.has_key(key): + del self.selectedNodePaths[key] + # Hide the manipulation widget + self.objectHandles.reparentTo(hidden) + self.readout.reparentTo(hidden) + self.readout.setText(' ') + taskMgr.removeTasksNamed('followSelectedNodePath') + + def deselectAll(self): + self.selectedNodePaths = {} + # Hide the manipulation widget + self.objectHandles.reparentTo(hidden) + self.readout.reparentTo(hidden) + self.readout.setText(' ') + taskMgr.removeTasksNamed('followSelectedNodePath') + + def highlightNodePath(self, aNodePath): + selectedBounds = self.getBounds(aNodePath) + # Does this work? + radius = selectedBounds.getRadius() + # radius = 5.0. + # Place the manipulation widget on the object too + self.objectHandles.reparentTo(render) + self.objectHandles.setScale(radius) + # Spawn task to have object handles follow the selected object + taskMgr.removeTasksNamed('followSelectedNodePath') + t = Task.Task(self.followSelectedNodePathTask) + t.aNodePath = aNodePath + taskMgr.spawnTaskNamed(t, 'followSelectedNodePath') + + def followSelectedNodePathTask(self, state): + aNodePath = state.aNodePath + pos = aNodePath.getPos(render) + self.objectHandles.setPos(pos) + return Task.cont + + def isolateSelected(self): + selected = self.selectedNodePath + if selected: + self.showAllDescendants(selected.getParent()) + self.hideSiblings(selected) + + def removeNodePath(self, aNodePath): + # Method to handle the remove event sent by the Scene Graph Explorer + # Remove highlight and deselect nodePath + self.deselectNodePath(aNodePath) + # Send message in case anyone needs to do something + # before node is deleted + messenger.send('preRemoveNodePath', [aNodePath]) + # Remove nodePath + aNodePath.reparentTo(hidden) + aNodePath.removeNode() + + def removeSelectedNodePaths(self): + # Remove all selected nodePaths from the Scene Graph + for key in self.selectedNodePaths.keys(): + np = self.selectedNodePaths[key] + self.removeNodePath(np) + + def toggleVizSelectedNodePaths(self): + # Toggle visibility of selected node paths + for key in self.selectedNodePaths.keys(): + path = self.selectedNodePaths[key] + if path.isHidden(): + path.show() + else: + path.hide() + + def getBounds(self, aNodePath): + # Get a node path's bounds + nodeBounds = aNodePath.node().getBound() + for kid in aNodePath.getChildrenAsList(): + nodeBounds.extendBy(kid.getBottomArc().getBound()) + return nodeBounds.makeCopy() + + def showAllDescendantsSelectedNodePath(self): + # Show the descendants of the selectedNodePath + selected = self.selectedNodePath + if selected: + self.showAllDescendants(selected) + + def showAllDescendants(self, aNodePath): + aNodePath.show() + for child in aNodePath.getChildrenAsList(): + self.showAllDescendants(child) + + def showSelectedNodePathSiblings(self): + selected = self.selectedNodePath + if selected: + self.showSiblings(selected) + + def showSiblings(self, aNodePath): + aNodePath.show() + for sib in aNodePath.getParent().getChildrenAsList(): + if sib != aNodePath: + sib.hide() + + def hideSelectedNodePathSiblings(self): + selected = self.selectedNodePath + if selected: + self.hideSiblings(selected) + + def hideSiblings(self, aNodePath): + aNodePath.show() + for sib in aNodePath.getParent().getChildrenAsList(): + if sib != aNodePath: + sib.hide() + + def enable(self): + # Start all display region context tasks + for context in self.contextList: + context.spawnContextTask() + # Turn on mouse Flying + self.cameraControls.enableMouseFly() + # Accept appropriate hooks + self.enableKeyEvents() + self.enableMouseEvents() + self.enableActionEvents() + + def disable(self): + # Shut down all display region context tasks + for context in self.contextList: + context.removeContextTask() + # Turn off camera fly + self.cameraControls.disableMouseFly() + self.disableKeyEvents() + self.disableMouseEvents() + self.disableActionEvents() + + def minimumConfiguration(self): + # Remove context task + for context in self.contextList: + context.removeContextTask() + # Turn off camera fly + self.cameraControls.disableMouseFly() + # Ignore keyboard and action events + self.disableKeyEvents() + self.disableActionEvents() + # But let mouse events pass through + self.enableMouseEvents() + + def destroy(self): + self.disable() + + def restart(self): + self.enable() + + def enableActionEvents(self): + for event, method in self.actionEvents: + self.accept(event, method) + + 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 in self.actionEvents: + 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 useObjectHandles(self): + self.widget = self.objectHandles + + def hideReadout(self): + self.readout.reparentTo(hidden) + + def getChanData(self, index): + return self.contextList[index] + + def inputHandler(self, input): + # Deal with keyboard and mouse input + if ((input != 'mouse1-up') & (input != 'mouse2-up') & + (input != 'mouse3-up')): + self.in2DWidget = 0 + + if input == 'mouse1': + messenger.send('handle2DMouse1') + if not self.in2DWidget: + messenger.send('handleMouse1') + elif input == 'mouse1-up': + messenger.send('handle2DMouse1Up') + if not self.in2DWidget: + messenger.send('handleMouse1Up') + elif input == 'mouse3': + messenger.send('handleMouse3') + elif input == 'mouse3-up': + messenger.send('handleMouse3Up') + elif input == 'shift': + self.fShift = true + elif input == 'shift-up': + self.fShift = false + elif input == 'control': + self.fControl = true + elif input == 'control-up': + self.fControl = false + elif input == 'alt': + self.fAlt = true + elif input == 'alt-up': + self.fAlt = false + elif input == 'escape': + self.deselectAll() + elif input == 'l': + if not self.lastSelected: + self.selectNodePath(self.lastSelected) + elif input == 'delete': + self.removeSelectedNodePaths() + elif input == 'v': + self.toggleVizSelectedNodePaths() + elif input == 'b': + base.toggleBackface() + elif input == 't': + base.toggleTexture() + elif input == 'w': + base.toggleWireframe() + def createBBox(self, parent = hidden): # Create a line segments object for the bbox bbox = self.bbox = LineNodePath(parent) @@ -111,19 +348,20 @@ class DirectSession(PandaObject): bbox.create() def createObjectHandles(self): - oh = self.objectHandles = hidden.attachNewNode( NamedNode('objectHandles') ) + oh = self.objectHandles = hidden.attachNewNode( + NamedNode('objectHandles') ) ohLines = LineNodePath( oh ) ohLines.setColor( VBase4( 1.0, 0.0, 1.0, 1.0) ) ohLines.setThickness( 3.0 ) - "InnerRing" + # InnerRing ohLines.moveTo( 0.8, 0.0, 0.0 ) for ang in range(10, 360, 10): ohLines.drawTo( (0.8 * math.cos(deg2Rad(ang))), (0.8 * math.sin(deg2Rad(ang))), 0.0 ) - "Outer Ring" + # Outer Ring ohLines.moveTo( 1.2, 0.0, 0.0 ) for ang in range(0, 360, 10): ohLines.drawTo( (1.2 * math.cos(deg2Rad(ang))), @@ -132,12 +370,61 @@ class DirectSession(PandaObject): ohLines.moveTo( 0.0, 0.0, 0.0 ) ohLines.drawTo( 0.0, 0.0, 1.5 ) - + # Create the line segments ohLines.create() - - - - +class DisplayRegionContext(PandaObject): + def __init__(self, win, camera): + self.win = win + self.camera = camera + self.cam = camera.getChild(0) + self.camNode = self.cam.getNode(0) + self.mouseData = win.getMouseData(0) + self.mouseX = 0.0 + self.mouseY = 0.0 + + def __getitem__(self,key): + return self.__dict__[key] + + def start(self): + # First shutdown any existing task + self.stop() + # Start a new context task + self.spawnContextTask() + + def stop(self): + # Kill the existing context task + taskMgr.removeTasksNamed('DIRECTContextTask') + + def spawnContextTask(self): + taskMgr.spawnTaskNamed(Task.Task(self.contextTask), + 'DIRECTContextTask') + + def removeContextTask(self): + taskMgr.removeTasksNamed('DIRECTContextTask') + + def contextTask(self, state): + # Window Data + self.width = self.win.getWidth() + self.height = self.win.getHeight() + self.near = self.camNode.getNear() + self.far = self.camNode.getFar() + self.fovH = self.camNode.getHfov() + self.fovV = self.camNode.getVfov() + self.nearWidth = math.tan(deg2Rad(self.fovH / 2.0)) * self.near * 2.0 + self.nearHeight = math.tan(deg2Rad(self.fovV / 2.0)) * self.near * 2.0 + # Mouse Data + # Last frame + self.mouseLastX = self.mouseX + self.mouseLastY = self.mouseY + # This frame + self.mousePixelX = self.mouseData.getX() + self.mousePixelY = self.mouseData.getY() + self.mouseX = ((self.mousePixelX / float(self.width)) * 2.0) - 1.0 + self.mouseY = ((self.mousePixelY / float(self.height)) * -2.0) + 1.0 + self.mouseDeltaX = self.mouseX - self.mouseLastX + self.mouseDeltaY = self.mouseY - self.mouseLastY + # Continue the task + return Task.cont diff --git a/direct/src/extensions/NodePath-extensions.py b/direct/src/extensions/NodePath-extensions.py index 695239a47c..80fcf3c924 100644 --- a/direct/src/extensions/NodePath-extensions.py +++ b/direct/src/extensions/NodePath-extensions.py @@ -3,6 +3,12 @@ of the NodePath class """ + # For iterating over children + def getChildrenAsList(self): + childrenList = [] + for childNum in range(self.getNumChildren()): + childrenList.append(self.getChild(childNum)) + return childrenList # private methods diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index 212b13ec1b..9aed3f378e 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -21,6 +21,7 @@ class ShowBase: # Store dconfig variables self.wantTk = self.config.GetBool('want-tk', 0) self.wantSound = self.config.GetBool('want-sound', 1) + self.wantDIRECT = self.config.GetBool('want-directtools', 0) import Loader @@ -72,7 +73,7 @@ class ShowBase: self.createAudioManager() self.createRootPanel() - + self.restart() def createAudioManager(self): diff --git a/direct/src/showbase/ShowBaseGlobal.py b/direct/src/showbase/ShowBaseGlobal.py index dd79b70292..84989febd8 100644 --- a/direct/src/showbase/ShowBaseGlobal.py +++ b/direct/src/showbase/ShowBaseGlobal.py @@ -12,3 +12,12 @@ camera = base.camera loader = base.loader run = base.run tkroot = base.tkroot + +# Now create the DIRECT tools +if base.wantDIRECT: + import DirectSession + direct = base.direct = DirectSession.DirectSession() + chanCenter = direct.chanCenter +else: + direct = base.direct = None + chanCenter = None diff --git a/direct/src/showbase/Task.py b/direct/src/showbase/Task.py index c1e6bfe4bc..79530523b4 100644 --- a/direct/src/showbase/Task.py +++ b/direct/src/showbase/Task.py @@ -252,6 +252,8 @@ class TaskManager: self.step() except KeyboardInterrupt: self.stop() + except: + raise def stop(self): # Set a flag so we will stop before beginning next frame