Skip to content
Snippets Groups Projects
__init__.py 20.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • # SPDX-License-Identifier: GPL-2.0-or-later
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    """Import, export and render to POV engines.
    
    
    These engines can be POV-Ray, Uberpov, HgPovray but others too, since POV is a
    Scene Description Language. The script has been split in as few files as possible and
    metaphorically structured as a train with some boilerplate rendering locomotive,
    followed by its cars each representing a thematic in the 3D field:
    
    ########################################### RENDERING ###########################################
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    __init__.py :
    
        Provide script's metadata, Initialize addon preferences, (re)load package modules
    
    ui_core.py :
        Set up workspaces and load other ui files for the user to set up all variables
    
    render_core.py :
        Define the POV render engines declinations from generic Blender RenderEngine class
    
    render_properties.py :
        Initialize properties for render parameters (Blender generic and POV native)
    
    render_gui.py :
        Display properties from render_properties.py for user to change them
    
    render.py :
    
        Translate render properties (Blender and POV native) to POV, ini file and CLI
    
                                                                              __------------------Z__
                                                                        _--¨¨] |  __ __ _____________||
                                                                    _-¨7____/  | | °|° | □□□ □□□ □□□ ||
                                                                   (===========|=|  |  |=============||
    
                                                                    `-,_(@)(@)----------------(@)(@)-'
    
    ############################################# LAYOUT ##############################################
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    scenography_properties.py
    
        Initialize properties for passing layout (camera/light/environment) parameters to pov
    
        Display camera/light/environment properties from scenography_properties.py for user to change
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
    scenography.py
    
        Translate  camera/light/environment properties to corresponding pov features
    
                                                        __------------------Z__   ____________________
                                                  _--¨¨] |  __ __ _____________|||____________________|
                                              _-¨7____/  | | °|° | □□□ □□□ □□□ ||| □□□ □□□ □□□ □□□ □□ |
                                             (===========|=|  |  |=============|||====================|
    
                                              `-,_(@)(@)----------------(@)(@)-'^-(@)(@)--------(@)(@)'
    
    ############################################### MODEL #############################################
    
    model_properties.py :
        Initialize properties for translating Blender geometry objects parameters to pov
    
    model_gui.py :
        Display properties from model_properties.py for the user to change them
    
    model_all.py :
        Translate to POV the object level data
    
    model_poly_topology.py :
        Translate to POV the mesh based geometries
    
    model_curve_topology.py :
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        Translate to POV the curve based geometries
    
    
    model_meta_topology.py :
        Translate to POV the metaball based geometries
    
    model_primitives.py :
        Display some simple POV native primitives in 3D view for input and output
    
    model_primitives_topology.py :
        Display some POV native complex or compound primitives in 3D view for input and output
    
                                 __------------------Z__   ____________________   ____________________
                           _--¨¨] |  __ __ _____________|||____________________|||____________________
                       _-¨7____/  | | °|° | □□□ □□□ □□□ ||| □□□ □□□ □□□ □□□ □□ ||| □□□ □□□ □□□ □□□ □□
                      (===========|=|  |  |=============|||====================|||====================
    
                       `-,_(@)(@)----------------(@)(@)-'^-(@)(@)--------(@)(@)-^-(@)(@)--------(@)(@)
    
    ############################################ SHADING #############################################
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        Initialize properties for translating Blender materials parameters to pov
    
    
    shading_ray_properties.py :
        Initialize properties for translating Blender ray paths relevant material parameters to pov
    
        Display variables from shading_properties.py and shading_ray_properties.py for user to change
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    shading.py
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        Translate shading properties to declared textures at the top of a pov file
    
        Initialize properties for translating Blender materials/world... texture influences to pov
    
        Display properties from texturing_properties.py available for user to change
    
        Translate blender pixel based bitmap texture influences into POV
    
    texturing_procedural.py :
        Translate blender algorithmic procedural texture influences into POV
    
               __------------------Z__   ____________________   ____________________   ________________
         _--¨¨] |  __ __ _____________|||____________________|||____________________|||________________
     _-¨7____/  | | °|° | □□□ □□□ □□□ ||| □□□ □□□ □□□ □□□ □□ ||| □□□ □□□ □□□ □□□ □□ ||| □□□ □□□ □□□ □□□
    (===========|=|  |  |=============|||====================|||====================|||================
    
     `-,_(@)(@)----------------(@)(@)-'^-(@)(@)--------(@)(@)-^-(@)(@)--------(@)(@)-^-(@)(@)----------
    
    ############################################ VFX/TECH #############################################
    
    particles_properties.py :
        Initialize all strands, fx, or particles based objects properties to be translated to POV
    
    particles.py :
        Translate to POV the particle based geometries
    
    voxel_lib.py :
        Render smoke to *.df3 files using an updated version of Mike Kost's df3.py legacy library
    
    nodes_properties.py :
        Define all node items and their respective variables or sockets available to POV node trees
    
    nodes.py :
        Translate node trees to the pov file
    
    nodes_fn.py :
        Functions toolbox used by nodes.py to translate node trees to the pov file
    
    nodes_gui.py :
        Operators and menus to interact with POV specific node trees
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
    scripting_properties.py :
    
        Initialize properties for hand written scene description language fragments (POV native)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
    scripting_gui.py :
        Display properties from scripting_properties.py for user to add his custom POV code
    
    scripting.py :
    
        Insert POV native scene description elements into blender scene or to exported POV file
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        Update new variables to values from older API. This file needs an update
    
    ######################################## PRESETS/TEMPLATES ########################################
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
    Along these essential files also coexist a few additional libraries to help make
    
    Blender stand up to other POV enabled IDEs (povwin, POV for Mac, QTPOV, VSCode, Vim...)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        presets :
            Material (sss)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                apple.py ; chicken.py ; cream.py ; Ketchup.py ; marble.py ;
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                potato.py ; skim_milk.py ; skin1.py ; skin2.py ; whole_milk.py
            Radiosity
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                01_Debug.py ; 02_Fast.py ; 03_Normal.py ; 04_Two_Bounces.py ;
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                05_Final.py ; 06_Outdoor_Low_Quality.py ; 07_Outdoor_High_Quality.py ;
                08_Outdoor(Sun)Light.py ; 09_Indoor_Low_Quality.py ;
                10_Indoor_High_Quality.py ;
            World
                01_Clear_Blue_Sky.py ; 02_Partly_Hazy_Sky.py ; 03_Overcast_Sky.py ;
                04_Cartoony_Sky.py ; 05_Under_Water.py ;
            Light
    
                01_(4800K)_Direct_Sun.py ;
                02_(5400K)_High_Noon_Sun.py ;
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                03_(6000K)_Daylight_Window.py ;
                04_(6000K)_2500W_HMI_(Halogen_Metal_Iodide).py ;
    
                05_(4000K)_100W_Metal_Halide.py ;
                06_(3200K)_100W_Quartz_Halogen.py ;
                07_(2850K)_100w_Tungsten.py ;
                08_(2600K)_40w_Tungsten.py ;
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                09_(5000K)_75W_Full_Spectrum_Fluorescent_T12.py ;
                10_(4300K)_40W_Vintage_Fluorescent_T12.py ;
                11_(5000K)_18W_Standard_Fluorescent_T8 ;
                12_(4200K)_18W_Cool_White_Fluorescent_T8.py ;
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                13_(3000K)_18W_Warm_Fluorescent_T8.py ;
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                14_(6500K)_54W_Grow_Light_Fluorescent_T5-HO.py ;
                15_(3200K)_40W_Induction_Fluorescent.py ;
                16_(2100K)_150W_High_Pressure_Sodium.py ;
                17_(1700K)_135W_Low_Pressure_Sodium.py ;
    
                18_(6800K)_175W_Mercury_Vapor.py ;
                19_(5200K)_700W_Carbon_Arc.py ;
                20_(6500K)_15W_LED_Spot.py ;
                21_(2700K)_7W_OLED_Panel.py ;
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                22_(30000K)_40W_Black_Light_Fluorescent.py ;
    
                23_(30000K)_40W_Black_Light_Bulb.py;
                24_(1850K)_Candle.py
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        templates:
            abyss.pov ; biscuit.pov ; bsp_Tango.pov ; chess2.pov ;
            cornell.pov ; diffract.pov ; diffuse_back.pov ; float5 ;
            gamma_showcase.pov ; grenadine.pov ; isocacti.pov ;
            mediasky.pov ; patio-radio.pov ; subsurface.pov ; wallstucco.pov
    """
    
    
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                  "Maurice Raybaud, "
                  "Leonid Desyatkov, "
                  "Bastien Montagne, "
                  "Constantin Rahn, "
                  "Silvio Falcinelli,"
                  "Paco García",
    
        'version': (0, 1, 3),
        'blender': (3, 2, 0),
    
        'location': "Render Properties > Render Engine > Persistence of Vision",
    
        'description': "Persistence of Vision addon for Blender",
    
        'doc_url': "{BLENDER_MANUAL_URL}/addons/render/povray.html",
        'category': "Render",
        'warning': "Co-maintainers welcome",
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    # Other occasional contributors, more or less in chronological order:
    # Luca Bonavita ; Shane Ambler ; Brendon Murphy ; Doug Hammond ;
    # Thomas Dinges ; Jonathan Smith ; Sebastian Nell ; Philipp Oeser ;
    # Sybren A. Stüvel ; Dalai Felinto ; Sergey Sharybin ; Brecht Van Lommel ;
    # Stephen Leger ; Rune Morling ; Aaron Carlisle ; Ankit Meel ;
    
    
    if "bpy" in locals():
    
        importlib.reload(ui_core)
        importlib.reload(nodes_properties)
        importlib.reload(nodes_gui)
        importlib.reload(nodes_fn)
        importlib.reload(nodes)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        importlib.reload(scenography_properties)
    
        importlib.reload(scenography_gui)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        importlib.reload(scenography)
        importlib.reload(render_properties)
        importlib.reload(render_gui)
    
        importlib.reload(render)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        importlib.reload(shading_properties)
    
        importlib.reload(shading_ray_properties)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        importlib.reload(shading_gui)
    
        importlib.reload(shading)
    
        importlib.reload(texturing_procedural)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        importlib.reload(texturing_properties)
        importlib.reload(texturing_gui)
        importlib.reload(texturing)
    
        importlib.reload(model_properties)
        importlib.reload(model_gui)
        importlib.reload(model_all)
        importlib.reload(model_poly_topology)
        importlib.reload(model_meta_topology)
        importlib.reload(model_curve_topology)
        importlib.reload(model_primitives)
        importlib.reload(model_primitives_topology)
        importlib.reload(particles_properties)
        importlib.reload(particles)
        importlib.reload(scripting_properties)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        importlib.reload(scripting_gui)
    
        importlib.reload(update_files)
    
        from bpy.utils import register_class, unregister_class
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        from bpy.props import StringProperty, BoolProperty, EnumProperty
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        from . import (
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            render_properties,
            scenography_properties,
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            shading_properties,
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            texturing_properties,
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            scripting_properties,
            render,
    
            render_core,
            model_primitives,
            model_primitives_topology,
            particles_properties,
            particles,
    
    # ---------------------------------------------------------------- #
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    # Auto update.
    
    # ---------------------------------------------------------------- #
    
    
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    class POV_OT_update_addon(bpy.types.Operator):
    
        """Update this addon to the latest version"""
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
        bl_idname = "pov.update_addon"
        bl_label = "Update POV addon"
    
    
            import os
            import shutil
    
            import urllib.error
    
            import zipfile
    
        def recursive_overwrite(self, src, dest, ignore=None):
            """Update the script automatically (along with other addons).
    
            Arguments:
                src -- path where to update from
                dest -- storing temporary download here
            Keyword Arguments:
                ignore -- leave some directories alone (default: {None})
    
            Returns:
                finished flag for operator which is a set()
            """
            if os.path.isdir(src):
                if not os.path.isdir(dest):
                    os.makedirs(dest)
                files = os.listdir(src)
                ignored = ignore(src, files) if ignore is not None else set()
                unignored_files = (fle for fle in files if fle not in ignored)
                for f in unignored_files:
                    source = os.path.join(src, f)
                    destination = os.path.join(dest, f)
                    recursive_overwrite(source, destination, ignore)
            else:
                shutil.copyfile(src, dest)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
            with tempfile.TemporaryDirectory() as temp_dir_path:
    
                temp_zip_path = os.path.join(temp_dir_path, "master.zip")
    
                # Download zip archive of latest addons master branch commit
                # More work needed so we also get files from the shared addons presets /pov folder
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                # switch this URL back to the BF hosted one as soon as gitweb snapshot gets fixed
    
                url = "https://github.com/blender/blender-addons/archive/refs/heads/master.zip"
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                try:
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
                    with urllib.request.urlopen(url, timeout=60) as url_handle, open(
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    ) as file_handle:
                        file_handle.write(url_handle.read())
                except urllib.error.URLError as err:
    
                    self.report({"ERROR"}, "Could not download: %s" % err)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
                # Extract the zip
    
                print("Extracting ZIP archive")
                with zipfile.ZipFile(temp_zip_path) as zip_archive:
    
                    pov_addon_pkg = (member for member in zip_archive.namelist() if
                                      "blender-addons-master/render_povray" in member)
                    for member in pov_addon_pkg:
                        # Remove the first directory and the filename
                        # e.g. blender-addons-master/render_povray/nodes.py
                        # becomes render_povray/nodes.py
                        target_path = os.path.join(
                            temp_dir_path, os.path.join(*member.split("/")[1:-1])
                        )
    
                        filename = os.path.basename(member)
                        # Skip directories
                        if not filename:
                            continue
    
                        # Create the target directory if necessary
                        if not os.path.exists(target_path):
                            os.makedirs(target_path)
    
                        source = zip_archive.open(member)
                        target = open(os.path.join(target_path, filename), "wb")
    
                        with source, target:
                            shutil.copyfileobj(source, target)
                            print("copying", source, "to", target)
    
                extracted_render_povray_path = os.path.join(temp_dir_path, "render_povray")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
                if not os.path.exists(extracted_render_povray_path):
    
                    self.report({"ERROR"}, "Could not extract ZIP archive! Aborting.")
                    return {"FINISHED"}
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
                # Find the old POV addon files
    
                render_povray_dir = os.path.abspath(os.path.dirname(__file__)) # Unnecessary abspath?
    
                print("POV addon addon folder:", render_povray_dir)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
                # TODO: Create backup
    
    
                # Delete old POV addon files
                # (only directories and *.py files, user might have other stuff in there!)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                # remove __init__.py
    
                os.remove(os.path.join(render_povray_dir, "__init__.py"))
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                # remove all folders
    
                dir_names = 1
                for directory in next(os.walk(render_povray_dir))[dir_names]:
    
                    shutil.rmtree(os.path.join(render_povray_dir, directory))
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                # copy new POV addon files
                # copy __init__.py
                shutil.copy2(
    
                    os.path.join(extracted_render_povray_path, "__init__.py"),
                    render_povray_dir,
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                # copy all folders
                recursive_overwrite(extracted_render_povray_path, render_povray_dir)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            bpy.ops.preferences.addon_refresh()
    
            print("POV addon update finished, restart Blender for the changes to take effect.")
            print("-" * 20)
    
            self.report({"WARNING"}, "Restart Blender!")
            return {"FINISHED"}
    
    # ---------------------------------------------------------------- #
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    # Povray Preferences.
    
    # ---------------------------------------------------------------- #
    
    class PovPreferences(bpy.types.AddonPreferences):
        """Declare preference variables to set up POV binary."""
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        bl_idname = __name__
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        branch_feature_set_povray: EnumProperty(
    
            name="Feature Set",
            description="Choose between official (POV-Ray) or (UberPOV) "
            "development branch features to write in the pov file",
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            items=(
    
                ("povray", "Official POV-Ray", "", "PLUGIN", 0),
                ("uberpov", "Unofficial UberPOV", "", "PLUGIN", 1),
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        filepath_povray: StringProperty(
    
            name="Binary Location", description="Path to renderer executable", subtype="FILE_PATH"
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        docpath_povray: StringProperty(
    
            name="Includes Location", description="Path to Insert Menu files", subtype="FILE_PATH",
            default="",
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        use_sounds: BoolProperty(
    
            name="Use Sound",
            description="Signaling end of the render process at various"
            "stages can help if you're away from monitor",
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            default=False,
        )
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        # TODO: Auto find POV sound directory as it does for binary
        # And implement the three cases, left uncommented for a dummy
        # interface in case some doc screenshots get made for that area
        filepath_complete_sound: StringProperty(
    
            name="Finish Render Sound",
            description="Path to finished render sound file",
            subtype="FILE_PATH",
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        filepath_parse_error_sound: StringProperty(
    
            name="Parse Error Sound",
            description="Path to parsing time error sound file",
            subtype="FILE_PATH",
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        filepath_cancel_sound: StringProperty(
    
            name="Cancel Render Sound",
            description="Path to cancelled or render time error sound file",
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        def draw(self, context):
            layout = self.layout
    
            layout.prop(self, 'branch_feature_set_povray')
            layout.prop(self, 'filepath_povray')
            layout.prop(self, 'docpath_povray')
            layout.prop(self, 'filepath_complete_sound')
            layout.prop(self, 'filepath_parse_error_sound')
            layout.prop(self, 'filepath_cancel_sound')
            layout.prop(self, 'use_sounds', icon='SOUND')
            layout.operator('pov.update_addon', icon='FILE_REFRESH')
            layout.operator("wm.url_open", text="Community",icon='EVENT_F').url = \
                "https://www.facebook.com/povable"
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
    classes = (
        POV_OT_update_addon,
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    def register():
        for cls in classes:
            register_class(cls)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        render_properties.register()
        scenography_properties.register()
        shading_properties.register()
    
        shading_ray_properties.register()
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        texturing_properties.register()
    
        model_properties.register()
        particles_properties.register()
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        scripting_properties.register()
    
        nodes_properties.register()
        nodes_gui.register()
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        render.register()
    
        render_core.register()
        ui_core.register()
        model_primitives_topology.register()
        model_primitives.register()
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    def unregister():
    
        model_primitives.unregister()
        model_primitives_topology.unregister()
        ui_core.unregister()
        render_core.unregister()
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        render.unregister()
    
        nodes_gui.unregister()
        nodes_properties.unregister()
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        scripting_properties.unregister()
    
        particles_properties.unregister()
        model_properties.unregister()
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        texturing_properties.unregister()
    
        shading_ray_properties.unregister()
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        shading_properties.unregister()
        scenography_properties.unregister()
        render_properties.unregister()
    
        for cls in reversed(classes):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            unregister_class(cls)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        register()
    
    # ------------8<---------[ BREAKPOINT ]--------------8<----------- #  Move this snippet around
    # __import__('code').interact(local=dict(globals(), **locals()))   # < and uncomment this line
    # ---------------------------------------------------------------- #  to inspect from Terminal