1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
25 from netrender
.utils
import *
27 from bpy
.props
import PointerProperty
, StringProperty
, BoolProperty
, EnumProperty
, IntProperty
, CollectionProperty
34 ADDRESS_TEST_TIMEOUT
= 30
36 def base_poll(cls
, context
):
37 rd
= context
.scene
.render
38 return (rd
.use_game_engine
==False) and (rd
.engine
in cls
.COMPAT_ENGINES
)
42 if netrender
.init_file
!= bpy
.data
.filepath
:
43 netrender
.init_file
= bpy
.data
.filepath
44 netrender
.init_data
= True
45 netrender
.valid_address
= False
47 def init_data(netsettings
):
50 if netrender
.init_data
:
51 netrender
.init_data
= False
53 netsettings
.active_slave_index
= 0
54 while(len(netsettings
.slaves
) > 0):
55 netsettings
.slaves
.remove(0)
57 netsettings
.active_blacklisted_slave_index
= 0
58 while(len(netsettings
.slaves_blacklist
) > 0):
59 netsettings
.slaves_blacklist
.remove(0)
61 netsettings
.active_job_index
= 0
62 while(len(netsettings
.jobs
) > 0):
63 netsettings
.jobs
.remove(0)
65 def verify_address(netsettings
, force
=False):
66 global LAST_ADDRESS_TEST
69 if force
or LAST_ADDRESS_TEST
+ ADDRESS_TEST_TIMEOUT
< time
.time():
70 LAST_ADDRESS_TEST
= time
.time()
73 conn
= clientConnection(netsettings
, scan
= False, timeout
= 1)
78 netrender
.valid_address
= True
81 netrender
.valid_address
= False
83 return netrender
.valid_address
85 class NeedValidAddress():
87 def poll(cls
, context
):
88 return super().poll(context
) and verify_address(context
.scene
.network_render
)
90 class NetRenderButtonsPanel():
91 bl_space_type
= "PROPERTIES"
92 bl_region_type
= "WINDOW"
94 # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
97 def poll(cls
, context
):
98 rd
= context
.scene
.render
99 return rd
.engine
== 'NET_RENDER' and rd
.use_game_engine
== False
101 # Setting panel, use in the scene for now.
102 class RENDER_PT_network_settings(NetRenderButtonsPanel
, bpy
.types
.Panel
):
103 bl_label
= "Network Settings"
104 COMPAT_ENGINES
= {'NET_RENDER'}
107 def poll(cls
, context
):
108 return super().poll(context
)
110 def draw(self
, context
):
113 netsettings
= context
.scene
.network_render
115 verify_address(netsettings
)
117 layout
.prop(netsettings
, "mode", expand
=True)
119 if netsettings
.mode
in {'RENDER_MASTER', 'RENDER_SLAVE'}:
120 layout
.operator("render.netclientstart", icon
='PLAY')
122 layout
.prop(netsettings
, "path")
126 split
= layout
.split(percentage
=0.5)
129 col
.prop(netsettings
, "server_address", text
="Address")
133 row
.prop(netsettings
, "server_port", text
="Port")
134 row
.prop(netsettings
, "use_ssl", text
="SSL")
136 if netsettings
.mode
!= "RENDER_MASTER":
137 layout
.operator("render.netclientscan", icon
='FILE_REFRESH', text
="")
139 if not netrender
.valid_address
:
140 layout
.label(text
="No master at specified address")
143 if netsettings
.use_ssl
and netsettings
.mode
== "RENDER_MASTER":
144 layout
.prop(netsettings
, "cert_path", text
="Certificate")
145 layout
.prop(netsettings
, "key_path", text
="Key")
147 layout
.operator("render.netclientweb", icon
='QUESTION')
151 class RENDER_PT_network_slave_settings(NetRenderButtonsPanel
, bpy
.types
.Panel
):
152 bl_label
= "Slave Settings"
153 COMPAT_ENGINES
= {'NET_RENDER'}
156 def poll(cls
, context
):
157 scene
= context
.scene
158 return super().poll(context
) and scene
.network_render
.mode
== "RENDER_SLAVE"
160 def draw(self
, context
):
163 rd
= context
.scene
.render
164 netsettings
= context
.scene
.network_render
166 layout
.prop(netsettings
, "slave_tags", text
="Tags")
167 layout
.prop(netsettings
, "slave_render")
168 layout
.prop(netsettings
, "slave_bake")
169 layout
.prop(netsettings
, "use_slave_clear")
170 layout
.prop(netsettings
, "use_slave_thumb")
171 layout
.prop(netsettings
, "use_slave_output_log")
172 layout
.label(text
="Threads:")
173 layout
.prop(rd
, "threads_mode", expand
=True)
175 col
= layout
.column()
176 col
.enabled
= rd
.threads_mode
== 'FIXED'
177 col
.prop(rd
, "threads")
179 class RENDER_PT_network_master_settings(NetRenderButtonsPanel
, bpy
.types
.Panel
):
180 bl_label
= "Master Settings"
181 COMPAT_ENGINES
= {'NET_RENDER'}
184 def poll(cls
, context
):
185 scene
= context
.scene
186 return super().poll(context
) and scene
.network_render
.mode
== "RENDER_MASTER"
188 def draw(self
, context
):
191 netsettings
= context
.scene
.network_render
193 layout
.prop(netsettings
, "use_master_broadcast")
194 layout
.prop(netsettings
, "use_master_force_upload")
195 layout
.prop(netsettings
, "use_master_clear")
197 class RENDER_PT_network_job(NetRenderButtonsPanel
, bpy
.types
.Panel
):
198 bl_label
= "Job Settings"
199 COMPAT_ENGINES
= {'NET_RENDER'}
202 def poll(cls
, context
):
203 scene
= context
.scene
204 return super().poll(context
) and scene
.network_render
.mode
== "RENDER_CLIENT"
206 def draw(self
, context
):
209 netsettings
= context
.scene
.network_render
211 verify_address(netsettings
)
213 if netsettings
.server_address
!= "[default]":
214 layout
.operator("render.netclientanim", icon
='RENDER_ANIMATION')
215 layout
.operator("render.netclientsend", icon
='FILE_BLEND')
216 layout
.operator("render.netclientsendbake", icon
='PHYSICS')
217 layout
.operator("render.netclientsendframe", icon
='RENDER_STILL')
218 if netsettings
.job_id
:
220 row
.operator("render.render", text
="Get Image", icon
='RENDER_STILL')
221 row
.operator("render.render", text
="Get Animation", icon
='RENDER_ANIMATION').animation
= True
223 layout
.prop(netsettings
, "job_type", text
="Type")
224 layout
.prop(netsettings
, "job_name", text
="Name")
225 layout
.prop(netsettings
, "job_category", text
="Category")
226 layout
.prop(netsettings
, "job_tags", text
="Tags")
227 layout
.prop(netsettings
, "job_render_engine", text
="Engine")
229 if netsettings
.job_render_engine
== "OTHER":
230 layout
.prop(netsettings
, "job_render_engine_other", text
="Other Engine")
233 row
.prop(netsettings
, "priority")
234 row
.prop(netsettings
, "chunks")
236 if netsettings
.job_type
== "JOB_BLENDER":
237 layout
.prop(netsettings
, "save_before_job")
241 class RENDER_PT_network_job_vcs(NetRenderButtonsPanel
, bpy
.types
.Panel
):
242 bl_label
= "VCS Job Settings"
243 COMPAT_ENGINES
= {'NET_RENDER'}
246 def poll(cls
, context
):
247 scene
= context
.scene
248 return (super().poll(context
)
249 and scene
.network_render
.mode
== "RENDER_CLIENT"
250 and scene
.network_render
.job_type
== "JOB_VCS")
252 def draw(self
, context
):
255 netsettings
= context
.scene
.network_render
257 layout
.operator("render.netclientvcsguess", icon
='FILE_REFRESH', text
="")
259 layout
.prop(netsettings
, "vcs_system")
260 layout
.prop(netsettings
, "vcs_revision")
261 layout
.prop(netsettings
, "vcs_rpath")
262 layout
.prop(netsettings
, "vcs_wpath")
264 class RENDER_PT_network_slaves(NeedValidAddress
, NetRenderButtonsPanel
, bpy
.types
.Panel
):
265 bl_label
= "Slaves Status"
266 COMPAT_ENGINES
= {'NET_RENDER'}
269 def poll(cls
, context
):
270 netsettings
= context
.scene
.network_render
271 return super().poll(context
) and netsettings
.mode
== "RENDER_CLIENT"
273 def draw(self
, context
):
276 netsettings
= context
.scene
.network_render
279 row
.template_list("UI_UL_list", "net_render_slaves", netsettings
, "slaves",
280 netsettings
, "active_slave_index", rows
=2)
282 sub
= row
.column(align
=True)
283 sub
.operator("render.netclientslaves", icon
='FILE_REFRESH', text
="")
284 sub
.operator("render.netclientblacklistslave", icon
='ZOOMOUT', text
="")
286 if len(netrender
.slaves
) > netsettings
.active_slave_index
>= 0:
289 slave
= netrender
.slaves
[netsettings
.active_slave_index
]
291 layout
.label(text
="Name: " + slave
.name
)
292 layout
.label(text
="Address: " + slave
.address
[0])
293 layout
.label(text
="Seen: " + time
.ctime(slave
.last_seen
))
294 layout
.label(text
="Stats: " + slave
.stats
)
296 class RENDER_PT_network_slaves_blacklist(NeedValidAddress
, NetRenderButtonsPanel
, bpy
.types
.Panel
):
297 bl_label
= "Slaves Blacklist"
298 COMPAT_ENGINES
= {'NET_RENDER'}
301 def poll(cls
, context
):
302 netsettings
= context
.scene
.network_render
303 return super().poll(context
) and netsettings
.mode
== "RENDER_CLIENT"
305 def draw(self
, context
):
308 netsettings
= context
.scene
.network_render
311 row
.template_list("UI_UL_list", "net_render_slaves_blacklist", netsettings
, "slaves_blacklist",
312 netsettings
, "active_blacklisted_slave_index", rows
=2)
314 sub
= row
.column(align
=True)
315 sub
.operator("render.netclientwhitelistslave", icon
='ZOOMOUT', text
="")
317 if len(netrender
.blacklist
) > netsettings
.active_blacklisted_slave_index
>= 0:
320 slave
= netrender
.blacklist
[netsettings
.active_blacklisted_slave_index
]
322 layout
.label(text
="Name: " + slave
.name
)
323 layout
.label(text
="Address: " + slave
.address
[0])
324 layout
.label(text
="Seen: " + time
.ctime(slave
.last_seen
))
325 layout
.label(text
="Stats: " + slave
.stats
)
327 class RENDER_PT_network_jobs(NeedValidAddress
, NetRenderButtonsPanel
, bpy
.types
.Panel
):
329 COMPAT_ENGINES
= {'NET_RENDER'}
332 def poll(cls
, context
):
333 netsettings
= context
.scene
.network_render
334 return super().poll(context
) and netsettings
.mode
== "RENDER_CLIENT"
336 def draw(self
, context
):
339 netsettings
= context
.scene
.network_render
342 row
.template_list("UI_UL_list", "net_render", netsettings
, "jobs", netsettings
, "active_job_index", rows
=2)
344 sub
= row
.column(align
=True)
345 sub
.operator("render.netclientstatus", icon
='FILE_REFRESH', text
="")
346 sub
.operator("render.netclientcancel", icon
='ZOOMOUT', text
="")
347 sub
.operator("render.netclientcancelall", icon
='PANEL_CLOSE', text
="")
348 sub
.operator("render.netclientdownload", icon
='RENDER_ANIMATION', text
="")
350 if len(netrender
.jobs
) > netsettings
.active_job_index
>= 0:
353 job
= netrender
.jobs
[netsettings
.active_job_index
]
355 layout
.label(text
="Name: %s" % job
.name
)
356 layout
.label(text
="Length: %04i" % len(job
))
357 layout
.label(text
="Done: %04i" % job
.results
[netrender
.model
.FRAME_DONE
])
358 layout
.label(text
="Error: %04i" % job
.results
[netrender
.model
.FRAME_ERROR
])
360 import bl_ui
.properties_render
as properties_render
361 class RENDER_PT_network_output(NeedValidAddress
, NetRenderButtonsPanel
, bpy
.types
.Panel
):
363 COMPAT_ENGINES
= {'NET_RENDER'}
366 def poll(cls
, context
):
367 netsettings
= context
.scene
.network_render
368 return super().poll(context
) and netsettings
.mode
== "RENDER_CLIENT"
370 draw
= properties_render
.RENDER_PT_output
.draw
373 class NetRenderSlave(bpy
.types
.PropertyGroup
):
375 def register(NetRenderSlave
):
377 NetRenderSlave
.name
= StringProperty(
378 name
="Name of the slave",
383 class NetRenderJob(bpy
.types
.PropertyGroup
):
385 def register(NetRenderJob
):
387 NetRenderJob
.name
= StringProperty(
388 name
="Name of the job",
393 class NetRenderSettings(bpy
.types
.PropertyGroup
):
395 def register(NetRenderSettings
):
397 def address_update_callback(self
, context
):
398 netsettings
= context
.scene
.network_render
399 verify_address(netsettings
, True)
401 NetRenderSettings
.server_address
= StringProperty(
402 name
="Server address",
403 description
="IP or name of the master render server",
405 default
= "[default]",
406 update
= address_update_callback
)
408 NetRenderSettings
.server_port
= IntProperty(
410 description
="port of the master render server",
415 NetRenderSettings
.use_master_broadcast
= BoolProperty(
417 description
="broadcast master server address on local network",
419 NetRenderSettings
.use_ssl
= BoolProperty(
421 description
="use ssl encryption for communication",
423 NetRenderSettings
.cert_path
= StringProperty(
425 description
="Path to ssl certifcate",
429 NetRenderSettings
.key_path
= StringProperty(
431 description
="Path to ssl key file",
436 NetRenderSettings
.use_slave_clear
= BoolProperty(
437 name
="Clear on exit",
438 description
="delete downloaded files on exit",
441 NetRenderSettings
.use_slave_thumb
= BoolProperty(
442 name
="Generate thumbnails",
443 description
="Generate thumbnails on slaves instead of master",
446 NetRenderSettings
.slave_tags
= StringProperty(
448 description
="Tags to associate with the slave (semi-colon separated)",
452 NetRenderSettings
.use_slave_output_log
= BoolProperty(
453 name
="Output render log on console",
454 description
="Output render text log to console as well as sending it to the master",
457 NetRenderSettings
.slave_render
= BoolProperty(
458 name
="Render on slave",
459 description
="Use slave for render jobs",
462 NetRenderSettings
.slave_bake
= BoolProperty(
463 name
="Bake on slave",
464 description
="Use slave for baking jobs",
467 NetRenderSettings
.use_master_clear
= BoolProperty(
468 name
="Clear on exit",
469 description
="Delete saved files on exit",
472 NetRenderSettings
.use_master_force_upload
= BoolProperty(
473 name
="Force Dependency Upload",
474 description
="Force client to upload dependency files to master",
477 default_path
= os
.environ
.get("TEMP")
481 default_path
= "c:/tmp/"
483 default_path
= "/tmp/"
484 elif not default_path
.endswith(os
.sep
):
485 default_path
+= os
.sep
487 NetRenderSettings
.path
= StringProperty(
489 description
="Path for temporary files",
491 default
= default_path
,
494 NetRenderSettings
.job_type
= EnumProperty(
496 ("JOB_BLENDER", "Blender", "Standard Blender Job"),
497 ("JOB_PROCESS", "Process", "Custom Process Job"),
498 ("JOB_VCS", "VCS", "Version Control System Managed Job"),
501 description
="Type of render job",
502 default
="JOB_BLENDER")
504 NetRenderSettings
.job_name
= StringProperty(
506 description
="Name of the job",
508 default
= "[default]")
510 NetRenderSettings
.job_category
= StringProperty(
512 description
="Category of the job",
516 NetRenderSettings
.job_tags
= StringProperty(
518 description
="Tags to associate with the job (semi-colon separated)",
522 NetRenderSettings
.job_render_engine
= EnumProperty(
524 ("BLENDER_RENDER", "BLENDER", "Standard Blender Render"),
525 ("CYCLES", "CYCLES", "Cycle Render"),
526 ("OTHER", "OTHER", "Other non-default Render"),
529 description
="Render engine used to render this job",
530 default
="BLENDER_RENDER")
532 NetRenderSettings
.job_render_engine_other
= StringProperty(
533 name
="Render engine",
534 description
="Render engine other than the builtin defaults (POVRAY_RENDER, ...)",
538 NetRenderSettings
.save_before_job
= BoolProperty(
539 name
="Save Before Job",
540 description
="Save current file before sending a job",
543 NetRenderSettings
.chunks
= IntProperty(
545 description
="Number of frame to dispatch to each slave in one chunk",
550 NetRenderSettings
.priority
= IntProperty(
552 description
="Priority of the job",
557 NetRenderSettings
.vcs_wpath
= StringProperty(
559 description
="Path of the local working copy",
563 NetRenderSettings
.vcs_rpath
= StringProperty(
565 description
="Path of the server copy (protocol specific)",
569 NetRenderSettings
.vcs_revision
= StringProperty(
571 description
="Revision for this job",
575 NetRenderSettings
.vcs_system
= EnumProperty(
576 items
= netrender
.versioning
.ITEMS
,
578 description
="Version Control System",
579 default
=netrender
.versioning
.ITEMS
[0][0])
581 NetRenderSettings
.job_id
= StringProperty(
582 name
="Network job id",
583 description
="id of the last sent render job",
587 NetRenderSettings
.active_slave_index
= IntProperty(
588 name
="Index of the active slave",
594 NetRenderSettings
.active_blacklisted_slave_index
= IntProperty(
595 name
="Index of the active slave",
601 NetRenderSettings
.active_job_index
= IntProperty(
602 name
="Index of the active job",
608 NetRenderSettings
.mode
= EnumProperty(
610 ("RENDER_CLIENT", "Client", "Act as render client"),
611 ("RENDER_MASTER", "Master", "Act as render master"),
612 ("RENDER_SLAVE", "Slave", "Act as render slave"),
615 description
="Mode of operation of this instance",
616 default
="RENDER_CLIENT")
618 NetRenderSettings
.slaves
= CollectionProperty(type=NetRenderSlave
, name
="Slaves", description
="")
619 NetRenderSettings
.slaves_blacklist
= CollectionProperty(type=NetRenderSlave
, name
="Slaves Blacklist", description
="")
620 NetRenderSettings
.jobs
= CollectionProperty(type=NetRenderJob
, name
="Job List", description
="")
622 bpy
.types
.Scene
.network_render
= PointerProperty(type=NetRenderSettings
, name
="Network Render", description
="Network Render Settings")
626 del bpy
.types
.Scene
.network_render