Browse Source

*** empty log message ***

Mark Mine 25 years ago
parent
commit
c738d0f324

+ 41 - 21
direct/src/directutil/DirectCameraControl.py

@@ -6,7 +6,7 @@ class DirectCameraControl(PandaObject):
     def __init__(self, direct):
         # Create the grid
         self.direct = direct
-        self.chan = direct.chanCenter
+        self.chan = direct.chan
         self.camera = self.chan.camera
 	self.orthoViewRoll = 0.0
 	self.lastView = 0
@@ -27,13 +27,17 @@ class DirectCameraControl(PandaObject):
 	# Where are we in the channel?
         if ((abs(self.initMouseX) < 0.9) & (abs(self.initMouseY) < 0.9)):
             # MOUSE IS IN CENTRAL REGION
+            # Hide the marker for this kind of motion
+            self.coaMarker.hide()
+            # See if the shift key is pressed
             if (self.direct.fShift):
                 # If shift key is pressed, just perform horiz and vert pan:
                 self.spawnHPPan()
             else:
                 # Otherwise, check for a hit point based on current mouse position
                 # And then spawn task to determine mouse mode
-                numEntries = self.direct.iRay.pick(render,chan.mouseX,chan.mouseY)
+                numEntries = self.direct.iRay.pickGeom(
+                    render,chan.mouseX,chan.mouseY)
                 coa = Point3(0)
                 if(numEntries):
                     # Start off with first point
@@ -77,6 +81,10 @@ class DirectCameraControl(PandaObject):
     def mouseFlyStop(self):
 	taskMgr.removeTasksNamed('determineMouseFlyMode')
 	taskMgr.removeTasksNamed('manipulateCamera')
+        # Show the marker
+        self.coaMarker.show()
+        # Resize it
+        self.updateCoaMarkerSize()
 
     def determineMouseFlyMode(self):
         # Otherwise, determine mouse fly mode
@@ -103,8 +111,16 @@ class DirectCameraControl(PandaObject):
             self.coaDist = Vec3(self.coa - self.zeroPoint).length()
         # Place the marker in render space
         self.coaMarker.setPos(self.camera,self.coa)
+        # Resize it
+        self.updateCoaMarkerSize(coaDist)
         # Record marker pos in render space
-        self.coaMarkerPos = self.coaMarker.getPos()
+        self.coaMarkerPos.assign(self.coaMarker.getPos())
+
+    def updateCoaMarkerSize(self, coaDist = None):
+        if not coaDist:
+            coaDist = Vec3(self.coaMarker.getPos( self.chan.camera )).length()
+        self.coaMarker.setScale(0.01 * coaDist *
+                                math.tan(deg2Rad(self.chan.fovV)))
 
     def homeCam(self, chan):
         chan.camera.setMat(Mat4.identMat())
@@ -155,16 +171,17 @@ class DirectCameraControl(PandaObject):
         
     def SpawnMoveToView(self, chan, view):
         # Kill any existing tasks
-	taskMgr.removeTasksNamed('manipulateCamera')
+        taskMgr.removeTasksNamed('manipulateCamera')
         # Calc hprOffset
-	hprOffset = VBase3()
-
+        hprOffset = VBase3()
         if view == 8:
             # Try the next roll angle
             self.orthoViewRoll = (self.orthoViewRoll + 90.0) % 360.0
             # but use the last view
             view = self.lastView
-        
+        else:
+            self.orthoViewRoll = 0.0
+        # Adjust offset based on specified view
         if view == 1:
             hprOffset.set(180., 0., 0.)
         elif view == 2:
@@ -180,30 +197,25 @@ class DirectCameraControl(PandaObject):
         elif view == 7:
             hprOffset.set(135., -35.264, 0.)
         # Position target
-	self.relNodePath.setPosHpr(self.coaMarker, self.zeroBaseVec,
+        self.relNodePath.setPosHpr(self.coaMarker, self.zeroBaseVec,
                                    hprOffset)
-	# Scale center vec by current distance to target
-	offsetDistance = Vec3(chan.camera.getPos(self.relNodePath) - 
+        # 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.centerVec * (-1.0 * offsetDistance)
+        # Now put the relNodePath at that point
+        self.relNodePath.setPosHpr(self.relNodePath,
                                    scaledCenterVec,
                                    self.zeroBaseVec)
-
-        # Store this view for next time
-        # Reset orthoViewRoll if you change views
-        if view != self.lastView:
-            self.orthoViewRoll = 0.0
-            
+        # Record view for next time around
         self.lastView = view
-	chan.camera.lerpPosHpr(self.zeroPoint,
+        chan.camera.lerpPosHpr(self.zeroPoint,
                                VBase3(0,0,self.orthoViewRoll),
                                CAM_MOVE_DURATION,
                                other = self.relNodePath,
                                blendType = 'easeInOut',
                                task = 'manipulateCamera')
+
         
     def swingCamAboutWidget(self, chan, degrees, t):
         # Remove existing camera manipulation task
@@ -231,6 +243,8 @@ class DirectCameraControl(PandaObject):
     def spawnHPanYZoom(self):
         # Kill any existing tasks
 	taskMgr.removeTasksNamed('manipulateCamera')
+        # hide the marker
+        self.coaMarker.hide()
         # Negate vec to give it the correct sense for mouse motion below
         targetVector = self.coa * -1
         t = Task.Task(self.HPanYZoomTask)
@@ -253,6 +267,8 @@ class DirectCameraControl(PandaObject):
     def spawnXZTranslateOrHPPan(self):
         # Kill any existing tasks
 	taskMgr.removeTasksNamed('manipulateCamera')
+        # Hide the marker
+        self.coaMarker.hide()
         t = Task.Task(self.XZTranslateOrHPPanTask)
         t.scaleFactor = (self.coaDist / self.chan.near)
         taskMgr.spawnTaskNamed(t, 'manipulateCamera')
@@ -279,6 +295,8 @@ class DirectCameraControl(PandaObject):
     def spawnXZTranslate(self):
         # Kill any existing tasks
 	taskMgr.removeTasksNamed('manipulateCamera')
+        # Hide the marker
+        self.coaMarker.hide()
         t = Task.Task(self.XZTranslateTask)
         t.scaleFactor = (self.coaDist / self.chan.near)
         taskMgr.spawnTaskNamed(t, 'manipulateCamera')
@@ -316,6 +334,8 @@ class DirectCameraControl(PandaObject):
     def spawnHPPan(self):
         # Kill any existing tasks
 	taskMgr.removeTasksNamed('manipulateCamera')
+        # Hide the marker
+        self.coaMarker.hide()
         t = Task.Task(self.HPPanTask)
         taskMgr.spawnTaskNamed(t, 'manipulateCamera')
 

+ 12 - 0
direct/src/directutil/DirectGeometry.py

@@ -56,3 +56,15 @@ class LineNodePath(NodePath):
 
     def getVertexColor( self ):
         return self.lineSegs.getVertexColor()
+
+
+##
+## Given a point in space, and a direction, find the point of intersection
+## of that ray with a plane at the specified origin, with the specified normal
+def planeIntersect (lineOrigin, lineDir, planeOrigin, normal):
+    t = 0
+    offset = planeOrigin - lineOrigin
+    t = offset.dot(normal) / lineDir.dot(normal)
+    hitPt = lineDir * t
+    return hitPt + lineOrigin
+

+ 214 - 190
direct/src/directutil/DirectSelection.py

@@ -3,174 +3,6 @@ from DirectGeometry import *
 from DirectSelection 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() )
-        # Don't pay the penalty of drawing this collision ray
-        self.rayCollisionNodePath.hide()
-        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 objectToHitPt(self, index):
-        return self.cq.getEntry(index).getIntoIntersectionPoint()
-
-    def camToHitPt(self, index):
-        # Get the specified entry
-        entry = self.cq.getEntry(index)
-        hitPt = entry.getIntoIntersectionPoint()
-        # Convert point from object local space to camera space
-        return entry.getInvWrtSpace().xformPoint(hitPt)
-
-
-class DirectBoundingBox:
-    def __init__(self, nodePath):
-        # Record the node path
-        self.nodePath = nodePath
-        # Compute bounds, min, max, etc.
-        self.computeBounds()
-        # Generate the bounding box
-        self.lines = self.createBBoxLines()
-
-    def computeBounds(self):
-        self.bounds = self.nodePath.getBounds()
-        self.center = self.bounds.getCenter()
-        self.radius = self.bounds.getRadius()
-        self.min = Point3(self.center - Point3(self.radius))
-        self.max = Point3(self.center + Point3(self.radius))
-        
-    def createBBoxLines(self):
-        # Create a line segments object for the bbox
-        lines = LineNodePath(hidden)
-        lines.node().setName('bboxLines')
-        lines.setColor( VBase4( 1., 0., 0., 1. ) )
-	lines.setThickness( 0.5 )
-
-        minX = self.min[0]
-        minY = self.min[1]
-        minZ = self.min[2]
-        maxX = self.max[0]
-        maxY = self.max[1]
-        maxZ = self.max[2]
-        
-        # Bottom face
-	lines.moveTo( minX, minY, minZ )
-	lines.drawTo( maxX, minY, minZ )
-	lines.drawTo( maxX, maxY, minZ )
-	lines.drawTo( minX, maxY, minZ )
-	lines.drawTo( minX, minY, minZ )
-
-	# Front Edge/Top face
-	lines.drawTo( minX, minY, maxZ )
-	lines.drawTo( maxX, minY, maxZ )
-	lines.drawTo( maxX, maxY, maxZ )
-	lines.drawTo( minX, maxY, maxZ )
-	lines.drawTo( minX, minY, maxZ )
-
-	# Three remaining edges
-	lines.moveTo( maxX, minY, minZ )
-	lines.drawTo( maxX, minY, maxZ )
-	lines.moveTo( maxX, maxY, minZ )
-	lines.drawTo( maxX, maxY, maxZ )
-	lines.moveTo( minX, maxY, minZ )
-	lines.drawTo( minX, maxY, maxZ )
-
-        # Create and return bbox lines
-	lines.create()
-        return lines
-
-    def updateBBoxLines(self):
-        ls = self.lines.lineSegs
-        
-        minX = self.min[0]
-        minY = self.min[1]
-        minZ = self.min[2]
-        maxX = self.max[0]
-        maxY = self.max[1]
-        maxZ = self.max[2]
-        
-        # Bottom face
-	ls.setVertex( 0, minX, minY, minZ )
-	ls.setVertex( 1, maxX, minY, minZ )
-	ls.setVertex( 2, maxX, maxY, minZ )
-	ls.setVertex( 3, minX, maxY, minZ )
-	ls.setVertex( 4, minX, minY, minZ )
-
-	# Front Edge/Top face
-	ls.setVertex( 5, minX, minY, maxZ )
-	ls.setVertex( 6, maxX, minY, maxZ )
-	ls.setVertex( 7, maxX, maxY, maxZ )
-	ls.setVertex( 8, minX, maxY, maxZ )
-	ls.setVertex( 9, minX, minY, maxZ )
-
-	# Three remaining edges
-	ls.setVertex( 10, maxX, minY, minZ )
-	ls.setVertex( 11, maxX, minY, maxZ )
-	ls.setVertex( 12, maxX, maxY, minZ )
-	ls.setVertex( 13, maxX, maxY, maxZ )
-	ls.setVertex( 14, minX, maxY, minZ )
-	ls.setVertex( 15, minX, maxY, maxZ )
-
-    def getBounds(self):
-        # Get a node path's bounds
-        nodeBounds = self.nodePath.node().getBound()
-        for child in self.nodePath.getChildrenAsList():
-            nodeBounds.extendBy(child.getBottomArc().getBound())
-            return nodeBounds.makeCopy()
-
-    def show(self):
-        self.lines.reparentTo(self.nodePath)
-
-    def hide(self):
-        self.lines.reparentTo(hidden)
-        
-    def getCenter(self):
-        return self.center
-
-    def getRadius(self):
-        return self.radius
-
-    def getMin(self):
-        return self.min
-
-    def getMax(self):
-        return self.max
-
-    def vecAsString(self, vec):
-        return '%.2f %.2f %.2f' % (vec[0], vec[1], vec[2])
-
-    def __repr__(self):
-        return (`self.__class__` + 
-                '\nNodePath:\t%s\n' % self.name +
-                'Min:\t\t%s\n' % self.vecAsString(self.min) +
-                'Max:\t\t%s\n' % self.vecAsString(self.max) +
-                'Center:\t\t%s\n' % self.vecAsString(self.center) +
-                'Radius:\t\t%.2f' % self.radius
-                )
-
-
 class DirectNodePath(NodePath):
     # A node path augmented with info, bounding box, and utility methods
     def __init__(self, nodePath):
@@ -181,10 +13,17 @@ class DirectNodePath(NodePath):
         self.name = self.getNodePathName()
         # Create a bounding box
         self.bbox = DirectBoundingBox(self)
+        center = self.bbox.getCenter()
+        # Create matrix to hold the offset between the nodepath
+        # and its center of action (COA)
+        self.mCoa2Dnp = Mat4()
+        self.mCoa2Dnp.assign(Mat4.identMat())
+        self.mCoa2Dnp.setRow(3, Vec4(center[0], center[1], center[2], 1))
+        # Transform from nodePath to widget
+        self.mDnp2Widget = Mat4()
+        self.mDnp2Widget.assign(Mat4.identMat())
         # Use value of this pointer as unique ID
         self.id = self.node().this
-        # Show bounding box
-        self.highlight()
 
     def highlight(self):
         self.bbox.show()
@@ -207,8 +46,10 @@ class DirectNodePath(NodePath):
     def __repr__(self):
         return ('NodePath:\t%s\n' % self.name)
 
+
 class SelectedNodePaths(PandaObject):
-    def __init__(self):
+    def __init__(self,direct):
+        self.direct = direct
         self.selectedDict = {}
         self.deselectedDict = {}
         self.last = None
@@ -240,6 +81,8 @@ class SelectedNodePaths(PandaObject):
             else:
                 # Didn't find it, create a new selectedNodePath instance
                 dnp = DirectNodePath(nodePath)
+                # Show its bounding box
+                dnp.highlight()
             # Add it to the selected dictionary
             self.selectedDict[dnp.id] = dnp
         # And update last
@@ -281,6 +124,18 @@ class SelectedNodePaths(PandaObject):
         for key in duplicateKeys:
             func(self.deselectedDict[key])
 
+    def getWrtAll(self):
+        self.forEachSelectedNodePathDo(self.getWrt)
+
+    def getWrt(self, nodePath):
+        nodePath.mDnp2Widget.assign(nodePath.getMat(self.direct.widget))
+
+    def moveWrtWidgetAll(self):
+        self.forEachSelectedNodePathDo(self.moveWrtWidget)
+
+    def moveWrtWidget(self, nodePath):
+        nodePath.setMat(self.direct.widget, nodePath.mDnp2Widget)
+
     def deselectAll(self):
         self.forEachSelectedNodePathDo(self.deselect)
 
@@ -327,22 +182,191 @@ class SelectedNodePaths(PandaObject):
     def getNumSelected(self):
         return len(self.selectedDict.keys())
 
-"""
-dd = loader.loadModel(r"I:\beta\toons\install\neighborhoods\donalds_dock")
-dd.reparentTo(render)
-
-# Operations on cq
-cq.getNumEntries()
-cq.getEntry(0).getIntoNode()
-cq.getEntry(0).getIntoNode().getName()
-print cq.getEntry(i).getIntoIntersectionPoint()
-
-for i in range(0,bobo.cq.getNumEntries()):
-    name = bobo.cq.getEntry(i).getIntoNode().getName()
-    if not name:
-        name = "<noname>"
-    print name
-    print bobo.cq.getEntry(i).getIntoIntersectionPoint()[0],
-    print bobo.cq.getEntry(i).getIntoIntersectionPoint()[1],
-    print bobo.cq.getEntry(i).getIntoIntersectionPoint()[2]
-"""
+
+class DirectBoundingBox:
+    def __init__(self, nodePath):
+        # Record the node path
+        self.nodePath = nodePath
+        # Compute bounds, min, max, etc.
+        self.computeBounds()
+        # Generate the bounding box
+        self.lines = self.createBBoxLines()
+
+    def computeBounds(self):
+        self.bounds = self.nodePath.getBounds()
+        self.center = self.bounds.getCenter()
+        self.radius = self.bounds.getRadius()
+        self.min = Point3(self.center - Point3(self.radius))
+        self.max = Point3(self.center + Point3(self.radius))
+        
+    def createBBoxLines(self):
+        # Create a line segments object for the bbox
+        lines = LineNodePath(hidden)
+        lines.node().setName('bboxLines')
+        lines.setColor( VBase4( 1., 0., 0., 1. ) )
+	lines.setThickness( 0.5 )
+
+        minX = self.min[0]
+        minY = self.min[1]
+        minZ = self.min[2]
+        maxX = self.max[0]
+        maxY = self.max[1]
+        maxZ = self.max[2]
+        
+        # Bottom face
+	lines.moveTo( minX, minY, minZ )
+	lines.drawTo( maxX, minY, minZ )
+	lines.drawTo( maxX, maxY, minZ )
+	lines.drawTo( minX, maxY, minZ )
+	lines.drawTo( minX, minY, minZ )
+
+	# Front Edge/Top face
+	lines.drawTo( minX, minY, maxZ )
+	lines.drawTo( maxX, minY, maxZ )
+	lines.drawTo( maxX, maxY, maxZ )
+	lines.drawTo( minX, maxY, maxZ )
+	lines.drawTo( minX, minY, maxZ )
+
+	# Three remaining edges
+	lines.moveTo( maxX, minY, minZ )
+	lines.drawTo( maxX, minY, maxZ )
+	lines.moveTo( maxX, maxY, minZ )
+	lines.drawTo( maxX, maxY, maxZ )
+	lines.moveTo( minX, maxY, minZ )
+	lines.drawTo( minX, maxY, maxZ )
+
+        # Create and return bbox lines
+	lines.create()
+        return lines
+
+    def updateBBoxLines(self):
+        ls = self.lines.lineSegs
+        
+        minX = self.min[0]
+        minY = self.min[1]
+        minZ = self.min[2]
+        maxX = self.max[0]
+        maxY = self.max[1]
+        maxZ = self.max[2]
+        
+        # Bottom face
+	ls.setVertex( 0, minX, minY, minZ )
+	ls.setVertex( 1, maxX, minY, minZ )
+	ls.setVertex( 2, maxX, maxY, minZ )
+	ls.setVertex( 3, minX, maxY, minZ )
+	ls.setVertex( 4, minX, minY, minZ )
+
+	# Front Edge/Top face
+	ls.setVertex( 5, minX, minY, maxZ )
+	ls.setVertex( 6, maxX, minY, maxZ )
+	ls.setVertex( 7, maxX, maxY, maxZ )
+	ls.setVertex( 8, minX, maxY, maxZ )
+	ls.setVertex( 9, minX, minY, maxZ )
+
+	# Three remaining edges
+	ls.setVertex( 10, maxX, minY, minZ )
+	ls.setVertex( 11, maxX, minY, maxZ )
+	ls.setVertex( 12, maxX, maxY, minZ )
+	ls.setVertex( 13, maxX, maxY, maxZ )
+	ls.setVertex( 14, minX, maxY, minZ )
+	ls.setVertex( 15, minX, maxY, maxZ )
+
+    def getBounds(self):
+        # Get a node path's bounds
+        nodeBounds = self.nodePath.node().getBound()
+        for child in self.nodePath.getChildrenAsList():
+            nodeBounds.extendBy(child.getBottomArc().getBound())
+            return nodeBounds.makeCopy()
+
+    def show(self):
+        self.lines.reparentTo(self.nodePath)
+
+    def hide(self):
+        self.lines.reparentTo(hidden)
+        
+    def getCenter(self):
+        return self.center
+
+    def getRadius(self):
+        return self.radius
+
+    def getMin(self):
+        return self.min
+
+    def getMax(self):
+        return self.max
+
+    def vecAsString(self, vec):
+        return '%.2f %.2f %.2f' % (vec[0], vec[1], vec[2])
+
+    def __repr__(self):
+        return (`self.__class__` + 
+                '\nNodePath:\t%s\n' % self.nodePath.getNodePathName() +
+                'Min:\t\t%s\n' % self.vecAsString(self.min) +
+                'Max:\t\t%s\n' % self.vecAsString(self.max) +
+                'Center:\t\t%s\n' % self.vecAsString(self.center) +
+                'Radius:\t\t%.2f' % self.radius
+                )
+
+
+class SelectionRay:
+    def __init__(self, camera):
+        # Record the camera associated with this selection ray
+        self.camera = camera
+        # Create a collision node
+        self.rayCollisionNodePath = camera.attachNewNode( CollisionNode() )
+        # Don't pay the penalty of drawing this collision ray
+        self.rayCollisionNodePath.hide()
+        self.rayCollisionNode = self.rayCollisionNodePath.node()
+        # Intersect with geometry to begin with
+        self.collideWithGeom()
+        # Create a collision ray
+        self.ray = CollisionRay()
+        # Add the ray to the collision Node
+        self.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(self.rayCollisionNode, self.cq )
+
+    def pickGeom(self, targetNodePath, mouseX, mouseY):
+        self.collideWithGeom()
+        return self.pick(targetNodePath, mouseX, mouseY)
+
+    def pickWidget(self, targetNodePath, mouseX, mouseY):
+        self.collideWithWidget()
+        return self.pick(targetNodePath, mouseX, mouseY)
+
+    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 collideWithGeom(self):
+        self.rayCollisionNode.setIntoCollideMask(BitMask32().allOff())
+        self.rayCollisionNode.setFromCollideMask(BitMask32().allOff())
+        self.rayCollisionNode.setCollideGeom(1)
+
+    def collideWithWidget(self):
+        self.rayCollisionNode.setIntoCollideMask(BitMask32().allOff())
+        mask = BitMask32()
+        mask.setWord(0x80000000)
+        self.rayCollisionNode.setFromCollideMask(mask)
+        self.rayCollisionNode.setCollideGeom(0)
+
+    def objectToHitPt(self, index):
+        return self.cq.getEntry(index).getIntoIntersectionPoint()
+
+    def camToHitPt(self, index):
+        # Get the specified entry
+        entry = self.cq.getEntry(index)
+        hitPt = entry.getIntoIntersectionPoint()
+        # Convert point from object local space to camera space
+        return entry.getInvWrtSpace().xformPoint(hitPt)
+

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

@@ -14,31 +14,30 @@ class DirectSession(PandaObject):
         for camera in base.cameraList:
             self.contextList.append(DisplayRegionContext(base.win, camera))
             self.iRayList.append(SelectionRay(camera))
-        self.chanCenter = self.getChanData(0)
+        self.chan = self.getChanData(0)
+        self.camera = base.cameraList[0]
 
-        self.cameraControls = DirectCameraControl(self)
-        self.manipulationControls = DirectManipulationControl(self)
+        self.cameraControl = DirectCameraControl(self)
+        self.manipulationControl = DirectManipulationControl(self)
+        self.useObjectHandles()
 
         # Initialize the collection of selected nodePaths
-        self.selected = SelectedNodePaths()
+        self.selected = SelectedNodePaths(self)
 
         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.createObjectHandles()
-        self.useObjectHandles()
-        
         self.fControl = 0
         self.fAlt = 0
         self.fShift = 0
         self.in2DWidget = 0
 
+        self.pos = VBase3()
+        self.hpr = VBase3()
+        self.scale = VBase3()
+
         self.iRay = self.iRayList[0]
-        self.iRay.rayCollisionNodePath.node().setFromCollideMask(
-            BitMask32().allOff())
-        self.iRay.rayCollisionNodePath.node().setIntoCollideMask(
-            BitMask32().allOff())
         self.hitPt = Point3(0.0)
 
         self.actionEvents = [('select', self.select),
@@ -52,7 +51,6 @@ class DirectSession(PandaObject):
                           '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']
@@ -64,36 +62,38 @@ class DirectSession(PandaObject):
             self.readout.reparentTo(render2d)
             self.readout.setText(dnp.name)
             # Show the manipulation widget
-            self.objectHandles.reparentTo(render)
-            # Adjust its size
-            self.objectHandles.setScale(dnp.getRadius())
+            self.widget.reparentTo(render)
 
-            # TBD Compute widget COA
-            
             # Update camera controls coa to this point
-            wrtMat = dnp.getMat(base.camera)
-            self.cameraControls.updateCoa(
-                wrtMat.xformPoint(dnp.getCenter()))
+            # Coa2Camera = Coa2Dnp * Dnp2Camera
+            mCoa2Camera = dnp.mCoa2Dnp * dnp.getMat(base.camera)
+            row = mCoa2Camera.getRow(3)
+            coa = Vec3(row[0], row[1], row[2])
+            self.cameraControl.updateCoa(coa)
+
+            # Adjust widgets size
+            self.widget.setScale(dnp.getRadius())
             
             # Spawn task to have object handles follow the selected object
             taskMgr.removeTasksNamed('followSelectedNodePath')
             t = Task.Task(self.followSelectedNodePathTask)
-            t.nodePath = dnp
+            t.dnp = dnp
             taskMgr.spawnTaskNamed(t, 'followSelectedNodePath')
             # Send an message marking the event
             messenger.send('selectedNodePath', [dnp])
 
     def followSelectedNodePathTask(self, state):
-        nodePath = state.nodePath
-        pos = nodePath.getPos(render)
-        self.objectHandles.setPos(pos)
+        mCoa2Render = state.dnp.mCoa2Dnp * state.dnp.getMat(render)
+        mCoa2Render.decomposeMatrix(
+            self.scale,self.hpr,self.pos,getDefaultCoordinateSystem())
+        self.widget.setPosHpr(self.pos,self.hpr)
         return Task.cont
 
     def deselect(self, nodePath):
-        dnp = self.snp.deselect(nodePath)
+        dnp = self.selected.deselect(nodePath)
         if dnp:
             # Hide the manipulation widget
-            self.objectHandles.reparentTo(hidden)
+            self.widget.reparentTo(hidden)
             self.readout.reparentTo(hidden)
             self.readout.setText(' ')
             taskMgr.removeTasksNamed('followSelectedNodePath')
@@ -103,7 +103,7 @@ class DirectSession(PandaObject):
     def deselectAll(self):
         self.selected.deselectAll()
         # Hide the manipulation widget
-        self.objectHandles.reparentTo(hidden)
+        self.widget.reparentTo(hidden)
         self.readout.reparentTo(hidden)
         self.readout.setText(' ')
         taskMgr.removeTasksNamed('followSelectedNodePath')
@@ -116,9 +116,9 @@ class DirectSession(PandaObject):
         for context in self.contextList:
             context.spawnContextTask()
 	# Turn on mouse Flying
-	self.cameraControls.enableMouseFly()
+	self.cameraControl.enableMouseFly()
         # Turn on object manipulation
-        self.manipulationControls.enableManipulation()
+        self.manipulationControl.enableManipulation()
 	# Accept appropriate hooks
 	self.enableKeyEvents()
 	self.enableMouseEvents()
@@ -129,9 +129,9 @@ class DirectSession(PandaObject):
         for context in self.contextList:
             context.removeContextTask()
 	# Turn off camera fly
-	self.cameraControls.disableMouseFly()
+	self.cameraControl.disableMouseFly()
         # Turn off object manipulation
-        self.manipulationControls.disableManipulation()
+        self.manipulationControl.disableManipulation()
 	self.disableKeyEvents()
 	self.disableMouseEvents()
 	self.disableActionEvents()
@@ -141,7 +141,7 @@ class DirectSession(PandaObject):
 	for context in self.contextList:
             context.removeContextTask()
 	# Turn off camera fly
-	self.cameraControls.disableMouseFly()
+	self.cameraControl.disableMouseFly()
 	# Ignore keyboard and action events
 	self.disableKeyEvents()
 	self.disableActionEvents()
@@ -167,7 +167,7 @@ class DirectSession(PandaObject):
             self.accept(event, self.inputHandler, [event])
 
     def disableActionEvents(self):
-        for event in self.actionEvents:
+        for event, method in self.actionEvents:
             self.ignore(event)
 
     def disableKeyEvents(self):
@@ -179,7 +179,7 @@ class DirectSession(PandaObject):
             self.ignore(event)
 
     def useObjectHandles(self):
-        self.widget = self.objectHandles
+        self.widget = self.manipulationControl.objectHandles
 
     def hideReadout(self):
 	self.readout.reparentTo(hidden)
@@ -236,32 +236,6 @@ class DirectSession(PandaObject):
             base.toggleTexture()
         elif input == 'w':
             base.toggleWireframe()
-
-    def createObjectHandles(self):
-	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
-	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 
-	ohLines.moveTo( 1.2, 0.0, 0.0 )
-        for ang in range(0, 360, 10):
-            ohLines.drawTo( (1.2 * math.cos(deg2Rad(ang))),
-                            (1.2 * math.sin(deg2Rad(ang))),
-                            0.0 )
-
-	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):
@@ -270,6 +244,7 @@ class DisplayRegionContext(PandaObject):
         self.cam = camera.getChild(0)
         self.camNode = self.cam.getNode(0)
         self.mouseData = win.getMouseData(0)
+        self.nearVec = Vec3(0)
         self.mouseX = 0.0
         self.mouseY = 0.0
 
@@ -303,17 +278,27 @@ class DisplayRegionContext(PandaObject):
         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
+        self.left = -self.nearWidth/2.0
+        self.right = self.nearWidth/2.0
+        self.top = self.nearHeight/2.0
+        self.bottom = -self.nearHeight/2.0
         # Mouse Data
         # Last frame
         self.mouseLastX = self.mouseX
         self.mouseLastY = self.mouseY
-        # This frame
+        # Values for this frame
+        # Pixel coordinates of the mouse
         self.mousePixelX = self.mouseData.getX()
         self.mousePixelY = self.mouseData.getY()
+        # This ranges from -1 to 1
         self.mouseX = ((self.mousePixelX / float(self.width)) * 2.0) - 1.0
         self.mouseY = ((self.mousePixelY / float(self.height)) * -2.0) + 1.0
+        # Delta percent of window the mouse moved
         self.mouseDeltaX = self.mouseX - self.mouseLastX
         self.mouseDeltaY = self.mouseY - self.mouseLastY
+        self.nearVec.set((self.nearWidth/2.0) * self.mouseX,
+                         self.near,
+                         (self.nearHeight/2.0) * self.mouseY)
         # Continue the task
         return Task.cont
 

+ 0 - 2
direct/src/directutil/DirectSessionGlobal.py

@@ -4,9 +4,7 @@ from DirectSession import *
 # If specified in the user's Configrc, create the direct session
 if base.wantDIRECT:
     direct = base.direct = DirectSession()
-    chanCenter = direct.chanCenter
 else:
     # Otherwise set the values to None
     direct = base.direct = None
-    chanCenter = None
 

+ 24 - 5
direct/src/extensions/NodePath-extensions.py

@@ -51,12 +51,31 @@
         self.hideSiblings()
 
     def remove(self):
-	# Send message in case anyone needs to do something
+        from PandaObject import *
+        # Send message in case anyone needs to do something
         # before node is deleted
-	messenger.send('preRemoveNodePath', [self])
-	# Remove nodePath
-	self.reparentTo(hidden)
-	self.removeNode()
+        messenger.send('preRemoveNodePath', [self])
+        # Remove nodePath
+        self.reparentTo(hidden)
+        self.removeNode()
+
+    def reversels(self):
+        ancestry = self.getAncestry()
+        indentString = ""
+        for nodePath in ancestry:
+            type = nodePath.node().getType().getName()
+            name = nodePath.getNodePathName()
+            print indentString + type + "  " + name
+            indentString = indentString + " "
+
+    def getAncestry(self):
+        from PandaObject import *
+        if self.node() != render.node():
+            ancestry = self.getParent().getAncestry()
+            ancestry.append(self)
+            return ancestry
+        else:
+            return [self]
 
     # private methods
     

+ 3 - 0
direct/src/showbase/ShowBase.py

@@ -27,6 +27,9 @@ class ShowBase:
         import Loader
 
         self.initialState = NodeAttributes()
+        # Set a default "off color" (i.e. use poly color) for color transitions
+        self.initialState.setAttribute(ColorTransition.getClassType(),
+                                       ColorAttribute())
         self.renderTop = NodePath(NamedNode('renderTop'))
         self.render = self.renderTop.attachNewNode('render')
         self.hidden = NodePath(NamedNode('hidden'))

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

@@ -10,5 +10,6 @@ render = base.render
 hidden = base.hidden
 camera = base.camera
 loader = base.loader
+ostream = Notify.out()
 run = base.run
 tkroot = base.tkroot