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