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