rna UI api rename...
[blender.git] / release / scripts / io / engine_render_pov.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 import bpy
20
21 from math import atan, pi, degrees
22 import subprocess
23 import os
24 import sys
25 import time
26
27 import platform as pltfrm
28
29 if pltfrm.architecture()[0] == '64bit':
30         bitness = 64
31 else:
32         bitness = 32
33
34 def write_pov(filename, scene=None, info_callback = None):
35         file = open(filename, 'w')
36         
37         # Only for testing
38         if not scene:
39                 scene = bpy.data.scenes[0]
40         
41         render = scene.render_data
42         world = scene.world
43         
44         # --- taken from fbx exporter 
45         ## This was used to make V, but faster not to do all that
46         ##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_,.()[]{}'
47         ##v = range(255)
48         ##for c in valid: v.remove(ord(c))
49         v = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,42,43,46,47,58,59,60,61,62,63,64,92,94,96,124,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254]
50         invalid = ''.join([chr(i) for i in v])
51         def cleanName(name):
52                 for ch in invalid:      name = name.replace(ch, '_')
53                 return name
54         del v
55         
56         # --- done with clean name.
57         
58         def uniqueName(name, nameSeq):
59                 
60                 if name not in nameSeq:
61                         return name
62                 
63                 name_orig = name
64                 i = 1
65                 while name in nameSeq:
66                         name = '%s_%.3d' % (name_orig, i)
67                         i+=1
68                 
69                 return name
70                 
71         
72         def writeMatrix(matrix):
73                 file.write('\tmatrix <%.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, %.6f>\n' %\
74                 (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]) )
75         
76         def writeObjectMaterial(material):
77                 if material and material.transparency_method=='RAYTRACE':
78                         file.write('\tinterior { ior %.6f }\n' % material.raytrace_transparency.ior)
79                         
80                         # Other interior args
81                         # fade_distance 2
82                         # fade_power [Value]
83                         # fade_color
84                         
85                         # dispersion
86                         # dispersion_samples
87         
88         materialNames = {}
89         DEF_MAT_NAME = 'Default'
90         def writeMaterial(material):
91                 # Assumes only called once on each material
92                 
93                 if material:
94                         name_orig = material.name
95                 else:
96                         name_orig = DEF_MAT_NAME
97                 
98                 name = materialNames[name_orig] = uniqueName(cleanName(name_orig), materialNames)
99                 
100                 file.write('#declare %s = finish {\n' % name)
101                 
102                 if material:
103                         file.write('\tdiffuse %.3g\n' % material.diffuse_intensity)
104                         file.write('\tspecular %.3g\n' % material.specular_intensity)
105                         
106                         file.write('\tambient %.3g\n' % material.ambient)
107                         #file.write('\tambient rgb <%.3g, %.3g, %.3g>\n' % tuple([c*material.ambient for c in world.ambient_color])) # povray blends the global value
108                         
109                         # map hardness between 0.0 and 1.0
110                         roughness = ((1.0 - ((material.specular_hardness-1.0)/510.0)))
111                         # scale from 0.0 to 0.1
112                         roughness *= 0.1
113                         # add a small value because 0.0 is invalid
114                         roughness += (1/511.0)
115                         
116                         file.write('\troughness %.3g\n' % roughness)
117                         
118                         # 'phong 70.0 '
119                         
120                         if material.raytrace_mirror.enabled:
121                                 raytrace_mirror= material.raytrace_mirror
122                                 if raytrace_mirror.reflect_factor:
123                                         file.write('\treflection {\n')
124                                         file.write('\t\trgb <%.3g, %.3g, %.3g>' % tuple(material.mirror_color))
125                                         file.write('\t\tfresnel 1 falloff %.3g exponent %.3g metallic %.3g} ' % (raytrace_mirror.fresnel, raytrace_mirror.fresnel_factor, raytrace_mirror.reflect_factor))
126                 
127                 else:
128                         file.write('\tdiffuse 0.8\n')
129                         file.write('\tspecular 0.2\n')
130                         
131
132                 # This is written into the object
133                 '''
134                 if material and material.transparency_method=='RAYTRACE':
135                         'interior { ior %.3g} ' % material.raytrace_transparency.ior
136                 '''
137                 
138                 #file.write('\t\t\tcrand 1.0\n') # Sand granyness
139                 #file.write('\t\t\tmetallic %.6f\n' % material.spec)
140                 #file.write('\t\t\tphong %.6f\n' % material.spec)
141                 #file.write('\t\t\tphong_size %.6f\n' % material.spec)
142                 #file.write('\t\t\tbrilliance %.6f ' % (material.specular_hardness/256.0) # Like hardness
143                 
144                 file.write('}\n')
145         
146         def exportCamera():
147                 camera = scene.camera
148                 matrix = camera.matrix
149                 
150                 # compute resolution
151                 Qsize=float(render.resolution_x)/float(render.resolution_y)
152                 
153                 file.write('camera {\n')
154                 file.write('\tlocation  <0, 0, 0>\n')
155                 file.write('\tlook_at  <0, 0, -1>\n')
156                 file.write('\tright <%s, 0, 0>\n' % -Qsize)
157                 file.write('\tup <0, 1, 0>\n')
158                 file.write('\tangle  %f \n' % (360.0*atan(16.0/camera.data.lens)/pi))
159                 
160                 file.write('\trotate  <%.6f, %.6f, %.6f>\n' % tuple([degrees(e) for e in matrix.rotationPart().toEuler()]))
161                 file.write('\ttranslate <%.6f, %.6f, %.6f>\n' % (matrix[3][0], matrix[3][1], matrix[3][2]))
162                 file.write('}\n')
163
164         def exportLamps(lamps):
165                 # Get all lamps
166                 for ob in lamps:
167                         lamp = ob.data
168                         
169                         matrix = ob.matrix
170                         
171                         color = tuple([c * lamp.energy for c in lamp.color]) # Colour is modified by energy
172                         
173                         file.write('light_source {\n')
174                         file.write('\t< 0,0,0 >\n')
175                         file.write('\tcolor rgb<%.3g, %.3g, %.3g>\n' % color)
176                         
177                         if lamp.type == 'POINT': # Point Lamp 
178                                 pass
179                         elif lamp.type == 'SPOT': # Spot
180                                 file.write('\tspotlight\n')
181                                 
182                                 # Falloff is the main radius from the centre line
183                                 file.write('\tfalloff %.2f\n' % (lamp.spot_size/2.0) ) # 1 TO 179 FOR BOTH
184                                 file.write('\tradius %.6f\n' % ((lamp.spot_size/2.0) * (1-lamp.spot_blend)) ) 
185                                 
186                                 # Blender does not have a tightness equivilent, 0 is most like blender default.
187                                 file.write('\ttightness 0\n') # 0:10f
188                                 
189                                 file.write('\tpoint_at  <0, 0, -1>\n')
190                         elif lamp.type == 'SUN':
191                                 file.write('\tparallel\n')
192                                 file.write('\tpoint_at  <0, 0, -1>\n') # *must* be after 'parallel'
193                                 
194                         elif lamp.type == 'AREA':
195                                 
196                                 size_x = lamp.size
197                                 samples_x = lamp.shadow_ray_samples_x
198                                 if lamp.shape == 'SQUARE':
199                                         size_y = size_x
200                                         samples_y = samples_x
201                                 else:
202                                         size_y = lamp.size_y
203                                         samples_y = lamp.shadow_ray_samples_y
204
205                                 file.write('\tarea_light <%d,0,0>,<0,0,%d> %d, %d\n' % (size_x, size_y, samples_x, samples_y))
206                                 if lamp.shadow_ray_sampling_method == 'CONSTANT_JITTERED':
207                                         if lamp.jitter:
208                                                 file.write('\tjitter\n')
209                                 else:
210                                         file.write('\tadaptive 1\n')
211                                         file.write('\tjitter\n')
212                         
213                         if lamp.shadow_method == 'NOSHADOW':
214                                 file.write('\tshadowless\n')    
215                         
216                         file.write('\tfade_distance %.6f\n' % lamp.distance)
217                         file.write('\tfade_power %d\n' % 1) # Could use blenders lamp quad?
218                         writeMatrix(matrix)
219                         
220                         file.write('}\n')
221         
222         def exportMeta(metas):
223                 
224                 # TODO - blenders 'motherball' naming is not supported.
225                 
226                 for ob in metas:
227                         meta = ob.data
228                         
229                         file.write('blob {\n')
230                         file.write('\t\tthreshold %.4g\n' % meta.threshold)
231                         
232                         try:
233                                 material= meta.materials[0] # lame! - blender cant do enything else.
234                         except:
235                                 material= None
236                         
237                         for elem in meta.elements:
238                                 
239                                 if elem.type not in ('BALL', 'ELLIPSOID'):
240                                         continue # Not supported
241                                 
242                                 loc = elem.location
243                                 
244                                 stiffness= elem.stiffness
245                                 if elem.negative:
246                                         stiffness = -stiffness
247                                 
248                                 if elem.type == 'BALL':
249                                         
250                                         file.write('\tsphere { <%.6g, %.6g, %.6g>, %.4g, %.4g ' % (loc.x, loc.y, loc.z, elem.radius, stiffness))
251                                         
252                                         # After this wecould do something simple like...
253                                         #       "pigment {Blue} }"
254                                         # except we'll write the color
255                                 
256                                 elif elem.type == 'ELLIPSOID':
257                                         # location is modified by scale
258                                         file.write('\tsphere { <%.6g, %.6g, %.6g>, %.4g, %.4g ' % (loc.x/elem.size_x, loc.y/elem.size_y, loc.z/elem.size_z, elem.radius, stiffness))
259                                         file.write(     'scale <%.6g, %.6g, %.6g> ' % (elem.size_x, elem.size_y, elem.size_z))
260                                 
261                                 if material:
262                                         diffuse_color = material.diffuse_color
263                                         
264                                         if material.transparency and material.transparency_method=='RAYTRACE':  trans = 1-material.raytrace_transparency.filter
265                                         else:                                                                                                                                   trans = 0.0
266                                         
267                                         file.write(
268                                                 'pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} finish {%s} }\n' % \
269                                                 (diffuse_color[0], diffuse_color[1], diffuse_color[2], 1-material.alpha, trans, materialNames[material.name])
270                                         )
271                                         
272                                 else:
273                                         file.write('pigment {rgb<1 1 1>} finish {%s} }\n' % DEF_MAT_NAME)               # Write the finish last.
274                         
275                         writeObjectMaterial(material)
276
277                         writeMatrix(ob.matrix)
278                         
279                         file.write('}\n')
280
281         def exportMeshs(sel):
282                 
283                 ob_num = 0
284                 
285                 for ob in sel:
286                         ob_num+= 1
287                         
288                         if ob.type in ('LAMP', 'CAMERA', 'EMPTY', 'META', 'ARMATURE'):
289                                 continue
290                         
291                         me = ob.data
292                         me_materials= me.materials
293                         
294                         me = ob.create_mesh(True, 'RENDER')
295                         
296                         if not me:
297                                 continue
298                         
299                         if info_callback:
300                                 info_callback('Object %2.d of %2.d (%s)' % (ob_num, len(sel), ob.name))
301                         
302                         #if ob.type!='MESH':
303                         #       continue
304                         # me = ob.data
305                         
306                         matrix = ob.matrix
307                         try:    uv_layer = me.active_uv_texture.data
308                         except:uv_layer = None
309                                 
310                         try:    vcol_layer = me.active_vertex_color.data
311                         except:vcol_layer = None
312                         
313                         faces_verts = [f.verts for f in me.faces]
314                         faces_normals = [tuple(f.normal) for f in me.faces]
315                         verts_normals = [tuple(v.normal) for v in me.verts]
316                         
317                         # quads incur an extra face
318                         quadCount = len([f for f in faces_verts if len(f)==4])
319                         
320                         file.write('mesh2 {\n')
321                         file.write('\tvertex_vectors {\n')
322                         file.write('\t\t%s' % (len(me.verts))) # vert count
323                         for v in me.verts:
324                                 file.write(',\n\t\t<%.6f, %.6f, %.6f>' % tuple(v.co)) # vert count
325                         file.write('\n  }\n')
326                         
327                         
328                         # Build unique Normal list
329                         uniqueNormals = {}
330                         for fi, f in enumerate(me.faces):
331                                 fv = faces_verts[fi]
332                                 # [-1] is a dummy index, use a list so we can modify in place
333                                 if f.smooth: # Use vertex normals
334                                         for v in fv:
335                                                 key = verts_normals[v]
336                                                 uniqueNormals[key] = [-1]
337                                 else: # Use face normal
338                                         key = faces_normals[fi]
339                                         uniqueNormals[key] = [-1]
340                         
341                         file.write('\tnormal_vectors {\n')
342                         file.write('\t\t%d' % len(uniqueNormals)) # vert count
343                         idx = 0
344                         for no, index in uniqueNormals.items():
345                                 file.write(',\n\t\t<%.6f, %.6f, %.6f>' % no) # vert count
346                                 index[0] = idx
347                                 idx +=1
348                         file.write('\n  }\n')
349                         
350                         
351                         # Vertex colours
352                         vertCols = {} # Use for material colours also.
353                         
354                         if uv_layer:
355                                 # Generate unique UV's
356                                 uniqueUVs = {}
357                                 
358                                 for fi, uv in enumerate(uv_layer):
359                                         
360                                         if len(faces_verts[fi])==4:
361                                                 uvs = uv.uv1, uv.uv2, uv.uv3, uv.uv4
362                                         else:
363                                                 uvs = uv.uv1, uv.uv2, uv.uv3
364                                         
365                                         for uv in uvs:
366                                                 uniqueUVs[tuple(uv)] = [-1]
367                                 
368                                 file.write('\tuv_vectors {\n')
369                                 #print unique_uvs
370                                 file.write('\t\t%s' % (len(uniqueUVs))) # vert count
371                                 idx = 0
372                                 for uv, index in uniqueUVs.items():
373                                         file.write(',\n\t\t<%.6f, %.6f>' % uv)
374                                         index[0] = idx
375                                         idx +=1
376                                 '''
377                                 else:
378                                         # Just add 1 dummy vector, no real UV's
379                                         file.write('\t\t1') # vert count
380                                         file.write(',\n\t\t<0.0, 0.0>')
381                                 '''
382                                 file.write('\n  }\n')
383                         
384                         
385                         if me.vertex_colors:
386                                 
387                                 for fi, f in enumerate(me.faces):
388                                         material_index = f.material_index
389                                         material = me_materials[material_index]
390                                         
391                                         if material and material.vertex_color_paint:
392                                                 
393                                                 col = vcol_layer[fi]
394                                                 
395                                                 if len(faces_verts[fi])==4:
396                                                         cols = col.color1, col.color2, col.color3, col.color4
397                                                 else:
398                                                         cols = col.color1, col.color2, col.color3
399                                                 
400                                                 for col in cols:                                        
401                                                         key = col[0], col[1], col[2], material_index # Material index!
402                                                         vertCols[key] = [-1]
403                                                 
404                                         else:
405                                                 if material:
406                                                         diffuse_color = tuple(material.diffuse_color)
407                                                         key = diffuse_color[0], diffuse_color[1], diffuse_color[2], material_index
408                                                         vertCols[key] = [-1]
409                                                 
410                         
411                         else:
412                                 # No vertex colours, so write material colours as vertex colours
413                                 for i, material in enumerate(me_materials):
414                                         
415                                         if material:
416                                                 diffuse_color = tuple(material.diffuse_color)
417                                                 key = diffuse_color[0], diffuse_color[1], diffuse_color[2], i # i == f.mat
418                                                 vertCols[key] = [-1]
419                                 
420                         
421                         # Vert Colours
422                         file.write('\ttexture_list {\n')
423                         file.write('\t\t%s' % (len(vertCols))) # vert count
424                         idx=0
425                         for col, index in vertCols.items():
426                                 
427                                 if me_materials:
428                                         material = me_materials[col[3]]
429                                         material_finish = materialNames[material.name]
430                                         
431                                         if material.transparency and material.transparency_method=='RAYTRACE':  trans = 1-material.raytrace_transparency.filter
432                                         else:                                                                                                                                   trans = 0.0
433                                         
434                                 else:
435                                         material_finish = DEF_MAT_NAME # not working properly,
436                                         trans = 0.0
437                                 
438                                 #print material.apl
439                                 file.write(     ',\n\t\ttexture { pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} finish {%s}}' %
440                                                         (col[0], col[1], col[2], 1-material.alpha, trans, material_finish) )
441                                 
442                                 index[0] = idx
443                                 idx+=1
444                         
445                         file.write( '\n  }\n' )
446                         
447                         # Face indicies
448                         file.write('\tface_indices {\n')
449                         file.write('\t\t%d' % (len(me.faces) + quadCount)) # faces count
450                         for fi, f in enumerate(me.faces):
451                                 fv = faces_verts[fi]
452                                 material_index= f.material_index
453                                 if len(fv) == 4:        indicies = (0,1,2), (0,2,3)
454                                 else:                           indicies = ((0,1,2),)
455                                 
456                                 if vcol_layer:
457                                         col = vcol_layer[fi]
458                                         
459                                         if len(fv) == 4:
460                                                 cols = col.color1, col.color2, col.color3, col.color4
461                                         else:
462                                                 cols = col.color1, col.color2, col.color3
463                                 
464                                 
465                                 if not me_materials or me_materials[material_index] == None: # No materials
466                                         for i1, i2, i3 in indicies:
467                                                 file.write(',\n\t\t<%d,%d,%d>' % (fv[i1], fv[i2], fv[i3])) # vert count
468                                 else:
469                                         material = me_materials[material_index]
470                                         for i1, i2, i3 in indicies:
471                                                 if me.vertex_colors and material.vertex_color_paint:
472                                                         # Colour per vertex - vertex colour
473                                                         
474                                                         col1 = cols[i1]
475                                                         col2 = cols[i2]
476                                                         col3 = cols[i3]
477                                                 
478                                                         ci1 = vertCols[col1[0], col1[1], col1[2], material_index][0]
479                                                         ci2 = vertCols[col2[0], col2[1], col2[2], material_index][0]
480                                                         ci3 = vertCols[col3[0], col3[1], col3[2], material_index][0]
481                                                 else:
482                                                         # Colour per material - flat material colour
483                                                         diffuse_color= material.diffuse_color
484                                                         ci1 = ci2 = ci3 = vertCols[diffuse_color[0], diffuse_color[1], diffuse_color[2], f.material_index][0]
485                                                 
486                                                 file.write(',\n\t\t<%d,%d,%d>, %d,%d,%d' % (fv[i1], fv[i2], fv[i3], ci1, ci2, ci3)) # vert count
487                                         
488         
489                         file.write('\n  }\n')
490                         
491                         # normal_indices indicies
492                         file.write('\tnormal_indices {\n')
493                         file.write('\t\t%d' % (len(me.faces) + quadCount)) # faces count
494                         for fi, fv in enumerate(faces_verts):
495                                 
496                                 if len(fv) == 4:        indicies = (0,1,2), (0,2,3)
497                                 else:                           indicies = ((0,1,2),)
498                                 
499                                 for i1, i2, i3 in indicies:
500                                         if f.smooth:
501                                                 file.write(',\n\t\t<%d,%d,%d>' %\
502                                                 (uniqueNormals[verts_normals[fv[i1]]][0],\
503                                                  uniqueNormals[verts_normals[fv[i2]]][0],\
504                                                  uniqueNormals[verts_normals[fv[i3]]][0])) # vert count
505                                         else:
506                                                 idx = uniqueNormals[faces_normals[fi]][0]
507                                                 file.write(',\n\t\t<%d,%d,%d>' % (idx, idx, idx)) # vert count
508                                                 
509                         file.write('\n  }\n')
510                         
511                         if uv_layer:
512                                 file.write('\tuv_indices {\n')
513                                 file.write('\t\t%d' % (len(me.faces) + quadCount)) # faces count
514                                 for fi, fv in enumerate(faces_verts):
515                                         
516                                         if len(fv) == 4:        indicies = (0,1,2), (0,2,3)
517                                         else:                           indicies = ((0,1,2),)
518                                         
519                                         uv = uv_layer[fi]
520                                         if len(faces_verts[fi])==4:
521                                                 uvs = tuple(uv.uv1), tuple(uv.uv2), tuple(uv.uv3), tuple(uv.uv4)
522                                         else:
523                                                 uvs = tuple(uv.uv1), tuple(uv.uv2), tuple(uv.uv3)
524                                         
525                                         for i1, i2, i3 in indicies:
526                                                 file.write(',\n\t\t<%d,%d,%d>' %\
527                                                 (uniqueUVs[uvs[i1]][0],\
528                                                  uniqueUVs[uvs[i2]][0],\
529                                                  uniqueUVs[uvs[i2]][0])) # vert count
530                                 file.write('\n  }\n')
531                         
532                         if me.materials:
533                                 material = me.materials[0] # dodgy
534                                 writeObjectMaterial(material)
535                         
536                         writeMatrix(matrix)
537                         file.write('}\n')
538                         
539                         bpy.data.remove_mesh(me)
540         
541         def exportWorld(world):
542                 if not world:
543                         return
544                 
545                 mist = world.mist
546                 
547                 if mist.enabled:
548                         file.write('fog {\n')
549                         file.write('\tdistance %.6f\n' % mist.depth)
550                         file.write('\tcolor rgbt<%.3g, %.3g, %.3g, %.3g>\n' % (tuple(world.horizon_color) + (1-mist.intensity,)))
551                         #file.write('\tfog_offset %.6f\n' % mist.start)
552                         #file.write('\tfog_alt 5\n')
553                         #file.write('\tturbulence 0.2\n')
554                         #file.write('\tturb_depth 0.3\n')
555                         file.write('\tfog_type 1\n')
556                         file.write('}\n')
557         
558         def exportGlobalSettings(scene):
559                 
560                 file.write('global_settings {\n')
561
562                 if scene.pov_radio_enable:
563                         file.write('\tradiosity {\n')
564                         file.write("\t\tadc_bailout %.4g\n" % scene.pov_radio_adc_bailout)
565                         file.write("\t\talways_sample %d\n" % scene.pov_radio_always_sample)
566                         file.write("\t\tbrightness %.4g\n" % scene.pov_radio_brightness)
567                         file.write("\t\tcount %d\n" % scene.pov_radio_count)
568                         file.write("\t\terror_bound %.4g\n" % scene.pov_radio_error_bound)
569                         file.write("\t\tgray_threshold %.4g\n" % scene.pov_radio_gray_threshold)
570                         file.write("\t\tlow_error_factor %.4g\n" % scene.pov_radio_low_error_factor)
571                         file.write("\t\tmedia %d\n" % scene.pov_radio_media)
572                         file.write("\t\tminimum_reuse %.4g\n" % scene.pov_radio_minimum_reuse)
573                         file.write("\t\tnearest_count %d\n" % scene.pov_radio_nearest_count)
574                         file.write("\t\tnormal %d\n" % scene.pov_radio_normal)
575                         file.write("\t\trecursion_limit %d\n" % scene.pov_radio_recursion_limit)
576                         file.write('\t}\n')
577                 
578                 if world:
579                         file.write("\tambient_light rgb<%.3g, %.3g, %.3g>\n" % tuple(world.ambient_color))
580                 
581                 file.write('}\n')
582         
583         
584         # Convert all materials to strings we can access directly per vertex.
585         writeMaterial(None) # default material
586         
587         for material in bpy.data.materials:
588                 writeMaterial(material)
589         
590         exportCamera()
591         #exportMaterials()
592         sel = scene.objects
593         exportLamps([l for l in sel if l.type == 'LAMP'])
594         exportMeta([l for l in sel if l.type == 'META'])
595         exportMeshs(sel)
596         exportWorld(scene.world)
597         exportGlobalSettings(scene)
598         
599         file.close()
600
601 def write_pov_ini(filename_ini, filename_pov, filename_image):
602         scene = bpy.data.scenes[0]
603         render = scene.render_data
604         
605         x= int(render.resolution_x*render.resolution_percentage*0.01)
606         y= int(render.resolution_y*render.resolution_percentage*0.01)
607         
608         file = open(filename_ini, 'w')
609         
610         file.write('Input_File_Name="%s"\n' % filename_pov)
611         file.write('Output_File_Name="%s"\n' % filename_image)
612         
613         file.write('Width=%d\n' % x)
614         file.write('Height=%d\n' % y)
615         
616         # Needed for border render.
617         '''
618         file.write('Start_Column=%d\n' % part.x)
619         file.write('End_Column=%d\n' % (part.x+part.w))
620         
621         file.write('Start_Row=%d\n' % (part.y))
622         file.write('End_Row=%d\n' % (part.y+part.h))
623         '''
624         
625         file.write('Display=0\n')
626         file.write('Pause_When_Done=0\n')
627         file.write('Output_File_Type=T\n') # TGA, best progressive loading
628         file.write('Output_Alpha=1\n')
629         
630         if render.antialiasing: 
631                 aa_mapping = {'OVERSAMPLE_5':2, 'OVERSAMPLE_8':3, 'OVERSAMPLE_11':4, 'OVERSAMPLE_16':5} # method 1 assumed
632                 file.write('Antialias=1\n')
633                 file.write('Antialias_Depth=%d\n' % aa_mapping[render.antialiasing_samples])
634         else:
635                 file.write('Antialias=0\n')
636         
637         file.close()
638
639 # Radiosity panel, use in the scene for now.
640 FloatProperty= bpy.types.Scene.FloatProperty
641 IntProperty= bpy.types.Scene.IntProperty
642 BoolProperty= bpy.types.Scene.BoolProperty
643
644 # Not a real pov option, just to know if we should write
645 BoolProperty(   attr="pov_radio_enable",
646                                 name="Enable Radiosity",
647                                 description="Enable povrays radiosity calculation.",
648                                 default= False)
649 BoolProperty(   attr="pov_radio_display_advanced",
650                                 name="Advanced Options",
651                                 description="Show advanced options.",
652                                 default= False)
653
654 # Real pov options
655 FloatProperty(  attr="pov_radio_adc_bailout",
656                                 name="ADC Bailout",
657                                 description="The adc_bailout for radiosity rays. Use adc_bailout = 0.01 / brightest_ambient_object for good results.",
658                                 min=0.0, max=1000.0, soft_min=0.0, soft_max=1.0, default= 0.01)
659
660 BoolProperty(   attr="pov_radio_always_sample",
661                                 name="Always Sample",
662                                 description="Only use the data from the pretrace step and not gather any new samples during the final radiosity pass..",
663                                 default= True)
664
665 FloatProperty(  attr="pov_radio_brightness",
666                                 name="Brightness",
667                                 description="Ammount objects are brightened before being returned upwards to the rest of the system.",
668                                 min=0.0, max=1000.0, soft_min=0.0, soft_max=10.0, default= 1.0)
669
670 IntProperty(    attr="pov_radio_count",
671                                 name="Ray Count",
672                                 description="number of rays that are sent out whenever a new radiosity value has to be calculated.",
673                                 min=1, max=1600, default= 35)
674
675 FloatProperty(  attr="pov_radio_error_bound",
676                                 name="Error Bound",
677                                 description="one of the two main speed/quality tuning values, lower values are more accurate.",
678                                 min=0.0, max=1000.0, soft_min=0.1, soft_max=10.0, default= 1.8)
679
680 FloatProperty(  attr="pov_radio_gray_threshold",
681                                 name="Gray Threshold",
682                                 description="one of the two main speed/quality tuning values, lower values are more accurate.",
683                                 min=0.0, max=1.0, soft_min=0, soft_max=1, default= 0.0)
684                                                                 
685 FloatProperty(  attr="pov_radio_low_error_factor",
686                                 name="Low Error Factor",
687                                 description="If you calculate just enough samples, but no more, you will get an image which has slightly blotchy lighting.",
688                                 min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default= 0.5)
689
690 # max_sample - not available yet
691 BoolProperty(   attr="pov_radio_media", 
692                                 name="Media",
693                                 description="Radiosity estimation can be affected by media.",
694                                 default= False)
695
696 FloatProperty(  attr="pov_radio_minimum_reuse",
697                                 name="Minimum Reuse",
698                                 description="Fraction of the screen width which sets the minimum radius of reuse for each sample point (At values higher than 2% expect errors).",
699                                 min=0.0, max=1.0, soft_min=0.1, soft_max=0.1, default= 0.015)
700                                 
701 IntProperty(    attr="pov_radio_nearest_count",
702                                 name="Nearest Count",
703                                 description="Number of old ambient values blended together to create a new interpolated value.",
704                                 min=1, max=20, default= 5)
705                                 
706 BoolProperty(   attr="pov_radio_normal",
707                                 name="Normals",
708                                 description="Radiosity estimation can be affected by normals.",
709                                 default= False)
710
711 IntProperty(    attr="pov_radio_recursion_limit",
712                                 name="Recursion Limit",
713                                 description="how many recursion levels are used to calculate the diffuse inter-reflection.",
714                                 min=1, max=20, default= 3)
715         
716
717 class PovrayRender(bpy.types.RenderEngine):
718         bl_idname = 'POVRAY_RENDER'
719         bl_label = "Povray"
720         DELAY = 0.02
721         
722         def _export(self, scene):
723                 import tempfile
724                 
725                 self._temp_file_in = tempfile.mktemp(suffix='.pov')
726                 self._temp_file_out = tempfile.mktemp(suffix='.tga')
727                 self._temp_file_ini = tempfile.mktemp(suffix='.ini')
728                 '''
729                 self._temp_file_in = '/test.pov'
730                 self._temp_file_out = '/test.tga'
731                 self._temp_file_ini = '/test.ini'
732                 '''
733                 
734                 def info_callback(txt):
735                         self.update_stats("", "POVRAY: " + txt)
736                         
737                 write_pov(self._temp_file_in, scene, info_callback)
738                 
739         def _render(self):
740                 
741                 try:            os.remove(self._temp_file_out) # so as not to load the old file
742                 except: pass
743                 
744                 write_pov_ini(self._temp_file_ini, self._temp_file_in, self._temp_file_out)
745                 
746                 print ("***-STARTING-***")
747                 
748                 pov_binary = "povray"
749                 
750                 if sys.platform=='win32':
751                         import winreg
752                         regKey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Software\\POV-Ray\\v3.6\\Windows')
753                         
754                         if bitness == 64:
755                                 pov_binary = winreg.QueryValueEx(regKey, 'Home')[0] + '\\bin\\pvengine64'
756                         else:
757                                 pov_binary = winreg.QueryValueEx(regKey, 'Home')[0] + '\\bin\\pvengine'
758                         
759                 if 1:
760                         self._process = subprocess.Popen([pov_binary, self._temp_file_ini]) # stdout=subprocess.PIPE, stderr=subprocess.PIPE
761                 else:
762                         # This works too but means we have to wait until its done
763                         os.system('%s %s' % (pov_binary, self._temp_file_ini))
764                 
765                 print ("***-DONE-***")
766         
767         def _cleanup(self):
768                 for f in (self._temp_file_in, self._temp_file_ini, self._temp_file_out):
769                         try:            os.remove(f)
770                         except: pass
771                 
772                 self.update_stats("", "")
773         
774         def render(self, scene):
775                 
776                 self.update_stats("", "POVRAY: Exporting data from Blender")
777                 self._export(scene)
778                 self.update_stats("", "POVRAY: Parsing File")
779                 self._render()
780                 
781                 r = scene.render_data
782                 
783                 # compute resolution
784                 x= int(r.resolution_x*r.resolution_percentage*0.01)
785                 y= int(r.resolution_y*r.resolution_percentage*0.01)
786
787                 # Wait for the file to be created
788                 while not os.path.exists(self._temp_file_out):
789                         if self.test_break():
790                                 try:            self._process.terminate()
791                                 except: pass
792                                 break
793                         
794                         if self._process.poll() != None:
795                                 self.update_stats("", "POVRAY: Failed")
796                                 break
797                         
798                         time.sleep(self.DELAY)
799                 
800                 if os.path.exists(self._temp_file_out):
801                         
802                         self.update_stats("", "POVRAY: Rendering")
803                         
804                         prev_size = -1
805                         
806                         def update_image():
807                                 result = self.begin_result(0, 0, x, y)
808                                 lay = result.layers[0]
809                                 # possible the image wont load early on.
810                                 try:            lay.load_from_file(self._temp_file_out)
811                                 except: pass
812                                 self.end_result(result)
813                         
814                         # Update while povray renders
815                         while True:
816                                 
817                                 # test if povray exists
818                                 if self._process.poll() != None:
819                                         update_image();
820                                         break
821                                 
822                                 # user exit
823                                 if self.test_break():
824                                         try:            self._process.terminate()
825                                         except: pass
826                                         
827                                         break
828                                 
829                                 # Would be nice to redirect the output
830                                 # stdout_value, stderr_value = self._process.communicate() # locks
831                                 
832                                 
833                                 # check if the file updated
834                                 new_size = os.path.getsize(self._temp_file_out)
835                                 
836                                 if new_size != prev_size:
837                                         update_image()
838                                         prev_size = new_size
839                                 
840                                 time.sleep(self.DELAY)
841                 
842                 self._cleanup()
843
844 bpy.types.register(PovrayRender)
845
846 # Use some of the existing buttons.
847 import properties_render
848 properties_render.RENDER_PT_render.COMPAT_ENGINES.add('POVRAY_RENDER')
849 properties_render.RENDER_PT_dimensions.COMPAT_ENGINES.add('POVRAY_RENDER')
850 properties_render.RENDER_PT_antialiasing.COMPAT_ENGINES.add('POVRAY_RENDER')
851 properties_render.RENDER_PT_output.COMPAT_ENGINES.add('POVRAY_RENDER')
852 del properties_render
853
854 # Use only a subset of the world panels
855 import properties_world
856 properties_world.WORLD_PT_preview.COMPAT_ENGINES.add('POVRAY_RENDER')
857 properties_world.WORLD_PT_context_world.COMPAT_ENGINES.add('POVRAY_RENDER')
858 properties_world.WORLD_PT_world.COMPAT_ENGINES.add('POVRAY_RENDER')
859 properties_world.WORLD_PT_mist.COMPAT_ENGINES.add('POVRAY_RENDER')
860 del properties_world
861
862 # Example of wrapping every class 'as is'
863 import properties_material
864 for member in dir(properties_material):
865         subclass = getattr(properties_material, member)
866         try:            subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
867         except: pass
868 del properties_material
869
870 class RenderButtonsPanel(bpy.types.Panel):
871         bl_space_type = 'PROPERTIES'
872         bl_region_type = 'WINDOW'
873         bl_context = "render"
874         # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
875         
876         def poll(self, context):
877                 rd = context.scene.render_data
878                 return (rd.use_game_engine==False) and (rd.engine in self.COMPAT_ENGINES)
879
880 class RENDER_PT_povray_radiosity(RenderButtonsPanel):
881         bl_label = "Radiosity"
882         COMPAT_ENGINES = set(['POVRAY_RENDER'])
883
884         def draw_header(self, context):
885                 scene = context.scene
886
887                 self.layout.prop(scene, "pov_radio_enable", text="")
888
889         def draw(self, context):
890                 layout = self.layout
891
892                 scene = context.scene
893                 rd = scene.render_data
894                 
895                 layout.active = scene.pov_radio_enable
896                 
897                 split = layout.split()
898                 
899                 col = split.column()
900                 col.prop(scene, "pov_radio_count", text="Rays")
901                 col.prop(scene, "pov_radio_recursion_limit", text="Recursions")
902                 col = split.column()
903                 col.prop(scene, "pov_radio_error_bound", text="Error")
904                 
905                 layout.prop(scene, "pov_radio_display_advanced")
906                 
907                 if scene.pov_radio_display_advanced:
908                         split = layout.split()
909                 
910                         col = split.column()
911                         col.prop(scene, "pov_radio_adc_bailout", slider=True)
912                         col.prop(scene, "pov_radio_gray_threshold", slider=True)
913                         col.prop(scene, "pov_radio_low_error_factor", slider=True)
914
915                         col = split.column()
916                         col.prop(scene, "pov_radio_brightness")
917                         col.prop(scene, "pov_radio_minimum_reuse", text="Min Reuse")
918                         col.prop(scene, "pov_radio_nearest_count")
919
920                         split = layout.split()
921                 
922                         col = split.column()
923                         col.label(text="Estimation Influence:")
924                         col.prop(scene, "pov_radio_media")
925                         col.prop(scene, "pov_radio_normal")
926                         
927                         col = split.column()
928                         col.prop(scene, "pov_radio_always_sample")
929
930 bpy.types.register(RENDER_PT_povray_radiosity)