Skip to content
Snippets Groups Projects
shading.py 82 KiB
Newer Older
# SPDX-License-Identifier: GPL-2.0-or-later
Maurice Raybaud's avatar
Maurice Raybaud committed
"""Translate complex shaders to exported POV textures."""

def write_object_material_interior(material, ob, tab_write):
Maurice Raybaud's avatar
Maurice Raybaud committed
    """Translate some object level material from Blender UI (VS data level)

    to POV interior{} syntax and write it to exported file.
    This is called in object_mesh_topology.export_meshes
Maurice Raybaud's avatar
Maurice Raybaud committed
    """
    # 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.pov_subsurface_scattering.use:  # SSS IOR get highest priority
            tab_write("interior {\n")
            tab_write("ior %.6f\n" % material.pov_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:
            tab_write("interior {\n")
            tab_write("ior %.6f\n" % material.pov_raytrace_transparency.ior)
        elif material.pov.transparency_method == 'Z_TRANSPARENCY':
            tab_write("interior {\n")
            tab_write("ior 1.0\n")
        else:
            tab_write("interior {\n")
            tab_write("ior %.6f\n" % material.pov_raytrace_transparency.ior)

        pov_fake_caustics = False
        pov_photons_refraction = False
        pov_photons_reflection = False

        if material.pov.photons_reflection:
            pov_photons_reflection = True
        if not material.pov.refraction_caustics:
            pov_fake_caustics = False
            pov_photons_refraction = False
        elif material.pov.refraction_type == "1":
            pov_fake_caustics = True
            pov_photons_refraction = False
        elif material.pov.refraction_type == "2":
            pov_fake_caustics = False
            pov_photons_refraction = True

        # 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:
            if pov_fake_caustics:
                tab_write("caustics %.3g\n" % material.pov.fake_caustics_power)
            if pov_photons_refraction:
                # Default of 1 means no dispersion
                tab_write("dispersion %.6f\n" % material.pov.photons_dispersion)
                tab_write("dispersion_samples %.d\n" % material.pov.photons_dispersion_samples)
        # TODO
        # Other interior args
        if material.pov.use_transparency and material.pov.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
            tab_write(
                "fade_distance %.3g\n" % (100.001 - material.pov_raytrace_transparency.depth_max)
            )
            # fade_power
            tab_write("fade_power %.3g\n" % material.pov_raytrace_transparency.falloff)
            # fade_color
            tab_write("fade_color <%.3g, %.3g, %.3g>\n" % material.pov.interior_fade_color[:])

        # (variable) dispersion_samples (constant count for now)
        tab_write("}\n")
        if material.pov.photons_reflection or material.pov.refraction_type == "2":
            tab_write("photons{")
            tab_write("target %.3g\n" % ob.pov.spacing_multiplier)
            if not ob.pov.collect_photons:
                tab_write("collect off\n")
            if pov_photons_refraction:
                tab_write("refraction on\n")
            if pov_photons_reflection:
                tab_write("reflection on\n")
            tab_write("}\n")


def write_material(
    using_uberpov,
    DEF_MAT_NAME,
    tab_write,
    safety,
    comments,
    unique_name,
    material_names_dictionary,
    material
Maurice Raybaud's avatar
Maurice Raybaud committed
):
    """Translate Blender material to POV texture{} block and write in exported file."""
    # Assumes only called once on each material
    if material:
        name_orig = material.name
        name = material_names_dictionary[name_orig] = unique_name(
            bpy.path.clean_name(name_orig), material_names_dictionary
        # If saturation(.s) is not zero, then color is not grey, and has a tint
Maurice Raybaud's avatar
Maurice Raybaud committed
        colored_specular_found = (material.pov.specular_color.s > 0.0) and (
            material.pov.diffuse_shader != "MINNAERT"
        )
    else:
        name = name_orig = DEF_MAT_NAME
Maurice Raybaud's avatar
Maurice Raybaud committed
    # Several versions of the finish: ref_level_bound conditions are variations for specular/Mirror
    # texture channel map with alternative finish of 0 specular and no mirror reflection.
Maurice Raybaud's avatar
Maurice Raybaud committed
    # ref_level_bound=1 Means No specular nor Mirror reflection
    # ref_level_bound=2 Means translation of spec and mir levels for when no map influences them
    # ref_level_bound=3 Means Maximum Spec and Mirror
Maurice Raybaud's avatar
Maurice Raybaud committed
    def pov_has_no_specular_maps(ref_level_bound):
Maurice Raybaud's avatar
Maurice Raybaud committed
        """Translate Blender specular map influence to POV finish map trick and write to file."""
Maurice Raybaud's avatar
Maurice Raybaud committed
        if ref_level_bound == 1:
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write("//--No specular nor Mirror reflection--\n")
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write("\n")
            tab_write("#declare %s = finish {\n" % safety(name, ref_level_bound=1))
Maurice Raybaud's avatar
Maurice Raybaud committed
        elif ref_level_bound == 2:
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write(
                    "//--translation of spec and mir levels for when no map " "influences them--\n"
                )
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write("\n")
            tab_write("#declare %s = finish {\n" % safety(name, ref_level_bound=2))
Maurice Raybaud's avatar
Maurice Raybaud committed

Maurice Raybaud's avatar
Maurice Raybaud committed
        elif ref_level_bound == 3:
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write("//--Maximum Spec and Mirror--\n")
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write("\n")
            tab_write("#declare %s = finish {\n" % safety(name, ref_level_bound=3))
        if material:
            # POV-Ray 3.7 now uses two diffuse values respectively for front and back shading
            # (the back diffuse is like blender translucency)
Maurice Raybaud's avatar
Maurice Raybaud committed
            front_diffuse = material.pov.diffuse_intensity
            back_diffuse = material.pov.translucency
Maurice Raybaud's avatar
Maurice Raybaud committed
                # Total should not go above one
                if (front_diffuse + back_diffuse) <= 1.0:
Maurice Raybaud's avatar
Maurice Raybaud committed
                elif front_diffuse == back_diffuse:
                    # Try to respect the user's 'intention' by comparing the two values but
                    # bringing the total back to one.
Maurice Raybaud's avatar
Maurice Raybaud committed
                    front_diffuse = back_diffuse = 0.5
                # Let the highest value stay the highest value.
Maurice Raybaud's avatar
Maurice Raybaud committed
                elif front_diffuse > back_diffuse:
Maurice Raybaud's avatar
Maurice Raybaud committed
                    back_diffuse = min(back_diffuse, (1.0 - front_diffuse))
Maurice Raybaud's avatar
Maurice Raybaud committed
                    front_diffuse = min(front_diffuse, (1.0 - back_diffuse))

            # map hardness between 0.0 and 1.0
Maurice Raybaud's avatar
Maurice Raybaud committed
            roughness = 1.0 - ((material.pov.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.
Maurice Raybaud's avatar
Maurice Raybaud committed
            roughness += 1.0 / 511.0
            # ------------------------------ Diffuse Shader ------------------------------ #
Maurice Raybaud's avatar
Maurice Raybaud committed
            # Not used for Full spec (ref_level_bound=3) of the shader.
            if material.pov.diffuse_shader == "OREN_NAYAR" and ref_level_bound != 3:
                # Blender roughness is what is generally called oren nayar Sigma,
                # and brilliance in POV-Ray.
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write("brilliance %.3g\n" % (0.9 + material.roughness))
Maurice Raybaud's avatar
Maurice Raybaud committed
            if material.pov.diffuse_shader == "TOON" and ref_level_bound != 3:
                tab_write("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.
Maurice Raybaud's avatar
Maurice Raybaud committed
                front_diffuse *= 0.5
Maurice Raybaud's avatar
Maurice Raybaud committed
            if material.pov.diffuse_shader == "MINNAERT" and ref_level_bound != 3:
                # tab_write("aoi %.3g\n" % material.darkness)
                pass  # let's keep things simple for now
Maurice Raybaud's avatar
Maurice Raybaud committed
            if material.pov.diffuse_shader == "FRESNEL" and ref_level_bound != 3:
                # tab_write("aoi %.3g\n" % material.diffuse_fresnel_factor)
                pass  # let's keep things simple for now
Maurice Raybaud's avatar
Maurice Raybaud committed
            if material.pov.diffuse_shader == "LAMBERT" and ref_level_bound != 3:
                # trying to best match lambert attenuation by that constant brilliance value
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write("brilliance 1\n")
Maurice Raybaud's avatar
Maurice Raybaud committed
            if ref_level_bound == 2:
                # ------------------------------ Specular Shader ------------------------------ #
                # No difference between phong and cook torrence in blender HaHa!
Maurice Raybaud's avatar
Maurice Raybaud committed
                if (
                    material.pov.specular_shader == "COOKTORR"
                    or material.pov.specular_shader == "PHONG"
                ):
                    tab_write("phong %.3g\n" % material.pov.specular_intensity)
Maurice Raybaud's avatar
Maurice Raybaud committed
                    tab_write("phong_size %.3g\n" % (material.pov.specular_hardness / 3.14))

                # POV-Ray 'specular' keyword corresponds to a Blinn model, without the ior.
Maurice Raybaud's avatar
Maurice Raybaud committed
                elif material.pov.specular_shader == "BLINN":
                    # Use blender Blinn's IOR just as some factor for spec intensity
Maurice Raybaud's avatar
Maurice Raybaud committed
                    tab_write(
                        "specular %.3g\n"
                        % (material.pov.specular_intensity * (material.pov.specular_ior / 4.0))
                    )
                    tab_write("roughness %.3g\n" % roughness)
                    # Could use brilliance 2(or varying around 2 depending on ior or factor) too.

                elif material.pov.specular_shader == "TOON":
                    tab_write("phong %.3g\n" % (material.pov.specular_intensity * 2.0))
Maurice Raybaud's avatar
Maurice Raybaud committed
                    tab_write("phong_size %.3g\n" % (0.1 + material.pov.specular_toon_smooth / 2.0))
Maurice Raybaud's avatar
Maurice Raybaud committed
                elif material.pov.specular_shader == "WARDISO":
                    # find best suited default constant for brilliance Use both phong and
                    # specular for some values.
Maurice Raybaud's avatar
Maurice Raybaud committed
                    tab_write(
                        "specular %.3g\n"
                        % (material.pov.specular_intensity / (material.pov.specular_slope + 0.0005))
                    )
                    # find best suited default constant for brilliance Use both phong and
                    # specular for some values.
Maurice Raybaud's avatar
Maurice Raybaud committed
                    tab_write("roughness %.4g\n" % (0.0005 + material.pov.specular_slope / 10.0))
                    # find best suited default constant for brilliance Use both phong and
                    # specular for some values.
Maurice Raybaud's avatar
Maurice Raybaud committed
                    tab_write("brilliance %.4g\n" % (1.8 - material.pov.specular_slope * 1.8))
            # -------------------------------------------------------------------------------- #
Maurice Raybaud's avatar
Maurice Raybaud committed
            elif ref_level_bound == 1:
                if (
                    material.pov.specular_shader == "COOKTORR"
                    or material.pov.specular_shader == "PHONG"
                ):
                    tab_write("phong 0\n")  # %.3g\n" % (material.pov.specular_intensity/5))
Maurice Raybaud's avatar
Maurice Raybaud committed
                    tab_write("phong_size %.3g\n" % (material.pov.specular_hardness / 3.14))

                # POV-Ray 'specular' keyword corresponds to a Blinn model, without the ior.
Maurice Raybaud's avatar
Maurice Raybaud committed
                elif material.pov.specular_shader == "BLINN":
                    # Use blender Blinn's IOR just as some factor for spec intensity
Maurice Raybaud's avatar
Maurice Raybaud committed
                    tab_write(
                        "specular %.3g\n"
                        % (material.pov.specular_intensity * (material.pov.specular_ior / 4.0))
                    )
                    tab_write("roughness %.3g\n" % roughness)
                    # Could use brilliance 2(or varying around 2 depending on ior or factor) too.

                elif material.pov.specular_shader == "TOON":
                    tab_write("phong %.3g\n" % (material.pov.specular_intensity * 2.0))
                    # use extreme phong_size
Maurice Raybaud's avatar
Maurice Raybaud committed
                    tab_write("phong_size %.3g\n" % (0.1 + material.pov.specular_toon_smooth / 2.0))
Maurice Raybaud's avatar
Maurice Raybaud committed
                elif material.pov.specular_shader == "WARDISO":
                    # find best suited default constant for brilliance Use both phong and
                    # specular for some values.
Maurice Raybaud's avatar
Maurice Raybaud committed
                    tab_write(
                        "specular %.3g\n"
                        % (material.pov.specular_intensity / (material.pov.specular_slope + 0.0005))
                    )
                    # find best suited default constant for brilliance Use both phong and
                    # specular for some values.
Maurice Raybaud's avatar
Maurice Raybaud committed
                    tab_write("roughness %.4g\n" % (0.0005 + material.pov.specular_slope / 10.0))
                    # find best suited default constant for brilliance Use both phong and
                    # specular for some values.
Maurice Raybaud's avatar
Maurice Raybaud committed
                    tab_write("brilliance %.4g\n" % (1.8 - material.pov.specular_slope * 1.8))
            elif ref_level_bound == 3:
                # Spec must be Max at ref_level_bound 3 so that white of mixing texture always shows specularity
                # That's why it's multiplied by 255. maybe replace by texture's brightest pixel value?
                if material.pov_texture_slots:
                    max_spec_factor = (
                            material.pov.specular_intensity
                            * material.pov.specular_color.v
                            * 255
                            * slot.specular_factor
Maurice Raybaud's avatar
Maurice Raybaud committed
                    )
                else:
                    max_spec_factor = (
                            material.pov.specular_intensity
                            * material.pov.specular_color.v
                            * 255
                    )
                tab_write("specular %.3g\n" % max_spec_factor)
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write("roughness %.3g\n" % (1 / material.pov.specular_hardness))
            tab_write("diffuse %.3g %.3g\n" % (front_diffuse, back_diffuse))

            tab_write("ambient %.3g\n" % material.pov.ambient)
            # POV-Ray blends the global value
Maurice Raybaud's avatar
Maurice Raybaud committed
            # tab_write("ambient rgb <%.3g, %.3g, %.3g>\n" % \
            #         tuple([c*material.pov.ambient for c in world.ambient_color]))
Maurice Raybaud's avatar
Maurice Raybaud committed
            tab_write("emission %.3g\n" % material.pov.emit)  # New in POV-Ray 3.7
Maurice Raybaud's avatar
Maurice Raybaud committed
            # POV-Ray just ignores roughness if there's no specular keyword
            # tab_write("roughness %.3g\n" % roughness)

            if material.pov.conserve_energy:
                # added for more realistic shading. Needs some checking to see if it
                # really works. --Maurice.
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write("conserve_energy\n")
Maurice Raybaud's avatar
Maurice Raybaud committed
            if colored_specular_found:
                tab_write("metallic\n")
Maurice Raybaud's avatar
Maurice Raybaud committed
            if ref_level_bound != 1:
                if material.pov_raytrace_mirror.use:
                    raytrace_mirror = material.pov_raytrace_mirror
                    if raytrace_mirror.reflect_factor:
Maurice Raybaud's avatar
Maurice Raybaud committed
                        tab_write("reflection {\n")
                        tab_write("rgb <%.3g, %.3g, %.3g>\n" % material.pov.mirror_color[:])
                        if material.pov.mirror_metallic:
                            tab_write("metallic %.3g\n" % raytrace_mirror.reflect_factor)
                        # Blurry reflections for UberPOV
                        if using_uberpov and raytrace_mirror.gloss_factor < 1.0:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            # tab_write("#ifdef(unofficial) #if(unofficial = \"patch\") #if(patch(\"upov-reflection-roughness\") > 0)\n")
                            tab_write(
                                "roughness %.6f\n" % (0.000001 / raytrace_mirror.gloss_factor)
                            )
                            # tab_write("#end #end #end\n") # This and previous comment for backward compatibility, messier pov code
                        if material.pov.mirror_use_IOR:  # WORKING ?
                            # Removed from the line below: gives a more physically correct
                            # material but needs proper IOR. --Maurice
Maurice Raybaud's avatar
Maurice Raybaud committed
                            tab_write("fresnel 1 ")
                        tab_write(
                            "falloff %.3g exponent %.3g} "
                            % (raytrace_mirror.fresnel, raytrace_mirror.fresnel_factor)
                        )
            if material.pov_subsurface_scattering.use:
                subsurface_scattering = material.pov_subsurface_scattering
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write(
                    "subsurface { translucency <%.3g, %.3g, %.3g> }\n"
                    % (
                        (subsurface_scattering.radius[0]),
                        (subsurface_scattering.radius[1]),
                        (subsurface_scattering.radius[2]),
                    )
                )
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write(
                    "irid { %.4g thickness %.4g turbulence %.4g }"
                    % (
                        material.pov.irid_amount,
                        material.pov.irid_thickness,
                        material.pov.irid_turbulence,
                    )
                )
Maurice Raybaud's avatar
Maurice Raybaud committed
            tab_write("diffuse 0.8\n")
            tab_write("phong 70.0\n")
Maurice Raybaud's avatar
Maurice Raybaud committed
            # tab_write("specular 0.2\n")

        # This is written into the object
Maurice Raybaud's avatar
Maurice Raybaud committed
        """
        if material and material.pov.transparency_method=='RAYTRACE':
            'interior { ior %.3g} ' % material.raytrace_transparency.ior
Maurice Raybaud's avatar
Maurice Raybaud committed
        """
Maurice Raybaud's avatar
Maurice Raybaud committed
        # tab_write("crand 1.0\n") # Sand granyness
        # tab_write("metallic %.6f\n" % material.spec)
        # tab_write("phong %.6f\n" % material.spec)
        # tab_write("phong_size %.6f\n" % material.spec)
        # tab_write("brilliance %.6f " % (material.pov.specular_hardness/256.0) # Like hardness
Maurice Raybaud's avatar
Maurice Raybaud committed
        tab_write("}\n\n")
Maurice Raybaud's avatar
Maurice Raybaud committed
    # ref_level_bound=2 Means translation of spec and mir levels for when no map influences them
    pov_has_no_specular_maps(ref_level_bound=2)

    if material:
        special_texture_found = False
        for t in material.pov_texture_slots:
Maurice Raybaud's avatar
Maurice Raybaud committed
            # index = material.pov.active_texture_index
Maurice Raybaud's avatar
Maurice Raybaud committed
            slot = material.pov_texture_slots[tmpidx]  # [index]
            povtex = slot.texture  # slot.name
Maurice Raybaud's avatar
Maurice Raybaud committed
            tex = bpy.data.textures[povtex]

Maurice Raybaud's avatar
Maurice Raybaud committed
            if t and t.use and tex is not None:
Maurice Raybaud's avatar
Maurice Raybaud committed
                if (tex.type == "IMAGE" and tex.image) or tex.type != "IMAGE":
                    # validPath
                    if (
                        t
                        and t.use
                        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:
Maurice Raybaud's avatar
Maurice Raybaud committed
            # ref_level_bound=1 Means No specular nor Mirror reflection
            pov_has_no_specular_maps(ref_level_bound=1)

            # ref_level_bound=3 Means Maximum Spec and Mirror
            pov_has_no_specular_maps(ref_level_bound=3)
Maurice Raybaud's avatar
Maurice Raybaud committed

Maurice Raybaud's avatar
Maurice Raybaud committed
def export_pattern(texture):
Maurice Raybaud's avatar
Maurice Raybaud committed
    """Translate Blender procedural textures to POV patterns and write to pov file.
Maurice Raybaud's avatar
Maurice Raybaud committed
    Function Patterns can be used to better access sub components of a pattern like
Maurice Raybaud's avatar
Maurice Raybaud committed
    grey values for influence mapping
    """
    tex = texture
Maurice Raybaud's avatar
Maurice Raybaud committed
    pat = tex.pov
Maurice Raybaud's avatar
Maurice Raybaud committed
    pat_name = "PAT_%s" % string_strip_hyphen(bpy.path.clean_name(tex.name))
    mapping_dif = "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,
    )
    text_strg = ""

    def export_color_ramp(texture):
        tex = texture
Campbell Barton's avatar
Campbell Barton committed
        pat = tex.pov
Maurice Raybaud's avatar
Maurice Raybaud committed
        col_ramp_strg = "color_map {\n"
        num_color = 0
Maurice Raybaud's avatar
Maurice Raybaud committed
        for el in tex.color_ramp.elements:
Maurice Raybaud's avatar
Maurice Raybaud committed
            num_color += 1
Maurice Raybaud's avatar
Maurice Raybaud committed
            pos = el.position
Maurice Raybaud's avatar
Maurice Raybaud committed
            col = el.color
            col_r, col_g, col_b, col_a = col[0], col[1], col[2], 1 - col[3]
            if pat.tex_pattern_type not in {"checker", "hexagon", "square", "triangular", "brick"}:
                col_ramp_strg += "[%.4g color rgbf<%.4g,%.4g,%.4g,%.4g>] \n" % (
                    pos,
                    col_r,
                    col_g,
                    col_b,
                    col_a,
                )
            if pat.tex_pattern_type in {"brick", "checker"} and num_color < 3:
                col_ramp_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
            if pat.tex_pattern_type == "hexagon" and num_color < 4:
                col_ramp_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
            if pat.tex_pattern_type == "square" and num_color < 5:
                col_ramp_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
            if pat.tex_pattern_type == "triangular" and num_color < 7:
                col_ramp_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)

        col_ramp_strg += "} \n"
        # end color map
        return col_ramp_strg

    # much work to be done here only defaults translated for now:
    # pov noise_generator 3 means perlin noise
    if tex.type not in {"NONE", "IMAGE"} and pat.tex_pattern_type == "emulator":
        text_strg += "pigment {\n"
        # ------------------------- EMULATE BLENDER VORONOI TEXTURE ------------------------- #
Maurice Raybaud's avatar
Maurice Raybaud committed
        if tex.type == "VORONOI":
            text_strg += "crackle\n"
            text_strg += "    offset %.4g\n" % tex.nabla
            text_strg += "    form <%.4g,%.4g,%.4g>\n" % (tex.weight_1, tex.weight_2, tex.weight_3)
            if tex.distance_metric == "DISTANCE":
                text_strg += "    metric 2.5\n"
            if tex.distance_metric == "DISTANCE_SQUARED":
                text_strg += "    metric 2.5\n"
                text_strg += "    poly_wave 2\n"
            if tex.distance_metric == "MINKOVSKY":
                text_strg += "    metric %s\n" % tex.minkovsky_exponent
            if tex.distance_metric == "MINKOVSKY_FOUR":
                text_strg += "    metric 4\n"
            if tex.distance_metric == "MINKOVSKY_HALF":
                text_strg += "    metric 0.5\n"
            if tex.distance_metric == "CHEBYCHEV":
                text_strg += "    metric 10\n"
            if tex.distance_metric == "MANHATTAN":
                text_strg += "    metric 1\n"

            if tex.color_mode == "POSITION":
                text_strg += "solid\n"
            text_strg += "scale 0.25\n"
            if tex.use_color_ramp:
                text_strg += export_color_ramp(tex)
Maurice Raybaud's avatar
Maurice Raybaud committed
            else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                text_strg += "color_map {\n"
                text_strg += "[0 color rgbt<0,0,0,1>]\n"
                text_strg += "[1 color rgbt<1,1,1,0>]\n"
                text_strg += "}\n"
        # ------------------------- EMULATE BLENDER CLOUDS TEXTURE ------------------------- #
Maurice Raybaud's avatar
Maurice Raybaud committed
        if tex.type == "CLOUDS":
            if tex.noise_type == "SOFT_NOISE":
                text_strg += "wrinkles\n"
                text_strg += "scale 0.25\n"
Maurice Raybaud's avatar
Maurice Raybaud committed
            else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                text_strg += "granite\n"
            if tex.use_color_ramp:
                text_strg += export_color_ramp(tex)
Maurice Raybaud's avatar
Maurice Raybaud committed
            else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                text_strg += "color_map {\n"
                text_strg += "[0 color rgbt<0,0,0,1>]\n"
                text_strg += "[1 color rgbt<1,1,1,0>]\n"
                text_strg += "}\n"
        # ------------------------- EMULATE BLENDER WOOD TEXTURE ------------------------- #
Maurice Raybaud's avatar
Maurice Raybaud committed
        if tex.type == "WOOD":
            if tex.wood_type == "RINGS":
                text_strg += "wood\n"
                text_strg += "scale 0.25\n"
            if tex.wood_type == "RINGNOISE":
                text_strg += "wood\n"
                text_strg += "scale 0.25\n"
                text_strg += "turbulence %.4g\n" % (tex.turbulence / 100)
            if tex.wood_type == "BANDS":
                text_strg += "marble\n"
                text_strg += "scale 0.25\n"
                text_strg += "rotate <45,-45,45>\n"
            if tex.wood_type == "BANDNOISE":
                text_strg += "marble\n"
                text_strg += "scale 0.25\n"
                text_strg += "rotate <45,-45,45>\n"
                text_strg += "turbulence %.4g\n" % (tex.turbulence / 10)

            if tex.noise_basis_2 == "SIN":
                text_strg += "sine_wave\n"
            if tex.noise_basis_2 == "TRI":
                text_strg += "triangle_wave\n"
            if tex.noise_basis_2 == "SAW":
                text_strg += "ramp_wave\n"
            if tex.use_color_ramp:
                text_strg += export_color_ramp(tex)
Maurice Raybaud's avatar
Maurice Raybaud committed
            else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                text_strg += "color_map {\n"
                text_strg += "[0 color rgbt<0,0,0,0>]\n"
                text_strg += "[1 color rgbt<1,1,1,0>]\n"
                text_strg += "}\n"
        # ------------------------- EMULATE BLENDER STUCCI TEXTURE ------------------------- #
Maurice Raybaud's avatar
Maurice Raybaud committed
        if tex.type == "STUCCI":
            text_strg += "bozo\n"
            text_strg += "scale 0.25\n"
            if tex.noise_type == "HARD_NOISE":
                text_strg += "triangle_wave\n"
                if tex.use_color_ramp:
                    text_strg += export_color_ramp(tex)
Maurice Raybaud's avatar
Maurice Raybaud committed
                else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                    text_strg += "color_map {\n"
                    text_strg += "[0 color rgbf<1,1,1,0>]\n"
                    text_strg += "[1 color rgbt<0,0,0,1>]\n"
                    text_strg += "}\n"
Maurice Raybaud's avatar
Maurice Raybaud committed
            else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                if tex.use_color_ramp:
                    text_strg += export_color_ramp(tex)
Maurice Raybaud's avatar
Maurice Raybaud committed
                else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                    text_strg += "color_map {\n"
                    text_strg += "[0 color rgbf<0,0,0,1>]\n"
                    text_strg += "[1 color rgbt<1,1,1,0>]\n"
                    text_strg += "}\n"
        # ------------------------- EMULATE BLENDER MAGIC TEXTURE ------------------------- #
Maurice Raybaud's avatar
Maurice Raybaud committed
        if tex.type == "MAGIC":
            text_strg += "leopard\n"
            if tex.use_color_ramp:
                text_strg += export_color_ramp(tex)
Maurice Raybaud's avatar
Maurice Raybaud committed
            else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                text_strg += "color_map {\n"
                text_strg += "[0 color rgbt<1,1,1,0.5>]\n"
                text_strg += "[0.25 color rgbf<0,1,0,0.75>]\n"
                text_strg += "[0.5 color rgbf<0,0,1,0.75>]\n"
                text_strg += "[0.75 color rgbf<1,0,1,0.75>]\n"
                text_strg += "[1 color rgbf<0,1,0,0.75>]\n"
                text_strg += "}\n"
            text_strg += "scale 0.1\n"
        # ------------------------- EMULATE BLENDER MARBLE TEXTURE ------------------------- #
Maurice Raybaud's avatar
Maurice Raybaud committed
        if tex.type == "MARBLE":
            text_strg += "marble\n"
            text_strg += "turbulence 0.5\n"
            text_strg += "noise_generator 3\n"
            text_strg += "scale 0.75\n"
            text_strg += "rotate <45,-45,45>\n"
            if tex.use_color_ramp:
                text_strg += export_color_ramp(tex)
Maurice Raybaud's avatar
Maurice Raybaud committed
            else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                if tex.marble_type == "SOFT":
                    text_strg += "color_map {\n"
                    text_strg += "[0 color rgbt<0,0,0,0>]\n"
                    text_strg += "[0.05 color rgbt<0,0,0,0>]\n"
                    text_strg += "[1 color rgbt<0.9,0.9,0.9,0>]\n"
                    text_strg += "}\n"
                elif tex.marble_type == "SHARP":
                    text_strg += "color_map {\n"
                    text_strg += "[0 color rgbt<0,0,0,0>]\n"
                    text_strg += "[0.025 color rgbt<0,0,0,0>]\n"
                    text_strg += "[1 color rgbt<0.9,0.9,0.9,0>]\n"
                    text_strg += "}\n"
Maurice Raybaud's avatar
Maurice Raybaud committed
                else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                    text_strg += "[0 color rgbt<0,0,0,0>]\n"
                    text_strg += "[1 color rgbt<1,1,1,0>]\n"
                    text_strg += "}\n"
            if tex.noise_basis_2 == "SIN":
                text_strg += "sine_wave\n"
            if tex.noise_basis_2 == "TRI":
                text_strg += "triangle_wave\n"
            if tex.noise_basis_2 == "SAW":
                text_strg += "ramp_wave\n"
        # ------------------------- EMULATE BLENDER BLEND TEXTURE ------------------------- #
Maurice Raybaud's avatar
Maurice Raybaud committed
        if tex.type == "BLEND":
            if tex.progression == "RADIAL":
                text_strg += "radial\n"
                if tex.use_flip_axis == "HORIZONTAL":
                    text_strg += "rotate x*90\n"
Maurice Raybaud's avatar
Maurice Raybaud committed
                else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                    text_strg += "rotate <-90,0,90>\n"
                text_strg += "ramp_wave\n"
            elif tex.progression == "SPHERICAL":
                text_strg += "spherical\n"
                text_strg += "scale 3\n"
                text_strg += "poly_wave 1\n"
            elif tex.progression == "QUADRATIC_SPHERE":
                text_strg += "spherical\n"
                text_strg += "scale 3\n"
                text_strg += "    poly_wave 2\n"
            elif tex.progression == "DIAGONAL":
                text_strg += "gradient <1,1,0>\n"
                text_strg += "scale 3\n"
            elif tex.use_flip_axis == "HORIZONTAL":
                text_strg += "gradient x\n"
                text_strg += "scale 2.01\n"
            elif tex.use_flip_axis == "VERTICAL":
                text_strg += "gradient y\n"
                text_strg += "scale 2.01\n"
            # text_strg+="ramp_wave\n"
            # text_strg+="frequency 0.5\n"
            text_strg += "phase 0.5\n"
            if tex.use_color_ramp:
                text_strg += export_color_ramp(tex)
Maurice Raybaud's avatar
Maurice Raybaud committed
            else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                text_strg += "color_map {\n"
                text_strg += "[0 color rgbt<1,1,1,0>]\n"
                text_strg += "[1 color rgbf<0,0,0,1>]\n"
                text_strg += "}\n"
            if tex.progression == "LINEAR":
                text_strg += "    poly_wave 1\n"
            if tex.progression == "QUADRATIC":
                text_strg += "    poly_wave 2\n"
            if tex.progression == "EASING":
                text_strg += "    poly_wave 1.5\n"
        # ------------------------- EMULATE BLENDER MUSGRAVE TEXTURE ------------------------- #
Campbell Barton's avatar
Campbell Barton committed
        # if tex.type == 'MUSGRAVE':
Maurice Raybaud's avatar
Maurice Raybaud committed
        # text_strg+="function{ f_ridged_mf( x, y, 0, 1, 2, 9, -0.5, 3,3 )*0.5}\n"
        # text_strg+="color_map {\n"
        # text_strg+="[0 color rgbf<0,0,0,1>]\n"
        # text_strg+="[1 color rgbf<1,1,1,0>]\n"
        # text_strg+="}\n"
Maurice Raybaud's avatar
Maurice Raybaud committed
        # simplified for now:

Maurice Raybaud's avatar
Maurice Raybaud committed
        if tex.type == "MUSGRAVE":
            text_strg += "bozo scale 0.25 \n"
            if tex.use_color_ramp:
                text_strg += export_color_ramp(tex)
Campbell Barton's avatar
Campbell Barton committed
            else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                text_strg += (
                    "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 ------------------------- #
Maurice Raybaud's avatar
Maurice Raybaud committed
        if tex.type == "DISTORTED_NOISE":
            text_strg += "average\n"
            text_strg += "  pigment_map {\n"
            text_strg += "  [1 bozo scale 0.25 turbulence %.4g\n" % tex.distortion
            if tex.use_color_ramp:
                text_strg += export_color_ramp(tex)
Campbell Barton's avatar
Campbell Barton committed
            else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                text_strg += "color_map {\n"
                text_strg += "[0 color rgbt<1,1,1,0>]\n"
                text_strg += "[1 color rgbf<0,0,0,1>]\n"
                text_strg += "}\n"
            text_strg += "]\n"

            if tex.noise_distortion == "CELL_NOISE":
                text_strg += "  [1 cells scale 0.1\n"
                if tex.use_color_ramp:
                    text_strg += export_color_ramp(tex)
Campbell Barton's avatar
Campbell Barton committed
                else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                    text_strg += "color_map {\n"
                    text_strg += "[0 color rgbt<1,1,1,0>]\n"
                    text_strg += "[1 color rgbf<0,0,0,1>]\n"
                    text_strg += "}\n"
                text_strg += "]\n"
            if tex.noise_distortion == "VORONOI_CRACKLE":
                text_strg += "  [1 crackle scale 0.25\n"
                if tex.use_color_ramp:
                    text_strg += export_color_ramp(tex)
Campbell Barton's avatar
Campbell Barton committed
                else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                    text_strg += "color_map {\n"
                    text_strg += "[0 color rgbt<1,1,1,0>]\n"
                    text_strg += "[1 color rgbf<0,0,0,1>]\n"
                    text_strg += "}\n"
                text_strg += "]\n"
            if tex.noise_distortion in [
                "VORONOI_F1",
                "VORONOI_F2",
                "VORONOI_F3",
                "VORONOI_F4",
                "VORONOI_F2_F1",
            ]:
                text_strg += "  [1 crackle metric 2.5 scale 0.25 turbulence %.4g\n" % (
                    tex.distortion / 2
                )
                if tex.use_color_ramp:
                    text_strg += export_color_ramp(tex)
Campbell Barton's avatar
Campbell Barton committed
                else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                    text_strg += "color_map {\n"
                    text_strg += "[0 color rgbt<1,1,1,0>]\n"
                    text_strg += "[1 color rgbf<0,0,0,1>]\n"
                    text_strg += "}\n"
                text_strg += "]\n"
Maurice Raybaud's avatar
Maurice Raybaud committed
            else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                text_strg += "  [1 wrinkles scale 0.25\n"
                if tex.use_color_ramp:
                    text_strg += export_color_ramp(tex)
Campbell Barton's avatar
Campbell Barton committed
                else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                    text_strg += "color_map {\n"
                    text_strg += "[0 color rgbt<1,1,1,0>]\n"
                    text_strg += "[1 color rgbf<0,0,0,1>]\n"
                    text_strg += "}\n"
                text_strg += "]\n"
            text_strg += "  }\n"
        # ------------------------- EMULATE BLENDER NOISE TEXTURE ------------------------- #
Maurice Raybaud's avatar
Maurice Raybaud committed
        if tex.type == "NOISE":
            text_strg += "cells\n"
            text_strg += "turbulence 3\n"
            text_strg += "omega 3\n"
            if tex.use_color_ramp:
                text_strg += export_color_ramp(tex)
Campbell Barton's avatar
Campbell Barton committed
            else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                text_strg += "color_map {\n"
                text_strg += "[0.75 color rgb<0,0,0,>]\n"
                text_strg += "[1 color rgb<1,1,1,>]\n"
                text_strg += "}\n"
Maurice Raybaud's avatar
Maurice Raybaud committed

        # ------------------------- IGNORE OTHER BLENDER TEXTURE ------------------------- #
Maurice Raybaud's avatar
Maurice Raybaud committed
        else:  # non translated textures
Maurice Raybaud's avatar
Maurice Raybaud committed
            pass
Maurice Raybaud's avatar
Maurice Raybaud committed
        text_strg += "}\n\n"

        text_strg += "#declare f%s=\n" % pat_name
        text_strg += "function{pigment{%s}}\n" % pat_name
        text_strg += "\n"

    elif pat.tex_pattern_type != "emulator":
        text_strg += "pigment {\n"
        text_strg += "%s\n" % pat.tex_pattern_type
        if pat.tex_pattern_type == "agate":
            text_strg += "agate_turb %.4g\n" % pat.modifier_turbulence
        if pat.tex_pattern_type in {"spiral1", "spiral2", "tiling"}:
            text_strg += "%s\n" % pat.modifier_numbers
        if pat.tex_pattern_type == "quilted":
            text_strg += "control0 %s control1 %s\n" % (
                pat.modifier_control0,
                pat.modifier_control1,
            )
        if pat.tex_pattern_type == "mandel":
            text_strg += "%s exponent %s \n" % (pat.f_iter, pat.f_exponent)
        if pat.tex_pattern_type == "julia":
            text_strg += "<%.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":
            text_strg += "%s mandel %s \n" % (pat.magnet_type, pat.f_iter)
        if pat.tex_pattern_type == "magnet" and pat.magnet_style == "julia":
            text_strg += "%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"}:
            text_strg += "interior %s, %.4g\n" % (pat.f_ior, pat.f_ior_fac)
            text_strg += "exterior %s, %.4g\n" % (pat.f_eor, pat.f_eor_fac)
        if pat.tex_pattern_type == "gradient":
            text_strg += "<%s, %s, %s> \n" % (
                pat.grad_orient_x,
                pat.grad_orient_y,
                pat.grad_orient_z,
            )
        if pat.tex_pattern_type == "pavement":
            num_tiles = pat.pave_tiles
            num_pattern = 1
            if pat.pave_sides == "4" and pat.pave_tiles == 3:
                num_pattern = pat.pave_pat_2
            if pat.pave_sides == "6" and pat.pave_tiles == 3:
                num_pattern = pat.pave_pat_3
            if pat.pave_sides == "3" and pat.pave_tiles == 4:
                num_pattern = pat.pave_pat_3
            if pat.pave_sides == "3" and pat.pave_tiles == 5:
                num_pattern = pat.pave_pat_4
            if pat.pave_sides == "4" and pat.pave_tiles == 4:
                num_pattern = pat.pave_pat_5
            if pat.pave_sides == "6" and pat.pave_tiles == 4:
                num_pattern = pat.pave_pat_7
            if pat.pave_sides == "4" and pat.pave_tiles == 5:
                num_pattern = pat.pave_pat_12
            if pat.pave_sides == "3" and pat.pave_tiles == 6:
                num_pattern = pat.pave_pat_12
            if pat.pave_sides == "6" and pat.pave_tiles == 5:
                num_pattern = pat.pave_pat_22
            if pat.pave_sides == "4" and pat.pave_tiles == 6:
                num_pattern = pat.pave_pat_35
            if pat.pave_sides == "6" and pat.pave_tiles == 6:
                num_tiles = 5
            text_strg += "number_of_sides %s number_of_tiles %s pattern %s form %s \n" % (
                pat.pave_sides,
                num_tiles,
                num_pattern,
                pat.pave_form,
            )
        # ------------------------- functions ------------------------- #
Maurice Raybaud's avatar
Maurice Raybaud committed
        if pat.tex_pattern_type == "function":
            text_strg += "{ %s" % pat.func_list
            text_strg += "(x"
Maurice Raybaud's avatar
Maurice Raybaud committed
            if pat.func_plus_x != "NONE":
Maurice Raybaud's avatar
Maurice Raybaud committed
                if pat.func_plus_x == "increase":
                    text_strg += "*"
                if pat.func_plus_x == "plus":
                    text_strg += "+"
                text_strg += "%.4g" % pat.func_x
            text_strg += ",y"
Maurice Raybaud's avatar
Maurice Raybaud committed
            if pat.func_plus_y != "NONE":
Maurice Raybaud's avatar
Maurice Raybaud committed
                if pat.func_plus_y == "increase":
                    text_strg += "*"
                if pat.func_plus_y == "plus":
                    text_strg += "+"
                text_strg += "%.4g" % pat.func_y
            text_strg += ",z"
Maurice Raybaud's avatar
Maurice Raybaud committed
            if pat.func_plus_z != "NONE":
Maurice Raybaud's avatar
Maurice Raybaud committed
                if pat.func_plus_z == "increase":
                    text_strg += "*"
                if pat.func_plus_z == "plus":
                    text_strg += "+"
                text_strg += "%.4g" % pat.func_z
Maurice Raybaud's avatar
Maurice Raybaud committed
            sort = -1
Maurice Raybaud's avatar
Maurice Raybaud committed
            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",
            }:
Maurice Raybaud's avatar
Maurice Raybaud committed
                sort = 0
Maurice Raybaud's avatar
Maurice Raybaud committed
            if pat.func_list in {
                "f_bicorn",
                "f_bifolia",
                "f_boy_surface",
                "f_superellipsoid",
                "f_torus",
            }:
Maurice Raybaud's avatar
Maurice Raybaud committed
                sort = 1
Maurice Raybaud's avatar
Maurice Raybaud committed
            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",
            }:
Maurice Raybaud's avatar
Maurice Raybaud committed
                sort = 2
Maurice Raybaud's avatar
Maurice Raybaud committed
            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",
            }:
Maurice Raybaud's avatar
Maurice Raybaud committed
                sort = 3
Maurice Raybaud's avatar
Maurice Raybaud committed
            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",
            }:
Maurice Raybaud's avatar
Maurice Raybaud committed
                sort = 4
Maurice Raybaud's avatar
Maurice Raybaud committed
            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",
            }:
Maurice Raybaud's avatar
Maurice Raybaud committed
                sort = 5
Maurice Raybaud's avatar
Maurice Raybaud committed
            if pat.func_list in {"f_helix1", "f_helix2", "f_piriform_2d", "f_strophoid_2d"}:
Maurice Raybaud's avatar
Maurice Raybaud committed
                sort = 6
            if pat.func_list == "f_helical_torus":
                sort = 7
            if sort > -1:
Maurice Raybaud's avatar
Maurice Raybaud committed
                text_strg += ",%.4g" % pat.func_P0
Maurice Raybaud's avatar
Maurice Raybaud committed
            if sort > 0:
Maurice Raybaud's avatar
Maurice Raybaud committed
                text_strg += ",%.4g" % pat.func_P1
Maurice Raybaud's avatar
Maurice Raybaud committed
            if sort > 1:
Maurice Raybaud's avatar
Maurice Raybaud committed
                text_strg += ",%.4g" % pat.func_P2
Maurice Raybaud's avatar
Maurice Raybaud committed
            if sort > 2:
Maurice Raybaud's avatar
Maurice Raybaud committed
                text_strg += ",%.4g" % pat.func_P3
Maurice Raybaud's avatar
Maurice Raybaud committed
            if sort > 3:
Maurice Raybaud's avatar
Maurice Raybaud committed
                text_strg += ",%.4g" % pat.func_P4
Maurice Raybaud's avatar
Maurice Raybaud committed
            if sort > 4:
Maurice Raybaud's avatar
Maurice Raybaud committed
                text_strg += ",%.4g" % pat.func_P5
Maurice Raybaud's avatar
Maurice Raybaud committed
            if sort > 5:
Maurice Raybaud's avatar
Maurice Raybaud committed
                text_strg += ",%.4g" % pat.func_P6
Maurice Raybaud's avatar
Maurice Raybaud committed
            if sort > 6:
Maurice Raybaud's avatar
Maurice Raybaud committed
                text_strg += ",%.4g" % pat.func_P7
                text_strg += ",%.4g" % pat.func_P8
                text_strg += ",%.4g" % pat.func_P9
            text_strg += ")}\n"
        # ------------------------- end functions ------------------------- #
Maurice Raybaud's avatar
Maurice Raybaud committed
        if pat.tex_pattern_type not in {"checker", "hexagon", "square", "triangular", "brick"}:
            text_strg += "color_map {\n"
        num_color = 0
        if tex.use_color_ramp:
Maurice Raybaud's avatar
Maurice Raybaud committed
            for el in tex.color_ramp.elements:
Maurice Raybaud's avatar
Maurice Raybaud committed
                num_color += 1
Maurice Raybaud's avatar
Maurice Raybaud committed
                pos = el.position
Maurice Raybaud's avatar
Maurice Raybaud committed
                col = el.color
                col_r, col_g, col_b, col_a = col[0], col[1], col[2], 1 - col[3]
                if pat.tex_pattern_type not in {
                    "checker",
                    "hexagon",
                    "square",
                    "triangular",
                    "brick",
                }:
                    text_strg += "[%.4g color rgbf<%.4g,%.4g,%.4g,%.4g>] \n" % (
                        pos,
                        col_r,
                        col_g,
                        col_b,
                        col_a,
                    )
                if pat.tex_pattern_type in {"brick", "checker"} and num_color < 3:
                    text_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
                if pat.tex_pattern_type == "hexagon" and num_color < 4:
                    text_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
                if pat.tex_pattern_type == "square" and num_color < 5:
                    text_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
                if pat.tex_pattern_type == "triangular" and num_color < 7:
                    text_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
Maurice Raybaud's avatar
Maurice Raybaud committed
        else:
Maurice Raybaud's avatar
Maurice Raybaud committed
            text_strg += "[0 color rgbf<0,0,0,1>]\n"
            text_strg += "[1 color rgbf<1,1,1,0>]\n"
        if pat.tex_pattern_type not in {"checker", "hexagon", "square", "triangular", "brick"}:
            text_strg += "} \n"
        if pat.tex_pattern_type == "brick":
            text_strg += "brick_size <%.4g, %.4g, %.4g> mortar %.4g \n" % (
                pat.brick_size_x,
                pat.brick_size_y,
                pat.brick_size_z,
                pat.brick_mortar,
            )
        text_strg += "%s \n" % mapping_dif
        text_strg += "rotate <%.4g,%.4g,%.4g> \n" % (pat.tex_rot_x, pat.tex_rot_y, pat.tex_rot_z)
        text_strg += "turbulence <%.4g,%.4g,%.4g> \n" % (
            pat.warp_turbulence_x,
            pat.warp_turbulence_y,
            pat.warp_turbulence_z,
        )
        text_strg += "octaves %s \n" % pat.modifier_octaves
        text_strg += "lambda %.4g \n" % pat.modifier_lambda
        text_strg += "omega %.4g \n" % pat.modifier_omega
        text_strg += "frequency %.4g \n" % pat.modifier_frequency
        text_strg += "phase %.4g \n" % pat.modifier_phase
        text_strg += "}\n\n"
        text_strg += "#declare f%s=\n" % pat_name
        text_strg += "function{pigment{%s}}\n" % pat_name
        text_strg += "\n"
    return text_strg

def string_strip_hyphen(name):
Maurice Raybaud's avatar
Maurice Raybaud committed
    """POV naming schemes like to conform to most restrictive charsets."""
    return name.replace("-", "")
# WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
def write_nodes(pov_mat_name, ntree, file):
Maurice Raybaud's avatar
Maurice Raybaud committed
    """Translate Blender node trees to pov and write them to file."""
    # such function local inlined import are official guidelines
    # of Blender Foundation to lighten addons footprint at startup
    from os import path

    declare_nodes = []
    scene = bpy.context.scene
    for node in ntree.nodes:
Maurice Raybaud's avatar
Maurice Raybaud committed
        pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
        if node.bl_idname == "PovrayFinishNode" and node.outputs["Finish"].is_linked:
Maurice Raybaud's avatar
Maurice Raybaud committed
            file.write("#declare %s = finish {\n" % pov_node_name)
            emission = node.inputs["Emission"].default_value
            if node.inputs["Emission"].is_linked:
                pass
Maurice Raybaud's avatar
Maurice Raybaud committed
            file.write("    emission %.4g\n" % emission)
            for link in ntree.links:
                if link.to_node == node:

Maurice Raybaud's avatar
Maurice Raybaud committed
                    if link.from_node.bl_idname == "PovrayDiffuseNode":
                        intensity = 0
                        albedo = ""
                        brilliance = 0
                        crand = 0
                        if link.from_node.inputs["Intensity"].is_linked:
                            pass
                        else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            intensity = link.from_node.inputs["Intensity"].default_value
                        if link.from_node.inputs["Albedo"].is_linked:
                            pass
                        else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            if link.from_node.inputs["Albedo"].default_value:
                                albedo = "albedo"
Maurice Raybaud's avatar
Maurice Raybaud committed
                        file.write("    diffuse %s %.4g\n" % (albedo, intensity))
                        if link.from_node.inputs["Brilliance"].is_linked:
                            pass
                        else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            brilliance = link.from_node.inputs["Brilliance"].default_value
                        file.write("    brilliance %.4g\n" % brilliance)
                        if link.from_node.inputs["Crand"].is_linked:
                            pass
                        else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            crand = link.from_node.inputs["Crand"].default_value
                        if crand > 0:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            file.write("    crand %.4g\n" % crand)
Maurice Raybaud's avatar
Maurice Raybaud committed
                    if link.from_node.bl_idname == "PovraySubsurfaceNode":
                        if scene.povray.sslt_enable:
                            energy = 0
                            r = g = b = 0
                            if link.from_node.inputs["Translucency"].is_linked:
                                pass
                            else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                                r, g, b, a = link.from_node.inputs["Translucency"].default_value[:]
                            if link.from_node.inputs["Energy"].is_linked:
                                pass
                            else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                                energy = link.from_node.inputs["Energy"].default_value
                            file.write(
                                "    subsurface { translucency <%.4g,%.4g,%.4g>*%s }\n"
                                % (r, g, b, energy)
                            )

                    if link.from_node.bl_idname in {"PovraySpecularNode", "PovrayPhongNode"}:
                        intensity = 0
                        albedo = ""
                        roughness = 0
                        metallic = 0
                        phong_size = 0
                        highlight = "specular"
                        if link.from_node.inputs["Intensity"].is_linked:
                            pass
                        else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            intensity = link.from_node.inputs["Intensity"].default_value

                        if link.from_node.inputs["Albedo"].is_linked:
                            pass
                        else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            if link.from_node.inputs["Albedo"].default_value:
                                albedo = "albedo"
Maurice Raybaud's avatar
Maurice Raybaud committed
                        if link.from_node.bl_idname in {"PovrayPhongNode"}:
                            highlight = "phong"
                        file.write("    %s %s %.4g\n" % (highlight, albedo, intensity))
Maurice Raybaud's avatar
Maurice Raybaud committed
                        if link.from_node.bl_idname in {"PovraySpecularNode"}:
                            if link.from_node.inputs["Roughness"].is_linked:
                                pass
                            else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                                roughness = link.from_node.inputs["Roughness"].default_value
                            file.write("    roughness %.6g\n" % roughness)
Maurice Raybaud's avatar
Maurice Raybaud committed
                        if link.from_node.bl_idname in {"PovrayPhongNode"}:
                            if link.from_node.inputs["Size"].is_linked:
                                pass
                            else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                                phong_size = link.from_node.inputs["Size"].default_value
                            file.write("    phong_size %s\n" % phong_size)

                        if link.from_node.inputs["Metallic"].is_linked:
                            pass
                        else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            metallic = link.from_node.inputs["Metallic"].default_value
                        file.write("    metallic %.4g\n" % metallic)

                    if link.from_node.bl_idname in {"PovrayMirrorNode"}:
                        file.write("    reflection {\n")
                        color = None
                        exponent = 0
                        metallic = 0
                        falloff = 0
                        fresnel = ""
                        conserve = ""
                        if link.from_node.inputs["Color"].is_linked:
                            pass
                        else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            color = link.from_node.inputs["Color"].default_value[:]
                        file.write(
                            "    <%.4g,%.4g,%.4g>\n"
                            % (color[0], color[1], color[2])
                        )

                        if link.from_node.inputs["Exponent"].is_linked:
                            pass
                        else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            exponent = link.from_node.inputs["Exponent"].default_value
                        file.write("    exponent %.4g\n" % exponent)

                        if link.from_node.inputs["Falloff"].is_linked:
                            pass
                        else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            falloff = link.from_node.inputs["Falloff"].default_value
                        file.write("    falloff %.4g\n" % falloff)

                        if link.from_node.inputs["Metallic"].is_linked:
                            pass
                        else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            metallic = link.from_node.inputs["Metallic"].default_value
                        file.write("    metallic %.4g" % metallic)

                        if link.from_node.inputs["Fresnel"].is_linked:
                            pass
                        else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            if link.from_node.inputs["Fresnel"].default_value:
                                fresnel = "fresnel"

                        if link.from_node.inputs["Conserve energy"].is_linked:
                            pass
                        else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            if link.from_node.inputs["Conserve energy"].default_value:
                                conserve = "conserve_energy"
Maurice Raybaud's avatar
Maurice Raybaud committed
                        file.write("    %s}\n    %s\n" % (fresnel, conserve))
Maurice Raybaud's avatar
Maurice Raybaud committed
                    if link.from_node.bl_idname == "PovrayAmbientNode":
                        ambient = (0, 0, 0)
                        if link.from_node.inputs["Ambient"].is_linked:
                            pass
                        else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            ambient = link.from_node.inputs["Ambient"].default_value[:]
                        file.write("    ambient <%.4g,%.4g,%.4g>\n" % ambient)

                    if link.from_node.bl_idname in {"PovrayIridescenceNode"}:
                        file.write("    irid {\n")
                        amount = 0
                        thickness = 0
                        turbulence = 0
                        if link.from_node.inputs["Amount"].is_linked:
                            pass
                        else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            amount = link.from_node.inputs["Amount"].default_value
                        file.write("    %.4g\n" % amount)

                        if link.from_node.inputs["Thickness"].is_linked:
                            pass
                        else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            exponent = link.from_node.inputs["Thickness"].default_value
                        file.write("    thickness %.4g\n" % thickness)

                        if link.from_node.inputs["Turbulence"].is_linked:
                            pass
                        else:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            falloff = link.from_node.inputs["Turbulence"].default_value
                        file.write("    turbulence %.4g}\n" % turbulence)
Maurice Raybaud's avatar
Maurice Raybaud committed
            file.write("}\n")

    for node in ntree.nodes:
Maurice Raybaud's avatar
Maurice Raybaud committed
        pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
        if node.bl_idname == "PovrayTransformNode" and node.outputs["Transform"].is_linked:
Maurice Raybaud's avatar
Maurice Raybaud committed
            tx = node.inputs["Translate x"].default_value
            ty = node.inputs["Translate y"].default_value
            tz = node.inputs["Translate z"].default_value
            rx = node.inputs["Rotate x"].default_value
            ry = node.inputs["Rotate y"].default_value
            rz = node.inputs["Rotate z"].default_value
            sx = node.inputs["Scale x"].default_value
            sy = node.inputs["Scale y"].default_value
            sz = node.inputs["Scale z"].default_value
            file.write(
                "#declare %s = transform {\n"
                "    translate<%.4g,%.4g,%.4g>\n"
                "    rotate<%.4g,%.4g,%.4g>\n"
                "    scale<%.4g,%.4g,%.4g>}\n" % (pov_node_name, tx, ty, tz, rx, ry, rz, sx, sy, sz)
            )

    for node in ntree.nodes:
Maurice Raybaud's avatar
Maurice Raybaud committed
        pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
        if node.bl_idname == "PovrayColorImageNode" and node.outputs["Pigment"].is_linked:
Maurice Raybaud's avatar
Maurice Raybaud committed
            declare_nodes.append(node.name)
            if node.image == "":
                file.write("#declare %s = pigment { color rgb 0.8}\n" % pov_node_name)
Maurice Raybaud's avatar
Maurice Raybaud committed
                im = bpy.data.images[node.image]
                if im.filepath and path.exists(bpy.path.abspath(im.filepath)):  # (os.path)
                    transform = ""
                    for link in ntree.links:
Maurice Raybaud's avatar
Maurice Raybaud committed
                        if (
                            link.from_node.bl_idname == "PovrayTransformNode"
                            and link.to_node == node
                        ):
                            pov_trans_name = (
                                string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
                                + "_%s" % pov_mat_name
                            )
                            transform = "transform {%s}" % pov_trans_name
                    uv = ""
                    if node.map_type == "uv_mapping":
                        uv = "uv_mapping"
                    filepath = bpy.path.abspath(im.filepath)
                    file.write("#declare %s = pigment {%s image_map {\n" % (pov_node_name, uv))
                    premul = "off"
                    if node.premultiplied:
Maurice Raybaud's avatar
Maurice Raybaud committed
                        premul = "on"
                    once = ""
                    if node.once:
Maurice Raybaud's avatar
Maurice Raybaud committed
                        once = "once"
                    file.write(
                        '    "%s"\n    gamma %.6g\n    premultiplied %s\n'
                        % (filepath, node.inputs["Gamma"].default_value, premul)
                    )
                    file.write("    %s\n" % once)
                    if node.map_type != "uv_mapping":
                        file.write("    map_type %s\n" % node.map_type)
Maurice Raybaud's avatar
Maurice Raybaud committed
                    file.write(
                        "    interpolate %s\n    filter all %.4g\n    transmit all %.4g\n"
                        % (
                            node.interpolate,
                            node.inputs["Filter"].default_value,
                            node.inputs["Transmit"].default_value,
                        )
                    )
                    file.write("    }\n")
                    file.write("    %s\n" % transform)
                    file.write("    }\n")

    for node in ntree.nodes:
Maurice Raybaud's avatar
Maurice Raybaud committed
        pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
        if node.bl_idname == "PovrayImagePatternNode" and node.outputs["Pattern"].is_linked:
Maurice Raybaud's avatar
Maurice Raybaud committed
            declare_nodes.append(node.name)
            if node.image != "":
Maurice Raybaud's avatar
Maurice Raybaud committed
                im = bpy.data.images[node.image]
                if im.filepath and path.exists(bpy.path.abspath(im.filepath)):
                    transform = ""
                    for link in ntree.links:
Maurice Raybaud's avatar
Maurice Raybaud committed
                        if (
                            link.from_node.bl_idname == "PovrayTransformNode"
                            and link.to_node == node
                        ):
                            pov_trans_name = (
                                string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
                                + "_%s" % pov_mat_name
                            )
                            transform = "transform {%s}" % pov_trans_name
                    uv = ""
                    if node.map_type == "uv_mapping":
                        uv = "uv_mapping"
                    filepath = bpy.path.abspath(im.filepath)
                    file.write("#macro %s() %s image_pattern {\n" % (pov_node_name, uv))
                    premul = "off"
                    if node.premultiplied:
Maurice Raybaud's avatar
Maurice Raybaud committed
                        premul = "on"
                    once = ""
                    if node.once:
Maurice Raybaud's avatar
Maurice Raybaud committed
                        once = "once"
                    file.write(
                        '    "%s"\n    gamma %.6g\n    premultiplied %s\n'
                        % (filepath, node.inputs["Gamma"].default_value, premul)
                    )
                    file.write("    %s\n" % once)
                    if node.map_type != "uv_mapping":
                        file.write("    map_type %s\n" % node.map_type)
Maurice Raybaud's avatar
Maurice Raybaud committed
                    file.write("    interpolate %s\n" % node.interpolate)
                    file.write("    }\n")
                    file.write("    %s\n" % transform)
                    file.write("#end\n")

    for node in ntree.nodes:
Maurice Raybaud's avatar
Maurice Raybaud committed
        pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
        if node.bl_idname == "PovrayBumpMapNode" and node.outputs["Normal"].is_linked:
            if node.image != "":
Maurice Raybaud's avatar
Maurice Raybaud committed
                im = bpy.data.images[node.image]
                if im.filepath and path.exists(bpy.path.abspath(im.filepath)):
                    transform = ""
                    for link in ntree.links:
Maurice Raybaud's avatar
Maurice Raybaud committed
                        if (
                            link.from_node.bl_idname == "PovrayTransformNode"
                            and link.to_node == node
                        ):
                            pov_trans_name = (
                                string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
                                + "_%s" % pov_mat_name
                            )
                            transform = "transform {%s}" % pov_trans_name
                    uv = ""
                    if node.map_type == "uv_mapping":
                        uv = "uv_mapping"
                    filepath = bpy.path.abspath(im.filepath)
                    file.write("#declare %s = normal {%s bump_map {\n" % (pov_node_name, uv))
                    once = ""
                    if node.once:
Maurice Raybaud's avatar
Maurice Raybaud committed
                        once = "once"
                    file.write('    "%s"\n' % filepath)
                    file.write("    %s\n" % once)
                    if node.map_type != "uv_mapping":
                        file.write("    map_type %s\n" % node.map_type)
Maurice Raybaud's avatar
Maurice Raybaud committed
                    bump_size = node.inputs["Normal"].default_value
                    if node.inputs["Normal"].is_linked:
                        pass
Maurice Raybaud's avatar
Maurice Raybaud committed
                    file.write(
                        "    interpolate %s\n    bump_size %.4g\n" % (node.interpolate, bump_size)
                    )
                    file.write("    }\n")
                    file.write("    %s\n" % transform)
                    file.write("    }\n")
                    declare_nodes.append(node.name)

    for node in ntree.nodes:
Maurice Raybaud's avatar
Maurice Raybaud committed
        pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
        if node.bl_idname == "PovrayPigmentNode" and node.outputs["Pigment"].is_linked:
Maurice Raybaud's avatar
Maurice Raybaud committed
            declare_nodes.append(node.name)
            r, g, b = node.inputs["Color"].default_value[:]
            f = node.inputs["Filter"].default_value
            t = node.inputs["Transmit"].default_value
            if node.inputs["Color"].is_linked:
                pass
Maurice Raybaud's avatar
Maurice Raybaud committed
            file.write(
                "#declare %s = pigment{color srgbft <%.4g,%.4g,%.4g,%.4g,%.4g>}\n"
                % (pov_node_name, r, g, b, f, t)
            )

    for node in ntree.nodes:
Maurice Raybaud's avatar
Maurice Raybaud committed
        pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
        if node.bl_idname == "PovrayTextureNode" and node.outputs["Texture"].is_linked:
Maurice Raybaud's avatar
Maurice Raybaud committed
            declare_nodes.append(node.name)
            r, g, b = node.inputs["Pigment"].default_value[:]
            pov_col_name = "color rgb <%.4g,%.4g,%.4g>" % (r, g, b)
            if node.inputs["Pigment"].is_linked:
                for link in ntree.links:
Maurice Raybaud's avatar
Maurice Raybaud committed
                    if link.to_node == node and link.to_socket.name == "Pigment":
                        pov_col_name = (
                            string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
                            + "_%s" % pov_mat_name
                        )
            file.write("#declare %s = texture{\n    pigment{%s}\n" % (pov_node_name, pov_col_name))
            if node.inputs["Normal"].is_linked:
                for link in ntree.links:
Maurice Raybaud's avatar
Maurice Raybaud committed
                    if (
                        link.to_node == node
                        and link.to_socket.name == "Normal"
                        and link.from_node.name in declare_nodes
                    ):
                        pov_nor_name = (
                            string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
                            + "_%s" % pov_mat_name
                        )
                        file.write("    normal{%s}\n" % pov_nor_name)
            if node.inputs["Finish"].is_linked:
                for link in ntree.links:
Maurice Raybaud's avatar
Maurice Raybaud committed
                    if link.to_node == node and link.to_socket.name == "Finish":
                        pov_fin_name = (
                            string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
                            + "_%s" % pov_mat_name
                        )
                        file.write("    finish{%s}\n" % pov_fin_name)
            file.write("}\n")
            declare_nodes.append(node.name)
Maurice Raybaud's avatar
Maurice Raybaud committed
    for i in range(0, len(ntree.nodes)):
        for node in ntree.nodes:
Maurice Raybaud's avatar
Maurice Raybaud committed
            if node.bl_idname in {"ShaderNodeGroup", "ShaderTextureMapNode"}:
                for output in node.outputs:
Maurice Raybaud's avatar
Maurice Raybaud committed
                    if (
                        output.name == "Texture"
                        and output.is_linked
                        and (node.name not in declare_nodes)
                    ):
                        declare = True
                        for link in ntree.links:
Maurice Raybaud's avatar
Maurice Raybaud committed
                            if link.to_node == node and link.to_socket.name not in {
                                "",
                                "Color ramp",
                                "Mapping",
                                "Transform",
                                "Modifier",
                            }:
                                if link.from_node.name not in declare_nodes:
                                    declare = False
Maurice Raybaud's avatar
Maurice Raybaud committed
                            pov_node_name = (
                                string_strip_hyphen(bpy.path.clean_name(node.name))
                                + "_%s" % pov_mat_name
                            )
                            uv = ""
                            warp = ""
                            for link in ntree.links:
Maurice Raybaud's avatar
Maurice Raybaud committed
                                if (
                                    link.to_node == node
                                    and link.from_node.bl_idname == "PovrayMappingNode"
                                    and link.from_node.warp_type != "NONE"
                                ):
                                    w_type = link.from_node.warp_type
Maurice Raybaud's avatar
Maurice Raybaud committed
                                    if w_type == "uv_mapping":
                                        uv = "uv_mapping"
Maurice Raybaud's avatar
Maurice Raybaud committed
                                        tor = ""
                                        if w_type == "toroidal":
                                            tor = (
                                                "major_radius %.4g"
                                                % link.from_node.warp_tor_major_radius
                                            )
                                        orient = link.from_node.warp_orientation
                                        exp = link.from_node.warp_dist_exp
                                        warp = "warp{%s orientation %s dist_exp %.4g %s}" % (
                                            w_type,
                                            orient,
                                            exp,
                                            tor,
                                        )
                                        if link.from_node.warp_type == "planar":
                                            warp = "warp{%s %s %.4g}" % (w_type, orient, exp)
                                        if link.from_node.warp_type == "cubic":
                                            warp = "warp{%s}" % w_type
                            file.write("#declare %s = texture {%s\n" % (pov_node_name, uv))
                            pattern = node.inputs[0].default_value
                            advanced = ""
                            if node.inputs[0].is_linked:
                                for link in ntree.links:
Maurice Raybaud's avatar
Maurice Raybaud committed
                                    if (
                                        link.to_node == node
                                        and link.from_node.bl_idname == "ShaderPatternNode"
                                    ):
                                        # ------------ advanced ------------------------- #
Maurice Raybaud's avatar
Maurice Raybaud committed
                                        lfn = link.from_node
                                        pattern = lfn.pattern
                                        if pattern == "agate":
                                            advanced = "agate_turb %.4g" % lfn.agate_turb
                                        if pattern == "crackle":
                                            advanced = "form <%.4g,%.4g,%.4g>" % (
                                                lfn.crackle_form_x,
                                                lfn.crackle_form_y,
                                                lfn.crackle_form_z,
                                            )
                                            advanced += " metric %.4g" % lfn.crackle_metric
                                            if lfn.crackle_solid:
Maurice Raybaud's avatar
Maurice Raybaud committed
                                                advanced += " solid"
                                        if pattern in {"spiral1", "spiral2"}:
                                            advanced = "%.4g" % lfn.spiral_arms
                                        if pattern in {"tiling"}:
                                            advanced = "%.4g" % lfn.tiling_number
                                        if pattern in {"gradient"}:
                                            advanced = "%s" % lfn.gradient_orient
                                    if (
                                        link.to_node == node
                                        and link.from_node.bl_idname == "PovrayImagePatternNode"
                                    ):
                                        pov_macro_name = (
                                            string_strip_hyphen(
                                                bpy.path.clean_name(link.from_node.name)
                                            )
                                            + "_%s" % pov_mat_name
                                        )
                                        pattern = "%s()" % pov_macro_name
                            file.write("    %s %s %s\n" % (pattern, advanced, warp))

                            repeat = ""
                            for link in ntree.links:
Maurice Raybaud's avatar
Maurice Raybaud committed
                                if (
                                    link.to_node == node
                                    and link.from_node.bl_idname == "PovrayMultiplyNode"
                                ):
                                    if link.from_node.amount_x > 1:
Maurice Raybaud's avatar
Maurice Raybaud committed
                                        repeat += "warp{repeat %.4g * x}" % link.from_node.amount_x
                                    if link.from_node.amount_y > 1:
Maurice Raybaud's avatar
Maurice Raybaud committed
                                        repeat += " warp{repeat %.4g * y}" % link.from_node.amount_y
                                    if link.from_node.amount_z > 1:
Maurice Raybaud's avatar
Maurice Raybaud committed
                                        repeat += " warp{repeat %.4g * z}" % link.from_node.amount_z
Maurice Raybaud's avatar
Maurice Raybaud committed
                            transform = ""
                            for link in ntree.links:
Maurice Raybaud's avatar
Maurice Raybaud committed
                                if (
                                    link.to_node == node
                                    and link.from_node.bl_idname == "PovrayTransformNode"
                                ):
                                    pov_trans_name = (
                                        string_strip_hyphen(
                                            bpy.path.clean_name(link.from_node.name)
                                        )
                                        + "_%s" % pov_mat_name
                                    )
                                    transform = "transform {%s}" % pov_trans_name
                            x = 0
                            y = 0
                            z = 0
                            d = 0
                            e = 0
                            f = 0
                            g = 0
                            h = 0
                            modifier = False
                            for link in ntree.links:
Maurice Raybaud's avatar
Maurice Raybaud committed
                                if (
                                    link.to_node == node
                                    and link.from_node.bl_idname == "PovrayModifierNode"
                                ):
                                    modifier = True
                                    if link.from_node.inputs["Turb X"].is_linked:
                                        pass
                                    else:
                                        x = link.from_node.inputs["Turb X"].default_value

                                    if link.from_node.inputs["Turb Y"].is_linked:
                                        pass
                                    else:
                                        y = link.from_node.inputs["Turb Y"].default_value

                                    if link.from_node.inputs["Turb Z"].is_linked:
                                        pass
                                    else:
                                        z = link.from_node.inputs["Turb Z"].default_value

                                    if link.from_node.inputs["Octaves"].is_linked:
                                        pass
                                    else:
                                        d = link.from_node.inputs["Octaves"].default_value

                                    if link.from_node.inputs["Lambda"].is_linked:
                                        pass
                                    else:
                                        e = link.from_node.inputs["Lambda"].default_value

                                    if link.from_node.inputs["Omega"].is_linked:
                                        pass
                                    else:
                                        f = link.from_node.inputs["Omega"].default_value

                                    if link.from_node.inputs["Frequency"].is_linked:
                                        pass
                                    else:
                                        g = link.from_node.inputs["Frequency"].default_value

                                    if link.from_node.inputs["Phase"].is_linked:
                                        pass
                                    else:
                                        h = link.from_node.inputs["Phase"].default_value

Maurice Raybaud's avatar
Maurice Raybaud committed
                            turb = "turbulence <%.4g,%.4g,%.4g>" % (x, y, z)
                            octv = "octaves %s" % d
                            lmbd = "lambda %.4g" % e
                            omg = "omega %.4g" % f
                            freq = "frequency %.4g" % g
                            pha = "phase %.4g" % h

                            file.write("\n")
                            if pattern not in {
                                "checker",
                                "hexagon",
                                "square",
                                "triangular",
                                "brick",
                            }:
                                file.write("    texture_map {\n")
                            if node.inputs["Color ramp"].is_linked:
                                for link in ntree.links:
Maurice Raybaud's avatar
Maurice Raybaud committed
                                    if (
                                        link.to_node == node
                                        and link.from_node.bl_idname == "ShaderNodeValToRGB"
                                    ):
                                        els = link.from_node.color_ramp.elements
Maurice Raybaud's avatar
Maurice Raybaud committed
                                        n = -1
                                        for el in els:
Maurice Raybaud's avatar
Maurice Raybaud committed
                                            n += 1
                                            pov_in_mat_name = string_strip_hyphen(
                                                bpy.path.clean_name(link.from_node.name)
                                            ) + "_%s_%s" % (n, pov_mat_name)
                                            default = True
                                            for ilink in ntree.links:
Maurice Raybaud's avatar
Maurice Raybaud committed
                                                if (
                                                    ilink.to_node == node
                                                    and ilink.to_socket.name == str(n)
                                                ):
                                                    default = False
                                                    pov_in_mat_name = (
                                                        string_strip_hyphen(
                                                            bpy.path.clean_name(
                                                                ilink.from_node.name
                                                            )
                                                        )
                                                        + "_%s" % pov_mat_name
                                                    )
Maurice Raybaud's avatar
Maurice Raybaud committed
                                                r, g, b, a = el.color[:]
                                                file.write(
                                                    "    #declare %s = texture{"
                                                    "pigment{"
                                                    "color srgbt <%.4g,%.4g,%.4g,%.4g>}};\n"
                                                    % (pov_in_mat_name, r, g, b, 1 - a)
                                                )
                                            file.write(
                                                "    [%s %s]\n" % (el.position, pov_in_mat_name)
                                            )
Maurice Raybaud's avatar
Maurice Raybaud committed
                                els = [[0, 0, 0, 0], [1, 1, 1, 1]]
                                for t in range(0, 2):
                                    pov_in_mat_name = string_strip_hyphen(
                                        bpy.path.clean_name(link.from_node.name)
                                    ) + "_%s_%s" % (t, pov_mat_name)
                                    default = True
                                    for ilink in ntree.links:
Maurice Raybaud's avatar
Maurice Raybaud committed
                                        if ilink.to_node == node and ilink.to_socket.name == str(t):
                                            default = False
                                            pov_in_mat_name = (
                                                string_strip_hyphen(
                                                    bpy.path.clean_name(ilink.from_node.name)
                                                )
                                                + "_%s" % pov_mat_name
                                            )
Maurice Raybaud's avatar
Maurice Raybaud committed
                                        r, g, b = els[t][1], els[t][2], els[t][3]
                                        if pattern not in {
                                            "checker",
                                            "hexagon",
                                            "square",
                                            "triangular",
                                            "brick",
                                        }:
                                            file.write(
                                                "    #declare %s = texture{pigment{color rgb <%.4g,%.4g,%.4g>}};\n"
                                                % (pov_in_mat_name, r, g, b)
                                            )
Maurice Raybaud's avatar
Maurice Raybaud committed
                                            file.write(
                                                "    texture{pigment{color rgb <%.4g,%.4g,%.4g>}}\n"
                                                % (r, g, b)
                                            )
                                    if pattern not in {
                                        "checker",
                                        "hexagon",
                                        "square",
                                        "triangular",
                                        "brick",
                                    }:
                                        file.write("    [%s %s]\n" % (els[t][0], pov_in_mat_name))
Maurice Raybaud's avatar
Maurice Raybaud committed
                                        if not default:
                                            file.write("    texture{%s}\n" % pov_in_mat_name)
                            if pattern not in {
                                "checker",
                                "hexagon",
                                "square",
                                "triangular",
                                "brick",
                            }:
                                file.write("}\n")
                            if pattern == "brick":
                                file.write(
                                    "brick_size <%.4g, %.4g, %.4g> mortar %.4g \n"
                                    % (
                                        node.brick_size_x,
                                        node.brick_size_y,
                                        node.brick_size_z,
                                        node.brick_mortar,
                                    )
                                )
                            file.write("    %s %s" % (repeat, transform))
Maurice Raybaud's avatar
Maurice Raybaud committed
                                file.write(
                                    " %s %s %s %s %s %s" % (turb, octv, lmbd, omg, freq, pha)
                                )
                            file.write("}\n")
                            declare_nodes.append(node.name)

    for link in ntree.links:
Maurice Raybaud's avatar
Maurice Raybaud committed
        if link.to_node.bl_idname == "PovrayOutputNode" and link.from_node.name in declare_nodes:
            pov_mat_node_name = (
                string_strip_hyphen(bpy.path.clean_name(link.from_node.name)) + "_%s" % pov_mat_name
            )
            file.write("#declare %s = %s\n" % (pov_mat_name, pov_mat_node_name))