| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | import bpy | 
					
						
							|  |  |  | import sys, os | 
					
						
							|  |  |  | import http, http.client, http.server, urllib | 
					
						
							|  |  |  | import subprocess, shutil, time, hashlib | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import netrender.slave as slave | 
					
						
							|  |  |  | import netrender.master as master | 
					
						
							|  |  |  | from netrender.utils import * | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-09 02:25:14 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def clientSendJob(conn, scene, anim = False, chunks = 5): | 
					
						
							|  |  |  | 	netsettings = scene.network_render | 
					
						
							|  |  |  | 	job = netrender.model.RenderJob() | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if anim: | 
					
						
							|  |  |  | 		for f in range(scene.start_frame, scene.end_frame + 1): | 
					
						
							|  |  |  | 			job.addFrame(f) | 
					
						
							|  |  |  | 	else: | 
					
						
							|  |  |  | 		job.addFrame(scene.current_frame) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	filename = bpy.data.filename | 
					
						
							|  |  |  | 	job.addFile(filename) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	job_name = netsettings.job_name | 
					
						
							|  |  |  | 	path, name = os.path.split(filename) | 
					
						
							|  |  |  | 	if job_name == "[default]": | 
					
						
							|  |  |  | 		job_name = name | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	for lib in bpy.data.libraries: | 
					
						
							|  |  |  | 		lib_path = lib.filename | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		if lib_path.startswith("//"): | 
					
						
							|  |  |  | 			lib_path = path + os.sep + lib_path[2:] | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 		job.addFile(lib_path) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	root, ext = os.path.splitext(name) | 
					
						
							|  |  |  | 	cache_path = path + os.sep + "blendcache_" + root + os.sep # need an API call for that | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	print("cache:", cache_path) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if os.path.exists(cache_path): | 
					
						
							|  |  |  | 		caches = {} | 
					
						
							|  |  |  | 		pattern = re.compile("([a-zA-Z0-9]+)_([0-9]+)_[0-9]+\.bphys") | 
					
						
							|  |  |  | 		for cache_file in sorted(os.listdir(cache_path)): | 
					
						
							|  |  |  | 			match = pattern.match(cache_file) | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			if match: | 
					
						
							|  |  |  | 				cache_id = match.groups()[0] | 
					
						
							|  |  |  | 				cache_frame = int(match.groups()[1]) | 
					
						
							|  |  |  | 					 | 
					
						
							|  |  |  | 				cache_files = caches.get(cache_id, []) | 
					
						
							|  |  |  | 				cache_files.append((cache_frame, cache_file)) | 
					
						
							|  |  |  | 				caches[cache_id] = cache_files | 
					
						
							|  |  |  | 				 | 
					
						
							|  |  |  | 		for cache in caches.values(): | 
					
						
							|  |  |  | 			cache.sort() | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			if len(cache) == 1: | 
					
						
							|  |  |  | 				cache_frame, cache_file = cache[0] | 
					
						
							|  |  |  | 				job.addFile(cache_path + cache_file, cache_frame, cache_frame) | 
					
						
							|  |  |  | 			else: | 
					
						
							|  |  |  | 				for i in range(len(cache)): | 
					
						
							|  |  |  | 					current_item = cache[i] | 
					
						
							|  |  |  | 					next_item = cache[i+1] if i + 1 < len(cache) else None | 
					
						
							|  |  |  | 					previous_item = cache[i - 1] if i > 0 else None | 
					
						
							|  |  |  | 					 | 
					
						
							|  |  |  | 					current_frame, current_file = current_item | 
					
						
							|  |  |  | 					 | 
					
						
							|  |  |  | 					if  not next_item and not previous_item: | 
					
						
							|  |  |  | 						job.addFile(cache_path + current_file, current_frame, current_frame) | 
					
						
							|  |  |  | 					elif next_item and not previous_item: | 
					
						
							|  |  |  | 						next_frame = next_item[0] | 
					
						
							|  |  |  | 						job.addFile(cache_path + current_file, current_frame, next_frame - 1) | 
					
						
							|  |  |  | 					elif not next_item and previous_item: | 
					
						
							|  |  |  | 						previous_frame = previous_item[0] | 
					
						
							|  |  |  | 						job.addFile(cache_path + current_file, previous_frame + 1, current_frame) | 
					
						
							|  |  |  | 					else: | 
					
						
							|  |  |  | 						next_frame = next_item[0] | 
					
						
							|  |  |  | 						previous_frame = previous_item[0] | 
					
						
							|  |  |  | 						job.addFile(cache_path + current_file, previous_frame + 1, next_frame - 1) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 	print(job.files) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	job.name = job_name | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	for slave in scene.network_render.slaves_blacklist: | 
					
						
							|  |  |  | 		job.blacklist.append(slave.id) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	job.chunks = netsettings.chunks | 
					
						
							|  |  |  | 	job.priority = netsettings.priority | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	# try to send path first | 
					
						
							|  |  |  | 	conn.request("POST", "job", repr(job.serialize())) | 
					
						
							|  |  |  | 	response = conn.getresponse() | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	job_id = response.getheader("job-id") | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	# if not ACCEPTED (but not processed), send files | 
					
						
							|  |  |  | 	if response.status == http.client.ACCEPTED: | 
					
						
							|  |  |  | 		for filepath in job.files: | 
					
						
							|  |  |  | 			f = open(filepath, "rb") | 
					
						
							|  |  |  | 			conn.request("PUT", "file", f, headers={"job-id": job_id, "job-file": filepath}) | 
					
						
							|  |  |  | 			f.close() | 
					
						
							|  |  |  | 			response = conn.getresponse() | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	# server will reply with NOT_FOUD until all files are found | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	return job_id | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def clientRequestResult(conn, scene, job_id): | 
					
						
							|  |  |  | 	conn.request("GET", "render", headers={"job-id": job_id, "job-frame":str(scene.current_frame)}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | class NetworkRenderEngine(bpy.types.RenderEngine): | 
					
						
							|  |  |  | 	__idname__ = 'NET_RENDER' | 
					
						
							|  |  |  | 	__label__ = "Network Render" | 
					
						
							|  |  |  | 	def render(self, scene): | 
					
						
							|  |  |  | 		if scene.network_render.mode == "RENDER_CLIENT": | 
					
						
							|  |  |  | 			self.render_client(scene) | 
					
						
							|  |  |  | 		elif scene.network_render.mode == "RENDER_SLAVE": | 
					
						
							|  |  |  | 			self.render_slave(scene) | 
					
						
							|  |  |  | 		elif scene.network_render.mode == "RENDER_MASTER": | 
					
						
							|  |  |  | 			self.render_master(scene) | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			print("UNKNOWN OPERATION MODE") | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	def render_master(self, scene): | 
					
						
							|  |  |  | 		server_address = (scene.network_render.server_address, scene.network_render.server_port) | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 		httpd = master.RenderMasterServer(server_address, master.RenderHandler, scene.network_render.path) | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 		httpd.timeout = 1 | 
					
						
							|  |  |  | 		httpd.stats = self.update_stats | 
					
						
							|  |  |  | 		while not self.test_break(): | 
					
						
							|  |  |  | 			httpd.handle_request() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def render_slave(self, scene): | 
					
						
							|  |  |  | 		slave.render_slave(self, scene) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	def render_client(self, scene): | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 		netsettings = scene.network_render | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 		self.update_stats("", "Network render client initiation") | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		conn = clientConnection(scene) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		if conn: | 
					
						
							|  |  |  | 			# Sending file | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			self.update_stats("", "Network render exporting") | 
					
						
							|  |  |  | 			 | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 			job_id = netsettings.job_id | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 			 | 
					
						
							|  |  |  | 			# reading back result | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			self.update_stats("", "Network render waiting for results") | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			clientRequestResult(conn, scene, job_id) | 
					
						
							|  |  |  | 			response = conn.getresponse() | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			if response.status == http.client.NO_CONTENT: | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 				netsettings.job_id = clientSendJob(conn, scene) | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 				clientRequestResult(conn, scene, job_id) | 
					
						
							|  |  |  | 			 | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 			while response.status == http.client.ACCEPTED and not self.test_break(): | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 				print("waiting") | 
					
						
							|  |  |  | 				time.sleep(1) | 
					
						
							|  |  |  | 				clientRequestResult(conn, scene, job_id) | 
					
						
							|  |  |  | 				response = conn.getresponse() | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 			if response.status != http.client.OK: | 
					
						
							|  |  |  | 				conn.close() | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			r = scene.render_data | 
					
						
							|  |  |  | 			x= int(r.resolution_x*r.resolution_percentage*0.01) | 
					
						
							|  |  |  | 			y= int(r.resolution_y*r.resolution_percentage*0.01) | 
					
						
							|  |  |  | 			 | 
					
						
							| 
									
										
										
										
											2009-09-02 00:07:55 +00:00
										 |  |  | 			f = open(netsettings.path + "output.exr", "wb") | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 			buf = response.read(1024) | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			while buf: | 
					
						
							|  |  |  | 				f.write(buf) | 
					
						
							|  |  |  | 				buf = response.read(1024) | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			f.close() | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			result = self.begin_result(0, 0, x, y) | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 			result.load_from_file(netsettings.path + "output.exr", 0, 0) | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 			self.end_result(result) | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			conn.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bpy.types.register(NetworkRenderEngine) | 
					
						
							|  |  |  | 
 |