*** empty log message ***
This commit is contained in:
parent
ccfffc6fdc
commit
30f14e0b2c
|
|
@ -51,6 +51,16 @@ class ClusterClient(DirectObject.DirectObject):
|
|||
self.qcm=QueuedConnectionManager()
|
||||
self.serverList = []
|
||||
self.msgHandler = ClusterMsgHandler(ClusterClient.MGR_NUM, self.notify)
|
||||
|
||||
# A dictionary of objects that can be accessed by name
|
||||
self.objectMappings = {}
|
||||
|
||||
# a dictionary of name objects and the corresponding names of
|
||||
# objects they are to control on the server side
|
||||
self.controlMappings = {}
|
||||
self.controlOffsets = {}
|
||||
self.taggedObjects = {}
|
||||
|
||||
for serverConfig in configList:
|
||||
server = DisplayConnection(
|
||||
self.qcm, serverConfig.serverName,
|
||||
|
|
@ -78,6 +88,27 @@ class ClusterClient(DirectObject.DirectObject):
|
|||
self.notify.debug('post startMoveCam')
|
||||
self.startMoveSelectedTask()
|
||||
|
||||
|
||||
def startReaderPollTask(self):
|
||||
""" Task to handle datagrams from server """
|
||||
# Run this task just after the listener poll task
|
||||
taskMgr.add(self._readerPollTask, "clientReaderPollTask", -39)
|
||||
|
||||
def _readerPollTask(self, state):
|
||||
""" Non blocking task to read all available datagrams """
|
||||
|
||||
for server in self.serverList:
|
||||
datagrams = server.poll()
|
||||
for data in datagrams:
|
||||
self.handleDatagram(data[0],data[1])
|
||||
|
||||
return Task.cont
|
||||
|
||||
|
||||
def startControlObjectTask(self):
|
||||
self.notify.debug("moving control objects")
|
||||
taskMgr.add(self.controlObjectTask,"controlObjectTask")
|
||||
|
||||
def startSynchronizeTimeTask(self):
|
||||
self.notify.debug('broadcasting frame time')
|
||||
taskMgr.add(self.synchronizeTimeTask, "synchronizeTimeTask", -40)
|
||||
|
|
@ -94,6 +125,27 @@ class ClusterClient(DirectObject.DirectObject):
|
|||
self.notify.debug('adding move cam')
|
||||
taskMgr.add(self.moveCameraTask, "moveCamTask", 49)
|
||||
|
||||
|
||||
def controlObjectTask(self, task):
|
||||
for object in self.controlMappings:
|
||||
name = self.controlMappings[object][0]
|
||||
serverList = self.controlMappings[object][1]
|
||||
if (self.objectMapping.has_key(object)):
|
||||
self.moveObject(self.objectMappings[object],name,serverList,
|
||||
self.controlOffsets[object])
|
||||
|
||||
return Task.cont
|
||||
|
||||
def moveObject(self, nodePath, object, serverList, offset):
|
||||
self.notify.debug('moving object '+object)
|
||||
xyz = nodePath.getPos(render) + offset
|
||||
hpr = nodePath.getHpr(render)
|
||||
scale = nodePath.getScale(render)
|
||||
hidden = nodePath.isHidden()
|
||||
for server in serverList:
|
||||
self.serverList[server].sendMoveNamedObject(xyz,hpr,scale,hidden,object)
|
||||
|
||||
|
||||
def moveCameraTask(self, task):
|
||||
self.moveCamera(
|
||||
base.camera.getPos(render),
|
||||
|
|
@ -120,6 +172,39 @@ class ClusterClient(DirectObject.DirectObject):
|
|||
server.sendMoveSelected(xyz, hpr, scale)
|
||||
return Task.cont
|
||||
|
||||
|
||||
def addNamedObjectMapping(self,object,name):
|
||||
if (not self.objectMappings.has_key(name)):
|
||||
self.objectMappings[name] = object
|
||||
else:
|
||||
self.notify.debug('attempt to add duplicate named object: '+name)
|
||||
|
||||
def removeObjectMapping(self,name):
|
||||
if (self.objectMappings.has_key(name)):
|
||||
self.objectMappings.pop(name)
|
||||
|
||||
|
||||
def addControlMapping(self,objectName,controlledName, serverList = None,
|
||||
offset = None):
|
||||
if (not self.controlMappings.has_key(objectName)):
|
||||
if (serverList == None):
|
||||
serverList = range(len(self.serverList))
|
||||
if (offset == None):
|
||||
offset = Vec3(0,0,0)
|
||||
|
||||
self.controlMappings[objectName] = [controlledName,serverList]
|
||||
self.controlOffsets[objectName] = offset
|
||||
else:
|
||||
self.notify.debug('attempt to add duplicate controlled object: '+name)
|
||||
|
||||
def setControlMappingOffset(self,objectName,offset):
|
||||
if (self.controlMappings.has_key(objectName)):
|
||||
self.controlOffsets[objectName] = offset
|
||||
|
||||
def removeControlMapping(self,name):
|
||||
if (self.controlMappings.has_key(name)):
|
||||
self.controlMappings.pop(name)
|
||||
|
||||
def getNodePathFindCmd(self, nodePath):
|
||||
import string
|
||||
pathString = `nodePath`
|
||||
|
|
@ -131,10 +216,53 @@ class ClusterClient(DirectObject.DirectObject):
|
|||
else:
|
||||
return rootName
|
||||
|
||||
def getNodePathName(self, nodePath):
|
||||
import string
|
||||
pathString = `nodePath`
|
||||
index = string.find(pathString, '/')
|
||||
if index != -1:
|
||||
name = pathString[index+1:]
|
||||
return name
|
||||
else:
|
||||
return pathString
|
||||
|
||||
|
||||
def addObjectTag(self,object,selectFunction,deselectFunction,selectArgs,deselectArgs):
|
||||
newTag = {}
|
||||
newTag["selectFunction"] = selectFunction
|
||||
newTag["selectArgs"] = selectArgs
|
||||
newTag["deselectFunction"] = deselectFunction
|
||||
newTag["deselectArgs"] = deselectArgs
|
||||
self.taggedObjects[object] = newTag
|
||||
|
||||
|
||||
def removeObjectTag(self,object):
|
||||
|
||||
self.taggedObjects.pop(object)
|
||||
|
||||
|
||||
def selectNodePath(self, nodePath):
|
||||
self(self.getNodePathFindCmd(nodePath) + '.select()', 0)
|
||||
name = self.getNodePathName(nodePath)
|
||||
if self.taggedObjects.has_key(name):
|
||||
taskMgr.remove("moveSelectedTask")
|
||||
tag = self.taggedObjects[name]
|
||||
function = tag["selectFunction"]
|
||||
args = tag["selectArgs"]
|
||||
if (function != None):
|
||||
function(*args)
|
||||
else:
|
||||
self(self.getNodePathFindCmd(nodePath) + '.select()', 0)
|
||||
|
||||
|
||||
def deselectNodePath(self, nodePath):
|
||||
name = self.getNodePathName(nodePath)
|
||||
if self.taggedObjects.has_key(name):
|
||||
tag = self.taggedObjects[name]
|
||||
function = tag["deselectFunction"]
|
||||
args = tag["deselectArgs"]
|
||||
if (function != None):
|
||||
function(*args)
|
||||
self.startMoveSelectedTask()
|
||||
self(self.getNodePathFindCmd(nodePath) + '.deselect()', 0)
|
||||
|
||||
def sendCamFrustum(self, focalLength, filmSize, filmOffset, indexList=[]):
|
||||
|
|
@ -163,6 +291,31 @@ class ClusterClient(DirectObject.DirectObject):
|
|||
# Execute locally
|
||||
exec(commandString, __builtins__)
|
||||
|
||||
|
||||
def handleDatagram(self,dgi,type):
|
||||
if (type == CLUSTER_NONE):
|
||||
pass
|
||||
elif (type == CLUSTER_NAMED_OBJECT_MOVEMENT):
|
||||
self.handleNamedMovement(dgi)
|
||||
else:
|
||||
self.notify.warning("Received unsupported packet type:" % type)
|
||||
return type
|
||||
|
||||
def handleNamedMovement(self, dgi):
|
||||
""" Update cameraJig position to reflect latest position """
|
||||
(name,x, y, z, h, p, r, sx, sy, sz, hidden) = self.msgHandler.parseNamedMovementDatagram(
|
||||
dgi)
|
||||
if (self.objectMappings.has_key(name)):
|
||||
self.objectMappings[name].setPosHpr(render, x, y, z, h, p, r)
|
||||
self.objectMappings[name].setScale(render,sx,sy,sz)
|
||||
if (hidden):
|
||||
self.objectMappings[name].hide()
|
||||
else:
|
||||
self.objectMappings[name].show()
|
||||
else:
|
||||
self.notify.debug("recieved unknown named object command: "+name)
|
||||
|
||||
|
||||
def exit(self):
|
||||
# Execute remotely
|
||||
for server in self.serverList:
|
||||
|
|
@ -178,6 +331,7 @@ class ClusterClientSync(ClusterClient):
|
|||
#I probably don't need this
|
||||
self.waitForSwap = 0
|
||||
self.ready = 0
|
||||
print "creating synced client"
|
||||
self.startSwapCoordinatorTask()
|
||||
|
||||
def startSwapCoordinatorTask(self):
|
||||
|
|
@ -200,6 +354,8 @@ class ClusterClientSync(ClusterClient):
|
|||
base.graphicsEngine.flipFrame()
|
||||
self.notify.debug(
|
||||
"------------------------------------------END swap")
|
||||
|
||||
#print "syncing"
|
||||
return Task.cont
|
||||
|
||||
def moveCamera(self, xyz, hpr):
|
||||
|
|
@ -226,6 +382,25 @@ class DisplayConnection:
|
|||
self.qcr.addConnection(self.tcpConn)
|
||||
self.cw=ConnectionWriter(qcm, 0)
|
||||
|
||||
|
||||
|
||||
def poll(self):
|
||||
""" Non blocking task to read all available datagrams """
|
||||
dataGrams = []
|
||||
while 1:
|
||||
(datagram, dgi, type) = self.msgHandler.nonBlockingRead(self.qcr)
|
||||
# Queue is empty, done for now
|
||||
if type is CLUSTER_NONE:
|
||||
break
|
||||
else:
|
||||
# Got a datagram, add it to the list
|
||||
dataGrams.append([dgi, type, datagram])
|
||||
|
||||
return dataGrams
|
||||
|
||||
|
||||
|
||||
|
||||
def sendCamOffset(self, xyz, hpr):
|
||||
ClusterClient.notify.debug("send cam offset...")
|
||||
ClusterClient.notify.debug(("packet %d xyz, hpr=%f %f %f %f %f %f" %
|
||||
|
|
@ -246,6 +421,16 @@ class DisplayConnection:
|
|||
focalLength, filmSize, filmOffset)
|
||||
self.cw.send(datagram, self.tcpConn)
|
||||
|
||||
|
||||
def sendMoveNamedObject(self, xyz, hpr, name):
|
||||
ClusterClient.notify.debug("send named object 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.makeNamedObjectMovementDatagram(xyz, hpr,
|
||||
name)
|
||||
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" %
|
||||
|
|
|
|||
|
|
@ -9,16 +9,17 @@ from direct.distributed.PyDatagramIterator import PyDatagramIterator
|
|||
import time
|
||||
|
||||
#these are the types of messages that are currently supported.
|
||||
CLUSTER_NONE = 0
|
||||
CLUSTER_CAM_OFFSET = 1
|
||||
CLUSTER_CAM_FRUSTUM = 2
|
||||
CLUSTER_CAM_MOVEMENT = 3
|
||||
CLUSTER_SWAP_READY = 4
|
||||
CLUSTER_SWAP_NOW = 5
|
||||
CLUSTER_COMMAND_STRING = 6
|
||||
CLUSTER_SELECTED_MOVEMENT = 7
|
||||
CLUSTER_TIME_DATA = 8
|
||||
CLUSTER_EXIT = 100
|
||||
CLUSTER_NONE = 0
|
||||
CLUSTER_CAM_OFFSET = 1
|
||||
CLUSTER_CAM_FRUSTUM = 2
|
||||
CLUSTER_CAM_MOVEMENT = 3
|
||||
CLUSTER_SWAP_READY = 4
|
||||
CLUSTER_SWAP_NOW = 5
|
||||
CLUSTER_COMMAND_STRING = 6
|
||||
CLUSTER_SELECTED_MOVEMENT = 7
|
||||
CLUSTER_TIME_DATA = 8
|
||||
CLUSTER_NAMED_OBJECT_MOVEMENT = 9
|
||||
CLUSTER_EXIT = 100
|
||||
|
||||
#Port number for cluster rendering
|
||||
# DAEMON PORT IS PORT USED FOR STARTUP MESSAGE EXCHANGE
|
||||
|
|
@ -156,6 +157,24 @@ class ClusterMsgHandler:
|
|||
datagram.addFloat32(hpr[2])
|
||||
return datagram
|
||||
|
||||
def makeNamedObjectMovementDatagram(self, xyz, hpr, scale, hidden, name):
|
||||
datagram = PyDatagram()
|
||||
datagram.addUint32(self.packetNumber)
|
||||
self.packetNumber = self.packetNumber + 1
|
||||
datagram.addUint8(CLUSTER_NAMED_OBJECT_MOVEMENT)
|
||||
datagram.addString(name)
|
||||
datagram.addFloat32(xyz[0])
|
||||
datagram.addFloat32(xyz[1])
|
||||
datagram.addFloat32(xyz[2])
|
||||
datagram.addFloat32(hpr[0])
|
||||
datagram.addFloat32(hpr[1])
|
||||
datagram.addFloat32(hpr[2])
|
||||
datagram.addFloat32(scale[0])
|
||||
datagram.addFloat32(scale[1])
|
||||
datagram.addFloat32(scale[2])
|
||||
datagram.addBool(hidden)
|
||||
return datagram
|
||||
|
||||
def parseCamMovementDatagram(self, dgi):
|
||||
x=dgi.getFloat32()
|
||||
y=dgi.getFloat32()
|
||||
|
|
@ -167,6 +186,21 @@ class ClusterMsgHandler:
|
|||
(x, y, z, h, p, r)))
|
||||
return (x, y, z, h, p, r)
|
||||
|
||||
def parseNamedMovementDatagram(self, dgi):
|
||||
name = dgi.getString()
|
||||
x=dgi.getFloat32()
|
||||
y=dgi.getFloat32()
|
||||
z=dgi.getFloat32()
|
||||
h=dgi.getFloat32()
|
||||
p=dgi.getFloat32()
|
||||
r=dgi.getFloat32()
|
||||
sx = dgi.getFloat32()
|
||||
sy = dgi.getFloat32()
|
||||
sz = dgi.getFloat32()
|
||||
hidden = dgi.getBool()
|
||||
return (name,x, y, z, h, p, r, sx, sy, sz, hidden)
|
||||
|
||||
|
||||
def makeSelectedMovementDatagram(self, xyz, hpr, scale):
|
||||
datagram = PyDatagram()
|
||||
datagram.addUint32(self.packetNumber)
|
||||
|
|
@ -181,6 +215,7 @@ class ClusterMsgHandler:
|
|||
datagram.addFloat32(scale[0])
|
||||
datagram.addFloat32(scale[1])
|
||||
datagram.addFloat32(scale[2])
|
||||
#datagram.addBool(hidden)
|
||||
return datagram
|
||||
|
||||
def parseSelectedMovementDatagram(self, dgi):
|
||||
|
|
|
|||
|
|
@ -54,6 +54,12 @@ class ClusterServer(DirectObject.DirectObject):
|
|||
globalClock.setMode(ClockObject.MSlave)
|
||||
# Send verification of startup to client
|
||||
self.daemon = DirectD()
|
||||
|
||||
self.objectMappings = {}
|
||||
self.controlMappings = {}
|
||||
self.controlOffsets = {}
|
||||
|
||||
|
||||
# These must be passed in as bootstrap arguments and stored in
|
||||
# the __builtins__ namespace
|
||||
try:
|
||||
|
|
@ -66,6 +72,8 @@ class ClusterServer(DirectObject.DirectObject):
|
|||
clusterDaemonPort = CLUSTER_DAEMON_PORT
|
||||
self.daemon.serverReady(clusterDaemonClient, clusterDaemonPort)
|
||||
|
||||
|
||||
|
||||
def startListenerPollTask(self):
|
||||
# Run this task near the start of frame, sometime after the dataLoop
|
||||
taskMgr.add(self.listenerPollTask, "serverListenerPollTask", -40)
|
||||
|
|
@ -88,6 +96,58 @@ class ClusterServer(DirectObject.DirectObject):
|
|||
self.notify.warning("getNewConnection returned false")
|
||||
return Task.cont
|
||||
|
||||
|
||||
def addNamedObjectMapping(self,object,name):
|
||||
if (not self.objectMappings.has_key(name)):
|
||||
self.objectMappings[name] = object
|
||||
else:
|
||||
self.notify.debug('attempt to add duplicate named object: '+name)
|
||||
|
||||
def removeObjectMapping(self,name):
|
||||
if (self.objectMappings.has_key(name)):
|
||||
self.objectMappings.pop(name)
|
||||
|
||||
|
||||
def addControlMapping(self,objectName,controlledName, offset = None):
|
||||
if (not self.controlMappings.has_key(objectName)):
|
||||
self.controlMappings[objectName] = controlledName
|
||||
if (offset == None):
|
||||
offset = Vec3(0,0,0)
|
||||
self.controlOffsets[objectName] = offset
|
||||
else:
|
||||
self.notify.debug('attempt to add duplicate controlled object: '+name)
|
||||
|
||||
def setControlMappingOffset(self,objectName,offset):
|
||||
if (self.controlMappings.has_key(objectName)):
|
||||
self.controlOffsets[objectName] = offset
|
||||
|
||||
|
||||
def removeControlMapping(self,name):
|
||||
if (self.controlMappings.has_key(name)):
|
||||
self.controlMappings.pop(name)
|
||||
|
||||
|
||||
def startControlObjectTask(self):
|
||||
self.notify.debug("moving control objects")
|
||||
taskMgr.add(self.controlObjectTask,"controlObjectTask")
|
||||
|
||||
def controlObjectTask(self, task):
|
||||
for object in self.controlMappings:
|
||||
name = self.controlMappings[object]
|
||||
if (self.objectMappings.has_key(object)):
|
||||
self.moveObject(self.objectMappings[object],name,self.controlOffsets[object])
|
||||
|
||||
return Task.cont
|
||||
|
||||
def moveObject(self, nodePath, object, offset):
|
||||
self.notify.debug('moving object '+object)
|
||||
xyz = nodePath.getPos(render) + offset
|
||||
hpr = nodePath.getHpr(render)
|
||||
scale = nodePath.getScale(render)
|
||||
hidden = nodePath.isHidden()
|
||||
datagram = self.msgHandler.makeNamedObjectMovementDatagram(xyz,hpr,scale,hidden,object)
|
||||
self.cw.send(datagram, self.lastConnection)
|
||||
|
||||
def startReaderPollTask(self):
|
||||
""" Task to handle datagrams from client """
|
||||
# Run this task just after the listener poll task
|
||||
|
|
@ -171,6 +231,8 @@ class ClusterServer(DirectObject.DirectObject):
|
|||
elif (type == CLUSTER_TIME_DATA):
|
||||
self.notify.debug('time data')
|
||||
self.handleTimeData(dgi)
|
||||
elif (type == CLUSTER_NAMED_OBJECT_MOVEMENT):
|
||||
self.handleNamedMovement(dgi)
|
||||
else:
|
||||
self.notify.warning("Received unknown packet type:" % type)
|
||||
return type
|
||||
|
|
@ -189,11 +251,25 @@ class ClusterServer(DirectObject.DirectObject):
|
|||
self.lens.setFilmSize(fs[0], fs[1])
|
||||
self.lens.setFilmOffset(fo[0], fo[1])
|
||||
|
||||
def handleNamedMovement(self, dgi):
|
||||
""" Update cameraJig position to reflect latest position """
|
||||
(name,x, y, z, h, p, r,sx,sy,sz, hidden) = self.msgHandler.parseNamedMovementDatagram(
|
||||
dgi)
|
||||
if (self.objectMappings.has_key(name)):
|
||||
self.objectMappings[name].setPosHpr(render, x, y, z, h, p, r)
|
||||
self.objectMappings[name].setScale(render,sx,sy,sz)
|
||||
if (hidden):
|
||||
self.objectMappings[name].hide()
|
||||
else:
|
||||
self.objectMappings[name].show()
|
||||
else:
|
||||
self.notify.debug("recieved unknown named object command: "+name)
|
||||
|
||||
def handleCamMovement(self, dgi):
|
||||
""" Update cameraJig position to reflect latest position """
|
||||
(x, y, z, h, p, r) = self.msgHandler.parseCamMovementDatagram(dgi)
|
||||
self.cameraJig.setPosHpr(render, x, y, z, h, p, r)
|
||||
self.fPosReceived = 1
|
||||
self.fPosReceived = 1
|
||||
|
||||
def handleSelectedMovement(self, dgi):
|
||||
""" Update cameraJig position to reflect latest position """
|
||||
|
|
|
|||
Loading…
Reference in New Issue