Skip to content
Snippets Groups Projects
render.py 233 KiB
Newer Older
  • Learn to ignore specific revisions
  •         # 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 !="":
    
                if scene.pov.tempfiles_enable:
                    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")
                    return False
    
                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-***")
    
                extra_args = []
    
                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:
                        extra_args.append("/EXIT")
    
                    # 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)
                    else:
                        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
                    traceback.print_exc()
                    print ("***-DONE-***")
                    return False
    
                else:
                    print("Engine ready!...")
                    print("Command line arguments passed: " + str(extra_args))
                    #return True
    
                    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
                            traceback.print_exc()
    
                            print("POV-Ray 3.7: Cannot create scenes directory: %r" % povPath)
                            self.update_stats("", "POV-Ray 3.7: Cannot create scenes directory %r" % \
                                              povPath)
                            time.sleep(2.0)
                            #return
    
                    '''
                    # 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)
                            #return
                        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")
                    #return
    
                #r = scene.render
                # compute resolution
                #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)
                    lay = result.layers[0]
    
                    # 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)
                    except RuntimeError:
    
                        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) as f: # The with keyword automatically closes the file when you are done
                    print(f.read())
    
                self.update_stats("", "")
    
                if scene.pov.tempfiles_enable or scene.pov.deletefiles_enable:
                    self._cleanup()
    
    ##################################################################################
    #################################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"
    
            if not os.path.isdir(preview_dir):
                os.mkdir(preview_dir)
    
            iniPrevFile=os.path.join(preview_dir, "Preview.ini")
            inputPrevFile=os.path.join(preview_dir, "Preview.pov")
            outputPrevFile=os.path.join(preview_dir, texPrevName)
    
            ##################### ini ##########################################
            fileIni=open("%s"%iniPrevFile,"w")
            fileIni.write('Version=3.7\n')
            fileIni.write('Input_File_Name="%s"\n'%inputPrevFile)
            fileIni.write('Output_File_Name="%s.png"\n'%outputPrevFile)
    
            fileIni.write('Library_Path="%s"\n' % preview_dir)
    
            fileIni.write('Width=256\n')
            fileIni.write('Height=256\n')
            fileIni.write('Pause_When_Done=0\n')
            fileIni.write('Output_File_Type=N\n')
            fileIni.write('Output_Alpha=1\n')
            fileIni.write('Antialias=on\n')
            fileIni.write('Sampling_Method=2\n')
            fileIni.write('Antialias_Depth=3\n')
            fileIni.write('-d\n')
            fileIni.close()
            ##################### pov ##########################################
            filePov=open("%s"%inputPrevFile,"w")
            PATname = "PAT_"+string_strip_hyphen(bpy.path.clean_name(tex.name))
            filePov.write("#declare %s = \n"%PATname)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            filePov.write(shading.exportPattern(tex, string_strip_hyphen))
    
    
            filePov.write("#declare Plane =\n")
            filePov.write("mesh {\n")
            filePov.write("    triangle {<-2.021,-1.744,2.021>,<-2.021,-1.744,-2.021>,<2.021,-1.744,2.021>}\n")
            filePov.write("    triangle {<-2.021,-1.744,-2.021>,<2.021,-1.744,-2.021>,<2.021,-1.744,2.021>}\n")
            filePov.write("    texture{%s}\n"%PATname)
            filePov.write("}\n")
            filePov.write("object {Plane}\n")
            filePov.write("light_source {\n")
            filePov.write("    <0,4.38,-1.92e-07>\n")
            filePov.write("    color rgb<4, 4, 4>\n")
            filePov.write("    parallel\n")
            filePov.write("    point_at  <0, 0, -1>\n")
            filePov.write("}\n")
            filePov.write("camera {\n")
            filePov.write("    location  <0, 0, 0>\n")
            filePov.write("    look_at  <0, 0, -1>\n")
            filePov.write("    right <-1.0, 0, 0>\n")
            filePov.write("    up <0, 1, 0>\n")
            filePov.write("    angle  96.805211\n")
            filePov.write("    rotate  <-90.000003, -0.000000, 0.000000>\n")
            filePov.write("    translate <0.000000, 0.000000, 0.000000>\n")
            filePov.write("}\n")
            filePov.close()
            ##################### end write ##########################################
    
            pov_binary = PovrayRender._locate_binary()
    
            if sys.platform[:3] == "win":
    
                p1=subprocess.Popen(["%s"%pov_binary,"/EXIT","%s"%iniPrevFile],
                    stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
    
                p1=subprocess.Popen(["%s"%pov_binary,"-d","%s"%iniPrevFile],
                    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")
    
            pathPrev="%s.png"%outputPrevFile
            im.image = bpy.data.images.load(pathPrev)
            name=pathPrev
            name=name.split("/")
            name=name[len(name)-1]
    
            im.name = name
    
            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
    
    
            #empty text name property engain
            scene.pov.text_block = ""
    
    
    classes = (
        PovrayRender,
        RenderPovTexturePreview,
        RunPovTextRender,
    )
    
    
    def register():
        #from bpy.utils import register_class
    
        for cls in classes:
            register_class(cls)
    
    
    def unregister():
        from bpy.utils import unregister_class
    
    
            unregister_class(cls)