netrender tab to spaces

This commit is contained in:
Campbell Barton 2009-12-29 00:04:57 +00:00
parent 42154ad226
commit 58b1591ceb
16 changed files with 2454 additions and 2454 deletions

@ -4,12 +4,12 @@
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

@ -4,12 +4,12 @@
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@ -22,129 +22,129 @@ from netrender.utils import *
import netrender.model
class RatingRule:
def rate(self, job):
return 0
def rate(self, job):
return 0
class ExclusionRule:
def test(self, job):
return False
def test(self, job):
return False
class PriorityRule:
def test(self, job):
return False
def test(self, job):
return False
class Balancer:
def __init__(self):
self.rules = []
self.priorities = []
self.exceptions = []
def addRule(self, rule):
self.rules.append(rule)
def addPriority(self, priority):
self.priorities.append(priority)
def addException(self, exception):
self.exceptions.append(exception)
def applyRules(self, job):
return sum((rule.rate(job) for rule in self.rules))
def applyPriorities(self, job):
for priority in self.priorities:
if priority.test(job):
return True # priorities are first
return False
def applyExceptions(self, job):
for exception in self.exceptions:
if exception.test(job):
return True # exceptions are last
return False
def sortKey(self, job):
return (1 if self.applyExceptions(job) else 0, # exceptions after
0 if self.applyPriorities(job) else 1, # priorities first
self.applyRules(job))
def balance(self, jobs):
if jobs:
# use inline copy to make sure the list is still accessible while sorting
jobs[:] = sorted(jobs, key=self.sortKey)
return jobs[0]
else:
return None
def __init__(self):
self.rules = []
self.priorities = []
self.exceptions = []
def addRule(self, rule):
self.rules.append(rule)
def addPriority(self, priority):
self.priorities.append(priority)
def addException(self, exception):
self.exceptions.append(exception)
def applyRules(self, job):
return sum((rule.rate(job) for rule in self.rules))
def applyPriorities(self, job):
for priority in self.priorities:
if priority.test(job):
return True # priorities are first
return False
def applyExceptions(self, job):
for exception in self.exceptions:
if exception.test(job):
return True # exceptions are last
return False
def sortKey(self, job):
return (1 if self.applyExceptions(job) else 0, # exceptions after
0 if self.applyPriorities(job) else 1, # priorities first
self.applyRules(job))
def balance(self, jobs):
if jobs:
# use inline copy to make sure the list is still accessible while sorting
jobs[:] = sorted(jobs, key=self.sortKey)
return jobs[0]
else:
return None
# ==========================
class RatingUsage(RatingRule):
def __str__(self):
return "Usage rating"
def rate(self, job):
# less usage is better
return job.usage / job.priority
def __str__(self):
return "Usage rating"
def rate(self, job):
# less usage is better
return job.usage / job.priority
class RatingUsageByCategory(RatingRule):
def __str__(self):
return "Usage per category rating"
def __init__(self, get_jobs):
self.getJobs = get_jobs
def rate(self, job):
total_category_usage = sum([j.usage for j in self.getJobs() if j.category == job.category])
maximum_priority = max([j.priority for j in self.getJobs() if j.category == job.category])
# less usage is better
return total_category_usage / maximum_priority
class NewJobPriority(PriorityRule):
def str_limit(self):
return "less than %i frame%s done" % (self.limit, "s" if self.limit > 1 else "")
def __str__(self):
return "Usage per category rating"
def __str__(self):
return "Priority to new jobs"
def __init__(self, limit = 1):
self.limit = limit
def test(self, job):
return job.countFrames(status = DONE) < self.limit
def __init__(self, get_jobs):
self.getJobs = get_jobs
def rate(self, job):
total_category_usage = sum([j.usage for j in self.getJobs() if j.category == job.category])
maximum_priority = max([j.priority for j in self.getJobs() if j.category == job.category])
# less usage is better
return total_category_usage / maximum_priority
class NewJobPriority(PriorityRule):
def str_limit(self):
return "less than %i frame%s done" % (self.limit, "s" if self.limit > 1 else "")
def __str__(self):
return "Priority to new jobs"
def __init__(self, limit = 1):
self.limit = limit
def test(self, job):
return job.countFrames(status = DONE) < self.limit
class MinimumTimeBetweenDispatchPriority(PriorityRule):
def str_limit(self):
return "more than %i minute%s since last" % (self.limit, "s" if self.limit > 1 else "")
def str_limit(self):
return "more than %i minute%s since last" % (self.limit, "s" if self.limit > 1 else "")
def __str__(self):
return "Priority to jobs that haven't been dispatched recently"
def __init__(self, limit = 10):
self.limit = limit
def test(self, job):
return job.countFrames(status = DISPATCHED) == 0 and (time.time() - job.last_dispatched) / 60 > self.limit
def __str__(self):
return "Priority to jobs that haven't been dispatched recently"
def __init__(self, limit = 10):
self.limit = limit
def test(self, job):
return job.countFrames(status = DISPATCHED) == 0 and (time.time() - job.last_dispatched) / 60 > self.limit
class ExcludeQueuedEmptyJob(ExclusionRule):
def __str__(self):
return "Exclude queued and empty jobs"
def test(self, job):
return job.status != JOB_QUEUED or job.countFrames(status = QUEUED) == 0
class ExcludeSlavesLimit(ExclusionRule):
def str_limit(self):
return "more than %.0f%% of all slaves" % (self.limit * 100)
def __str__(self):
return "Exclude queued and empty jobs"
def __str__(self):
return "Exclude jobs that would use too many slaves"
def __init__(self, count_jobs, count_slaves, limit = 0.75):
self.count_jobs = count_jobs
self.count_slaves = count_slaves
self.limit = limit
def test(self, job):
return not ( self.count_jobs() == 1 or self.count_slaves() <= 1 or float(job.countSlaves() + 1) / self.count_slaves() <= self.limit )
def test(self, job):
return job.status != JOB_QUEUED or job.countFrames(status = QUEUED) == 0
class ExcludeSlavesLimit(ExclusionRule):
def str_limit(self):
return "more than %.0f%% of all slaves" % (self.limit * 100)
def __str__(self):
return "Exclude jobs that would use too many slaves"
def __init__(self, count_jobs, count_slaves, limit = 0.75):
self.count_jobs = count_jobs
self.count_slaves = count_slaves
self.limit = limit
def test(self, job):
return not ( self.count_jobs() == 1 or self.count_slaves() <= 1 or float(job.countSlaves() + 1) / self.count_slaves() <= self.limit )

@ -4,12 +4,12 @@
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@ -28,253 +28,253 @@ import netrender.master as master
from netrender.utils import *
def addFluidFiles(job, path):
if os.path.exists(path):
pattern = re.compile("fluidsurface_(final|preview)_([0-9]+)\.(bobj|bvel)\.gz")
if os.path.exists(path):
pattern = re.compile("fluidsurface_(final|preview)_([0-9]+)\.(bobj|bvel)\.gz")
for fluid_file in sorted(os.listdir(path)):
match = pattern.match(fluid_file)
if match:
# fluid frames starts at 0, which explains the +1
# This is stupid
current_frame = int(match.groups()[1]) + 1
job.addFile(path + fluid_file, current_frame, current_frame)
for fluid_file in sorted(os.listdir(path)):
match = pattern.match(fluid_file)
if match:
# fluid frames starts at 0, which explains the +1
# This is stupid
current_frame = int(match.groups()[1]) + 1
job.addFile(path + fluid_file, current_frame, current_frame)
def addPointCache(job, ob, point_cache, default_path):
if not point_cache.disk_cache:
return
name = point_cache.name
if name == "":
name = "".join(["%02X" % ord(c) for c in ob.name])
cache_path = bpy.utils.expandpath(point_cache.filepath) if point_cache.external else default_path
index = "%02i" % point_cache.index
if os.path.exists(cache_path):
pattern = re.compile(name + "_([0-9]+)_" + index + "\.bphys")
cache_files = []
if not point_cache.disk_cache:
return
name = point_cache.name
if name == "":
name = "".join(["%02X" % ord(c) for c in ob.name])
cache_path = bpy.utils.expandpath(point_cache.filepath) if point_cache.external else default_path
index = "%02i" % point_cache.index
if os.path.exists(cache_path):
pattern = re.compile(name + "_([0-9]+)_" + index + "\.bphys")
cache_files = []
for cache_file in sorted(os.listdir(cache_path)):
match = pattern.match(cache_file)
if match:
cache_frame = int(match.groups()[0])
cache_files.append((cache_frame, cache_file))
cache_files.sort()
if len(cache_files) == 1:
cache_frame, cache_file = cache_files[0]
job.addFile(cache_path + cache_file, cache_frame, cache_frame)
else:
for i in range(len(cache_files)):
current_item = cache_files[i]
next_item = cache_files[i+1] if i + 1 < len(cache_files) else None
previous_item = cache_files[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)
for cache_file in sorted(os.listdir(cache_path)):
match = pattern.match(cache_file)
if match:
cache_frame = int(match.groups()[0])
cache_files.append((cache_frame, cache_file))
cache_files.sort()
if len(cache_files) == 1:
cache_frame, cache_file = cache_files[0]
job.addFile(cache_path + cache_file, cache_frame, cache_frame)
else:
for i in range(len(cache_files)):
current_item = cache_files[i]
next_item = cache_files[i+1] if i + 1 < len(cache_files) else None
previous_item = cache_files[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)
def clientSendJob(conn, scene, anim = False):
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
###########################
# LIBRARIES
###########################
for lib in bpy.data.libraries:
job.addFile(bpy.utils.expandpath(lib.filename))
###########################
# IMAGES
###########################
for image in bpy.data.images:
if image.source == "FILE" and not image.packed_file:
job.addFile(bpy.utils.expandpath(image.filename))
###########################
# FLUID + POINT CACHE
###########################
root, ext = os.path.splitext(name)
default_path = path + os.sep + "blendcache_" + root + os.sep # need an API call for that
netsettings = scene.network_render
job = netrender.model.RenderJob()
for object in bpy.data.objects:
for modifier in object.modifiers:
if modifier.type == 'FLUID_SIMULATION' and modifier.settings.type == "DOMAIN":
addFluidFiles(job, bpy.utils.expandpath(modifier.settings.path))
elif modifier.type == "CLOTH":
addPointCache(job, object, modifier.point_cache, default_path)
elif modifier.type == "SOFT_BODY":
addPointCache(job, object, modifier.point_cache, default_path)
elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN":
addPointCache(job, object, modifier.domain_settings.point_cache_low, default_path)
if modifier.domain_settings.highres:
addPointCache(job, object, modifier.domain_settings.point_cache_high, default_path)
if anim:
for f in range(scene.start_frame, scene.end_frame + 1):
job.addFrame(f)
else:
job.addFrame(scene.current_frame)
# particles modifier are stupid and don't contain data
# we have to go through the object property
for psys in object.particle_systems:
addPointCache(job, object, psys.point_cache, default_path)
#print(job.files)
job.name = job_name
job.category = netsettings.job_category
for slave in netrender.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 rfile in job.files:
f = open(rfile.filepath, "rb")
conn.request("PUT", fileURL(job_id, rfile.index), f)
f.close()
response = conn.getresponse()
# server will reply with ACCEPTED until all files are found
return job_id
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
###########################
# LIBRARIES
###########################
for lib in bpy.data.libraries:
job.addFile(bpy.utils.expandpath(lib.filename))
###########################
# IMAGES
###########################
for image in bpy.data.images:
if image.source == "FILE" and not image.packed_file:
job.addFile(bpy.utils.expandpath(image.filename))
###########################
# FLUID + POINT CACHE
###########################
root, ext = os.path.splitext(name)
default_path = path + os.sep + "blendcache_" + root + os.sep # need an API call for that
for object in bpy.data.objects:
for modifier in object.modifiers:
if modifier.type == 'FLUID_SIMULATION' and modifier.settings.type == "DOMAIN":
addFluidFiles(job, bpy.utils.expandpath(modifier.settings.path))
elif modifier.type == "CLOTH":
addPointCache(job, object, modifier.point_cache, default_path)
elif modifier.type == "SOFT_BODY":
addPointCache(job, object, modifier.point_cache, default_path)
elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN":
addPointCache(job, object, modifier.domain_settings.point_cache_low, default_path)
if modifier.domain_settings.highres:
addPointCache(job, object, modifier.domain_settings.point_cache_high, default_path)
# particles modifier are stupid and don't contain data
# we have to go through the object property
for psys in object.particle_systems:
addPointCache(job, object, psys.point_cache, default_path)
#print(job.files)
job.name = job_name
job.category = netsettings.job_category
for slave in netrender.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 rfile in job.files:
f = open(rfile.filepath, "rb")
conn.request("PUT", fileURL(job_id, rfile.index), f)
f.close()
response = conn.getresponse()
# server will reply with ACCEPTED until all files are found
return job_id
def requestResult(conn, job_id, frame):
conn.request("GET", renderURL(job_id, frame))
conn.request("GET", renderURL(job_id, frame))
@rnaType
class NetworkRenderEngine(bpy.types.RenderEngine):
bl_idname = 'NET_RENDER'
bl_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):
netsettings = scene.network_render
address = "" if netsettings.server_address == "[default]" else netsettings.server_address
master.runMaster((address, netsettings.server_port), netsettings.server_broadcast, netsettings.path, self.update_stats, self.test_break)
bl_idname = 'NET_RENDER'
bl_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):
netsettings = scene.network_render
address = "" if netsettings.server_address == "[default]" else netsettings.server_address
master.runMaster((address, netsettings.server_port), netsettings.server_broadcast, netsettings.path, self.update_stats, self.test_break)
def render_slave(self, scene):
slave.render_slave(self, scene.network_render)
def render_client(self, scene):
netsettings = scene.network_render
self.update_stats("", "Network render client initiation")
conn = clientConnection(netsettings.server_address, netsettings.server_port)
if conn:
# Sending file
self.update_stats("", "Network render exporting")
new_job = False
job_id = netsettings.job_id
# reading back result
self.update_stats("", "Network render waiting for results")
requestResult(conn, job_id, scene.current_frame)
response = conn.getresponse()
if response.status == http.client.NO_CONTENT:
new_job = True
netsettings.job_id = clientSendJob(conn, scene)
job_id = netsettings.job_id
requestResult(conn, job_id, scene.current_frame)
response = conn.getresponse()
while response.status == http.client.ACCEPTED and not self.test_break():
time.sleep(1)
requestResult(conn, job_id, scene.current_frame)
response = conn.getresponse()
# cancel new jobs (animate on network) on break
if self.test_break() and new_job:
conn.request("POST", cancelURL(job_id))
response = conn.getresponse()
print( response.status, response.reason )
netsettings.job_id = 0
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)
f = open(netsettings.path + "output.exr", "wb")
buf = response.read(1024)
while buf:
f.write(buf)
buf = response.read(1024)
f.close()
result = self.begin_result(0, 0, x, y)
result.load_from_file(netsettings.path + "output.exr", 0, 0)
self.end_result(result)
conn.close()
def render_slave(self, scene):
slave.render_slave(self, scene.network_render)
def render_client(self, scene):
netsettings = scene.network_render
self.update_stats("", "Network render client initiation")
conn = clientConnection(netsettings.server_address, netsettings.server_port)
if conn:
# Sending file
self.update_stats("", "Network render exporting")
new_job = False
job_id = netsettings.job_id
# reading back result
self.update_stats("", "Network render waiting for results")
requestResult(conn, job_id, scene.current_frame)
response = conn.getresponse()
if response.status == http.client.NO_CONTENT:
new_job = True
netsettings.job_id = clientSendJob(conn, scene)
job_id = netsettings.job_id
requestResult(conn, job_id, scene.current_frame)
response = conn.getresponse()
while response.status == http.client.ACCEPTED and not self.test_break():
time.sleep(1)
requestResult(conn, job_id, scene.current_frame)
response = conn.getresponse()
# cancel new jobs (animate on network) on break
if self.test_break() and new_job:
conn.request("POST", cancelURL(job_id))
response = conn.getresponse()
print( response.status, response.reason )
netsettings.job_id = 0
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)
f = open(netsettings.path + "output.exr", "wb")
buf = response.read(1024)
while buf:
f.write(buf)
buf = response.read(1024)
f.close()
result = self.begin_result(0, 0, x, y)
result.load_from_file(netsettings.path + "output.exr", 0, 0)
self.end_result(result)
conn.close()
def compatible(module):
module = __import__(module)
for subclass in module.__dict__.values():
try: subclass.COMPAT_ENGINES.add('NET_RENDER')
except: pass
del module
module = __import__(module)
for subclass in module.__dict__.values():
try: subclass.COMPAT_ENGINES.add('NET_RENDER')
except: pass
del module
compatible("properties_render")
compatible("properties_world")

File diff suppressed because it is too large Load Diff

@ -4,12 +4,12 @@
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@ -24,226 +24,226 @@ from netrender.utils import *
src_folder = os.path.split(__file__)[0]
def get(handler):
def output(text):
handler.wfile.write(bytes(text, encoding='utf8'))
def head(title):
output("<html><head>")
output("<script src='/html/netrender.js' type='text/javascript'></script>")
def output(text):
handler.wfile.write(bytes(text, encoding='utf8'))
def head(title):
output("<html><head>")
output("<script src='/html/netrender.js' type='text/javascript'></script>")
# output("<script src='/html/json2.js' type='text/javascript'></script>")
output("<title>")
output(title)
output("</title></head><body>")
output("<link rel='stylesheet' href='/html/netrender.css' type='text/css'>")
output("<title>")
output(title)
output("</title></head><body>")
output("<link rel='stylesheet' href='/html/netrender.css' type='text/css'>")
def link(text, url):
return "<a href='%s'>%s</a>" % (url, text)
def startTable(border=1, class_style = None, caption = None):
output("<table border='%i'" % border)
if class_style:
output(" class='%s'" % class_style)
output(">")
if caption:
output("<caption>%s</caption>" % caption)
def headerTable(*headers):
output("<thead><tr>")
for c in headers:
output("<td>" + c + "</td>")
output("</tr></thead>")
def rowTable(*data, id = None, class_style = None, extra = None):
output("<tr")
if id:
output(" id='%s'" % id)
if class_style:
output(" class='%s'" % class_style)
if extra:
output(" %s" % extra)
def link(text, url):
return "<a href='%s'>%s</a>" % (url, text)
output(">")
for c in data:
output("<td>" + str(c) + "</td>")
output("</tr>")
def endTable():
output("</table>")
if handler.path == "/html/netrender.js":
f = open(os.path.join(src_folder, "netrender.js"), 'rb')
handler.send_head(content = "text/javascript")
shutil.copyfileobj(f, handler.wfile)
f.close()
elif handler.path == "/html/netrender.css":
f = open(os.path.join(src_folder, "netrender.css"), 'rb')
handler.send_head(content = "text/css")
shutil.copyfileobj(f, handler.wfile)
f.close()
elif handler.path == "/html" or handler.path == "/":
handler.send_head(content = "text/html")
head("NetRender")
output("<h2>Master</h2>")
output("""<button title="remove all jobs" onclick="request('/clear', null);">CLEAR JOB LIST</button>""")
def startTable(border=1, class_style = None, caption = None):
output("<table border='%i'" % border)
startTable(caption = "Rules", class_style = "rules")
if class_style:
output(" class='%s'" % class_style)
headerTable("type", "description", "limit")
output(">")
for rule in handler.server.balancer.rules:
rowTable("rating", rule, rule.str_limit() if hasattr(rule, "limit") else "&nbsp;")
if caption:
output("<caption>%s</caption>" % caption)
for rule in handler.server.balancer.priorities:
rowTable("priority", rule, rule.str_limit() if hasattr(rule, "limit") else "&nbsp;")
for rule in handler.server.balancer.exceptions:
rowTable("exception", rule, rule.str_limit() if hasattr(rule, "limit") else "&nbsp;")
def headerTable(*headers):
output("<thead><tr>")
endTable()
for c in headers:
output("<td>" + c + "</td>")
output("<h2>Slaves</h2>")
startTable()
headerTable("name", "address", "last seen", "stats", "job")
for slave in handler.server.slaves:
rowTable(slave.name, slave.address[0], time.ctime(slave.last_seen), slave.stats, link(slave.job.name, "/html/job" + slave.job.id) if slave.job else "None")
endTable()
output("<h2>Jobs</h2>")
startTable()
headerTable(
"&nbsp;",
"id",
"name",
"category",
"chunks",
"priority",
"usage",
"wait",
"status",
"length",
"done",
"dispatched",
"error",
"first",
"exception"
)
output("</tr></thead>")
handler.server.balance()
for job in handler.server.jobs:
results = job.framesStatus()
rowTable(
"""<button title="cancel job" onclick="request('/cancel_%s', null);">X</button>""" % job.id +
"""<button title="reset all frames" onclick="request('/resetall_%s_0', null);">R</button>""" % job.id,
job.id,
link(job.name, "/html/job" + job.id),
job.category if job.category else "<i>None</i>",
str(job.chunks) +
"""<button title="increase priority" onclick="request('/edit_%s', &quot;{'chunks': %i}&quot;);">+</button>""" % (job.id, job.chunks + 1) +
"""<button title="decrease priority" onclick="request('/edit_%s', &quot;{'chunks': %i}&quot;);" %s>-</button>""" % (job.id, job.chunks - 1, "disabled=True" if job.chunks == 1 else ""),
str(job.priority) +
"""<button title="increase chunks size" onclick="request('/edit_%s', &quot;{'priority': %i}&quot;);">+</button>""" % (job.id, job.priority + 1) +
"""<button title="decrease chunks size" onclick="request('/edit_%s', &quot;{'priority': %i}&quot;);" %s>-</button>""" % (job.id, job.priority - 1, "disabled=True" if job.priority == 1 else ""),
"%0.1f%%" % (job.usage * 100),
"%is" % int(time.time() - job.last_dispatched),
job.statusText(),
len(job),
results[DONE],
results[DISPATCHED],
str(results[ERROR]) +
"""<button title="reset error frames" onclick="request('/reset_%s_0', null);" %s>R</button>""" % (job.id, "disabled=True" if not results[ERROR] else ""),
handler.server.balancer.applyPriorities(job), handler.server.balancer.applyExceptions(job)
)
endTable()
output("</body></html>")
elif handler.path.startswith("/html/job"):
handler.send_head(content = "text/html")
job_id = handler.path[9:]
head("NetRender")
job = handler.server.getJobID(job_id)
if job:
output("<h2>Files</h2>")
startTable()
headerTable("path")
tot_cache = 0
tot_fluid = 0
for file in job.files:
if file.filepath.endswith(".bphys"):
tot_cache += 1
elif file.filepath.endswith(".bobj.gz") or file.filepath.endswith(".bvel.gz"):
tot_fluid += 1
else:
rowTable(file.filepath)
def rowTable(*data, id = None, class_style = None, extra = None):
output("<tr")
if tot_cache > 0:
rowTable("%i physic cache files" % tot_cache, class_style = "toggle", extra = "onclick='toggleDisplay(&quot;.cache&quot;, &quot;none&quot;, &quot;table-row&quot;)'")
for file in job.files:
if file.filepath.endswith(".bphys"):
rowTable(os.path.split(file.filepath)[1], class_style = "cache")
if tot_fluid > 0:
rowTable("%i fluid bake files" % tot_fluid, class_style = "toggle", extra = "onclick='toggleDisplay(&quot;.fluid&quot;, &quot;none&quot;, &quot;table-row&quot;)'")
for file in job.files:
if file.filepath.endswith(".bobj.gz") or file.filepath.endswith(".bvel.gz"):
rowTable(os.path.split(file.filepath)[1], class_style = "fluid")
if id:
output(" id='%s'" % id)
endTable()
output("<h2>Blacklist</h2>")
if job.blacklist:
startTable()
headerTable("name", "address")
for slave_id in job.blacklist:
slave = handler.server.slaves_map[slave_id]
rowTable(slave.name, slave.address[0])
endTable()
else:
output("<i>Empty</i>")
if class_style:
output(" class='%s'" % class_style)
output("<h2>Frames</h2>")
startTable()
headerTable("no", "status", "render time", "slave", "log", "result")
for frame in job.frames:
rowTable(frame.number, frame.statusText(), "%.1fs" % frame.time, frame.slave.name if frame.slave else "&nbsp;", link("view log", logURL(job_id, frame.number)) if frame.log_path else "&nbsp;", link("view result", renderURL(job_id, frame.number)) if frame.status == DONE else "&nbsp;")
endTable()
else:
output("no such job")
output("</body></html>")
if extra:
output(" %s" % extra)
output(">")
for c in data:
output("<td>" + str(c) + "</td>")
output("</tr>")
def endTable():
output("</table>")
if handler.path == "/html/netrender.js":
f = open(os.path.join(src_folder, "netrender.js"), 'rb')
handler.send_head(content = "text/javascript")
shutil.copyfileobj(f, handler.wfile)
f.close()
elif handler.path == "/html/netrender.css":
f = open(os.path.join(src_folder, "netrender.css"), 'rb')
handler.send_head(content = "text/css")
shutil.copyfileobj(f, handler.wfile)
f.close()
elif handler.path == "/html" or handler.path == "/":
handler.send_head(content = "text/html")
head("NetRender")
output("<h2>Master</h2>")
output("""<button title="remove all jobs" onclick="request('/clear', null);">CLEAR JOB LIST</button>""")
startTable(caption = "Rules", class_style = "rules")
headerTable("type", "description", "limit")
for rule in handler.server.balancer.rules:
rowTable("rating", rule, rule.str_limit() if hasattr(rule, "limit") else "&nbsp;")
for rule in handler.server.balancer.priorities:
rowTable("priority", rule, rule.str_limit() if hasattr(rule, "limit") else "&nbsp;")
for rule in handler.server.balancer.exceptions:
rowTable("exception", rule, rule.str_limit() if hasattr(rule, "limit") else "&nbsp;")
endTable()
output("<h2>Slaves</h2>")
startTable()
headerTable("name", "address", "last seen", "stats", "job")
for slave in handler.server.slaves:
rowTable(slave.name, slave.address[0], time.ctime(slave.last_seen), slave.stats, link(slave.job.name, "/html/job" + slave.job.id) if slave.job else "None")
endTable()
output("<h2>Jobs</h2>")
startTable()
headerTable(
"&nbsp;",
"id",
"name",
"category",
"chunks",
"priority",
"usage",
"wait",
"status",
"length",
"done",
"dispatched",
"error",
"first",
"exception"
)
handler.server.balance()
for job in handler.server.jobs:
results = job.framesStatus()
rowTable(
"""<button title="cancel job" onclick="request('/cancel_%s', null);">X</button>""" % job.id +
"""<button title="reset all frames" onclick="request('/resetall_%s_0', null);">R</button>""" % job.id,
job.id,
link(job.name, "/html/job" + job.id),
job.category if job.category else "<i>None</i>",
str(job.chunks) +
"""<button title="increase priority" onclick="request('/edit_%s', &quot;{'chunks': %i}&quot;);">+</button>""" % (job.id, job.chunks + 1) +
"""<button title="decrease priority" onclick="request('/edit_%s', &quot;{'chunks': %i}&quot;);" %s>-</button>""" % (job.id, job.chunks - 1, "disabled=True" if job.chunks == 1 else ""),
str(job.priority) +
"""<button title="increase chunks size" onclick="request('/edit_%s', &quot;{'priority': %i}&quot;);">+</button>""" % (job.id, job.priority + 1) +
"""<button title="decrease chunks size" onclick="request('/edit_%s', &quot;{'priority': %i}&quot;);" %s>-</button>""" % (job.id, job.priority - 1, "disabled=True" if job.priority == 1 else ""),
"%0.1f%%" % (job.usage * 100),
"%is" % int(time.time() - job.last_dispatched),
job.statusText(),
len(job),
results[DONE],
results[DISPATCHED],
str(results[ERROR]) +
"""<button title="reset error frames" onclick="request('/reset_%s_0', null);" %s>R</button>""" % (job.id, "disabled=True" if not results[ERROR] else ""),
handler.server.balancer.applyPriorities(job), handler.server.balancer.applyExceptions(job)
)
endTable()
output("</body></html>")
elif handler.path.startswith("/html/job"):
handler.send_head(content = "text/html")
job_id = handler.path[9:]
head("NetRender")
job = handler.server.getJobID(job_id)
if job:
output("<h2>Files</h2>")
startTable()
headerTable("path")
tot_cache = 0
tot_fluid = 0
for file in job.files:
if file.filepath.endswith(".bphys"):
tot_cache += 1
elif file.filepath.endswith(".bobj.gz") or file.filepath.endswith(".bvel.gz"):
tot_fluid += 1
else:
rowTable(file.filepath)
if tot_cache > 0:
rowTable("%i physic cache files" % tot_cache, class_style = "toggle", extra = "onclick='toggleDisplay(&quot;.cache&quot;, &quot;none&quot;, &quot;table-row&quot;)'")
for file in job.files:
if file.filepath.endswith(".bphys"):
rowTable(os.path.split(file.filepath)[1], class_style = "cache")
if tot_fluid > 0:
rowTable("%i fluid bake files" % tot_fluid, class_style = "toggle", extra = "onclick='toggleDisplay(&quot;.fluid&quot;, &quot;none&quot;, &quot;table-row&quot;)'")
for file in job.files:
if file.filepath.endswith(".bobj.gz") or file.filepath.endswith(".bvel.gz"):
rowTable(os.path.split(file.filepath)[1], class_style = "fluid")
endTable()
output("<h2>Blacklist</h2>")
if job.blacklist:
startTable()
headerTable("name", "address")
for slave_id in job.blacklist:
slave = handler.server.slaves_map[slave_id]
rowTable(slave.name, slave.address[0])
endTable()
else:
output("<i>Empty</i>")
output("<h2>Frames</h2>")
startTable()
headerTable("no", "status", "render time", "slave", "log", "result")
for frame in job.frames:
rowTable(frame.number, frame.statusText(), "%.1fs" % frame.time, frame.slave.name if frame.slave else "&nbsp;", link("view log", logURL(job_id, frame.number)) if frame.log_path else "&nbsp;", link("view result", renderURL(job_id, frame.number)) if frame.status == DONE else "&nbsp;")
endTable()
else:
output("no such job")
output("</body></html>")

@ -4,12 +4,12 @@
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@ -23,256 +23,256 @@ import subprocess, shutil, time, hashlib
from netrender.utils import *
class LogFile:
def __init__(self, job_id = 0, slave_id = 0, frames = []):
self.job_id = job_id
self.slave_id = slave_id
self.frames = frames
def serialize(self):
return {
"job_id": self.job_id,
"slave_id": self.slave_id,
"frames": self.frames
}
@staticmethod
def materialize(data):
if not data:
return None
logfile = LogFile()
logfile.job_id = data["job_id"]
logfile.slave_id = data["slave_id"]
logfile.frames = data["frames"]
return logfile
def __init__(self, job_id = 0, slave_id = 0, frames = []):
self.job_id = job_id
self.slave_id = slave_id
self.frames = frames
def serialize(self):
return {
"job_id": self.job_id,
"slave_id": self.slave_id,
"frames": self.frames
}
@staticmethod
def materialize(data):
if not data:
return None
logfile = LogFile()
logfile.job_id = data["job_id"]
logfile.slave_id = data["slave_id"]
logfile.frames = data["frames"]
return logfile
class RenderSlave:
_slave_map = {}
def __init__(self):
self.id = ""
self.name = ""
self.address = ("",0)
self.stats = ""
self.total_done = 0
self.total_error = 0
self.last_seen = 0.0
def serialize(self):
return {
"id": self.id,
"name": self.name,
"address": self.address,
"stats": self.stats,
"total_done": self.total_done,
"total_error": self.total_error,
"last_seen": self.last_seen
}
@staticmethod
def materialize(data, cache = True):
if not data:
return None
slave_id = data["id"]
_slave_map = {}
if cache and slave_id in RenderSlave._slave_map:
return RenderSlave._slave_map[slave_id]
def __init__(self):
self.id = ""
self.name = ""
self.address = ("",0)
self.stats = ""
self.total_done = 0
self.total_error = 0
self.last_seen = 0.0
slave = RenderSlave()
slave.id = slave_id
slave.name = data["name"]
slave.address = data["address"]
slave.stats = data["stats"]
slave.total_done = data["total_done"]
slave.total_error = data["total_error"]
slave.last_seen = data["last_seen"]
def serialize(self):
return {
"id": self.id,
"name": self.name,
"address": self.address,
"stats": self.stats,
"total_done": self.total_done,
"total_error": self.total_error,
"last_seen": self.last_seen
}
if cache:
RenderSlave._slave_map[slave_id] = slave
return slave
@staticmethod
def materialize(data, cache = True):
if not data:
return None
slave_id = data["id"]
if cache and slave_id in RenderSlave._slave_map:
return RenderSlave._slave_map[slave_id]
slave = RenderSlave()
slave.id = slave_id
slave.name = data["name"]
slave.address = data["address"]
slave.stats = data["stats"]
slave.total_done = data["total_done"]
slave.total_error = data["total_error"]
slave.last_seen = data["last_seen"]
if cache:
RenderSlave._slave_map[slave_id] = slave
return slave
JOB_BLENDER = 1
JOB_PROCESS = 2
JOB_TYPES = {
JOB_BLENDER: "Blender",
JOB_PROCESS: "Process"
}
JOB_BLENDER: "Blender",
JOB_PROCESS: "Process"
}
class RenderFile:
def __init__(self, filepath = "", index = 0, start = -1, end = -1):
self.filepath = filepath
self.index = index
self.start = start
self.end = end
def __init__(self, filepath = "", index = 0, start = -1, end = -1):
self.filepath = filepath
self.index = index
self.start = start
self.end = end
def serialize(self):
return {
"filepath": self.filepath,
"index": self.index,
"start": self.start,
"end": self.end
}
def serialize(self):
return {
"filepath": self.filepath,
"index": self.index,
"start": self.start,
"end": self.end
}
@staticmethod
def materialize(data):
if not data:
return None
rfile = RenderFile(data["filepath"], data["index"], data["start"], data["end"])
@staticmethod
def materialize(data):
if not data:
return None
return rfile
rfile = RenderFile(data["filepath"], data["index"], data["start"], data["end"])
return rfile
class RenderJob:
def __init__(self, job_info = None):
self.id = ""
self.type = JOB_BLENDER
self.name = ""
self.category = "None"
self.status = JOB_WAITING
self.files = []
self.chunks = 0
self.priority = 0
self.blacklist = []
def __init__(self, job_info = None):
self.id = ""
self.type = JOB_BLENDER
self.name = ""
self.category = "None"
self.status = JOB_WAITING
self.files = []
self.chunks = 0
self.priority = 0
self.blacklist = []
self.usage = 0.0
self.last_dispatched = 0.0
self.frames = []
if job_info:
self.type = job_info.type
self.name = job_info.name
self.category = job_info.category
self.status = job_info.status
self.files = job_info.files
self.chunks = job_info.chunks
self.priority = job_info.priority
self.blacklist = job_info.blacklist
def addFile(self, file_path, start=-1, end=-1):
self.files.append(RenderFile(file_path, len(self.files), start, end))
def addFrame(self, frame_number, command = ""):
frame = RenderFrame(frame_number, command)
self.frames.append(frame)
return frame
def __len__(self):
return len(self.frames)
def countFrames(self, status=QUEUED):
total = 0
for f in self.frames:
if f.status == status:
total += 1
return total
def countSlaves(self):
return len(set((frame.slave for frame in self.frames if frame.status == DISPATCHED)))
def statusText(self):
return JOB_STATUS_TEXT[self.status]
def framesStatus(self):
results = {
QUEUED: 0,
DISPATCHED: 0,
DONE: 0,
ERROR: 0
}
for frame in self.frames:
results[frame.status] += 1
return results
def __contains__(self, frame_number):
for f in self.frames:
if f.number == frame_number:
return True
else:
return False
def __getitem__(self, frame_number):
for f in self.frames:
if f.number == frame_number:
return f
else:
return None
def serialize(self, frames = None):
min_frame = min((f.number for f in frames)) if frames else -1
max_frame = max((f.number for f in frames)) if frames else -1
return {
"id": self.id,
"type": self.type,
"name": self.name,
"category": self.category,
"status": self.status,
"files": [f.serialize() for f in self.files if f.start == -1 or not frames or (f.start <= max_frame and f.end >= min_frame)],
"frames": [f.serialize() for f in self.frames if not frames or f in frames],
"chunks": self.chunks,
"priority": self.priority,
"usage": self.usage,
"blacklist": self.blacklist,
"last_dispatched": self.last_dispatched
}
self.usage = 0.0
self.last_dispatched = 0.0
self.frames = []
@staticmethod
def materialize(data):
if not data:
return None
job = RenderJob()
job.id = data["id"]
job.type = data["type"]
job.name = data["name"]
job.category = data["category"]
job.status = data["status"]
job.files = [RenderFile.materialize(f) for f in data["files"]]
job.frames = [RenderFrame.materialize(f) for f in data["frames"]]
job.chunks = data["chunks"]
job.priority = data["priority"]
job.usage = data["usage"]
job.blacklist = data["blacklist"]
job.last_dispatched = data["last_dispatched"]
if job_info:
self.type = job_info.type
self.name = job_info.name
self.category = job_info.category
self.status = job_info.status
self.files = job_info.files
self.chunks = job_info.chunks
self.priority = job_info.priority
self.blacklist = job_info.blacklist
return job
def addFile(self, file_path, start=-1, end=-1):
self.files.append(RenderFile(file_path, len(self.files), start, end))
def addFrame(self, frame_number, command = ""):
frame = RenderFrame(frame_number, command)
self.frames.append(frame)
return frame
def __len__(self):
return len(self.frames)
def countFrames(self, status=QUEUED):
total = 0
for f in self.frames:
if f.status == status:
total += 1
return total
def countSlaves(self):
return len(set((frame.slave for frame in self.frames if frame.status == DISPATCHED)))
def statusText(self):
return JOB_STATUS_TEXT[self.status]
def framesStatus(self):
results = {
QUEUED: 0,
DISPATCHED: 0,
DONE: 0,
ERROR: 0
}
for frame in self.frames:
results[frame.status] += 1
return results
def __contains__(self, frame_number):
for f in self.frames:
if f.number == frame_number:
return True
else:
return False
def __getitem__(self, frame_number):
for f in self.frames:
if f.number == frame_number:
return f
else:
return None
def serialize(self, frames = None):
min_frame = min((f.number for f in frames)) if frames else -1
max_frame = max((f.number for f in frames)) if frames else -1
return {
"id": self.id,
"type": self.type,
"name": self.name,
"category": self.category,
"status": self.status,
"files": [f.serialize() for f in self.files if f.start == -1 or not frames or (f.start <= max_frame and f.end >= min_frame)],
"frames": [f.serialize() for f in self.frames if not frames or f in frames],
"chunks": self.chunks,
"priority": self.priority,
"usage": self.usage,
"blacklist": self.blacklist,
"last_dispatched": self.last_dispatched
}
@staticmethod
def materialize(data):
if not data:
return None
job = RenderJob()
job.id = data["id"]
job.type = data["type"]
job.name = data["name"]
job.category = data["category"]
job.status = data["status"]
job.files = [RenderFile.materialize(f) for f in data["files"]]
job.frames = [RenderFrame.materialize(f) for f in data["frames"]]
job.chunks = data["chunks"]
job.priority = data["priority"]
job.usage = data["usage"]
job.blacklist = data["blacklist"]
job.last_dispatched = data["last_dispatched"]
return job
class RenderFrame:
def __init__(self, number = 0, command = ""):
self.number = number
self.time = 0
self.status = QUEUED
self.slave = None
self.command = command
def __init__(self, number = 0, command = ""):
self.number = number
self.time = 0
self.status = QUEUED
self.slave = None
self.command = command
def statusText(self):
return FRAME_STATUS_TEXT[self.status]
def statusText(self):
return FRAME_STATUS_TEXT[self.status]
def serialize(self):
return {
"number": self.number,
"time": self.time,
"status": self.status,
"slave": None if not self.slave else self.slave.serialize(),
"command": self.command
}
@staticmethod
def materialize(data):
if not data:
return None
frame = RenderFrame()
frame.number = data["number"]
frame.time = data["time"]
frame.status = data["status"]
frame.slave = RenderSlave.materialize(data["slave"])
frame.command = data["command"]
def serialize(self):
return {
"number": self.number,
"time": self.time,
"status": self.status,
"slave": None if not self.slave else self.slave.serialize(),
"command": self.command
}
return frame
@staticmethod
def materialize(data):
if not data:
return None
frame = RenderFrame()
frame.number = data["number"]
frame.time = data["time"]
frame.status = data["status"]
frame.slave = RenderSlave.materialize(data["slave"])
frame.command = data["command"]
return frame

@ -4,12 +4,12 @@
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@ -28,414 +28,414 @@ import netrender.model
@rnaType
class RENDER_OT_netslave_bake(bpy.types.Operator):
'''NEED DESCRIPTION'''
bl_idname = "render.netslavebake"
bl_label = "Bake all in file"
def poll(self, context):
return True
def execute(self, context):
scene = context.scene
netsettings = scene.network_render
filename = bpy.data.filename
path, name = os.path.split(filename)
root, ext = os.path.splitext(name)
default_path = path + os.sep + "blendcache_" + root + os.sep # need an API call for that
relative_path = os.sep + os.sep + "blendcache_" + root + os.sep
# Force all point cache next to the blend file
for object in bpy.data.objects:
for modifier in object.modifiers:
if modifier.type == 'FLUID_SIMULATION' and modifier.settings.type == "DOMAIN":
modifier.settings.path = relative_path
bpy.ops.fluid.bake({"active_object": object, "scene": scene})
elif modifier.type == "CLOTH":
modifier.point_cache.step = 1
modifier.point_cache.disk_cache = True
modifier.point_cache.external = False
elif modifier.type == "SOFT_BODY":
modifier.point_cache.step = 1
modifier.point_cache.disk_cache = True
modifier.point_cache.external = False
elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN":
modifier.domain_settings.point_cache_low.step = 1
modifier.domain_settings.point_cache_low.disk_cache = True
modifier.domain_settings.point_cache_low.external = False
modifier.domain_settings.point_cache_high.step = 1
modifier.domain_settings.point_cache_high.disk_cache = True
modifier.domain_settings.point_cache_high.external = False
# particles modifier are stupid and don't contain data
# we have to go through the object property
for psys in object.particle_systems:
psys.point_cache.step = 1
psys.point_cache.disk_cache = True
psys.point_cache.external = False
psys.point_cache.filepath = relative_path
bpy.ops.ptcache.bake_all()
#bpy.ops.wm.save_mainfile(path = path + os.sep + root + "_baked.blend")
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
'''NEED DESCRIPTION'''
bl_idname = "render.netslavebake"
bl_label = "Bake all in file"
def poll(self, context):
return True
def execute(self, context):
scene = context.scene
netsettings = scene.network_render
filename = bpy.data.filename
path, name = os.path.split(filename)
root, ext = os.path.splitext(name)
default_path = path + os.sep + "blendcache_" + root + os.sep # need an API call for that
relative_path = os.sep + os.sep + "blendcache_" + root + os.sep
# Force all point cache next to the blend file
for object in bpy.data.objects:
for modifier in object.modifiers:
if modifier.type == 'FLUID_SIMULATION' and modifier.settings.type == "DOMAIN":
modifier.settings.path = relative_path
bpy.ops.fluid.bake({"active_object": object, "scene": scene})
elif modifier.type == "CLOTH":
modifier.point_cache.step = 1
modifier.point_cache.disk_cache = True
modifier.point_cache.external = False
elif modifier.type == "SOFT_BODY":
modifier.point_cache.step = 1
modifier.point_cache.disk_cache = True
modifier.point_cache.external = False
elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN":
modifier.domain_settings.point_cache_low.step = 1
modifier.domain_settings.point_cache_low.disk_cache = True
modifier.domain_settings.point_cache_low.external = False
modifier.domain_settings.point_cache_high.step = 1
modifier.domain_settings.point_cache_high.disk_cache = True
modifier.domain_settings.point_cache_high.external = False
# particles modifier are stupid and don't contain data
# we have to go through the object property
for psys in object.particle_systems:
psys.point_cache.step = 1
psys.point_cache.disk_cache = True
psys.point_cache.external = False
psys.point_cache.filepath = relative_path
bpy.ops.ptcache.bake_all()
#bpy.ops.wm.save_mainfile(path = path + os.sep + root + "_baked.blend")
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@rnaType
class RENDER_OT_netclientanim(bpy.types.Operator):
'''Start rendering an animation on network'''
bl_idname = "render.netclientanim"
bl_label = "Animation on network"
def poll(self, context):
return True
def execute(self, context):
scene = context.scene
netsettings = scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
'''Start rendering an animation on network'''
bl_idname = "render.netclientanim"
bl_label = "Animation on network"
if conn:
# Sending file
scene.network_render.job_id = client.clientSendJob(conn, scene, True)
conn.close()
bpy.ops.screen.render('INVOKE_AREA', animation=True)
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
def poll(self, context):
return True
def execute(self, context):
scene = context.scene
netsettings = scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
# Sending file
scene.network_render.job_id = client.clientSendJob(conn, scene, True)
conn.close()
bpy.ops.screen.render('INVOKE_AREA', animation=True)
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@rnaType
class RENDER_OT_netclientsend(bpy.types.Operator):
'''Send Render Job to the Network'''
bl_idname = "render.netclientsend"
bl_label = "Send job"
def poll(self, context):
return True
def execute(self, context):
scene = context.scene
netsettings = scene.network_render
try:
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
'''Send Render Job to the Network'''
bl_idname = "render.netclientsend"
bl_label = "Send job"
if conn:
# Sending file
scene.network_render.job_id = client.clientSendJob(conn, scene, True)
conn.close()
self.report('INFO', "Job sent to master")
except Exception as err:
self.report('ERROR', str(err))
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
def poll(self, context):
return True
def execute(self, context):
scene = context.scene
netsettings = scene.network_render
try:
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
# Sending file
scene.network_render.job_id = client.clientSendJob(conn, scene, True)
conn.close()
self.report('INFO', "Job sent to master")
except Exception as err:
self.report('ERROR', str(err))
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@rnaType
class RENDER_OT_netclientstatus(bpy.types.Operator):
'''Refresh the status of the current jobs'''
bl_idname = "render.netclientstatus"
bl_label = "Client Status"
def poll(self, context):
return True
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
'''Refresh the status of the current jobs'''
bl_idname = "render.netclientstatus"
bl_label = "Client Status"
if conn:
conn.request("GET", "/status")
response = conn.getresponse()
print( response.status, response.reason )
jobs = (netrender.model.RenderJob.materialize(j) for j in eval(str(response.read(), encoding='utf8')))
while(len(netsettings.jobs) > 0):
netsettings.jobs.remove(0)
netrender.jobs = []
for j in jobs:
netrender.jobs.append(j)
netsettings.jobs.add()
job = netsettings.jobs[-1]
j.results = j.framesStatus() # cache frame status
job.name = j.name
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
def poll(self, context):
return True
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
conn.request("GET", "/status")
response = conn.getresponse()
print( response.status, response.reason )
jobs = (netrender.model.RenderJob.materialize(j) for j in eval(str(response.read(), encoding='utf8')))
while(len(netsettings.jobs) > 0):
netsettings.jobs.remove(0)
netrender.jobs = []
for j in jobs:
netrender.jobs.append(j)
netsettings.jobs.add()
job = netsettings.jobs[-1]
j.results = j.framesStatus() # cache frame status
job.name = j.name
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@rnaType
class RENDER_OT_netclientblacklistslave(bpy.types.Operator):
'''Operator documentation text, will be used for the operator tooltip and python docs.'''
bl_idname = "render.netclientblacklistslave"
bl_label = "Client Blacklist Slave"
def poll(self, context):
return True
def execute(self, context):
netsettings = context.scene.network_render
if netsettings.active_slave_index >= 0:
# deal with data
slave = netrender.slaves.pop(netsettings.active_slave_index)
netrender.blacklist.append(slave)
# deal with rna
netsettings.slaves_blacklist.add()
netsettings.slaves_blacklist[-1].name = slave.name
netsettings.slaves.remove(netsettings.active_slave_index)
netsettings.active_slave_index = -1
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
'''Operator documentation text, will be used for the operator tooltip and python docs.'''
bl_idname = "render.netclientblacklistslave"
bl_label = "Client Blacklist Slave"
def poll(self, context):
return True
def execute(self, context):
netsettings = context.scene.network_render
if netsettings.active_slave_index >= 0:
# deal with data
slave = netrender.slaves.pop(netsettings.active_slave_index)
netrender.blacklist.append(slave)
# deal with rna
netsettings.slaves_blacklist.add()
netsettings.slaves_blacklist[-1].name = slave.name
netsettings.slaves.remove(netsettings.active_slave_index)
netsettings.active_slave_index = -1
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@rnaType
class RENDER_OT_netclientwhitelistslave(bpy.types.Operator):
'''Operator documentation text, will be used for the operator tooltip and python docs.'''
bl_idname = "render.netclientwhitelistslave"
bl_label = "Client Whitelist Slave"
def poll(self, context):
return True
def execute(self, context):
netsettings = context.scene.network_render
if netsettings.active_blacklisted_slave_index >= 0:
# deal with data
slave = netrender.blacklist.pop(netsettings.active_blacklisted_slave_index)
netrender.slaves.append(slave)
# deal with rna
netsettings.slaves.add()
netsettings.slaves[-1].name = slave.name
netsettings.slaves_blacklist.remove(netsettings.active_blacklisted_slave_index)
netsettings.active_blacklisted_slave_index = -1
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
'''Operator documentation text, will be used for the operator tooltip and python docs.'''
bl_idname = "render.netclientwhitelistslave"
bl_label = "Client Whitelist Slave"
def poll(self, context):
return True
def execute(self, context):
netsettings = context.scene.network_render
if netsettings.active_blacklisted_slave_index >= 0:
# deal with data
slave = netrender.blacklist.pop(netsettings.active_blacklisted_slave_index)
netrender.slaves.append(slave)
# deal with rna
netsettings.slaves.add()
netsettings.slaves[-1].name = slave.name
netsettings.slaves_blacklist.remove(netsettings.active_blacklisted_slave_index)
netsettings.active_blacklisted_slave_index = -1
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@rnaType
class RENDER_OT_netclientslaves(bpy.types.Operator):
'''Refresh status about available Render slaves'''
bl_idname = "render.netclientslaves"
bl_label = "Client Slaves"
def poll(self, context):
return True
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
conn.request("GET", "/slaves")
response = conn.getresponse()
print( response.status, response.reason )
slaves = (netrender.model.RenderSlave.materialize(s) for s in eval(str(response.read(), encoding='utf8')))
while(len(netsettings.slaves) > 0):
netsettings.slaves.remove(0)
netrender.slaves = []
for s in slaves:
for i in range(len(netrender.blacklist)):
slave = netrender.blacklist[i]
if slave.id == s.id:
netrender.blacklist[i] = s
netsettings.slaves_blacklist[i].name = s.name
break
else:
netrender.slaves.append(s)
netsettings.slaves.add()
slave = netsettings.slaves[-1]
slave.name = s.name
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
'''Refresh status about available Render slaves'''
bl_idname = "render.netclientslaves"
bl_label = "Client Slaves"
def poll(self, context):
return True
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
conn.request("GET", "/slaves")
response = conn.getresponse()
print( response.status, response.reason )
slaves = (netrender.model.RenderSlave.materialize(s) for s in eval(str(response.read(), encoding='utf8')))
while(len(netsettings.slaves) > 0):
netsettings.slaves.remove(0)
netrender.slaves = []
for s in slaves:
for i in range(len(netrender.blacklist)):
slave = netrender.blacklist[i]
if slave.id == s.id:
netrender.blacklist[i] = s
netsettings.slaves_blacklist[i].name = s.name
break
else:
netrender.slaves.append(s)
netsettings.slaves.add()
slave = netsettings.slaves[-1]
slave.name = s.name
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@rnaType
class RENDER_OT_netclientcancel(bpy.types.Operator):
'''Cancel the selected network rendering job.'''
bl_idname = "render.netclientcancel"
bl_label = "Client Cancel"
def poll(self, context):
netsettings = context.scene.network_render
return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
job = netrender.jobs[netsettings.active_job_index]
conn.request("POST", cancelURL(job.id))
response = conn.getresponse()
print( response.status, response.reason )
'''Cancel the selected network rendering job.'''
bl_idname = "render.netclientcancel"
bl_label = "Client Cancel"
def poll(self, context):
netsettings = context.scene.network_render
return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
job = netrender.jobs[netsettings.active_job_index]
conn.request("POST", cancelURL(job.id))
response = conn.getresponse()
print( response.status, response.reason )
netsettings.jobs.remove(netsettings.active_job_index)
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
netsettings.jobs.remove(netsettings.active_job_index)
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@rnaType
class RENDER_OT_netclientcancelall(bpy.types.Operator):
'''Cancel all running network rendering jobs.'''
bl_idname = "render.netclientcancelall"
bl_label = "Client Cancel All"
def poll(self, context):
return True
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
conn.request("POST", "/clear")
response = conn.getresponse()
print( response.status, response.reason )
while(len(netsettings.jobs) > 0):
netsettings.jobs.remove(0)
'''Cancel all running network rendering jobs.'''
bl_idname = "render.netclientcancelall"
bl_label = "Client Cancel All"
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
def poll(self, context):
return True
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
conn.request("POST", "/clear")
response = conn.getresponse()
print( response.status, response.reason )
while(len(netsettings.jobs) > 0):
netsettings.jobs.remove(0)
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@rnaType
class netclientdownload(bpy.types.Operator):
'''Download render results from the network'''
bl_idname = "render.netclientdownload"
bl_label = "Client Download"
def poll(self, context):
netsettings = context.scene.network_render
return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0
def execute(self, context):
netsettings = context.scene.network_render
rd = context.scene.render_data
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
job = netrender.jobs[netsettings.active_job_index]
for frame in job.frames:
client.requestResult(conn, job.id, frame.number)
response = conn.getresponse()
if response.status != http.client.OK:
print("missing", frame.number)
continue
print("got back", frame.number)
f = open(netsettings.path + "%06d" % frame.number + ".exr", "wb")
buf = response.read(1024)
while buf:
f.write(buf)
buf = response.read(1024)
f.close()
conn.close()
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
'''Download render results from the network'''
bl_idname = "render.netclientdownload"
bl_label = "Client Download"
def poll(self, context):
netsettings = context.scene.network_render
return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0
def execute(self, context):
netsettings = context.scene.network_render
rd = context.scene.render_data
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
job = netrender.jobs[netsettings.active_job_index]
for frame in job.frames:
client.requestResult(conn, job.id, frame.number)
response = conn.getresponse()
if response.status != http.client.OK:
print("missing", frame.number)
continue
print("got back", frame.number)
f = open(netsettings.path + "%06d" % frame.number + ".exr", "wb")
buf = response.read(1024)
while buf:
f.write(buf)
buf = response.read(1024)
f.close()
conn.close()
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@rnaType
class netclientscan(bpy.types.Operator):
__slots__ = []
'''Operator documentation text, will be used for the operator tooltip and python docs.'''
bl_idname = "render.netclientscan"
bl_label = "Client Scan"
def poll(self, context):
return True
def execute(self, context):
address, port = clientScan(self.report)
__slots__ = []
'''Operator documentation text, will be used for the operator tooltip and python docs.'''
bl_idname = "render.netclientscan"
bl_label = "Client Scan"
if address:
scene = context.scene
netsettings = scene.network_render
netsettings.server_address = address
netsettings.server_port = port
return {'FINISHED'}
def poll(self, context):
return True
def invoke(self, context, event):
print(dir(self))
return self.execute(context)
def execute(self, context):
address, port = clientScan(self.report)
if address:
scene = context.scene
netsettings = scene.network_render
netsettings.server_address = address
netsettings.server_port = port
return {'FINISHED'}
def invoke(self, context, event):
print(dir(self))
return self.execute(context)
@rnaType
class netclientweb(bpy.types.Operator):
'''Open new window with information about running rendering jobs'''
bl_idname = "render.netclientweb"
bl_label = "Open Master Monitor"
def poll(self, context):
netsettings = context.scene.network_render
return netsettings.server_address != "[default]"
def execute(self, context):
netsettings = context.scene.network_render
# open connection to make sure server exists
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
conn.close()
webbrowser.open("http://%s:%i" % (netsettings.server_address, netsettings.server_port))
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
'''Open new window with information about running rendering jobs'''
bl_idname = "render.netclientweb"
bl_label = "Open Master Monitor"
def poll(self, context):
netsettings = context.scene.network_render
return netsettings.server_address != "[default]"
def execute(self, context):
netsettings = context.scene.network_render
# open connection to make sure server exists
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
conn.close()
webbrowser.open("http://%s:%i" % (netsettings.server_address, netsettings.server_port))
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)

@ -4,12 +4,12 @@
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@ -30,218 +30,218 @@ MAX_TIMEOUT = 10
INCREMENT_TIMEOUT = 1
if platform.system() == 'Windows' and platform.version() >= '5': # Error mode is only available on Win2k or higher, that's version 5
import ctypes
def SetErrorMode():
val = ctypes.windll.kernel32.SetErrorMode(0x0002)
ctypes.windll.kernel32.SetErrorMode(val | 0x0002)
return val
def RestoreErrorMode(val):
ctypes.windll.kernel32.SetErrorMode(val)
import ctypes
def SetErrorMode():
val = ctypes.windll.kernel32.SetErrorMode(0x0002)
ctypes.windll.kernel32.SetErrorMode(val | 0x0002)
return val
def RestoreErrorMode(val):
ctypes.windll.kernel32.SetErrorMode(val)
else:
def SetErrorMode():
return 0
def RestoreErrorMode(val):
pass
def SetErrorMode():
return 0
def RestoreErrorMode(val):
pass
def slave_Info():
sysname, nodename, release, version, machine, processor = platform.uname()
slave = netrender.model.RenderSlave()
slave.name = nodename
slave.stats = sysname + " " + release + " " + machine + " " + processor
return slave
sysname, nodename, release, version, machine, processor = platform.uname()
slave = netrender.model.RenderSlave()
slave.name = nodename
slave.stats = sysname + " " + release + " " + machine + " " + processor
return slave
def testCancel(conn, job_id, frame_number):
conn.request("HEAD", "/status", headers={"job-id":job_id, "job-frame": str(frame_number)})
conn.request("HEAD", "/status", headers={"job-id":job_id, "job-frame": str(frame_number)})
# cancelled if job isn't found anymore
if conn.getresponse().status == http.client.NO_CONTENT:
return True
else:
return False
# cancelled if job isn't found anymore
if conn.getresponse().status == http.client.NO_CONTENT:
return True
else:
return False
def testFile(conn, job_id, slave_id, file_index, JOB_PREFIX, file_path, main_path = None):
job_full_path = prefixPath(JOB_PREFIX, file_path, main_path)
if not os.path.exists(job_full_path):
temp_path = JOB_PREFIX + "slave.temp.blend"
conn.request("GET", fileURL(job_id, file_index), headers={"slave-id":slave_id})
response = conn.getresponse()
if response.status != http.client.OK:
return None # file for job not returned by server, need to return an error code to server
f = open(temp_path, "wb")
buf = response.read(1024)
while buf:
f.write(buf)
buf = response.read(1024)
f.close()
os.renames(temp_path, job_full_path)
return job_full_path
job_full_path = prefixPath(JOB_PREFIX, file_path, main_path)
if not os.path.exists(job_full_path):
temp_path = JOB_PREFIX + "slave.temp.blend"
conn.request("GET", fileURL(job_id, file_index), headers={"slave-id":slave_id})
response = conn.getresponse()
if response.status != http.client.OK:
return None # file for job not returned by server, need to return an error code to server
f = open(temp_path, "wb")
buf = response.read(1024)
while buf:
f.write(buf)
buf = response.read(1024)
f.close()
os.renames(temp_path, job_full_path)
return job_full_path
def render_slave(engine, netsettings):
timeout = 1
engine.update_stats("", "Network render node initiation")
conn = clientConnection(netsettings.server_address, netsettings.server_port)
if conn:
conn.request("POST", "/slave", repr(slave_Info().serialize()))
response = conn.getresponse()
slave_id = response.getheader("slave-id")
NODE_PREFIX = netsettings.path + "slave_" + slave_id + os.sep
if not os.path.exists(NODE_PREFIX):
os.mkdir(NODE_PREFIX)
while not engine.test_break():
conn.request("GET", "/job", headers={"slave-id":slave_id})
response = conn.getresponse()
if response.status == http.client.OK:
timeout = 1 # reset timeout on new job
job = netrender.model.RenderJob.materialize(eval(str(response.read(), encoding='utf8')))
JOB_PREFIX = NODE_PREFIX + "job_" + job.id + os.sep
if not os.path.exists(JOB_PREFIX):
os.mkdir(JOB_PREFIX)
if job.type == netrender.model.JOB_BLENDER:
job_path = job.files[0].filepath # path of main file
main_path, main_file = os.path.split(job_path)
job_full_path = testFile(conn, job.id, slave_id, 0, JOB_PREFIX, job_path)
print("Fullpath", job_full_path)
print("File:", main_file, "and %i other files" % (len(job.files) - 1,))
engine.update_stats("", "Render File "+ main_file+ " for job "+ job.id)
for rfile in job.files[1:]:
print("\t", rfile.filepath)
testFile(conn, job.id, slave_id, rfile.index, JOB_PREFIX, rfile.filepath, main_path)
timeout = 1
# announce log to master
logfile = netrender.model.LogFile(job.id, slave_id, [frame.number for frame in job.frames])
conn.request("POST", "/log", bytes(repr(logfile.serialize()), encoding='utf8'))
response = conn.getresponse()
first_frame = job.frames[0].number
# start render
start_t = time.time()
if job.type == netrender.model.JOB_BLENDER:
frame_args = []
for frame in job.frames:
print("frame", frame.number)
frame_args += ["-f", str(frame.number)]
val = SetErrorMode()
process = subprocess.Popen([BLENDER_PATH, "-b", "-noaudio", job_full_path, "-o", JOB_PREFIX + "######", "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
RestoreErrorMode(val)
elif job.type == netrender.model.JOB_PROCESS:
command = job.frames[0].command
val = SetErrorMode()
process = subprocess.Popen(command.split(" "), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
RestoreErrorMode(val)
headers = {"slave-id":slave_id}
cancelled = False
stdout = bytes()
run_t = time.time()
while process.poll() == None and not cancelled:
stdout += process.stdout.read(32)
current_t = time.time()
cancelled = engine.test_break()
if current_t - run_t > CANCEL_POLL_SPEED:
# update logs if needed
if stdout:
# (only need to update on one frame, they are linked
conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers)
response = conn.getresponse()
stdout = bytes()
run_t = current_t
if testCancel(conn, job.id, first_frame):
cancelled = True
# read leftovers if needed
stdout += process.stdout.read()
if cancelled:
# kill process if needed
if process.poll() == None:
process.terminate()
continue # to next frame
total_t = time.time() - start_t
avg_t = total_t / len(job.frames)
status = process.returncode
print("status", status)
# flush the rest of the logs
if stdout:
# (only need to update on one frame, they are linked
conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers)
if conn.getresponse().status == http.client.NO_CONTENT:
continue
headers = {"job-id":job.id, "slave-id":slave_id, "job-time":str(avg_t)}
if status == 0: # non zero status is error
headers["job-result"] = str(DONE)
for frame in job.frames:
headers["job-frame"] = str(frame.number)
if job.type == netrender.model.JOB_BLENDER:
# send image back to server
f = open(JOB_PREFIX + "%06d" % frame.number + ".exr", 'rb')
conn.request("PUT", "/render", f, headers=headers)
f.close()
if conn.getresponse().status == http.client.NO_CONTENT:
continue
elif job.type == netrender.model.JOB_PROCESS:
conn.request("PUT", "/render", headers=headers)
if conn.getresponse().status == http.client.NO_CONTENT:
continue
else:
headers["job-result"] = str(ERROR)
for frame in job.frames:
headers["job-frame"] = str(frame.number)
# send error result back to server
conn.request("PUT", "/render", headers=headers)
if conn.getresponse().status == http.client.NO_CONTENT:
continue
else:
if timeout < MAX_TIMEOUT:
timeout += INCREMENT_TIMEOUT
for i in range(timeout):
time.sleep(1)
if engine.test_break():
conn.close()
return
conn.close()
engine.update_stats("", "Network render node initiation")
conn = clientConnection(netsettings.server_address, netsettings.server_port)
if conn:
conn.request("POST", "/slave", repr(slave_Info().serialize()))
response = conn.getresponse()
slave_id = response.getheader("slave-id")
NODE_PREFIX = netsettings.path + "slave_" + slave_id + os.sep
if not os.path.exists(NODE_PREFIX):
os.mkdir(NODE_PREFIX)
while not engine.test_break():
conn.request("GET", "/job", headers={"slave-id":slave_id})
response = conn.getresponse()
if response.status == http.client.OK:
timeout = 1 # reset timeout on new job
job = netrender.model.RenderJob.materialize(eval(str(response.read(), encoding='utf8')))
JOB_PREFIX = NODE_PREFIX + "job_" + job.id + os.sep
if not os.path.exists(JOB_PREFIX):
os.mkdir(JOB_PREFIX)
if job.type == netrender.model.JOB_BLENDER:
job_path = job.files[0].filepath # path of main file
main_path, main_file = os.path.split(job_path)
job_full_path = testFile(conn, job.id, slave_id, 0, JOB_PREFIX, job_path)
print("Fullpath", job_full_path)
print("File:", main_file, "and %i other files" % (len(job.files) - 1,))
engine.update_stats("", "Render File "+ main_file+ " for job "+ job.id)
for rfile in job.files[1:]:
print("\t", rfile.filepath)
testFile(conn, job.id, slave_id, rfile.index, JOB_PREFIX, rfile.filepath, main_path)
# announce log to master
logfile = netrender.model.LogFile(job.id, slave_id, [frame.number for frame in job.frames])
conn.request("POST", "/log", bytes(repr(logfile.serialize()), encoding='utf8'))
response = conn.getresponse()
first_frame = job.frames[0].number
# start render
start_t = time.time()
if job.type == netrender.model.JOB_BLENDER:
frame_args = []
for frame in job.frames:
print("frame", frame.number)
frame_args += ["-f", str(frame.number)]
val = SetErrorMode()
process = subprocess.Popen([BLENDER_PATH, "-b", "-noaudio", job_full_path, "-o", JOB_PREFIX + "######", "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
RestoreErrorMode(val)
elif job.type == netrender.model.JOB_PROCESS:
command = job.frames[0].command
val = SetErrorMode()
process = subprocess.Popen(command.split(" "), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
RestoreErrorMode(val)
headers = {"slave-id":slave_id}
cancelled = False
stdout = bytes()
run_t = time.time()
while process.poll() == None and not cancelled:
stdout += process.stdout.read(32)
current_t = time.time()
cancelled = engine.test_break()
if current_t - run_t > CANCEL_POLL_SPEED:
# update logs if needed
if stdout:
# (only need to update on one frame, they are linked
conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers)
response = conn.getresponse()
stdout = bytes()
run_t = current_t
if testCancel(conn, job.id, first_frame):
cancelled = True
# read leftovers if needed
stdout += process.stdout.read()
if cancelled:
# kill process if needed
if process.poll() == None:
process.terminate()
continue # to next frame
total_t = time.time() - start_t
avg_t = total_t / len(job.frames)
status = process.returncode
print("status", status)
# flush the rest of the logs
if stdout:
# (only need to update on one frame, they are linked
conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers)
if conn.getresponse().status == http.client.NO_CONTENT:
continue
headers = {"job-id":job.id, "slave-id":slave_id, "job-time":str(avg_t)}
if status == 0: # non zero status is error
headers["job-result"] = str(DONE)
for frame in job.frames:
headers["job-frame"] = str(frame.number)
if job.type == netrender.model.JOB_BLENDER:
# send image back to server
f = open(JOB_PREFIX + "%06d" % frame.number + ".exr", 'rb')
conn.request("PUT", "/render", f, headers=headers)
f.close()
if conn.getresponse().status == http.client.NO_CONTENT:
continue
elif job.type == netrender.model.JOB_PROCESS:
conn.request("PUT", "/render", headers=headers)
if conn.getresponse().status == http.client.NO_CONTENT:
continue
else:
headers["job-result"] = str(ERROR)
for frame in job.frames:
headers["job-frame"] = str(frame.number)
# send error result back to server
conn.request("PUT", "/render", headers=headers)
if conn.getresponse().status == http.client.NO_CONTENT:
continue
else:
if timeout < MAX_TIMEOUT:
timeout += INCREMENT_TIMEOUT
for i in range(timeout):
time.sleep(1)
if engine.test_break():
conn.close()
return
conn.close()
if __name__ == "__main__":
pass
pass

@ -4,12 +4,12 @@
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@ -37,319 +37,319 @@ DONE = 2
ERROR = 3
class RenderButtonsPanel(bpy.types.Panel):
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
# COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
def poll(self, context):
rd = context.scene.render_data
return (rd.use_game_engine==False) and (rd.engine in self.COMPAT_ENGINES)
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
# COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
def poll(self, context):
rd = context.scene.render_data
return (rd.use_game_engine==False) and (rd.engine in self.COMPAT_ENGINES)
# Setting panel, use in the scene for now.
@rnaType
class RENDER_PT_network_settings(RenderButtonsPanel):
bl_label = "Network Settings"
COMPAT_ENGINES = {'NET_RENDER'}
bl_label = "Network Settings"
COMPAT_ENGINES = {'NET_RENDER'}
def draw(self, context):
layout = self.layout
def draw(self, context):
layout = self.layout
scene = context.scene
rd = scene.render_data
layout.active = True
split = layout.split()
col = split.column()
scene = context.scene
rd = scene.render_data
if scene.network_render.mode in ("RENDER_MASTER", "RENDER_SLAVE"):
col.operator("screen.render", text="Start", icon='PLAY').animation = True
layout.active = True
col.prop(scene.network_render, "mode")
col.prop(scene.network_render, "path")
col.prop(scene.network_render, "server_address")
col.prop(scene.network_render, "server_port")
if scene.network_render.mode == "RENDER_MASTER":
col.prop(scene.network_render, "server_broadcast")
else:
col.operator("render.netclientscan", icon='FILE_REFRESH', text="")
split = layout.split()
col.operator("render.netclientweb", icon='QUESTION')
col = split.column()
if scene.network_render.mode in ("RENDER_MASTER", "RENDER_SLAVE"):
col.operator("screen.render", text="Start", icon='PLAY').animation = True
col.prop(scene.network_render, "mode")
col.prop(scene.network_render, "path")
col.prop(scene.network_render, "server_address")
col.prop(scene.network_render, "server_port")
if scene.network_render.mode == "RENDER_MASTER":
col.prop(scene.network_render, "server_broadcast")
else:
col.operator("render.netclientscan", icon='FILE_REFRESH', text="")
col.operator("render.netclientweb", icon='QUESTION')
@rnaType
class RENDER_PT_network_job(RenderButtonsPanel):
bl_label = "Job Settings"
COMPAT_ENGINES = {'NET_RENDER'}
def poll(self, context):
scene = context.scene
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT")
bl_label = "Job Settings"
COMPAT_ENGINES = {'NET_RENDER'}
def draw(self, context):
layout = self.layout
def poll(self, context):
scene = context.scene
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT")
scene = context.scene
rd = scene.render_data
layout.active = True
split = layout.split()
col = split.column()
if scene.network_render.server_address != "[default]":
col.operator("render.netclientanim", icon='RENDER_ANIMATION')
col.operator("render.netclientsend", icon='FILE_BLEND')
if scene.network_render.job_id:
col.operator("screen.render", text="Get Results", icon='RENDER_ANIMATION').animation = True
col.prop(scene.network_render, "job_name")
col.prop(scene.network_render, "job_category")
row = col.row()
row.prop(scene.network_render, "priority")
row.prop(scene.network_render, "chunks")
def draw(self, context):
layout = self.layout
scene = context.scene
rd = scene.render_data
layout.active = True
split = layout.split()
col = split.column()
if scene.network_render.server_address != "[default]":
col.operator("render.netclientanim", icon='RENDER_ANIMATION')
col.operator("render.netclientsend", icon='FILE_BLEND')
if scene.network_render.job_id:
col.operator("screen.render", text="Get Results", icon='RENDER_ANIMATION').animation = True
col.prop(scene.network_render, "job_name")
col.prop(scene.network_render, "job_category")
row = col.row()
row.prop(scene.network_render, "priority")
row.prop(scene.network_render, "chunks")
@rnaType
class RENDER_PT_network_slaves(RenderButtonsPanel):
bl_label = "Slaves Status"
COMPAT_ENGINES = {'NET_RENDER'}
def poll(self, context):
scene = context.scene
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT"
and scene.network_render.server_address != "[default]")
bl_label = "Slaves Status"
COMPAT_ENGINES = {'NET_RENDER'}
def draw(self, context):
layout = self.layout
scene = context.scene
netsettings = scene.network_render
def poll(self, context):
scene = context.scene
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT"
and scene.network_render.server_address != "[default]")
row = layout.row()
row.template_list(netsettings, "slaves", netsettings, "active_slave_index", rows=2)
def draw(self, context):
layout = self.layout
sub = row.column(align=True)
sub.operator("render.netclientslaves", icon='FILE_REFRESH', text="")
sub.operator("render.netclientblacklistslave", icon='ZOOMOUT', text="")
if len(netrender.slaves) == 0 and len(netsettings.slaves) > 0:
while(len(netsettings.slaves) > 0):
netsettings.slaves.remove(0)
if netsettings.active_slave_index >= 0 and len(netsettings.slaves) > 0:
layout.separator()
slave = netrender.slaves[netsettings.active_slave_index]
scene = context.scene
netsettings = scene.network_render
layout.label(text="Name: " + slave.name)
layout.label(text="Address: " + slave.address[0])
layout.label(text="Seen: " + time.ctime(slave.last_seen))
layout.label(text="Stats: " + slave.stats)
row = layout.row()
row.template_list(netsettings, "slaves", netsettings, "active_slave_index", rows=2)
sub = row.column(align=True)
sub.operator("render.netclientslaves", icon='FILE_REFRESH', text="")
sub.operator("render.netclientblacklistslave", icon='ZOOMOUT', text="")
if len(netrender.slaves) == 0 and len(netsettings.slaves) > 0:
while(len(netsettings.slaves) > 0):
netsettings.slaves.remove(0)
if netsettings.active_slave_index >= 0 and len(netsettings.slaves) > 0:
layout.separator()
slave = netrender.slaves[netsettings.active_slave_index]
layout.label(text="Name: " + slave.name)
layout.label(text="Address: " + slave.address[0])
layout.label(text="Seen: " + time.ctime(slave.last_seen))
layout.label(text="Stats: " + slave.stats)
@rnaType
class RENDER_PT_network_slaves_blacklist(RenderButtonsPanel):
bl_label = "Slaves Blacklist"
COMPAT_ENGINES = {'NET_RENDER'}
def poll(self, context):
scene = context.scene
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT"
and scene.network_render.server_address != "[default]")
def draw(self, context):
layout = self.layout
scene = context.scene
netsettings = scene.network_render
bl_label = "Slaves Blacklist"
COMPAT_ENGINES = {'NET_RENDER'}
row = layout.row()
row.template_list(netsettings, "slaves_blacklist", netsettings, "active_blacklisted_slave_index", rows=2)
def poll(self, context):
scene = context.scene
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT"
and scene.network_render.server_address != "[default]")
sub = row.column(align=True)
sub.operator("render.netclientwhitelistslave", icon='ZOOMOUT', text="")
def draw(self, context):
layout = self.layout
if len(netrender.blacklist) == 0 and len(netsettings.slaves_blacklist) > 0:
while(len(netsettings.slaves_blacklist) > 0):
netsettings.slaves_blacklist.remove(0)
if netsettings.active_blacklisted_slave_index >= 0 and len(netsettings.slaves_blacklist) > 0:
layout.separator()
slave = netrender.blacklist[netsettings.active_blacklisted_slave_index]
scene = context.scene
netsettings = scene.network_render
layout.label(text="Name: " + slave.name)
layout.label(text="Address: " + slave.address[0])
layout.label(text="Seen: " + time.ctime(slave.last_seen))
layout.label(text="Stats: " + slave.stats)
row = layout.row()
row.template_list(netsettings, "slaves_blacklist", netsettings, "active_blacklisted_slave_index", rows=2)
sub = row.column(align=True)
sub.operator("render.netclientwhitelistslave", icon='ZOOMOUT', text="")
if len(netrender.blacklist) == 0 and len(netsettings.slaves_blacklist) > 0:
while(len(netsettings.slaves_blacklist) > 0):
netsettings.slaves_blacklist.remove(0)
if netsettings.active_blacklisted_slave_index >= 0 and len(netsettings.slaves_blacklist) > 0:
layout.separator()
slave = netrender.blacklist[netsettings.active_blacklisted_slave_index]
layout.label(text="Name: " + slave.name)
layout.label(text="Address: " + slave.address[0])
layout.label(text="Seen: " + time.ctime(slave.last_seen))
layout.label(text="Stats: " + slave.stats)
@rnaType
class RENDER_PT_network_jobs(RenderButtonsPanel):
bl_label = "Jobs"
COMPAT_ENGINES = {'NET_RENDER'}
def poll(self, context):
scene = context.scene
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT"
and scene.network_render.server_address != "[default]")
def draw(self, context):
layout = self.layout
scene = context.scene
netsettings = scene.network_render
bl_label = "Jobs"
COMPAT_ENGINES = {'NET_RENDER'}
row = layout.row()
row.template_list(netsettings, "jobs", netsettings, "active_job_index", rows=2)
def poll(self, context):
scene = context.scene
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT"
and scene.network_render.server_address != "[default]")
sub = row.column(align=True)
sub.operator("render.netclientstatus", icon='FILE_REFRESH', text="")
sub.operator("render.netclientcancel", icon='ZOOMOUT', text="")
sub.operator("render.netclientcancelall", icon='PANEL_CLOSE', text="")
sub.operator("render.netclientdownload", icon='RENDER_ANIMATION', text="")
def draw(self, context):
layout = self.layout
if len(netrender.jobs) == 0 and len(netsettings.jobs) > 0:
while(len(netsettings.jobs) > 0):
netsettings.jobs.remove(0)
if netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0:
layout.separator()
job = netrender.jobs[netsettings.active_job_index]
scene = context.scene
netsettings = scene.network_render
layout.label(text="Name: %s" % job.name)
layout.label(text="Length: %04i" % len(job))
layout.label(text="Done: %04i" % job.results[DONE])
layout.label(text="Error: %04i" % job.results[ERROR])
row = layout.row()
row.template_list(netsettings, "jobs", netsettings, "active_job_index", rows=2)
sub = row.column(align=True)
sub.operator("render.netclientstatus", icon='FILE_REFRESH', text="")
sub.operator("render.netclientcancel", icon='ZOOMOUT', text="")
sub.operator("render.netclientcancelall", icon='PANEL_CLOSE', text="")
sub.operator("render.netclientdownload", icon='RENDER_ANIMATION', text="")
if len(netrender.jobs) == 0 and len(netsettings.jobs) > 0:
while(len(netsettings.jobs) > 0):
netsettings.jobs.remove(0)
if netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0:
layout.separator()
job = netrender.jobs[netsettings.active_job_index]
layout.label(text="Name: %s" % job.name)
layout.label(text="Length: %04i" % len(job))
layout.label(text="Done: %04i" % job.results[DONE])
layout.label(text="Error: %04i" % job.results[ERROR])
@rnaType
class NetRenderSettings(bpy.types.IDPropertyGroup):
pass
pass
@rnaType
class NetRenderSlave(bpy.types.IDPropertyGroup):
pass
pass
@rnaType
class NetRenderJob(bpy.types.IDPropertyGroup):
pass
pass
bpy.types.Scene.PointerProperty(attr="network_render", type=NetRenderSettings, name="Network Render", description="Network Render Settings")
NetRenderSettings.StringProperty( attr="server_address",
name="Server address",
description="IP or name of the master render server",
maxlen = 128,
default = "[default]")
name="Server address",
description="IP or name of the master render server",
maxlen = 128,
default = "[default]")
NetRenderSettings.IntProperty( attr="server_port",
name="Server port",
description="port of the master render server",
default = 8000,
min=1,
max=65535)
name="Server port",
description="port of the master render server",
default = 8000,
min=1,
max=65535)
NetRenderSettings.BoolProperty( attr="server_broadcast",
name="Broadcast server address",
description="broadcast server address on local network",
default = True)
name="Broadcast server address",
description="broadcast server address on local network",
default = True)
default_path = os.environ.get("TEMP", None)
if not default_path:
if os.name == 'nt':
default_path = "c:/tmp/"
else:
default_path = "/tmp/"
if os.name == 'nt':
default_path = "c:/tmp/"
else:
default_path = "/tmp/"
elif not default_path.endswith(os.sep):
default_path += os.sep
default_path += os.sep
NetRenderSettings.StringProperty( attr="path",
name="Path",
description="Path for temporary files",
maxlen = 128,
default = default_path)
name="Path",
description="Path for temporary files",
maxlen = 128,
default = default_path)
NetRenderSettings.StringProperty( attr="job_name",
name="Job name",
description="Name of the job",
maxlen = 128,
default = "[default]")
name="Job name",
description="Name of the job",
maxlen = 128,
default = "[default]")
NetRenderSettings.StringProperty( attr="job_category",
name="Job category",
description="Category of the job",
maxlen = 128,
default = "")
name="Job category",
description="Category of the job",
maxlen = 128,
default = "")
NetRenderSettings.IntProperty( attr="chunks",
name="Chunks",
description="Number of frame to dispatch to each slave in one chunk",
default = 5,
min=1,
max=65535)
name="Chunks",
description="Number of frame to dispatch to each slave in one chunk",
default = 5,
min=1,
max=65535)
NetRenderSettings.IntProperty( attr="priority",
name="Priority",
description="Priority of the job",
default = 1,
min=1,
max=10)
name="Priority",
description="Priority of the job",
default = 1,
min=1,
max=10)
NetRenderSettings.StringProperty( attr="job_id",
name="Network job id",
description="id of the last sent render job",
maxlen = 64,
default = "")
name="Network job id",
description="id of the last sent render job",
maxlen = 64,
default = "")
NetRenderSettings.IntProperty( attr="active_slave_index",
name="Index of the active slave",
description="",
default = -1,
min= -1,
max=65535)
name="Index of the active slave",
description="",
default = -1,
min= -1,
max=65535)
NetRenderSettings.IntProperty( attr="active_blacklisted_slave_index",
name="Index of the active slave",
description="",
default = -1,
min= -1,
max=65535)
name="Index of the active slave",
description="",
default = -1,
min= -1,
max=65535)
NetRenderSettings.IntProperty( attr="active_job_index",
name="Index of the active job",
description="",
default = -1,
min= -1,
max=65535)
name="Index of the active job",
description="",
default = -1,
min= -1,
max=65535)
NetRenderSettings.EnumProperty(attr="mode",
items=(
("RENDER_CLIENT", "Client", "Act as render client"),
("RENDER_MASTER", "Master", "Act as render master"),
("RENDER_SLAVE", "Slave", "Act as render slave"),
),
name="Network mode",
description="Mode of operation of this instance",
default="RENDER_CLIENT")
items=(
("RENDER_CLIENT", "Client", "Act as render client"),
("RENDER_MASTER", "Master", "Act as render master"),
("RENDER_SLAVE", "Slave", "Act as render slave"),
),
name="Network mode",
description="Mode of operation of this instance",
default="RENDER_CLIENT")
NetRenderSettings.CollectionProperty(attr="slaves", type=NetRenderSlave, name="Slaves", description="")
NetRenderSettings.CollectionProperty(attr="slaves_blacklist", type=NetRenderSlave, name="Slaves Blacklist", description="")
NetRenderSettings.CollectionProperty(attr="jobs", type=NetRenderJob, name="Job List", description="")
NetRenderSlave.StringProperty( attr="name",
name="Name of the slave",
description="",
maxlen = 64,
default = "")
name="Name of the slave",
description="",
maxlen = 64,
default = "")
NetRenderJob.StringProperty( attr="name",
name="Name of the job",
description="",
maxlen = 128,
default = "")
name="Name of the job",
description="",
maxlen = 128,
default = "")

@ -4,12 +4,12 @@
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@ -51,22 +51,22 @@ DONE = 2
ERROR = 3
FRAME_STATUS_TEXT = {
QUEUED: "Queued",
DISPATCHED: "Dispatched",
DONE: "Done",
ERROR: "Error"
}
QUEUED: "Queued",
DISPATCHED: "Dispatched",
DONE: "Done",
ERROR: "Error"
}
def rnaType(rna_type):
if bpy: bpy.types.register(rna_type)
return rna_type
if bpy: bpy.types.register(rna_type)
return rna_type
def reporting(report, message, errorType = None):
if errorType:
t = 'ERROR'
else:
t = 'INFO'
if report:
report(t, message)
return None
@ -82,14 +82,14 @@ def clientScan(report = None):
s.settimeout(30)
s.bind(('', 8000))
buf, address = s.recvfrom(64)
address = address[0]
port = int(str(buf, encoding='utf8'))
reporting(report, "Master server found")
return (address, port)
except socket.timeout:
reporting(report, "No master server on network", IOError)
@ -105,10 +105,10 @@ def clientConnection(address, port, report = None):
address, port = clientScan()
if address == "":
return None
try:
try:
conn = http.client.HTTPConnection(address, port)
if conn:
if clientVerifyVersion(conn):
return conn
@ -123,21 +123,21 @@ def clientConnection(address, port, report = None):
raise
def clientVerifyVersion(conn):
conn.request("GET", "/version")
response = conn.getresponse()
if response.status != http.client.OK:
conn.close()
return False
server_version = response.read()
if server_version != VERSION:
print("Incorrect server version!")
print("expected", str(VERSION, encoding='utf8'), "received", str(server_version, encoding='utf8'))
return False
return True
conn.request("GET", "/version")
response = conn.getresponse()
if response.status != http.client.OK:
conn.close()
return False
server_version = response.read()
if server_version != VERSION:
print("Incorrect server version!")
print("expected", str(VERSION, encoding='utf8'), "received", str(server_version, encoding='utf8'))
return False
return True
def fileURL(job_id, file_index):
return "/file_%s_%i" % (job_id, file_index)
@ -152,20 +152,20 @@ def cancelURL(job_id):
return "/cancel_%s" % (job_id)
def prefixPath(prefix_directory, file_path, prefix_path):
if os.path.isabs(file_path):
# if an absolute path, make sure path exists, if it doesn't, use relative local path
full_path = file_path
if not os.path.exists(full_path):
p, n = os.path.split(full_path)
if prefix_path and p.startswith(prefix_path):
directory = prefix_directory + p[len(prefix_path):]
full_path = directory + os.sep + n
if not os.path.exists(directory):
os.mkdir(directory)
else:
full_path = prefix_directory + n
else:
full_path = prefix_directory + file_path
return full_path
if os.path.isabs(file_path):
# if an absolute path, make sure path exists, if it doesn't, use relative local path
full_path = file_path
if not os.path.exists(full_path):
p, n = os.path.split(full_path)
if prefix_path and p.startswith(prefix_path):
directory = prefix_directory + p[len(prefix_path):]
full_path = directory + os.sep + n
if not os.path.exists(directory):
os.mkdir(directory)
else:
full_path = prefix_directory + n
else:
full_path = prefix_directory + file_path
return full_path

@ -4,4 +4,4 @@ bpy.context.scene.render_data.resolution_percentage = 100
bpy.context.scene.render_data.pixel_aspect_x = 1
bpy.context.scene.render_data.pixel_aspect_y = 1
bpy.context.scene.render_data.fps = 24
bpy.context.scene.render_data.fps_base = 1
bpy.context.scene.render_data.fps_base = 1

@ -4,4 +4,4 @@ bpy.context.scene.render_data.resolution_percentage = 100
bpy.context.scene.render_data.pixel_aspect_x = 1
bpy.context.scene.render_data.pixel_aspect_y = 1
bpy.context.scene.render_data.fps = 24
bpy.context.scene.render_data.fps_base = 1
bpy.context.scene.render_data.fps_base = 1

@ -4,4 +4,4 @@ bpy.context.scene.render_data.resolution_percentage = 100
bpy.context.scene.render_data.pixel_aspect_x = 54
bpy.context.scene.render_data.pixel_aspect_y = 51
bpy.context.scene.render_data.fps = 25
bpy.context.scene.render_data.fps_base = 1
bpy.context.scene.render_data.fps_base = 1

@ -4,4 +4,4 @@ bpy.context.scene.render_data.resolution_percentage = 100
bpy.context.scene.render_data.pixel_aspect_x = 64
bpy.context.scene.render_data.pixel_aspect_y = 45
bpy.context.scene.render_data.fps = 25
bpy.context.scene.render_data.fps_base = 1
bpy.context.scene.render_data.fps_base = 1

@ -1476,13 +1476,13 @@ class USERPREF_PT_input(bpy.types.Panel):
for km in kc.keymaps:
filtered_items = [kmi for kmi in km.items if filter in kmi.name.lower()]
if len(filtered_items) != 0:
km = km.active()
layout.set_context_pointer("keymap", km)
col = layout.column()
row = col.row()
row.label(text=km.name, icon="DOT")
@ -1496,7 +1496,7 @@ class USERPREF_PT_input(bpy.types.Panel):
for kmi in filtered_items:
self.draw_kmi(kc, km, kmi, col, 1)
# "Add New" at end of keymap item list
col = self.indented_layout(layout, 1)
subcol = col.split(percentage=0.2).column()
@ -1813,18 +1813,18 @@ class WM_OT_keyitem_add(bpy.types.Operator):
wm = context.manager
km = context.keymap
kc = wm.default_keyconfig
if km.modal:
km.add_modal_item("", 'A', 'PRESS') # kmi
else:
km.add_item("none", 'A', 'PRESS') # kmi
# clear filter and expand keymap so we can see the newly added item
if kc.filter != '':
kc.filter = ''
km.items_expanded = True
km.children_expanded = True
return {'FINISHED'}

@ -498,14 +498,14 @@ class VIEW3D_PT_tools_brush(PaintPanel):
if not context.particle_edit_object:
col = layout.split().column()
row = col.row()
if context.sculpt_object and brush:
defaulttools = 8
elif context.texture_paint_object and brush:
defaulttools = 4
else:
defaulttools = 2
row.template_list(settings, "brushes", settings, "active_brush_index", rows=2, maxrows=defaulttools)
col.template_ID(settings, "brush", new="brush.add")
@ -539,7 +539,7 @@ class VIEW3D_PT_tools_brush(PaintPanel):
elif context.sculpt_object and brush:
col = layout.column()
col.separator()
row = col.row(align=True)
row.prop(brush, "size", slider=True)
row.prop(brush, "use_size_pressure", toggle=True, text="")
@ -642,7 +642,7 @@ class VIEW3D_PT_tools_brush_tool(PaintPanel):
sculpt = context.sculpt_object
col = layout.column(align=True)
if context.sculpt_object:
col.prop(brush, "sculpt_tool", expand=True)
elif context.texture_paint_object: