* Updated icon sheet, thanks jendryzch!
[blender-staging.git] / release / io / engine_render_pov.py
1 import bpy
2
3 from math import atan, pi, degrees
4 import subprocess
5 import os
6 import sys
7 import time
8
9 import platform as pltfrm
10
11 if pltfrm.architecture()[0] == '64bit':
12         bitness = 64
13 else:
14         bitness = 32
15
16 def write_pov(filename, scene=None, info_callback = None):
17         file = open(filename, 'w')
18         
19         # Only for testing
20         if not scene:
21                 scene = bpy.data.scenes[0]
22                 
23         render = scene.render_data
24         materialTable = {}
25         
26         def saneName(name):
27                 name = name.lower()
28                 for ch in ' /\\+=-[]{}().,<>\'":;~!@#$%^&*|?':
29                         name = name.replace(ch, '_')
30                 return name
31         
32         def writeMatrix(matrix):
33                 file.write('\tmatrix <%.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, %.6f>\n' %\
34                 (matrix[0][0], matrix[0][1], matrix[0][2],  matrix[1][0], matrix[1][1], matrix[1][2],  matrix[2][0], matrix[2][1], matrix[2][2],  matrix[3][0], matrix[3][1], matrix[3][2]) )
35         
36         def exportCamera():
37                 camera = scene.camera
38                 matrix = camera.matrix
39                 
40                 # compute resolution
41                 Qsize=float(render.resolution_x)/float(render.resolution_y)
42                 
43                 file.write('camera {\n')
44                 file.write('\tlocation  <0, 0, 0>\n')
45                 file.write('\tlook_at  <0, 0, -1>\n')
46                 file.write('\tright <%s, 0, 0>\n' % -Qsize)
47                 file.write('\tup <0, 1, 0>\n')
48                 file.write('\tangle  %f \n' % (360.0*atan(16.0/camera.data.lens)/pi))
49                 
50                 file.write('\trotate  <%.6f, %.6f, %.6f>\n' % tuple([degrees(e) for e in matrix.rotationPart().toEuler()]))
51                 file.write('\ttranslate <%.6f, %.6f, %.6f>\n' % (matrix[3][0], matrix[3][1], matrix[3][2]))
52                 file.write('}\n')
53         
54         
55         
56         def exportLamps(lamps):
57                 # Get all lamps
58                 for ob in lamps:
59                         lamp = ob.data
60                         
61                         matrix = ob.matrix
62                         
63                         color = tuple([c * lamp.energy for c in lamp.color]) # Colour is modified by energy
64                         
65                         file.write('light_source {\n')
66                         file.write('\t< 0,0,0 >\n')
67                         file.write('\tcolor rgb<%.3g, %.3g, %.3g>\n' % color)
68                         
69                         if lamp.type == 'POINT': # Point Lamp 
70                                 pass
71                         elif lamp.type == 'SPOT': # Spot
72                                 file.write('\tspotlight\n')
73                                 
74                                 # Falloff is the main radius from the centre line
75                                 file.write('\tfalloff %.2f\n' % (lamp.spot_size/2.0) ) # 1 TO 179 FOR BOTH
76                                 file.write('\tradius %.6f\n' % ((lamp.spot_size/2.0) * (1-lamp.spot_blend)) ) 
77                                 
78                                 # Blender does not have a tightness equivilent, 0 is most like blender default.
79                                 file.write('\ttightness 0\n') # 0:10f
80                                 
81                                 file.write('\tpoint_at  <0, 0, -1>\n')
82                         elif lamp.type == 'AREA':
83                                 
84                                 size_x = lamp.size
85                                 samples_x = lamp.shadow_ray_samples_x
86                                 if lamp.shape == 'SQUARE':
87                                         size_y = size_x
88                                         samples_y = samples_x
89                                 else:
90                                         size_y = lamp.size_y
91                                         samples_y = lamp.shadow_ray_samples_y
92                                 
93                                 
94                                 
95                                 file.write('\tarea_light <%d,0,0>,<0,0,%d> %d, %d\n' % (size_x, size_y, samples_x, samples_y))
96                                 if lamp.shadow_ray_sampling_method == 'CONSTANT_JITTERED':
97                                         if lamp.jitter:
98                                                 file.write('\tjitter\n')
99                                 else:
100                                         file.write('\tadaptive 1\n')
101                                         file.write('\tjitter\n')
102                         
103                         if lamp.shadow_method == 'NOSHADOW':
104                                 file.write('\tshadowless\n')    
105                         
106                         file.write('\tfade_distance %.6f\n' % lamp.distance)
107                         file.write('\tfade_power %d\n' % 1) # Could use blenders lamp quad?
108                         writeMatrix(matrix)
109                         
110                         file.write('}\n')
111         
112         def exportMeshs(sel):
113                 def bMat2PovString(material):
114                         povstring = 'finish {'
115                         if world != None:
116                                 povstring += 'ambient <%.6f, %.6f, %.6f> ' % tuple([c*material.ambient for c in world.ambient_color])
117                         
118                         povstring += 'diffuse %.6f ' % material.diffuse_reflection
119                         povstring += 'specular %.6f ' % material.specular_reflection
120                         
121                         
122                         if material.raytrace_mirror.enabled:
123                                 #povstring += 'interior { ior %.6f } ' % material.IOR
124                                 raytrace_mirror= material.raytrace_mirror
125                                 if raytrace_mirror.reflect:
126                                         povstring += 'reflection {'
127                                         povstring += '<%.6f, %.6f, %.6f>' % tuple(material.mirror_color) # Should ask for ray mirror flag
128                                         povstring += 'fresnel 1 falloff %.6f exponent %.6f metallic %.6f} ' % (raytrace_mirror.fresnel, raytrace_mirror.fresnel_fac, raytrace_mirror.reflect)
129                                 
130                                 
131                                         
132                         if material.raytrace_transparency.enabled:
133                                 #povstring += 'interior { ior %.6f } ' % material.IOR
134                                 pass
135                         
136                         #file.write('\t\troughness %.6f\n' % (material.hard*0.5))
137                         #file.write('\t\t\tcrand 0.0\n') # Sand granyness
138                         #file.write('\t\t\tmetallic %.6f\n' % material.spec)
139                         #file.write('\t\t\tphong %.6f\n' % material.spec)
140                         #file.write('\t\t\tphong_size %.6f\n' % material.spec)
141                         povstring += 'brilliance %.6f ' % (material.specular_hardness/256.0) # Like hardness
142                         povstring += '}'
143                         #file.write('\t}\n')
144                         return povstring
145                         
146                 
147                 world = scene.world
148                 
149                 # Convert all materials to strings we can access directly per vertex.
150                 for material in bpy.data.materials:
151                         materialTable[material.name] = bMat2PovString(material)
152                 
153                 
154                 ob_num = 0
155                 
156                 for ob in sel:
157                         ob_num+= 1
158                         
159                         if ob.type in ('LAMP', 'CAMERA', 'EMPTY'):
160                                 continue
161                         
162                         me = ob.data
163                         me_materials= me.materials
164                         
165                         me = ob.create_render_mesh(scene)
166                         
167                         if not me:
168                                 continue
169                         
170                         if info_callback:
171                                 info_callback('Object %2.d of %2.d (%s)' % (ob_num, len(sel), ob.name))
172                         
173                         #if ob.type!='MESH':
174                         #       continue
175                         # me = ob.data
176                         
177                         matrix = ob.matrix
178                         try:    uv_layer = me.active_uv_texture.data
179                         except:uv_layer = None
180                                 
181                         try:    vcol_layer = me.active_vertex_color.data
182                         except:vcol_layer = None
183                         
184                         
185                         def regular_face(f):
186                                 fv = f.verts
187                                 if fv[3]== 0:
188                                         return fv[0], fv[1], fv[2]
189                                 return fv[0], fv[1], fv[2], fv[3]
190                         
191                         faces_verts = [regular_face(f) for f in me.faces]
192                         faces_normals = [tuple(f.normal) for f in me.faces]
193                         verts_normals = [tuple(v.normal) for v in me.verts]
194                         
195                         # quads incur an extra face
196                         quadCount = len([f for f in faces_verts if len(f)==4])
197                         
198                         file.write('mesh2 {\n')
199                         file.write('\tvertex_vectors {\n')
200                         file.write('\t\t%s' % (len(me.verts))) # vert count
201                         for v in me.verts:
202                                 file.write(',\n\t\t<%.6f, %.6f, %.6f>' % tuple(v.co)) # vert count
203                         file.write('\n  }\n')
204                         
205                         
206                         # Build unique Normal list
207                         uniqueNormals = {}
208                         for fi, f in enumerate(me.faces):
209                                 fv = faces_verts[fi]
210                                 # [-1] is a dummy index, use a list so we can modify in place
211                                 if f.smooth: # Use vertex normals
212                                         for v in fv:
213                                                 key = verts_normals[v]
214                                                 uniqueNormals[key] = [-1]
215                                 else: # Use face normal
216                                         key = faces_normals[fi]
217                                         uniqueNormals[key] = [-1]
218                         
219                         file.write('\tnormal_vectors {\n')
220                         file.write('\t\t%d' % len(uniqueNormals)) # vert count
221                         idx = 0
222                         for no, index in uniqueNormals.items():
223                                 file.write(',\n\t\t<%.6f, %.6f, %.6f>' % no) # vert count
224                                 index[0] = idx
225                                 idx +=1
226                         file.write('\n  }\n')
227                         
228                         
229                         # Vertex colours
230                         vertCols = {} # Use for material colours also.
231                         
232                         if uv_layer:
233                                 # Generate unique UV's
234                                 uniqueUVs = {}
235                                 
236                                 for fi, uv in enumerate(uv_layer):
237                                         
238                                         if len(faces_verts[fi])==4:
239                                                 uvs = uv.uv1, uv.uv2, uv.uv3, uv.uv4
240                                         else:
241                                                 uvs = uv.uv1, uv.uv2, uv.uv3
242                                         
243                                         for uv in uvs:
244                                                 uniqueUVs[tuple(uv)] = [-1]
245                                 
246                                 file.write('\tuv_vectors {\n')
247                                 #print unique_uvs
248                                 file.write('\t\t%s' % (len(uniqueUVs))) # vert count
249                                 idx = 0
250                                 for uv, index in uniqueUVs.items():
251                                         file.write(',\n\t\t<%.6f, %.6f>' % uv)
252                                         index[0] = idx
253                                         idx +=1
254                                 '''
255                                 else:
256                                         # Just add 1 dummy vector, no real UV's
257                                         file.write('\t\t1') # vert count
258                                         file.write(',\n\t\t<0.0, 0.0>')
259                                 '''
260                                 file.write('\n  }\n')
261                         
262                         
263                         if me.vertex_colors:
264                                 
265                                 for fi, f in enumerate(me.faces):
266                                         material_index = f.material_index
267                                         material = me_materials[material_index]
268                                         
269                                         if material and material.vertex_color_paint:
270                                                 
271                                                 col = vcol_layer[fi]
272                                                 
273                                                 if len(faces_verts[fi])==4:
274                                                         cols = col.color1, col.color2, col.color3, col.color4
275                                                 else:
276                                                         cols = col.color1, col.color2, col.color3
277                                                 
278                                                 for col in cols:                                        
279                                                         key = col[0], col[1], col[2], material_index # Material index!
280                                                         vertCols[key] = [-1]
281                                                 
282                                         else:
283                                                 if material:
284                                                         diffuse_color = tuple(material.diffuse_color)
285                                                         key = diffuse_color[0], diffuse_color[1], diffuse_color[2], material_index
286                                                         vertCols[key] = [-1]
287                                                 
288                         
289                         else:
290                                 # No vertex colours, so write material colours as vertex colours
291                                 for i, material in enumerate(me_materials):
292                                         
293                                         if material:
294                                                 diffuse_color = tuple(material.diffuse_color)
295                                                 key = diffuse_color[0], diffuse_color[1], diffuse_color[2], i # i == f.mat
296                                                 vertCols[key] = [-1]
297                                 
298                         
299                         # Vert Colours
300                         file.write('\ttexture_list {\n')
301                         file.write('\t\t%s' % (len(vertCols))) # vert count
302                         idx=0
303                         for col, index in vertCols.items():
304                                 
305                                 if me_materials:
306                                         material = me_materials[col[3]]
307                                         materialString = materialTable[material.name]
308                                 else:
309                                         materialString = '' # Dont write anything
310                                 
311                                 float_col = col[0], col[1], col[2], 1-material.alpha, materialString
312                                 #print material.apl
313                                 file.write(',\n\t\ttexture { pigment {rgbf<%.3g, %.3g, %.3g, %.3g>}%s}' % float_col)
314                                 index[0] = idx
315                                 idx+=1
316                         
317                         file.write( '\n  }\n' )
318                         
319                         # Face indicies
320                         file.write('\tface_indices {\n')
321                         file.write('\t\t%d' % (len(me.faces) + quadCount)) # faces count
322                         for fi, f in enumerate(me.faces):
323                                 fv = faces_verts[fi]
324                                 material_index= f.material_index
325                                 if len(fv) == 4:        indicies = (0,1,2), (0,2,3)
326                                 else:                           indicies = ((0,1,2),)
327                                 
328                                 if vcol_layer:
329                                         col = vcol_layer[fi]
330                                         
331                                         if len(fv) == 4:
332                                                 cols = col.color1, col.color2, col.color3, col.color4
333                                         else:
334                                                 cols = col.color1, col.color2, col.color3
335                                 
336                                 
337                                 if not me_materials or me_materials[material_index] == None: # No materials
338                                         for i1, i2, i3 in indicies:
339                                                 file.write(',\n\t\t<%d,%d,%d>' % (fv[i1], fv[i2], fv[i3])) # vert count
340                                 else:
341                                         material = me_materials[material_index]
342                                         for i1, i2, i3 in indicies:
343                                                 if me.vertex_colors and material.vertex_color_paint:
344                                                         # Colour per vertex - vertex colour
345                                                         
346                                                         col1 = cols[i1]
347                                                         col2 = cols[i2]
348                                                         col3 = cols[i3]
349                                                 
350                                                         ci1 = vertCols[col1[0], col1[1], col1[2], material_index][0]
351                                                         ci2 = vertCols[col2[0], col2[1], col2[2], material_index][0]
352                                                         ci3 = vertCols[col3[0], col3[1], col3[2], material_index][0]
353                                                 else:
354                                                         # Colour per material - flat material colour
355                                                         diffuse_color= material.diffuse_color
356                                                         ci1 = ci2 = ci3 = vertCols[diffuse_color[0], diffuse_color[1], diffuse_color[2], f.material_index][0]
357                                                 
358                                                 file.write(',\n\t\t<%d,%d,%d>, %d,%d,%d' % (fv[i1], fv[i2], fv[i3], ci1, ci2, ci3)) # vert count
359                                         
360                                         
361                                         
362                         file.write('\n  }\n')
363                         
364                         # normal_indices indicies
365                         file.write('\tnormal_indices {\n')
366                         file.write('\t\t%d' % (len(me.faces) + quadCount)) # faces count
367                         for fi, fv in enumerate(faces_verts):
368                                 
369                                 if len(fv) == 4:        indicies = (0,1,2), (0,2,3)
370                                 else:                           indicies = ((0,1,2),)
371                                 
372                                 for i1, i2, i3 in indicies:
373                                         if f.smooth:
374                                                 file.write(',\n\t\t<%d,%d,%d>' %\
375                                                 (uniqueNormals[verts_normals[fv[i1]]][0],\
376                                                  uniqueNormals[verts_normals[fv[i2]]][0],\
377                                                  uniqueNormals[verts_normals[fv[i3]]][0])) # vert count
378                                         else:
379                                                 idx = uniqueNormals[faces_normals[fi]][0]
380                                                 file.write(',\n\t\t<%d,%d,%d>' % (idx, idx, idx)) # vert count
381                                                 
382                         file.write('\n  }\n')
383                         
384                         if uv_layer:
385                                 file.write('\tuv_indices {\n')
386                                 file.write('\t\t%d' % (len(me.faces) + quadCount)) # faces count
387                                 for fi, fv in enumerate(faces_verts):
388                                         
389                                         if len(fv) == 4:        indicies = (0,1,2), (0,2,3)
390                                         else:                           indicies = ((0,1,2),)
391                                         
392                                         uv = uv_layer[fi]
393                                         if len(faces_verts[fi])==4:
394                                                 uvs = tuple(uv.uv1), tuple(uv.uv2), tuple(uv.uv3), tuple(uv.uv4)
395                                         else:
396                                                 uvs = tuple(uv.uv1), tuple(uv.uv2), tuple(uv.uv3)
397                                         
398                                         for i1, i2, i3 in indicies:
399                                                 file.write(',\n\t\t<%d,%d,%d>' %\
400                                                 (uniqueUVs[uvs[i1]][0],\
401                                                  uniqueUVs[uvs[i2]][0],\
402                                                  uniqueUVs[uvs[i2]][0])) # vert count
403                                 file.write('\n  }\n')
404                         
405                         if me.materials:
406                                 material = me.materials[0] # dodgy
407                                 if material and material.raytrace_transparency.enabled:
408                                         file.write('\tinterior { ior %.6f }\n' % material.raytrace_transparency.ior)
409                         
410                         writeMatrix(matrix)
411                         file.write('}\n')
412                         
413                         bpy.data.remove_mesh(me)
414         
415         def exportWorld(world):
416                 if not world:
417                         return
418                 
419                 mist = world.mist
420                 
421                 if mist.enabled:
422                         file.write('fog {\n')
423                         file.write('\tdistance %.6f\n' % mist.depth)
424                         file.write('\tcolor rgbt<%.3g, %.3g, %.3g, %.3g>\n' % (tuple(world.horizon_color) + (1-mist.intensity,)))
425                         #file.write('\tfog_offset %.6f\n' % mist.start)
426                         #file.write('\tfog_alt 5\n')
427                         #file.write('\tturbulence 0.2\n')
428                         #file.write('\tturb_depth 0.3\n')
429                         file.write('\tfog_type 1\n')
430                         file.write('}\n')
431         
432         def exportGlobalSettings(scene):
433                 
434                 file.write('global_settings {\n')
435
436                 if scene.pov_radio_enable:
437                         file.write('\tradiosity {\n')
438                         file.write("\t\tadc_bailout %.4g\n" % scene.pov_radio_adc_bailout)
439                         file.write("\t\talways_sample %d\n" % scene.pov_radio_always_sample)
440                         file.write("\t\tbrightness %.4g\n" % scene.pov_radio_brightness)
441                         file.write("\t\tcount %d\n" % scene.pov_radio_count)
442                         file.write("\t\terror_bound %.4g\n" % scene.pov_radio_error_bound)
443                         file.write("\t\tgray_threshold %.4g\n" % scene.pov_radio_gray_threshold)
444                         file.write("\t\tlow_error_factor %.4g\n" % scene.pov_radio_low_error_factor)
445                         file.write("\t\tminimum_reuse %.4g\n" % scene.pov_radio_minimum_reuse)
446                         file.write("\t\tnearest_count %d\n" % scene.pov_radio_nearest_count)
447                         file.write("\t\tnormal %d\n" % scene.pov_radio_normal)
448                         file.write("\t\trecursion_limit %d\n" % scene.pov_radio_recursion_limit)
449                         file.write('\t}\n')
450                 
451                 file.write('}\n')
452                         
453
454                 
455         
456         exportCamera()
457         #exportMaterials()
458         sel = scene.objects
459         lamps = [l for l in sel if l.type == 'LAMP']
460         exportLamps(lamps)
461         exportMeshs(sel)
462         exportWorld(scene.world)
463         exportGlobalSettings(scene)
464         
465         file.close()
466
467
468 def write_pov_ini(filename_ini, filename_pov, filename_image):
469         scene = bpy.data.scenes[0]
470         render = scene.render_data
471         
472         x= int(render.resolution_x*render.resolution_percentage*0.01)
473         y= int(render.resolution_y*render.resolution_percentage*0.01)
474         
475         file = open(filename_ini, 'w')
476         
477         file.write('Input_File_Name="%s"\n' % filename_pov)
478         file.write('Output_File_Name="%s"\n' % filename_image)
479         
480         file.write('Width=%d\n' % x)
481         file.write('Height=%d\n' % y)
482         
483         # Needed for border render.
484         '''
485         file.write('Start_Column=%d\n' % part.x)
486         file.write('End_Column=%d\n' % (part.x+part.w))
487         
488         file.write('Start_Row=%d\n' % (part.y))
489         file.write('End_Row=%d\n' % (part.y+part.h))
490         '''
491         
492         file.write('Display=0\n')
493         file.write('Pause_When_Done=0\n')
494         file.write('Output_File_Type=C\n') # TGA, best progressive loading
495         file.write('Output_Alpha=1\n')
496         
497         if render.antialiasing: 
498                 aa_mapping = {'OVERSAMPLE_5':2, 'OVERSAMPLE_8':3, 'OVERSAMPLE_11':4, 'OVERSAMPLE_16':5} # method 1 assumed
499                 file.write('Antialias=1\n')
500                 file.write('Antialias_Depth=%d\n' % aa_mapping[render.antialiasing_samples])
501         else:
502                 file.write('Antialias=0\n')
503         
504         file.close()
505
506
507 class PovrayRender(bpy.types.RenderEngine):
508         __idname__ = 'POVRAY_RENDER'
509         __label__ = "Povray"
510         DELAY = 0.02
511         def _export(self, scene):
512                 import tempfile
513                 
514                 self.temp_file_in = tempfile.mktemp(suffix='.pov')
515                 self.temp_file_out = tempfile.mktemp(suffix='.tga')
516                 self.temp_file_ini = tempfile.mktemp(suffix='.ini')
517                 '''
518                 self.temp_file_in = '/test.pov'
519                 self.temp_file_out = '/test.tga'
520                 self.temp_file_ini = '/test.ini'
521                 '''
522                 
523                 def info_callback(txt):
524                         self.update_stats("", "POVRAY: " + txt)
525                         
526                 write_pov(self.temp_file_in, scene, info_callback)
527                 
528         def _render(self):
529                 
530                 try:            os.remove(self.temp_file_out) # so as not to load the old file
531                 except: pass
532                 
533                 write_pov_ini(self.temp_file_ini, self.temp_file_in, self.temp_file_out)
534                 
535                 print ("***-STARTING-***")
536                 # This works too but means we have to wait until its done
537                 # os.system('povray %s' % self.temp_file_ini)
538                 
539                 pov_binary = "povray"
540                 
541                 if sys.platform=='win32':
542                         if bitness == 64:
543                                 pov_binary = "pvengine64"
544                         else:
545                                 pov_binary = "pvengine"
546                         
547                 self.process = subprocess.Popen([pov_binary, self.temp_file_ini]) # stdout=subprocess.PIPE, stderr=subprocess.PIPE
548                 
549                 print ("***-DONE-***")
550         
551         def _cleanup(self):
552                 for f in (self.temp_file_in, self.temp_file_ini, self.temp_file_out):
553                         try:            os.remove(f)
554                         except: pass
555                 
556                 self.update_stats("", "")
557         
558         def render(self, scene):
559                 
560                 self.update_stats("", "POVRAY: Exporting data from Blender")
561                 self._export(scene)
562                 self.update_stats("", "POVRAY: Parsing File")
563                 self._render()
564                 
565                 r = scene.render_data
566                 
567                 # compute resolution
568                 x= int(r.resolution_x*r.resolution_percentage*0.01)
569                 y= int(r.resolution_y*r.resolution_percentage*0.01)
570                 
571                 
572                 
573                 # Wait for the file to be created
574                 while not os.path.exists(self.temp_file_out):
575                         if self.test_break():
576                                 try:            self.process.terminate()
577                                 except: pass
578                                 break
579                         
580                         if self.process.poll() != None:
581                                 self.update_stats("", "POVRAY: Failed")
582                                 break
583                         
584                         time.sleep(self.DELAY)
585                 
586                 if os.path.exists(self.temp_file_out):
587                         
588                         self.update_stats("", "POVRAY: Rendering")
589                         
590                         prev_size = -1
591                         
592                         def update_image():
593                                 result = self.begin_result(0, 0, x, y)
594                                 lay = result.layers[0]
595                                 # possible the image wont load early on.
596                                 try:            lay.rect_from_file(self.temp_file_out, 0, 0)
597                                 except: pass
598                                 self.end_result(result)
599                         
600                         # Update while povray renders
601                         while True:
602                                 
603                                 # test if povray exists
604                                 if self.process.poll() != None:
605                                         update_image();
606                                         break
607                                 
608                                 # user exit
609                                 if self.test_break():
610                                         try:            self.process.terminate()
611                                         except: pass
612                                         
613                                         break
614                                 
615                                 # Would be nice to redirect the output
616                                 # stdout_value, stderr_value = self.process.communicate() # locks
617                                 
618                                 
619                                 # check if the file updated
620                                 new_size = os.path.getsize(self.temp_file_out)
621                                 
622                                 if new_size != prev_size:
623                                         update_image()
624                                         prev_size = new_size
625                                 
626                                 time.sleep(self.DELAY)
627                 
628                 self._cleanup()
629
630
631 bpy.types.register(PovrayRender)
632
633
634
635 # Use some of the existing buttons.
636 import buttons_scene
637 buttons_scene.SCENE_PT_render.COMPAT_ENGINES.add('POVRAY_RENDER')
638 buttons_scene.SCENE_PT_dimensions.COMPAT_ENGINES.add('POVRAY_RENDER')
639 buttons_scene.SCENE_PT_antialiasing.COMPAT_ENGINES.add('POVRAY_RENDER')
640 buttons_scene.SCENE_PT_output.COMPAT_ENGINES.add('POVRAY_RENDER')
641 del buttons_scene
642
643 # Use only a subset of the world panels
644 import buttons_world
645 buttons_world.WORLD_PT_preview.COMPAT_ENGINES.add('POVRAY_RENDER')
646 buttons_world.WORLD_PT_context_world.COMPAT_ENGINES.add('POVRAY_RENDER')
647 buttons_world.WORLD_PT_world.COMPAT_ENGINES.add('POVRAY_RENDER')
648 buttons_world.WORLD_PT_mist.COMPAT_ENGINES.add('POVRAY_RENDER')
649 del buttons_world
650
651 # Example of wrapping every class 'as is'
652 import buttons_material
653 for member in dir(buttons_material):
654         subclass = getattr(buttons_material, member)
655         try:            subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
656         except: pass
657 del buttons_material
658
659 class RenderButtonsPanel(bpy.types.Panel):
660         __space_type__ = "BUTTONS_WINDOW"
661         __region_type__ = "WINDOW"
662         __context__ = "scene"
663         # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
664         
665         def poll(self, context):
666                 rd = context.scene.render_data
667                 return (rd.use_game_engine==False) and (rd.engine in self.COMPAT_ENGINES)
668
669 # Radiosity panel, use in the scene for now.
670 class SCENE_PT_povray_radiosity(RenderButtonsPanel):
671         __label__ = "Radiosity"
672         COMPAT_ENGINES = set(['POVRAY_RENDER'])
673
674         def draw_header(self, context):
675                 layout = self.layout
676                 scene = context.scene
677                 layout.itemR(scene, "pov_radio_enable", text="")
678
679         def draw(self, context):
680                 layout = self.layout
681                 scene = context.scene
682                 rd = scene.render_data
683                 
684                 layout.active = scene.pov_radio_enable
685                 
686                 split = layout.split()
687                 
688                 col = split.column()
689                 
690                 col.itemR(scene, "pov_radio_count")
691                 col.itemR(scene, "pov_radio_recursion_limit")
692                 col.itemR(scene, "pov_radio_error_bound")
693                 
694                 col.itemR(scene, "pov_radio_display_advanced")
695                 
696                 if scene.pov_radio_display_advanced:
697                         col.itemR(scene, "pov_radio_adc_bailout")
698                         col.itemR(scene, "pov_radio_brightness")
699                         col.itemR(scene, "pov_radio_gray_threshold")
700                         col.itemR(scene, "pov_radio_low_error_factor")
701                         col.itemR(scene, "pov_radio_minimum_reuse")
702                         col.itemR(scene, "pov_radio_nearest_count")
703                         col.itemR(scene, "pov_radio_normal")
704                         col.itemR(scene, "pov_radio_always_sample")
705                 
706
707 bpy.types.register(SCENE_PT_povray_radiosity)
708
709
710 FloatProperty= bpy.types.Scene.FloatProperty
711 IntProperty= bpy.types.Scene.IntProperty
712 BoolProperty= bpy.types.Scene.BoolProperty
713
714 # Not a real pov option, just to know if we should write
715 BoolProperty(   attr="pov_radio_enable",
716                                 name="Enable Radiosity",
717                                 description="Enable povrays radiosity calculation.",
718                                 default= False)
719 BoolProperty(   attr="pov_radio_display_advanced",
720                                 name="Advanced Options",
721                                 description="Show advanced options.",
722                                 default= False)
723
724 # Real pov options
725 FloatProperty(  attr="pov_radio_adc_bailout",
726                                 name="ADC Bailout",
727                                 description="The adc_bailout for radiosity rays. Use adc_bailout = 0.01 / brightest_ambient_object for good results.",
728                                 min=0.0, max=1000.0, soft_min=0.0, soft_max=1.0, default= 0.01)
729
730 BoolProperty(   attr="pov_radio_always_sample",
731                                 name="Always Sample",
732                                 description="Only use the data from the pretrace step and not gather any new samples during the final radiosity pass..",
733                                 default= True)
734
735 FloatProperty(  attr="pov_radio_brightness",
736                                 name="Brightness",
737                                 description="Ammount objects are brightened before being returned upwards to the rest of the system.",
738                                 min=0.0, max=1000.0, soft_min=0.0, soft_max=10.0, default= 1.0)
739
740 IntProperty(    attr="pov_radio_count",
741                                 name="Ray Count",
742                                 description="number of rays that are sent out whenever a new radiosity value has to be calculated.",
743                                 min=1, max=1600, default= 35)
744
745 FloatProperty(  attr="pov_radio_error_bound",
746                                 name="Error Bound",
747                                 description="one of the two main speed/quality tuning values, lower values are more accurate.",
748                                 min=0.0, max=1000.0, soft_min=0.1, soft_max=10.0, default= 1.8)
749
750 FloatProperty(  attr="pov_radio_gray_threshold",
751                                 name="Gray Threshold",
752                                 description="one of the two main speed/quality tuning values, lower values are more accurate.",
753                                 min=0.0, max=1.0, default= 0.0)
754                                                                 
755 FloatProperty(  attr="pov_radio_low_error_factor",
756                                 name="Low Error Factor",
757                                 description="If you calculate just enough samples, but no more, you will get an image which has slightly blotchy lighting.",
758                                 min=0.0, max=1.0, default= 0.5)
759
760 # max_sample - not available yet
761
762 FloatProperty(  attr="pov_radio_minimum_reuse",
763                                 name="Minimum Reuse",
764                                 description="Fraction of the screen width which sets the minimum radius of reuse for each sample point (At values higher than 2% expect errors).",
765                                 min=0.0, max=1.0, soft_min=0.1, soft_max=0.1, default= 0.015)
766                                 
767 IntProperty(    attr="pov_radio_nearest_count",
768                                 name="Nearest Count",
769                                 description="Number of old ambient values blended together to create a new interpolated value.",
770                                 min=1, max=20, default= 5)
771                                 
772 BoolProperty(   attr="pov_radio_normal",
773                                 name="Normals",
774                                 description="Radiosity estimation can be affected by normals.",
775                                 default= False)
776
777 IntProperty(    attr="pov_radio_recursion_limit",
778                                 name="Recursion Limit",
779                                 description="how many recursion levels are used to calculate the diffuse inter-reflection.",
780                                 min=1, max=20, default= 3)