Skip to content
Snippets Groups Projects
render.py 171 KiB
Newer Older
  • Learn to ignore specific revisions
  • # ***** BEGIN GPL LICENSE BLOCK *****
    #
    # This program is free software; you can redistribute it and/or
    # modify it under the terms of the GNU General Public License
    # as published by the Free Software Foundation; either version 2
    # of the License, or (at your option) any later version.
    #
    # This program is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    # GNU General Public License for more details.
    #
    # You should have received a copy of the GNU General Public License
    # along with this program; if not, write to the Free Software Foundation,
    # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
    #
    # #**** END GPL LICENSE BLOCK #****
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    import bpy
    
    import subprocess
    import os
    import sys
    import time
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    from math import atan, pi, degrees, sqrt
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    import random
    
    import platform#
    import subprocess#
    from bpy.types import(Operator)#all added for render preview
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    ##############################SF###########################
    
    ##############find image texture
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    def imageFormat(imgF):
    
        ext = {
            'JPG': "jpeg",
            'JPEG': "jpeg",
            'GIF': "gif",
            'TGA': "tga",
            'IFF': "iff",
            'PPM': "ppm",
            'PNG': "png",
            'SYS': "sys",
            'TIFF': "tiff",
            'TIF': "tiff",
    
            'EXR': "exr",
            'HDR': "hdr",
    
        }.get(os.path.splitext(imgF)[-1].upper(), "")
    
    
            print(" WARNING: texture image format not supported ")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        return ext
    
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    def imgMap(ts):
    
        image_map = ""
        if ts.mapping == 'FLAT':
            image_map = "map_type 0 "
        elif ts.mapping == 'SPHERE':
    
            image_map = "map_type 1 " 
    
        elif ts.mapping == 'TUBE':
            image_map = "map_type 2 "
    
    
        ## map_type 3 and 4 in development (?)
        ## for POV-Ray, currently they just seem to default back to Flat (type 0)
    
        #    image_map = " map_type 3 "
    
        #    image_map = " map_type 4 "
    
        if ts.texture.use_interpolation:
            image_map += " interpolate 2 "
        if ts.texture.extension == 'CLIP':
            image_map += " once "
        #image_map += "}"
        #if ts.mapping=='CUBE':
    
        #    image_map+= "warp { cubic } rotate <-90,0,180>"
        # no direct cube type mapping. Though this should work in POV 3.7
        # it doesn't give that good results(best suited to environment maps?)
    
        #if image_map == "":
    
        #    print(" No texture image  found ")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        return image_map
    
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    def imgMapBG(wts):
    
        image_mapBG = ""
    
        # texture_coords refers to the mapping of world textures:
    
        if wts.texture_coords == 'VIEW':
    
            image_mapBG = " map_type 0 "
    
        elif wts.texture_coords == 'ANGMAP':
            image_mapBG = " map_type 1 "
        elif wts.texture_coords == 'TUBE':
            image_mapBG = " map_type 2 "
    
        if wts.texture.use_interpolation:
            image_mapBG += " interpolate 2 "
        if wts.texture.extension == 'CLIP':
            image_mapBG += " once "
    
        #image_mapBG += "}"
        #if wts.mapping == 'CUBE':
    
        #   image_mapBG += "warp { cubic } rotate <-90,0,180>"
        # no direct cube type mapping. Though this should work in POV 3.7
        # it doesn't give that good results(best suited to environment maps?)
    
        #if image_mapBG == "":
        #    print(" No background texture image  found ")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        return image_mapBG
    
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    def path_image(image):
    
    Campbell Barton's avatar
    Campbell Barton committed
        return bpy.path.abspath(image.filepath, library=image.library)
    
    Campbell Barton's avatar
    Campbell Barton committed
    # end find image texture
    # -----------------------------------------------------------------------------
    
    Campbell Barton's avatar
    Campbell Barton committed
    def string_strip_hyphen(name):
        return name.replace("-", "")
    
    def safety(name, Level):
    
        # safety string name material
        #
    
        # Level=1 is for texture with No specular nor Mirror reflection
    
        # Level=2 is for texture with translation of spec and mir levels
        # for when no map influences them
    
        # Level=3 is for texture with Maximum Spec and Mirror
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        try:
    
    Campbell Barton's avatar
    Campbell Barton committed
            if int(name) > 0:
    
                prefix = "shader"
    
    Campbell Barton's avatar
    Campbell Barton committed
        except:
    
        prefix = "shader_"
    
    Campbell Barton's avatar
    Campbell Barton committed
        name = string_strip_hyphen(name)
    
            return prefix + name
    
            return prefix + name + "0"  # used for 0 of specular map
    
            return prefix + name + "1"  # used for 1 of specular map
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    ##############end safety string name material
    ##############################EndSF###########################
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
    def is_renderable(ob):
        return (ob.hide_render==False)
    
    def renderable_objects():
        return [ob for ob in bpy.data.objects if is_renderable(ob)]
    
    unpacked_images=[]
     
    def exportPattern(texture):
        tex=texture
        pat = tex.pov
        PATname = "PAT_%s"%string_strip_hyphen(bpy.path.clean_name(tex.name))
        mappingDif = ("translate <%.4g,%.4g,%.4g> scale <%.4g,%.4g,%.4g>" % \
              (pat.tex_mov_x, pat.tex_mov_y, pat.tex_mov_z,
               1.0 / pat.tex_scale_x, 1.0 / pat.tex_scale_y, 1.0 / pat.tex_scale_z))
        texStrg=""
        def exportColorRamp(texture):
            tex=texture
            pat = tex.pov      
            colRampStrg="color_map {\n"
            numColor=0
            for el in tex.color_ramp.elements:
                numColor+=1
                pos = el.position
                col=el.color
                colR,colG,colB,colA = col[0],col[1],col[2],1-col[3]
                if pat.tex_pattern_type not in {'checker', 'hexagon', 'square', 'triangular', 'brick'} :
                    colRampStrg+="[%.4g color rgbf<%.4g,%.4g,%.4g,%.4g>] \n"%(pos,colR,colG,colB,colA)
                if pat.tex_pattern_type in {'brick','checker'} and numColor < 3:
                    colRampStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
                if pat.tex_pattern_type == 'hexagon' and numColor < 4 :
                    colRampStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
                if pat.tex_pattern_type == 'square' and numColor < 5 :
                    colRampStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
                if pat.tex_pattern_type == 'triangular' and numColor < 7 :
                    colRampStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
                          
            colRampStrg+="} \n"
            #end color map
            return colRampStrg
        #much work to be done here only defaults translated for now:
        #pov noise_generator 3 means perlin noise
        if pat.tex_pattern_type == 'emulator':
            texStrg+="pigment {\n"
            ####################### EMULATE BLENDER VORONOI TEXTURE ####################
            if tex.type == 'VORONOI':  
                texStrg+="crackle\n"
                texStrg+="    offset %.4g\n"%tex.nabla
                texStrg+="    form <%.4g,%.4g,%.4g>\n"%(tex.weight_1, tex.weight_2, tex.weight_3)
                if tex.distance_metric == 'DISTANCE':
                    texStrg+="    metric 2.5\n"          
                if tex.distance_metric == 'DISTANCE_SQUARED':
                    texStrg+="    metric 2.5\n"
                    texStrg+="    poly_wave 2\n"                
                if tex.distance_metric == 'MINKOVSKY': 
                    texStrg+="    metric %s\n"%tex.minkovsky_exponent             
                if tex.distance_metric == 'MINKOVSKY_FOUR': 
                    texStrg+="    metric 4\n"
                if tex.distance_metric == 'MINKOVSKY_HALF': 
                    texStrg+="    metric 0.5\n"
                if tex.distance_metric == 'CHEBYCHEV': 
                    texStrg+="    metric 10\n"
                if tex.distance_metric == 'MANHATTAN': 
                    texStrg+="    metric 1\n"
    
                if tex.color_mode == 'POSITION':
                    texStrg+="solid\n"
                texStrg+="scale 0.25\n"
                
                if tex.use_color_ramp == True:
                    texStrg+=exportColorRamp(tex)
                else:
                    texStrg+="color_map {\n"
                    texStrg+="[0 color rgbt<0,0,0,1>]\n"
                    texStrg+="[1 color rgbt<1,1,1,0>]\n" 
                    texStrg+="}\n"            
            ####################### EMULATE BLENDER CLOUDS TEXTURE ####################
            if tex.type == 'CLOUDS':  
                if tex.noise_type == 'SOFT_NOISE':
                    texStrg+="wrinkles\n"
                    texStrg+="scale 0.25\n"
                else:
                    texStrg+="granite\n"
                if tex.use_color_ramp == True:
                    texStrg+=exportColorRamp(tex)
                else:
                    texStrg+="color_map {\n"
                    texStrg+="[0 color rgbt<0,0,0,1>]\n"
                    texStrg+="[1 color rgbt<1,1,1,0>]\n" 
                    texStrg+="}\n"
            ####################### EMULATE BLENDER WOOD TEXTURE ####################
            if tex.type == 'WOOD':
                if tex.wood_type == 'RINGS':
                    texStrg+="wood\n"
                    texStrg+="scale 0.25\n"
                if tex.wood_type == 'RINGNOISE':
                    texStrg+="wood\n"
                    texStrg+="scale 0.25\n"
                    texStrg+="turbulence %.4g\n"%(tex.turbulence/100)
                if tex.wood_type == 'BANDS':
                    texStrg+="marble\n"
                    texStrg+="scale 0.25\n"
                    texStrg+="rotate <45,-45,45>\n"
                if tex.wood_type == 'BANDNOISE':
                    texStrg+="marble\n"
                    texStrg+="scale 0.25\n"
                    texStrg+="rotate <45,-45,45>\n"
                    texStrg+="turbulence %.4g\n"%(tex.turbulence/10)
                
                if tex.noise_basis_2 == 'SIN':
                    texStrg+="sine_wave\n"
                if tex.noise_basis_2 == 'TRI':
                    texStrg+="triangle_wave\n"
                if tex.noise_basis_2 == 'SAW':
                    texStrg+="ramp_wave\n"
                if tex.use_color_ramp == True:
                    texStrg+=exportColorRamp(tex)
                else:
                    texStrg+="color_map {\n"
                    texStrg+="[0 color rgbt<0,0,0,0>]\n"
                    texStrg+="[1 color rgbt<1,1,1,0>]\n" 
                    texStrg+="}\n"
            ####################### EMULATE BLENDER STUCCI TEXTURE ####################
            if tex.type == 'STUCCI':  
                texStrg+="bozo\n"
                texStrg+="scale 0.25\n"
                if tex.noise_type == 'HARD_NOISE':
                    texStrg+="triangle_wave\n"
                    if tex.use_color_ramp == True:
                        texStrg+=exportColorRamp(tex)
                    else:
                        texStrg+="color_map {\n"
                        texStrg+="[0 color rgbf<1,1,1,0>]\n"
                        texStrg+="[1 color rgbt<0,0,0,1>]\n"
                        texStrg+="}\n"
                else:
                    if tex.use_color_ramp == True:
                        texStrg+=exportColorRamp(tex)
                    else:
                        texStrg+="color_map {\n"
                        texStrg+="[0 color rgbf<0,0,0,1>]\n"
                        texStrg+="[1 color rgbt<1,1,1,0>]\n"
                        texStrg+="}\n"
            ####################### EMULATE BLENDER MAGIC TEXTURE ####################
            if tex.type == 'MAGIC':  
                texStrg+="leopard\n"
                if tex.use_color_ramp == True:
                    texStrg+=exportColorRamp(tex)
                else:
                    texStrg+="color_map {\n"
                    texStrg+="[0 color rgbt<1,1,1,0.5>]\n"
                    texStrg+="[0.25 color rgbf<0,1,0,0.75>]\n"
                    texStrg+="[0.5 color rgbf<0,0,1,0.75>]\n"
                    texStrg+="[0.75 color rgbf<1,0,1,0.75>]\n"
                    texStrg+="[1 color rgbf<0,1,0,0.75>]\n"
                    texStrg+="}\n"
                texStrg+="scale 0.1\n"            
            ####################### EMULATE BLENDER MARBLE TEXTURE ####################
            if tex.type == 'MARBLE':  
                texStrg+="marble\n"
                texStrg+="turbulence 0.5\n"
                texStrg+="noise_generator 3\n"
                texStrg+="scale 0.75\n"
                texStrg+="rotate <45,-45,45>\n"
                if tex.use_color_ramp == True:
                    texStrg+=exportColorRamp(tex)
                else:
                    if tex.marble_type == 'SOFT':
                        texStrg+="color_map {\n"
                        texStrg+="[0 color rgbt<0,0,0,0>]\n"
                        texStrg+="[0.05 color rgbt<0,0,0,0>]\n"
                        texStrg+="[1 color rgbt<0.9,0.9,0.9,0>]\n"
                        texStrg+="}\n"
                    elif tex.marble_type == 'SHARP':
                        texStrg+="color_map {\n"
                        texStrg+="[0 color rgbt<0,0,0,0>]\n"
                        texStrg+="[0.025 color rgbt<0,0,0,0>]\n"
                        texStrg+="[1 color rgbt<0.9,0.9,0.9,0>]\n"
                        texStrg+="}\n"
                    else:
                        texStrg+="[0 color rgbt<0,0,0,0>]\n"
                        texStrg+="[1 color rgbt<1,1,1,0>]\n"            
                        texStrg+="}\n"
                if tex.noise_basis_2 == 'SIN':
                    texStrg+="sine_wave\n"
                if tex.noise_basis_2 == 'TRI':
                    texStrg+="triangle_wave\n"
                if tex.noise_basis_2 == 'SAW':
                    texStrg+="ramp_wave\n"
            ####################### EMULATE BLENDER BLEND TEXTURE ####################
            if tex.type == 'BLEND':
                if tex.progression=='RADIAL':
                    texStrg+="radial\n"
                    if tex.use_flip_axis=='HORIZONTAL':
                        texStrg+="rotate x*90\n"
                    else:
                        texStrg+="rotate <-90,0,90>\n"
                    texStrg+="ramp_wave\n"
                elif tex.progression=='SPHERICAL':
                    texStrg+="spherical\n"
                    texStrg+="scale 3\n"
                    texStrg+="poly_wave 1\n"
                elif tex.progression=='QUADRATIC_SPHERE':
                    texStrg+="spherical\n"
                    texStrg+="scale 3\n"
                    texStrg+="    poly_wave 2\n"
                elif tex.progression=='DIAGONAL':
                    texStrg+="gradient <1,1,0>\n"
                    texStrg+="scale 3\n"
                elif tex.use_flip_axis=='HORIZONTAL':        
                    texStrg+="gradient x\n"
                    texStrg+="scale 2.01\n"
                elif tex.use_flip_axis=='VERTICAL':
                    texStrg+="gradient y\n"
                    texStrg+="scale 2.01\n"
                #texStrg+="ramp_wave\n"
                #texStrg+="frequency 0.5\n"
                texStrg+="phase 0.5\n"
                if tex.use_color_ramp == True:
                    texStrg+=exportColorRamp(tex)
                else:
                    texStrg+="color_map {\n"
                    texStrg+="[0 color rgbt<1,1,1,0>]\n"
                    texStrg+="[1 color rgbf<0,0,0,1>]\n"
                    texStrg+="}\n"
                if tex.progression == 'LINEAR': 
                    texStrg+="    poly_wave 1\n"
                if tex.progression == 'QUADRATIC': 
                    texStrg+="    poly_wave 2\n"
                if tex.progression == 'EASING':
                    texStrg+="    poly_wave 1.5\n"            
            ####################### EMULATE BLENDER MUSGRAVE TEXTURE ####################
            # if tex.type == 'MUSGRAVE':  
                # texStrg+="function{ f_ridged_mf( x, y, 0, 1, 2, 9, -0.5, 3,3 )*0.5}\n"
                # texStrg+="color_map {\n"
                # texStrg+="[0 color rgbf<0,0,0,1>]\n"
                # texStrg+="[1 color rgbf<1,1,1,0>]\n"
                # texStrg+="}\n"
            # simplified for now:
    
            if tex.type == 'MUSGRAVE':
                texStrg+="bozo scale 0.25 \n"
                if tex.use_color_ramp == True:
                    texStrg+=exportColorRamp(tex)
                else: 
                    texStrg+="color_map {[0.5 color rgbf<0,0,0,1>][1 color rgbt<1,1,1,0>]}ramp_wave \n"            
            ####################### EMULATE BLENDER DISTORTED NOISE TEXTURE ####################
            if tex.type == 'DISTORTED_NOISE':  
                texStrg+="average\n"
                texStrg+="  pigment_map {\n"
                texStrg+="  [1 bozo scale 0.25 turbulence %.4g\n" %tex.distortion
                if tex.use_color_ramp == True:
                    texStrg+=exportColorRamp(tex)
                else: 
                    texStrg+="color_map {\n"
                    texStrg+="[0 color rgbt<1,1,1,0>]\n"
                    texStrg+="[1 color rgbf<0,0,0,1>]\n"
                    texStrg+="}\n"
                texStrg+="]\n"
    
                if tex.noise_distortion == 'CELL_NOISE':
                    texStrg+="  [1 cells scale 0.1\n"
                    if tex.use_color_ramp == True:
                        texStrg+=exportColorRamp(tex)
                    else: 
                        texStrg+="color_map {\n"
                        texStrg+="[0 color rgbt<1,1,1,0>]\n"
                        texStrg+="[1 color rgbf<0,0,0,1>]\n"
                        texStrg+="}\n"
                    texStrg+="]\n"                
                if tex.noise_distortion=='VORONOI_CRACKLE':
                    texStrg+="  [1 crackle scale 0.25\n"
                    if tex.use_color_ramp == True:
                        texStrg+=exportColorRamp(tex)
                    else: 
                        texStrg+="color_map {\n"
                        texStrg+="[0 color rgbt<1,1,1,0>]\n"
                        texStrg+="[1 color rgbf<0,0,0,1>]\n"
                        texStrg+="}\n"
                    texStrg+="]\n"                
                if tex.noise_distortion in ['VORONOI_F1','VORONOI_F2','VORONOI_F3','VORONOI_F4','VORONOI_F2_F1']:
                    texStrg+="  [1 crackle metric 2.5 scale 0.25 turbulence %.4g\n" %(tex.distortion/2)
                    if tex.use_color_ramp == True:
                        texStrg+=exportColorRamp(tex)
                    else: 
                        texStrg+="color_map {\n"
                        texStrg+="[0 color rgbt<1,1,1,0>]\n"
                        texStrg+="[1 color rgbf<0,0,0,1>]\n"
                        texStrg+="}\n"
                    texStrg+="]\n"                
                else:
                    texStrg+="  [1 wrinkles scale 0.25\n" 
                    if tex.use_color_ramp == True:
                        texStrg+=exportColorRamp(tex)
                    else: 
                        texStrg+="color_map {\n"
                        texStrg+="[0 color rgbt<1,1,1,0>]\n"
                        texStrg+="[1 color rgbf<0,0,0,1>]\n"
                        texStrg+="}\n"
                    texStrg+="]\n"
                texStrg+="  }\n"
            ####################### EMULATE BLENDER NOISE TEXTURE ####################
            if tex.type == 'NOISE':  
                texStrg+="cells\n"
                texStrg+="turbulence 3\n"
                texStrg+="omega 3\n"
                if tex.use_color_ramp == True:
                    texStrg+=exportColorRamp(tex)
                else: 
                    texStrg+="color_map {\n"
                    texStrg+="[0.75 color rgb<0,0,0,>]\n"
                    texStrg+="[1 color rgb<1,1,1,>]\n"
                    texStrg+="}\n"
    
            ####################### IGNORE OTHER BLENDER TEXTURE ####################
            else: #non translated textures
                pass
            texStrg+="}\n\n"            
    
            texStrg+="#declare f%s=\n"%PATname
            texStrg+="function{pigment{%s}}\n"%PATname       
            texStrg+="\n"
            
        else:
            texStrg+="pigment {\n"
            texStrg+="%s\n"%pat.tex_pattern_type
            if pat.tex_pattern_type == 'agate': 
                texStrg+="agate_turb %.4g\n"%pat.modifier_turbulence                           
            if pat.tex_pattern_type in {'spiral1', 'spiral2', 'tiling'}: 
                texStrg+="%s\n"%pat.modifier_numbers
            if pat.tex_pattern_type == 'quilted': 
                texStrg+="control0 %s control1 %s\n"%(pat.modifier_control0, pat.modifier_control1)                           
            if pat.tex_pattern_type == 'mandel': 
                texStrg+="%s exponent %s \n"%(pat.f_iter, pat.f_exponent)  
            if pat.tex_pattern_type == 'julia': 
                texStrg+="<%.4g, %.4g> %s exponent %s \n"%(pat.julia_complex_1, pat.julia_complex_2, pat.f_iter, pat.f_exponent)   
            if pat.tex_pattern_type == 'magnet' and pat.magnet_style == 'mandel': 
                texStrg+="%s mandel %s \n"%(pat.magnet_type, pat.f_iter)
            if pat.tex_pattern_type == 'magnet' and pat.magnet_style == 'julia':  
                texStrg+="%s julia <%.4g, %.4g> %s\n"%(pat.magnet_type, pat.julia_complex_1, pat.julia_complex_2, pat.f_iter) 
            if pat.tex_pattern_type in {'mandel', 'julia', 'magnet'}:
                texStrg+="interior %s, %.4g\n"%(pat.f_ior, pat.f_ior_fac) 
                texStrg+="exterior %s, %.4g\n"%(pat.f_eor, pat.f_eor_fac)
            if pat.tex_pattern_type == 'gradient': 
                texStrg+="<%s, %s, %s> \n"%(pat.grad_orient_x, pat.grad_orient_y, pat.grad_orient_z)
            if pat.tex_pattern_type == 'pavement':
                numTiles=pat.pave_tiles
                numPattern=1
                if pat.pave_sides == '4' and pat.pave_tiles == 3: 
                     numPattern = pat.pave_pat_2
                if pat.pave_sides == '6' and pat.pave_tiles == 3: 
                    numPattern = pat.pave_pat_3
                if pat.pave_sides == '3' and pat.pave_tiles == 4: 
                    numPattern = pat.pave_pat_3
                if pat.pave_sides == '3' and pat.pave_tiles == 5: 
                    numPattern = pat.pave_pat_4
                if pat.pave_sides == '4' and pat.pave_tiles == 4: 
                    numPattern = pat.pave_pat_5
                if pat.pave_sides == '6' and pat.pave_tiles == 4: 
                    numPattern = pat.pave_pat_7
                if pat.pave_sides == '4' and pat.pave_tiles == 5: 
                    numPattern = pat.pave_pat_12
                if pat.pave_sides == '3' and pat.pave_tiles == 6: 
                    numPattern = pat.pave_pat_12
                if pat.pave_sides == '6' and pat.pave_tiles == 5: 
                    numPattern = pat.pave_pat_22
                if pat.pave_sides == '4' and pat.pave_tiles == 6: 
                    numPattern = pat.pave_pat_35
                if pat.pave_sides == '6' and pat.pave_tiles == 6: 
                    numTiles = 5                                
                texStrg+="number_of_sides %s number_of_tiles %s pattern %s form %s \n"%(pat.pave_sides, numTiles, numPattern, pat.pave_form)
            ################ functions #####################################################################################################
            if pat.tex_pattern_type == 'function':                 
                texStrg+="{ %s"%pat.func_list
                texStrg+="(x"
                if pat.func_plus_x != "NONE":
                    if pat.func_plus_x =='increase':
                        texStrg+="*"                                    
                    if pat.func_plus_x =='plus':
                        texStrg+="+"
                    texStrg+="%.4g"%pat.func_x
                texStrg+=",y"
                if pat.func_plus_y != "NONE":
                    if pat.func_plus_y =='increase':
                        texStrg+="*"                                   
                    if pat.func_plus_y =='plus':
                        texStrg+="+"
                    texStrg+="%.4g"%pat.func_y
                texStrg+=",z"
                if pat.func_plus_z != "NONE":
                    if pat.func_plus_z =='increase':
                        texStrg+="*"                                    
                    if pat.func_plus_z =='plus':
                        texStrg+="+"
                    texStrg+="%.4g"%pat.func_z
                sort = -1
                if pat.func_list in {"f_comma","f_crossed_trough","f_cubic_saddle","f_cushion","f_devils_curve",
                                     "f_enneper","f_glob","f_heart","f_hex_x","f_hex_y","f_hunt_surface",
                                     "f_klein_bottle","f_kummer_surface_v1","f_lemniscate_of_gerono","f_mitre",
                                     "f_nodal_cubic","f_noise_generator","f_odd","f_paraboloid","f_pillow",
                                     "f_piriform","f_quantum","f_quartic_paraboloid","f_quartic_saddle",
                                     "f_sphere","f_steiners_roman","f_torus_gumdrop","f_umbrella"}:
                    sort = 0
                if pat.func_list in {"f_bicorn","f_bifolia","f_boy_surface","f_superellipsoid","f_torus"}:
                    sort = 1
                if pat.func_list in {"f_ellipsoid","f_folium_surface","f_hyperbolic_torus",
                                     "f_kampyle_of_eudoxus","f_parabolic_torus","f_quartic_cylinder","f_torus2"}:
                    sort = 2
                if pat.func_list in {"f_blob2","f_cross_ellipsoids","f_flange_cover","f_isect_ellipsoids",
                                     "f_kummer_surface_v2","f_ovals_of_cassini","f_rounded_box","f_spikes_2d","f_strophoid"}:
                    sort = 3
                if pat.func_list in {"f_algbr_cyl1","f_algbr_cyl2","f_algbr_cyl3","f_algbr_cyl4","f_blob","f_mesh1","f_poly4","f_spikes"}:
                    sort = 4
                if pat.func_list in {"f_devils_curve_2d","f_dupin_cyclid","f_folium_surface_2d","f_hetero_mf","f_kampyle_of_eudoxus_2d",
                                     "f_lemniscate_of_gerono_2d","f_polytubes","f_ridge","f_ridged_mf","f_spiral","f_witch_of_agnesi"}:
                    sort = 5
                if pat.func_list in {"f_helix1","f_helix2","f_piriform_2d","f_strophoid_2d"}:
                    sort = 6
                if pat.func_list == "f_helical_torus":
                    sort = 7
                if sort > -1:
                    texStrg+=",%.4g"%pat.func_P0
                if sort > 0:
                    texStrg+=",%.4g"%pat.func_P1
                if sort > 1:
                    texStrg+=",%.4g"%pat.func_P2
                if sort > 2:
                    texStrg+=",%.4g"%pat.func_P3
                if sort > 3:
                    texStrg+=",%.4g"%pat.func_P4
                if sort > 4:
                    texStrg+=",%.4g"%pat.func_P5
                if sort > 5:
                    texStrg+=",%.4g"%pat.func_P6
                if sort > 6:
                    texStrg+=",%.4g"%pat.func_P7
                    texStrg+=",%.4g"%pat.func_P8
                    texStrg+=",%.4g"%pat.func_P9
                texStrg+=")}\n"
            ############## end functions ###############################################################
            if pat.tex_pattern_type not in {'checker', 'hexagon', 'square', 'triangular', 'brick'}:                        
                texStrg+="color_map {\n"
            numColor=0
            if tex.use_color_ramp == True:
                for el in tex.color_ramp.elements:
                    numColor+=1
                    pos = el.position
                    col=el.color
                    colR,colG,colB,colA = col[0],col[1],col[2],1-col[3]
                    if pat.tex_pattern_type not in {'checker', 'hexagon', 'square', 'triangular', 'brick'} :
                        texStrg+="[%.4g color rgbf<%.4g,%.4g,%.4g,%.4g>] \n"%(pos,colR,colG,colB,colA)
                    if pat.tex_pattern_type in {'brick','checker'} and numColor < 3:
                        texStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
                    if pat.tex_pattern_type == 'hexagon' and numColor < 4 :
                        texStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
                    if pat.tex_pattern_type == 'square' and numColor < 5 :
                        texStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
                    if pat.tex_pattern_type == 'triangular' and numColor < 7 :
                        texStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
            else:
                texStrg+="[0 color rgbf<0,0,0,1>]\n"
                texStrg+="[1 color rgbf<1,1,1,0>]\n"
            if pat.tex_pattern_type not in {'checker', 'hexagon', 'square', 'triangular', 'brick'} :                        
                texStrg+="} \n"                       
            if pat.tex_pattern_type == 'brick':                        
                texStrg+="brick_size <%.4g, %.4g, %.4g> mortar %.4g \n"%(pat.brick_size_x, pat.brick_size_y, pat.brick_size_z, pat.brick_mortar)
            texStrg+="%s \n"%mappingDif
            texStrg+="rotate <%.4g,%.4g,%.4g> \n"%(pat.tex_rot_x, pat.tex_rot_y, pat.tex_rot_z)
            texStrg+="turbulence <%.4g,%.4g,%.4g> \n"%(pat.warp_turbulence_x, pat.warp_turbulence_y, pat.warp_turbulence_z)
            texStrg+="octaves %s \n"%pat.modifier_octaves
            texStrg+="lambda %.4g \n"%pat.modifier_lambda
            texStrg+="omega %.4g \n"%pat.modifier_omega
            texStrg+="frequency %.4g \n"%pat.modifier_frequency
            texStrg+="phase %.4g \n"%pat.modifier_phase                       
            texStrg+="}\n\n"
            texStrg+="#declare f%s=\n"%PATname
            texStrg+="function{pigment{%s}}\n"%PATname       
            texStrg+="\n"
        return(texStrg)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    def write_pov(filename, scene=None, info_callback=None):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        #file = filename
    
        file = open(filename, "w")
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
        # Only for testing
        if not scene:
            scene = bpy.data.scenes[0]
    
        render = scene.render
        world = scene.world
    
        global_matrix = mathutils.Matrix.Rotation(-pi / 2.0, 4, 'X')
    
        comments = scene.pov.comments_enable and not scene.pov.tempfiles_enable
        linebreaksinlists= scene.pov.list_lf_enable and not scene.pov.tempfiles_enable
    
        tab = setTab(scene.pov.indentation_character, scene.pov.indentation_spaces)
    
        if not scene.pov.tempfiles_enable:
            def tabWrite(str_o):
    
                global tabLevel
                brackets = str_o.count("{") - str_o.count("}") + str_o.count("[") - str_o.count("]")
                if brackets < 0:
                    tabLevel = tabLevel + brackets
                if tabLevel < 0:
                    print("Indentation Warning: tabLevel = %s" % tabLevel)
                    tabLevel = 0
                if tabLevel >= 1:
                    file.write("%s" % tab * tabLevel)
                file.write(str_o)
                if brackets > 0:
                    tabLevel = tabLevel + brackets
    
        else:
            def tabWrite(str_o):
    
                file.write(str_o)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        def uniqueName(name, nameSeq):
    
            if name not in nameSeq:
    
    Campbell Barton's avatar
    Campbell Barton committed
                name = string_strip_hyphen(name)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                return name
    
            name_orig = name
            i = 1
            while name in nameSeq:
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                i += 1
    
    Campbell Barton's avatar
    Campbell Barton committed
            name = string_strip_hyphen(name)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            return name
    
        def writeMatrix(matrix):
    
            tabWrite("matrix <%.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, %.6f>\n" %
                     (matrix[0][0], matrix[1][0], matrix[2][0],
                      matrix[0][1], matrix[1][1], matrix[2][1],
                      matrix[0][2], matrix[1][2], matrix[2][2],
                      matrix[0][3], matrix[1][3], matrix[2][3]))
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
            sMatrix = ("matrix <%.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, %.6f>\n" %
                       (matrix[0][0], matrix[1][0], matrix[2][0],
                        matrix[0][1], matrix[1][1], matrix[2][1],
                        matrix[0][2], matrix[1][2], matrix[2][2],
                        matrix[0][3], matrix[1][3], matrix[2][3]))
    
        def writeObjectMaterial(material, ob):
    
            # DH - modified some variables to be function local, avoiding RNA write
            # this should be checked to see if it is functionally correct
    
            # Commented out: always write IOR to be able to use it for SSS, Fresnel reflections...
            #if material and material.transparency_method == 'RAYTRACE':
            if material:
    
                # But there can be only one!
                if material.subsurface_scattering.use:  # SSS IOR get highest priority
    
                    tabWrite("interior {\n")
                    tabWrite("ior %.6f\n" % material.subsurface_scattering.ior)
    
                # Then the raytrace IOR taken from raytrace transparency properties and used for
                # reflections if IOR Mirror option is checked.
                elif material.pov.mirror_use_IOR:
    
                    tabWrite("interior {\n")
                    tabWrite("ior %.6f\n" % material.raytrace_transparency.ior)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                else:
    
                    tabWrite("interior {\n")
                    tabWrite("ior %.6f\n" % material.raytrace_transparency.ior)
    
                pov_fake_caustics = False
                pov_photons_refraction = False
                pov_photons_reflection = False
    
                    pov_photons_reflection = True
    
                    pov_fake_caustics = False
                    pov_photons_refraction = False
    
                    pov_fake_caustics = True
                    pov_photons_refraction = False
    
                    pov_fake_caustics = False
                    pov_photons_refraction = True
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                # If only Raytrace transparency is set, its IOR will be used for refraction, but user
                # can set up 'un-physical' fresnel reflections in raytrace mirror parameters.
                # Last, if none of the above is specified, user can set up 'un-physical' fresnel
                # reflections in raytrace mirror parameters. And pov IOR defaults to 1.
                if material.pov.caustics_enable:
    
                        tabWrite("caustics %.3g\n" % material.pov.fake_caustics_power)
    
                        # Default of 1 means no dispersion
                        tabWrite("dispersion %.6f\n" % material.pov.photons_dispersion)
    
                        tabWrite("dispersion_samples %.d\n" % material.pov.photons_dispersion_samples)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                # Other interior args
    
                if material.use_transparency and material.transparency_method == 'RAYTRACE':
                    # fade_distance
    
                    # In Blender this value has always been reversed compared to what tooltip says.
                    # 100.001 rather than 100 so that it does not get to 0
    
                    # which deactivates the feature in POV
    
                    tabWrite("fade_distance %.3g\n" % \
                             (100.001 - material.raytrace_transparency.depth_max))
    
                    # fade_power
                    tabWrite("fade_power %.3g\n" % material.raytrace_transparency.falloff)
                    # fade_color
    
                    tabWrite("fade_color <%.3g, %.3g, %.3g>\n" % material.pov.interior_fade_color[:])
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                # (variable) dispersion_samples (constant count for now)
    
                if material.pov.photons_reflection or material.pov.refraction_type=="2":
                    tabWrite("photons{")
    
                    tabWrite("target %.3g\n" % ob.pov.spacing_multiplier)
    
                    if not ob.pov.collect_photons:
                        tabWrite("collect off\n")
                    if pov_photons_refraction:
                        tabWrite("refraction on\n")
                    if pov_photons_reflection:
                        tabWrite("reflection on\n")
                    tabWrite("}\n")
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        materialNames = {}
    
        DEF_MAT_NAME = "" #or "Default"?
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
        def writeMaterial(material):
            # Assumes only called once on each material
            if material:
                name_orig = material.name
    
                name = materialNames[name_orig] = uniqueName(bpy.path.clean_name(name_orig), materialNames)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            else:
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                # If saturation(.s) is not zero, then color is not grey, and has a tint
    
                colored_specular_found = (material.specular_color.s > 0.0)
    
    
            ##################
            # Several versions of the finish: Level conditions are variations for specular/Mirror
            # texture channel map with alternative finish of 0 specular and no mirror reflection.
    
            # Level=1 Means No specular nor Mirror reflection
            # Level=2 Means translation of spec and mir levels for when no map influences them
    
            # Level=3 Means Maximum Spec and Mirror
    
            def povHasnoSpecularMaps(Level):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                if Level == 1:
    
                    tabWrite("#declare %s = finish {" % safety(name, Level=1))
    
                        file.write("  //No specular nor Mirror reflection\n")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                elif Level == 2:
    
                    tabWrite("#declare %s = finish {" % safety(name, Level=2))
    
                        file.write("  //translation of spec and mir levels for when no map " \
                                   "influences them\n")
    
                    tabWrite("#declare %s = finish {" % safety(name, Level=3))
    
                        file.write("  //Maximum Spec and Mirror\n")
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                    # POV-Ray 3.7 now uses two diffuse values respectively for front and back shading
                    # (the back diffuse is like blender translucency)
    
                    frontDiffuse = material.diffuse_intensity
                    backDiffuse = material.translucency
    
    
    
                        #Total should not go above one
                        if (frontDiffuse + backDiffuse) <= 1.0:
                            pass
    
                        elif frontDiffuse == backDiffuse:
    
                            # Try to respect the user's 'intention' by comparing the two values but
                            # bringing the total back to one.
                            frontDiffuse = backDiffuse = 0.5
                        # Let the highest value stay the highest value.
                        elif frontDiffuse > backDiffuse:
                            # clamps the sum below 1
                            backDiffuse = min(backDiffuse, (1.0 - frontDiffuse))
    
    Maurice Raybaud's avatar
     
    Maurice Raybaud committed
                            frontDiffuse = min(frontDiffuse, (1.0 - backDiffuse))
    
    
                    # map hardness between 0.0 and 1.0
                    roughness = ((1.0 - ((material.specular_hardness - 1.0) / 510.0)))
                    ## scale from 0.0 to 0.1
    
                    roughness *= 0.1
    
                    # add a small value because 0.0 is invalid.
    
                    roughness += (1.0 / 511.0)
    
                    ################################Diffuse Shader######################################
                    # Not used for Full spec (Level=3) of the shader.
    
                    if material.diffuse_shader == 'OREN_NAYAR' and Level != 3:
    
                        # Blender roughness is what is generally called oren nayar Sigma,
                        # and brilliance in POV-Ray.
                        tabWrite("brilliance %.3g\n" % (0.9 + material.roughness))
    
                    if material.diffuse_shader == 'TOON' and Level != 3:
    
                        tabWrite("brilliance %.3g\n" % (0.01 + material.diffuse_toon_smooth * 0.25))
    
                        # Lower diffuse and increase specular for toon effect seems to look better
                        # in POV-Ray.
                        frontDiffuse *= 0.5
    
                    if material.diffuse_shader == 'MINNAERT' and Level != 3:
    
                        #tabWrite("aoi %.3g\n" % material.darkness)
    
                        pass  # let's keep things simple for now
    
                    if material.diffuse_shader == 'FRESNEL' and Level != 3:
    
                        #tabWrite("aoi %.3g\n" % material.diffuse_fresnel_factor)
    
                        pass  # let's keep things simple for now
    
                    if material.diffuse_shader == 'LAMBERT' and Level != 3:
    
                        # trying to best match lambert attenuation by that constant brilliance value
                        tabWrite("brilliance 1.8\n")
    
                        ###########################Specular Shader######################################
                        # No difference between phong and cook torrence in blender HaHa!
                        if (material.specular_shader == 'COOKTORR' or
                            material.specular_shader == 'PHONG'):
    
                            tabWrite("phong %.3g\n" % (material.specular_intensity))
                            tabWrite("phong_size %.3g\n" % (material.specular_hardness / 2 + 0.25))
    
                        # POV-Ray 'specular' keyword corresponds to a Blinn model, without the ior.
                        elif material.specular_shader == 'BLINN':
                            # Use blender Blinn's IOR just as some factor for spec intensity
                            tabWrite("specular %.3g\n" % (material.specular_intensity *
                                                          (material.specular_ior / 4.0)))
    
                            tabWrite("roughness %.3g\n" % roughness)
    
                            #Could use brilliance 2(or varying around 2 depending on ior or factor) too.
    
    
                        elif material.specular_shader == 'TOON':
    
                            tabWrite("phong %.3g\n" % (material.specular_intensity * 2.0))
    
                            tabWrite("phong_size %.3g\n" % (0.1 + material.specular_toon_smooth / 2.0))
    
                        elif material.specular_shader == 'WARDISO':
    
                            # find best suited default constant for brilliance Use both phong and
                            # specular for some values.
                            tabWrite("specular %.3g\n" % (material.specular_intensity /
                                                          (material.specular_slope + 0.0005)))
                            # find best suited default constant for brilliance Use both phong and
                            # specular for some values.
                            tabWrite("roughness %.4g\n" % (0.0005 + material.specular_slope / 10.0))
                            # find best suited default constant for brilliance Use both phong and
                            # specular for some values.
                            tabWrite("brilliance %.4g\n" % (1.8 - material.specular_slope * 1.8))
    
                    ####################################################################################
    
                        tabWrite("specular 1\n")
                    tabWrite("diffuse %.3g %.3g\n" % (frontDiffuse, backDiffuse))
    
                    tabWrite("ambient %.3g\n" % material.ambient)
    
                    # POV-Ray blends the global value
                    #tabWrite("ambient rgb <%.3g, %.3g, %.3g>\n" % \
                    #         tuple([c*material.ambient for c in world.ambient_color]))
    
                    tabWrite("emission %.3g\n" % material.emit)  # New in POV-Ray 3.7
    
                    #POV-Ray just ignores roughness if there's no specular keyword
                    #tabWrite("roughness %.3g\n" % roughness)
    
                    if material.pov.conserve_energy:
                        # added for more realistic shading. Needs some checking to see if it
                        # really works. --Maurice.
                        tabWrite("conserve_energy\n")
    
                    if colored_specular_found == True:
                         tabWrite("metallic\n")          
    
    
                    # 'phong 70.0 '
                    if Level != 1:
                        if material.raytrace_mirror.use:
                            raytrace_mirror = material.raytrace_mirror
                            if raytrace_mirror.reflect_factor:
    
                                tabWrite("reflection {\n")
                                tabWrite("rgb <%.3g, %.3g, %.3g>" % material.mirror_color[:])
    
                                    tabWrite("metallic %.3g" % (raytrace_mirror.reflect_factor))
    
                                if material.pov.mirror_use_IOR:  # WORKING ?
                                    # Removed from the line below: gives a more physically correct
                                    # material but needs proper IOR. --Maurice
                                    tabWrite("fresnel 1 ")
                                tabWrite("falloff %.3g exponent %.3g} " % \
                                         (raytrace_mirror.fresnel, raytrace_mirror.fresnel_factor))
    
    
                    if material.subsurface_scattering.use:
                        subsurface_scattering = material.subsurface_scattering
    
                        tabWrite("subsurface { translucency <%.3g, %.3g, %.3g> }\n" % (
    
                                 (subsurface_scattering.radius[0]),
                                 (subsurface_scattering.radius[1]),
    
    Campbell Barton's avatar
    Campbell Barton committed
                                 (subsurface_scattering.radius[2]),
    
                    if material.pov.irid_enable:
                        tabWrite("irid { %.4g thickness %.4g turbulence %.4g }" % \
                                 (material.pov.irid_amount, material.pov.irid_thickness,
                                  material.pov.irid_turbulence))
    
                    tabWrite("diffuse 0.8\n")
                    tabWrite("phong 70.0\n")
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                # This is written into the object
                '''
                if material and material.transparency_method=='RAYTRACE':
                    'interior { ior %.3g} ' % material.raytrace_transparency.ior
                '''
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                #tabWrite("crand 1.0\n") # Sand granyness
                #tabWrite("metallic %.6f\n" % material.spec)
                #tabWrite("phong %.6f\n" % material.spec)
                #tabWrite("phong_size %.6f\n" % material.spec)
                #tabWrite("brilliance %.6f " % (material.specular_hardness/256.0) # Like hardness
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
            # Level=2 Means translation of spec and mir levels for when no map influences them
            povHasnoSpecularMaps(Level=2)
    
                special_texture_found = False
                for t in material.texture_slots:
    
                    if t and t.use:
                        if (t.texture.type == 'IMAGE' and t.texture.image) or t.texture.type != 'IMAGE':
                            validPath=True
                    else:
                        validPath=False
                    if(t and t.use and validPath and
    
                       (t.use_map_specular or t.use_map_raymir or t.use_map_normal or t.use_map_alpha)):
    
                        special_texture_found = True
    
                        continue  # Some texture found
    
    
                if special_texture_found or colored_specular_found:
    
                    # Level=1 Means No specular nor Mirror reflection
                    povHasnoSpecularMaps(Level=1)
    
                    # Level=3 Means Maximum Spec and Mirror