c60b10c484a27dd985aba8673ca3975ab76f85aa
[blender.git] / release / scripts / io / netrender / ui.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
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.
7 #
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.
12 #
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.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 import bpy
20 import sys, os
21 import http, http.client, http.server, urllib
22 import subprocess, shutil, time, hashlib
23
24 import netrender
25 import netrender.slave as slave
26 import netrender.master as master
27
28 from netrender.utils import *
29
30 VERSION = b"0.3"
31
32 PATH_PREFIX = "/tmp/"
33
34 QUEUED = 0
35 DISPATCHED = 1
36 DONE = 2
37 ERROR = 3
38
39 def init_file():
40     if netrender.init_file != bpy.data.filepath:
41         netrender.init_file = bpy.data.filepath
42         netrender.init_data = True
43         netrender.init_address = True
44
45 def init_data(netsettings):
46     init_file()
47
48     if netrender.init_data:
49         netrender.init_data = False
50
51         netsettings.active_slave_index = 0
52         while(len(netsettings.slaves) > 0):
53             netsettings.slaves.remove(0)
54
55         netsettings.active_blacklisted_slave_index = 0
56         while(len(netsettings.slaves_blacklist) > 0):
57             netsettings.slaves_blacklist.remove(0)
58
59         netsettings.active_job_index = 0
60         while(len(netsettings.jobs) > 0):
61             netsettings.jobs.remove(0)
62
63 def verify_address(netsettings):
64     init_file()
65
66     if netrender.init_address:
67         netrender.init_address = False
68
69         try:
70             conn = clientConnection(netsettings.server_address, netsettings.server_port, scan = False)
71         except:
72             conn = None
73
74         if conn:
75             conn.close()
76         else:
77             netsettings.server_address = "[default]"
78
79 class RenderButtonsPanel():
80     bl_space_type = "PROPERTIES"
81     bl_region_type = "WINDOW"
82     bl_context = "render"
83     # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
84
85     def poll(self, context):
86         rd = context.scene.render
87         return (rd.use_game_engine==False) and (rd.engine in self.COMPAT_ENGINES)
88
89 # Setting panel, use in the scene for now.
90 @rnaType
91 class RENDER_PT_network_settings(bpy.types.Panel, RenderButtonsPanel):
92     bl_label = "Network Settings"
93     COMPAT_ENGINES = {'NET_RENDER'}
94
95     def draw(self, context):
96         layout = self.layout
97
98         scene = context.scene
99         netsettings = scene.network_render
100
101         verify_address(netsettings)
102
103         layout.prop(netsettings, "mode", expand=True)
104
105         if netsettings.mode in ("RENDER_MASTER", "RENDER_SLAVE"):
106             layout.operator("render.netclientstart", icon='PLAY')
107
108         layout.prop(netsettings, "path")
109
110         split = layout.split(percentage=0.7)
111
112         col = split.column()
113         col.label(text="Server Adress:")
114         col.prop(netsettings, "server_address", text="")
115
116         col = split.column()
117         col.label(text="Port:")
118         col.prop(netsettings, "server_port", text="")
119
120         if netsettings.mode != "RENDER_MASTER":
121             layout.operator("render.netclientscan", icon='FILE_REFRESH', text="")
122
123         layout.operator("render.netclientweb", icon='QUESTION')
124
125 @rnaType
126 class RENDER_PT_network_slave_settings(bpy.types.Panel, RenderButtonsPanel):
127     bl_label = "Slave Settings"
128     COMPAT_ENGINES = {'NET_RENDER'}
129
130     def poll(self, context):
131         scene = context.scene
132         return (super().poll(context)
133                 and scene.network_render.mode == "RENDER_SLAVE")
134
135     def draw(self, context):
136         layout = self.layout
137
138         scene = context.scene
139         rd = scene.render
140         netsettings = scene.network_render
141
142         layout.prop(netsettings, "slave_clear")
143         layout.prop(netsettings, "slave_thumb")
144         layout.prop(netsettings, "slave_outputlog")
145         layout.label(text="Threads:")
146         layout.prop(rd, "threads_mode", expand=True)
147         sub = layout.column()
148         sub.enabled = rd.threads_mode == 'FIXED'
149         sub.prop(rd, "threads")
150 @rnaType
151 class RENDER_PT_network_master_settings(bpy.types.Panel, RenderButtonsPanel):
152     bl_label = "Master Settings"
153     COMPAT_ENGINES = {'NET_RENDER'}
154
155     def poll(self, context):
156         scene = context.scene
157         return (super().poll(context)
158                 and scene.network_render.mode == "RENDER_MASTER")
159
160     def draw(self, context):
161         layout = self.layout
162
163         scene = context.scene
164         netsettings = scene.network_render
165
166         layout.prop(netsettings, "master_broadcast")
167         layout.prop(netsettings, "master_clear")
168
169 @rnaType
170 class RENDER_PT_network_job(bpy.types.Panel, RenderButtonsPanel):
171     bl_label = "Job Settings"
172     COMPAT_ENGINES = {'NET_RENDER'}
173
174     def poll(self, context):
175         scene = context.scene
176         return (super().poll(context)
177                 and scene.network_render.mode == "RENDER_CLIENT")
178
179     def draw(self, context):
180         layout = self.layout
181
182         scene = context.scene
183         netsettings = scene.network_render
184
185         verify_address(netsettings)
186
187         if netsettings.server_address != "[default]":
188             layout.operator("render.netclientanim", icon='RENDER_ANIMATION')
189             layout.operator("render.netclientsend", icon='FILE_BLEND')
190             layout.operator("render.netclientsendframe", icon='RENDER_STILL')
191             if netsettings.job_id:
192                 row = layout.row()
193                 row.operator("render.render", text="Get Image", icon='RENDER_STILL')
194                 row.operator("render.render", text="Get Animation", icon='RENDER_ANIMATION').animation = True
195
196         split = layout.split(percentage=0.3)
197
198         col = split.column()
199         col.label(text="Name:")
200         col.label(text="Category:")
201
202         col = split.column()
203         col.prop(netsettings, "job_name", text="")
204         col.prop(netsettings, "job_category", text="")
205
206         row = layout.row()
207         row.prop(netsettings, "priority")
208         row.prop(netsettings, "chunks")
209
210 @rnaType
211 class RENDER_PT_network_slaves(bpy.types.Panel, RenderButtonsPanel):
212     bl_label = "Slaves Status"
213     COMPAT_ENGINES = {'NET_RENDER'}
214
215     def poll(self, context):
216         scene = context.scene
217         netsettings = scene.network_render
218         if netsettings.mode != "RENDER_CLIENT":
219             return False
220         verify_address(netsettings)
221         return (super().poll(context)
222                 and netsettings.server_address != "[default]")
223
224     def draw(self, context):
225         layout = self.layout
226
227         scene = context.scene
228         netsettings = scene.network_render
229
230         row = layout.row()
231         row.template_list(netsettings, "slaves", netsettings, "active_slave_index", rows=2)
232
233         sub = row.column(align=True)
234         sub.operator("render.netclientslaves", icon='FILE_REFRESH', text="")
235         sub.operator("render.netclientblacklistslave", icon='ZOOMOUT', text="")
236
237         init_data(netsettings)
238
239         if netsettings.active_slave_index >= 0 and len(netsettings.slaves) > 0:
240             layout.separator()
241
242             slave = netrender.slaves[netsettings.active_slave_index]
243
244             layout.label(text="Name: " + slave.name)
245             layout.label(text="Address: " + slave.address[0])
246             layout.label(text="Seen: " + time.ctime(slave.last_seen))
247             layout.label(text="Stats: " + slave.stats)
248
249 @rnaType
250 class RENDER_PT_network_slaves_blacklist(bpy.types.Panel, RenderButtonsPanel):
251     bl_label = "Slaves Blacklist"
252     COMPAT_ENGINES = {'NET_RENDER'}
253
254     def poll(self, context):
255         scene = context.scene
256         netsettings = scene.network_render
257         if netsettings.mode != "RENDER_CLIENT":
258             return False
259         verify_address(netsettings)
260         return (super().poll(context)
261                 and netsettings.server_address != "[default]")
262
263     def draw(self, context):
264         layout = self.layout
265
266         scene = context.scene
267         netsettings = scene.network_render
268
269         row = layout.row()
270         row.template_list(netsettings, "slaves_blacklist", netsettings, "active_blacklisted_slave_index", rows=2)
271
272         sub = row.column(align=True)
273         sub.operator("render.netclientwhitelistslave", icon='ZOOMOUT', text="")
274
275         init_data(netsettings)
276
277         if netsettings.active_blacklisted_slave_index >= 0 and len(netsettings.slaves_blacklist) > 0:
278             layout.separator()
279
280             slave = netrender.blacklist[netsettings.active_blacklisted_slave_index]
281
282             layout.label(text="Name: " + slave.name)
283             layout.label(text="Address: " + slave.address[0])
284             layout.label(text="Seen: " + time.ctime(slave.last_seen))
285             layout.label(text="Stats: " + slave.stats)
286
287 @rnaType
288 class RENDER_PT_network_jobs(bpy.types.Panel, RenderButtonsPanel):
289     bl_label = "Jobs"
290     COMPAT_ENGINES = {'NET_RENDER'}
291
292     def poll(self, context):
293         scene = context.scene
294         netsettings = scene.network_render
295         if netsettings.mode != "RENDER_CLIENT":
296             return False
297         verify_address(netsettings)
298         return (super().poll(context)
299                 and netsettings.server_address != "[default]")
300
301     def draw(self, context):
302         layout = self.layout
303
304         scene = context.scene
305         netsettings = scene.network_render
306
307         row = layout.row()
308         row.template_list(netsettings, "jobs", netsettings, "active_job_index", rows=2)
309
310         sub = row.column(align=True)
311         sub.operator("render.netclientstatus", icon='FILE_REFRESH', text="")
312         sub.operator("render.netclientcancel", icon='ZOOMOUT', text="")
313         sub.operator("render.netclientcancelall", icon='PANEL_CLOSE', text="")
314         sub.operator("render.netclientdownload", icon='RENDER_ANIMATION', text="")
315
316         init_data(netsettings)
317
318         if netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0:
319             layout.separator()
320
321             job = netrender.jobs[netsettings.active_job_index]
322
323             layout.label(text="Name: %s" % job.name)
324             layout.label(text="Length: %04i" % len(job))
325             layout.label(text="Done: %04i" % job.results[DONE])
326             layout.label(text="Error: %04i" % job.results[ERROR])
327
328 @rnaType
329 class NetRenderSettings(bpy.types.IDPropertyGroup):
330     pass
331
332 @rnaType
333 class NetRenderSlave(bpy.types.IDPropertyGroup):
334     pass
335
336 @rnaType
337 class NetRenderJob(bpy.types.IDPropertyGroup):
338     pass
339
340 bpy.types.Scene.PointerProperty(attr="network_render", type=NetRenderSettings, name="Network Render", description="Network Render Settings")
341
342 NetRenderSettings.StringProperty( attr="server_address",
343                 name="Server address",
344                 description="IP or name of the master render server",
345                 maxlen = 128,
346                 default = "[default]")
347
348 NetRenderSettings.IntProperty( attr="server_port",
349                 name="Server port",
350                 description="port of the master render server",
351                 default = 8000,
352                 min=1,
353                 max=65535)
354
355 NetRenderSettings.BoolProperty( attr="master_broadcast",
356                 name="Broadcast",
357                 description="broadcast master server address on local network",
358                 default = True)
359
360 NetRenderSettings.BoolProperty( attr="slave_clear",
361                 name="Clear on exit",
362                 description="delete downloaded files on exit",
363                 default = True)
364
365 NetRenderSettings.BoolProperty( attr="slave_thumb",
366                 name="Generate thumbnails",
367                 description="Generate thumbnails on slaves instead of master",
368                 default = False)
369
370 NetRenderSettings.BoolProperty( attr="slave_outputlog",
371                 name="Output render log on console",
372                 description="Output render text log to console as well as sending it to the master",
373                 default = True)
374
375 NetRenderSettings.BoolProperty( attr="master_clear",
376                 name="Clear on exit",
377                 description="delete saved files on exit",
378                 default = False)
379
380 default_path = os.environ.get("TEMP")
381
382 if not default_path:
383     if os.name == 'nt':
384         default_path = "c:/tmp/"
385     else:
386         default_path = "/tmp/"
387 elif not default_path.endswith(os.sep):
388     default_path += os.sep
389
390 NetRenderSettings.StringProperty( attr="path",
391                 name="Path",
392                 description="Path for temporary files",
393                 maxlen = 128,
394                 default = default_path,
395                 subtype='FILE_PATH')
396
397 NetRenderSettings.StringProperty( attr="job_name",
398                 name="Job name",
399                 description="Name of the job",
400                 maxlen = 128,
401                 default = "[default]")
402
403 NetRenderSettings.StringProperty( attr="job_category",
404                 name="Job category",
405                 description="Category of the job",
406                 maxlen = 128,
407                 default = "")
408
409 NetRenderSettings.IntProperty( attr="chunks",
410                 name="Chunks",
411                 description="Number of frame to dispatch to each slave in one chunk",
412                 default = 5,
413                 min=1,
414                 max=65535)
415
416 NetRenderSettings.IntProperty( attr="priority",
417                 name="Priority",
418                 description="Priority of the job",
419                 default = 1,
420                 min=1,
421                 max=10)
422
423 NetRenderSettings.StringProperty( attr="job_id",
424                 name="Network job id",
425                 description="id of the last sent render job",
426                 maxlen = 64,
427                 default = "")
428
429 NetRenderSettings.IntProperty( attr="active_slave_index",
430                 name="Index of the active slave",
431                 description="",
432                 default = -1,
433                 min= -1,
434                 max=65535)
435
436 NetRenderSettings.IntProperty( attr="active_blacklisted_slave_index",
437                 name="Index of the active slave",
438                 description="",
439                 default = -1,
440                 min= -1,
441                 max=65535)
442
443 NetRenderSettings.IntProperty( attr="active_job_index",
444                 name="Index of the active job",
445                 description="",
446                 default = -1,
447                 min= -1,
448                 max=65535)
449
450 NetRenderSettings.EnumProperty(attr="mode",
451                         items=(
452                                         ("RENDER_CLIENT", "Client", "Act as render client"),
453                                         ("RENDER_MASTER", "Master", "Act as render master"),
454                                         ("RENDER_SLAVE", "Slave", "Act as render slave"),
455                                     ),
456                         name="Network mode",
457                         description="Mode of operation of this instance",
458                         default="RENDER_CLIENT")
459
460 NetRenderSettings.CollectionProperty(attr="slaves", type=NetRenderSlave, name="Slaves", description="")
461 NetRenderSettings.CollectionProperty(attr="slaves_blacklist", type=NetRenderSlave, name="Slaves Blacklist", description="")
462 NetRenderSettings.CollectionProperty(attr="jobs", type=NetRenderJob, name="Job List", description="")
463
464 NetRenderSlave.StringProperty( attr="name",
465                 name="Name of the slave",
466                 description="",
467                 maxlen = 64,
468                 default = "")
469
470 NetRenderJob.StringProperty( attr="name",
471                 name="Name of the job",
472                 description="",
473                 maxlen = 128,
474                 default = "")