Skip to content
Snippets Groups Projects
render.py 287 KiB
Newer Older
  • Learn to ignore specific revisions
  • Maurice Raybaud's avatar
    Maurice Raybaud committed
        exportGlobalSettings(scene)
    
            file.write("\n//--Custom Code--\n\n")
        exportCustomCode()
    
    
        if comments:
            file.write("\n//--Patterns Definitions--\n\n")
        LocalPatternNames = []
    
        for texture in bpy.data.textures:  # ok?
    
            if texture.users > 0:
    
                currentPatName = string_strip_hyphen(
                    bpy.path.clean_name(texture.name)
                )
                # string_strip_hyphen(patternNames[texture.name]) #maybe instead of the above
    
                LocalPatternNames.append(currentPatName)
    
                # use above list to prevent writing texture instances several times and assign in mats?
                if (
                    texture.type not in {'NONE', 'IMAGE'}
                    and texture.pov.tex_pattern_type == 'emulator'
                ) or (
                    texture.type in {'NONE', 'IMAGE'}
                    and texture.pov.tex_pattern_type != 'emulator'
                ):
    
                    file.write("\n#declare PAT_%s = \n" % currentPatName)
    
                    file.write(shading.exportPattern(texture, string_strip_hyphen))
    
                file.write("\n")
    
            file.write("\n//--Background--\n\n")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        exportWorld(scene.world)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        exportCamera()
    
        for ob in bpy.data.objects:
            if ob.type == 'MESH':
                for mod in ob.modifiers:
                    if mod.type == 'BOOLEAN':
                        if mod.object not in csg_list:
                            csg_list.append(mod.object)
        if csg_list != []:
            csg = False
            sel = no_renderable_objects(scene)
            exportMeshes(scene, sel, csg)
    
        csg = True
        sel = renderable_objects(scene)
    
    
        exportLamps(
            [L for L in sel if (L.type == 'LIGHT' and L.pov.object_as != 'RAINBOW')]
        )
    
        if comments:
            file.write("\n//--Rainbows--\n\n")
    
        exportRainbows(
            [L for L in sel if (L.type == 'LIGHT' and L.pov.object_as == 'RAINBOW')]
        )
    
        if comments:
            file.write("\n//--Special Curves--\n\n")
        for c in sel:
    
            if c.is_modified(scene, 'RENDER'):
    
                continue  # don't export as pov curves objects with modifiers, but as mesh
            elif c.type == 'CURVE' and (
                c.pov.curveshape in {'lathe', 'sphere_sweep', 'loft', 'birail'}
            ):
                exportCurves(scene, c)
    
            file.write("\n//--Material Definitions--\n\n")
    
        # write a default pigment for objects with no material (comment out to show black)
    
        file.write("#default{ pigment{ color srgb 0.8 }}\n")
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        # Convert all materials to strings we can access directly per vertex.
    
        # exportMaterials()
        shading.writeMaterial(
            using_uberpov,
            DEF_MAT_NAME,
            scene,
            tabWrite,
            safety,
            comments,
            uniqueName,
            materialNames,
            None,
        )  # default material
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        for material in bpy.data.materials:
    
            if material.users > 0:
    
                if material.pov.material_use_nodes:
                    ntree = material.node_tree
    
                    povMatName = string_strip_hyphen(
                        bpy.path.clean_name(material.name)
                    )
                    if len(ntree.nodes) == 0:
                        file.write(
                            '#declare %s = texture {%s}\n' % (povMatName, color)
                        )
    
                        shading.write_nodes(scene, povMatName, ntree, file)
    
    
                    for node in ntree.nodes:
                        if node:
                            if node.bl_idname == "PovrayOutputNode":
                                if node.inputs["Texture"].is_linked:
                                    for link in ntree.links:
    
                                        if (
                                            link.to_node.bl_idname
                                            == "PovrayOutputNode"
                                        ):
                                            povMatName = (
                                                string_strip_hyphen(
                                                    bpy.path.clean_name(
                                                        link.from_node.name
                                                    )
                                                )
                                                + "_%s" % povMatName
                                            )
    
                                    file.write(
                                        '#declare %s = texture {%s}\n'
                                        % (povMatName, color)
                                    )
    
                    shading.writeMaterial(
                        using_uberpov,
                        DEF_MAT_NAME,
                        scene,
                        tabWrite,
                        safety,
                        comments,
                        uniqueName,
                        materialNames,
                        material,
                    )
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                # attributes are all the variables needed by the other python file...
    
        exportMeta([m for m in sel if m.type == 'META'])
    
        exportMeshes(scene, sel, csg)
    
        #totime = time.time() - tbefore
        #print("exportMeshes took" + str(totime))
    
        # What follow used to happen here:
        # exportCamera()
        # exportWorld(scene.world)
        # exportGlobalSettings(scene)
    
        # MR:..and the order was important for implementing pov 3.7 baking
    
        # CR: Baking should be a special case than. If "baking", than we could change the order.
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
        # print("pov file closed %s" % file.closed)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        file.close()
    
        # print("pov file closed %s" % file.closed)
    
    def write_pov_ini(
        scene, filename_ini, filename_log, filename_pov, filename_image
    ):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Write ini file."""
    
        feature_set = bpy.context.preferences.addons[
            __package__
        ].preferences.branch_feature_set_povray
        using_uberpov = feature_set == 'uberpov'
        # scene = bpy.data.scenes[0]
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        render = scene.render
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        x = int(render.resolution_x * render.resolution_percentage * 0.01)
        y = int(render.resolution_y * render.resolution_percentage * 0.01)
    
    
        file = open(filename_ini, "w")
    
        file.write("Version=3.8\n")
    
        # write povray text stream to temporary file of same name with _log suffix
        # file.write("All_File='%s'\n" % filename_log)
    
        # DEBUG.OUT log if none specified:
        file.write("All_File=1\n")
    
        file.write("Input_File_Name='%s'\n" % filename_pov)
        file.write("Output_File_Name='%s'\n" % filename_image)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
        file.write("Width=%d\n" % x)
        file.write("Height=%d\n" % y)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
        # Border render.
        if render.use_border:
            file.write("Start_Column=%4g\n" % render.border_min_x)
            file.write("End_Column=%4g\n" % (render.border_max_x))
    
    
    Campbell Barton's avatar
    Campbell Barton committed
            file.write("Start_Row=%4g\n" % (1.0 - render.border_max_y))
            file.write("End_Row=%4g\n" % (1.0 - render.border_min_y))
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
        file.write(
            "Bounding_Method=2\n"
        )  # The new automatic BSP is faster in most scenes
    
        # Activated (turn this back off when better live exchange is done between the two programs
        # (see next comment)
        file.write("Display=1\n")
    
        # PNG, with POV-Ray 3.7, can show background color with alpha. In the long run using the
        # POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
        file.write("Output_File_Type=N\n")
    
        # file.write("Output_File_Type=T\n") # TGA, best progressive loading
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
        if scene.pov.antialias_enable:
            # method 2 (recursive) with higher max subdiv forced because no mipmapping in POV-Ray
            # needs higher sampling.
            # aa_mapping = {"5": 2, "8": 3, "11": 4, "16": 5}
    
            if using_uberpov:
                method = {"0": 1, "1": 2, "2": 3}
            else:
                method = {"0": 1, "1": 2, "2": 2}
    
            file.write("Antialias_Depth=%d\n" % scene.pov.antialias_depth)
            file.write("Antialias_Threshold=%.3g\n" % scene.pov.antialias_threshold)
    
            if using_uberpov and scene.pov.antialias_method == '2':
    
                file.write(
                    "Sampling_Method=%s\n" % method[scene.pov.antialias_method]
                )
                file.write(
                    "Antialias_Confidence=%.3g\n" % scene.pov.antialias_confidence
                )
    
                file.write(
                    "Sampling_Method=%s\n" % method[scene.pov.antialias_method]
                )
    
            file.write("Antialias_Gamma=%.3g\n" % scene.pov.antialias_gamma)
            if scene.pov.jitter_enable:
    
                file.write("Jitter_Amount=%3g\n" % scene.pov.jitter_amount)
    
                file.write("Jitter=off\n")  # prevent animation flicker
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        else:
    
        # print("ini file closed %s" % file.closed)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        file.close()
    
        # print("ini file closed %s" % file.closed)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
    class PovrayRender(bpy.types.RenderEngine):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Define the external renderer"""
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        bl_idname = 'POVRAY_RENDER'
    
        bl_label = "Persitence Of Vision"
    
        bl_use_shading_nodes_custom = False
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            """Identify POV engine"""
    
            addon_prefs = bpy.context.preferences.addons[__package__].preferences
    
    
            # Use the system preference if its set.
            pov_binary = addon_prefs.filepath_povray
            if pov_binary:
                if os.path.exists(pov_binary):
                    return pov_binary
                else:
    
                    print(
                        "User Preferences path to povray %r NOT FOUND, checking $PATH"
                        % pov_binary
                    )
    
    
            # Windows Only
            # assume if there is a 64bit binary that the user has a 64bit capable OS
            if sys.platform[:3] == "win":
                import winreg
    
    
                win_reg_key = winreg.OpenKey(
                    winreg.HKEY_CURRENT_USER, "Software\\POV-Ray\\v3.7\\Windows"
                )
    
                win_home = winreg.QueryValueEx(win_reg_key, "Home")[0]
    
    
                # First try 64bits UberPOV
                pov_binary = os.path.join(win_home, "bin", "uberpov64.exe")
                if os.path.exists(pov_binary):
                    return pov_binary
    
                pov_binary = os.path.join(win_home, "bin", "pvengine64.exe")
                if os.path.exists(pov_binary):
                    return pov_binary
    
    
                # Then try 32bits UberPOV
                pov_binary = os.path.join(win_home, "bin", "uberpov32.exe")
                if os.path.exists(pov_binary):
    
                    return pov_binary
    
    
                pov_binary = os.path.join(win_home, "bin", "pvengine.exe")
                if os.path.exists(pov_binary):
                    return pov_binary
    
            # search the path all os's
            pov_binary_default = "povray"
    
            os_path_ls = os.getenv("PATH").split(':') + [""]
    
            for dir_name in os_path_ls:
                pov_binary = os.path.join(dir_name, pov_binary_default)
                if os.path.exists(pov_binary):
                    return pov_binary
            return ""
    
    
        def _export(self, depsgraph, povPath, renderImagePath):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            """gather all necessary output files paths user defined and auto generated and export there"""
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            import tempfile
    
                self._temp_file_in = tempfile.NamedTemporaryFile(
                    suffix=".pov", delete=False
                ).name
    
                # PNG with POV 3.7, can show the background color with alpha. In the long run using the
                # POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
    
                self._temp_file_out = tempfile.NamedTemporaryFile(
                    suffix=".png", delete=False
                ).name
                # self._temp_file_out = tempfile.NamedTemporaryFile(suffix=".tga", delete=False).name
                self._temp_file_ini = tempfile.NamedTemporaryFile(
                    suffix=".ini", delete=False
                ).name
                self._temp_file_log = os.path.join(
                    tempfile.gettempdir(), "alltext.out"
                )
    
            else:
                self._temp_file_in = povPath + ".pov"
    
                # PNG with POV 3.7, can show the background color with alpha. In the long run using the
                # POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
                self._temp_file_out = renderImagePath + ".png"
    
                # self._temp_file_out = renderImagePath + ".tga"
    
                self._temp_file_ini = povPath + ".ini"
    
                logPath = bpy.path.abspath(scene.pov.scene_path).replace('\\', '/')
                self._temp_file_log = os.path.join(logPath, "alltext.out")
    
                '''
                self._temp_file_in = "/test.pov"
    
                # PNG with POV 3.7, can show the background color with alpha. In the long run using the
                # POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
                self._temp_file_out = "/test.png"
    
                #self._temp_file_out = "/test.tga"
                self._temp_file_ini = "/test.ini"
                '''
    
            if scene.pov.text_block == "":
    
    
                def info_callback(txt):
                    self.update_stats("", "POV-Ray 3.7: " + txt)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                # os.makedirs(user_dir, exist_ok=True)  # handled with previews
                os.makedirs(preview_dir, exist_ok=True)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                write_pov(self._temp_file_in, scene, info_callback)
            else:
                pass
    
        def _render(self, depsgraph):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            """Export necessary files and render image."""
    
            scene = bpy.context.scene
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            try:
    
                os.remove(self._temp_file_out)  # so as not to load the old file
    
    Campbell Barton's avatar
    Campbell Barton committed
            except OSError:
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                pass
    
    
            pov_binary = PovrayRender._locate_binary()
            if not pov_binary:
    
                print(
                    "POV-Ray 3.7: could not execute povray, possibly POV-Ray isn't installed"
                )
    
            write_pov_ini(
                scene,
                self._temp_file_ini,
                self._temp_file_log,
                self._temp_file_in,
                self._temp_file_out,
            )
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
            print("***-STARTING-***")
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
            if scene.pov.command_line_switches != "":
                for newArg in scene.pov.command_line_switches.split(" "):
    
            if sys.platform[:3] == "win":
    
                if "/EXIT" not in extra_args and not scene.pov.pov_editor:
    
                    extra_args.append("/EXIT")
    
                # added -d option to prevent render window popup which leads to segfault on linux
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                self._process = subprocess.Popen(
                    [pov_binary, self._temp_file_ini] + extra_args,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.STDOUT,
                )
    
            except OSError:
                # TODO, report api
                print("POV-Ray 3.7: could not execute '%s'" % pov_binary)
                import traceback
    
                print("Command line arguments passed: " + str(extra_args))
                return True
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        def _cleanup(self):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            """Delete temp files and unpacked ones"""
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            for f in (self._temp_file_in, self._temp_file_ini, self._temp_file_out):
    
                for i in range(5):
                    try:
                        os.unlink(f)
                        break
                    except OSError:
                        # Wait a bit before retrying file might be still in use by Blender,
                        # and Windows does not know how to delete a file in use!
                        time.sleep(self.DELAY)
    
            for i in unpacked_images:
                for c in range(5):
                    try:
                        os.unlink(i)
                        break
                    except OSError:
                        # Wait a bit before retrying file might be still in use by Blender,
                        # and Windows does not know how to delete a file in use!
                        time.sleep(self.DELAY)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            """Export necessary files from text editor and render image."""
    
            import tempfile
    
            r = scene.render
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            x = int(r.resolution_x * r.resolution_percentage * 0.01)
            y = int(r.resolution_y * r.resolution_percentage * 0.01)
    
            # This makes some tests on the render, returning True if all goes good, and False if
            # it was finished one way or the other.
            # It also pauses the script (time.sleep())
            def _test_wait():
                time.sleep(self.DELAY)
    
                # User interrupts the rendering
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                if self.test_break():
                    try:
    
    Campbell Barton's avatar
    Campbell Barton committed
                        self._process.terminate()
    
    Campbell Barton's avatar
    Campbell Barton committed
                    except OSError:
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                        pass
    
                # POV process is finisehd, one way or the other
    
    Campbell Barton's avatar
    Campbell Barton committed
                if poll_result is not None:
    
                    if poll_result < 0:
                        print("***POV PROCESS FAILED : %s ***" % poll_result)
                        self.update_stats("", "POV-Ray 3.7: Failed")
                    return False
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
            if bpy.context.scene.pov.text_block != "":
    
                    self._temp_file_in = tempfile.NamedTemporaryFile(
                        suffix=".pov", delete=False
                    ).name
                    self._temp_file_out = tempfile.NamedTemporaryFile(
                        suffix=".png", delete=False
                    ).name
                    # self._temp_file_out = tempfile.NamedTemporaryFile(suffix=".tga", delete=False).name
                    self._temp_file_ini = tempfile.NamedTemporaryFile(
                        suffix=".ini", delete=False
                    ).name
                    self._temp_file_log = os.path.join(
                        tempfile.gettempdir(), "alltext.out"
                    )
    
                else:
                    povPath = scene.pov.text_block
                    renderImagePath = os.path.splitext(povPath)[0]
    
                    self._temp_file_out = os.path.join(preview_dir, renderImagePath)
    
                    self._temp_file_in = os.path.join(preview_dir, povPath)
    
                    self._temp_file_ini = os.path.join(
                        preview_dir,
                        (os.path.splitext(self._temp_file_in)[0] + ".INI"),
                    )
    
                    self._temp_file_log = os.path.join(preview_dir, "alltext.out")
    
                '''
                try:
                    os.remove(self._temp_file_in)  # so as not to load the old file
                except OSError:
                    pass
    
                print(scene.pov.text_block)
                text = bpy.data.texts[scene.pov.text_block]
    
                file = open("%s" % self._temp_file_in, "w")
    
                # Why are the newlines needed?
                file.write("\n")
                file.write(text.as_string())
    
                file.write("\n")
    
                file.close()
    
                # has to be called to update the frame on exporting animations
                scene.frame_set(scene.frame_current)
    
                pov_binary = PovrayRender._locate_binary()
    
                if not pov_binary:
    
                    print(
                        "POV-Ray 3.7: could not execute povray, possibly POV-Ray isn't installed"
                    )
    
                self.update_stats(
                    "", "POV-Ray 3.7: Exporting ini options from Blender"
                )
    
                write_pov_ini(
                    scene,
                    self._temp_file_ini,
                    self._temp_file_log,
                    self._temp_file_in,
                    self._temp_file_out,
                )
    
                print("***-STARTING-***")
    
                if scene.pov.command_line_switches != "":
                    for newArg in scene.pov.command_line_switches.split(" "):
                        extra_args.append(newArg)
    
                if sys.platform[:3] == "win":
    
                    if "/EXIT" not in extra_args and not scene.pov.pov_editor:
    
                    # added -d option to prevent render window popup which leads to segfault on linux
                    extra_args.append("-d")
    
                # Start Rendering!
                try:
    
                    if (
                        sys.platform[:3] != "win" and scene.pov.sdl_window_enable
                    ):  # segfault on linux == False !!!
    
                        env = {'POV_DISPLAY_SCALED': 'off'}
                        env.update(os.environ)
    
                        self._process = subprocess.Popen(
                            [pov_binary, self._temp_file_ini],
                            stdout=subprocess.PIPE,
                            stderr=subprocess.STDOUT,
                            env=env,
                        )
    
                        self._process = subprocess.Popen(
                            [pov_binary, self._temp_file_ini] + extra_args,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.STDOUT,
                        )
    
                except OSError:
                    # TODO, report api
                    print("POV-Ray 3.7: could not execute '%s'" % pov_binary)
                    import traceback
    
                    return False
    
                else:
                    print("Engine ready!...")
                    print("Command line arguments passed: " + str(extra_args))
    
                    self.update_stats("", "POV-Ray 3.7: Parsing File")
    
                # Indented in main function now so repeated here but still not working
    
                # to bring back render result to its buffer
    
                if os.path.exists(self._temp_file_out):
                    xmin = int(r.border_min_x * x)
                    ymin = int(r.border_min_y * y)
                    xmax = int(r.border_max_x * x)
                    ymax = int(r.border_max_y * y)
    
                    result = self.begin_result(0, 0, x, y)
    
                    time.sleep(self.DELAY)
                    try:
                        lay.load_from_file(self._temp_file_out)
                    except RuntimeError:
                        print("***POV ERROR WHILE READING OUTPUT FILE***")
                    self.end_result(result)
    
                # print(self._temp_file_log) #bring the pov log to blender console with proper path?
                with open(
                    self._temp_file_log
                ) as f:  # The with keyword automatically closes the file when you are done
    
                    print(f.read())
    
    
                if scene.pov.tempfiles_enable or scene.pov.deletefiles_enable:
    
                    self._cleanup()
    
                ##WIP output format
                ##        if r.image_settings.file_format == 'OPENEXR':
                ##            fformat = 'EXR'
                ##            render.image_settings.color_mode = 'RGBA'
                ##        else:
                ##            fformat = 'TGA'
                ##            r.image_settings.file_format = 'TARGA'
                ##            r.image_settings.color_mode = 'RGBA'
    
                blendSceneName = bpy.data.filepath.split(os.path.sep)[-1].split(
                    "."
                )[0]
    
                povSceneName = ""
                povPath = ""
                renderImagePath = ""
    
                # has to be called to update the frame on exporting animations
                scene.frame_set(scene.frame_current)
    
                if not scene.pov.tempfiles_enable:
    
                    # check paths
    
                    povPath = bpy.path.abspath(scene.pov.scene_path).replace(
                        '\\', '/'
                    )
    
                    if povPath == "":
                        if bpy.data.is_saved:
                            povPath = bpy.path.abspath("//")
    
                            povPath = tempfile.gettempdir()
                    elif povPath.endswith("/"):
                        if povPath == "/":
                            povPath = bpy.path.abspath("//")
                        else:
                            povPath = bpy.path.abspath(scene.pov.scene_path)
    
                    if not os.path.exists(povPath):
                        try:
                            os.makedirs(povPath)
                        except:
                            import traceback
    
                            print(
                                "POV-Ray 3.7: Cannot create scenes directory: %r"
                                % povPath
                            )
                            self.update_stats(
                                "",
                                "POV-Ray 3.7: Cannot create scenes directory %r"
                                % povPath,
                            )
    
    
                    '''
                    # Bug in POV-Ray RC3
                    renderImagePath = bpy.path.abspath(scene.pov.renderimage_path).replace('\\','/')
                    if renderImagePath == "":
                        if bpy.data.is_saved:
                            renderImagePath = bpy.path.abspath("//")
                        else:
                            renderImagePath = tempfile.gettempdir()
                        #print("Path: " + renderImagePath)
                    elif path.endswith("/"):
                        if renderImagePath == "/":
                            renderImagePath = bpy.path.abspath("//")
                        else:
                            renderImagePath = bpy.path.abspath(scene.pov.renderimage_path)
                    if not os.path.exists(path):
                        print("POV-Ray 3.7: Cannot find render image directory")
                        self.update_stats("", "POV-Ray 3.7: Cannot find render image directory")
                        time.sleep(2.0)
                        return
                    '''
    
                    # check name
                    if scene.pov.scene_name == "":
                        if blendSceneName != "":
                            povSceneName = blendSceneName
                        else:
                            povSceneName = "untitled"
                    else:
                        povSceneName = scene.pov.scene_name
                        if os.path.isfile(povSceneName):
                            povSceneName = os.path.basename(povSceneName)
                        povSceneName = povSceneName.split('/')[-1].split('\\')[-1]
                        if not povSceneName:
                            print("POV-Ray 3.7: Invalid scene name")
                            self.update_stats("", "POV-Ray 3.7: Invalid scene name")
                            time.sleep(2.0)
    
                        povSceneName = os.path.splitext(povSceneName)[0]
    
                    print("Scene name: " + povSceneName)
                    print("Export path: " + povPath)
                    povPath = os.path.join(povPath, povSceneName)
                    povPath = os.path.realpath(povPath)
    
                    # for now this has to be the same like the pov output. Bug in POV-Ray RC3.
                    # renderImagePath = renderImagePath + "\\" + povSceneName
                    renderImagePath = povPath  # Bugfix for POV-Ray RC3 bug
                    # renderImagePath = os.path.realpath(renderImagePath)  # Bugfix for POV-Ray RC3 bug
    
    
                    # print("Export path: %s" % povPath)
                    # print("Render Image path: %s" % renderImagePath)
    
    
                # start export
                self.update_stats("", "POV-Ray 3.7: Exporting data from Blender")
    
                self._export(depsgraph, povPath, renderImagePath)
    
                self.update_stats("", "POV-Ray 3.7: Parsing File")
    
    
                if not self._render(depsgraph):
    
                    self.update_stats("", "POV-Ray 3.7: Not found")
    
                # x = int(r.resolution_x * r.resolution_percentage * 0.01)
                # y = int(r.resolution_y * r.resolution_percentage * 0.01)
    
    
                # Wait for the file to be created
                # XXX This is no more valid, as 3.7 always creates output file once render is finished!
                parsing = re.compile(br"= \[Parsing\.\.\.\] =")
                rendering = re.compile(br"= \[Rendering\.\.\.\] =")
                percent = re.compile(r"\(([0-9]{1,3})%\)")
                # print("***POV WAITING FOR FILE***")
    
                data = b""
                last_line = ""
                while _test_wait():
    
                    # POV in Windows did not output its stdout/stderr, it displayed them in its GUI
                    # But now writes file
    
                    if self._is_windows:
                        self.update_stats("", "POV-Ray 3.7: Rendering File")
                    else:
                        t_data = self._process.stdout.read(10000)
                        if not t_data:
                            continue
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                        data += t_data
                        # XXX This is working for UNIX, not sure whether it might need adjustments for
                        #     other OSs
                        # First replace is for windows
    
                        t_data = (
                            str(t_data)
                            .replace('\\r\\n', '\\n')
                            .replace('\\r', '\r')
                        )
    
                        lines = t_data.split('\\n')
                        last_line += lines[0]
                        lines[0] = last_line
                        print('\n'.join(lines), end="")
                        last_line = lines[-1]
    
                        if rendering.search(data):
                            _pov_rendering = True
                            match = percent.findall(str(data))
                            if match:
    
                                self.update_stats(
                                    "",
                                    "POV-Ray 3.7: Rendering File (%s%%)"
                                    % match[-1],
                                )
    
                            else:
                                self.update_stats("", "POV-Ray 3.7: Rendering File")
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                        elif parsing.search(data):
                            self.update_stats("", "POV-Ray 3.7: Parsing File")
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                if os.path.exists(self._temp_file_out):
                    # print("***POV FILE OK***")
    
                    # self.update_stats("", "POV-Ray 3.7: Rendering")
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                    xmin = int(r.border_min_x * x)
                    ymin = int(r.border_min_y * y)
                    xmax = int(r.border_max_x * x)
                    ymax = int(r.border_max_y * y)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                    # print("***POV UPDATING IMAGE***")
                    result = self.begin_result(0, 0, x, y)
    
                    # result = self.begin_result(xmin, ymin, xmax - xmin, ymax - ymin)
                    # result = self.begin_result(0, 0, xmax - xmin, ymax - ymin)
    
                    # This assumes the file has been fully written We wait a bit, just in case!
                    time.sleep(self.DELAY)
    
                    try:
                        lay.load_from_file(self._temp_file_out)
                        # XXX, tests for border render.
    
                        # lay.load_from_file(self._temp_file_out, xmin, ymin)
    
                        print("***POV ERROR WHILE READING OUTPUT FILE***")
    
                    # Not needed right now, might only be useful if we find a way to use temp raw output of
                    # pov 3.7 (in which case it might go under _test_wait()).
                    '''
                    def update_image():
                        # possible the image wont load early on.
    
                            lay.load_from_file(self._temp_file_out)
                            # XXX, tests for border render.
                            #lay.load_from_file(self._temp_file_out, xmin, ymin)
                            #lay.load_from_file(self._temp_file_out, xmin, ymin)
                        except RuntimeError:
    
                    # Update while POV-Ray renders
                    while True:
                        # print("***POV RENDER LOOP***")
    
                        # test if POV-Ray exists
                        if self._process.poll() is not None:
                            print("***POV PROCESS FINISHED***")
                            update_image()
                            break
    
                        # user exit
                        if self.test_break():
                            try:
                                self._process.terminate()
                                print("***POV PROCESS INTERRUPTED***")
                            except OSError:
                                pass
    
                        # Would be nice to redirect the output
                        # stdout_value, stderr_value = self._process.communicate() # locks
    
                        # check if the file updated
                        new_size = os.path.getsize(self._temp_file_out)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
                        if new_size != prev_size:
                            update_image()
                            prev_size = new_size
    
                else:
                    print("***POV FILE NOT FOUND***")
    
                print("***POV FILE FINISHED***")
    
    
                # print(filename_log) #bring the pov log to blender console with proper path?
                with open(
    
                    self._temp_file_log,
                    encoding='utf-8'
    
                ) as f:  # The with keyword automatically closes the file when you are done
    
                    msg = f.read()
                    #if isinstance(msg, str):
                        #stdmsg = msg
                        #decoded = False
                    #else:
                        #if type(msg) == bytes:
                    #stdmsg = msg.split('\n')
                    #stdmsg = msg.encode('utf-8', "replace")
                    #stdmsg = msg.encode("utf-8", "replace")
    
                    #stdmsg = msg.decode(encoding)
                        #decoded = True
                    #msg.encode('utf-8').decode('utf-8')
                    print(msg)
                    # Also print to the interactive console used in POV centric workspace
                    # To do: get a grip on new line encoding
                    # and make this a function to be used elsewhere
                    for win in bpy.context.window_manager.windows:
                        if win.screen != None:
                            scr = win.screen
                            for area in scr.areas:
                                if area.type == 'CONSOLE':
                                    #context override
                                    #ctx = {'window': win, 'screen': scr, 'area':area}#bpy.context.copy()
                                    ctx = {}
                                    ctx['area'] = area
                                    ctx['region'] = area.regions[-1]
                                    ctx['space_data'] = area.spaces.active
                                    ctx['screen'] = scr#C.screen
                                    ctx['window'] = win
    
                                    #bpy.ops.console.banner(ctx, text = "Hello world")
                                    bpy.ops.console.clear_line(ctx)
                                    stdmsg = msg.split('\n') #XXX todo , test and see
                                    for i in stdmsg:
                                        bpy.ops.console.insert(ctx, text = i)
    
                self.update_stats("", "")
    
                if scene.pov.tempfiles_enable or scene.pov.deletefiles_enable:
                    self._cleanup()
    
                sound_on = bpy.context.preferences.addons[
                    __package__
                ].preferences.use_sounds
    
                if sys.platform[:3] == "win" and sound_on:
                    # Could not find tts Windows command so playing beeps instead :-)
                    # "Korobeiniki"(Коробе́йники)
                    # aka "A-Type" Tetris theme
                    import winsound
                    winsound.Beep(494,250) #B
                    winsound.Beep(370,125) #F
                    winsound.Beep(392,125) #G
                    winsound.Beep(440,250) #A
                    winsound.Beep(392,125) #G
                    winsound.Beep(370,125) #F#
                    winsound.Beep(330,275) #E
                    winsound.Beep(330,125) #E
                    winsound.Beep(392,125) #G
                    winsound.Beep(494,275) #B
                    winsound.Beep(440,125) #A
                    winsound.Beep(392,125) #G
                    winsound.Beep(370,275) #F
                    winsound.Beep(370,125) #F
                    winsound.Beep(392,125) #G
                    winsound.Beep(440,250) #A
                    winsound.Beep(494,250) #B
                    winsound.Beep(392,250) #G
                    winsound.Beep(330,350) #E
                    time.sleep(0.5)
                    winsound.Beep(440,250) #A
                    winsound.Beep(440,150) #A
                    winsound.Beep(523,125) #D8
                    winsound.Beep(659,250) #E8
                    winsound.Beep(587,125) #D8
                    winsound.Beep(523,125) #C8
                    winsound.Beep(494,250) #B
                    winsound.Beep(494,125) #B
                    winsound.Beep(392,125) #G
                    winsound.Beep(494,250) #B
                    winsound.Beep(440,150) #A
                    winsound.Beep(392,125) #G
                    winsound.Beep(370,250) #F#
                    winsound.Beep(370,125) #F#
                    winsound.Beep(392,125) #G
                    winsound.Beep(440,250) #A
                    winsound.Beep(494,250) #B
                    winsound.Beep(392,250) #G
                    winsound.Beep(330,300) #E
    
                #Does Linux support say command?
                elif sys.platform[:3] != "win" :
                    finished_render_message = "\'Render completed\'"
                    # We don't want the say command to block Python,
                    # so we add an ampersand after the message
                    os.system("say %s &" % (finished_render_message))
    
    ##################################################################################
    #################################Operators########################################
    ##################################################################################
    
    class RenderPovTexturePreview(Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Export only files necessary to texture preview and render image."""
    
        bl_idname = "tex.preview_update"
        bl_label = "Update preview"
    
        def execute(self, context):
    
            tex = (
                bpy.context.object.active_material.active_texture
            )  # context.texture
            texPrevName = (
                string_strip_hyphen(bpy.path.clean_name(tex.name)) + "_prev"