Browse Source

*** empty log message ***

Mark Mine 25 years ago
parent
commit
dc229aacb8

+ 1 - 1
direct/src/directscripts/python-mode.el

@@ -3161,7 +3161,7 @@ These are Python temporary files awaiting execution."
   (end-of-buffer)
   (end-of-buffer)
   (insert "run()")
   (insert "run()")
   (newline 1)
   (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)
 (provide 'python-mode)
 ;;; python-mode.el ends here
 ;;; python-mode.el ends here

+ 328 - 0
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')
+
+
+

+ 0 - 307
direct/src/directutil/DirectCameraManipulation.py

@@ -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. ].! !
-

+ 4 - 1
direct/src/directutil/DirectGeometry.py

@@ -2,11 +2,14 @@ from PandaObject import *
 import math
 import math
 
 
 class LineNodePath(NodePath):
 class LineNodePath(NodePath):
-    def __init__(self, parent = hidden, **kw):
+    def __init__(self, parent = None, **kw):
 
 
         # Initialize the superclass
         # Initialize the superclass
         NodePath.__init__(self)
         NodePath.__init__(self)
 
 
+        if parent is None:
+            parent = hidden
+
         # Attach a geomNode to the parent and set self to be
         # Attach a geomNode to the parent and set self to be
         # the resulting node path
         # the resulting node path
         self.lineNode = GeomNode()
         self.lineNode = GeomNode()

+ 3 - 1
direct/src/directutil/DirectGrid.py

@@ -1,7 +1,9 @@
 from PandaObject import *
 from PandaObject import *
 
 
 class DirectGrid(NodePath):
 class DirectGrid(NodePath):
-    def __init__(self, parent = hidden):
+    def __init__(self, parent = None):
         NodePath.__init__(self)
         NodePath.__init__(self)
+        if parent is None:
+            parent = hidden
         self.assign(parent.attachNewNode( NamedNode('grid') ))
         self.assign(parent.attachNewNode( NamedNode('grid') ))
 
 

+ 46 - 19
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 = loader.loadModel(r"I:\beta\toons\install\neighborhoods\donalds_dock")
 dd.reparentTo(render)
 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
 # Operations on cq
 cq.getNumEntries()
 cq.getNumEntries()
 cq.getEntry(0).getIntoNode()
 cq.getEntry(0).getIntoNode()
 cq.getEntry(0).getIntoNode().getName()
 cq.getEntry(0).getIntoNode().getName()
 print cq.getEntry(i).getIntoIntersectionPoint()
 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:
     if not name:
         name = "<noname>"
         name = "<noname>"
     print 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]
+"""

+ 348 - 61
direct/src/directutil/DirectSession.py

@@ -1,84 +1,321 @@
 from PandaObject import *
 from PandaObject import *
 from DirectGeometry import *
 from DirectGeometry import *
+from DirectSelection import *
+from DirectCameraControl import *
 import OnscreenText
 import OnscreenText
 import math
 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):
 class DirectSession(PandaObject):
+    
     def __init__(self):
     def __init__(self):
         self.contextList = []
         self.contextList = []
+        self.iRayList = []
         for camera in base.cameraList:
         for camera in base.cameraList:
             self.contextList.append(DisplayRegionContext(base.win, camera))
             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
         # Initialize the collection of selected nodePaths
         self.selectedNodePaths = {}
         self.selectedNodePaths = {}
+        self.selectedNodePath = None
         self.lastSelected = None
         self.lastSelected = None
 
 
         self.readout = OnscreenText.OnscreenText( '', 0.1, -0.95 )
         self.readout = OnscreenText.OnscreenText( '', 0.1, -0.95 )
         # self.readout.textNode.setCardColor(0.5, 0.5, 0.5, 0.5)
         # self.readout.textNode.setCardColor(0.5, 0.5, 0.5, 0.5)
         self.readout.reparentTo( hidden )
         self.readout.reparentTo( hidden )
 
 
-        self.createBBox()
-
-        # self.createObjectHandles()
-        # self.useObjectHandles()
+        self.createObjectHandles()
+        self.useObjectHandles()
         
         
+        self.createBBox()
         self.bboxList = []
         self.bboxList = []
 
 
         self.fControl = 0
         self.fControl = 0
         self.fAlt = 0
         self.fAlt = 0
         self.fShift = 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 = '<noname>'
+        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):
     def createBBox(self, parent = hidden):
         # Create a line segments object for the bbox
         # Create a line segments object for the bbox
 	bbox = self.bbox = LineNodePath(parent)
 	bbox = self.bbox = LineNodePath(parent)
@@ -111,19 +348,20 @@ class DirectSession(PandaObject):
 	bbox.create()
 	bbox.create()
 
 
     def createObjectHandles(self):
     def createObjectHandles(self):
-	oh = self.objectHandles = hidden.attachNewNode( NamedNode('objectHandles') )
+	oh = self.objectHandles = hidden.attachNewNode(
+            NamedNode('objectHandles') )
 	ohLines = LineNodePath( oh )
 	ohLines = LineNodePath( oh )
 	ohLines.setColor( VBase4( 1.0, 0.0, 1.0, 1.0) )
 	ohLines.setColor( VBase4( 1.0, 0.0, 1.0, 1.0) )
 	ohLines.setThickness( 3.0 )
 	ohLines.setThickness( 3.0 )
 
 
-	"InnerRing"
+	# InnerRing
 	ohLines.moveTo( 0.8, 0.0, 0.0 )
 	ohLines.moveTo( 0.8, 0.0, 0.0 )
         for ang in range(10, 360, 10):
         for ang in range(10, 360, 10):
             ohLines.drawTo( (0.8 * math.cos(deg2Rad(ang))),
             ohLines.drawTo( (0.8 * math.cos(deg2Rad(ang))),
                             (0.8 * math.sin(deg2Rad(ang))),
                             (0.8 * math.sin(deg2Rad(ang))),
                             0.0 )
                             0.0 )
 
 
-	"Outer Ring" 
+	# Outer Ring 
 	ohLines.moveTo( 1.2, 0.0, 0.0 )
 	ohLines.moveTo( 1.2, 0.0, 0.0 )
         for ang in range(0, 360, 10):
         for ang in range(0, 360, 10):
             ohLines.drawTo( (1.2 * math.cos(deg2Rad(ang))),
             ohLines.drawTo( (1.2 * math.cos(deg2Rad(ang))),
@@ -132,12 +370,61 @@ class DirectSession(PandaObject):
 
 
 	ohLines.moveTo( 0.0, 0.0, 0.0 )
 	ohLines.moveTo( 0.0, 0.0, 0.0 )
 	ohLines.drawTo( 0.0, 0.0, 1.5 )
 	ohLines.drawTo( 0.0, 0.0, 1.5 )
-
+        # Create the line segments
 	ohLines.create()
 	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
 
 
 
 

+ 6 - 0
direct/src/extensions/NodePath-extensions.py

@@ -3,6 +3,12 @@
     of the NodePath class
     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
     # private methods
     
     

+ 2 - 1
direct/src/showbase/ShowBase.py

@@ -21,6 +21,7 @@ class ShowBase:
         # Store dconfig variables
         # Store dconfig variables
         self.wantTk = self.config.GetBool('want-tk', 0)
         self.wantTk = self.config.GetBool('want-tk', 0)
         self.wantSound = self.config.GetBool('want-sound', 1)
         self.wantSound = self.config.GetBool('want-sound', 1)
+        self.wantDIRECT = self.config.GetBool('want-directtools', 0)
         
         
         import Loader
         import Loader
 
 
@@ -72,7 +73,7 @@ class ShowBase:
 
 
         self.createAudioManager()
         self.createAudioManager()
         self.createRootPanel()
         self.createRootPanel()
-        
+
         self.restart()
         self.restart()
 
 
     def createAudioManager(self):
     def createAudioManager(self):

+ 9 - 0
direct/src/showbase/ShowBaseGlobal.py

@@ -12,3 +12,12 @@ camera = base.camera
 loader = base.loader
 loader = base.loader
 run = base.run
 run = base.run
 tkroot = base.tkroot
 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

+ 2 - 0
direct/src/showbase/Task.py

@@ -252,6 +252,8 @@ class TaskManager:
                 self.step()
                 self.step()
             except KeyboardInterrupt:
             except KeyboardInterrupt:
                 self.stop()
                 self.stop()
+            except:
+                raise
 
 
     def stop(self):
     def stop(self):
         # Set a flag so we will stop before beginning next frame
         # Set a flag so we will stop before beginning next frame