mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
Synced version of cluster code with select/deselect and limited command support
This commit is contained in:
parent
54563e7a00
commit
55a3ae9bff
@ -1,123 +1,28 @@
|
|||||||
"""ClusterClient: Master for mutlipiping or PC clusters. """
|
"""ClusterClient: Master for mutli-piping or PC clusters. """
|
||||||
|
|
||||||
from PandaModules import *
|
from PandaModules import *
|
||||||
from ClusterMsgs import *
|
from ClusterMsgs import *
|
||||||
|
from ClusterConfig import *
|
||||||
import DirectNotifyGlobal
|
import DirectNotifyGlobal
|
||||||
import DirectObject
|
import DirectObject
|
||||||
import Task
|
import Task
|
||||||
|
|
||||||
class ClusterConfigItem:
|
class ClusterClient(DirectObject.DirectObject):
|
||||||
def __init__(self, serverFunction, serverName, port):
|
|
||||||
self.serverName = serverName
|
|
||||||
self.serverFunction = serverFunction
|
|
||||||
self.port = port
|
|
||||||
# Camera Offset
|
|
||||||
self.xyz = Vec3(0)
|
|
||||||
self.hpr = Vec3(0)
|
|
||||||
# Camera Frustum Data
|
|
||||||
self.fFrustum = 0
|
|
||||||
self.focalLength = None
|
|
||||||
self.filmSize = None
|
|
||||||
self.filmOffset = None
|
|
||||||
def setCamOffset(self, xyz, hpr):
|
|
||||||
self.xyz = xyz
|
|
||||||
self.hpr = hpr
|
|
||||||
def setCamFrustum(self, focalLength, filmSize, filmOffset):
|
|
||||||
self.fFrustum = 1
|
|
||||||
self.focalLength = focalLength
|
|
||||||
self.filmSize = filmSize
|
|
||||||
self.filmOffset = filmOffset
|
|
||||||
|
|
||||||
class DisplayConnection:
|
|
||||||
def __init__(self,qcm,serverName,port,msgHandler):
|
|
||||||
self.msgHandler = msgHandler
|
|
||||||
gameServerTimeoutMs = base.config.GetInt(
|
|
||||||
"game-server-timeout-ms", 20000)
|
|
||||||
# A big old 20 second timeout.
|
|
||||||
self.tcpConn = qcm.openTCPClientConnection(
|
|
||||||
serverName, port, gameServerTimeoutMs)
|
|
||||||
# Test for bad connection
|
|
||||||
if self.tcpConn == None:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
self.tcpConn.setNoDelay(1)
|
|
||||||
self.qcr=QueuedConnectionReader(qcm, 0)
|
|
||||||
self.qcr.addConnection(self.tcpConn)
|
|
||||||
self.cw=ConnectionWriter(qcm, 0)
|
|
||||||
|
|
||||||
def sendCamOffset(self,xyz,hpr):
|
|
||||||
ClusterManager.notify.debug("send cam offset...")
|
|
||||||
ClusterManager.notify.debug( ("packet %d xyz,hpr=%f %f %f %f %f %f" %
|
|
||||||
(self.msgHandler.packetNumber,xyz[0],xyz[1],xyz[2],
|
|
||||||
hpr[0],hpr[1],hpr[2])) )
|
|
||||||
datagram = self.msgHandler.makeCamOffsetDatagram(xyz, hpr)
|
|
||||||
self.cw.send(datagram, self.tcpConn)
|
|
||||||
|
|
||||||
def sendCamFrustum(self,focalLength, filmSize, filmOffset):
|
|
||||||
ClusterManager.notify.debug("send cam frustum...")
|
|
||||||
ClusterManager.notify.debug(
|
|
||||||
(("packet %d" % self.msgHandler.packetNumber) +
|
|
||||||
(" fl, fs, fo=%0.3f, (%0.3f, %0.3f), (%0.3f, %0.3f)" %
|
|
||||||
(focalLength, filmSize[0], filmSize[1],
|
|
||||||
filmOffset[0], filmOffset[1])))
|
|
||||||
)
|
|
||||||
datagram = self.msgHandler.makeCamFrustumDatagram(
|
|
||||||
focalLength, filmSize, filmOffset)
|
|
||||||
self.cw.send(datagram, self.tcpConn)
|
|
||||||
|
|
||||||
def sendMoveCam(self,xyz,hpr):
|
|
||||||
ClusterManager.notify.debug("send cam move...")
|
|
||||||
ClusterManager.notify.debug( ("packet %d xyz,hpr=%f %f %f %f %f %f" %
|
|
||||||
(self.msgHandler.packetNumber,xyz[0],xyz[1],xyz[2],
|
|
||||||
hpr[0],hpr[1],hpr[2])) )
|
|
||||||
datagram = self.msgHandler.makeMoveCamDatagram(xyz, hpr)
|
|
||||||
self.cw.send(datagram, self.tcpConn)
|
|
||||||
|
|
||||||
# the following should only be called by a synchronized cluster manger
|
|
||||||
def getSwapReady(self):
|
|
||||||
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
|
|
||||||
def sendSwapNow(self):
|
|
||||||
ClusterManager.notify.debug(
|
|
||||||
"display connect send swap now, packet %d" %
|
|
||||||
self.msgHandler.packetNumber)
|
|
||||||
datagram = self.msgHandler.makeSwapNowDatagram()
|
|
||||||
self.cw.send(datagram, self.tcpConn)
|
|
||||||
|
|
||||||
def sendCommandString(self, commandString):
|
|
||||||
ClusterManager.notify.debug("send command string: %s" % commandString)
|
|
||||||
datagram = self.msgHandler.makeCommandStringDatagram(commandString)
|
|
||||||
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):
|
|
||||||
notify = DirectNotifyGlobal.directNotify.newCategory("ClusterClient")
|
notify = DirectNotifyGlobal.directNotify.newCategory("ClusterClient")
|
||||||
MGR_NUM = 1000000
|
MGR_NUM = 1000000
|
||||||
|
|
||||||
def __init__(self, configList):
|
def __init__(self, configList):
|
||||||
self.qcm=QueuedConnectionManager()
|
self.qcm=QueuedConnectionManager()
|
||||||
self.serverList = []
|
self.serverList = []
|
||||||
self.msgHandler = MsgHandler(ClusterManager.MGR_NUM,self.notify)
|
self.msgHandler = ClusterMsgHandler(ClusterClient.MGR_NUM, self.notify)
|
||||||
for serverConfig in configList:
|
for serverConfig in configList:
|
||||||
server = DisplayConnection(self.qcm,serverConfig.serverName,
|
server = DisplayConnection(self.qcm,serverConfig.serverName,
|
||||||
serverConfig.port,self.msgHandler)
|
serverConfig.port,self.msgHandler)
|
||||||
if server == None:
|
if server == None:
|
||||||
self.notify.error( ('Could not open %s on %s port %d' %
|
self.notify.error('Could not open %s on %s port %d' %
|
||||||
(serverConfig.serverFunction,
|
(serverConfig.serverConfigName,
|
||||||
serverConfig.serverName,
|
serverConfig.serverName,
|
||||||
serverConfig.port)) )
|
serverConfig.port))
|
||||||
else:
|
else:
|
||||||
server.sendCamOffset(serverConfig.xyz,serverConfig.hpr)
|
server.sendCamOffset(serverConfig.xyz,serverConfig.hpr)
|
||||||
if serverConfig.fFrustum:
|
if serverConfig.fFrustum:
|
||||||
@ -128,6 +33,7 @@ class ClusterManager(DirectObject.DirectObject):
|
|||||||
self.startMoveCamTask()
|
self.startMoveCamTask()
|
||||||
|
|
||||||
def moveCamera(self, xyz, hpr):
|
def moveCamera(self, xyz, hpr):
|
||||||
|
self.notify.debug('moving unsynced camera')
|
||||||
for server in self.serverList:
|
for server in self.serverList:
|
||||||
server.sendMoveCam(xyz,hpr)
|
server.sendMoveCam(xyz,hpr)
|
||||||
|
|
||||||
@ -136,16 +42,34 @@ class ClusterManager(DirectObject.DirectObject):
|
|||||||
|
|
||||||
def moveCameraTask(self,task):
|
def moveCameraTask(self,task):
|
||||||
self.moveCamera(
|
self.moveCamera(
|
||||||
direct.camera.getPos(render),
|
base.camera.getPos(render),
|
||||||
direct.camera.getHpr(render))
|
base.camera.getHpr(render))
|
||||||
return Task.cont
|
return Task.cont
|
||||||
|
|
||||||
def clusterCommand(self, commandString):
|
def cmd(self, commandString, fLocally = 1):
|
||||||
# Execute remotely
|
# Execute remotely
|
||||||
for server in self.serverList:
|
for server in self.serverList:
|
||||||
server.sendCommandString(commandString)
|
server.sendCommandString(commandString)
|
||||||
# Execute locally
|
if fLocally:
|
||||||
exec( commandString, globals())
|
# Execute locally
|
||||||
|
exec( commandString, globals() )
|
||||||
|
|
||||||
|
def getNodePathFindCmd(self, nodePath):
|
||||||
|
import string
|
||||||
|
pathString = `nodePath`
|
||||||
|
index = string.find(pathString, '/')
|
||||||
|
if index != -1:
|
||||||
|
rootName = pathString[:index]
|
||||||
|
searchString = pathString[index+1:]
|
||||||
|
return rootName + ('.find("%s")' % searchString)
|
||||||
|
else:
|
||||||
|
return rootName
|
||||||
|
|
||||||
|
def selectNodePath(self, nodePath):
|
||||||
|
self.cmd(self.getNodePathFindCmd(nodePath) + '.select()', 0)
|
||||||
|
|
||||||
|
def deselectNodePath(self, nodePath):
|
||||||
|
self.cmd(self.getNodePathFindCmd(nodePath) + '.deselect()', 0)
|
||||||
|
|
||||||
def exit(self):
|
def exit(self):
|
||||||
# Execute remotely
|
# Execute remotely
|
||||||
@ -155,10 +79,10 @@ class ClusterManager(DirectObject.DirectObject):
|
|||||||
import sys
|
import sys
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
class ClusterManagerSync(ClusterManager):
|
class ClusterClientSync(ClusterClient):
|
||||||
|
|
||||||
def __init__(self, configList):
|
def __init__(self, configList):
|
||||||
ClusterManager.__init__(self, configList)
|
ClusterClient.__init__(self, configList)
|
||||||
#I probably don't need this
|
#I probably don't need this
|
||||||
self.waitForSwap = 0
|
self.waitForSwap = 0
|
||||||
self.ready = 0
|
self.ready = 0
|
||||||
@ -190,11 +114,167 @@ class ClusterManagerSync(ClusterManager):
|
|||||||
def moveCamera(self,xyz,hpr):
|
def moveCamera(self,xyz,hpr):
|
||||||
if self.ready:
|
if self.ready:
|
||||||
self.notify.debug('moving synced camera')
|
self.notify.debug('moving synced camera')
|
||||||
ClusterManager.moveCamera(self,xyz,hpr)
|
ClusterClient.moveCamera(self,xyz,hpr)
|
||||||
self.waitForSwap=1
|
self.waitForSwap=1
|
||||||
|
|
||||||
|
class DisplayConnection:
|
||||||
|
def __init__(self,qcm,serverName,port,msgHandler):
|
||||||
|
self.msgHandler = msgHandler
|
||||||
|
gameServerTimeoutMs = base.config.GetInt(
|
||||||
|
"game-server-timeout-ms", 20000)
|
||||||
|
# A big old 20 second timeout.
|
||||||
|
self.tcpConn = qcm.openTCPClientConnection(
|
||||||
|
serverName, port, gameServerTimeoutMs)
|
||||||
|
# Test for bad connection
|
||||||
|
if self.tcpConn == None:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
self.tcpConn.setNoDelay(1)
|
||||||
|
self.qcr=QueuedConnectionReader(qcm, 0)
|
||||||
|
self.qcr.addConnection(self.tcpConn)
|
||||||
|
self.cw=ConnectionWriter(qcm, 0)
|
||||||
|
|
||||||
|
def sendCamOffset(self,xyz,hpr):
|
||||||
|
ClusterClient.notify.debug("send cam offset...")
|
||||||
|
ClusterClient.notify.debug( ("packet %d xyz,hpr=%f %f %f %f %f %f" %
|
||||||
|
(self.msgHandler.packetNumber,xyz[0],xyz[1],xyz[2],
|
||||||
|
hpr[0],hpr[1],hpr[2])) )
|
||||||
|
datagram = self.msgHandler.makeCamOffsetDatagram(xyz, hpr)
|
||||||
|
self.cw.send(datagram, self.tcpConn)
|
||||||
|
|
||||||
|
def sendCamFrustum(self,focalLength, filmSize, filmOffset):
|
||||||
|
ClusterClient.notify.info("send cam frustum...")
|
||||||
|
ClusterClient.notify.info(
|
||||||
|
(("packet %d" % self.msgHandler.packetNumber) +
|
||||||
|
(" fl, fs, fo=%0.3f, (%0.3f, %0.3f), (%0.3f, %0.3f)" %
|
||||||
|
(focalLength, filmSize[0], filmSize[1],
|
||||||
|
filmOffset[0], filmOffset[1])))
|
||||||
|
)
|
||||||
|
datagram = self.msgHandler.makeCamFrustumDatagram(
|
||||||
|
focalLength, filmSize, filmOffset)
|
||||||
|
self.cw.send(datagram, self.tcpConn)
|
||||||
|
|
||||||
|
def sendMoveCam(self,xyz,hpr):
|
||||||
|
ClusterClient.notify.debug("send cam move...")
|
||||||
|
ClusterClient.notify.debug( ("packet %d xyz,hpr=%f %f %f %f %f %f" %
|
||||||
|
(self.msgHandler.packetNumber,xyz[0],xyz[1],xyz[2],
|
||||||
|
hpr[0],hpr[1],hpr[2])) )
|
||||||
|
datagram = self.msgHandler.makeCamMovementDatagram(xyz, hpr)
|
||||||
|
self.cw.send(datagram, self.tcpConn)
|
||||||
|
|
||||||
|
# the following should only be called by a synchronized cluster manger
|
||||||
|
def getSwapReady(self):
|
||||||
|
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
|
||||||
|
def sendSwapNow(self):
|
||||||
|
ClusterClient.notify.debug(
|
||||||
|
"display connect send swap now, packet %d" %
|
||||||
|
self.msgHandler.packetNumber)
|
||||||
|
datagram = self.msgHandler.makeSwapNowDatagram()
|
||||||
|
self.cw.send(datagram, self.tcpConn)
|
||||||
|
|
||||||
|
def sendCommandString(self, commandString):
|
||||||
|
ClusterClient.notify.debug("send command string: %s" % commandString)
|
||||||
|
datagram = self.msgHandler.makeCommandStringDatagram(commandString)
|
||||||
|
self.cw.send(datagram, self.tcpConn)
|
||||||
|
|
||||||
|
def sendExit(self):
|
||||||
|
ClusterClient.notify.debug(
|
||||||
|
"display connect send exit, packet %d" %
|
||||||
|
self.msgHandler.packetNumber)
|
||||||
|
datagram = self.msgHandler.makeExitDatagram()
|
||||||
|
self.cw.send(datagram, self.tcpConn)
|
||||||
|
|
||||||
|
class ClusterConfigItem:
|
||||||
|
def __init__(self, serverConfigName, serverName, port):
|
||||||
|
self.serverConfigName = serverConfigName
|
||||||
|
self.serverName = serverName
|
||||||
|
self.port = port
|
||||||
|
# Camera Offset
|
||||||
|
self.xyz = Vec3(0)
|
||||||
|
self.hpr = Vec3(0)
|
||||||
|
# Camera Frustum Data
|
||||||
|
self.fFrustum = 0
|
||||||
|
self.focalLength = None
|
||||||
|
self.filmSize = None
|
||||||
|
self.filmOffset = None
|
||||||
|
def setCamOffset(self, xyz, hpr):
|
||||||
|
self.xyz = xyz
|
||||||
|
self.hpr = hpr
|
||||||
|
def setCamFrustum(self, focalLength, filmSize, filmOffset):
|
||||||
|
self.fFrustum = 1
|
||||||
|
self.focalLength = focalLength
|
||||||
|
self.filmSize = filmSize
|
||||||
|
self.filmOffset = filmOffset
|
||||||
|
|
||||||
|
def createClusterClient():
|
||||||
|
# setup camera offsets based on cluster-config
|
||||||
|
clusterConfig = base.config.GetString('cluster-config', 'single-server')
|
||||||
|
# No cluster config specified!
|
||||||
|
if not ClientConfigs.has_key(clusterConfig):
|
||||||
|
base.notify.warning(
|
||||||
|
'createClusterClient: %s cluster-config is undefined.' %
|
||||||
|
clusterConfig)
|
||||||
|
return None
|
||||||
|
# Get display config for each server in the cluster
|
||||||
|
displayConfigs = []
|
||||||
|
configList = ClientConfigs[clusterConfig]
|
||||||
|
numConfigs = len(configList)
|
||||||
|
for i in range(numConfigs):
|
||||||
|
configData = configList[i]
|
||||||
|
displayName = configData.get('display name', ('display%d' % i))
|
||||||
|
displayMode = configData.get('display mode', 'server')
|
||||||
|
# Init Cam Offset
|
||||||
|
pos = configData.get('pos', Vec3(0))
|
||||||
|
hpr = configData.get('hpr', Vec3(0))
|
||||||
|
# Init Frustum if specified
|
||||||
|
fl = configData.get('focal length', None)
|
||||||
|
fs = configData.get('film size', None)
|
||||||
|
fo = configData.get('film offset', None)
|
||||||
|
if displayMode == 'client':
|
||||||
|
base.camera.setPosHpr(pos,hpr)
|
||||||
|
lens = base.cam.node().getLens()
|
||||||
|
lens.setFocalLength(fl)
|
||||||
|
lens.setFilmSize(fs[0], fs[1])
|
||||||
|
lens.setFilmOffset(fo[0], fo[1])
|
||||||
|
else:
|
||||||
|
serverConfigName = 'cluster-server-%s' % displayName
|
||||||
|
serverString = base.config.GetString(serverConfigName, '')
|
||||||
|
if serverString == '':
|
||||||
|
base.notify.warning(
|
||||||
|
'%s undefined in Configrc: expected by %s display client.'%
|
||||||
|
(serverConfigName,clusterConfig))
|
||||||
|
base.notify.warning('%s will not be used.' % serverConfigName)
|
||||||
|
else:
|
||||||
|
serverInfo = string.split(serverString)
|
||||||
|
serverName = serverInfo[0]
|
||||||
|
if len(serverInfo) > 1:
|
||||||
|
port = int(serverInfo[1])
|
||||||
|
else:
|
||||||
|
# Use default port
|
||||||
|
port = CLUSTER_PORT
|
||||||
|
cci = ClusterConfigItem(
|
||||||
|
serverConfigName,
|
||||||
|
serverName,
|
||||||
|
port)
|
||||||
|
# Init cam offset
|
||||||
|
cci.setCamOffset(pos, hpr)
|
||||||
|
# Init frustum if specified
|
||||||
|
if fl and fs and fo:
|
||||||
|
cci.setCamFrustum(fl, fs, fo)
|
||||||
|
displayConfigs.append(cci)
|
||||||
|
# Create Cluster Managers (opening connections to servers)
|
||||||
|
# Are the servers going to be synced?
|
||||||
|
if base.config.GetBool('cluster-sync', 0):
|
||||||
|
base.win.setSync(1)
|
||||||
|
return ClusterClientSync(displayConfigs)
|
||||||
|
else:
|
||||||
|
return ClusterClient(displayConfigs)
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,144 +2,101 @@ from PandaObject import *
|
|||||||
from ClusterClient import *
|
from ClusterClient import *
|
||||||
import string
|
import string
|
||||||
|
|
||||||
# this is an array of offsets for the various servers. For example,
|
# A dictionary of information for various cluster configurations.
|
||||||
# mono-modelcave-pipe0 has one server with both a pos and hpr of 0.
|
# Dictionary is keyed on cluster-config string
|
||||||
# For mono-modelcave-pipe0, I decided to set the offsets in the
|
# Each dictionary contains a list of display configurations, one for
|
||||||
# actual configuration for the display.
|
# each display in the cluster
|
||||||
|
# Information that can be specified for each display:
|
||||||
|
# display name: Name of display (used in Configrc to specify server)
|
||||||
|
# display type: Used to flag client vs. server
|
||||||
|
# pos: positional offset of display's camera from main cluster group
|
||||||
|
# hpr: orientation offset of display's camera from main cluster group
|
||||||
|
# focal length: display's focal length (in mm)
|
||||||
|
# film size: display's film size (in inches)
|
||||||
|
# film offset: offset of film back (in inches)
|
||||||
|
# Note: Note, this overrides offsets specified in DirectCamConfig.py
|
||||||
|
# For now we only specify frustum for first display region of configuration
|
||||||
|
# TODO: Need to handle multiple display regions per cluster node and to
|
||||||
|
# generalize to non cluster situations
|
||||||
|
|
||||||
# Specify offset from client for each server's camera group
|
|
||||||
# Note: If server chan-config consists of multiple display regions
|
|
||||||
# each display region can have an additional offset as specified in
|
|
||||||
# DirectCamConfig.py
|
|
||||||
ClientConfigs = {
|
ClientConfigs = {
|
||||||
'mono-modelcave-pipe0': [{'pos' : Vec3(0),
|
'single-server' : [{'display name' : 'display0',
|
||||||
|
'pos' : Vec3(0),
|
||||||
'hpr' : Vec3(0)}
|
'hpr' : Vec3(0)}
|
||||||
],
|
],
|
||||||
'single-server' : [{'pos' : Vec3(0),
|
'two-server' : [{'display name' : 'display0',
|
||||||
'hpr' : Vec3(0)}
|
'pos' : Vec3(0),
|
||||||
],
|
|
||||||
'two-server' : [{'pos' : Vec3(0),
|
|
||||||
'hpr' : Vec3(-60,0,0)},
|
'hpr' : Vec3(-60,0,0)},
|
||||||
{'pos' : Vec3(0),
|
{'display name' : 'display1',
|
||||||
|
'pos' : Vec3(0),
|
||||||
'hpr' : Vec3(60,0,0)}
|
'hpr' : Vec3(60,0,0)}
|
||||||
],
|
],
|
||||||
'cavetest-old' : [{'pos' : Vec3(-0.105, -0.020, 5.000),
|
'mono-modelcave-pipe0': [{'display name' : 'display0',
|
||||||
'hpr' : Vec3(51.213, 0.000, 0.000),
|
'pos' : Vec3(0),
|
||||||
'focal length' : 0.809,
|
'hpr' : Vec3(0)},
|
||||||
'film size' : (1.000, 0.831),
|
{'display name' : 'display1',
|
||||||
'film offset' : (0.000, 0.173),
|
'pos' : Vec3(0),
|
||||||
},
|
'hpr' : Vec3(0)}
|
||||||
{'pos' : Vec3(-0.105, -0.020, 5.000),
|
|
||||||
'hpr' : Vec3(-0.370, 0.000, 0.000),
|
|
||||||
'focal length' : 0.815,
|
|
||||||
'film size' : (1.000, 0.831),
|
|
||||||
'film offset' : (0.000, 0.173),
|
|
||||||
},
|
|
||||||
{'pos' : Vec3(-0.105, -0.020, 5.000),
|
|
||||||
'hpr' : Vec3(-51.675, 0.000, 0.000),
|
|
||||||
'focal length' : 0.820,
|
|
||||||
'film size' : (1.000, 0.830),
|
|
||||||
'film offset' : (-0.000, 0.173),
|
|
||||||
},
|
|
||||||
{'pos' : Vec3(0.105, -0.020, 5.000),
|
|
||||||
'hpr' : Vec3(51.675, 0.000, 0.000),
|
|
||||||
'focal length' : 0.820,
|
|
||||||
'film size' : (1.000, 0.830),
|
|
||||||
'film offset' : (0.000, 0.173),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'cavetest' : [{'pos' : Vec3(-0.105, -0.020, 5.000),
|
|
||||||
'hpr' : Vec3(51.213, 0.000, 0.000),
|
|
||||||
'focal length' : 0.809,
|
|
||||||
'film size' : (1.000, 0.831),
|
|
||||||
'film offset' : (0.000, 0.173),
|
|
||||||
},
|
|
||||||
{'pos' : Vec3(-0.105, -0.020, 5.000),
|
|
||||||
'hpr' : Vec3(-0.370, 0.000, 0.000),
|
|
||||||
'focal length' : 0.815,
|
|
||||||
'film size' : (1.000, 0.831),
|
|
||||||
'film offset' : (0.000, 0.173),
|
|
||||||
},
|
|
||||||
{'pos' : Vec3(-0.105, -0.020, 5.000),
|
|
||||||
'hpr' : Vec3(-51.675, 0.000, 0.000),
|
|
||||||
'focal length' : 0.820,
|
|
||||||
'film size' : (1.000, 0.830),
|
|
||||||
'film offset' : (-0.000, 0.173),
|
|
||||||
},
|
|
||||||
{'pos' : Vec3(0.105, -0.020, 5.000),
|
|
||||||
'hpr' : Vec3(51.675, 0.000, 0.000),
|
|
||||||
'focal length' : 0.820,
|
|
||||||
'film size' : (1.000, 0.830),
|
|
||||||
'film offset' : (0.000, 0.173),
|
|
||||||
},
|
|
||||||
{'pos' : Vec3(0.105, -0.020, 5.000),
|
|
||||||
'hpr' : Vec3(0.370, 0.000, 0.000),
|
|
||||||
'focal length' : 0.815,
|
|
||||||
'film size' : (1.000, 0.831),
|
|
||||||
'film offset' : (0.000, 0.173),
|
|
||||||
},
|
|
||||||
{'pos' : Vec3(0.105, -0.020, 5.000),
|
|
||||||
'hpr' : Vec3(-51.213, 0.000, 0.000),
|
|
||||||
'focal length' : 0.809,
|
|
||||||
'film size' : (1.000, 0.831),
|
|
||||||
'film offset' : (-0.000, 0.173),
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
'cavetestsmall' : [{'display name' : 'la',
|
||||||
|
'pos' : Vec3(-0.105, -0.020, 5.000),
|
||||||
|
'hpr' : Vec3(51.213, 0.000, 0.000),
|
||||||
|
'focal length' : 0.809,
|
||||||
|
'film size' : (1.000, 0.831),
|
||||||
|
'film offset' : (0.000, 0.173),
|
||||||
|
},
|
||||||
|
{'display name' : 'lb',
|
||||||
|
'display mode' : 'client',
|
||||||
|
'pos' : Vec3(-0.105, -0.020, 5.000),
|
||||||
|
'hpr' : Vec3(-0.370, 0.000, 0.000),
|
||||||
|
'focal length' : 0.815,
|
||||||
|
'film size' : (1.000, 0.831),
|
||||||
|
'film offset' : (0.000, 0.173),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'cavetest' : [{'display name' : 'la',
|
||||||
|
'pos' : Vec3(-0.105, -0.020, 5.000),
|
||||||
|
'hpr' : Vec3(51.213, 0.000, 0.000),
|
||||||
|
'focal length' : 0.809,
|
||||||
|
'film size' : (1.000, 0.831),
|
||||||
|
'film offset' : (0.000, 0.173),
|
||||||
|
},
|
||||||
|
{'display name' : 'lb',
|
||||||
|
'display mode' : 'client',
|
||||||
|
'pos' : Vec3(-0.105, -0.020, 5.000),
|
||||||
|
'hpr' : Vec3(-0.370, 0.000, 0.000),
|
||||||
|
'focal length' : 0.815,
|
||||||
|
'film size' : (1.000, 0.831),
|
||||||
|
'film offset' : (0.000, 0.173),
|
||||||
|
},
|
||||||
|
{'display name' : 'lc',
|
||||||
|
'pos' : Vec3(-0.105, -0.020, 5.000),
|
||||||
|
'hpr' : Vec3(-51.675, 0.000, 0.000),
|
||||||
|
'focal length' : 0.820,
|
||||||
|
'film size' : (1.000, 0.830),
|
||||||
|
'film offset' : (-0.000, 0.173),
|
||||||
|
},
|
||||||
|
{'display name' : 'ra',
|
||||||
|
'pos' : Vec3(0.105, -0.020, 5.000),
|
||||||
|
'hpr' : Vec3(51.675, 0.000, 0.000),
|
||||||
|
'focal length' : 0.820,
|
||||||
|
'film size' : (1.000, 0.830),
|
||||||
|
'film offset' : (0.000, 0.173),
|
||||||
|
},
|
||||||
|
{'display name' : 'rb',
|
||||||
|
'pos' : Vec3(0.105, -0.020, 5.000),
|
||||||
|
'hpr' : Vec3(0.370, 0.000, 0.000),
|
||||||
|
'focal length' : 0.815,
|
||||||
|
'film size' : (1.000, 0.831),
|
||||||
|
'film offset' : (0.000, 0.173),
|
||||||
|
},
|
||||||
|
{'display name' : 'rc',
|
||||||
|
'pos' : Vec3(0.105, -0.020, 5.000),
|
||||||
|
'hpr' : Vec3(-51.213, 0.000, 0.000),
|
||||||
|
'focal length' : 0.809,
|
||||||
|
'film size' : (1.000, 0.831),
|
||||||
|
'film offset' : (-0.000, 0.173),
|
||||||
|
},
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
def createClusterManager():
|
|
||||||
# setup camera offsets based on cluster-config
|
|
||||||
clusterConfig = base.config.GetString('cluster-config', 'single-server')
|
|
||||||
# No cluster config specified!
|
|
||||||
if not ClientConfigs.has_key(clusterConfig):
|
|
||||||
base.notify.warning(
|
|
||||||
'display-client flag set, but %s cluster-config is undefined.' %
|
|
||||||
clusterConfig)
|
|
||||||
return None
|
|
||||||
# Get display config for each server in the cluster
|
|
||||||
displayConfigs = []
|
|
||||||
configList = ClientConfigs[clusterConfig]
|
|
||||||
numConfigs = len(configList)
|
|
||||||
for i in range(1,numConfigs):
|
|
||||||
configData = configList[i]
|
|
||||||
serverConfigName = 'display%d' % i
|
|
||||||
serverString = base.config.GetString(serverConfigName, '')
|
|
||||||
if serverString == '':
|
|
||||||
base.notify.warning(
|
|
||||||
'%s undefined in Configrc: expected by %s display client.' %
|
|
||||||
(serverConfigName,clusterConfig))
|
|
||||||
base.notify.warning('%s will not be used.' % serverConfigName)
|
|
||||||
else:
|
|
||||||
serverInfo = string.split(serverString)
|
|
||||||
serverName = serverInfo[0]
|
|
||||||
if len(serverInfo) > 1:
|
|
||||||
port = int(serverInfo[1])
|
|
||||||
else:
|
|
||||||
# Use default port
|
|
||||||
port = CLUSTER_PORT
|
|
||||||
cci = ClusterConfigItem(
|
|
||||||
serverConfigName,
|
|
||||||
serverName,
|
|
||||||
port)
|
|
||||||
# Init Cam Offset
|
|
||||||
pos = configData.get('pos', Vec3(0))
|
|
||||||
hpr = configData.get('hpr', Vec3(0))
|
|
||||||
cci.setCamOffset(pos, hpr)
|
|
||||||
# Init Frustum if specified
|
|
||||||
fl = configData.get('focalLength', None)
|
|
||||||
fs = configData.get('filmSize', None)
|
|
||||||
fo = configData.get('filmOffset', None)
|
|
||||||
if fl and fs and fo:
|
|
||||||
cci.setCamFrustum(fl, fs, fo)
|
|
||||||
displayConfigs.append(cci)
|
|
||||||
# Create Cluster Managers (opening connections to servers)
|
|
||||||
# Are the servers going to be synced?
|
|
||||||
synced = base.config.GetBool('sync-display', 0)
|
|
||||||
if synced:
|
|
||||||
base.win.setSync(1)
|
|
||||||
return ClusterManagerSync(displayConfigs)
|
|
||||||
else:
|
|
||||||
return ClusterManager(displayConfigs)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
"""ClusterMsgs module: Message types for Cluster rendering"""
|
"""ClusterMsgs module: Message types for Cluster rendering"""
|
||||||
|
|
||||||
# This module is intended to supply routines and dataformats common to
|
# This module is intended to supply routines and dataformats common to
|
||||||
# both ClusterClient and ClusterServer. There is a bit of sloppiness
|
# both ClusterClient and ClusterServer.
|
||||||
# though. For example:
|
|
||||||
# This is where datagrams are constructed for sending, but datagrams
|
|
||||||
# recieved are handled outside of here, after the header (message type
|
|
||||||
# and number) are read here.
|
|
||||||
|
|
||||||
from PandaModules import *
|
from PandaModules import *
|
||||||
import Datagram
|
import Datagram
|
||||||
@ -24,11 +20,11 @@ CLUSTER_EXIT = 100
|
|||||||
#Port number for cluster rendering
|
#Port number for cluster rendering
|
||||||
CLUSTER_PORT = 1970
|
CLUSTER_PORT = 1970
|
||||||
|
|
||||||
class MsgHandler:
|
class ClusterMsgHandler:
|
||||||
"""MsgHandler: wrapper for PC clusters/multi-piping networking"""
|
"""ClusterMsgHandler: 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
|
# packetStart can be used to distinguish which ClusterMsgHandler
|
||||||
# given packet.
|
# sends a given packet.
|
||||||
self.packetNumber = packetStart
|
self.packetNumber = packetStart
|
||||||
self.notify = notify
|
self.notify = notify
|
||||||
|
|
||||||
@ -76,7 +72,7 @@ class MsgHandler:
|
|||||||
dgi = DatagramIterator(datagram)
|
dgi = DatagramIterator(datagram)
|
||||||
number = dgi.getUint32()
|
number = dgi.getUint32()
|
||||||
type = dgi.getUint8()
|
type = dgi.getUint8()
|
||||||
self.notify.debug("Packet %d type %d recieved" % (number,type))
|
self.notify.debug("Packet %d type %d received" % (number,type))
|
||||||
return (dgi,type)
|
return (dgi,type)
|
||||||
|
|
||||||
def makeCamOffsetDatagram(self,xyz,hpr):
|
def makeCamOffsetDatagram(self,xyz,hpr):
|
||||||
@ -92,6 +88,16 @@ class MsgHandler:
|
|||||||
datagram.addFloat32(hpr[2])
|
datagram.addFloat32(hpr[2])
|
||||||
return datagram
|
return datagram
|
||||||
|
|
||||||
|
def parseCamOffsetDatagram(self, dgi):
|
||||||
|
x=dgi.getFloat32()
|
||||||
|
y=dgi.getFloat32()
|
||||||
|
z=dgi.getFloat32()
|
||||||
|
h=dgi.getFloat32()
|
||||||
|
p=dgi.getFloat32()
|
||||||
|
r=dgi.getFloat32()
|
||||||
|
self.notify.debug('new offset=%f %f %f %f %f %f' % (x,y,z,h,p,r))
|
||||||
|
return (x,y,z,h,p,r)
|
||||||
|
|
||||||
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)
|
||||||
@ -104,7 +110,16 @@ class MsgHandler:
|
|||||||
datagram.addFloat32(filmOffset[1])
|
datagram.addFloat32(filmOffset[1])
|
||||||
return datagram
|
return datagram
|
||||||
|
|
||||||
def makeMoveCamDatagram(self,xyz,hpr):
|
def parseCamFrustumDatagram(self, dgi):
|
||||||
|
focalLength = dgi.getFloat32()
|
||||||
|
filmSize = (dgi.getFloat32(), dgi.getFloat32())
|
||||||
|
filmOffset = (dgi.getFloat32(),dgi.getFloat32())
|
||||||
|
self.notify.debug('fl, fs, fo=%f, (%f, %f), (%f, %f)' %
|
||||||
|
(focalLength, filmSize[0], filmSize[1],
|
||||||
|
filmOffset[0], filmOffset[1]))
|
||||||
|
return (focalLength, filmSize, filmOffset)
|
||||||
|
|
||||||
|
def makeCamMovementDatagram(self,xyz,hpr):
|
||||||
datagram = Datagram.Datagram()
|
datagram = Datagram.Datagram()
|
||||||
datagram.addUint32(self.packetNumber)
|
datagram.addUint32(self.packetNumber)
|
||||||
self.packetNumber = self.packetNumber + 1
|
self.packetNumber = self.packetNumber + 1
|
||||||
@ -117,6 +132,17 @@ class MsgHandler:
|
|||||||
datagram.addFloat32(hpr[2])
|
datagram.addFloat32(hpr[2])
|
||||||
return datagram
|
return datagram
|
||||||
|
|
||||||
|
def parseCamMovementDatagram(self, dgi):
|
||||||
|
x=dgi.getFloat32()
|
||||||
|
y=dgi.getFloat32()
|
||||||
|
z=dgi.getFloat32()
|
||||||
|
h=dgi.getFloat32()
|
||||||
|
p=dgi.getFloat32()
|
||||||
|
r=dgi.getFloat32()
|
||||||
|
self.notify.debug((' new position=%f %f %f %f %f %f' %
|
||||||
|
(x,y,z,h,p,r)))
|
||||||
|
return (x,y,z,h,p,r)
|
||||||
|
|
||||||
def makeCommandStringDatagram(self, commandString):
|
def makeCommandStringDatagram(self, commandString):
|
||||||
datagram = Datagram.Datagram()
|
datagram = Datagram.Datagram()
|
||||||
datagram.addUint32(self.packetNumber)
|
datagram.addUint32(self.packetNumber)
|
||||||
@ -125,6 +151,10 @@ class MsgHandler:
|
|||||||
datagram.addString(commandString)
|
datagram.addString(commandString)
|
||||||
return datagram
|
return datagram
|
||||||
|
|
||||||
|
def parseCommandStringDatagram(self, dgi):
|
||||||
|
command = dgi.getString()
|
||||||
|
return command
|
||||||
|
|
||||||
def makeSwapNowDatagram(self):
|
def makeSwapNowDatagram(self):
|
||||||
datagram = Datagram.Datagram()
|
datagram = Datagram.Datagram()
|
||||||
datagram.addUint32(self.packetNumber)
|
datagram.addUint32(self.packetNumber)
|
||||||
|
@ -7,10 +7,6 @@ import DirectNotifyGlobal
|
|||||||
import DirectObject
|
import DirectObject
|
||||||
import Task
|
import Task
|
||||||
|
|
||||||
# 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
|
|
||||||
# group.
|
|
||||||
|
|
||||||
# Also, I'm not sure multiple camera-group configurations are working for the
|
# Also, I'm not sure multiple camera-group configurations are working for the
|
||||||
# cluster system.
|
# cluster system.
|
||||||
|
|
||||||
@ -18,138 +14,120 @@ class ClusterServer(DirectObject.DirectObject):
|
|||||||
notify = DirectNotifyGlobal.directNotify.newCategory("ClusterServer")
|
notify = DirectNotifyGlobal.directNotify.newCategory("ClusterServer")
|
||||||
MSG_NUM = 2000000
|
MSG_NUM = 2000000
|
||||||
|
|
||||||
def __init__(self,cameraGroup,camera):
|
def __init__(self,cameraJig,camera):
|
||||||
# Store information about the cluster's camera
|
# Store information about the cluster's camera
|
||||||
self.cameraGroup = cameraGroup
|
self.cameraJig = cameraJig
|
||||||
self.camera = camera
|
self.camera = camera
|
||||||
self.lens = camera.node().getLens()
|
self.lens = camera.node().getLens()
|
||||||
# Initialize camera offsets
|
|
||||||
self.posOffset = Vec3(0,0,0)
|
|
||||||
self.hprOffset = Vec3(0,0,0)
|
|
||||||
# Create network layer objects
|
|
||||||
self.lastConnection = None
|
self.lastConnection = None
|
||||||
|
self.fPosReceived = 0
|
||||||
|
# Create network layer objects
|
||||||
self.qcm = QueuedConnectionManager()
|
self.qcm = QueuedConnectionManager()
|
||||||
self.qcl = QueuedConnectionListener(self.qcm, 0)
|
self.qcl = QueuedConnectionListener(self.qcm, 0)
|
||||||
self.qcr = QueuedConnectionReader(self.qcm, 0)
|
self.qcr = QueuedConnectionReader(self.qcm, 0)
|
||||||
self.cw = ConnectionWriter(self.qcm,0)
|
self.cw = ConnectionWriter(self.qcm,0)
|
||||||
port = base.config.GetInt("cluster-server-port",CLUSTER_PORT)
|
port = base.config.GetInt('cluster-server-port', CLUSTER_PORT)
|
||||||
self.tcpRendezvous = self.qcm.openTCPServerRendezvous(port, 1)
|
self.tcpRendezvous = self.qcm.openTCPServerRendezvous(port, 1)
|
||||||
self.qcl.addConnection(self.tcpRendezvous)
|
self.qcl.addConnection(self.tcpRendezvous)
|
||||||
self.msgHandler = MsgHandler(ClusterServer.MSG_NUM,self.notify)
|
self.msgHandler = ClusterMsgHandler(ClusterServer.MSG_NUM, self.notify)
|
||||||
# Start cluster tasks
|
# Start cluster tasks
|
||||||
self.startListenerPollTask()
|
self.startListenerPollTask()
|
||||||
self.startReaderPollTask()
|
self.startReaderPollTask()
|
||||||
|
|
||||||
def startListenerPollTask(self):
|
def startListenerPollTask(self):
|
||||||
|
# Run this task near the start of frame, sometime after the dataloop
|
||||||
taskMgr.add(self.listenerPollTask, "serverListenerPollTask",-40)
|
taskMgr.add(self.listenerPollTask, "serverListenerPollTask",-40)
|
||||||
|
|
||||||
def listenerPollTask(self, task):
|
def listenerPollTask(self, task):
|
||||||
""" Task to listen for a new connection from the client """
|
""" Task to listen for a new connection from the client """
|
||||||
# Run this task after the dataloop
|
# Run this task after the dataloop
|
||||||
if self.qcl.newConnectionAvailable():
|
if self.qcl.newConnectionAvailable():
|
||||||
print "New connection is available"
|
self.notify.info("New connection is available")
|
||||||
rendezvous = PointerToConnection()
|
rendezvous = PointerToConnection()
|
||||||
netAddress = NetAddress()
|
netAddress = NetAddress()
|
||||||
newConnection = PointerToConnection()
|
newConnection = PointerToConnection()
|
||||||
retVal = self.qcl.getNewConnection(rendezvous, netAddress,
|
if self.qcl.getNewConnection(rendezvous,netAddress,newConnection):
|
||||||
newConnection)
|
|
||||||
if retVal:
|
|
||||||
# Crazy dereferencing
|
# Crazy dereferencing
|
||||||
newConnection=newConnection.p()
|
newConnection=newConnection.p()
|
||||||
self.qcr.addConnection(newConnection)
|
self.qcr.addConnection(newConnection)
|
||||||
print "Got a connection!"
|
|
||||||
self.lastConnection = newConnection
|
self.lastConnection = newConnection
|
||||||
|
self.notify.info("Got a connection!")
|
||||||
else:
|
else:
|
||||||
self.notify.warning(
|
self.notify.warning("getNewConnection returned false")
|
||||||
"getNewConnection returned false")
|
|
||||||
return Task.cont
|
return Task.cont
|
||||||
|
|
||||||
def startReaderPollTask(self):
|
def startReaderPollTask(self):
|
||||||
""" Task to handle datagrams from client """
|
""" Task to handle datagrams from client """
|
||||||
# Run this task just after the listener poll task and dataloop
|
# Run this task just after the listener poll task
|
||||||
taskMgr.add(self.readerPollTask, "serverReaderPollTask", -39)
|
taskMgr.add(self.readerPollTask, "serverReaderPollTask", -39)
|
||||||
|
|
||||||
def readerPollTask(self, state):
|
def readerPollTask(self, state):
|
||||||
# Process all available datagrams
|
""" Non blocking task to read all available datagrams """
|
||||||
while 1:
|
while 1:
|
||||||
(datagram, dgi,type) = self.msgHandler.nonBlockingRead(self.qcr)
|
(datagram, dgi,type) = self.msgHandler.nonBlockingRead(self.qcr)
|
||||||
|
# Queue is empty, done for now
|
||||||
if type is CLUSTER_NONE:
|
if type is CLUSTER_NONE:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
handleDatagram(dgi, type)
|
# Got a datagram, handle it
|
||||||
|
self.handleDatagram(dgi, type)
|
||||||
return Task.cont
|
return Task.cont
|
||||||
|
|
||||||
def handleDatagram(self, dgi, type):
|
def handleDatagram(self, dgi, type):
|
||||||
if type == CLUSTER_NONE:
|
""" Process a datagram depending upon type flag """
|
||||||
|
if (type == CLUSTER_NONE):
|
||||||
pass
|
pass
|
||||||
elif type == CLUSTER_EXIT:
|
elif (type == CLUSTER_EXIT):
|
||||||
import sys
|
import sys
|
||||||
sys.exit()
|
sys.exit()
|
||||||
elif type == CLUSTER_CAM_OFFSET:
|
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_CAM_MOVEMENT:
|
elif (type == CLUSTER_CAM_MOVEMENT):
|
||||||
self.handleCamMovement(dgi)
|
self.handleCamMovement(dgi)
|
||||||
elif type == CLUSTER_COMMAND_STRING:
|
elif (type == CLUSTER_COMMAND_STRING):
|
||||||
self.handleCommandString(dgi)
|
self.handleCommandString(dgi)
|
||||||
|
elif (type == CLUSTER_SWAP_READY):
|
||||||
|
pass
|
||||||
|
elif (type == CLUSTER_SWAP_NOW):
|
||||||
|
self.notify.debug('swapping')
|
||||||
|
base.win.swap()
|
||||||
else:
|
else:
|
||||||
self.notify.warning("Recieved unknown packet type:" % type)
|
self.notify.warning("Received unknown packet type:" % type)
|
||||||
return type
|
return type
|
||||||
|
|
||||||
|
# Server specific tasks
|
||||||
def handleCamOffset(self,dgi):
|
def handleCamOffset(self,dgi):
|
||||||
x=dgi.getFloat32()
|
""" Set offset of camera from cameraJig """
|
||||||
y=dgi.getFloat32()
|
(x,y,z,h,p,r) = self.msgHandler.parseCamOffsetDatagram(dgi)
|
||||||
z=dgi.getFloat32()
|
self.lens.setIodOffset(x)
|
||||||
h=dgi.getFloat32()
|
self.lens.setViewHpr(h,p,r)
|
||||||
p=dgi.getFloat32()
|
|
||||||
r=dgi.getFloat32()
|
|
||||||
self.notify.debug((' new offset=%f %f %f %f %f %f' %
|
|
||||||
(x,y,z,h,p,r)))
|
|
||||||
self.posOffset = Vec3(x,y,z)
|
|
||||||
self.hprOffset = Vec3(h,p,r)
|
|
||||||
|
|
||||||
def handleCamFrustum(self,dgi):
|
def handleCamFrustum(self,dgi):
|
||||||
focalLength=dgi.getFloat32()
|
""" Adjust camera frustum based on parameters sent by client """
|
||||||
filmSize=(dgi.getFloat32(), dgi.getFloat32())
|
(fl,fs,fo) = self.msgHandler.parseCamFrustumDatagram(dgi)
|
||||||
filmOffset=(dgi.getFloat32(),dgi.getFloat32())
|
self.lens.setFocalLength(fl)
|
||||||
self.notify.debug(' fl, fs, fo=%f, (%f, %f), (%f, %f)' %
|
self.lens.setFilmSize(fs[0], fs[1])
|
||||||
(focalLength, filmSize[0], filmSize[1],
|
self.lens.setFilmOffset(fo[0], fo[1])
|
||||||
filmOffset[0], filmOffset[1]))
|
|
||||||
self.lens.setFocalLength(focalLength)
|
|
||||||
self.lens.setFilmSize(filmSize[0], filmSize[1])
|
|
||||||
self.lens.setFilmOffset(filmOffset[0], filmOffset[1])
|
|
||||||
|
|
||||||
def handleCamMovement(self,dgi):
|
def handleCamMovement(self,dgi):
|
||||||
x=dgi.getFloat32()
|
""" Update cameraJig position to reflect latest position """
|
||||||
y=dgi.getFloat32()
|
(x,y,z,h,p,r) = self.msgHandler.parseCamMovementDatagram(dgi)
|
||||||
z=dgi.getFloat32()
|
self.cameraJig.setPosHpr(render,x,y,z,h,p,r)
|
||||||
h=dgi.getFloat32()
|
self.fPosReceived = 1
|
||||||
p=dgi.getFloat32()
|
|
||||||
r=dgi.getFloat32()
|
|
||||||
self.notify.debug((' new position=%f %f %f %f %f %f' %
|
|
||||||
(x,y,z,h,p,r)))
|
|
||||||
finalX = x + self.posOffset[0]
|
|
||||||
finalY = y + self.posOffset[1]
|
|
||||||
finalZ = z + self.posOffset[2]
|
|
||||||
finalH = h + self.hprOffset[0]
|
|
||||||
finalP = p + self.hprOffset[1]
|
|
||||||
finalR = r + self.hprOffset[2]
|
|
||||||
self.cameraGroup.setPosHpr(render,finalX,finalY,finalZ,
|
|
||||||
finalH,finalP,finalR)
|
|
||||||
|
|
||||||
def handleCommandString(self, dgi):
|
def handleCommandString(self, dgi):
|
||||||
command = dgi.getString()
|
""" Handle arbitrary command string from client """
|
||||||
exec( command, globals())
|
command = self.msgHandler.parseCommandStringDatagram(dgi)
|
||||||
|
exec( command, globals() )
|
||||||
|
|
||||||
class ClusterServerSync(ClusterServer):
|
class ClusterServerSync(ClusterServer):
|
||||||
|
|
||||||
def __init__(self,cameraGroup,camera):
|
def __init__(self,cameraJig,camera):
|
||||||
self.notify.info('starting ClusterServerSync')
|
self.notify.info('starting ClusterServerSync')
|
||||||
self.posRecieved = 0
|
ClusterServer.__init__(self,cameraJig,camera)
|
||||||
ClusterServer.__init__(self,cameraGroup,camera)
|
|
||||||
self.startSwapCoordinator()
|
self.startSwapCoordinator()
|
||||||
return None
|
|
||||||
|
|
||||||
def readerPollTask(self, task):
|
def readerPollTask(self, task):
|
||||||
if self.lastConnection is None:
|
if self.lastConnection is None:
|
||||||
@ -158,42 +136,32 @@ class ClusterServerSync(ClusterServer):
|
|||||||
# Process datagrams till you get a postion update
|
# Process datagrams till you get a postion update
|
||||||
type = CLUSTER_NONE
|
type = CLUSTER_NONE
|
||||||
while type != CLUSTER_CAM_MOVEMENT:
|
while type != CLUSTER_CAM_MOVEMENT:
|
||||||
|
# Block until you get a new datagram
|
||||||
(datagram,dgi,type) = self.msgHandler.blockingRead(self.qcr)
|
(datagram,dgi,type) = self.msgHandler.blockingRead(self.qcr)
|
||||||
if type == CLUSTER_CAM_MOVEMENT:
|
# Process datagram
|
||||||
# Move camera
|
self.handleDatagram(dgi,type)
|
||||||
self.handleCamMovement(dgi)
|
|
||||||
# Set flag for swap coordinator
|
|
||||||
self.posRecieved = 1
|
|
||||||
elif type == CLUSTER_CAM_OFFSET:
|
|
||||||
# Update camera offset
|
|
||||||
self.handleCamOffset(dgi)
|
|
||||||
elif type == CLUSTER_COMMAND_STRING:
|
|
||||||
# Got a command, execute it
|
|
||||||
self.handleCommandString(dgi)
|
|
||||||
return Task.cont
|
return Task.cont
|
||||||
|
|
||||||
def sendSwapReady(self):
|
def sendSwapReady(self):
|
||||||
self.notify.debug( ('send swap ready packet %d' %
|
self.notify.debug(
|
||||||
self.msgHandler.packetNumber ) )
|
'send swap ready packet %d' % self.msgHandler.packetNumber)
|
||||||
datagram = self.msgHandler.makeSwapReadyDatagram()
|
datagram = self.msgHandler.makeSwapReadyDatagram()
|
||||||
self.cw.send(datagram, self.lastConnection)
|
self.cw.send(datagram, self.lastConnection)
|
||||||
|
|
||||||
def startSwapCoordinator(self):
|
def startSwapCoordinator(self):
|
||||||
taskMgr.add(self.swapCoordinatorTask, "serverSwapCoordinator", 51)
|
taskMgr.add(self.swapCoordinatorTask, "serverSwapCoordinator", 51)
|
||||||
return None
|
|
||||||
|
|
||||||
def swapCoordinatorTask(self, task):
|
def swapCoordinatorTask(self, task):
|
||||||
if self.posRecieved:
|
if self.fPosReceived:
|
||||||
self.posRecieved = 0
|
self.fPosReceived = 0
|
||||||
|
# Alert client that this server is ready to swap
|
||||||
self.sendSwapReady()
|
self.sendSwapReady()
|
||||||
|
# Wait for swap command (processing any intermediate datagrams)
|
||||||
while 1:
|
while 1:
|
||||||
(datagram,dgi,type) = self.msgHandler.blockingRead(self.qcr)
|
(datagram,dgi,type) = self.msgHandler.blockingRead(self.qcr)
|
||||||
|
self.handleDatagram(dgi,type)
|
||||||
if type == CLUSTER_SWAP_NOW:
|
if type == CLUSTER_SWAP_NOW:
|
||||||
self.notify.debug('swapping')
|
|
||||||
base.win.swap()
|
|
||||||
break
|
break
|
||||||
else:
|
|
||||||
self.handleDatagram(dgi,type)
|
|
||||||
return Task.cont
|
return Task.cont
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ class DirectLight(NodePath):
|
|||||||
NodePath.__init__(self)
|
NodePath.__init__(self)
|
||||||
# Record light and name
|
# Record light and name
|
||||||
self.light = light
|
self.light = light
|
||||||
self.name = light.getName()
|
|
||||||
|
|
||||||
# Upcast the light object to its node base pointer
|
# Upcast the light object to its node base pointer
|
||||||
if isinstance(light, Spotlight):
|
if isinstance(light, Spotlight):
|
||||||
@ -25,7 +24,8 @@ class DirectLight(NodePath):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def getName(self):
|
def getName(self):
|
||||||
return self.name
|
return self.light.getName()
|
||||||
|
|
||||||
def getLight(self):
|
def getLight(self):
|
||||||
return self.light
|
return self.light
|
||||||
|
|
||||||
|
@ -113,6 +113,9 @@ class DirectManipulationControl(PandaObject):
|
|||||||
self.fScaling = 0
|
self.fScaling = 0
|
||||||
direct.selected.highlightAll()
|
direct.selected.highlightAll()
|
||||||
self.objectHandles.showAllHandles()
|
self.objectHandles.showAllHandles()
|
||||||
|
if direct.clusterMode == 'client':
|
||||||
|
direct.cluster.cmd(
|
||||||
|
'direct.manipulationControl.objectHandles.showAllHandles()')
|
||||||
self.objectHandles.hideGuides()
|
self.objectHandles.hideGuides()
|
||||||
# Restart followSelectedNodePath task
|
# Restart followSelectedNodePath task
|
||||||
self.spawnFollowSelectedNodePathTask()
|
self.spawnFollowSelectedNodePathTask()
|
||||||
@ -177,6 +180,11 @@ class DirectManipulationControl(PandaObject):
|
|||||||
self.objectHandles.showGuides()
|
self.objectHandles.showGuides()
|
||||||
self.objectHandles.hideAllHandles()
|
self.objectHandles.hideAllHandles()
|
||||||
self.objectHandles.showHandle(self.constraint)
|
self.objectHandles.showHandle(self.constraint)
|
||||||
|
if direct.clusterMode == 'client':
|
||||||
|
oh = 'direct.manipulationControl.objectHandles'
|
||||||
|
direct.cluster.cmd(oh + '.showGuides()', 0)
|
||||||
|
direct.cluster.cmd(oh + '.hideAllHandles()', 0)
|
||||||
|
direct.cluster.cmd(oh + ('.showHandle("%s")'% self.constraint))
|
||||||
# Record relationship between selected nodes and widget
|
# Record relationship between selected nodes and widget
|
||||||
direct.selected.getWrtAll()
|
direct.selected.getWrtAll()
|
||||||
# hide the bbox of the selected objects during interaction
|
# hide the bbox of the selected objects during interaction
|
||||||
|
@ -13,8 +13,6 @@ class DirectNodePath(NodePath):
|
|||||||
# Initialize the superclass
|
# Initialize the superclass
|
||||||
NodePath.__init__(self)
|
NodePath.__init__(self)
|
||||||
self.assign(nodePath)
|
self.assign(nodePath)
|
||||||
# Get a reasonable name
|
|
||||||
self.name = self.getName()
|
|
||||||
# Create a bounding box
|
# Create a bounding box
|
||||||
self.bbox = DirectBoundingBox(self)
|
self.bbox = DirectBoundingBox(self)
|
||||||
center = self.bbox.getCenter()
|
center = self.bbox.getCenter()
|
||||||
@ -45,10 +43,6 @@ class DirectNodePath(NodePath):
|
|||||||
def getMax(self):
|
def getMax(self):
|
||||||
return self.bbox.getMax()
|
return self.bbox.getMax()
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return ('NodePath:\t%s\n' % self.name)
|
|
||||||
|
|
||||||
|
|
||||||
class SelectedNodePaths(PandaObject):
|
class SelectedNodePaths(PandaObject):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.reset()
|
self.reset()
|
||||||
@ -91,6 +85,9 @@ class SelectedNodePaths(PandaObject):
|
|||||||
self.selectedDict[dnp.id()] = dnp
|
self.selectedDict[dnp.id()] = dnp
|
||||||
# And update last
|
# And update last
|
||||||
__builtin__.last = self.last = dnp
|
__builtin__.last = self.last = dnp
|
||||||
|
# Update cluster servers if this is a cluster client
|
||||||
|
if direct.clusterMode == 'client':
|
||||||
|
direct.cluster.selectNodePath(dnp)
|
||||||
return dnp
|
return dnp
|
||||||
|
|
||||||
def deselect(self, nodePath):
|
def deselect(self, nodePath):
|
||||||
@ -109,6 +106,9 @@ class SelectedNodePaths(PandaObject):
|
|||||||
self.deselectedDict[id] = dnp
|
self.deselectedDict[id] = dnp
|
||||||
# Send a message
|
# Send a message
|
||||||
messenger.send('DIRECT_deselectedNodePath', [dnp])
|
messenger.send('DIRECT_deselectedNodePath', [dnp])
|
||||||
|
# Update cluster servers if this is a cluster client
|
||||||
|
if direct.clusterMode == 'client':
|
||||||
|
direct.cluster.deselectNodePath(dnp)
|
||||||
return dnp
|
return dnp
|
||||||
|
|
||||||
def getSelectedAsList(self):
|
def getSelectedAsList(self):
|
||||||
@ -173,6 +173,17 @@ class SelectedNodePaths(PandaObject):
|
|||||||
|
|
||||||
def moveWrtWidgetAll(self):
|
def moveWrtWidgetAll(self):
|
||||||
self.forEachSelectedNodePathDo(self.moveWrtWidget)
|
self.forEachSelectedNodePathDo(self.moveWrtWidget)
|
||||||
|
# Update cluster if current display is a cluster client
|
||||||
|
if (direct.clusterMode == 'client') and (last is not None):
|
||||||
|
pos = Point3(0)
|
||||||
|
hpr = VBase3(0)
|
||||||
|
scale = VBase3(1)
|
||||||
|
decomposeMatrix(last.getMat(), scale, hpr, pos)
|
||||||
|
direct.cluster.cmd(
|
||||||
|
'last.setPosHprScale(%f,%f,%f,%f,%f,%f,%f,%f,%f)' %
|
||||||
|
(pos[0], pos[1], pos[2],
|
||||||
|
hpr[0], hpr[1], hpr[2],
|
||||||
|
scale[0], scale[1], scale[2]))
|
||||||
|
|
||||||
def moveWrtWidget(self, nodePath):
|
def moveWrtWidget(self, nodePath):
|
||||||
nodePath.setMat(direct.widget, nodePath.mDnp2Widget)
|
nodePath.setMat(direct.widget, nodePath.mDnp2Widget)
|
||||||
|
@ -7,7 +7,6 @@ from DirectGrid import *
|
|||||||
from DirectGeometry import *
|
from DirectGeometry import *
|
||||||
from DirectLights import *
|
from DirectLights import *
|
||||||
from DirectSessionPanel import *
|
from DirectSessionPanel import *
|
||||||
from DirectCamConfig import *
|
|
||||||
from ClusterClient import *
|
from ClusterClient import *
|
||||||
from ClusterServer import *
|
from ClusterServer import *
|
||||||
from tkSimpleDialog import askstring
|
from tkSimpleDialog import askstring
|
||||||
@ -241,7 +240,7 @@ class DirectSession(PandaObject):
|
|||||||
|
|
||||||
self.oobeVis = loader.loadModelOnce('models/misc/camera')
|
self.oobeVis = loader.loadModelOnce('models/misc/camera')
|
||||||
if self.oobeVis:
|
if self.oobeVis:
|
||||||
self.oobeVis.arc().setFinal(1)
|
self.oobeVis.node().setFinal(1)
|
||||||
|
|
||||||
if self.oobeMode:
|
if self.oobeMode:
|
||||||
# Position a target point to lerp the oobe camera to
|
# Position a target point to lerp the oobe camera to
|
||||||
@ -259,8 +258,7 @@ class DirectSession(PandaObject):
|
|||||||
# Remove any transformation on the models arc
|
# Remove any transformation on the models arc
|
||||||
self.oobeVis.clearMat()
|
self.oobeVis.clearMat()
|
||||||
# Make oobeCamera be a sibling of wherever camera is now.
|
# Make oobeCamera be a sibling of wherever camera is now.
|
||||||
cameraParent = NodePath(self.camera)
|
cameraParent = self.camera.getParent()
|
||||||
cameraParent.shorten(1)
|
|
||||||
# Prepare oobe camera
|
# Prepare oobe camera
|
||||||
self.oobeCamera.reparentTo(cameraParent)
|
self.oobeCamera.reparentTo(cameraParent)
|
||||||
self.oobeCamera.iPosHpr(self.trueCamera)
|
self.oobeCamera.iPosHpr(self.trueCamera)
|
||||||
@ -396,6 +394,12 @@ class DirectSession(PandaObject):
|
|||||||
self.undo()
|
self.undo()
|
||||||
elif (input == ']') or (input == '}'):
|
elif (input == ']') or (input == '}'):
|
||||||
self.redo()
|
self.redo()
|
||||||
|
|
||||||
|
#Pass along certain events if this display is a cluster client
|
||||||
|
if self.clusterMode == 'client':
|
||||||
|
if input in ('v','b','l','p', 'r', 'shift-r', 's', 't',
|
||||||
|
'shift-a', 'w'):
|
||||||
|
self.cluster.cmd('messenger.send("%s")' % input,0)
|
||||||
|
|
||||||
def select(self, nodePath, fMultiSelect = 0, fResetAncestry = 1):
|
def select(self, nodePath, fMultiSelect = 0, fResetAncestry = 1):
|
||||||
dnp = self.selected.select(nodePath, fMultiSelect)
|
dnp = self.selected.select(nodePath, fMultiSelect)
|
||||||
@ -409,7 +413,7 @@ class DirectSession(PandaObject):
|
|||||||
# Update the selectedNPReadout
|
# Update the selectedNPReadout
|
||||||
self.selectedNPReadout.reparentTo(aspect2d)
|
self.selectedNPReadout.reparentTo(aspect2d)
|
||||||
self.selectedNPReadout.setText(
|
self.selectedNPReadout.setText(
|
||||||
'Selected:' + dnp.name)
|
'Selected:' + dnp.getName())
|
||||||
# Show the manipulation widget
|
# Show the manipulation widget
|
||||||
self.widget.showWidget()
|
self.widget.showWidget()
|
||||||
# Update camera controls coa to this point
|
# Update camera controls coa to this point
|
||||||
|
Loading…
x
Reference in New Issue
Block a user