Browse Source

Fixes to make compatible with new panda

Mark Mine 24 years ago
parent
commit
ce32c8c748

+ 26 - 16
direct/src/cluster/ClusterClient.py

@@ -1,14 +1,10 @@
 """ClusterClient: Master for mutlipiping or PC clusters.  """
 """ClusterClient: Master for mutlipiping or PC clusters.  """
 
 
 from PandaModules import *
 from PandaModules import *
-from TaskManagerGlobal import *
-from ShowBaseGlobal import *
-import Task
+from ClusterMsgs import *
 import DirectNotifyGlobal
 import DirectNotifyGlobal
-import Datagram
 import DirectObject
 import DirectObject
-from ClusterMsgs import *
-import time
+import Task
 
 
 class ClusterConfigItem:
 class ClusterConfigItem:
     def __init__(self, serverFunction, serverName, port):
     def __init__(self, serverFunction, serverName, port):
@@ -79,10 +75,12 @@ class DisplayConnection:
 
 
     # the following should only be called by a synchronized cluster manger
     # the following should only be called by a synchronized cluster manger
     def getSwapReady(self):
     def getSwapReady(self):
-        datagram = self.msgHandler.blockingRead(self.qcr)
-        (type,dgi) = self.msgHandler.readHeader(datagram)
-        if type != CLUSTER_SWAP_READY:
-            self.notify.warning( ('was expecting SWAP_READY, got %d' % type) )
+        while 1:
+            (datagram, dgi,type) = self.msgHandler.blockingRead(self.qcr)
+            if type == CLUSTER_SWAP_READY:
+                break
+            else:
+                self.notify.warning('was expecting SWAP_READY, got %d' % type)
 
 
     # the following should only be called by a synchronized cluster manger
     # the following should only be called by a synchronized cluster manger
     def sendSwapNow(self):
     def sendSwapNow(self):
@@ -97,6 +95,13 @@ class DisplayConnection:
         datagram = self.msgHandler.makeCommandStringDatagram(commandString)
         datagram = self.msgHandler.makeCommandStringDatagram(commandString)
         self.cw.send(datagram, self.tcpConn)
         self.cw.send(datagram, self.tcpConn)
 
 
+    def sendExit(self):
+        ClusterManager.notify.debug( 
+            "display connect send exit, packet %d" %
+            self.msgHandler.packetNumber)
+        datagram = self.msgHandler.makeExitDatagram()
+        self.cw.send(datagram, self.tcpConn)
+
 class ClusterManager(DirectObject.DirectObject):
 class ClusterManager(DirectObject.DirectObject):
     notify = DirectNotifyGlobal.directNotify.newCategory("ClusterClient")
     notify = DirectNotifyGlobal.directNotify.newCategory("ClusterClient")
     MGR_NUM = 1000000
     MGR_NUM = 1000000
@@ -127,9 +132,7 @@ class ClusterManager(DirectObject.DirectObject):
             server.sendMoveCam(xyz,hpr)
             server.sendMoveCam(xyz,hpr)
 
 
     def startMoveCamTask(self):
     def startMoveCamTask(self):
-        task = Task.Task(self.moveCameraTask,49)
-        taskMgr.add(task, "moveCamTask")
-        return None        
+        taskMgr.add(self.moveCameraTask, "moveCamTask", 49)
 
 
     def moveCameraTask(self,task):
     def moveCameraTask(self,task):
         self.moveCamera(
         self.moveCamera(
@@ -142,7 +145,15 @@ class ClusterManager(DirectObject.DirectObject):
         for server in self.serverList:
         for server in self.serverList:
             server.sendCommandString(commandString)
             server.sendCommandString(commandString)
         # Execute locally
         # Execute locally
-        exec( commandString, globals() )
+        exec( commandString, globals())
+
+    def exit(self):
+        # Execute remotely
+        for server in self.serverList:
+            server.sendExit()
+        # Execute locally
+        import sys
+        sys.exit()
 
 
 class ClusterManagerSync(ClusterManager):
 class ClusterManagerSync(ClusterManager):
 
 
@@ -154,8 +165,7 @@ class ClusterManagerSync(ClusterManager):
         self.startSwapCoordinatorTask()
         self.startSwapCoordinatorTask()
 
 
     def startSwapCoordinatorTask(self):
     def startSwapCoordinatorTask(self):
-        task = Task.Task(self.swapCoordinator,51)
-        taskMgr.add(task, "clientSwapCoordinator")
+        taskMgr.add(self.swapCoordinator, "clientSwapCoordinator", 51)
         return None
         return None
 
 
     def swapCoordinator(self,task):
     def swapCoordinator(self,task):

+ 3 - 3
direct/src/cluster/ClusterConfig.py

@@ -23,7 +23,7 @@ ClientConfigs = {
                              {'pos' : Vec3(0),
                              {'pos' : Vec3(0),
                               'hpr' : Vec3(60,0,0)}
                               'hpr' : Vec3(60,0,0)}
                              ],
                              ],
-    'cavetest'            : [{'pos' : Vec3(-0.105, -0.020, 5.000),
+    'cavetest-old'            : [{'pos' : Vec3(-0.105, -0.020, 5.000),
                               'hpr' : Vec3(51.213, 0.000, 0.000),
                               'hpr' : Vec3(51.213, 0.000, 0.000),
                               'focal length' : 0.809,
                               'focal length' : 0.809,
                               'film size' : (1.000, 0.831),
                               'film size' : (1.000, 0.831),
@@ -48,7 +48,7 @@ ClientConfigs = {
                               'film offset' : (0.000, 0.173),
                               'film offset' : (0.000, 0.173),
                               },
                               },
                              ],
                              ],
-    'cavetest-all'        : [{'pos' : Vec3(-0.105, -0.020, 5.000),
+    'cavetest'        : [{'pos' : Vec3(-0.105, -0.020, 5.000),
                               'hpr' : Vec3(51.213, 0.000, 0.000),
                               'hpr' : Vec3(51.213, 0.000, 0.000),
                               'focal length' : 0.809,
                               'focal length' : 0.809,
                               'film size' : (1.000, 0.831),
                               'film size' : (1.000, 0.831),
@@ -100,7 +100,7 @@ def createClusterManager():
     displayConfigs = []
     displayConfigs = []
     configList = ClientConfigs[clusterConfig]
     configList = ClientConfigs[clusterConfig]
     numConfigs = len(configList)
     numConfigs = len(configList)
-    for i in range(numConfigs):
+    for i in range(1,numConfigs):
         configData = configList[i]
         configData = configList[i]
         serverConfigName = 'display%d' % i
         serverConfigName = 'display%d' % i
         serverString = base.config.GetString(serverConfigName, '')
         serverString = base.config.GetString(serverConfigName, '')

+ 55 - 41
direct/src/cluster/ClusterMsgs.py

@@ -7,70 +7,77 @@
 #    recieved are handled outside of here, after the header (message type
 #    recieved are handled outside of here, after the header (message type
 #    and number) are read here.
 #    and number) are read here.
 
 
+from PandaModules import *
+import Datagram
+import time
+
 #these are the types of messages that are currently supported.
 #these are the types of messages that are currently supported.
-CLUSTER_NOTHING    = -1
+CLUSTER_NONE    = 0
 CLUSTER_CAM_OFFSET = 1
 CLUSTER_CAM_OFFSET = 1
 CLUSTER_CAM_FRUSTUM = 2
 CLUSTER_CAM_FRUSTUM = 2
-CLUSTER_POS_UPDATE = 3
+CLUSTER_CAM_MOVEMENT = 3
 CLUSTER_SWAP_READY = 4
 CLUSTER_SWAP_READY = 4
 CLUSTER_SWAP_NOW   = 5
 CLUSTER_SWAP_NOW   = 5
 CLUSTER_COMMAND_STRING = 6
 CLUSTER_COMMAND_STRING = 6
+CLUSTER_EXIT = 100
 
 
 #Port number for cluster rendering
 #Port number for cluster rendering
 CLUSTER_PORT = 1970
 CLUSTER_PORT = 1970
 
 
-from ShowBaseGlobal import *
-from PandaModules import *
-from TaskManagerGlobal import *
-import Task
-import DirectNotifyGlobal
-import Datagram
-import time
-
 class MsgHandler:
 class MsgHandler:
     """MsgHandler: wrapper for PC clusters/multi-piping networking"""
     """MsgHandler: wrapper for PC clusters/multi-piping networking"""
     def __init__(self,packetStart, notify):
     def __init__(self,packetStart, notify):
-        #packetStart can be used to distinguish which MsgHandler sends a
-        #given packet.
+        # packetStart can be used to distinguish which MsgHandler sends a
+        # given packet.
         self.packetNumber = packetStart
         self.packetNumber = packetStart
         self.notify = notify
         self.notify = notify
 
 
     def nonBlockingRead(self,qcr):
     def nonBlockingRead(self,qcr):
-        availGetVal = qcr.dataAvailable()
-        if availGetVal:
+        """
+        Return a datagram iterator and type if data is available on the
+        queued connection reader
+        """
+        if qcr.dataAvailable():
             datagram = NetDatagram()
             datagram = NetDatagram()
-            readRetVal = qcr.getData(datagram)
-            if readRetVal:
-                dgi = DatagramIterator(datagram)
-                number = dgi.getUint32()
-                type = dgi.getUint8()
-                self.notify.debug( ("Packet %d type %d recieved" % (number,type)) )    
+            if qcr.getData(datagram):
+                (dgi, type) = self.readHeader(datagram)
             else:
             else:
+                dgi = None
+                type = CLUSTER_NONE
                 self.notify.warning("getData returned false")
                 self.notify.warning("getData returned false")
         else:
         else:
-            type = CLUSTER_NOTHING
             dgi = None
             dgi = None
-        return (type,dgi)
-
-    def readHeader(self,datagram):
-        dgi = DatagramIterator(datagram)
-        number = dgi.getUint32()
-        type = dgi.getUint8()
-        self.notify.debug( ("Packet %d type %d recieved" % (number,type)) )
-        return (type,dgi)        
+            type = CLUSTER_NONE
+        # Note, return datagram to keep a handle on the data
+        return (datagram, dgi,type)
 
 
     def blockingRead(self,qcr):
     def blockingRead(self,qcr):
+        """
+        Block until data is available on the queued connection reader.
+        Returns a datagram iterator and type
+        """
         while not qcr.dataAvailable():
         while not qcr.dataAvailable():
             # The following may not be necessary.
             # The following may not be necessary.
             # I just wanted some
             # I just wanted some
             # time given to the operating system while
             # time given to the operating system while
             # busy waiting.
             # busy waiting.
             time.sleep(0.002)
             time.sleep(0.002)
+        # Data is available, create a datagram iterator
         datagram = NetDatagram()
         datagram = NetDatagram()
-        readRetVal = qcr.getData(datagram)
-        if not readRetVal:
+        if qcr.getData(datagram):
+            (dgi, type) = self.readHeader(datagram)
+        else:
+            (dgi, type) = (None, CLUSTER_NONE)
             self.notify.warning("getData returned false")
             self.notify.warning("getData returned false")
-        return datagram
+        # Note, return datagram to keep a handle on the data
+        return (datagram, dgi, type)
+
+    def readHeader(self,datagram):
+        dgi = DatagramIterator(datagram)
+        number = dgi.getUint32()
+        type = dgi.getUint8()
+        self.notify.debug("Packet %d type %d recieved" % (number,type))
+        return (dgi,type)        
 
 
     def makeCamOffsetDatagram(self,xyz,hpr):
     def makeCamOffsetDatagram(self,xyz,hpr):
         datagram = Datagram.Datagram()
         datagram = Datagram.Datagram()
@@ -85,14 +92,6 @@ class MsgHandler:
         datagram.addFloat32(hpr[2])
         datagram.addFloat32(hpr[2])
         return datagram
         return datagram
 
 
-    def makeCommandStringDatagram(self, commandString):
-        datagram = Datagram.Datagram()
-        datagram.addUint32(self.packetNumber)
-        self.packetNumber = self.packetNumber + 1
-        datagram.addUint8(CLUSTER_COMMAND_STRING)
-        datagram.addString(commandString)
-        return datagram
-
     def makeCamFrustumDatagram(self,focalLength, filmSize, filmOffset):
     def makeCamFrustumDatagram(self,focalLength, filmSize, filmOffset):
         datagram = Datagram.Datagram()
         datagram = Datagram.Datagram()
         datagram.addUint32(self.packetNumber)
         datagram.addUint32(self.packetNumber)
@@ -109,7 +108,7 @@ class MsgHandler:
         datagram = Datagram.Datagram()
         datagram = Datagram.Datagram()
         datagram.addUint32(self.packetNumber)
         datagram.addUint32(self.packetNumber)
         self.packetNumber = self.packetNumber + 1
         self.packetNumber = self.packetNumber + 1
-        datagram.addUint8(CLUSTER_POS_UPDATE)
+        datagram.addUint8(CLUSTER_CAM_MOVEMENT)
         datagram.addFloat32(xyz[0])
         datagram.addFloat32(xyz[0])
         datagram.addFloat32(xyz[1])
         datagram.addFloat32(xyz[1])
         datagram.addFloat32(xyz[2])
         datagram.addFloat32(xyz[2])
@@ -118,6 +117,14 @@ class MsgHandler:
         datagram.addFloat32(hpr[2])
         datagram.addFloat32(hpr[2])
         return datagram
         return datagram
 
 
+    def makeCommandStringDatagram(self, commandString):
+        datagram = Datagram.Datagram()
+        datagram.addUint32(self.packetNumber)
+        self.packetNumber = self.packetNumber + 1
+        datagram.addUint8(CLUSTER_COMMAND_STRING)
+        datagram.addString(commandString)
+        return datagram
+
     def makeSwapNowDatagram(self):
     def makeSwapNowDatagram(self):
         datagram = Datagram.Datagram()
         datagram = Datagram.Datagram()
         datagram.addUint32(self.packetNumber)
         datagram.addUint32(self.packetNumber)
@@ -131,6 +138,13 @@ class MsgHandler:
         self.packetNumber = self.packetNumber + 1
         self.packetNumber = self.packetNumber + 1
         datagram.addUint8(CLUSTER_SWAP_READY)
         datagram.addUint8(CLUSTER_SWAP_READY)
         return datagram
         return datagram
+
+    def makeExitDatagram(self):
+        datagram = Datagram.Datagram()
+        datagram.addUint32(self.packetNumber)
+        self.packetNumber = self.packetNumber + 1
+        datagram.addUint8(CLUSTER_EXIT)
+        return datagram
         
         
 
 
 
 

+ 34 - 41
direct/src/cluster/ClusterServer.py

@@ -1,18 +1,11 @@
 """ServerRepository module: contains the ServerRepository class"""
 """ServerRepository module: contains the ServerRepository class"""
 
 
-from ShowBaseGlobal import *
-from ClusterMsgs import *
-import DirectObject
-import Datagram
-#import DatagramIterator
-#import NetDatagram
-import __builtin__
-import time
 from PandaModules import *
 from PandaModules import *
-from TaskManagerGlobal import *
+from ClusterMsgs import *
 from MsgTypes import *
 from MsgTypes import *
-import Task
 import DirectNotifyGlobal
 import DirectNotifyGlobal
+import DirectObject
+import Task
 
 
 # Cam offset handling is a little sloppy.  The problem is that there is a
 # Cam offset handling is a little sloppy.  The problem is that there is a
 # single arc used for both movement of the camera, and the offset of the
 # single arc used for both movement of the camera, and the offset of the
@@ -76,32 +69,32 @@ class ClusterServer(DirectObject.DirectObject):
         # Run this task just after the listener poll task and dataloop
         # Run this task just after the listener poll task and dataloop
         taskMgr.add(self.readerPollTask, "serverReaderPollTask", -39)
         taskMgr.add(self.readerPollTask, "serverReaderPollTask", -39)
 
 
-    def readerPollTask(self):
-        while self.qcr.dataAvailable():
-            datagram = NetDatagram()
-            readRetVal = self.qcr.getData(datagram)
-            if readRetVal:
-                self.handleDatagram(datagram)
+    def readerPollTask(self, state):
+        # Process all available datagrams
+        while 1:
+            (datagram, dgi,type) = self.msgHandler.nonBlockingRead(self.qcr)
+            if type is CLUSTER_NONE:
+                break
             else:
             else:
-                self.notify.warning("getData returned false")
+                handleDatagram(dgi, type)
         return Task.cont
         return Task.cont
 
 
-    def handleDatagram(self, datagram):
-        (type, dgi) = self.msgHandler.nonBlockingRead(self.qcr)
-        if type==CLUSTER_CAM_OFFSET:
+    def handleDatagram(self, dgi, type):
+        if type == CLUSTER_NONE:
+            pass
+        elif type == CLUSTER_EXIT:
+            import sys
+            sys.exit()
+        elif type == CLUSTER_CAM_OFFSET:
             self.handleCamOffset(dgi)
             self.handleCamOffset(dgi)
-        elif type==CLUSTER_CAM_FRUSTUM:
+        elif type == CLUSTER_CAM_FRUSTUM:
             self.handleCamFrustum(dgi)
             self.handleCamFrustum(dgi)
-        elif type==CLUSTER_POS_UPDATE:
+        elif type == CLUSTER_CAM_MOVEMENT:
             self.handleCamMovement(dgi)
             self.handleCamMovement(dgi)
-        elif type==CLUSTER_SWAP_READY:
-            pass
-        elif type==CLUSTER_SWAP_NOW:
-            pass
-        elif type==CLUSTER_COMMAND_STRING:
+        elif type == CLUSTER_COMMAND_STRING:
             self.handleCommandString(dgi)
             self.handleCommandString(dgi)
         else:
         else:
-            self.notify.warning("recieved unknown packet")
+            self.notify.warning("Recieved unknown packet type:" % type)
         return type
         return type
     
     
     def handleCamOffset(self,dgi):
     def handleCamOffset(self,dgi):
@@ -147,7 +140,7 @@ class ClusterServer(DirectObject.DirectObject):
 
 
     def handleCommandString(self, dgi):
     def handleCommandString(self, dgi):
         command = dgi.getString()
         command = dgi.getString()
-        exec( command, globals() )
+        exec( command, globals())
         
         
 class ClusterServerSync(ClusterServer):
 class ClusterServerSync(ClusterServer):
 
 
@@ -163,11 +156,10 @@ class ClusterServerSync(ClusterServer):
             pass
             pass
         elif self.qcr.isConnectionOk(self.lastConnection):
         elif self.qcr.isConnectionOk(self.lastConnection):
             # Process datagrams till you get a postion update
             # Process datagrams till you get a postion update
-            type = CLUSTER_NOTHING
-            while type != CLUSTER_POS_UPDATE:
-                datagram = self.msgHandler.blockingRead(self.qcr)
-                (type,dgi) = self.msgHandler.readHeader(datagram)
-                if type == CLUSTER_POS_UPDATE:
+            type = CLUSTER_NONE
+            while type != CLUSTER_CAM_MOVEMENT:
+                (datagram,dgi,type) = self.msgHandler.blockingRead(self.qcr)
+                if type == CLUSTER_CAM_MOVEMENT:
                     # Move camera
                     # Move camera
                     self.handleCamMovement(dgi)
                     self.handleCamMovement(dgi)
                     # Set flag for swap coordinator
                     # Set flag for swap coordinator
@@ -194,13 +186,14 @@ class ClusterServerSync(ClusterServer):
         if self.posRecieved:
         if self.posRecieved:
             self.posRecieved = 0
             self.posRecieved = 0
             self.sendSwapReady()
             self.sendSwapReady()
-            datagram = self.msgHandler.blockingRead(self.qcr)
-            (type,dgi) = self.msgHandler.readHeader(datagram)
-            if type == CLUSTER_SWAP_NOW:
-                self.notify.debug('swapping')
-                base.win.swap()
-            else:
-                self.notify.warning("did not get expected swap now")
+            while 1:
+                (datagram,dgi,type) = self.msgHandler.blockingRead(self.qcr)
+                if type == CLUSTER_SWAP_NOW:
+                    self.notify.debug('swapping')
+                    base.win.swap()
+                    break
+                else:
+                    self.handleDatagram(dgi,type)
         return Task.cont
         return Task.cont
 
 
 
 

+ 14 - 0
direct/src/directtools/DirectCameraControl.py

@@ -260,11 +260,23 @@ class DirectCameraControl(PandaObject):
         angle = getCrankAngle(state.coaCenter)
         angle = getCrankAngle(state.coaCenter)
         deltaAngle = angle - state.lastAngle
         deltaAngle = angle - state.lastAngle
         state.lastAngle = angle
         state.lastAngle = angle
+        if deltaAngle != 0.0:
+            print deltaAngle
+        print 'cam Manip before'
+        print self.camManipRef.getMat()
         if base.config.GetBool('temp-hpr-fix',0):
         if base.config.GetBool('temp-hpr-fix',0):
             self.camManipRef.setHpr(self.camManipRef, 0, 0, deltaAngle)
             self.camManipRef.setHpr(self.camManipRef, 0, 0, deltaAngle)
         else:
         else:
             self.camManipRef.setHpr(self.camManipRef, 0, 0, -deltaAngle)
             self.camManipRef.setHpr(self.camManipRef, 0, 0, -deltaAngle)
+        print 'cam Manip after'
+        print self.camManipRef.getMat()
+        print 'direct camera before'
+        print direct.camera.getMat()
         direct.camera.setMat(self.camManipRef, wrtMat)
         direct.camera.setMat(self.camManipRef, wrtMat)
+        print 'direct camera after'
+        print direct.camera.getMat()
+        print
+        print
         return Task.cont
         return Task.cont
 
 
     def lockCOA(self):
     def lockCOA(self):
@@ -352,6 +364,8 @@ class DirectCameraControl(PandaObject):
             # ref = base.cam
             # ref = base.cam
             ref = direct.drList.getCurrentDr().cam
             ref = direct.drList.getCurrentDr().cam
         self.coaMarker.setPos(ref, self.coa)
         self.coaMarker.setPos(ref, self.coa)
+        pos = self.coaMarker.getPos()
+        self.coaMarker.setPosHprScale(pos, Vec3(0), Vec3(1))
         # Resize it
         # Resize it
         self.updateCoaMarkerSize(coaDist)
         self.updateCoaMarkerSize(coaDist)
         # Record marker pos in render space
         # Record marker pos in render space

+ 2 - 2
direct/src/directtools/DirectManipulation.py

@@ -98,7 +98,7 @@ class DirectManipulationControl(PandaObject):
                 self.hitPt.assign(hitPt)
                 self.hitPt.assign(hitPt)
                 self.hitPtDist = hitPtDist
                 self.hitPtDist = hitPtDist
                 # Find the node path from the node found above
                 # Find the node path from the node found above
-                nodePath = render.findPathDownTo(node)
+                nodePath = render.findAllPathsTo(node)[0]
                 # Select it
                 # Select it
                 direct.select(nodePath, direct.fShift)
                 direct.select(nodePath, direct.fShift)
             else:
             else:
@@ -223,7 +223,7 @@ class DirectManipulationControl(PandaObject):
                 self.objectHandles.transferObjectHandlesScale()
                 self.objectHandles.transferObjectHandlesScale()
                 self.fScaling = 0
                 self.fScaling = 0
             # Alt key switches to a scaling mode
             # Alt key switches to a scaling mode
-            if direct.fAlt:
+            if direct.fControl:
                 self.fScaling = 1
                 self.fScaling = 1
                 self.scale3D(state)
                 self.scale3D(state)
             # Otherwise, manip mode depends on where you started
             # Otherwise, manip mode depends on where you started

+ 16 - 35
direct/src/directtools/DirectSelection.py

@@ -22,7 +22,7 @@ class DirectNodePath(NodePath):
         # and its center of action (COA)
         # and its center of action (COA)
         self.mCoa2Dnp = Mat4()
         self.mCoa2Dnp = Mat4()
         self.mCoa2Dnp.assign(Mat4.identMat())
         self.mCoa2Dnp.assign(Mat4.identMat())
-        # self.mCoa2Dnp.setRow(3, Vec4(center[0], center[1], center[2], 1))
+        self.mCoa2Dnp.setRow(3, Vec4(center[0], center[1], center[2], 1))
         # Transform from nodePath to widget
         # Transform from nodePath to widget
         self.mDnp2Widget = Mat4()
         self.mDnp2Widget = Mat4()
         self.mDnp2Widget.assign(Mat4.identMat())
         self.mDnp2Widget.assign(Mat4.identMat())
@@ -127,18 +127,7 @@ class SelectedNodePaths(PandaObject):
         """
         """
         dnp = self.selectedDict.get(id, None)
         dnp = self.selectedDict.get(id, None)
         if dnp:
         if dnp:
-            # Found item in selected Dictionary, is it still valid?
-            if dnp.verifyConnectivity():
-                # Yes
-                return dnp
-            else:
-                # Not valid anymore, try to repair
-                if dnp.repairConnectivity(render):
-                    # Fixed, return node path
-                    return dnp
-                else:
-                    del(self.selectedDict[id])
-                    return None
+            return dnp
         else:
         else:
             # Not in selected dictionary
             # Not in selected dictionary
             return None
             return None
@@ -152,18 +141,8 @@ class SelectedNodePaths(PandaObject):
         """
         """
         dnp = self.deselectedDict.get(id, None)
         dnp = self.deselectedDict.get(id, None)
         if dnp:
         if dnp:
-            # Found item in deselected Dictionary, is it still valid?
-            if dnp.verifyConnectivity():
-                # Yes
-                return dnp
-            else:
-                # Not valid anymore, try to repair
-                if dnp.repairConnectivity(render):
-                    # Fixed, return node path
-                    return dnp
-                else:
-                    del(self.deselectedDict[id])
-                    return None
+            # Yes
+            return dnp
         else:
         else:
             # Not in deselected dictionary
             # Not in deselected dictionary
             return None
             return None
@@ -344,10 +323,11 @@ class DirectBoundingBox:
 
 
     def getBounds(self):
     def getBounds(self):
         # Get a node path's bounds
         # Get a node path's bounds
-        nodeBounds = self.nodePath.node().getBound()
+        nodeBounds = BoundingSphere()
+        nodeBounds.extendBy(self.nodePath.node().getInternalBound())
         for child in self.nodePath.getChildrenAsList():
         for child in self.nodePath.getChildrenAsList():
-            nodeBounds.extendBy(child.arc().getBound())
-            return nodeBounds.makeCopy()
+            nodeBounds.extendBy(child.getBounds())
+        return nodeBounds.makeCopy()
 
 
     def show(self):
     def show(self):
         self.lines.reparentTo(self.nodePath)
         self.lines.reparentTo(self.nodePath)
@@ -428,11 +408,11 @@ class SelectionRay:
         for i in range(0,self.numEntries):
         for i in range(0,self.numEntries):
             entry = self.cq.getEntry(i)
             entry = self.cq.getEntry(i)
             node = entry.getIntoNode()
             node = entry.getIntoNode()
-            nodePath = render.findPathDownTo(node)
+            nodePath = render.findAllPathsTo(node)[0]
             # Don't pick hidden nodes
             # Don't pick hidden nodes
-            if node.isHidden():
-                pass
-            elif fIgnoreCamera and (direct.camera in nodePath.getAncestry()):
+            #if node.isHidden():
+            #pass
+            if fIgnoreCamera and (direct.camera in nodePath.getAncestry()):
                 # This avoids things parented to a camera.  Good idea?
                 # This avoids things parented to a camera.  Good idea?
                 pass
                 pass
             # Can pick unpickable, use the first visible node
             # Can pick unpickable, use the first visible node
@@ -520,10 +500,11 @@ class SelectionRay:
             entry = self.cq.getEntry(i)
             entry = self.cq.getEntry(i)
             node = entry.getIntoNode()
             node = entry.getIntoNode()
             # Don't pick hidden nodes
             # Don't pick hidden nodes
-            if node.isHidden():
-                pass
+            # MRM: Doesn't work in new panda for GeomNodes
+            #if node.isHidden():
+            #pass
             # Can pick unpickable, use the first visible node
             # Can pick unpickable, use the first visible node
-            elif fIntersectUnpickable:
+            if fIntersectUnpickable:
                 self.cqIndex = i
                 self.cqIndex = i
                 break
                 break
             # Is it a named node?, If so, see if it has a name
             # Is it a named node?, If so, see if it has a name

+ 11 - 16
direct/src/showbase/qpShowBase.py

@@ -96,12 +96,7 @@ class ShowBase:
         self.camList = []
         self.camList = []
         self.camNode = None
         self.camNode = None
         self.camLens = None
         self.camLens = None
-
-        # base.camera is a little different; rather than referring to
-        # base.cameraList[0], it is instead the parent node of all
-        # cameras in base.cameraList.  That way, multiple cameras can
-        # easily be dragged around by moving the one node.
-        self.camera = self.render.attachNewNode('camera')
+        self.camera = None
         self.cameraList = []
         self.cameraList = []
         self.groupList = []
         self.groupList = []
         self.camera2d = self.render2d.attachNewNode('camera2d')
         self.camera2d = self.render2d.attachNewNode('camera2d')
@@ -383,8 +378,8 @@ class ShowBase:
         
         
 
 
     def getCameras(self, chanConfig):
     def getCameras(self, chanConfig):
-        """getCameras(self, chanConfig)
-
+        """
+        getCameras(self, chanConfig)
         Extracts the camera(s) out of the ChanConfig record, parents
         Extracts the camera(s) out of the ChanConfig record, parents
         them all to base.camera, and adds them to base.cameraList.
         them all to base.camera, and adds them to base.cameraList.
         """
         """
@@ -393,7 +388,7 @@ class ShowBase:
         # be more than one display region/camera node beneath each
         # be more than one display region/camera node beneath each
         # one.
         # one.
         for i in range(chanConfig.getNumGroups()):
         for i in range(chanConfig.getNumGroups()):
-            camera = self.camera.attachNewNode(chanConfig.getGroupNode(i))
+            camera = self.render.attachNewNode(chanConfig.getGroupNode(i))
             cam = camera.find('**/+Camera')
             cam = camera.find('**/+Camera')
             lens = cam.node().getLens()
             lens = cam.node().getLens()
 
 
@@ -409,19 +404,18 @@ class ShowBase:
         for i in range(chanConfig.getNumDrs()):
         for i in range(chanConfig.getNumDrs()):
             self.groupList.append(chanConfig.getGroupMembership(i))
             self.groupList.append(chanConfig.getGroupMembership(i))
 
 
-        # Set the default camera
+        # Set the default camera and cam
+        if self.camera == None:
+            self.camera = self.cameraList[0]
         if self.cam == None:
         if self.cam == None:
             self.cam = self.camList[0]
             self.cam = self.camList[0]
-
             # If you need to get a handle to the camera node itself,
             # If you need to get a handle to the camera node itself,
             # use self.camNode.
             # use self.camNode.
             self.camNode = self.cam.node()
             self.camNode = self.cam.node()
-
             # If you need to adjust camera parameters, like fov or
             # If you need to adjust camera parameters, like fov or
             # near/far clipping planes, use self.camLens.
             # near/far clipping planes, use self.camLens.
             self.camLens = self.camNode.getLens()
             self.camLens = self.camNode.getLens()
 
 
-
     def getAlt(self):
     def getAlt(self):
         return base.mouseWatcherNode.getModifierButtons().isDown(
         return base.mouseWatcherNode.getModifierButtons().isDown(
             KeyboardButton.alt())
             KeyboardButton.alt())
@@ -576,12 +570,13 @@ class ShowBase:
             self.backfaceCullingOn()
             self.backfaceCullingOn()
 
 
     def backfaceCullingOn(self):
     def backfaceCullingOn(self):
-        self.render.setTwoSided(self.wireframeEnabled)
+        if not self.backfaceCullingEnabled:
+            self.render.setTwoSided(0)
         self.backfaceCullingEnabled = 1
         self.backfaceCullingEnabled = 1
 
 
     def backfaceCullingOff(self):
     def backfaceCullingOff(self):
-        if not self.wireframeEnabled:
-            self.render.setTwoSided(0)
+        if self.backfaceCullingEnabled:
+            self.render.setTwoSided(1)
         self.backfaceCullingEnabled = 0
         self.backfaceCullingEnabled = 0
 
 
     def toggleTexture(self):
     def toggleTexture(self):

+ 21 - 0
direct/src/task/Task.py

@@ -5,6 +5,7 @@ from MessengerGlobal import *
 import time
 import time
 import fnmatch
 import fnmatch
 import string
 import string
+import signal
 
 
 # MRM: Need to make internal task variables like time, name, index
 # MRM: Need to make internal task variables like time, name, index
 # more unique (less likely to have name clashes)
 # more unique (less likely to have name clashes)
@@ -230,6 +231,8 @@ class TaskManager:
             TaskManager.notify = directNotify.newCategory("TaskManager")
             TaskManager.notify = directNotify.newCategory("TaskManager")
         self.taskTimerVerbose = 0
         self.taskTimerVerbose = 0
         self.extendedExceptions = 0
         self.extendedExceptions = 0
+        self.fKeyboardInterrupt = 0
+        self.interruptCount = 0
         self.pStatsTasks = 0
         self.pStatsTasks = 0
         self.resumeFunc = None
         self.resumeFunc = None
         self.fVerbose = 0
         self.fVerbose = 0
@@ -241,6 +244,14 @@ class TaskManager:
         self.fVerbose = value
         self.fVerbose = value
         messenger.send('TaskManager-setVerbose', sentArgs = [value])
         messenger.send('TaskManager-setVerbose', sentArgs = [value])
 
 
+    def keyboardInterruptHandler(self, signalNumber, stackFrame):
+        self.fKeyboardInterrupt = 1
+        self.interruptCount += 1
+        if self.interruptCount == 2:
+            # The user must really want to interrupt this process
+            # Next time around use the default interrupt handler
+            signal.signal(signal.SIGINT, signal.default_int_handler)
+
     def add(self, funcOrTask, name, priority = 0):
     def add(self, funcOrTask, name, priority = 0):
         """
         """
         Add a new task to the taskMgr.
         Add a new task to the taskMgr.
@@ -370,6 +381,12 @@ class TaskManager:
         if TaskManager.notify.getDebug():
         if TaskManager.notify.getDebug():
             TaskManager.notify.debug('step')
             TaskManager.notify.debug('step')
         self.currentTime, self.currentFrame = self.__getTimeFrame()
         self.currentTime, self.currentFrame = self.__getTimeFrame()
+        # Replace keyboard interrupt handler during task list processing
+        # so we catch the keyboard interrupt but don't handle it until
+        # after task list processing is complete.
+        self.fKeyboardInterrupt = 0
+        self.interruptCount = 0
+        signal.signal(signal.SIGINT, self.keyboardInterruptHandler)
         for task in self.taskList:
         for task in self.taskList:
             task.setCurrentTimeFrame(self.currentTime, self.currentFrame)
             task.setCurrentTimeFrame(self.currentTime, self.currentFrame)
 
 
@@ -410,6 +427,10 @@ class TaskManager:
                 self.__removeTask(task)
                 self.__removeTask(task)
             else:
             else:
                 raise StandardError, "Task named %s did not return cont, exit, or done" % task.name
                 raise StandardError, "Task named %s did not return cont, exit, or done" % task.name
+        # Restore default interrupt handler
+        signal.signal(signal.SIGINT, signal.default_int_handler)
+        if self.fKeyboardInterrupt:
+            raise KeyboardInterrupt
         return len(self.taskList)
         return len(self.taskList)
 
 
     def run(self):
     def run(self):

+ 1 - 1
direct/src/tkpanels/DirectSessionPanel.py

@@ -695,7 +695,7 @@ class DirectSessionPanel(AppShell):
             dictName = name
             dictName = name
         else:
         else:
             # Generate a unique name for the dict
             # Generate a unique name for the dict
-            dictName = name + '-' + `nodePath.id().this`
+            dictName = name + '-' + `nodePath.id()`
         if not dict.has_key(dictName):
         if not dict.has_key(dictName):
             # Update combo box to include new item
             # Update combo box to include new item
             names.append(dictName)
             names.append(dictName)

+ 5 - 5
direct/src/tkpanels/MopathRecorder.py

@@ -292,8 +292,7 @@ class MopathRecorder(AppShell, PandaObject):
             resolution = 0.01, command = self.playbackGoTo, side = TOP)
             resolution = 0.01, command = self.playbackGoTo, side = TOP)
         widget.component('hull')['relief'] = RIDGE
         widget.component('hull')['relief'] = RIDGE
         # Kill playback task if drag slider
         # Kill playback task if drag slider
-        widget.component('scale').bind(
-            '<ButtonPress-1>', lambda e = None, s = self: s.stopPlayback())
+        widget['preCallback'] = self.stopPlayback
         # Jam duration entry into entry scale
         # Jam duration entry into entry scale
         self.createLabeledEntry(widget.labelFrame, 'Resample', 'Path Duration',
         self.createLabeledEntry(widget.labelFrame, 'Resample', 'Path Duration',
                                 'Set total curve duration',
                                 'Set total curve duration',
@@ -371,7 +370,7 @@ class MopathRecorder(AppShell, PandaObject):
             'Number of samples in resampled curve',
             'Number of samples in resampled curve',
             resolution = 1, min = 2, max = 1000, command = self.setNumSamples)
             resolution = 1, min = 2, max = 1000, command = self.setNumSamples)
         widget.component('hull')['relief'] = RIDGE
         widget.component('hull')['relief'] = RIDGE
-        widget['preCallback'] = widget['postCallback'] = self.sampleCurve
+        widget['postCallback'] = self.sampleCurve
 
 
         frame = Frame(resampleFrame)
         frame = Frame(resampleFrame)
         self.createButton(
         self.createButton(
@@ -785,7 +784,9 @@ class MopathRecorder(AppShell, PandaObject):
     def extractPointSetFromCurveCollection(self):
     def extractPointSetFromCurveCollection(self):
         # Use curve to compute new point set
         # Use curve to compute new point set
         # Record maxT
         # Record maxT
+        print 'before', self.maxT
         self.maxT = self.curveCollection.getMaxT()
         self.maxT = self.curveCollection.getMaxT()
+        print 'after', self.maxT
         # Determine num samples
         # Determine num samples
         # Limit point set to 1000 points and samples per second to 30
         # Limit point set to 1000 points and samples per second to 30
         samplesPerSegment = min(30.0, 1000.0/self.curveCollection.getMaxT())
         samplesPerSegment = min(30.0, 1000.0/self.curveCollection.getMaxT())
@@ -1232,7 +1233,7 @@ class MopathRecorder(AppShell, PandaObject):
             dictName = name
             dictName = name
         else:
         else:
             # Generate a unique name for the dict
             # Generate a unique name for the dict
-            dictName = name + '-' + `nodePath.id().this`
+            dictName = name + '-' + `nodePath.id()`
         if not dict.has_key(dictName):
         if not dict.has_key(dictName):
             # Update combo box to include new item
             # Update combo box to include new item
             names.append(dictName)
             names.append(dictName)
@@ -1248,7 +1249,6 @@ class MopathRecorder(AppShell, PandaObject):
     def playbackGoTo(self, time):
     def playbackGoTo(self, time):
         if self.curveCollection == None:
         if self.curveCollection == None:
             return
             return
-        print time
         self.playbackTime = CLAMP(time, 0.0, self.maxT)
         self.playbackTime = CLAMP(time, 0.0, self.maxT)
         if self.curveCollection != None:
         if self.curveCollection != None:
             pos = Point3(0)
             pos = Point3(0)

+ 1 - 1
direct/src/tkpanels/Placer.py

@@ -493,7 +493,7 @@ class Placer(AppShell):
             dictName = name
             dictName = name
         else:
         else:
             # Generate a unique name for the dict
             # Generate a unique name for the dict
-            dictName = name + '-' + `nodePath.id().this`
+            dictName = name + '-' + `nodePath.id()`
         if not dict.has_key(dictName):
         if not dict.has_key(dictName):
             # Update combo box to include new item
             # Update combo box to include new item
             names.append(dictName)
             names.append(dictName)

+ 7 - 0
direct/src/tkwidgets/Slider.py

@@ -374,6 +374,8 @@ class SliderWidget(Pmw.MegaWidget):
         if fInside:
         if fInside:
             self._fPressInside = 1
             self._fPressInside = 1
             self._fUpdate = 1
             self._fUpdate = 1
+            if self['preCallback']:
+                apply(self['preCallback'], self['callbackData'])
             self._updateValue(event)
             self._updateValue(event)
         else:
         else:
             self._fPressInside = 0
             self._fPressInside = 0
@@ -385,11 +387,16 @@ class SliderWidget(Pmw.MegaWidget):
                 event.y_root - self._widget.winfo_rooty())
                 event.y_root - self._widget.winfo_rooty())
             if canvasY > 0:
             if canvasY > 0:
                 self._fUpdate = 1
                 self._fUpdate = 1
+                if self['preCallback']:
+                    apply(self['preCallback'], self['callbackData'])
                 self._unpostOnNextRelease()
                 self._unpostOnNextRelease()
         elif self._fUpdate:
         elif self._fUpdate:
             self._updateValue(event)
             self._updateValue(event)
 
 
     def _widgetBtnRelease(self, event):
     def _widgetBtnRelease(self, event):
+        # Do post callback if any
+        if self._fUpdate and self['postCallback']:
+            apply(self['postCallback'], self['callbackData'])
         if (self._fUnpost or
         if (self._fUnpost or
             (not (self._firstPress or self._fPressInside))):
             (not (self._firstPress or self._fPressInside))):
             self._unpostSlider()
             self._unpostSlider()