Skip to content
Snippets Groups Projects
render.py 76.2 KiB
Newer Older
  • Learn to ignore specific revisions
  •             pov_binary = os.path.join(win_home, "bin", "pvengine64.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 ""
    
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        def _export(self, depsgraph, pov_path, image_render_path):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            """gather all necessary output files paths user defined and auto generated and export there"""
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                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.
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                self._temp_file_out = tempfile.NamedTemporaryFile(suffix=".png", delete=False).name
    
                # self._temp_file_out = tempfile.NamedTemporaryFile(suffix=".tga", delete=False).name
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                self._temp_file_ini = tempfile.NamedTemporaryFile(suffix=".ini", delete=False).name
                self._temp_file_log = os.path.join(tempfile.gettempdir(), "alltext.out")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                self._temp_file_in = pov_path + ".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.
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                self._temp_file_out = image_render_path + ".png"
                # self._temp_file_out = image_render_path + ".tga"
                self._temp_file_ini = pov_path + ".ini"
                log_path = bpy.path.abspath(scene.pov.scene_path).replace('\\', '/')
                self._temp_file_log = os.path.join(log_path, "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:
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                print("POV-Ray 3.7: could not execute povray, possibly POV-Ray isn't installed")
    
                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
    
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                for new_arg in scene.pov.command_line_switches.split(" "):
                    extra_args.append(new_arg)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            if platform.startswith('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:
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                for j 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."""
    
            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
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                try:
                    poll_result = self._process.poll()
                except AttributeError:
                    print("***CHECK POV PATH IN PREFERENCES***")
                    return False
    
                # 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 != "":
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    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
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    self._temp_file_ini = tempfile.NamedTemporaryFile(suffix=".ini", delete=False).name
                    self._temp_file_log = os.path.join(tempfile.gettempdir(), "alltext.out")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    pov_path = scene.pov.text_block
                    image_render_path = os.path.splitext(pov_path)[0]
                    self._temp_file_out = os.path.join(preview_dir, image_render_path)
                    self._temp_file_in = os.path.join(preview_dir, pov_path)
    
                    self._temp_file_ini = os.path.join(
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                        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]
    
                with open(self._temp_file_in, "w") as file:
                    # Why are the newlines needed?
                    file.write("\n")
                    file.write(text.as_string())
                    file.write("\n")
                if not file.closed:
                    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:
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    print("POV-Ray 3.7: could not execute povray, possibly POV-Ray isn't installed")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                self.update_stats("", "POV-Ray 3.7: Exporting ini options from Blender")
    
                write_pov_ini(
                    self._temp_file_ini,
                    self._temp_file_log,
                    self._temp_file_in,
                    self._temp_file_out,
                )
    
                print("***-STARTING-***")
    
                if scene.pov.command_line_switches != "":
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    for new_arg in scene.pov.command_line_switches.split(" "):
                        extra_args.append(new_arg)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                if platform.startswith('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:
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    if scene.pov.sdl_window_enable and not platform.startswith(
                        'win'
    
                    ):  # 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'
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                blend_scene_name = bpy.data.filepath.split(os.path.sep)[-1].split(".")[0]
                pov_scene_name = ""
                pov_path = ""
                image_render_path = ""
    
    
                # 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
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    pov_path = bpy.path.abspath(scene.pov.scene_path).replace('\\', '/')
                    if pov_path == "":
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                            pov_path = bpy.path.abspath("//")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                            pov_path = tempfile.gettempdir()
                    elif pov_path.endswith("/"):
                        if pov_path == "/":
                            pov_path = bpy.path.abspath("//")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                            pov_path = bpy.path.abspath(scene.pov.scene_path)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    if not os.path.exists(pov_path):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                            os.makedirs(pov_path)
                        except BaseException as e:
                            print(e.__doc__)
                            print('An exception occurred: {}'.format(e))
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                            print("POV-Ray 3.7: Cannot create scenes directory: %r" % pov_path)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                                "", "POV-Ray 3.7: Cannot create scenes directory %r" % pov_path
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    image_render_path = bpy.path.abspath(scene.pov.renderimage_path).replace('\\','/')
                    if image_render_path == "":
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                            image_render_path = bpy.path.abspath("//")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                            image_render_path = tempfile.gettempdir()
                        #print("Path: " + image_render_path)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                        if image_render_path == "/":
                            image_render_path = bpy.path.abspath("//")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                            image_render_path = bpy.path.abspath(scene.pov.)
    
                    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 == "":
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                        if blend_scene_name != "":
                            pov_scene_name = blend_scene_name
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                            pov_scene_name = "untitled"
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                        pov_scene_name = scene.pov.scene_name
                        if os.path.isfile(pov_scene_name):
                            pov_scene_name = os.path.basename(pov_scene_name)
                        pov_scene_name = pov_scene_name.split('/')[-1].split('\\')[-1]
                        if not pov_scene_name:
    
                            print("POV-Ray 3.7: Invalid scene name")
                            self.update_stats("", "POV-Ray 3.7: Invalid scene name")
                            time.sleep(2.0)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                        pov_scene_name = os.path.splitext(pov_scene_name)[0]
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    print("Scene name: " + pov_scene_name)
                    print("Export path: " + pov_path)
                    pov_path = os.path.join(pov_path, pov_scene_name)
                    pov_path = os.path.realpath(pov_path)
    
                    image_render_path = pov_path
                    # print("Render Image path: " + image_render_path)
    
    
                # start export
                self.update_stats("", "POV-Ray 3.7: Exporting data from Blender")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                self._export(depsgraph, pov_path, image_render_path)
    
                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
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                        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:
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                                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(
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    self._temp_file_log, encoding='utf-8'
    
                ) as f:  # The with keyword automatically closes the file when you are done
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    # 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')
                    msg.replace("\t", "    ")
    
                    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:
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                        if win.screen is not None:
    
                            scr = win.screen
                            for area in scr.areas:
                                if area.type == 'CONSOLE':
    
                                        # context override
                                        ctx = {
                                            'area': area,
                                            'screen': scr,
                                            'window': win
                                        }
    
    
                                        # bpy.ops.console.banner(ctx, text = "Hello world")
                                        bpy.ops.console.clear_line(ctx)
    
                                        for i in msg.split('\n'):
                                            bpy.ops.console.scrollback_append(
                                                ctx,
                                                text=i,
                                                type='INFO'
                                            )
    
                                            # bpy.ops.console.insert(ctx, text=(i + "\n"))
                                    except BaseException as e:
                                        print(e.__doc__)
                                        print('An exception occurred: {}'.format(e))
                                        pass
    
                self.update_stats("", "")
    
                if scene.pov.tempfiles_enable or scene.pov.deletefiles_enable:
                    self._cleanup()
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                sound_on = bpy.context.preferences.addons[__package__].preferences.use_sounds
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                if platform.startswith('win') and sound_on:
    
                    # Could not find tts Windows command so playing beeps instead :-)
                    # "Korobeiniki"(Коробе́йники)
                    # aka "A-Type" Tetris theme
                    import winsound
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
                    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
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    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
    
                # Mac supports natively say command
                elif platform == "darwin":
    
                    # We don't want the say command to block Python,
                    # so we add an ampersand after the message
    
                    # but if the os TTS package isn't up to date it
                    # still does thus, the try except clause
                    try:
                        os.system("say %s &" % finished_render_message)
                    except BaseException as e:
                        print(e.__doc__)
                        print("your Mac may need an update, try to restart computer")
                        pass
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                # While Linux frequently has espeak installed or at least can suggest
                # Maybe windows could as well ?
                elif platform == "linux":
    
                    # We don't want the espeak command to block Python,
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    # so we add an ampersand after the message
    
                    # but if the espeak TTS package isn't installed it
                    # still does thus, the try except clause
                    try:
                        os.system("echo %s | espeak &" % finished_render_message)
                    except BaseException as e:
                        print(e.__doc__)
                        pass
    
    
    # --------------------------------------------------------------------------------- #
    # ----------------------------------- Operators ----------------------------------- #
    # --------------------------------------------------------------------------------- #
    
    class RenderPovTexturePreview(Operator):
    
        """Export only files necessary to texture preview and render image"""
    
        bl_idname = "tex.preview_update"
        bl_label = "Update preview"
    
        def execute(self, context):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            tex = bpy.context.object.active_material.active_texture  # context.texture
            tex_prev_name = string_strip_hyphen(bpy.path.clean_name(tex.name)) + "_prev"
    
            # Make sure Preview directory exists and is empty
    
            if not os.path.isdir(preview_dir):
                os.mkdir(preview_dir)
    
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            ini_prev_file = os.path.join(preview_dir, "Preview.ini")
            input_prev_file = os.path.join(preview_dir, "Preview.pov")
            output_prev_file = os.path.join(preview_dir, tex_prev_name)
    
            # ---------------------------------- ini ---------------------------------- #
    
            with open(ini_prev_file, "w") as file_ini:
                file_ini.write('Version=3.8\n')
                file_ini.write('Input_File_Name="%s"\n' % input_prev_file)
                file_ini.write('Output_File_Name="%s.png"\n' % output_prev_file)
                file_ini.write('Library_Path="%s"\n' % preview_dir)
                file_ini.write('Width=256\n')
                file_ini.write('Height=256\n')
                file_ini.write('Pause_When_Done=0\n')
                file_ini.write('Output_File_Type=N\n')
                file_ini.write('Output_Alpha=1\n')
                file_ini.write('Antialias=on\n')
                file_ini.write('Sampling_Method=2\n')
                file_ini.write('Antialias_Depth=3\n')
                file_ini.write('-d\n')
            if not file_ini.closed:
                file_ini.close()
    
            # ---------------------------------- pov ---------------------------------- #
    
            with open(input_prev_file, "w") as file_pov:
                pat_name = "PAT_" + string_strip_hyphen(bpy.path.clean_name(tex.name))
                file_pov.write("#declare %s = \n" % pat_name)
                file_pov.write(shading.export_pattern(tex))
    
                file_pov.write("#declare Plane =\n")
                file_pov.write("mesh {\n")
                file_pov.write(
                    "    triangle {<-2.021,-1.744,2.021>,<-2.021,-1.744,-2.021>,<2.021,-1.744,2.021>}\n"
                )
                file_pov.write(
                    "    triangle {<-2.021,-1.744,-2.021>,<2.021,-1.744,-2.021>,<2.021,-1.744,2.021>}\n"
                )
                file_pov.write("    texture{%s}\n" % pat_name)
                file_pov.write("}\n")
                file_pov.write("object {Plane}\n")
                file_pov.write("light_source {\n")
                file_pov.write("    <0,4.38,-1.92e-07>\n")
                file_pov.write("    color rgb<4, 4, 4>\n")
                file_pov.write("    parallel\n")
                file_pov.write("    point_at  <0, 0, -1>\n")
                file_pov.write("}\n")
                file_pov.write("camera {\n")
                file_pov.write("    location  <0, 0, 0>\n")
                file_pov.write("    look_at  <0, 0, -1>\n")
                file_pov.write("    right <-1.0, 0, 0>\n")
                file_pov.write("    up <0, 1, 0>\n")
                file_pov.write("    angle  96.805211\n")
                file_pov.write("    rotate  <-90.000003, -0.000000, 0.000000>\n")
                file_pov.write("    translate <0.000000, 0.000000, 0.000000>\n")
                file_pov.write("}\n")
            if not file_pov.closed:
                file_pov.close()
    
            # ------------------------------- end write ------------------------------- #
    
    
            pov_binary = PovrayRender._locate_binary()
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            if platform.startswith('win'):
    
                p1 = subprocess.Popen(
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    ["%s" % pov_binary, "/EXIT", "%s" % ini_prev_file],
    
                    stdout=subprocess.PIPE,
                    stderr=subprocess.STDOUT,
                )
    
                p1 = subprocess.Popen(
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    ["%s" % pov_binary, "-d", "%s" % ini_prev_file],
    
                    stdout=subprocess.PIPE,
                    stderr=subprocess.STDOUT,
                )
    
            p1.wait()
    
            tex.use_nodes = True
            tree = tex.node_tree
            links = tree.links
            for n in tree.nodes:
                tree.nodes.remove(n)
    
            im = tree.nodes.new("TextureNodeImage")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            path_prev = "%s.png" % output_prev_file
            im.image = bpy.data.images.load(path_prev)
            name = path_prev
    
            name = name.split("/")
            name = name[len(name) - 1]
    
            im.name = name
    
            im.location = 200, 200
    
            previewer = tree.nodes.new('TextureNodeOutput')
    
            previewer.label = "Preview"
    
            previewer.location = 400, 400
            links.new(im.outputs[0], previewer.inputs[0])
            # tex.type="IMAGE" # makes clip extend possible
            # tex.extension="CLIP"
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Export files depending on text editor options and render image."""
    
        bl_idname = "text.run"
        bl_label = "Run"
        bl_context = "text"
        bl_description = "Run a render with this text only"
    
        def execute(self, context):
            scene = context.scene
            scene.pov.text_block = context.space_data.text.name
    
            bpy.ops.render.render()
    
    classes = (
        PovrayRender,
        RenderPovTexturePreview,
        RunPovTextRender,
    )
    
    
    
    def register():
        for cls in classes:
            register_class(cls)
    
        scripting.register()
    
        scripting.unregister()
    
            unregister_class(cls)