Skip to content
Snippets Groups Projects
render.py 262 KiB
Newer Older
  • Learn to ignore specific revisions
  •                         numPoints+=3
    
                        tabWrite("sphere_sweep { %s_spline %s,\n"%(spl_type,numPoints))
                        if spl.use_cyclic_u:
                            pt1 = points[len(points)-1]
                            wpt1 = pt1.co
                            tabWrite("<%.4g,%.4g,%.4g>,%.4g\n" %(wpt1[0], wpt1[1], wpt1[2], pt1.radius*ob.data.bevel_depth))
                        for pt in points:
                            wpt = pt.co
                            tabWrite("<%.4g,%.4g,%.4g>,%.4g\n" %(wpt[0], wpt[1], wpt[2], pt.radius*ob.data.bevel_depth))
                        if spl.use_cyclic_u:
                            for i in range (0,2):
                                endPt=points[i]
                                wpt = endPt.co
                                tabWrite("<%.4g,%.4g,%.4g>,%.4g\n" %(wpt[0], wpt[1], wpt[2], endPt.radius*ob.data.bevel_depth))
    
                        
                    tabWrite("}\n")
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
            if ob.pov.curveshape == 'sor':
                for spl in ob.data.splines:
                    if spl.type in {'POLY','NURBS'}:
                        points=spl.points
                        numPoints=len(points)
                        tabWrite("sor { %s,\n"%numPoints)
                        for pt in points:
                            wpt = pt.co
                            tabWrite("<%.4g,%.4g>\n" %(wpt[0], wpt[1]))
                    else:
                        tabWrite("box { 0,0\n")
            if ob.pov.curveshape in {'lathe','prism'}:
                spl = ob.data.splines[0]
                if spl.type == "BEZIER":
                    points=spl.bezier_points
                    lenCur=len(points)-1
                    lenPts=lenCur*4
                    ifprism = ''
                    if ob.pov.curveshape in {'prism'}:
                        height = ob.data.extrude
                        ifprism = '-%s, %s,'%(height, height)
                        lenCur+=1
                        lenPts+=4
                    tabWrite("%s { bezier_spline %s %s,\n"%(ob.pov.curveshape,ifprism,lenPts))
                    for i in range(0,lenCur):
                        p1=points[i].co
                        pR=points[i].handle_right
                        end = i+1
                        if i == lenCur-1 and ob.pov.curveshape in {'prism'}:
                            end = 0
                        pL=points[end].handle_left
                        p2=points[end].co
                        line="<%.4g,%.4g>"%(p1[0],p1[1])
                        line+="<%.4g,%.4g>"%(pR[0],pR[1])
                        line+="<%.4g,%.4g>"%(pL[0],pL[1])
                        line+="<%.4g,%.4g>"%(p2[0],p2[1])
                        tabWrite("%s\n" %line)
                else:
                    points=spl.points
                    lenCur=len(points)
                    lenPts=lenCur
                    ifprism = ''
                    if ob.pov.curveshape in {'prism'}:
                        height = ob.data.extrude
                        ifprism = '-%s, %s,'%(height, height)
                        lenPts+=3
                    spl_type = 'quadratic'
                    if spl.type == 'POLY':
                        spl_type = 'linear'
                    tabWrite("%s { %s_spline %s %s,\n"%(ob.pov.curveshape,spl_type,ifprism,lenPts))
                    if ob.pov.curveshape in {'prism'}:
                        pt = points[len(points)-1]
                        wpt = pt.co
                        tabWrite("<%.4g,%.4g>\n" %(wpt[0], wpt[1]))
                    for pt in points:
                        wpt = pt.co
                        tabWrite("<%.4g,%.4g>\n" %(wpt[0], wpt[1]))
                    if ob.pov.curveshape in {'prism'}:
                        for i in range(2):
                            pt = points[i]
                            wpt = pt.co
                            tabWrite("<%.4g,%.4g>\n" %(wpt[0], wpt[1]))
            if bezier_sweep:
                spl = ob.data.splines[0]
                points=spl.bezier_points
                lenCur = len(points)-1
                numPoints = lenCur*4
                if spl.use_cyclic_u:
                    lenCur += 1
                    numPoints += 4
                tabWrite("#declare %s_bezier_points = array[%s]{\n"%(dataname,numPoints))
                for i in range(lenCur):
                    p1=points[i].co
                    pR=points[i].handle_right
                    end = i+1
                    if spl.use_cyclic_u and i == (lenCur - 1):
                        end = 0
                    pL=points[end].handle_left
                    p2=points[end].co
                    line="<%.4g,%.4g,%.4f>"%(p1[0],p1[1],p1[2])
                    line+="<%.4g,%.4g,%.4f>"%(pR[0],pR[1],pR[2])
                    line+="<%.4g,%.4g,%.4f>"%(pL[0],pL[1],pL[2])
                    line+="<%.4g,%.4g,%.4f>"%(p2[0],p2[1],p2[2])
                    tabWrite("%s\n" %line)
                tabWrite("}\n")
                #tabWrite('#include "bezier_spheresweep.inc"\n') #now inlined
                tabWrite('#declare %s = object{Shape_Bezierpoints_Sphere_Sweep(%s, %s_bezier_points, %.4f) \n'%(dataname,ob.data.resolution_u,dataname,ob.data.bevel_depth))
            if ob.pov.curveshape in {'loft'}:
                tabWrite('object {MSM(%s,%s,"c",%s,"")\n'%(dataname,ob.pov.res_u,ob.pov.res_v))
            if ob.pov.curveshape in {'birail'}:
                splines = '%s1,%s2,%s3,%s4'%(dataname,dataname,dataname,dataname)
                tabWrite('object {Coons(%s, %s, %s, "")\n'%(splines,ob.pov.res_u,ob.pov.res_v))
            povMatName = "Default_texture"
            if ob.active_material:
                #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
                try:
                    material = ob.active_material
                    writeObjectMaterial(material, ob)
                except IndexError:
                    print(me)
            #tabWrite("texture {%s}\n"%povMatName)
            if ob.pov.curveshape in {'prism'}:
                tabWrite("rotate <90,0,0>\n")
                tabWrite("scale y*-1\n" )
            tabWrite("}\n")
            
    #################################################################        
            
                
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        def exportMeta(metas):
    
            # TODO - blenders 'motherball' naming is not supported.
    
            if comments and len(metas) >= 1:
    
                file.write("//--Blob objects--\n\n")
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            for ob in metas:
                meta = ob.data
    
    
                # important because no elements will break parsing.
    
                elements = [elem for elem in meta.elements if elem.type in {'BALL', 'ELLIPSOID'}]
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                    tabWrite("blob {\n")
                    tabWrite("threshold %.4g\n" % meta.threshold)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                        material = meta.materials[0]  # lame! - blender cant do enything else.
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                    for elem in elements:
                        loc = elem.co
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                        stiffness = elem.stiffness
                        if elem.use_negative:
                            stiffness = - stiffness
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                        if elem.type == 'BALL':
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                            tabWrite("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g }\n" % \
                                     (loc.x, loc.y, loc.z, elem.radius, stiffness))
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                            # After this wecould do something simple like...
    
                            # except we'll write the color
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                        elif elem.type == 'ELLIPSOID':
                            # location is modified by scale
    
                            tabWrite("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g }\n" % \
                                     (loc.x / elem.size_x, loc.y / elem.size_y, loc.z / elem.size_z,
                                      elem.radius, stiffness))
                            tabWrite("scale <%.6g, %.6g, %.6g> \n" % \
                                     (elem.size_x, elem.size_y, elem.size_z))
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                    if material:
                        diffuse_color = material.diffuse_color
    
                        if material.use_transparency and material.transparency_method == 'RAYTRACE':
    
                            povFilter = material.raytrace_transparency.filter * (1.0 - material.alpha)
                            trans = (1.0 - material.alpha) - povFilter
    
                            povFilter = 0.0
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                        material_finish = materialNames[material.name]
    
                        tabWrite("pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} \n" % \
                                 (diffuse_color[0], diffuse_color[1], diffuse_color[2],
                                  povFilter, trans))
    
                        tabWrite("finish {%s}\n" % safety(material_finish, Level=2))
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                        tabWrite("pigment {rgb<1 1 1>} \n")
    
                        # Write the finish last.
                        tabWrite("finish {%s}\n" % (safety(DEF_MAT_NAME, Level=2)))
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                    writeObjectMaterial(material, ob)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                    writeMatrix(global_matrix * ob.matrix_world)
    
                    # Importance for radiosity sampling added here
    
                    tabWrite("radiosity { \n")
                    tabWrite("importance %3g \n" % importance)
                    tabWrite("}\n")
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                    tabWrite("}\n")  # End of Metaball block
    
                    if comments and len(metas) >= 1:
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
        def exportMeshes(scene, sel):
    #        obmatslist = []
    #        def hasUniqueMaterial():
    #            # Grab materials attached to object instances ...
    #            if hasattr(ob, 'material_slots'):
    #                for ms in ob.material_slots:
    
    #                    if ms.material is not None and ms.link == 'OBJECT':
    
    #                        if ms.material in obmatslist:
    #                            return False
    #                        else:
    #                            obmatslist.append(ms.material)
    #                            return True
    #        def hasObjectMaterial(ob):
    #            # Grab materials attached to object instances ...
    #            if hasattr(ob, 'material_slots'):
    #                for ms in ob.material_slots:
    
    #                    if ms.material is not None and ms.link == 'OBJECT':
    
    #                        # If there is at least one material slot linked to the object
    
    #                        # and not the data (mesh), always create a new, "private" data instance.
    
    #                        return True
    #            return False
            # For objects using local material(s) only!
    
            # This is a mapping between a tuple (dataname, materialnames, ...), and the POV dataname.
    
            # As only objects using:
            #     * The same data.
            #     * EXACTLY the same materials, in EXACTLY the same sockets.
    
            # ... can share a same instance in POV export.
    
            def checkObjectMaterials(ob, name, dataname):
                if hasattr(ob, 'material_slots'):
                    has_local_mats = False
                    key = [dataname]
                    for ms in ob.material_slots:
    
                        if ms.material is not None:
    
                            key.append(ms.material.name)
                            if ms.link == 'OBJECT' and not has_local_mats:
                                has_local_mats = True
                        else:
    
                            # Even if the slot is empty, it is important to grab it...
    
                            key.append("")
                    if has_local_mats:
                        # If this object uses local material(s), lets find if another object
                        # using the same data and exactly the same list of materials
    
                        # (in the same slots) has already been processed...
    
                        # Note that here also, we use object name as new, unique dataname for Pov.
    
                        key = tuple(key)  # Lists are not hashable...
    
                        if key not in obmats2data:
                            obmats2data[key] = name
                        return obmats2data[key]
                return None
    
            data_ref = {}
    
            def store(scene, ob, name, dataname, matrix):
                # The Object needs to be written at least once but if its data is
                # already in data_ref this has already been done.
    
                # This func returns the "povray" name of the data, or None
    
                # if no writing is needed.
                if ob.is_modified(scene, 'RENDER'):
                    # Data modified.
                    # Create unique entry in data_ref by using object name
                    # (always unique in Blender) as data name.
                    data_ref[name] = [(name, MatrixAsPovString(matrix))]
                    return name
                # Here, we replace dataname by the value returned by checkObjectMaterials, only if
                # it is not evaluated to False (i.e. only if the object uses some local material(s)).
                dataname = checkObjectMaterials(ob, name, dataname) or dataname
                if dataname in data_ref:
                    # Data already known, just add the object instance.
                    data_ref[dataname].append((name, MatrixAsPovString(matrix)))
                    # No need to write data
                    return None
                else:
                    # Data not yet processed, create a new entry in data_ref.
                    data_ref[dataname] = [(name, MatrixAsPovString(matrix))]
                    return dataname
    
               
                 
            def exportSmoke(smoke_obj_name):
                #if LuxManager.CurrentScene.name == 'preview':
                    #return 1, 1, 1, 1.0
                #else:
                flowtype = -1
                smoke_obj = bpy.data.objects[smoke_obj_name]
                domain = None
    
                # Search smoke domain target for smoke modifiers
                for mod in smoke_obj.modifiers:
                    if mod.name == 'Smoke':
                        if mod.smoke_type == 'FLOW':
                            if mod.flow_settings.smoke_flow_type == 'BOTH':
                                flowtype = 2
                            else:
                                if mod.flow_settings.smoke_flow_type == 'SMOKE':
                                    flowtype = 0
                                else:
                                    if mod.flow_settings.smoke_flow_type == 'FIRE':
                                        flowtype = 1
    
                        if mod.smoke_type == 'DOMAIN':
                            domain = smoke_obj
                            smoke_modifier = mod
    
                eps = 0.000001
                if domain is not None:
                    #if bpy.app.version[0] >= 2 and bpy.app.version[1] >= 71:
                    # Blender version 2.71 supports direct access to smoke data structure
                    set = mod.domain_settings
                    channeldata = []
                    for v in set.density_grid:
                        channeldata.append(v.real)
                        print(v.real)
                    ## Usage en voxel texture:
                    # channeldata = []
                    # if channel == 'density':
                        # for v in set.density_grid:
                            # channeldata.append(v.real)
    
                    # if channel == 'fire':
                        # for v in set.flame_grid:
                            # channeldata.append(v.real)
    
                    resolution = set.resolution_max
                    big_res = []
                    big_res.append(set.domain_resolution[0])
                    big_res.append(set.domain_resolution[1])
                    big_res.append(set.domain_resolution[2])
    
                    if set.use_high_resolution:
                        big_res[0] = big_res[0] * (set.amplify + 1)
                        big_res[1] = big_res[1] * (set.amplify + 1)
                        big_res[2] = big_res[2] * (set.amplify + 1)
                    # else:
                        # p = []
                        ##gather smoke domain settings
                        # BBox = domain.bound_box
                        # p.append([BBox[0][0], BBox[0][1], BBox[0][2]])
                        # p.append([BBox[6][0], BBox[6][1], BBox[6][2]])
                        # set = mod.domain_settings
                        # resolution = set.resolution_max
                        # smokecache = set.point_cache
                        # ret = read_cache(smokecache, set.use_high_resolution, set.amplify + 1, flowtype)
                        # res_x = ret[0]
                        # res_y = ret[1]
                        # res_z = ret[2]
                        # density = ret[3]
                        # fire = ret[4]
    
                        # if res_x * res_y * res_z > 0:
                            ##new cache format
                            # big_res = []
                            # big_res.append(res_x)
                            # big_res.append(res_y)
                            # big_res.append(res_z)
                        # else:
                            # max = domain.dimensions[0]
                            # if (max - domain.dimensions[1]) < -eps:
                                # max = domain.dimensions[1]
    
                            # if (max - domain.dimensions[2]) < -eps:
                                # max = domain.dimensions[2]
    
                            # big_res = [int(round(resolution * domain.dimensions[0] / max, 0)),
                                       # int(round(resolution * domain.dimensions[1] / max, 0)),
                                       # int(round(resolution * domain.dimensions[2] / max, 0))]
    
                        # if set.use_high_resolution:
                            # big_res = [big_res[0] * (set.amplify + 1), big_res[1] * (set.amplify + 1),
                                       # big_res[2] * (set.amplify + 1)]
    
                        # if channel == 'density':
                            # channeldata = density
    
                        # if channel == 'fire':
                            # channeldata = fire
    
                            # sc_fr = '%s/%s/%s/%05d' % (efutil.export_path, efutil.scene_filename(), bpy.context.scene.name, bpy.context.scene.frame_current)
    
                            #               if not os.path.exists( sc_fr ):
                            #                   os.makedirs(sc_fr)
    
                            #               smoke_filename = '%s.smoke' % bpy.path.clean_name(domain.name)
                            #               smoke_path = '/'.join([sc_fr, smoke_filename])
    
                            #               with open(smoke_path, 'wb') as smoke_file:
                            #                   # Binary densitygrid file format
                            #                   #
                            #                   # File header
                            #                   smoke_file.write(b'SMOKE')        #magic number
                            #                   smoke_file.write(struct.pack('<I', big_res[0]))
                            #                   smoke_file.write(struct.pack('<I', big_res[1]))
                            #                   smoke_file.write(struct.pack('<I', big_res[2]))
    
                            # Density data
    
                            #                   smoke_file.write(struct.pack('<%df'%len(channeldata), *channeldata))
    
                            #               LuxLog('Binary SMOKE file written: %s' % (smoke_path))
    
    
            #return big_res[0], big_res[1], big_res[2], channeldata
    
                    mydf3 = df3.df3(big_res[0],big_res[1],big_res[2])
    
                    sim_sizeX, sim_sizeY, sim_sizeZ = mydf3.size()
                    for x in range(sim_sizeX):
                        for y in range(sim_sizeY):
                            for z in range(sim_sizeZ):
                                mydf3.set(x, y, z, channeldata[((z * sim_sizeY + y) * sim_sizeX + x)])
    
    
                    mydf3.exportDF3(smokePath)
                    print('Binary smoke.df3 file written in preview directory')
                    if comments:
                        file.write("\n//--Smoke--\n\n")
    
    
                    # Note: We start with a default unit cube.
                    #       This is mandatory to read correctly df3 data - otherwise we could just directly use bbox
                    #       coordinates from the start, and avoid scale/translate operations at the end...
                    file.write("box{<0,0,0>, <1,1,1>\n")
    
                    file.write("    pigment{ rgbt 1 }\n")
                    file.write("    hollow\n")
                    file.write("    interior{ //---------------------\n")
                    file.write("        media{ method 3\n")
                    file.write("               emission <1,1,1>*1\n")# 0>1 for dark smoke to white vapour
                    file.write("               scattering{ 1, // Type\n")
    
                    file.write("                  <1,1,1>*0.1\n")
    
                    file.write("                } // end scattering\n")
    
                    file.write("                density{density_file df3 \"%s\"\n" % (smokePath))
                    file.write("                        color_map {\n")
                    file.write("                        [0.00 rgb 0]\n")
                    file.write("                        [0.05 rgb 0]\n")
                    file.write("                        [0.20 rgb 0.2]\n")
                    file.write("                        [0.30 rgb 0.6]\n")
                    file.write("                        [0.40 rgb 1]\n")
                    file.write("                        [1.00 rgb 1]\n")
                    file.write("                       } // end color_map\n")
                    file.write("               } // end of density\n")
                    file.write("               samples %i // higher = more precise\n" % resolution)
    
                    file.write("         } // end of media --------------------------\n")
                    file.write("    } // end of interior\n")
    
    
                    # START OF TRANSFORMATIONS
    
                    # Size to consider here are bbox dimensions (i.e. still in object space, *before* applying
                    # loc/rot/scale and other transformations (like parent stuff), aka matrix_world).
                    bbox = smoke_obj.bound_box
                    dim = [abs(bbox[6][0] - bbox[0][0]), abs(bbox[6][1] - bbox[0][1]), abs(bbox[6][2] - bbox[0][2])]
    
                    # We scale our cube to get its final size and shapes but still in *object* space (same as Blender's bbox).
                    file.write("scale<%.6g,%.6g,%.6g>\n" % (dim[0], dim[1], dim[2]))
    
                    # We offset our cube such that (0,0,0) coordinate matches Blender's object center.
                    file.write("translate<%.6g,%.6g,%.6g>\n" % (bbox[0][0], bbox[0][1], bbox[0][2]))
    
                    # We apply object's transformations to get final loc/rot/size in world space!
                    # Note: we could combine the two previous transformations with this matrix directly...
    
                    writeMatrix(global_matrix * smoke_obj.matrix_world)
    
    
                    # END OF TRANSFORMATIONS
    
    
                    file.write("}\n")
    
                    #file.write("               interpolate 1\n")
                    #file.write("               frequency 0\n")
                    #file.write("   }\n")
    
                    #file.write("}\n")                            
                    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            for ob in sel:
                ob_num += 1
    
    
                # XXX I moved all those checks here, as there is no need to compute names
    
                if (ob.type in {'LAMP', 'CAMERA', 'EMPTY',
                                'META', 'ARMATURE', 'LATTICE'}):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    continue
    
                for mod in ob.modifiers:
                    if mod and hasattr(mod, 'smoke_type'):
    
                        smokeFlag=True
                        if (mod.smoke_type == 'DOMAIN'):
                            exportSmoke(ob.name)
                        break # don't render domain mesh or flow emitter mesh, skip to next object.
                if not smokeFlag:    
                    # Export Hair
                    renderEmitter = True
                    if hasattr(ob, 'particle_systems'):
                        renderEmitter = False
                        for pSys in ob.particle_systems:
                            if pSys.settings.use_render_emitter:
                                renderEmitter = True
                            for mod in [m for m in ob.modifiers if (m is not None) and (m.type == 'PARTICLE_SYSTEM')]:
                                if (pSys.settings.render_type == 'PATH') and mod.show_render and (pSys.name == mod.particle_system.name):
                                    tstart = time.time()
                                    texturedHair=0
                                    if ob.active_material is not None:
                                        pmaterial = ob.material_slots[pSys.settings.material - 1].material
                                        for th in pmaterial.texture_slots:
                                            if th and th.use:
                                                if (th.texture.type == 'IMAGE' and th.texture.image) or th.texture.type != 'IMAGE':
                                                    if th.use_map_color_diffuse:
                                                        texturedHair=1
                                        if pmaterial.strand.use_blender_units:
                                            strandStart = pmaterial.strand.root_size
                                            strandEnd = pmaterial.strand.tip_size
                                            strandShape = pmaterial.strand.shape 
                                        else:  # Blender unit conversion
                                            strandStart = pmaterial.strand.root_size / 200.0
                                            strandEnd = pmaterial.strand.tip_size / 200.0
                                            strandShape = pmaterial.strand.shape
                                    else:
                                        pmaterial = "default"  # No material assigned in blender, use default one
                                        strandStart = 0.01
                                        strandEnd = 0.01
                                        strandShape = 0.0
                                    # Set the number of particles to render count rather than 3d view display    
                                    pSys.set_resolution(scene, ob, 'RENDER')    
                                    steps = pSys.settings.draw_step
                                    steps = 3 ** steps # or (power of 2 rather than 3) + 1 # Formerly : len(particle.hair_keys)
                                    
                                    totalNumberOfHairs = ( len(pSys.particles) + len(pSys.child_particles) )
                                    #hairCounter = 0
                                    file.write('#declare HairArray = array[%i] {\n' % totalNumberOfHairs)
                                    for pindex in range(0, totalNumberOfHairs):
    
                                        #if particle.is_exist and particle.is_visible:
                                            #hairCounter += 1
                                            #controlPointCounter = 0
                                            # Each hair is represented as a separate sphere_sweep in POV-Ray.
    
                                            file.write('sphere_sweep{')
                                            if pSys.settings.use_hair_bspline:
                                                file.write('b_spline ')
                                                file.write('%i,\n' % (steps + 2))  # +2 because the first point needs tripling to be more than a handle in POV
                                            else:
                                                file.write('linear_spline ')
                                                file.write('%i,\n' % (steps))
                                            #changing world coordinates to object local coordinates by multiplying with inverted matrix    
                                            initCo = ob.matrix_world.inverted()*(pSys.co_hair(ob, pindex, 0))
                                            if ob.active_material is not None:
                                                pmaterial = ob.material_slots[pSys.settings.material-1].material
                                                for th in pmaterial.texture_slots:
                                                    if th and th.use and th.use_map_color_diffuse:
                                                        #treat POV textures as bitmaps
                                                        if (th.texture.type == 'IMAGE' and th.texture.image and th.texture_coords == 'UV' and ob.data.uv_textures != None): # or (th.texture.pov.tex_pattern_type != 'emulator' and th.texture_coords == 'UV' and ob.data.uv_textures != None):
                                                            image=th.texture.image
                                                            image_width = image.size[0]
                                                            image_height = image.size[1]
                                                            image_pixels = image.pixels[:]
                                                            uv_co = pSys.uv_on_emitter(mod, pSys.particles[pindex], pindex, 0)
                                                            x_co = round(uv_co[0] * (image_width - 1))
                                                            y_co = round(uv_co[1] * (image_height - 1))
                                                            pixelnumber = (image_width * y_co) + x_co
                                                            r = image_pixels[pixelnumber*4]
                                                            g = image_pixels[pixelnumber*4+1]
                                                            b = image_pixels[pixelnumber*4+2]
                                                            a = image_pixels[pixelnumber*4+3]
                                                            initColor=(r,g,b,a)                                              
                                                        else:
                                                            #only overwrite variable for each competing texture for now
                                                            initColor=th.texture.evaluate((initCo[0],initCo[1],initCo[2]))
                                            for step in range(0, steps):
                                                co = pSys.co_hair(ob, pindex, step)
                                            #for controlPoint in particle.hair_keys:
                                                if pSys.settings.clump_factor != 0:
                                                    hDiameter = pSys.settings.clump_factor / 200.0 * random.uniform(0.5, 1)
                                                elif step == 0:
                                                    hDiameter = strandStart
                                                else:
                                                    hDiameter += (strandEnd-strandStart)/(pSys.settings.draw_step+1) #XXX +1 or not?
                                                if step == 0 and pSys.settings.use_hair_bspline:
                                                    # Write three times the first point to compensate pov Bezier handling
                                                    file.write('<%.6g,%.6g,%.6g>,%.7g,\n' % (co[0], co[1], co[2], abs(hDiameter)))
                                                    file.write('<%.6g,%.6g,%.6g>,%.7g,\n' % (co[0], co[1], co[2], abs(hDiameter)))                                          
                                                    #file.write('<%.6g,%.6g,%.6g>,%.7g' % (particle.location[0], particle.location[1], particle.location[2], abs(hDiameter))) # Useless because particle location is the tip, not the root.
                                                    #file.write(',\n')
                                                #controlPointCounter += 1
                                                #totalNumberOfHairs += len(pSys.particles)# len(particle.hair_keys)
                                                     
                                              # Each control point is written out, along with the radius of the
                                              # hair at that point.
                                                file.write('<%.6g,%.6g,%.6g>,%.7g' % (co[0], co[1], co[2], abs(hDiameter)))
    
                                              # All coordinates except the last need a following comma.
    
                                                if step != steps - 1:
                                                    file.write(',\n')
                                                else:
                                                    if texturedHair:
                                                        # Write pigment and alpha (between Pov and Blender alpha 0 and 1 are reversed)
                                                        file.write('\npigment{ color rgbf < %.3g, %.3g, %.3g, %.3g> }\n' %(initColor[0], initColor[1], initColor[2], 1.0-initColor[3]))
                                                    # End the sphere_sweep declaration for this hair
                                                    file.write('}\n')
                                                
                                              # All but the final sphere_sweep (each array element) needs a terminating comma.
    
                                            if pindex != totalNumberOfHairs:
                                                file.write(',\n')
                                            else:
                                                file.write('\n')
    
                                    # End the array declaration.
    
                                    file.write('}\n')
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                                    file.write('\n')
    
                                    
                                    if not texturedHair:
                                        # Pick up the hair material diffuse color and create a default POV-Ray hair texture.
    
                                        file.write('#ifndef (HairTexture)\n')
                                        file.write('  #declare HairTexture = texture {\n')
                                        file.write('    pigment {rgbt <%s,%s,%s,%s>}\n' % (pmaterial.diffuse_color[0], pmaterial.diffuse_color[1], pmaterial.diffuse_color[2], (pmaterial.strand.width_fade + 0.05)))
                                        file.write('  }\n')
                                        file.write('#end\n')
                                        file.write('\n')
    
                                    # Dynamically create a union of the hairstrands (or a subset of them).
                                    # By default use every hairstrand, commented line is for hand tweaking test renders.
                                    file.write('//Increasing HairStep divides the amount of hair for test renders.\n')
                                    file.write('#ifndef(HairStep) #declare HairStep = 1; #end\n')
                                    file.write('union{\n')
                                    file.write('  #local I = 0;\n')
                                    file.write('  #while (I < %i)\n' % totalNumberOfHairs)
                                    file.write('    object {HairArray[I]')
                                    if not texturedHair:
                                        file.write(' texture{HairTexture}\n')
                                    else:
                                        file.write('\n')
                                    # Translucency of the hair:
                                    file.write('        hollow\n')
                                    file.write('        double_illuminate\n')
                                    file.write('        interior {\n')
                                    file.write('            ior 1.45\n')
                                    file.write('            media {\n')
                                    file.write('                scattering { 1, 10*<0.73, 0.35, 0.15> /*extinction 0*/ }\n')
                                    file.write('                absorption 10/<0.83, 0.75, 0.15>\n')
                                    file.write('                samples 1\n')
                                    file.write('                method 2\n')
                                    file.write('                density {\n')
                                    file.write('                    color_map {\n')
                                    file.write('                        [0.0 rgb <0.83, 0.45, 0.35>]\n')
                                    file.write('                        [0.5 rgb <0.8, 0.8, 0.4>]\n')
                                    file.write('                        [1.0 rgb <1,1,1>]\n')
                                    file.write('                    }\n')
                                    file.write('                }\n')
                                    file.write('            }\n')
                                    file.write('        }\n')
                                    file.write('    }\n')
                                    
                                    file.write('    #local I = I + HairStep;\n')
                                    file.write('  #end\n')
                                    
                                    writeMatrix(global_matrix * ob.matrix_world)
    
                                    
                                    file.write('}')
                                    print('Totals hairstrands written: %i' % totalNumberOfHairs)
                                    print('Number of tufts (particle systems)', len(ob.particle_systems))
                                    
                                    # Set back the displayed number of particles to preview count
                                    pSys.set_resolution(scene, ob, 'PREVIEW')
                                    
                                    if renderEmitter == False:
                                        continue #don't render mesh, skip to next object.
    
        #############################################
                    # Generating a name for object just like materials to be able to use it
                    # (baking for now or anything else).
                    # XXX I don't understand that:&nbsp;if we are here, sel if a non-empty iterable,
                    #     so this condition is always True, IMO -- mont29
                    if sel:
                        name_orig = "OB" + ob.name
                        dataname_orig = "DATA" + ob.data.name
    
                        name_orig = DEF_OBJ_NAME
                        dataname_orig = DEF_OBJ_NAME
                    name = string_strip_hyphen(bpy.path.clean_name(name_orig))
                    dataname = string_strip_hyphen(bpy.path.clean_name(dataname_orig))
        ##            for slot in ob.material_slots:
        ##                if slot.material is not None and slot.link == 'OBJECT':
        ##                    obmaterial = slot.material
    
        #############################################
    
                    if info_callback:
                        info_callback("Object %2.d of %2.d (%s)" % (ob_num, len(sel), ob.name))
    
                    #if ob.type != 'MESH':
                    #    continue
                    # me = ob.data
    
                    matrix = global_matrix * ob.matrix_world
                    povdataname = store(scene, ob, name, dataname, matrix)
                    if povdataname is None:
                        print("This is an instance")
                        continue
    
                    print("Writing Down First Occurence")
    
                                        
    ############################################Povray Primitives
                    # special exportCurves() function takes care of writing
                    # lathe, sphere_sweep, birail, and loft
                    if ob.type == 'CURVE' and (ob.pov.curveshape in 
                                    {'lathe', 'sphere_sweep', 'loft'}):
                        continue #Don't render proxy mesh, skip to next object
    
                    if ob.pov.object_as == 'ISOSURFACE':
                        tabWrite("#declare %s = isosurface{ \n"% povdataname)
                        tabWrite("function{ \n")
                        textName = ob.pov.iso_function_text
                        if textName:
                            node_tree = bpy.context.scene.node_tree
                            for node in node_tree.nodes:
                                if node.bl_idname == "IsoPropsNode" and node.label == ob.name:
                                    for inp in node.inputs:
                                        if inp:
                                            tabWrite("#declare %s = %.6g;\n"%(inp.name,inp.default_value))
    
                            text = bpy.data.texts[textName]
                            for line in text.lines:
                                split = line.body.split()
                                if split[0] != "#declare":
                                    tabWrite("%s\n"%line.body)
                        else:
                            tabWrite("abs(x) - 2 + y")
                        tabWrite("}\n")
                        tabWrite("threshold %.6g\n"%ob.pov.threshold)
                        tabWrite("max_gradient %.6g\n"%ob.pov.max_gradient)
                        tabWrite("accuracy  %.6g\n"%ob.pov.accuracy)
                        tabWrite("contained_by { ")
                        if ob.pov.contained_by == "sphere":
                            tabWrite("sphere {0,%.6g}}\n"%ob.pov.container_scale)
                        else:
                            tabWrite("box {-%.6g,%.6g}}\n"%(ob.pov.container_scale,ob.pov.container_scale))
                        if ob.pov.all_intersections:
                            tabWrite("all_intersections\n")
                        else:
                            if ob.pov.max_trace > 1:
                                tabWrite("max_trace %.6g\n"%ob.pov.max_trace)
                        povMatName = "Default_texture"
                        if ob.active_material:
                            #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
                            try:
                                material = ob.active_material
                                writeObjectMaterial(material, ob)
                            except IndexError:
                                print(me)
                        #tabWrite("texture {%s}\n"%povMatName)
                        tabWrite("scale %.6g\n"%(1/ob.pov.container_scale))
                        tabWrite("}\n")
                        continue #Don't render proxy mesh, skip to next object
    
                    if ob.pov.object_as == 'SUPERELLIPSOID':
                        tabWrite("#declare %s = superellipsoid{ <%.4f,%.4f>\n"%(povdataname,ob.pov.se_n2,ob.pov.se_n1))
                        povMatName = "Default_texture"
                        if ob.active_material:
                            #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
                            try:
                                material = ob.active_material
                                writeObjectMaterial(material, ob)
                            except IndexError:
                                print(me)
                        #tabWrite("texture {%s}\n"%povMatName)
                        write_object_modifiers(scene,ob,file)
                        tabWrite("}\n")
                        continue #Don't render proxy mesh, skip to next object
    
    
                    if ob.pov.object_as == 'SUPERTORUS':
                        rMajor = ob.pov.st_major_radius
                        rMinor = ob.pov.st_minor_radius
                        ring = ob.pov.st_ring
                        cross = ob.pov.st_cross
                        accuracy=ob.pov.st_accuracy
                        gradient=ob.pov.st_max_gradient
                        ############Inline Supertorus macro
                        file.write("#macro Supertorus(RMj, RMn, MajorControl, MinorControl, Accuracy, MaxGradient)\n")
                        file.write("   #local CP = 2/MinorControl;\n")
                        file.write("   #local RP = 2/MajorControl;\n")
                        file.write("   isosurface {\n")
                        file.write("      function { pow( pow(abs(pow(pow(abs(x),RP) + pow(abs(z),RP), 1/RP) - RMj),CP) + pow(abs(y),CP) ,1/CP) - RMn }\n")
                        file.write("      threshold 0\n")
                        file.write("      contained_by {box {<-RMj-RMn,-RMn,-RMj-RMn>, < RMj+RMn, RMn, RMj+RMn>}}\n")
                        file.write("      #if(MaxGradient >= 1)\n")
                        file.write("         max_gradient MaxGradient\n")
                        file.write("      #else\n")
                        file.write("         evaluate 1, 10, 0.1\n")
                        file.write("      #end\n")
                        file.write("      accuracy Accuracy\n")
                        file.write("   }\n")
                        file.write("#end\n")
                        ############
                        tabWrite("#declare %s = object{ Supertorus( %.4g,%.4g,%.4g,%.4g,%.4g,%.4g)\n"%(povdataname,rMajor,rMinor,ring,cross,accuracy,gradient))
                        povMatName = "Default_texture"
                        if ob.active_material:
                            #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
                            try:
                                material = ob.active_material
                                writeObjectMaterial(material, ob)
                            except IndexError:
                                print(me)
                        #tabWrite("texture {%s}\n"%povMatName)
                        write_object_modifiers(scene,ob,file)
                        tabWrite("rotate x*90\n")
                        tabWrite("}\n")
                        continue #Don't render proxy mesh, skip to next object
                        
    
                    if ob.pov.object_as == 'PLANE':
                        tabWrite("#declare %s = plane{ <0,0,1>,1\n"%povdataname)
                        povMatName = "Default_texture"
                        if ob.active_material:
                             #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
                            try:
                                material = ob.active_material
                                writeObjectMaterial(material, ob)
                            except IndexError:
                                print(me) 
                        #tabWrite("texture {%s}\n"%povMatName)
                        write_object_modifiers(scene,ob,file)
                        #tabWrite("rotate x*90\n")
                        tabWrite("}\n")
                        continue #Don't render proxy mesh, skip to next object
    
                    if ob.pov.object_as == 'BOX':
                        tabWrite("#declare %s = box { -1,1\n"%povdataname)
                        povMatName = "Default_texture"
                        if ob.active_material:
                            #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
                            try:
                                material = ob.active_material
                                writeObjectMaterial(material, ob)
                            except IndexError:
                                print(me)
                        #tabWrite("texture {%s}\n"%povMatName)
                        write_object_modifiers(scene,ob,file)
                        #tabWrite("rotate x*90\n")
                        tabWrite("}\n")
                        continue #Don't render proxy mesh, skip to next object
    
    
                    if ob.pov.object_as == 'CONE':
                        br = ob.pov.cone_base_radius
                        cr = ob.pov.cone_cap_radius
                        bz = ob.pov.cone_base_z
                        cz = ob.pov.cone_cap_z
                        tabWrite("#declare %s = cone { <0,0,%.4f>,%.4f,<0,0,%.4f>,%.4f\n"%(povdataname,bz,br,cz,cr))
                        povMatName = "Default_texture"
                        if ob.active_material:
                            #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
                            try:
                                material = ob.active_material
                                writeObjectMaterial(material, ob)
                            except IndexError:
                                print(me)
                        #tabWrite("texture {%s}\n"%povMatName)
                        write_object_modifiers(scene,ob,file)
                        #tabWrite("rotate x*90\n")
                        tabWrite("}\n")
                        continue #Don't render proxy mesh, skip to next object
    
                    if ob.pov.object_as == 'CYLINDER':
                        tabWrite("#declare %s = cylinder { <0,0,1>,<0,0,-1>,1\n"%povdataname)
                        povMatName = "Default_texture"
                        if ob.active_material:
                            #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
                            try:
                                material = ob.active_material
                                writeObjectMaterial(material, ob)
                            except IndexError:
                                print(me)
                        #tabWrite("texture {%s}\n"%povMatName)
                        write_object_modifiers(scene,ob,file)
                        #tabWrite("rotate x*90\n")
                        tabWrite("}\n")
                        continue #Don't render proxy mesh, skip to next object
    
    
                    if ob.pov.object_as == 'HEIGHT_FIELD':
                        data = ""
                        filename = ob.pov.hf_filename
                        data += '"%s"'%filename
                        gamma = ' gamma %.4f'%ob.pov.hf_gamma
                        data += gamma
                        if ob.pov.hf_premultiplied:
                            data += ' premultiplied on'
                        if ob.pov.hf_smooth:
                            data += ' smooth'
                        if ob.pov.hf_water > 0:
                            data += ' water_level %.4f'%ob.pov.hf_water
                        #hierarchy = ob.pov.hf_hierarchy
                        tabWrite('#declare %s = height_field { %s\n'%(povdataname,data))
                        povMatName = "Default_texture"
                        if ob.active_material:
                            #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
                            try:
                                material = ob.active_material
                                writeObjectMaterial(material, ob)
                            except IndexError:
                                print(me)
                        #tabWrite("texture {%s}\n"%povMatName)
                        write_object_modifiers(scene,ob,file)
                        tabWrite("rotate x*90\n")
                        tabWrite("translate <-0.5,0.5,0>\n")
                        tabWrite("scale <0,-1,0>\n")
                        tabWrite("}\n")
                        continue #Don't render proxy mesh, skip to next object
    
                    if ob.pov.object_as == 'SPHERE':
    
                        tabWrite("#declare %s = sphere { 0,%6f\n"%(povdataname,ob.pov.sphere_radius))
                        povMatName = "Default_texture"
                        if ob.active_material:
                            #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
                            try:
                                material = ob.active_material
                                writeObjectMaterial(material, ob)
                            except IndexError:
                                print(me)
                        #tabWrite("texture {%s}\n"%povMatName)
                        write_object_modifiers(scene,ob,file)
                        #tabWrite("rotate x*90\n")
                        tabWrite("}\n")
                        continue #Don't render proxy mesh, skip to next object
    
                    if ob.pov.object_as == 'TORUS':
                        tabWrite("#declare %s = torus { %.4f,%.4f\n"%(povdataname,ob.pov.torus_major_radius,ob.pov.torus_minor_radius))
                        povMatName = "Default_texture"
                        if ob.active_material:
                            #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
                            try:
                                material = ob.active_material
                                writeObjectMaterial(material, ob)
                            except IndexError:
                                print(me)
                        #tabWrite("texture {%s}\n"%povMatName)
                        write_object_modifiers(scene,ob,file)
                        tabWrite("rotate x*90\n")
                        tabWrite("}\n")
                        continue #Don't render proxy mesh, skip to next object
    
                        
                    if ob.pov.object_as == 'PARAMETRIC':
                        tabWrite("#declare %s = parametric {\n"%povdataname)
                        tabWrite("function { %s }\n"%ob.pov.x_eq)
                        tabWrite("function { %s }\n"%ob.pov.y_eq)
                        tabWrite("function { %s }\n"%ob.pov.z_eq)
                        tabWrite("<%.4f,%.4f>, <%.4f,%.4f>\n"%(ob.pov.u_min,ob.pov.v_min,ob.pov.u_max,ob.pov.v_max))
                        if ob.pov.contained_by == "sphere":
                            tabWrite("contained_by { sphere{0, 2} }\n")
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                        else:
    
                            tabWrite("contained_by { box{-2, 2} }\n")
                        tabWrite("max_gradient %.6f\n"%ob.pov.max_gradient)
                        tabWrite("accuracy %.6f\n"%ob.pov.accuracy)
                        tabWrite("precompute 10 x,y,z\n")
                        tabWrite("}\n")
                        continue #Don't render proxy mesh, skip to next object
                        
                    if ob.pov.object_as == 'POLYCIRCLE':
                        #TODO write below macro Once:
                        #if write_polytocircle_macro_once == 0:
                        file.write("/****************************\n")
                        file.write("This macro was written by 'And'.\n")
                        file.write("Link:(http://news.povray.org/povray.binaries.scene-files/)\n")
                        file.write("****************************/\n")
                        file.write("//from math.inc:\n")
                        file.write("#macro VPerp_Adjust(V, Axis)\n")
                        file.write("   vnormalize(vcross(vcross(Axis, V), Axis))\n")
                        file.write("#end\n")
                        file.write("//Then for the actual macro\n")
                        file.write("#macro Shape_Slice_Plane_2P_1V(point1, point2, clip_direct)\n")
                        file.write("#local p1 = point1 + <0,0,0>;\n")
                        file.write("#local p2 = point2 + <0,0,0>;\n")
                        file.write("#local clip_v = vnormalize(clip_direct + <0,0,0>);\n")
                        file.write("#local direct_v1 = vnormalize(p2 - p1);\n")
                        file.write("#if(vdot(direct_v1, clip_v) = 1)\n")
                        file.write('    #error "Shape_Slice_Plane_2P_1V error: Can\'t decide plane"\n')
                        file.write("#end\n\n")
                        file.write("#local norm = -vnormalize(clip_v - direct_v1*vdot(direct_v1,clip_v));\n")
                        file.write("#local d = vdot(norm, p1);\n")
                        file.write("plane{\n")
                        file.write("norm, d\n")
                        file.write("}\n")
                        file.write("#end\n\n")
                        file.write("//polygon to circle\n")
                        file.write("#macro Shape_Polygon_To_Circle_Blending(_polygon_n, _side_face, _polygon_circumscribed_radius, _circle_radius, _height)\n")
                        file.write("#local n = int(_polygon_n);\n")
                        file.write("#if(n < 3)\n")
                        file.write("    #error ""\n")