Example #1
0
	def _setParam(self,scn,context,partindex,nparts):
		"""
		Initializes scene and context for rendering a given part.

		Also saves the altered parameters of scene and context for
		later restoration by L{_resetParam()}. See L{NetworkRender.StillRenderThread}
		for typical use.

		@param scn: the current scene
		@type scn : Blender.Scene
		@param context: the current render context
		@type context: Scene.Renderdata
		@param partindex: the number of parts in either direction
		@type partindex: int
		@param nparts: the number of parts in either direction
		@type nparts: int.

		@requires: nparts = 2,3,4,5, ....
		@requires: partindex = [0, nparts^2 >
		"""

		self.nparts = nparts
		self.cam = Camera.Get(scn.getCurrentCamera().getName())
		self.scn = scn
		self.depth = context.imagePlanes
		self.aspx = float(context.sizeX) / float(context.sizeY)
		self.aspy = float(context.sizeY) / float(context.sizeX)
		self.camipo = None	  
		if self.cam.ipo:
			self.camipo = self.cam.ipo
			self.cam.ipo = None
		self.lens = self.cam.lens
		self.scale = self.cam.scale
		self.shiftX = self.cam.shiftX
		self.shiftY = self.cam.shiftY
		self.path = context.renderPath
		
		self.cam.scale = (self.scale / (nparts + 1))  
		self.cam.lens = (self.lens * (nparts))
	
		tileStart = [ i * -0.5 for i in range(nparts + 1)]
		print partindex, nparts, tileStart
		y = int(partindex/nparts)
		x = partindex%nparts
		shiftY = (-tileStart[nparts - 1] - float(y))
		shiftX = (float(x) + tileStart[nparts - 1])

		if self.aspx > 1.0 :
			shiftY /= self.aspx
		else :
			shiftX /= self.aspy

		self.cam.shiftX = shiftX
		self.cam.shiftY = shiftY

		debug('x=%d y=%d shiftX=%4.2f shiftY=%4.2f index=%d nparts%d'%(x, y, shiftX, shiftY, partindex, nparts))
	def renderPart(self, scenename, partindex, nparts, imageType):
		"""
		Render a single part of a multipart still. 
		@scenename: the name of the scene to render
		@partindex: the partnumber to render ( 0 <= partindex < nparts^2 ) 
		@nparts   : the number of parts a still is divided in both directions
		@imageType: type of output image

		Based on Macouno's Really Big Render ( http://www.alienhelpdesk.com/python_scripts/really_big_render )
		Kudos to him, implementation errors are entirely mine.
		See NetworkRender.PartRenderer for additional info.
		"""

		import bpy
		lib = bpy.libraries.load(self.name)
		print self.name,' loaded'
		scn = lib.scenes.link(scenename)
		context = scn.getRenderingContext()
		print 'remote render start part',partindex
		context.displayMode = 0 # to prevent an additional render window popping up

		self._PartName(partindex, nparts)
		# change camera related stuff
		self._setParam(scn, context, partindex, nparts)
		scn.update()
		context.renderPath = self.result
		f = context.currentFrame()

		# remember to restore later!
		s,context.sFrame = context.sFrame,f
		e,context.eFrame = context.eFrame,f
		oldImagetype = context.imageType
		oldWidth, oldHeight = context.sizeX, context.sizeY
		oldRenderPath = context.getRenderPath()

		context.imageType = imageType
		context.sizeX /= self.nparts
		context.sizeY /= self.nparts
		context.setRenderPath(configurer.get('ServerRenderPath'))
		debug('current=%d start=%d end=%d' % (f, context.sFrame, context.eFrame))
		debug('start render')
		context.renderPath = self.result
		context.renderAnim() # because .render doesn't work in the background
		self.result = context.getFrameFilename()

		# Restore changed settings
		context.sFrame,context.eFrame = s,e
		context.imageType = oldImagetype
		context.setRenderPath(oldRenderPath)
		context.sizeX, context.sizeY = oldWidth, oldHeight

		self._resetParam(scn,context)

		print 'remote render end part',partindex
		return 'render finished'
Example #3
0
	def _sendBlendFile(self):
		"""
		Sent saved .blendfile if needed.

		Uploads saved .blend file to remote host if not already done so.
		"""

		if self.isLocal() or self.blendSent:
			pass
		else:
			self.rpcserver.newfile()
			fd = open(self.name, 'rb', self.configurer.get('ServerBufferSize'))
			debug('%s sending .blend: %s'%(self.uri, fd))
			n = 0
			buffer = True
			while buffer :
				buffer = fd.read(self.configurer.get('ServerBufferSize'))
				if buffer:
					r = self.rpcserver.put(Binary(buffer))
					debug('%s put response %s' % (self.uri, r))
					n = n + 1
					debug('%s %d blocks put'%(self.uri, n))
			fd.close()
			r = self.rpcserver.endfile()
			debug('%s endfile called, response %s'%(self.uri, r))
		self.blendSent = True
Example #4
0
	def registerNode(self, uri):
		"""
		Register rendering node
		"""

		nodeData = self.uriMap.get(uri)
		if (nodeData == None or self.reusable(uri)):
			debug('spawning new thread for %s' % uri)
			rt = self.factory(uri, self.scenename, self.context,
							self.name, self.fqueue,
							self.squeue,*self.args)
			self.r.append(rt)
			self.uriMap[uri] = {'renderThread': rt}
			rt.start()
	def _renderFrame(self):
		debug('%s render started for frame %d'%(self.uri,self.frame))
		if self.isLocal():
			self.context.currentFrame(self.frame)

			# remember to restore later!
			s,self.context.sFrame = self.context.sFrame,self.frame
			e,self.context.eFrame = self.context.eFrame,self.frame
			oldImagetype = self.context.imageType

			self.context.imageType = self.imageType
			self.context.renderAnim()
			self.result = self.context.getFrameFilename()

			# Restore changed settings
			self.context.sFrame,self.context.eFrame = s,e
			self.context.imageType = oldImagetype
		else:
			self.rpcserver.renderFrame(self.scenename, self.frame, self.imageType)
		debug('%s render completed for frame %d'%(self.uri, self.frame))
Example #6
0
	def reusable(self, uri):
		nodeData = self.uriMap.get(uri)

		rt = nodeData['renderThread']

		# Check is thread still alive and not failed
		if (not rt.serviceAlive()):
			# Thread is not alive because of remote server caught an
			# unhandled exception. But is this case remote server freezes.
			# So, a ping pocket from this server means this server is restarted
			# and we could reuse this thread

			# It would be safer to manually request stopping of thread
			rt.requestStop()

			debug('node uri %s caught a failure, but send a ping pocket again.')

			return True

		return False
	def broadcast_uri(self):
		from time import sleep
		global running, configurer
		bcast = configurer.get('ServerBCast')
		port = configurer.get('ClientPort')
		delay = configurer.get('ServerBCastInterval')
		while running:
			# Broadcast server's address
			if (bcast != ''):
				debug('Broadcast server URI %s to all clients on %s:%d' %
					(self.uri, bcast, port))
				self.broadcast.sendto(self.uri, (bcast, port))

			# Try to send server's data to clients from static map
			for staticClient in self.staticMap:
				map = self.staticMap[staticClient]
				debug('Send server URI %s to client %s:%d' %
					(map['serverURI'], staticClient, port))
				self.broadcast.sendto(map['serverURI'], (staticClient, port))

			sleep(delay)
Example #8
0
	def run(self):
		"""
		Run as long as there is work available in the workqueue.
		
		If an exception is caught while rendering, the workitem is put
		back on the worklist and a statistic is recorded as a failed render.

		@warning: Note that this might end up as an endless loop if a remote server
		continues to fail and the localhost thread is never fast enough to
		snatch the workitem from the queue. This needs some work!
		"""

		# this might not be correct, get(nonblocking) better?
		while not self.stop and not self.frames.empty():
			debug('%s retrieving frame from queue' % self.uri) 
			frame = self.frames.get()
			ts = time.time()
			debug('%s got frame %d' % (self.uri,frame))

			try:
				self.render(frame) # provided by mixin/subclass
			except (xmlrpclib.Error, socket.error),e:
				print 'remote exception caught',e
				print 'requeueing frame',frame

				# Need this for correct joining to the frame queue
				# (formally task is done and queue after requeueing of buggy
				# frame it will be another task)
				self.frames.task_done()

				self.frames.put(frame)
				te = time.time()
				self.stats.put((self.uri, frame, te - ts, 1, 'none'))
				self.failure = True
				break 

			te = time.time()
			self.frames.task_done()
			self.stats.put((self.uri, frame, te - ts, 0, self.result))
	def __init__(self, address, handler):
		global configurer

		SimpleXMLRPCServer.__init__(self, address, handler)
		self.broadcast = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

		# Allow the socket to broadcast, set e socket options.
		self.broadcast.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

		self.ip = configurer.get('ServerAddr');
		if (self.ip == '0.0.0.0'):
			self.ip = socket.gethostbyname(socket.gethostname())

		self.uri = 'http://' + self.ip + ':' + str(configurer.get('ServerPort'))

		self.staticMap = {}
		sMap = configurer.get('ServerStaticMap')

		debug('Parsing static server string specification "%s"...' % (sMap))

		dummyMap = sMap.split(',')
		for x in dummyMap:
			if (x.strip() == ''):
				continue

			debug('Parsing static server data "%s"...' % (x))
			dummy = x.split(':')

			if (len(dummy) == 1):
				dummy.append(self.ip)

			if (len(dummy) != 2):
				continue

			self.staticMap[dummy[0]] = {'serverIP': dummy[1].strip(),
									    'serverURI': 'http://' +
									    dummy[1].strip() +
									    ':' + str(configurer.get('ServerPort'))}
Example #10
0
	def run(self):
		"""
		Listen and spawn new worker threads if appropriate.

		Overridden from Thread. Implements a stoppable loop (stops
		when requestStop is called on this thread) and records with
		workerthreads were spawned.
		"""

		import time
		self.stop = False
		self.r = []
		self.uriMap = {}

		# Register static list of server
		servers = self.configurer.get('ClientServerList').split(',')
		for server in servers:
			if (server == ''):
				continue
			serverData = server.split(':')
			if (len (serverData) == 1):
				serverData.append(str(self.configurer.get('ServerPort')))
			self.registerNode('http://' + serverData[0].strip() + ':' +
							serverData[1].strip())

		while not self.stop:
			debug('UDPlistener ready for request on %s,%s' % self.socket.getsockname())
			try:
				self.socket.settimeout(5)
				data, addr = self.socket.recvfrom(512)
				debug('UDPlistener received request: %s from %s' % (data, addr))
				self.registerNode(data)
			except (socket.timeout) :
				debug('UDPlistener received nothing, will try again')
			finally:
				time.sleep(self.configurer.get('ServerBCastInterval'))
		debug('UDPlistener stopped')
Example #11
0
	def __init__(self, scenename, context, name, fqueue, squeue, threadfactory, *args):
		"""
		Initialize a Listener instance.
		@param scenename: name of current scene
		@type scenename: string
		@param context: rendercontext of current scene
		@type context: Blender.Renderdata
		@param name: filename of saved .blend file
		@type name: string
		@param fqueue: worklist queue
		@type fqueue: Queue.queue
		@param squeue: statistics queue
		@type squeue: Queue.queue
		@param threadfactory: a classfactory to spawn worker threads
		@type threadfactory: NetworkRender.Renderthread
		@param args: additional arguments to be given to the threadfactory
		"""

		Thread.__init__(self)
		self.scenename = scenename
		self.context = context
		self.name = name
		self.factory = threadfactory
		self.fqueue = fqueue
		self.squeue = squeue
		self.args = args
		self.configurer = Configurer()
		debug('UDPlistener starting')
		self.socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)	
		debug('UDPlistener socket created %s' % self.socket)
		self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
		debug('UDPlistener options set')
		#self.ip = socket.gethostbyname(socket.gethostname())
		self.ip = '0.0.0.0'
		self.socket.bind((self.ip, self.configurer.get('ClientPort')))
		debug('UDPlistener listening on %s'%self.socket)
# the worklist (either part- or framenumbers)
frames = Queue()

# statistics are communicated by the renderthreads via this queue
stats = Queue()

# lets start!
starttime = time.time()

# save the current .blend
(scn, context, scenename, name) = NetworkRender.saveblend()

# initialize the worklist
for frame in range(parts * parts):
	debug('queueing frame %d' %frame)
	frames.put(frame)

# start listening for remote servers
from NetworkRender.Listener import Listener
listener = Listener(scenename, context, name, frames, \
				stats, StillRenderThread, parts, imageType)
listener.start()

# create a local renderer (we wont let others do all the dirty work :-)
if localRendering:
	localrenderer = StillRenderThread('localhost', scenename, context, \
									name, frames, stats, parts, imageType)

# start the local renderer
if localRendering:
	def _renderStill(self):
		debug('%s render started for frame %d'%(self.uri,self.frame))
		if self.isLocal():
			self._PartName(self.frame, self.nparts)
			debug('partname set')
			self._setParam(self.scn, self.context, self.frame, self.nparts)
			debug('setparam done')
			self.scn.update()
			self.context.renderPath = self.result
			debug('renderpath before %s'%self.context.renderPath)
			f = self.context.currentFrame()

			# remember to restore later!
			s,self.context.sFrame = self.context.sFrame,f
			e,self.context.eFrame = self.context.eFrame,f
			oldImagetype = self.context.imageType
			oldWidth, oldHeight = self.context.sizeX, self.context.sizeY

			debug('current=%d start=%d end=%d' % (f, self.context.sFrame, self.context.eFrame))
			debug('start render')

			self.context.imageType = self.imageType
			self.context.sizeX /= self.nparts
			self.context.sizeY /= self.nparts
			self.context.renderAnim() # because .render doesn't work in the background
			self.result = self.context.getFrameFilename()

			# Restore changed settings
			self.context.sFrame,self.context.eFrame = s,e
			self.context.imageType = oldImagetype
			self.context.sizeX,self.context.sizeY = oldWidth, oldHeight

			#self.context.saveRenderedImage(self.result, 0)
			debug('resetparam')
			self._resetParam(self.scn, self.context)
			debug('renderpath after %s'%self.context.renderPath)
		else:
			self.rpcserver.renderPart(self.scenename, self.frame, \
									self.nparts, self.imageType)

		debug('%s render completed for frame %d'%(self.uri, self.frame))
Example #14
0
	def _getResult(self):
		"""
		Download rendered frame or part from remote server.
		"""

		debug('%s saving frame %d'%(self.uri, self.frame))
		if not self.isLocal():
			debug('%s getting remote frame %d'%(self.uri, self.frame))
			rname = self.rpcserver.getResult()

			from tempfile import mkstemp
			import os
			from os import path

			remotedir,remotefile = path.split(rname)
			if self.animation == True :
				localdir,localfile = path.split(self.context.getFrameFilename())
				name = path.join(localdir,remotefile)

			fd,tname = mkstemp(suffix = remotefile)
			os.close(fd)
			debug('%s saving remote frame %d as tempfile %s' %
				(self.uri, self.frame, tname))
			fd = open(tname,'wb',self.configurer.get('ServerBufferSize'))

			while True:
				data = str(self.rpcserver.get())
				if len(data) <= 0:
					fd.close()
					break
				else:
					fd.write(str(data))

			fd.close()
			if self.animation == True :
				debug('%s frame %d renaming %s to %s'%(self.uri,self.frame, tname, name))
				if os.access(name, os.F_OK):
					os.unlink(name) # windows won't let us rename to an existing file
				debug("%s %s exists? %s" % (self.uri,tname, os.access(tname, os.F_OK)))
				os.rename(tname,name)

				# why all this trouble? the source file on the serverside might
				# be on the exact same location as the file we try to write
				# on the clientside if we run the server and the on the same
				# machine (as we might do for testing)
				self.result = name
			else :
				self.result = tname

			print 'Saved: %s (remotely rendered)'% self.result
		else:
			print 'Saved: %s (locally rendered)'% self.result
			pass
		debug('%s saving frame %d done'%(self.uri,self.frame))
# the worklist (either part- or framenumbers)
frames = Queue()

# statistics are communicated by the renderthreads via this queue
stats = Queue()

# lets start!
starttime = time.time()

# save the current .blend
(scn, context, scenename, name) = NetworkRender.saveblend()

# initialize the worklist
for frame in range(context.sFrame, context.eFrame + 1):
    debug("queueing frame %d" % frame)
    frames.put(frame)

# start listening for remote servers
from NetworkRender.Listener import Listener

listener = Listener(scenename, context, name, frames, stats, AnimRenderThread, imageType)
listener.start()

# create a local renderer (we wont let others do all the dirty work :-)
if localRendering:
    localrenderer = AnimRenderThread("localhost", scenename, context, name, frames, stats, imageType)

# start the local renderer
if localRendering:
    localrenderer.start()