diff --git a/render_renderfarmfi.py b/render_renderfarmfi.py index d5319c44c9d42d285fcb9b163c210d16e6863f45..e4bd8cf2ec33fa09270c31c151df9b2560f965eb 100644 --- a/render_renderfarmfi.py +++ b/render_renderfarmfi.py @@ -21,8 +21,8 @@ DEV = False bl_info = { "name": "Renderfarm.fi", "author": "Nathan Letwory <nathan@letworyinteractive.com>, Jesse Kaukonen <jesse.kaukonen@gmail.com>", - "version": (15,), - "blender": (2, 6, 1), + "version": (16,), + "blender": (2, 6, 2), "location": "Render > Engine > Renderfarm.fi", "description": "Send .blend as session to http://www.renderfarm.fi to render", "warning": "", @@ -85,6 +85,7 @@ bpy.originalFileName = bpy.path.display_name_from_filepath(bpy.data.filepath) bpy.particleBakeWarning = False bpy.childParticleWarning = False bpy.simulationWarning = False +bpy.file_format_warning = False bpy.ready = False if False and DEV: @@ -123,6 +124,9 @@ class ORESettings(bpy.types.PropertyGroup): longdesc = StringProperty(name='Description', description='Description of the scene (2k)', maxlen=2048, default='') title = StringProperty(name='Title', description='Title for this session (128 characters)', maxlen=128, default='') url = StringProperty(name='Project URL', description='Project URL. Leave empty if not applicable', maxlen=256, default='') + engine = StringProperty(name='Engine', description='The rendering engine that is used for rendering', maxlen=64, default='blender') + samples = IntProperty(name='Samples', description='Number of samples that is used (Cycles only)', min=1, max=1000000, soft_min=1, soft_max=100000, default=100) + file_format = StringProperty(name='File format', description='File format used for the rendering', maxlen=20, default='PNG_FORMAT') parts = IntProperty(name='Parts/Frame', description='', min=1, max=1000, soft_min=1, soft_max=64, default=1) resox = IntProperty(name='Resolution X', description='X of render', min=1, max=10000, soft_min=1, soft_max=10000, default=1920) @@ -130,7 +134,7 @@ class ORESettings(bpy.types.PropertyGroup): memusage = IntProperty(name='Memory Usage', description='Estimated maximum memory usage during rendering in MB', min=1, max=6*1024, soft_min=1, soft_max=3*1024, default=256) start = IntProperty(name='Start Frame', description='Start Frame', default=1) end = IntProperty(name='End Frame', description='End Frame', default=250) - fps = IntProperty(name='FPS', description='FPS', min=1, max=256, default=25) + fps = IntProperty(name='FPS', description='FPS', min=1, max=120, default=25) prepared = BoolProperty(name='Prepared', description='Set to True if preparation has been run', default=False) loginInserted = BoolProperty(name='LoginInserted', description='Set to True if user has logged in', default=False) @@ -139,8 +143,8 @@ class ORESettings(bpy.types.PropertyGroup): selected_session = IntProperty(name='Selected Session', description='The selected session', default=0) hasUnsupportedSimulation = BoolProperty(name='HasSimulation', description='Set to True if therea re unsupported simulations', default=False) - inlicense = EnumProperty(items=licenses, name='source license', description='license speficied for the source files', default='1') - outlicense = EnumProperty(items=licenses, name='output license', description='license speficied for the output files', default='1') + inlicense = EnumProperty(items=licenses, name='Scene license', description='License speficied for the source files', default='1') + outlicense = EnumProperty(items=licenses, name='Product license', description='License speficied for the output files', default='1') sessions = CollectionProperty(type=ORESession, name='Sessions', description='Sessions on Renderfarm.fi') completed_sessions = CollectionProperty(type=ORESession, name='Completed sessions', description='Sessions that have been already rendered') rejected_sessions = CollectionProperty(type=ORESession, name='Rejected sessions', description='Sessions that have been rejected') @@ -244,6 +248,31 @@ def changeSettings(): ore.end = sce.frame_end ore.fps = rd.fps + bpy.file_format_warning = False + bpy.simulationWarning = False + bpy.texturePackError = False + bpy.particleBakeWarning = False + bpy.childParticleWarning = False + + if (rd.image_settings.file_format == 'HDR'): + rd.image_settings.file_format = 'PNG' + bpy.file_format_warning = True + + # Convert between Blender's image format and BURP's formats + if (rd.image_settings.file_format == 'PNG'): + ore.file_format = 'PNG_FORMAT' + elif (rd.image_settings.file_format == 'OPEN_EXR'): + ore.file_format = 'EXR_FORMAT' + elif (rd.image_settings.file_format == 'OPEN_EXR_MULTILAYER'): + ore.file_format = 'EXR_MULTILAYER_FORMAT' + elif (rd.image_settings.file_format == 'HDR'): + ore.file_format = 'PNG_FORMAT' + else: + ore.file_format = 'PNG_FORMAT' + + if (ore.engine == 'cycles'): + ore.samples = bpy.context.scene.cycles.samples + # Multipart support doesn' work if SSS is used if ((rd.use_sss == True and hasSSSMaterial()) and ore.parts > 1): ore.parts = 1; @@ -266,8 +295,13 @@ def prepareScene(): changeSettings() + ore.resox = rd.resolution_x + ore.resoy = rd.resolution_y + ore.fps = rd.fps + ore.start = sce.frame_start + ore.end = sce.frame_end + print("Packing external textures...") - # Pack all external textures try: bpy.ops.file.pack_all() bpy.texturePackError = False @@ -315,20 +349,34 @@ class OpSwitchRenderfarm(bpy.types.Operator): def execute(self, context): changeSettings() + if (bpy.context.scene.render.engine == 'CYCLES'): + bpy.context.scene.ore_render.engine = 'cycles' + else: + bpy.context.scene.ore_render.engine = 'blender' bpy.context.scene.render.engine = 'RENDERFARMFI_RENDER' return {'FINISHED'} class OpSwitchBlenderRender(bpy.types.Operator): - bl_label = "Switch to Blender Render" - bl_idname = "ore.switch_to_blender_render" + bl_label = "Switch to local render" + bl_idname = "ore.switch_to_local_render" def execute(self, context): - bpy.context.scene.render.engine = 'BLENDER_RENDER' - return {'FINISHED'} + rd = bpy.context.scene.render + ore = bpy.context.scene.ore_render + rd.resolution_x = ore.resox + rd.resolution_y = ore.resoy + rd.fps = ore.fps + bpy.context.scene.frame_start = ore.start + bpy.context.scene.frame_end = ore.end + if (bpy.context.scene.ore_render.engine == 'cycles'): + bpy.context.scene.render.engine = 'CYCLES' + else: + bpy.context.scene.render.engine = 'BLENDER_RENDER' + return {'FINISHED'} # Copies start & end frame + others from render settings to ore settings class OpCopySettings(bpy.types.Operator): - bl_label = "Copy from Blender Render settings" + bl_label = "Copy settings from current scene" bl_idname = "ore.copy_settings" def execute(self, context): @@ -342,31 +390,6 @@ class OpCopySettings(bpy.types.Operator): ore.fps = rd.fps return {'FINISHED'} -# We re-write the default render panel (not enabled, breaks Cycles) -'''class RENDER_PT_render(RenderButtonsPanel, bpy.types.Panel): - bl_label = "Render" - COMPAT_ENGINES = {'BLENDER_RENDER'} - - def draw(self, context): - layout = self.layout - rd = context.scene.render - row = layout.row() - row.operator("ore.switch_to_renderfarm_render", text="Renderfarm.fi", icon='WORLD') - row.operator("ore.switch_to_blender_render", text="Blender Render", icon='BLENDER') - row = layout.row() - if (bpy.context.scene.render.engine == 'BLENDER_RENDER'): - row.operator("render.render", text="Image", icon='RENDER_STILL') - row.operator("render.render", text="Animation", icon='RENDER_ANIMATION').animation = True - layout.prop(rd, "display_mode", text="Display") - else: - if bpy.found_newer_version == True: - layout.operator('ore.open_download_location') - else: - if bpy.up_to_date == True: - layout.label(text='You have the latest version') - layout.operator('ore.check_update') -''' - class EngineSelectPanel(bpy.types.Panel): bl_idname = "OBJECT_PT_engineSelectPanel" bl_label = "Choose rendering mode" @@ -379,7 +402,7 @@ class EngineSelectPanel(bpy.types.Panel): rd = context.scene.render row = layout.row() row.operator("ore.switch_to_renderfarm_render", text="Renderfarm.fi", icon='WORLD') - row.operator("ore.switch_to_blender_render", text="Blender Render", icon='BLENDER') + row.operator("ore.switch_to_local_render", text="Local computer", icon='BLENDER') row = layout.row() if (bpy.context.scene.render.engine == 'RENDERFARMFI_RENDER'): if bpy.found_newer_version == True: @@ -489,6 +512,50 @@ class RENDER_PT_RenderfarmFi(RenderButtonsPanel, bpy.types.Panel): layout.label(text="Example: blue skies hero castle flowers grass particles") layout.prop(ore, 'url') layout.label(text="Example: www.sintel.org") + + layout.label(text="Please verify your settings", icon='MODIFIER') + row = layout.row() + #row.operator('ore.copy_settings') + #row = layout.row() + + layout.label(text="Rendering engine") + row = layout.row() + if (ore.engine == 'blender'): + row.operator('ore.use_blender_render', icon='FILE_TICK') + row.operator('ore.use_cycles_render') + elif (ore.engine == 'cycles' ): + row.operator('ore.use_blender_render') + row.operator('ore.use_cycles_render', icon='FILE_TICK') + else: + row.operator('ore.use_blender_render', icon='FILE_TICK') + row.operator('ore.use_cycles_render') + + row = layout.row() + + layout.separator() + row = layout.row() + row.prop(ore, 'resox') + row.prop(ore, 'resoy') + row = layout.row() + row.prop(ore, 'start') + row.prop(ore, 'end') + row = layout.row() + row.prop(ore, 'fps') + row = layout.row() + if (ore.engine == 'cycles'): + row.prop(ore, 'samples') + row = layout.row() + row.prop(ore, 'memusage') + #row.prop(ore, 'parts') + layout.separator() + row = layout.row() + + layout.label(text="Licenses", icon='FILE_REFRESH') + row = layout.row() + row.prop(ore, 'inlicense') + row = layout.row() + row.prop(ore, 'outlicense') + checkStatus(ore) if (len(bpy.errors) > 0): bpy.ready = False @@ -496,7 +563,7 @@ class RENDER_PT_RenderfarmFi(RenderButtonsPanel, bpy.types.Panel): bpy.ready = True class UPLOAD_PT_RenderfarmFi(RenderButtonsPanel, bpy.types.Panel): - bl_label = "Upload" + bl_label = "Upload to www.renderfarm.fi" COMPAT_ENGINES = set(['RENDERFARMFI_RENDER']) @classmethod @@ -525,48 +592,24 @@ class UPLOAD_PT_RenderfarmFi(RenderButtonsPanel, bpy.types.Panel): layout.separator() - layout.label(text="Please verify your settings", icon='MODIFIER') - row = layout.row() - row.operator('ore.copy_settings') - row = layout.row() - row.label(text="Resolution: " + str(ore.resox) + "x" + str(ore.resoy)) - row = layout.row() - row.label(text="Frames: " + str(ore.start) + " - " + str(ore.end)) - row = layout.row() - if (ore.start == ore.end): - row.label(text="You have selected only 1 frame to be rendered", icon='ERROR') - row = layout.row() - row.label(text="Renderfarm.fi does not render stills - only animations") - row = layout.row() - row.label(text="Frame rate: " + str(ore.fps)) - row = layout.row() - - layout.separator() - - layout.label(text="Optional advanced settings", icon='MODIFIER') - row = layout.row() - row.prop(ore, 'memusage') - #row.prop(ore, 'parts') - layout.separator() - row = layout.row() - - layout.label(text="Licenses", icon='FILE_REFRESH') - row = layout.row() - row.prop(ore, 'inlicense') - row.prop(ore, 'outlicense') - row = layout.row() if (bpy.uploadInProgress == True): - layout.label(text="Attempting upload...") + layout.label(text="------------------------") + layout.label(text="- Attempting upload... -") + layout.label(text="------------------------") + if (bpy.file_format_warning == True): + layout.label(text="Your output format is HDR", icon='ERROR') + layout.label(text="Right now we don't support this file format") + layout.label(text="File format will be changed to PNG") if (bpy.texturePackError): layout.label(text="There was an error in packing external textures", icon='ERROR') layout.label(text="Make sure that all your textures exist on your computer") layout.label(text="The render will still work, but won't have the missing textures") - layout.label(text="You may want to cancel your render above") + layout.label(text="You may want to cancel your render above in \"My sessions\"") if (bpy.linkedFileError): layout.label(text="There was an error in appending linked .blend files", icon='ERROR') layout.label(text="Your render might not have all the external content") - layout.label(text="You may want to cancel your render above") + layout.label(text="You may want to cancel your render above in \"My sessions\"") if (bpy.particleBakeWarning): layout.label(text="You have a particle simulation", icon='ERROR') layout.label(text="All Emitter type particles must be baked") @@ -585,7 +628,8 @@ class UPLOAD_PT_RenderfarmFi(RenderButtonsPanel, bpy.types.Panel): if (errorTime > 4): bpy.infoError = False bpy.errorStartTime = -1 - layout.label(text="Blender may seem frozen during the upload!", icon='LAMP') + layout.label(text="Warning:", icon='LAMP') + layout.label(text="Blender may seem frozen during the upload!") row.operator('ore.reset', icon='FILE_REFRESH') else: layout.label(text="Fill the scene information first") @@ -608,10 +652,16 @@ def encode_multipart_data(data, files): def encode_file(field_name): filename = files [field_name] + fcontent = None + print('encoding', field_name) + try: + fcontent = str(open(filename, 'rb').read(), encoding='iso-8859-1') + except Exception: + print('Trouble in paradise') return ('--' + boundary, 'Content-Disposition: form-data; name="%s"; filename="%s"' % (field_name, filename), 'Content-Type: %s' % get_content_type(filename), - '', str(open(filename, 'rb').read(), encoding='iso-8859-1')) + '', fcontent) lines = [] for name in data: @@ -619,10 +669,13 @@ def encode_multipart_data(data, files): for name in files: lines.extend(encode_file(name)) lines.extend(('--%s--' % boundary, '')) + print("joining lines into body") body = '\r\n'.join(lines) headers = {'content-type': 'multipart/form-data; boundary=' + boundary, 'content-length': str(len(body))} + + print("headers and body ready") return body, headers @@ -686,10 +739,10 @@ def ore_upload(op, context): key = res['key'] userid = res['userId'] print("Creating server proxy") - proxy = xmlrpc.client.ServerProxy(rffi_xmlrpc, verbose=DEV) + proxy = xmlrpc.client.ServerProxy(rffi_xmlrpc, verbose=DEV) #r'http://xmlrpc.renderfarm.fi/session') proxy._ServerProxy__transport.user_agent = 'Renderfarm.fi Uploader/%s' % (bpy.CURRENT_VERSION) print("Creating a new session") - res = proxy.session.createSession(userid, key) + res = proxy.session.createSession(userid, key) # This may use an existing, non-rendered session. Prevents spamming in case the upload fails for some reason sessionid = res['sessionId'] key = res['key'] print("Session id is " + str(sessionid)) @@ -709,7 +762,13 @@ def ore_upload(op, context): res = proxy.session.setXSize(userid, res['key'], sessionid, ore.resox) res = proxy.session.setYSize(userid, res['key'], sessionid, ore.resoy) res = proxy.session.setFrameRate(userid, res['key'], sessionid, ore.fps) - res = proxy.session.setRenderer(userid, res['key'], sessionid, 'blender') + res = proxy.session.setFrameFormat(userid, res['key'], sessionid, ore.file_format) + res = proxy.session.setRenderer(userid, res['key'], sessionid, ore.engine) + res = proxy.session.setSamples(userid, res['key'], sessionid, ore.samples) + if (ore.engine == 'cycles'): + res = proxy.session.setReplication(userid, res['key'], sessionid, 1) + else: + res = proxy.session.setReplication(userid, res['key'], sessionid, 3) res = proxy.session.setOutputLicense(userid, res['key'], sessionid, int(ore.outlicense)) res = proxy.session.setInputLicense(userid, res['key'], sessionid, int(ore.inlicense)) print("Setting primary input file") @@ -1087,6 +1146,22 @@ class ORE_UseBlenderReso(bpy.types.Operator): ore.fps = rd.fps return {'FINISHED'} + +class ORE_UseCyclesRender(bpy.types.Operator): + bl_idname = "ore.use_cycles_render" + bl_label = "Cycles" + + def execute(self, context): + context.scene.ore_render.engine = 'cycles' + return {'FINISHED'} + +class ORE_UseBlenderRender(bpy.types.Operator): + bl_idname = "ore.use_blender_render" + bl_label = "Blender Internal" + + def execute(self, context): + context.scene.ore_render.engine = 'blender' + return {'FINISHED'} class ORE_ChangeUser(bpy.types.Operator): bl_idname = "ore.change_user"