~siretart/ubuntu/utopic/blender/libav10

« back to all changes in this revision

Viewing changes to release/scripts/io/netrender/client.py

Tags: upstream-2.50~alpha~0~svn24834
ImportĀ upstreamĀ versionĀ 2.50~alpha~0~svn24834

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
16
#
 
17
# ##### END GPL LICENSE BLOCK #####
 
18
 
 
19
import bpy
 
20
import sys, os, re
 
21
import http, http.client, http.server, urllib
 
22
import subprocess, shutil, time, hashlib
 
23
 
 
24
import netrender
 
25
import netrender.model
 
26
import netrender.slave as slave
 
27
import netrender.master as master
 
28
from netrender.utils import *
 
29
 
 
30
def addFluidFiles(job, path):
 
31
        if os.path.exists(path):
 
32
                pattern = re.compile("fluidsurface_(final|preview)_([0-9]+)\.(bobj|bvel)\.gz")
 
33
 
 
34
                for fluid_file in sorted(os.listdir(path)):
 
35
                        match = pattern.match(fluid_file)
 
36
                        
 
37
                        if match:
 
38
                                # fluid frames starts at 0, which explains the +1
 
39
                                # This is stupid
 
40
                                current_frame = int(match.groups()[1]) + 1 
 
41
                                job.addFile(path + fluid_file, current_frame, current_frame)
 
42
 
 
43
def addPointCache(job, ob, point_cache, default_path):
 
44
        if not point_cache.disk_cache:
 
45
                return
 
46
        
 
47
        
 
48
        name = point_cache.name
 
49
        if name == "":
 
50
                name = "".join(["%02X" % ord(c) for c in ob.name])
 
51
        
 
52
        cache_path = bpy.utils.expandpath(point_cache.filepath) if point_cache.external else default_path
 
53
        
 
54
        index = "%02i" % point_cache.index
 
55
        
 
56
        if os.path.exists(cache_path):
 
57
                pattern = re.compile(name + "_([0-9]+)_" + index + "\.bphys")
 
58
                
 
59
                cache_files = []
 
60
 
 
61
                for cache_file in sorted(os.listdir(cache_path)):
 
62
                        match = pattern.match(cache_file)
 
63
                        
 
64
                        if match:
 
65
                                cache_frame = int(match.groups()[0])
 
66
                                cache_files.append((cache_frame, cache_file))
 
67
                                
 
68
                cache_files.sort()
 
69
                
 
70
                if len(cache_files) == 1:
 
71
                        cache_frame, cache_file = cache_files[0]
 
72
                        job.addFile(cache_path + cache_file, cache_frame, cache_frame)
 
73
                else:
 
74
                        for i in range(len(cache_files)):
 
75
                                current_item = cache_files[i]
 
76
                                next_item = cache_files[i+1] if i + 1 < len(cache_files) else None
 
77
                                previous_item = cache_files[i - 1] if i > 0 else None
 
78
                                
 
79
                                current_frame, current_file = current_item
 
80
                                
 
81
                                if  not next_item and not previous_item:
 
82
                                        job.addFile(cache_path + current_file, current_frame, current_frame)
 
83
                                elif next_item and not previous_item:
 
84
                                        next_frame = next_item[0]
 
85
                                        job.addFile(cache_path + current_file, current_frame, next_frame - 1)
 
86
                                elif not next_item and previous_item:
 
87
                                        previous_frame = previous_item[0]
 
88
                                        job.addFile(cache_path + current_file, previous_frame + 1, current_frame)
 
89
                                else:
 
90
                                        next_frame = next_item[0]
 
91
                                        previous_frame = previous_item[0]
 
92
                                        job.addFile(cache_path + current_file, previous_frame + 1, next_frame - 1)
 
93
                                                
 
94
def clientSendJob(conn, scene, anim = False):
 
95
        netsettings = scene.network_render
 
96
        job = netrender.model.RenderJob()
 
97
        
 
98
        if anim:
 
99
                for f in range(scene.start_frame, scene.end_frame + 1):
 
100
                        job.addFrame(f)
 
101
        else:
 
102
                job.addFrame(scene.current_frame)
 
103
        
 
104
        filename = bpy.data.filename
 
105
        job.addFile(filename)
 
106
        
 
107
        job_name = netsettings.job_name
 
108
        path, name = os.path.split(filename)
 
109
        path += os.sep
 
110
        if job_name == "[default]":
 
111
                job_name = name
 
112
        
 
113
        ###########################
 
114
        # LIBRARIES
 
115
        ###########################
 
116
        for lib in bpy.data.libraries:
 
117
                job.addFile(bpy.utils.expandpath(lib.filename))
 
118
                
 
119
        ###########################
 
120
        # IMAGES
 
121
        ###########################
 
122
        for image in bpy.data.images:
 
123
                if image.source == "FILE" and not image.packed_file:
 
124
                        job.addFile(bpy.utils.expandpath(image.filename))
 
125
        
 
126
        ###########################
 
127
        # FLUID + POINT CACHE
 
128
        ###########################
 
129
        root, ext = os.path.splitext(name)
 
130
        default_path = path + "blendcache_" + root + os.sep # need an API call for that
 
131
 
 
132
        for object in bpy.data.objects:
 
133
                for modifier in object.modifiers:
 
134
                        if modifier.type == 'FLUID_SIMULATION' and modifier.settings.type == "DOMAIN":
 
135
                                addFluidFiles(job, bpy.utils.expandpath(modifier.settings.path))
 
136
                        elif modifier.type == "CLOTH":
 
137
                                addPointCache(job, object, modifier.point_cache, default_path)
 
138
                        elif modifier.type == "SOFT_BODY":
 
139
                                addPointCache(job, object, modifier.point_cache, default_path)
 
140
                        elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN":
 
141
                                addPointCache(job, object, modifier.domain_settings.point_cache_low, default_path)
 
142
                                if modifier.domain_settings.highres:
 
143
                                        addPointCache(job, object, modifier.domain_settings.point_cache_high, default_path)
 
144
 
 
145
                # particles modifier are stupid and don't contain data
 
146
                # we have to go through the object property
 
147
                for psys in object.particle_systems:
 
148
                        addPointCache(job, object, psys.point_cache, default_path)
 
149
        
 
150
        # print(job.files)
 
151
        
 
152
        job.name = job_name
 
153
        
 
154
        for slave in netrender.blacklist:
 
155
                job.blacklist.append(slave.id)
 
156
        
 
157
        job.chunks = netsettings.chunks
 
158
        job.priority = netsettings.priority
 
159
        
 
160
        # try to send path first
 
161
        conn.request("POST", "/job", repr(job.serialize()))
 
162
        response = conn.getresponse()
 
163
        
 
164
        job_id = response.getheader("job-id")
 
165
        
 
166
        # if not ACCEPTED (but not processed), send files
 
167
        if response.status == http.client.ACCEPTED:
 
168
                for filepath, start, end in job.files:
 
169
                        f = open(filepath, "rb")
 
170
                        conn.request("PUT", "/file", f, headers={"job-id": job_id, "job-file": filepath})
 
171
                        f.close()
 
172
                        response = conn.getresponse()
 
173
        
 
174
        # server will reply with NOT_FOUD until all files are found
 
175
        
 
176
        return job_id
 
177
 
 
178
def requestResult(conn, job_id, frame):
 
179
        conn.request("GET", "/render", headers={"job-id": job_id, "job-frame":str(frame)})
 
180
 
 
181
@rnaType
 
182
class NetworkRenderEngine(bpy.types.RenderEngine):
 
183
        bl_idname = 'NET_RENDER'
 
184
        bl_label = "Network Render"
 
185
        def render(self, scene):
 
186
                if scene.network_render.mode == "RENDER_CLIENT":
 
187
                        self.render_client(scene)
 
188
                elif scene.network_render.mode == "RENDER_SLAVE":
 
189
                        self.render_slave(scene)
 
190
                elif scene.network_render.mode == "RENDER_MASTER":
 
191
                        self.render_master(scene)
 
192
                else:
 
193
                        print("UNKNOWN OPERATION MODE")
 
194
        
 
195
        def render_master(self, scene):
 
196
                netsettings = scene.network_render
 
197
                
 
198
                address = "" if netsettings.server_address == "[default]" else netsettings.server_address
 
199
                
 
200
                master.runMaster((address, netsettings.server_port), netsettings.server_broadcast, netsettings.path, self.update_stats, self.test_break)
 
201
 
 
202
 
 
203
        def render_slave(self, scene):
 
204
                slave.render_slave(self, scene.network_render)
 
205
        
 
206
        def render_client(self, scene):
 
207
                netsettings = scene.network_render
 
208
                self.update_stats("", "Network render client initiation")
 
209
                
 
210
                
 
211
                conn = clientConnection(netsettings.server_address, netsettings.server_port)
 
212
                
 
213
                if conn:
 
214
                        # Sending file
 
215
                        
 
216
                        self.update_stats("", "Network render exporting")
 
217
                        
 
218
                        job_id = netsettings.job_id
 
219
                        
 
220
                        # reading back result
 
221
                        
 
222
                        self.update_stats("", "Network render waiting for results")
 
223
                        
 
224
                        requestResult(conn, job_id, scene.current_frame)
 
225
                        response = conn.getresponse()
 
226
                        
 
227
                        if response.status == http.client.NO_CONTENT:
 
228
                                netsettings.job_id = clientSendJob(conn, scene)
 
229
                                requestResult(conn, job_id, scene.current_frame)
 
230
                        
 
231
                        while response.status == http.client.ACCEPTED and not self.test_break():
 
232
                                time.sleep(1)
 
233
                                requestResult(conn, job_id, scene.current_frame)
 
234
                                response = conn.getresponse()
 
235
        
 
236
                        if response.status != http.client.OK:
 
237
                                conn.close()
 
238
                                return
 
239
                        
 
240
                        r = scene.render_data
 
241
                        x= int(r.resolution_x*r.resolution_percentage*0.01)
 
242
                        y= int(r.resolution_y*r.resolution_percentage*0.01)
 
243
                        
 
244
                        f = open(netsettings.path + "output.exr", "wb")
 
245
                        buf = response.read(1024)
 
246
                        
 
247
                        while buf:
 
248
                                f.write(buf)
 
249
                                buf = response.read(1024)
 
250
                        
 
251
                        f.close()
 
252
                        
 
253
                        result = self.begin_result(0, 0, x, y)
 
254
                        result.load_from_file(netsettings.path + "output.exr", 0, 0)
 
255
                        self.end_result(result)
 
256
                        
 
257
                        conn.close()
 
258
 
 
259
def compatible(module):
 
260
        module = __import__(module)
 
261
        for subclass in module.__dict__.values():
 
262
                try:            subclass.COMPAT_ENGINES.add('NET_RENDER')
 
263
                except: pass
 
264
        del module
 
265
 
 
266
compatible("properties_render")
 
267
compatible("properties_world")
 
268
compatible("properties_material")