From fad5186bb6880aadbb0cd9d983035c7890801aa7 Mon Sep 17 00:00:00 2001
From: Maurice Raybaud <mauriceraybaud@hotmail.fr>
Date: Wed, 26 May 2021 01:34:50 +0200
Subject: [PATCH] Formatting and fixes

* Moved: some existing functions into new separate files to improve code
readability (detailed in __init__.py docstring)

* Remove: max_intersections deprecated in pov 3.8

* Add: Validate utf-8 characters with specific API function at session's
first script init

* Add : Icons to some text fields and inviting labels

* Change default camera normal perturbation value to non zero since its
use is first driven by a boolean toggle

* Change: lists (vectors and indices) are now exported in one line by
default for better manual scene overview and debugging

* Change: a couple of tooltips corrections

* Change : renamed many variables and functions to snake_case according
to recommanded style guides

* Fix : Heightfield primitive (forward slashes were expected for
displacement texture path)

* Fix : Text nippet insertion operator

* Fix : added console print tip to check executable path on failure to
process

* Fix : tweaked finished render say command for Linux

* Fix : interface of some shader nodes broken since 2.8 api changes

* Fix : export hair particles
---
 presets/pov/light/02_(5400K)_High_Noon_Sun.py |    4 +-
 .../pov/light/03_(6000K)_Daylight_Window.py   |    4 +-
 ...000K)_75W_Full_Spectrum_Fluorescent_T12.py |    4 +-
 .../10_(4300K)_40W_Vintage_Fluorescent_T12.py |    4 +-
 .../11_(5000K)_18W_Standard_Fluorescent_T8.py |    4 +-
 ...2_(4200K)_18W_Cool_White_Fluorescent_T8.py |    4 +-
 .../13_(3000K)_18W_Warm_Fluorescent_T8.py     |    4 +-
 ...6500K)_54W_Grow_Light_Fluorescent_T5-HO.py |    4 +-
 presets/pov/light/21_(2700K)_7W_OLED_Panel.py |    4 +-
 render_povray/__init__.py                     | 5831 +----------------
 render_povray/base_ui.py                      |  307 +
 render_povray/{df3.py => df3_library.py}      |  253 +-
 render_povray/nodes.py                        | 1369 ----
 render_povray/object_curve_topology.py        |  974 +++
 render_povray/object_gui.py                   |  731 +++
 render_povray/object_mesh_topology.py         | 1540 +++++
 render_povray/object_particles.py             |  255 +
 .../{primitives.py => object_primitives.py}   | 1010 +--
 render_povray/object_properties.py            |  670 ++
 render_povray/render.py                       | 5552 ++--------------
 render_povray/render_gui.py                   |  562 ++
 render_povray/render_properties.py            |  687 ++
 render_povray/scenography.py                  |  847 +++
 render_povray/scenography_gui.py              |  800 +++
 render_povray/scenography_properties.py       |  514 ++
 render_povray/scripting.py                    |  529 ++
 render_povray/scripting_gui.py                |  268 +
 render_povray/scripting_properties.py         |   57 +
 render_povray/shading.py                      | 2719 ++++----
 render_povray/shading_gui.py                  |  688 ++
 render_povray/shading_nodes.py                | 2011 ++++++
 render_povray/shading_properties.py           | 2290 +++++++
 render_povray/texturing.py                    |  902 +++
 render_povray/texturing_gui.py                | 1255 ++++
 render_povray/texturing_properties.py         | 1137 ++++
 render_povray/ui.py                           | 4719 -------------
 render_povray/update_files.py                 |  196 +-
 37 files changed, 19671 insertions(+), 19038 deletions(-)
 mode change 100644 => 100755 presets/pov/light/02_(5400K)_High_Noon_Sun.py
 mode change 100644 => 100755 presets/pov/light/03_(6000K)_Daylight_Window.py
 mode change 100644 => 100755 presets/pov/light/09_(5000K)_75W_Full_Spectrum_Fluorescent_T12.py
 mode change 100644 => 100755 presets/pov/light/10_(4300K)_40W_Vintage_Fluorescent_T12.py
 mode change 100644 => 100755 presets/pov/light/11_(5000K)_18W_Standard_Fluorescent_T8.py
 mode change 100644 => 100755 presets/pov/light/12_(4200K)_18W_Cool_White_Fluorescent_T8.py
 mode change 100644 => 100755 presets/pov/light/13_(3000K)_18W_Warm_Fluorescent_T8.py
 mode change 100644 => 100755 presets/pov/light/14_(6500K)_54W_Grow_Light_Fluorescent_T5-HO.py
 mode change 100644 => 100755 presets/pov/light/21_(2700K)_7W_OLED_Panel.py
 mode change 100644 => 100755 render_povray/__init__.py
 create mode 100755 render_povray/base_ui.py
 rename render_povray/{df3.py => df3_library.py} (57%)
 mode change 100644 => 100755
 delete mode 100644 render_povray/nodes.py
 create mode 100755 render_povray/object_curve_topology.py
 create mode 100755 render_povray/object_gui.py
 create mode 100755 render_povray/object_mesh_topology.py
 create mode 100755 render_povray/object_particles.py
 rename render_povray/{primitives.py => object_primitives.py} (58%)
 mode change 100644 => 100755
 create mode 100755 render_povray/object_properties.py
 mode change 100644 => 100755 render_povray/render.py
 create mode 100755 render_povray/render_gui.py
 create mode 100755 render_povray/render_properties.py
 create mode 100755 render_povray/scenography.py
 create mode 100755 render_povray/scenography_gui.py
 create mode 100755 render_povray/scenography_properties.py
 create mode 100755 render_povray/scripting.py
 create mode 100755 render_povray/scripting_gui.py
 create mode 100755 render_povray/scripting_properties.py
 mode change 100644 => 100755 render_povray/shading.py
 create mode 100755 render_povray/shading_gui.py
 create mode 100755 render_povray/shading_nodes.py
 create mode 100755 render_povray/shading_properties.py
 create mode 100755 render_povray/texturing.py
 create mode 100755 render_povray/texturing_gui.py
 create mode 100755 render_povray/texturing_properties.py
 delete mode 100644 render_povray/ui.py
 mode change 100644 => 100755 render_povray/update_files.py

diff --git a/presets/pov/light/02_(5400K)_High_Noon_Sun.py b/presets/pov/light/02_(5400K)_High_Noon_Sun.py
old mode 100644
new mode 100755
index 47499b526..7b5b9e2e8
--- a/presets/pov/light/02_(5400K)_High_Noon_Sun.py
+++ b/presets/pov/light/02_(5400K)_High_Noon_Sun.py
@@ -9,8 +9,8 @@ lampdata = bpy.context.object.data
 lampdata.shape = 'SQUARE'
 lampdata.size = 30000000#0.02
 #lampdata.size_y = 0.02
-lampdata.shadow_ray_samples_x = 2
-#lampdata.shadow_ray_samples_y = 3
+lampdata.pov.shadow_ray_samples_x = 2
+#lampdata.pov.shadow_ray_samples_y = 3
 lampdata.color = (1.0, 1.0, 1.0)
 lampdata.energy = 1.094316#91193 #lux
 lampdata.distance =695699968
diff --git a/presets/pov/light/03_(6000K)_Daylight_Window.py b/presets/pov/light/03_(6000K)_Daylight_Window.py
old mode 100644
new mode 100755
index a9781f579..eae7cd16c
--- a/presets/pov/light/03_(6000K)_Daylight_Window.py
+++ b/presets/pov/light/03_(6000K)_Daylight_Window.py
@@ -6,8 +6,8 @@ lampdata = bpy.context.object.data
 
 lampdata.size = 1.2
 lampdata.size_y = 2.10
-lampdata.shadow_ray_samples_x = 2
-lampdata.shadow_ray_samples_y = 3
+lampdata.pov.shadow_ray_samples_x = 2
+lampdata.pov.shadow_ray_samples_y = 3
 lampdata.color = (1.0, 1.0, 1.0)
 lampdata.energy = 1.094316#91193 #lux
 lampdata.distance = 1.0
diff --git a/presets/pov/light/09_(5000K)_75W_Full_Spectrum_Fluorescent_T12.py b/presets/pov/light/09_(5000K)_75W_Full_Spectrum_Fluorescent_T12.py
old mode 100644
new mode 100755
index 78fa29cbe..6d09b96f5
--- a/presets/pov/light/09_(5000K)_75W_Full_Spectrum_Fluorescent_T12.py
+++ b/presets/pov/light/09_(5000K)_75W_Full_Spectrum_Fluorescent_T12.py
@@ -6,8 +6,8 @@ lampdata = bpy.context.object.data
 
 lampdata.size = 0.038
 lampdata.size_y = 2.40284
-lampdata.shadow_ray_samples_x = 1
-lampdata.shadow_ray_samples_y = 2
+lampdata.pov.shadow_ray_samples_x = 1
+lampdata.pov.shadow_ray_samples_y = 2
 lampdata.color = (1.0, 0.95686274766922, 0.9490200281143188)
 lampdata.energy = 4.45304#4775lm/21.446(=lux)*0.004(distance) *2 for distance is the point of half strength 6200lm?
 lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/presets/pov/light/10_(4300K)_40W_Vintage_Fluorescent_T12.py b/presets/pov/light/10_(4300K)_40W_Vintage_Fluorescent_T12.py
old mode 100644
new mode 100755
index dc78bc5c5..5a5a7eb97
--- a/presets/pov/light/10_(4300K)_40W_Vintage_Fluorescent_T12.py
+++ b/presets/pov/light/10_(4300K)_40W_Vintage_Fluorescent_T12.py
@@ -6,8 +6,8 @@ lampdata = bpy.context.object.data
 
 lampdata.size = 0.038
 lampdata.size_y = 1.2192
-lampdata.shadow_ray_samples_x = 1
-lampdata.shadow_ray_samples_y = 2
+lampdata.pov.shadow_ray_samples_x = 1
+lampdata.pov.shadow_ray_samples_y = 2
 lampdata.color = (0.901, 1.0, 0.979)
 lampdata.energy = 2.14492#2300lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
 lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/presets/pov/light/11_(5000K)_18W_Standard_Fluorescent_T8.py b/presets/pov/light/11_(5000K)_18W_Standard_Fluorescent_T8.py
old mode 100644
new mode 100755
index a70cda3fa..5f7ce0a6b
--- a/presets/pov/light/11_(5000K)_18W_Standard_Fluorescent_T8.py
+++ b/presets/pov/light/11_(5000K)_18W_Standard_Fluorescent_T8.py
@@ -6,8 +6,8 @@ lampdata = bpy.context.object.data
 
 lampdata.size = 0.026
 lampdata.size_y = 0.59
-lampdata.shadow_ray_samples_x = 1
-lampdata.shadow_ray_samples_y = 2
+lampdata.pov.shadow_ray_samples_x = 1
+lampdata.pov.shadow_ray_samples_y = 2
 lampdata.color = (0.95686274766922, 1.0, 0.9803921580314636)
 lampdata.energy = 1.25898#1350lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
 lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/presets/pov/light/12_(4200K)_18W_Cool_White_Fluorescent_T8.py b/presets/pov/light/12_(4200K)_18W_Cool_White_Fluorescent_T8.py
old mode 100644
new mode 100755
index c2a0d65d3..0bbf19656
--- a/presets/pov/light/12_(4200K)_18W_Cool_White_Fluorescent_T8.py
+++ b/presets/pov/light/12_(4200K)_18W_Cool_White_Fluorescent_T8.py
@@ -7,8 +7,8 @@ lampdata = bpy.context.object.data
 
 lampdata.size = 0.026
 lampdata.size_y = 0.59
-lampdata.shadow_ray_samples_x = 1
-lampdata.shadow_ray_samples_y = 2
+lampdata.pov.shadow_ray_samples_x = 1
+lampdata.pov.shadow_ray_samples_y = 2
 lampdata.color = (0.8313725590705872, 0.9215686321258545, 1.0)
 lampdata.energy = 1.25898#1350lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
 lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/presets/pov/light/13_(3000K)_18W_Warm_Fluorescent_T8.py b/presets/pov/light/13_(3000K)_18W_Warm_Fluorescent_T8.py
old mode 100644
new mode 100755
index e1cee557d..187b26d36
--- a/presets/pov/light/13_(3000K)_18W_Warm_Fluorescent_T8.py
+++ b/presets/pov/light/13_(3000K)_18W_Warm_Fluorescent_T8.py
@@ -7,8 +7,8 @@ lampdata = bpy.context.object.data
 
 lampdata.size = 0.026
 lampdata.size_y = 0.59
-lampdata.shadow_ray_samples_x = 1
-lampdata.shadow_ray_samples_y = 2
+lampdata.pov.shadow_ray_samples_x = 1
+lampdata.pov.shadow_ray_samples_y = 2
 lampdata.color = (1.0, 0.95686274766922, 0.8980392217636108)
 lampdata.energy = 1.25898#1350lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
 lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/presets/pov/light/14_(6500K)_54W_Grow_Light_Fluorescent_T5-HO.py b/presets/pov/light/14_(6500K)_54W_Grow_Light_Fluorescent_T5-HO.py
old mode 100644
new mode 100755
index 55f84ab81..c0b992ca8
--- a/presets/pov/light/14_(6500K)_54W_Grow_Light_Fluorescent_T5-HO.py
+++ b/presets/pov/light/14_(6500K)_54W_Grow_Light_Fluorescent_T5-HO.py
@@ -6,8 +6,8 @@ lampdata = bpy.context.object.data
 
 lampdata.size = 0.016
 lampdata.size_y = 1.149
-lampdata.shadow_ray_samples_x = 1
-lampdata.shadow_ray_samples_y = 2
+lampdata.pov.shadow_ray_samples_x = 1
+lampdata.pov.shadow_ray_samples_y = 2
 lampdata.color = (1.0, 0.83, 0.986274528503418)
 lampdata.energy = 4.66287 #0.93257#4.66287#5000lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
 lampdata.distance = 0.1 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/presets/pov/light/21_(2700K)_7W_OLED_Panel.py b/presets/pov/light/21_(2700K)_7W_OLED_Panel.py
old mode 100644
new mode 100755
index 8f2ebb8fe..8a6ba8d93
--- a/presets/pov/light/21_(2700K)_7W_OLED_Panel.py
+++ b/presets/pov/light/21_(2700K)_7W_OLED_Panel.py
@@ -7,8 +7,8 @@ lampdata = bpy.context.object.data
 
 lampdata.size = 0.033
 lampdata.size_y = 0.133
-lampdata.shadow_ray_samples_x = 2
-lampdata.shadow_ray_samples_y = 2
+lampdata.pov.shadow_ray_samples_x = 2
+lampdata.pov.shadow_ray_samples_y = 2
 lampdata.color = (1.0, 0.8292156958580017, 0.6966666865348816)
 lampdata.energy = 0.83932#900lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
 lampdata.distance = 1.18 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/render_povray/__init__.py b/render_povray/__init__.py
old mode 100644
new mode 100755
index da7296a9a..58f6040d8
--- a/render_povray/__init__.py
+++ b/render_povray/__init__.py
@@ -24,29 +24,83 @@ These engines can be POV-Ray or Uberpov but others too, since POV is a
 Scene Description Language. The script has been split in as few files
 as possible :
 
-___init__.py :
+__init__.py :
     Initialize properties
 
-update_files.py
-    Update new variables to values from older API. This file needs an update
-
-ui.py :
+base_ui.py :
     Provide property buttons for the user to set up the variables
 
-primitives.py :
+scenography_properties.py
+    Initialize properties for translating Blender cam/light/environment parameters to pov
+
+scenography_gui.py
+    Display cam/light/environment properties from situation_properties.py for user to change them
+
+scenography.py
+    Translate  cam/light/environment properties to corresponding pov features
+
+object_properties.py :
+    nitialize properties for translating Blender objects parameters to pov
+
+object_primitives.py :
     Display some POV native primitives in 3D view for input and output
 
+object_mesh_topology.py :
+    Translate to POV the meshes geometries
+
+object_curve_topology.py :
+    Translate to POV the curve based geometries
+
+object_particles.py :
+    Translate to POV the particle based geometries
+
+object_gui.py :
+    Display properties from object_properties.py for user to change them
+
+shading_properties.py
+    Initialize properties for translating Blender materials parameters to pov
+
+shading_nodes.py
+    Translate node trees to the pov file
+
+shading_gui.py
+    Display properties from shading_properties.py for user to change them
+
 shading.py
     Translate shading properties to declared textures at the top of a pov file
 
-nodes.py
-    Translate node trees to the pov file
+texturing_properties.py
+    Initialize properties for translating Blender materials /world... texture influences to pov
 
-df3.py
-    Render smoke to *.df3 files
+texturing_gui.py
+    Display properties from texturing_properties.py for user to change them
+
+texturing.py
+    Translate blender texture influences into POV
+
+render_properties.py :
+    Initialize properties for render parameters (Blender and POV native)
+
+render_gui.py :
+    Display properties from render_properties.py for user to change them
 
 render.py :
-    Translate geometry and UI properties (Blender and POV native) to the POV file
+    Translate render properties (Blender and POV native) to POV, ini file and bash
+
+scripting_properties.py :
+    Initialize properties for scene description language parameters (POV native)
+
+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 to exported POV file
+
+df3_library.py
+    Render smoke to *.df3 files
+
+update_files.py
+    Update new variables to values from older API. This file needs an update
 
 
 Along these essential files also coexist a few additional libraries to help make
@@ -99,5587 +153,290 @@ Blender stand up to other POV IDEs such as povwin or QTPOV
 bl_info = {
     "name": "Persistence of Vision",
     "author": "Campbell Barton, "
-    "Maurice Raybaud, "
-    "Leonid Desyatkov, "
-    "Bastien Montagne, "
-    "Constantin Rahn, "
-    "Silvio Falcinelli",
-    "version": (0, 1, 1),
+              "Maurice Raybaud, "
+              "Leonid Desyatkov, "
+              "Bastien Montagne, "
+              "Constantin Rahn, "
+              "Silvio Falcinelli,"
+              "Paco GarcĂ­a",
+              "version": (0, 1, 2),
     "blender": (2, 81, 0),
     "location": "Render Properties > Render Engine > Persistence of Vision",
     "description": "Persistence of Vision integration for blender",
     "doc_url": "{BLENDER_MANUAL_URL}/addons/render/povray.html",
     "category": "Render",
-    "warning": "Under active development, seeking co-maintainer(s)",
+    "warning": "Co-maintainers welcome",
 }
 
+# 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():
     import importlib
 
-    importlib.reload(ui)
-    importlib.reload(nodes)
+    importlib.reload(base_ui)
+    importlib.reload(shading_nodes)
+    importlib.reload(scenography_properties)
+    importlib.reload(scenography)
+    importlib.reload(render_properties)
+    importlib.reload(render_gui)
     importlib.reload(render)
+    importlib.reload(shading_properties)
+    importlib.reload(shading_gui)
     importlib.reload(shading)
-    importlib.reload(primitives)
+    importlib.reload(texturing_properties)
+    importlib.reload(texturing_gui)
+    importlib.reload(texturing)
+    importlib.reload(object_properties)
+    importlib.reload(object_gui)
+    importlib.reload(object_mesh_topology)
+    importlib.reload(object_curve_topology)
+    importlib.reload(object_primitives)
+    importlib.reload(scripting_gui)
     importlib.reload(update_files)
 
 else:
     import bpy
     from bpy.utils import register_class, unregister_class
-    # import addon_utils  # To use some other addons
-    import nodeitems_utils  # for Nodes
-    from nodeitems_utils import NodeCategory, NodeItem  # for Nodes
-    from bl_operators.presets import AddPresetBase
-    from bpy.types import (
-        AddonPreferences,
-        PropertyGroup,
-        NodeSocket,
-    )
-
-    from bpy.props import (
-        FloatVectorProperty,
-        StringProperty,
-        BoolProperty,
-        IntProperty,
-        FloatProperty,
-        EnumProperty,
-        PointerProperty,
-        CollectionProperty,
-    )
-    from . import ui, render, update_files
-
-
-def string_strip_hyphen(name):
-
-    """Remove hyphen characters from a string to avoid POV errors"""
-
-    return name.replace("-", "")
-
-def pov_context_tex_datablock(context):
-    """Texture context type recreated as deprecated in blender 2.8"""
-
-    idblock = context.brush
-    if idblock and context.scene.texture_context == 'OTHER':
-        return idblock
-
-    # idblock = bpy.context.active_object.active_material
-    idblock = context.view_layer.objects.active.active_material
-    if idblock and context.scene.texture_context == 'MATERIAL':
-        return idblock
-
-    idblock = context.world
-    if idblock and context.scene.texture_context == 'WORLD':
-        return idblock
-
-    idblock = context.light
-    if idblock and context.scene.texture_context == 'LIGHT':
-        return idblock
-
-    if context.particle_system and context.scene.texture_context == 'PARTICLES':
-        idblock = context.particle_system.settings
-
-    return idblock
-
-    idblock = context.line_style
-    if idblock and context.scene.texture_context == 'LINESTYLE':
-        return idblock
-
-def brush_texture_update(self, context):
-
-    """Brush texture rolldown must show active slot texture props"""
-    idblock = pov_context_tex_datablock(context)
-    if idblock is not None:
-        #mat = context.view_layer.objects.active.active_material
-        idblock = pov_context_tex_datablock(context)
-        slot = idblock.pov_texture_slots[idblock.pov.active_texture_index]
-        tex = slot.texture
-
-        if tex:
-            # Switch paint brush to active texture so slot and settings remain contextual
-            bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[tex]
-            bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[tex]
-
-def active_texture_name_from_uilist(self, context):
-
-    idblock = pov_context_tex_datablock(context)
-    #mat = context.view_layer.objects.active.active_material
-    if idblock is not None:
-        index = idblock.pov.active_texture_index
-        name = idblock.pov_texture_slots[index].name
-        newname = idblock.pov_texture_slots[index].texture
-        tex = bpy.data.textures[name]
-        tex.name = newname
-        idblock.pov_texture_slots[index].name = newname
-
-
-def active_texture_name_from_search(self, context):
-    """Texture rolldown to change the data linked by an existing texture"""
-    idblock = pov_context_tex_datablock(context)
-    #mat = context.view_layer.objects.active.active_material
-    if idblock is not None:
-        index = idblock.pov.active_texture_index
-        slot = idblock.pov_texture_slots[index]
-        name = slot.texture_search
-
-    try:
-        tex = bpy.data.textures[name]
-        slot.name = name
-        slot.texture = name
-        # Switch paint brush to this texture so settings remain contextual
-        #bpy.context.tool_settings.image_paint.brush.texture = tex
-        #bpy.context.tool_settings.image_paint.brush.mask_texture = tex
-    except:
-        pass
 
+    from bpy.props import StringProperty, BoolProperty, EnumProperty
 
+    from . import (
+        base_ui,
+        render_properties,
+        scenography_properties,
+        shading_properties,
+        texturing_properties,
+        object_properties,
+        scripting_properties,
+        render,
+        object_primitives,  # for import and export of POV specific primitives
+        update_files,
+    )
 
 ###############################################################################
-# Scene POV properties.
+# Auto update.
 ###############################################################################
-class RenderPovSettingsScene(PropertyGroup):
-
-    """Declare scene level properties controllable in UI and translated to POV"""
-
-    # Linux SDL-window enable
-    sdl_window_enable: BoolProperty(
-        name="Enable SDL window",
-        description="Enable the SDL window in Linux OS",
-        default=True,
-    )
-    # File Options
-    text_block: StringProperty(
-        name="Text Scene Name",
-        description="Name of POV scene to use. "
-        "Set when clicking Run to render current text only",
-        maxlen=1024,
-    )
-    tempfiles_enable: BoolProperty(
-        name="Enable Tempfiles",
-        description="Enable the OS-Tempfiles. Otherwise set the path where"
-        " to save the files",
-        default=True,
-    )
-    pov_editor: BoolProperty(
-        name="POV editor",
-        description="Don't Close POV editor after rendering (Overridden"
-        " by /EXIT command)",
-        default=False,
-    )
-    deletefiles_enable: BoolProperty(
-        name="Delete files",
-        description="Delete files after rendering. "
-        "Doesn't work with the image",
-        default=True,
-    )
-    scene_name: StringProperty(
-        name="Scene Name",
-        description="Name of POV scene to create. Empty name will use "
-        "the name of the blend file",
-        maxlen=1024,
-    )
-    scene_path: StringProperty(
-        name="Export scene path",
-        # Bug in POV-Ray RC3
-        # description="Path to directory where the exported scene "
-        # "(POV and INI) is created",
-        description="Path to directory where the files are created",
-        maxlen=1024,
-        subtype="DIR_PATH",
-    )
-    renderimage_path: StringProperty(
-        name="Rendered image path",
-        description="Full path to directory where the rendered image is "
-        "saved",
-        maxlen=1024,
-        subtype="DIR_PATH",
-    )
-    list_lf_enable: BoolProperty(
-        name="LF in lists",
-        description="Enable line breaks in lists (vectors and indices). "
-        "Disabled: lists are exported in one line",
-        default=True,
-    )
-
-    # Not a real pov option, just to know if we should write
-    radio_enable: BoolProperty(
-        name="Enable Radiosity",
-        description="Enable POV radiosity calculation",
-        default=True,
-    )
-
-    radio_display_advanced: BoolProperty(
-        name="Advanced Options",
-        description="Show advanced options",
-        default=False,
-    )
-
-    media_enable: BoolProperty(
-        name="Enable Media",
-        description="Enable POV atmospheric media",
-        default=False,
-    )
-
-    media_samples: IntProperty(
-        name="Samples",
-        description="Number of samples taken from camera to first object "
-        "encountered along ray path for media calculation",
-        min=1,
-        max=100,
-        default=35,
-    )
-
-    media_scattering_type: EnumProperty(
-        name="Scattering Type",
-        description="Scattering model",
-        items=(
-            (
-                '1',
-                "1 Isotropic",
-                "The simplest form of scattering because"
-                " it is independent of direction."
-            ),
-            (
-                '2',
-                "2 Mie haze ",
-                "For relatively small particles such as "
-                "minuscule water droplets of fog, cloud "
-                "particles, and particles responsible "
-                "for the polluted sky. In this model the"
-                " scattering is extremely directional in"
-                " the forward direction i.e. the amount "
-                "of scattered light is largest when the "
-                "incident light is anti-parallel to the "
-                "viewing direction (the light goes "
-                "directly to the viewer). It is smallest"
-                " when the incident light is parallel to"
-                " the viewing direction. "
-            ),
-            (
-                '3',
-                "3 Mie murky",
-                "Like haze but much more directional"
-            ),
-            (
-                '4',
-                "4 Rayleigh",
-                "For extremely small particles such as "
-                "molecules of the air. The amount of "
-                "scattered light depends on the incident"
-                " light angle. It is largest when the "
-                "incident light is parallel or "
-                "anti-parallel to the viewing direction "
-                "and smallest when the incident light is "
-                "perpendicular to viewing direction."
-            ),
-            (
-                '5',
-                "5 Henyey-Greenstein",
-                "The default eccentricity value "
-                "of zero defines isotropic "
-                "scattering while positive "
-                "values lead to scattering in "
-                "the direction of the light and "
-                "negative values lead to "
-                "scattering in the opposite "
-                "direction of the light. Larger "
-                "values of e (or smaller values "
-                "in the negative case) increase "
-                "the directional property of the"
-                " scattering."
+class POV_OT_update_addon(bpy.types.Operator):
+    """Update this addon to the latest version."""
+
+    bl_idname = "pov.update_addon"
+    bl_label = "Update POV addon"
+
+    def execute(self, context):
+        import os, tempfile, shutil, urllib.request, urllib.error, zipfile
+
+        def recursive_overwrite(src, dest, ignore=None):
+            if os.path.isdir(src):
+                if not os.path.isdir(dest):
+                    os.makedirs(dest)
+                files = os.listdir(src)
+                if ignore is not None:
+                    ignored = ignore(src, files)
+                else:
+                    ignored = set()
+                for f in files:
+                    if f not in ignored:
+                        recursive_overwrite(os.path.join(src, f), os.path.join(dest, f), ignore)
+            else:
+                shutil.copyfile(src, dest)
+
+        print('-' * 20)
+        print('Updating POV addon...')
+
+        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 (So we also get presets)
+            # 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'
+            try:
+                print('Downloading', url)
+
+                with urllib.request.urlopen(url, timeout=60) as url_handle, open(
+                    temp_zip_path, 'wb'
+                ) as file_handle:
+                    file_handle.write(url_handle.read())
+            except urllib.error.URLError as err:
+                self.report({'ERROR'}, 'Could not download: %s' % err)
+
+            # Extract the zip
+            print('Extracting ZIP archive')
+            with zipfile.ZipFile(temp_zip_path) as zip:
+                for member in zip.namelist():
+                    if 'blender-addons-master/render_povray' in member:
+                        # Remove the first directory and the filename
+                        # e.g. blender-addons-master/render_povray/shading_nodes.py
+                        # becomes render_povray/shading_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 len(filename) == 0:
+                            continue
+
+                        # Create the target directory if necessary
+                        if not os.path.exists(target_path):
+                            os.makedirs(target_path)
+
+                        source = zip.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')
+
+            if not os.path.exists(extracted_render_povray_path):
+                self.report({'ERROR'}, 'Could not extract ZIP archive! Aborting.')
+                return {'FINISHED'}
+
+            # Find the old POV addon files
+            render_povray_dir = os.path.abspath(os.path.dirname(__file__))
+            print('POV addon addon folder:', render_povray_dir)
+
+            # TODO: Create backup
+
+            # Delete old POV addon files (only directories and *.py files, the user might have other stuff in there!)
+            print('Deleting old POV addon files')
+            # remove __init__.py
+            os.remove(os.path.join(render_povray_dir, '__init__.py'))
+            # remove all folders
+            DIRNAMES = 1
+            for dir in next(os.walk(render_povray_dir))[DIRNAMES]:
+                shutil.rmtree(os.path.join(render_povray_dir, dir))
+
+            print('Copying new POV addon files')
+            # copy new POV addon files
+            # copy __init__.py
+            shutil.copy2(
+                os.path.join(extracted_render_povray_path, '__init__.py'), render_povray_dir
             )
-        ),
-        default='1',
-    )
-
-    media_diffusion_scale: FloatProperty(
-        name="Scale",
-        description="Scale factor of Media Diffusion Color",
-        precision=6, step=0.00000001, min=0.000000001, max=1.0,
-        default=(1.0),
-    )
-
-    media_diffusion_color: FloatVectorProperty(
-        name="Media Diffusion Color",
-        description="The atmospheric media color",
-        precision=4, step=0.01, min=0, soft_max=1,
-        default=(0.001, 0.001, 0.001),
-        options={'ANIMATABLE'},
-        subtype='COLOR',
-    )
-
-    media_absorption_scale: FloatProperty(
-        name="Scale",
-        description="Scale factor of Media Absorption Color. "
-        "use 1/depth of media volume in meters",
-        precision=6,
-        step=0.000001,
-        min=0.000000001,
-        max=1.0,
-        default=(0.00002),
-    )
-
-    media_absorption_color: FloatVectorProperty(
-        name="Media Absorption Color",
-        description="The atmospheric media absorption color",
-        precision=4, step=0.01, min=0, soft_max=1,
-        default=(0.0, 0.0, 0.0),
-        options={'ANIMATABLE'},
-        subtype='COLOR',
-    )
-
-    media_eccentricity: FloatProperty(
-        name="Media Eccenticity Factor",
-        description="Positive values lead"
-        " to scattering in the direction of the light and negative "
-        "values lead to scattering in the opposite direction of the "
-        "light. Larger values of e (or smaller values in the negative"
-        " case) increase the directional property of the scattering",
-        precision=2,
-        step=0.01,
-        min=-1.0,
-        max=1.0,
-        default=(0.0),
-        options={'ANIMATABLE'},
-    )
-
-    baking_enable: BoolProperty(
-        name="Enable Baking",
-        description="Enable POV texture baking",
-        default=False
-    )
-
-    indentation_character: EnumProperty(
-        name="Indentation",
-        description="Select the indentation type",
-        items=(
-            ('NONE', "None", "No indentation"),
-            ('TAB', "Tabs", "Indentation with tabs"),
-            ('SPACE', "Spaces", "Indentation with spaces")
-        ),
-        default='SPACE'
-    )
-
-    indentation_spaces: IntProperty(
-        name="Quantity of spaces",
-        description="The number of spaces for indentation",
-        min=1,
-        max=10,
-        default=4,
-    )
-
-    comments_enable: BoolProperty(
-        name="Enable Comments",
-        description="Add comments to pov file",
-        default=True,
-    )
-
-    # Real pov options
-    command_line_switches: StringProperty(
-        name="Command Line Switches",
-        description="Command line switches consist of a + (plus) or - "
-        "(minus) sign, followed by one or more alphabetic "
-        "characters and possibly a numeric value",
-        maxlen=500,
-    )
-
-    antialias_enable: BoolProperty(
-        name="Anti-Alias", description="Enable Anti-Aliasing",
-        default=True,
-    )
-
-    antialias_method: EnumProperty(
-        name="Method",
-        description="AA-sampling method. Type 1 is an adaptive, "
-        "non-recursive, super-sampling method. Type 2 is an "
-        "adaptive and recursive super-sampling method. Type 3 "
-        "is a stochastic halton based super-sampling method",
-        items=(
-            ("0", "non-recursive AA", "Type 1 Sampling in POV"),
-            ("1", "recursive AA", "Type 2 Sampling in POV"),
-            ("2", "stochastic AA", "Type 3 Sampling in POV")
-        ),
-        default="1",
-    )
-
-    antialias_confidence: FloatProperty(
-        name="Antialias Confidence",
-        description="how surely the computed color "
-        "of a given pixel is indeed"
-        "within the threshold error margin",
-        min=0.0001,
-        max=1.0000,
-        default=0.9900,
-        precision=4
-    )
-
-    antialias_depth: IntProperty(
-        name="Antialias Depth",
-        description="Depth of pixel for sampling",
-        min=1,
-        max=9,
-        default=3
-    )
-
-    antialias_threshold: FloatProperty(
-        name="Antialias Threshold",
-        description="Tolerance for sub-pixels",
-        min=0.0,
-        max=1.0,
-        soft_min=0.05,
-        soft_max=0.5,
-        default=0.03,
-    )
-
-    jitter_enable: BoolProperty(
-        name="Jitter",
-        description="Enable Jittering. Adds noise into the sampling "
-        "process (it should be avoided to use jitter in "
-        "animation)",
-        default=False,
-    )
-
-    jitter_amount: FloatProperty(
-        name="Jitter Amount",
-        description="Amount of jittering",
-        min=0.0,
-        max=1.0,
-        soft_min=0.01,
-        soft_max=1.0,
-        default=1.0,
-    )
-
-    antialias_gamma: FloatProperty(
-        name="Antialias Gamma",
-        description="POV-Ray compares gamma-adjusted values for super "
-        "sampling. Antialias Gamma sets the Gamma before "
-        "comparison",
-        min=0.0,
-        max=5.0,
-        soft_min=0.01,
-        soft_max=2.5,
-        default=2.5,
-    )
-
-    alpha_mode: EnumProperty(
-        name="Alpha",
-        description="Representation of alpha information in the RGBA pixels",
-        items=(
-            ("SKY", "Sky", "Transparent pixels are filled with sky color"),
-            (
-            "TRANSPARENT",
-            "Transparent",
-            "Transparent, World background is transparent with premultiplied alpha",
-            ),
-        ),
-        default="SKY",
-    )
-
-    use_shadows: BoolProperty(
-        name="Shadows",
-        description="Calculate shadows while rendering",
-        default=True,
-    )
-
-    max_trace_level: IntProperty(
-        name="Max Trace Level",
-        description="Number of reflections/refractions allowed on ray "
-        "path",
-        min=1,
-        max=256,
-        default=5
-    )
-
-    adc_bailout_enable: BoolProperty(
-        name="Enable",
-        description="",
-        default=False,
-    )
-
-    adc_bailout: FloatProperty(
-        name="ADC Bailout",
-        description="Adaptive Depth Control (ADC) to stop computing additional"
-            "reflected or refracted rays when their contribution is insignificant."
-            "The default value is 1/255, or approximately 0.0039, since a change "
-            "smaller than that could not be visible in a 24 bit image. Generally "
-            "this value is fine and should be left alone."
-            "Setting adc_bailout to 0 will disable ADC, relying completely on "
-            "max_trace_level to set an upper limit on the number of rays spawned. ",
-        min=0.0,
-        max=1000.0,
-        default=0.00392156862745,
-        precision=3
-    )
-
-    ambient_light_enable: BoolProperty(
-        name="Enable",
-        description="",
-        default=False,
-    )
-
-    ambient_light: FloatVectorProperty(
-        name="Ambient Light",
-        description="Ambient light is used to simulate the effect of inter-diffuse reflection",
-        precision=4, step=0.01, min=0, soft_max=1,
-        default=(1, 1, 1), options={'ANIMATABLE'}, subtype='COLOR',
-    )
-    global_settings_advanced: BoolProperty(
-        name="Advanced",
-        description="",
-        default=False,
-    )
-
-    irid_wavelength_enable: BoolProperty(
-        name="Enable",
-        description="",
-        default=False,
-    )
-
-    irid_wavelength: FloatVectorProperty(
-        name="Irid Wavelength",
-        description=(
-            "Iridescence calculations depend upon the dominant "
-            "wavelengths of the primary colors of red, green and blue light"
-        ),
-        precision=4,
-        step=0.01,
-        min=0,
-        soft_max=1,
-        default=(0.25,0.18,0.14),
-        options={'ANIMATABLE'},
-        subtype='COLOR'
-    )
-    # Deprecated (autodetected in pov3.8):
-    # charset: EnumProperty(
-        # name="Charset",
-        # description="This allows you to specify the assumed character set of all text strings",
-        # items=(
-            # ("ascii", "ASCII", ""),
-            # ("utf8", "UTF-8", ""),
-            # ("sys", "SYS", "")
-        # ),
-        # default="utf8",
-    # )
-
-    max_intersections_enable: BoolProperty(
-        name="Enable",
-        description="",
-        default=False,
-    )
-
-    max_intersections: IntProperty(
-        name="Max Intersections",
-        description="POV-Ray uses a set of internal stacks to collect ray/object intersection points",
-        min=2,
-        max=1024,
-        default=64,
-    )
-
-    number_of_waves_enable: BoolProperty(
-        name="Enable",
-        description="",
-        default=False,
-    )
-
-    number_of_waves: IntProperty(
-        name="Number Waves",
-        description=(
-            "The waves and ripples patterns are generated by summing a series of waves, "
-            "each with a slightly different center and size"
-        ),
-        min=1,
-        max=10,
-        default=1000,
-    )
-
-    noise_generator_enable: BoolProperty(
-        name="Enable",
-        description="",
-        default=False,
-    )
-
-    noise_generator: IntProperty(
-        name="Noise Generator",
-        description="There are three noise generators implemented",
-        min=1,
-        max=3,
-        default=2,
-    )
-
-    ########################### PHOTONS #######################################
-    photon_enable: BoolProperty(
-        name="Photons",
-        description="Enable global photons",
-        default=False,
-    )
-
-    photon_enable_count: BoolProperty(
-        name="Spacing / Count",
-        description="Enable count photons",
-        default=False,
-    )
+            # copy all folders
+            recursive_overwrite(extracted_render_povray_path, render_povray_dir)
 
-    photon_count: IntProperty(
-        name="Count",
-        description="Photons count",
-        min=1,
-        max=100000000,
-        default=20000
-    )
+        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'}
 
-    photon_spacing: FloatProperty(
-        name="Spacing",
-        description="Average distance between photons on surfaces. half "
-        "this get four times as many surface photons",
-        min=0.001,
-        max=1.000,
-        soft_min=0.001,
-        soft_max=1.000,
-        precision=3,
-        default=0.005,
-    )
 
-    photon_max_trace_level: IntProperty(
-        name="Max Trace Level",
-        description="Number of reflections/refractions allowed on ray "
-        "path",
-        min=1,
-        max=256,
-        default=5
-    )
+###############################################################################
+# Povray Preferences.
+###############################################################################
 
-    photon_adc_bailout: FloatProperty(
-        name="ADC Bailout",
-        description="The adc_bailout for photons. Use adc_bailout = "
-        "0.01 / brightest_ambient_object for good results",
-        min=0.0,
-        max=1000.0,
-        soft_min=0.0,
-        soft_max=1.0,
-        precision=3,
-        default=0.1,
-    )
 
-    photon_gather_min: IntProperty(
-        name="Gather Min", description="Minimum number of photons gathered"
-        "for each point",
-        min=1, max=256, default=20
-    )
+class PovrayPreferences(bpy.types.AddonPreferences):
+    """Declare preference variables to set up POV binary."""
 
-    photon_gather_max: IntProperty(
-        name="Gather Max", description="Maximum number of photons gathered for each point",
-        min=1, max=256, default=100
-    )
+    bl_idname = __name__
 
-    photon_map_file_save_load: EnumProperty(
-        name="Operation",
-        description="Load or Save photon map file",
+    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",
         items=(
-            ("NONE", "None", ""),
-            ("save", "Save", ""),
-            ("load", "Load", "")
+            ("povray", "Official POV-Ray", "", "PLUGIN", 0),
+            ("uberpov", "Unofficial UberPOV", "", "PLUGIN", 1),
         ),
-        default="NONE",
-    )
-
-    photon_map_filename: StringProperty(
-        name="Filename",
-        description="",
-        maxlen=1024
-    )
-
-    photon_map_dir: StringProperty(
-        name="Directory",
-        description="",
-        maxlen=1024,
-        subtype="DIR_PATH",
-    )
-
-    photon_map_file: StringProperty(
-        name="File",
-        description="",
-        maxlen=1024,
-        subtype="FILE_PATH"
-    )
-
-    #########RADIOSITY########
-    radio_adc_bailout: FloatProperty(
-        name="ADC Bailout",
-        description="The adc_bailout for radiosity rays. Use "
-        "adc_bailout = 0.01 / brightest_ambient_object for good results",
-        min=0.0,
-        max=1000.0,
-        soft_min=0.0,
-        soft_max=1.0,
-        default=0.0039,
-        precision=4,
+        default="povray",
     )
 
-    radio_always_sample: BoolProperty(
-        name="Always Sample",
-        description="Only use the data from the pretrace step and not gather "
-        "any new samples during the final radiosity pass",
-        default=False,
-    )
-
-    radio_brightness: FloatProperty(
-        name="Brightness",
-        description="Amount objects are brightened before being returned "
-        "upwards to the rest of the system",
-        min=0.0, max=1000.0, soft_min=0.0, soft_max=10.0, default=1.0
-    )
-
-    radio_count: IntProperty(
-        name="Ray Count",
-        description="Number of rays for each new radiosity value to be calculated "
-        "(halton sequence over 1600)",
-        min=1, max=10000, soft_max=1600, default=35
-    )
-
-    radio_error_bound: FloatProperty(
-        name="Error Bound",
-        description="One of the two main speed/quality tuning values, "
-        "lower values are more accurate",
-        min=0.0, max=1000.0, soft_min=0.1, soft_max=10.0, default=10.0
-    )
-
-    radio_gray_threshold: FloatProperty(
-        name="Gray Threshold",
-        description="One of the two main speed/quality tuning values, "
-        "lower values are more accurate",
-        min=0.0, max=1.0, soft_min=0, soft_max=1, default=0.0
-    )
-
-    radio_low_error_factor: FloatProperty(
-        name="Low Error Factor",
-        description="Just enough samples is slightly blotchy. Low error changes error "
-        "tolerance for less critical last refining pass",
-        min=0.000001, max=1.0, soft_min=0.000001, soft_max=1.0, default=0.5
+    filepath_povray: StringProperty(
+        name="Binary Location", description="Path to renderer executable", subtype="FILE_PATH"
     )
 
-    radio_media: BoolProperty(
-        name="Media",
-        description="Radiosity estimation can be affected by media",
-        default=True,
+    docpath_povray: StringProperty(
+        name="Includes Location", description="Path to Insert Menu files", subtype="FILE_PATH"
     )
 
-    radio_subsurface: BoolProperty(
-        name="Subsurface",
-        description="Radiosity estimation can be affected by Subsurface Light Transport",
+    use_sounds: BoolProperty(
+        name="Use Sound",
+        description="Signaling end of the render process at various"
+        "stages can help if you're away from monitor",
         default=False,
     )
 
-    radio_minimum_reuse: FloatProperty(
-        name="Minimum Reuse",
-        description="Fraction of the screen width which sets the minimum radius of reuse "
-        "for each sample point (At values higher than 2% expect errors)",
-        min=0.0, max=1.0, soft_min=0.1, soft_max=0.1, default=0.015, precision=3
+    # 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",
     )
 
-    radio_maximum_reuse: FloatProperty(
-        name="Maximum Reuse",
-        description="The maximum reuse parameter works in conjunction with, and is similar to that of minimum reuse, "
-        "the only difference being that it is an upper bound rather than a lower one",
-        min=0.0, max=1.0,default=0.2, precision=3
+    filepath_parse_error_sound: StringProperty(
+        name="Parse Error Sound",
+        description="Path to parsing time error sound file",
+        subtype="FILE_PATH",
     )
 
-    radio_nearest_count: IntProperty(
-        name="Nearest Count",
-        description="Number of old ambient values blended together to "
-        "create a new interpolated value",
-        min=1, max=20, default=1
+    filepath_cancel_sound: StringProperty(
+        name="Cancel Render Sound",
+        description="Path to cancelled or render time error sound file",
+        subtype="FILE_PATH",
     )
 
-    radio_normal: BoolProperty(
-        name="Normals",
-        description="Radiosity estimation can be affected by normals",
-        default=False,
-    )
+    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')
 
-    radio_recursion_limit: IntProperty(
-        name="Recursion Limit",
-        description="how many recursion levels are used to calculate "
-        "the diffuse inter-reflection",
-        min=1, max=20, default=1
-    )
 
-    radio_pretrace_start: FloatProperty(
-        name="Pretrace Start",
-        description="Fraction of the screen width which sets the size of the "
-        "blocks in the mosaic preview first pass",
-        min=0.005, max=1.00, soft_min=0.02, soft_max=1.0, default=0.04
-    )
-    # XXX TODO set automatically to  pretrace_end = 8 / max (image_width, image_height)
-    # for non advanced mode
-    radio_pretrace_end: FloatProperty(
-        name="Pretrace End",
-        description="Fraction of the screen width which sets the size of the blocks "
-        "in the mosaic preview last pass",
-        min=0.000925, max=1.00, soft_min=0.01, soft_max=1.00, default=0.004, precision=3
-    )
+classes = (POV_OT_update_addon, PovrayPreferences)
 
-###############################################################################
-# Material POV properties.
-###############################################################################
-class MaterialTextureSlot(PropertyGroup):
-    """Declare material texture slot level properties for UI and translated to POV."""
 
-    bl_idname="pov_texture_slots",
-    bl_description="Texture_slots from Blender-2.79",
+def register():
+    for cls in classes:
+        register_class(cls)
 
-    # Adding a "real" texture datablock as property is not possible
-    # (or at least not easy through a dynamically populated EnumProperty).
-    # That's why we'll use a prop_search() UILayout function in ui.py.
-    # So we'll assign the name of the needed texture datablock to the below StringProperty.
-    texture : StringProperty(update=active_texture_name_from_uilist)
-    # and use another temporary StringProperty to change the linked data
-    texture_search : StringProperty(
-        name="",
-        update = active_texture_name_from_search,
-        description = "Browse Texture to be linked",
-    )
+    render_properties.register()
+    scenography_properties.register()
+    shading_properties.register()
+    texturing_properties.register()
+    object_properties.register()
+    scripting_properties.register()
+    scenography.register()
+    render.register()
+    base_ui.register()
+    scripting.register()
+    object_primitives.register()
 
-    alpha_factor: FloatProperty(
-        name="Alpha",
-        description="Amount texture affects alpha",
-        default = 1.0,
-    )
 
-    ambient_factor: FloatProperty(
-        name="",
-        description="Amount texture affects ambient",
-        default = 1.0,
-    )
+def unregister():
+    object_primitives.unregister()
+    scripting.unregister()
+    base_ui.unregister()
+    render.unregister()
+    scenography.register()
+    scripting_properties.unregister()
+    object_properties.unregister()
+    texturing_properties.unregister()
+    shading_properties.unregister()
+    scenography_properties.unregister()
+    render_properties.unregister()
 
-    bump_method: EnumProperty(
-        name="",
-        description="Method to use for bump mapping",
-        items=(
-            ("BUMP_ORIGINAL", "Bump Original", ""),
-            ("BUMP_COMPATIBLE", "Bump Compatible", ""),
-            ("BUMP_DEFAULT", "Bump Default", ""),
-            ("BUMP_BEST_QUALITY", "Bump Best Quality", "")
-        ),
-        default="BUMP_ORIGINAL",
-    )
+    for cls in classes:
+        unregister_class(cls)
 
-    bump_objectspace: EnumProperty(
-        name="",
-        description="Space to apply bump mapping in",
-        items=(
-            ("BUMP_VIEWSPACE", "Bump Viewspace", ""),
-            ("BUMP_OBJECTSPACE", "Bump Objectspace", ""),
-            ("BUMP_TEXTURESPACE", "Bump Texturespace", "")
-        ),
-        default="BUMP_VIEWSPACE",
-    )
 
-    density_factor: FloatProperty(
-        name="",
-        description="Amount texture affects density",
-        default = 1.0,
-    )
+if __name__ == "__main__":
+    register()
 
-    diffuse_color_factor: FloatProperty(
-        name="",
-        description="Amount texture affects diffuse color",
-        default = 1.0,
-    )
-
-    diffuse_factor: FloatProperty(
-        name="",
-        description="Amount texture affects diffuse reflectivity",
-        default = 1.0,
-    )
-
-    displacement_factor: FloatProperty(
-        name="",
-        description="Amount texture displaces the surface",
-        default = 0.2,
-    )
-
-    emission_color_factor: FloatProperty(
-        name="",
-        description="Amount texture affects emission color",
-        default = 1.0,
-    )
-
-    emission_factor: FloatProperty(
-        name="",
-        description="Amount texture affects emission",
-        default = 1.0,
-    )
-
-    emit_factor: FloatProperty(
-        name="",
-        description="Amount texture affects emission",
-        default = 1.0,
-    )
-
-    hardness_factor: FloatProperty(
-        name="",
-        description="Amount texture affects hardness",
-        default = 1.0,
-    )
-
-    mapping: EnumProperty(
-        name="",
-        description="",
-        items=(("FLAT", "Flat", ""),
-               ("CUBE", "Cube", ""),
-               ("TUBE", "Tube", ""),
-               ("SPHERE", "Sphere", "")),
-        default="FLAT",
-    )
-
-    mapping_x: EnumProperty(
-        name="",
-        description="",
-        items=(("NONE", "", ""),
-               ("X", "", ""),
-               ("Y", "", ""),
-               ("Z", "", "")),
-        default="NONE",
-    )
-
-    mapping_y: EnumProperty(
-        name="",
-        description="",
-        items=(("NONE", "", ""),
-               ("X", "", ""),
-               ("Y", "", ""),
-               ("Z", "", "")),
-        default="NONE",
-    )
-
-    mapping_z: EnumProperty(
-        name="",
-        description="",
-        items=(("NONE", "", ""),
-               ("X", "", ""),
-               ("Y", "", ""),
-               ("Z", "", "")),
-        default="NONE",
-    )
-
-    mirror_factor: FloatProperty(
-        name="",
-        description="Amount texture affects mirror color",
-        default = 1.0,
-    )
-
-    normal_factor: FloatProperty(
-        name="",
-        description="Amount texture affects normal values",
-        default = 1.0,
-    )
-
-    normal_map_space: EnumProperty(
-        name="",
-        description="Sets space of normal map image",
-        items=(("CAMERA", "Camera", ""),
-               ("WORLD", "World", ""),
-               ("OBJECT", "Object", ""),
-               ("TANGENT", "Tangent", "")),
-        default="CAMERA",
-    )
-
-    object: StringProperty(
-        name="Object",
-        description="Object to use for mapping with Object texture coordinates",
-        default ="",
-    )
-
-    raymir_factor: FloatProperty(
-        name="",
-        description="Amount texture affects ray mirror",
-        default = 1.0,
-    )
-
-    reflection_color_factor: FloatProperty(
-        name="",
-        description="Amount texture affects color of out-scattered light",
-        default = 1.0,
-    )
-
-    reflection_factor: FloatProperty(
-        name="",
-        description="Amount texture affects brightness of out-scattered light",
-        default = 1.0,
-    )
-
-    scattering_factor: FloatProperty(
-        name="",
-        description="Amount texture affects scattering",
-        default = 1.0,
-    )
-
-    specular_color_factor: FloatProperty(
-        name="",
-        description="Amount texture affects specular color",
-        default = 1.0,
-    )
-
-    specular_factor: FloatProperty(
-        name="",
-        description="Amount texture affects specular reflectivity",
-        default = 1.0,
-    )
-
-    offset: FloatVectorProperty(
-        name="Offset",
-        description=("Fine tune of the texture mapping X, Y and Z locations "),
-        precision=4,
-        step=0.1,
-        soft_min= -100.0,
-        soft_max=100.0,
-        default=(0.0,0.0,0.0),
-        options={'ANIMATABLE'},
-        subtype='TRANSLATION',
-    )
-
-    scale: FloatVectorProperty(
-        name="Size",
-        subtype='XYZ',
-        size=3,
-        description="Set scaling for the texture’s X, Y and Z sizes ",
-        precision=4,
-        step=0.1,
-        soft_min= -100.0,
-        soft_max=100.0,
-        default=(1.0,1.0,1.0),
-        options={'ANIMATABLE'},
-    )
-
-
-    texture_coords: EnumProperty(
-        name="",
-        description="",
-        items=(
-            ("GLOBAL", "Global", ""),
-            ("OBJECT", "Object", ""),
-            ("UV", "UV", ""),
-            ("ORCO", "Original Coordinates", ""),
-            ("STRAND", "Strand", ""),
-            ("STICKY", "Sticky", ""),
-            ("WINDOW", "Window", ""),
-            ("NORMAL", "Normal", ""),
-            ("REFLECTION", "Reflection", ""),
-            ("STRESS", "Stress", ""),
-            ("TANGENT", "Tangent", "")
-        ),
-        default="GLOBAL",
-    )
-
-    translucency_factor: FloatProperty(
-        name="",
-        description="Amount texture affects translucency",
-        default = 1.0,
-    )
-
-    transmission_color_factor: FloatProperty(
-        name="",
-        description="Amount texture affects result color after light has been scattered/absorbed",
-        default = 1.0,
-    )
-
-    use: BoolProperty(
-        name="",
-        description="Enable this material texture slot",
-        default = True,
-    )
-
-    use_from_dupli: BoolProperty(
-        name="",
-        description="Dupli’s instanced from verts, faces or particles, inherit texture coordinate from their parent",
-        default = False,
-    )
-
-    use_from_original: BoolProperty(
-        name="",
-        description="Dupli’s derive their object coordinates from the original objects transformation",
-        default = False,
-    )
-
-    use_interpolation: BoolProperty(
-        name="",
-        description="Interpolates pixels using selected filter ",
-        default = False,
-    )
-
-    use_map_alpha: BoolProperty(
-        name="",
-        description="Causes the texture to affect the alpha value",
-        default = False,
-    )
-
-    use_map_ambient: BoolProperty(
-        name="",
-        description="Causes the texture to affect the value of ambient",
-        default = False,
-    )
-
-    use_map_color_diffuse: BoolProperty(
-        name="",
-        description="Causes the texture to affect basic color of the material",
-        default = True,
-    )
-
-    use_map_color_emission: BoolProperty(
-        name="",
-        description="Causes the texture to affect the color of emission",
-        default = False,
-    )
-
-    use_map_color_reflection: BoolProperty(
-        name="",
-        description="Causes the texture to affect the color of scattered light",
-        default = False,
-    )
-
-    use_map_color_spec: BoolProperty(
-        name="",
-        description="Causes the texture to affect the specularity color",
-        default = False,
-    )
-
-    use_map_color_transmission: BoolProperty(
-        name="",
-        description="Causes the texture to affect the result color after other light has been scattered/absorbed",
-        default = False,
-    )
-
-    use_map_density: BoolProperty(
-        name="",
-        description="Causes the texture to affect the volume’s density",
-        default = False,
-    )
-
-    use_map_diffuse: BoolProperty(
-        name="",
-        description="Causes the texture to affect the value of the materials diffuse reflectivity",
-        default = False,
-    )
-
-    use_map_displacement: BoolProperty(
-        name="",
-        description="Let the texture displace the surface",
-        default = False,
-    )
-
-    use_map_emission: BoolProperty(
-        name="",
-        description="Causes the texture to affect the volume’s emission",
-        default = False,
-    )
-
-    use_map_emit: BoolProperty(
-        name="",
-        description="Causes the texture to affect the emit value",
-        default = False,
-    )
-
-    use_map_hardness: BoolProperty(
-        name="",
-        description="Causes the texture to affect the hardness value",
-        default = False,
-    )
-
-    use_map_mirror: BoolProperty(
-        name="",
-        description="Causes the texture to affect the mirror color",
-        default = False,
-    )
-
-    use_map_normal: BoolProperty(
-        name="",
-        description="Causes the texture to affect the rendered normal",
-        default = False,
-    )
-
-    use_map_raymir: BoolProperty(
-        name="",
-        description="Causes the texture to affect the ray-mirror value",
-        default = False,
-    )
-
-    use_map_reflect: BoolProperty(
-        name="",
-        description="Causes the texture to affect the reflected light’s brightness",
-        default = False,
-    )
-
-    use_map_scatter: BoolProperty(
-        name="",
-        description="Causes the texture to affect the volume’s scattering",
-        default = False,
-    )
-
-    use_map_specular: BoolProperty(
-        name="",
-        description="Causes the texture to affect the value of specular reflectivity",
-        default = False,
-    )
-
-    use_map_translucency: BoolProperty(
-        name="",
-        description="Causes the texture to affect the translucency value",
-        default = False,
-    )
-
-    use_map_warp: BoolProperty(
-        name="",
-        description="Let the texture warp texture coordinates of next channels",
-        default = False,
-    )
-
-    uv_layer: StringProperty(
-        name="",
-        description="UV layer to use for mapping with UV texture coordinates",
-        default = "",
-    )
-
-    warp_factor: FloatProperty(
-        name="",
-        description="Amount texture affects texture coordinates of next channels",
-        default = 0.0,
-    )
-
-
-#######################################
-
-    blend_factor: FloatProperty(
-        name="Blend",
-        description="Amount texture affects color progression of the "
-        "background",
-        soft_min=0.0, soft_max=1.0, default=1.0,
-    )
-
-    horizon_factor: FloatProperty(
-        name="Horizon",
-        description="Amount texture affects color of the horizon"
-                    "",
-        soft_min=0.0, soft_max=1.0, default=1.0
-    )
-
-    object: StringProperty(
-        name="Object",
-        description="Object to use for mapping with Object texture coordinates",
-        default="",
-    )
-
-    texture_coords: EnumProperty(
-        name="Coordinates",
-        description="Texture coordinates used to map the texture onto the background",
-        items=(
-            ("VIEW", "View", "Use view vector for the texture coordinates"),
-            ("GLOBAL", "Global", "Use global coordinates for the texture coordinates (interior mist)"),
-            ("ANGMAP", "AngMap", "Use 360 degree angular coordinates, e.g. for spherical light probes"),
-            ("SPHERE", "Sphere", "For 360 degree panorama sky, spherical mapped, only top half"),
-            ("EQUIRECT", "Equirectangular", "For 360 degree panorama sky, equirectangular mapping"),
-            ("TUBE", "Tube", "For 360 degree panorama sky, cylindrical mapped, only top half"),
-            ("OBJECT", "Object", "Use linked object’s coordinates for texture coordinates")
-        ),
-        default="VIEW",
-    )
-
-    use_map_blend: BoolProperty(
-        name="Blend Map",
-        description="Affect the color progression of the background",
-        default=True,
-    )
-
-    use_map_horizon: BoolProperty(
-        name="Horizon Map",
-        description="Affect the color of the horizon",
-        default=False,
-    )
-
-    use_map_zenith_down: BoolProperty(
-        name="", description="Affect the color of the zenith below",
-        default=False,
-    )
-
-    use_map_zenith_up: BoolProperty(
-        name="Zenith Up Map", description="Affect the color of the zenith above",
-        default=False,
-    )
-
-    zenith_down_factor: FloatProperty(
-        name="Zenith Down",
-        description="Amount texture affects color of the zenith below",
-        soft_min=0.0, soft_max=1.0, default=1.0
-    )
-
-    zenith_up_factor: FloatProperty(
-        name="Zenith Up",
-        description="Amount texture affects color of the zenith above",
-        soft_min=0.0, soft_max=1.0, default=1.0
-    )
-
-
-# former Space properties from  removed Blender Internal added below at superclass level
-# so as to be available in World, Material, Light for texture slots use
-
-bpy.types.ID.use_limited_texture_context = BoolProperty(
-    name="",
-    description="Use the limited version of texture user (for ‘old shading’ mode)",
-    default=True,
-)
-bpy.types.ID.texture_context = EnumProperty(
-    name="Texture context",
-    description="Type of texture data to display and edit",
-    items=(
-        ('MATERIAL', "", "Show material textures", "MATERIAL",0), # "Show material textures"
-        ('WORLD', "", "Show world textures", "WORLD",1), # "Show world textures"
-        ('LIGHT', "", "Show lamp textures", "LIGHT",2), # "Show lamp textures"
-        ('PARTICLES', "", "Show particles textures", "PARTICLES",3), # "Show particles textures"
-        ('LINESTYLE', "", "Show linestyle textures", "LINE_DATA",4), # "Show linestyle textures"
-        ('OTHER', "", "Show other data textures", "TEXTURE_DATA",5) # "Show other data textures"
-    ),
-    default = 'MATERIAL',
-)
-
-# bpy.types.ID.active_texture_index = IntProperty(
-    # name = "Index for texture_slots",
-    # default = 0,
-# )
-
-class RenderPovSettingsMaterial(PropertyGroup):
-    """Declare material level properties controllable in UI and translated to POV."""
-
-    ######################Begin Old Blender Internal Props#########################
-    # former Space properties from  removed Blender Internal
-    use_limited_texture_context: BoolProperty(
-        name="",
-        description="Use the limited version of texture user (for ‘old shading’ mode)",
-        default=True,
-    )
-    texture_context: EnumProperty(
-        name="Texture context",
-        description="Type of texture data to display and edit",
-        items=(
-            ('MATERIAL', "", "Show material textures", "MATERIAL",0), # "Show material textures"
-            ('WORLD', "", "Show world textures", "WORLD",1), # "Show world textures"
-            ('LAMP', "", "Show lamp textures", "LIGHT",2), # "Show lamp textures"
-            ('PARTICLES', "", "Show particles textures", "PARTICLES",3), # "Show particles textures"
-            ('LINESTYLE', "", "Show linestyle textures", "LINE_DATA",4), # "Show linestyle textures"
-            ('OTHER', "", "Show other data textures", "TEXTURE_DATA",5) # "Show other data textures"
-        ),
-        default = 'MATERIAL',
-    )
-
-    active_texture_index: IntProperty(
-        name = "Index for texture_slots",
-        default = 0,
-        update = brush_texture_update
-    )
-
-    transparency_method: EnumProperty(
-        name="Specular Shader Model",
-        description="Method to use for rendering transparency",
-        items=(
-            ("MASK", "Mask", "Mask the background"),
-            ("Z_TRANSPARENCY", "Z Transparency", "Use alpha buffer for transparent faces"),
-            ("RAYTRACE", "Raytrace", "Use raytracing for transparent refraction rendering")
-        ),
-        default="MASK",
-    )
-
-    use_transparency: BoolProperty(
-        name="Transparency",
-        description="Render material as transparent",
-        default=False,
-    )
-
-    alpha: FloatProperty(
-        name="Alpha",
-        description="Alpha transparency of the material",
-        min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3,
-    )
-
-    specular_alpha: FloatProperty(
-        name="Specular alpha",
-        description="Alpha transparency for specular areas",
-        min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3,
-    )
-
-    ambient: FloatProperty(
-        name="Ambient",
-        description="Amount of global ambient color the material receives",
-        min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3,
-    )
-
-    diffuse_color: FloatVectorProperty(
-        name="Diffuse color",
-        description=("Diffuse color of the material"),
-        precision=4, step=0.01, min=0, # max=inf, soft_max=1,
-        default=(0.6,0.6,0.6), options={'ANIMATABLE'}, subtype='COLOR',
-    )
-
-    darkness: FloatProperty(
-        name="Darkness",
-        description="Minnaert darkness",
-        min=0.0, max=2.0, soft_min=0.0, soft_max=2.0, default=1.0, precision=3,
-    )
-
-    diffuse_fresnel: FloatProperty(
-        name="Diffuse fresnel",
-        description="Power of Fresnel",
-        min=0.0, max=5.0, soft_min=0.0, soft_max=5.0, default=1.0, precision=3,
-    )
-
-    diffuse_fresnel_factor: FloatProperty(
-        name="Diffuse fresnel factor",
-        description="Blending factor of Fresnel",
-        min=0.0, max=5.0, soft_min=0.0, soft_max=5.0, default=0.5, precision=3,
-    )
-
-    diffuse_intensity: FloatProperty(
-        name="Diffuse intensity",
-        description="Amount of diffuse reflection multiplying color",
-        min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.8, precision=3,
-    )
-
-    diffuse_ramp_blend: EnumProperty(
-        name="Diffuse ramp blend",
-        description="Blending method of the ramp and the diffuse color",
-        items=(
-            ("MIX", "Mix", ""),
-            ("ADD", "Add", ""),
-            ("MULTIPLY", "Multiply", ""),
-            ("SUBTRACT", "Subtract", ""),
-            ("SCREEN", "Screen", ""),
-            ("DIVIDE", "Divide", ""),
-            ("DIFFERENCE", "Difference", ""),
-            ("DARKEN", "Darken", ""),
-            ("LIGHTEN", "Lighten", ""),
-            ("OVERLAY", "Overlay", ""),
-            ("DODGE", "Dodge", ""),
-            ("BURN", "Burn", ""),
-            ("HUE", "Hue", ""),
-            ("SATURATION", "Saturation", ""),
-            ("VALUE", "Value", ""),
-            ("COLOR", "Color", ""),
-            ("SOFT_LIGHT", "Soft light", ""),
-            ("LINEAR_LIGHT", "Linear light", "")
-        ),
-        default="MIX",
-    )
-
-    diffuse_ramp_factor: FloatProperty(
-        name="Factor",
-        description="Blending factor (also uses alpha in Colorband)",
-        min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3,
-    )
-
-    diffuse_ramp_input: EnumProperty(
-        name="Input",
-        description="How the ramp maps on the surface",
-        items=(
-            ("SHADER", "Shader", ""),
-            ("ENERGY", "Energy", ""),
-            ("NORMAL", "Normal", ""),
-            ("RESULT", "Result", "")
-        ),
-            default="SHADER",
-    )
-
-    diffuse_shader: EnumProperty(
-        name="Diffuse Shader Model",
-        description="How the ramp maps on the surface",
-        items=(
-            ("LAMBERT", "Lambert", "Use a Lambertian shader"),
-            ("OREN_NAYAR", "Oren-Nayar", "Use an Oren-Nayar shader"),
-            ("MINNAERT", "Minnaert", "Use a Minnaert shader"),
-            ("FRESNEL", "Fresnel", "Use a Fresnel shader")
-        ),
-        default="LAMBERT",
-    )
-
-    diffuse_toon_size: FloatProperty(
-        name="Size",
-        description="Size of diffuse toon area",
-        min=0.0, max=3.14, soft_min=0.0, soft_max=3.14, default=0.5, precision=3,
-    )
-
-    diffuse_toon_smooth: FloatProperty(
-        name="Smooth",
-        description="Smoothness of diffuse toon area",
-        min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.1, precision=3,
-    )
-
-    emit: FloatProperty(
-        name="Emit",
-        description="Amount of light to emit",
-        min=0.0, soft_min=0.0, # max=inf, soft_max=inf,
-        default=0.0, precision=3,
-        )
-
-    mirror_color: FloatVectorProperty(
-        name="Mirror color",
-        description=("Mirror color of the material"),
-        precision=4, step=0.01, min=0, # max=inf, soft_max=1,
-        default=(0.6,0.6,0.6), options={'ANIMATABLE'}, subtype='COLOR'
-    )
-
-    roughness: FloatProperty(
-        name="Roughness",
-        description="Oren-Nayar Roughness",
-        min=0.0, max=3.14, soft_min=0.0, soft_max=3.14,
-        precision=3,
-        default=0.5,
-    )
-
-    halo: BoolProperty(
-        name="Halo",
-        description=" Halo settings for the material",
-        default=False,
-    )
-            # (was readonly in Blender2.79, never None)
-
-    line_color: FloatVectorProperty(
-        name="Line color",
-        description=("Line color used for Freestyle line rendering"),
-        precision=4, step=0.01, min=0, # max=inf, soft_max=1,
-        default=(0.0,0.0,0.0), options={'ANIMATABLE'}, subtype='COLOR'
-    )
-
-    # diffuse_ramp:
-    ## Color ramp used to affect diffuse shading
-            ## Type:	ColorRamp, (readonly)
-
-            # cr_node = bpy.data.materials['Material'].node_tree.nodes['ColorRamp']
-            # layout.template_color_ramp(cr_node, "color_ramp", expand=True)
-
-            # ou
-
-            # class bpy.types.ColorRamp(bpy_struct)
-
-    line_priority: IntProperty(
-        name="Recursion Limit",
-        description="The line color of a higher priority is used at material boundaries",
-        min=0, max=32767, default=0,
-    )
-
-    specular_color: FloatVectorProperty(
-        name="Specular color",
-        description=("Specular color of the material "),
-        precision=4, step=0.01, min=0, # max=inf, soft_max=1,
-        default=(1.0,1.0,1.0), options={'ANIMATABLE'}, subtype='COLOR'
-    )
-
-    specular_hardness: IntProperty(
-        name="Hardness",
-        description="How hard (sharp) the specular reflection is",
-        min=1, max=511, default=50,
-    )
-
-    specular_intensity: FloatProperty(
-        name="Intensity",
-        description="How intense (bright) the specular reflection is",
-        min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.5, precision=3
-    )
-
-    specular_ior: FloatProperty(
-        name="IOR",
-        description="Specular index of refraction",
-        min=-10.0, max=10.0, soft_min=0.0, soft_max=10.0, default=1.0, precision=3
-    )
-
-    ior: FloatProperty(
-        name="IOR",
-        description="Index of refraction",
-        min=-10.0, max=10.0, soft_min=0.0, soft_max=10.0, default=1.0, precision=3
-    )
-
-    specular_shader: EnumProperty(
-        name="Specular Shader Model",
-        description="How the ramp maps on the surface",
-        items=(
-            ("COOKTORR", "CookTorr", "Use a Cook-Torrance shader"),
-            ("PHONG", "Phong", "Use a Phong shader"),
-            ("BLINN", "Blinn", "Use a Blinn shader"),
-            ("TOON", "Toon", "Use a Toon shader"),
-            ("WARDISO", "WardIso", "Use a Ward anisotropic shader")
-        ),
-        default="COOKTORR",
-    )
-
-    specular_slope: FloatProperty(
-        name="Slope",
-        description="The standard deviation of surface slope",
-        min=0.0, max=0.4, soft_min=0.0, soft_max=0.4, default=0.1, precision=3
-    )
-
-    specular_toon_size: FloatProperty(
-        name="Size",
-        description="Size of specular toon area",
-        min=0.0, max=0.53, soft_min=0.0, soft_max=0.53, default=0.5, precision=3
-    )
-
-    specular_toon_smooth: FloatProperty(
-        name="Smooth",
-        description="Smoothness of specular toon area",
-        min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.1, precision=3
-    )
-
-
-    translucency: FloatProperty(
-        name="Translucency",
-        description="Amount of diffuse shading on the back side",
-        min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.0, precision=3
-    )
-
-    transparency_method: EnumProperty(
-        name="Specular Shader Model",
-        description="Method to use for rendering transparency",
-        items=(
-            ("MASK", "Mask", "Mask the background"),
-            ("Z_TRANSPARENCY", "Z Transparency", "Use an ior of 1 for transparent faces"),
-            ("RAYTRACE", "Raytrace", "Use raytracing for transparent refraction rendering")
-        ),
-        default="MASK",
-    )
-
-    type: EnumProperty(
-        name="Type",
-        description="Material type defining how the object is rendered",
-        items=(
-            ("SURFACE", "Surface", "Render object as a surface"),
-            ("WIRE", "Wire", "Render the edges of faces as wires (not supported in raytracing)"),# TO UPDATE > USE MACRO AND CHANGE DESCRIPTION
-            ("VOLUME", "Volume", "Render object as a volume"),
-            ("‘HALO’", "Halo", "Render object as halo particles")
-        ), # TO UPDATE > USE MACRO AND CHANGE DESCRIPTION
-        default="SURFACE",
-    )
-
-    use_cast_shadows: BoolProperty(
-        name="Cast",
-        description="Allow this material to cast shadows",
-        default=True,
-    )
-
-    use_cast_shadows_only: BoolProperty(
-        name="Cast Only",
-        description="Make objects with this material "
-        "appear invisible (not rendered), only "
-        "casting shadows",
-        default=False,
-    )
-
-    use_cubic: BoolProperty(
-        name="Cubic Interpolation",
-        description="Use cubic interpolation for diffuse "
-        "values, for smoother transitions",
-        default=False,
-    )
-
-    use_diffuse_ramp: BoolProperty(
-        name="Ramp",
-        description="Toggle diffuse ramp operations",
-        default=False,
-    )
-
-    use_light_group_exclusive: BoolProperty(
-        name="Exclusive",
-        description="Material uses the light group exclusively"
-        "- these lamps are excluded from other "
-        "scene lighting",
-        default=False,
-    )
-
-    use_light_group_local: BoolProperty(
-        name="Local",
-        description="When linked in, material uses local light"
-        " group with the same name",
-        default=False,
-    )
-
-    use_mist: BoolProperty(
-        name="Use Mist",
-        description="Use mist with this material "
-        "(in world settings)",
-        default=True,
-        )
-
-    use_nodes: BoolProperty(
-        name="Nodes",
-        description="Use shader nodes to render the material",# Add Icon in UI or here? icon='NODES'
-        default=False,
-    )
-
-    use_object_color: BoolProperty(
-        name="Object Color",
-        description="Modulate the result with a per-object color",
-        default=False,
-    )
-
-    use_only_shadow: BoolProperty(
-        name="Shadows Only",
-        description="Render shadows as the material’s alpha "
-        "value, making the material transparent "
-        "except for shadowed areas",
-        default=False,
-    )
-
-    use_shadeless: BoolProperty(
-        name="Shadeless",
-        description="Make this material insensitive to "
-        "light or shadow",
-        default=False,
-    )
-
-    use_shadows: BoolProperty(
-        name="Receive",
-        description="Allow this material to receive shadows",
-        default=True,
-    )
-
-    use_sky: BoolProperty(
-        name="Sky",
-        description="Render this material with zero alpha, "
-        "with sky background in place (scanline only)",
-        default=False,
-    )
-
-    use_specular_ramp: BoolProperty(
-        name="Ramp",
-        description="Toggle specular ramp operations",
-        default=False,
-    )
-
-    use_tangent_shading: BoolProperty(
-        name="Tangent Shading",
-        description="Use the material’s tangent vector instead"
-        "of the normal for shading - for "
-        "anisotropic shading effects",
-        default=False,
-    )
-
-    use_transparent_shadows: BoolProperty(
-        name="Receive Transparent",
-        description="Allow this object to receive transparent "
-        "shadows cast through other object",
-        default=False,
-    ) # linked to fake caustics
-
-    use_vertex_color_light: BoolProperty(
-        name="Vertex Color Light",
-        description="Add vertex colors as additional lighting",
-        default=False,
-    )
-
-    use_vertex_color_paint: BoolProperty(
-        name="Vertex Color Paint", description="Replace object base color with vertex "
-        "colors (multiply with ‘texture face’ "
-        "face assigned textures)",
-        default=False,
-    )
-
-
-    specular_ramp_blend: EnumProperty(
-        name="Specular ramp blend",
-        description="Blending method of the ramp and the specular color",
-        items=(
-            ("MIX", "Mix", ""),
-            ("ADD", "Add", ""),
-            ("MULTIPLY", "Multiply", ""),
-            ("SUBTRACT", "Subtract", ""),
-            ("SCREEN", "Screen", ""),
-            ("DIVIDE", "Divide", ""),
-            ("DIFFERENCE", "Difference", ""),
-            ("DARKEN", "Darken", ""),
-            ("LIGHTEN", "Lighten", ""),
-            ("OVERLAY", "Overlay", ""),
-            ("DODGE", "Dodge", ""),
-            ("BURN", "Burn", ""),
-            ("HUE", "Hue", ""),
-            ("SATURATION", "Saturation", ""),
-            ("VALUE", "Value", ""),
-            ("COLOR", "Color", ""),
-            ("SOFT_LIGHT", "Soft light", ""),
-            ("LINEAR_LIGHT", "Linear light", "")
-        ),
-        default="MIX",
-    )
-
-    specular_ramp_factor: FloatProperty(
-        name="Factor",
-        description="Blending factor (also uses alpha in Colorband)",
-        min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3,
-    )
-
-    specular_ramp_input: EnumProperty(
-        name="Input",
-        description="How the ramp maps on the surface",
-        items=(
-            ("SHADER", "Shader", ""),
-            ("ENERGY", "Energy", ""),
-            ("NORMAL", "Normal", ""),
-            ("RESULT", "Result", "")
-        ),
-        default="SHADER",
-    )
-
-
-    irid_enable: BoolProperty(
-        name="Iridescence coating",
-        description="Newton's thin film interference (like an oil slick on a puddle of "
-        "water or the rainbow hues of a soap bubble.)",
-        default=False,
-    )
-
-    mirror_use_IOR: BoolProperty(
-        name="Correct Reflection",
-        description="Use same IOR as raytrace transparency to calculate mirror reflections. "
-        "More physically correct",
-        default=False,
-    )
-
-    mirror_metallic: BoolProperty(
-        name="Metallic Reflection",
-        description="mirror reflections get colored as diffuse (for metallic materials)",
-        default=False,
-    )
-
-    conserve_energy: BoolProperty(
-        name="Conserve Energy",
-        description="Light transmitted is more correctly reduced by mirror reflections, "
-        "also the sum of diffuse and translucency gets reduced below one ",
-        default=True,
-    )
-
-    irid_amount: FloatProperty(
-        name="amount",
-        description="Contribution of the iridescence effect to the overall surface color. "
-        "As a rule of thumb keep to around 0.25 (25% contribution) or less, "
-        "but experiment. If the surface is coming out too white, try lowering "
-        "the diffuse and possibly the ambient values of the surface",
-        min=0.0, max=1.0, soft_min=0.01, soft_max=1.0, default=0.25,
-    )
-
-    irid_thickness: FloatProperty(
-        name="thickness",
-        description="A very thin film will have a high frequency of color changes while a "
-        "thick film will have large areas of color",
-        min=0.0, max=1000.0, soft_min=0.1, soft_max=10.0, default=1,
-    )
-
-    irid_turbulence: FloatProperty(
-        name="turbulence",
-        description="This parameter varies the thickness",
-        min=0.0, max=10.0, soft_min=0.000, soft_max=1.0, default=0
-    )
-
-    interior_fade_color: FloatVectorProperty(
-        name="Interior Fade Color",
-        description="Color of filtered attenuation for transparent "
-        "materials",
-        precision=4, step=0.01, min=0.0, soft_max=1.0,
-        default=(0, 0, 0), options={'ANIMATABLE'}, subtype='COLOR'
-    )
-
-    caustics_enable: BoolProperty(
-        name="Caustics",
-        description="use only fake refractive caustics (default) or photon based "
-                    "reflective/refractive caustics",
-        default=True,
-    )
-
-    fake_caustics: BoolProperty(
-        name="Fake Caustics",
-        description="use only (Fast) fake refractive caustics",
-        default=True,
-    )
-
-    fake_caustics_power: FloatProperty(
-        name="Fake caustics power",
-        description="Values typically range from 0.0 to 1.0 or higher. Zero is no caustics. "
-        "Low, non-zero values give broad hot-spots while higher values give "
-        "tighter, smaller simulated focal points",
-        min=0.00, max=10.0, soft_min=0.00, soft_max=5.0, default=0.15
-    )
-
-    refraction_caustics: BoolProperty(
-        name="Refractive Caustics",
-        description="hotspots of light focused when going through the material",
-        default=True,
-    )
-
-    photons_dispersion: FloatProperty(
-        name="Chromatic Dispersion",
-        description="Light passing through will be separated according to wavelength. "
-        "This ratio of refractive indices for violet to red controls how much "
-        "the colors are spread out 1 = no dispersion, good values are 1.01 to 1.1",
-        min=1.0000, max=10.000, soft_min=1.0000, soft_max=1.1000, precision=4,
-        default=1.0000,
-    )
-
-    photons_dispersion_samples: IntProperty(
-        name="Dispersion Samples",
-        description="Number of color-steps for dispersion",
-        min=2, max=128, default=7,
-    )
-
-    photons_reflection: BoolProperty(
-        name="Reflective Photon Caustics",
-        description="Use this to make your Sauron's ring ;-P",
-        default=False,
-    )
-
-    refraction_type: EnumProperty(
-        items=[
-               ("1", "Z Transparency Fake Caustics", "use fake caustics"),
-               ("2", "Raytrace Photons Caustics", "use photons for refractive caustics")],
-        name="Refraction Type:",
-        description="use fake caustics (fast) or true photons for refractive Caustics",
-        default="1",
-    )
-
-    ##################################CustomPOV Code############################
-    replacement_text: StringProperty(
-        name="Declared name:",
-        description="Type the declared name in custom POV code or an external "
-        ".inc it points at. texture {} expected",
-        default="",
-    )
-
-
-            # NODES
-
-    def use_material_nodes_callback(self, context):
-        if hasattr(context.space_data, "tree_type"):
-            context.space_data.tree_type = 'ObjectNodeTree'
-        mat=context.object.active_material
-        if mat.pov.material_use_nodes:
-            mat.use_nodes=True
-            tree = mat.node_tree
-            tree.name=mat.name
-            links = tree.links
-            default = True
-            if len(tree.nodes) == 2:
-                o = 0
-                m = 0
-                for node in tree.nodes:
-                    if node.type in {"OUTPUT","MATERIAL"}:
-                        tree.nodes.remove(node)
-                        default = True
-                for node in tree.nodes:
-                    if node.bl_idname == 'PovrayOutputNode':
-                        o+=1
-                    if node.bl_idname == 'PovrayTextureNode':
-                        m+=1
-                if o == 1 and m == 1:
-                    default = False
-            elif len(tree.nodes) == 0:
-                default = True
-            else:
-                default = False
-            if default:
-                output = tree.nodes.new('PovrayOutputNode')
-                output.location = 200,200
-                tmap = tree.nodes.new('PovrayTextureNode')
-                tmap.location = 0,200
-                links.new(tmap.outputs[0],output.inputs[0])
-                tmap.select = True
-                tree.nodes.active = tmap
-        else:
-            mat.use_nodes=False
-
-
-    def use_texture_nodes_callback(self, context):
-        tex=context.object.active_material.active_texture
-        if tex.pov.texture_use_nodes:
-            tex.use_nodes=True
-            if len(tex.node_tree.nodes)==2:
-                for node in tex.node_tree.nodes:
-                    if node.type in {"OUTPUT","CHECKER"}:
-                        tex.node_tree.nodes.remove(node)
-        else:
-            tex.use_nodes=False
-
-    def node_active_callback(self, context):
-        items = []
-        mat=context.material
-        mat.node_tree.nodes
-        for node in mat.node_tree.nodes:
-            node.select=False
-        for node in mat.node_tree.nodes:
-            if node.name==mat.pov.material_active_node:
-                node.select=True
-                mat.node_tree.nodes.active=node
-
-                return node
-
-    def node_enum_callback(self, context):
-        items = []
-        mat=context.material
-        nodes=mat.node_tree.nodes
-        for node in nodes:
-            items.append(("%s"%node.name,"%s"%node.name,""))
-        return items
-
-    def pigment_normal_callback(self, context):
-        render = context.scene.pov.render
-        items = [("pigment", "Pigment", ""),("normal", "Normal", "")]
-        if render == 'hgpovray':
-            items = [("pigment", "Pigment", ""),("normal", "Normal", ""),("modulation", "Modulation", "")]
-        return items
-
-    def glow_callback(self, context):
-        scene = context.scene
-        ob = context.object
-        ob.pov.mesh_write_as_old = ob.pov.mesh_write_as
-        if scene.pov.render == 'uberpov' and ob.pov.glow:
-            ob.pov.mesh_write_as = 'NONE'
-        else:
-            ob.pov.mesh_write_as = ob.pov.mesh_write_as_old
-
-    material_use_nodes: BoolProperty(
-        name="Use nodes",
-        description="",
-        update=use_material_nodes_callback,
-        default=False,
-    )
-
-    material_active_node: EnumProperty(
-        name="Active node",
-        description="",
-        items=node_enum_callback,
-        update=node_active_callback
-    )
-
-    preview_settings: BoolProperty(
-        name="Preview Settings",
-        description="",
-        default=False,
-    )
-
-    object_preview_transform: BoolProperty(
-        name="Transform object",
-        description="",
-        default=False,
-    )
-
-    object_preview_scale: FloatProperty(
-        name="XYZ",
-        min=0.5,
-        max=2.0,
-        default=1.0,
-    )
-
-    object_preview_rotate: FloatVectorProperty(
-        name="Rotate",
-        description="",
-        min=-180.0,
-        max=180.0,
-        default=(0.0,0.0,0.0),
-        subtype='XYZ',
-    )
-
-    object_preview_bgcontrast: FloatProperty(
-        name="Contrast",
-        min=0.0,
-        max=1.0,
-        default=0.5,
-    )
-
-
-class MaterialRaytraceTransparency(PropertyGroup):
-    """Declare transparency panel properties controllable in UI and translated to POV."""
-
-    depth: IntProperty(
-        name="Depth",
-        description="Maximum allowed number of light inter-refractions",
-        min=0, max=32767, default=2
-    )
-
-    depth_max: FloatProperty(
-        name="Depth",
-        description="Maximum depth for light to travel through the "
-        "transparent material before becoming fully filtered (0.0 is disabled)",
-        min=0, max=100, default=0.0,
-    )
-
-    falloff: FloatProperty(
-        name="Falloff",
-        description="Falloff power for transmissivity filter effect (1.0 is linear)",
-        min=0.1, max=10.0, default=1.0, precision=3
-    )
-
-    filter: FloatProperty(
-        name="Filter",
-        description="Amount to blend in the material’s diffuse color in raytraced "
-        "transparency (simulating absorption)",
-        min=0.0, max=1.0, default=0.0, precision=3
-    )
-
-    fresnel: FloatProperty(
-        name="Fresnel",
-        description="Power of Fresnel for transparency (Ray or ZTransp)",
-        min=0.0, max=5.0, soft_min=0.0, soft_max=5.0, default=0.0, precision=3
-    )
-
-    fresnel_factor: FloatProperty(
-        name="Blend",
-        description="Blending factor for Fresnel",
-        min=0.0, max=5.0, soft_min=0.0, soft_max=5.0, default=1.250, precision=3
-    )
-
-    gloss_factor: FloatProperty(
-        name="Amount",
-        description="The clarity of the refraction. "
-        "(values < 1.0 give diffuse, blurry refractions)",
-        min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3
-    )
-
-    gloss_samples: IntProperty(
-        name="Samples",
-        description="frequency of the noise sample used for blurry refractions",
-        min=0, max=1024, default=18
-    )
-
-    gloss_threshold: FloatProperty(
-        name="Threshold",
-        description="Threshold for adaptive sampling (if a sample "
-        "contributes less than this amount [as a percentage], "
-        "sampling is stopped)",
-        min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.005, precision=3
-    )
-
-    ior: FloatProperty(
-        name="IOR",
-        description="Sets angular index of refraction for raytraced refraction",
-        min=-0.0, max=10.0, soft_min=0.25, soft_max=4.0, default=1.3
-    )
-
-class MaterialRaytraceMirror(PropertyGroup):
-    """Declare reflection panel properties controllable in UI and translated to POV."""
-
-    bl_description = "Raytraced reflection settings for the Material",
-
-    use: BoolProperty(
-        name="Mirror",
-        description="Enable raytraced reflections",
-        default=False,
-    )
-
-
-    depth: IntProperty(
-        name="Depth",
-        description="Maximum allowed number of light inter-reflections",
-        min=0, max=32767, default=2
-    )
-
-    distance: FloatProperty(
-        name="Max Dist",
-        description="Maximum distance of reflected rays "
-        "(reflections further than this range "
-        "fade to sky color or material color)",
-        min=0.0, max=100000.0, soft_min=0.0, soft_max=10000.0, default=0.0, precision=3
-    )
-
-    fade_to: EnumProperty(
-        items=[
-               ("FADE_TO_SKY", "Fade to sky", ""),
-               ("FADE_TO_MATERIAL", "Fade to material color", "")],
-        name="Fade-out Color",
-        description="The color that rays with no intersection within the "
-        "Max Distance take (material color can be best for "
-        "indoor scenes, sky color for outdoor)",
-        default="FADE_TO_SKY",
-    )
-
-    fresnel: FloatProperty(
-        name="Fresnel",
-        description="Power of Fresnel for mirror reflection",
-        min=0.0, max=5.0, soft_min=0.0, soft_max=5.0, default=0.0, precision=3,
-    )
-
-    fresnel_factor: FloatProperty(
-        name="Blend",
-        description="Blending factor for Fresnel",
-        min=0.0, max=5.0, soft_min=0.0, soft_max=5.0, default=1.250, precision=3
-    )
-
-    gloss_anisotropic: FloatProperty(
-        name="Anisotropic",
-        description="The shape of the reflection, from 0.0 (circular) "
-        "to 1.0 (fully stretched along the tangent",
-        min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3
-    )
-
-    gloss_factor: FloatProperty(
-        name="Amount",
-        description="The shininess of the reflection  "
-        "(values < 1.0 give diffuse, blurry reflections)",
-        min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3
-    )
-
-    gloss_samples: IntProperty(
-        name="Noise",
-        description="Frequency of the noise pattern bumps averaged for blurry reflections",
-        min=0, max=1024, default=18,
-    )
-
-    gloss_threshold: FloatProperty(
-        name="Threshold",
-        description="Threshold for adaptive sampling (if a sample "
-        "contributes less than this amount [as a percentage], "
-        "sampling is stopped)",
-        min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.005, precision=3
-    )
-
-    mirror_color: FloatVectorProperty(
-        name="Mirror color",
-        description=("Mirror color of the material"),
-        precision=4, step=0.01,
-        default=(1.0,1.0,1.0), options={'ANIMATABLE'}, subtype='COLOR'
-    )
-
-    reflect_factor: FloatProperty(
-        name="Reflectivity",
-        description="Amount of mirror reflection for raytrace",
-        min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3
-    )
-
-
-class MaterialSubsurfaceScattering(PropertyGroup):
-    r"""Declare SSS/SSTL properties controllable in UI and translated to POV."""
-
-    bl_description = "Subsurface scattering settings for the material",
-
-    use: BoolProperty(
-        name="Subsurface Scattering",
-        description="Enable diffuse subsurface scatting "
-        "effects in a material",
-        default=False,
-    )
-
-    back: FloatProperty(
-        name="Back",
-        description="Back scattering weight",
-        min=0.0, max=10.0, soft_min=0.0, soft_max=10.0, default=1.0, precision=3
-    )
-
-    color: FloatVectorProperty(
-        name="Scattering color",
-        description=("Scattering color"),
-        precision=4, step=0.01,
-        default=(0.604,0.604,0.604), options={'ANIMATABLE'}, subtype='COLOR'
-    )
-
-    color_factor: FloatProperty(
-        name="Color",
-        description="Blend factor for SSS colors",
-        min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3
-    )
-
-    error_threshold: FloatProperty(
-        name="Error",
-        description="Error tolerance (low values are slower and higher quality)",
-        default=0.050, precision=3
-    )
-
-    front: FloatProperty(
-        name="Front",
-        description="Front scattering weight",
-        min=0.0, max=2.0, soft_min=0.0, soft_max=2.0, default=1.0, precision=3
-    )
-
-    ior: FloatProperty(
-        name="IOR",
-        description="Index of refraction (higher values are denser)",
-        min=-0.0, max=10.0, soft_min=0.1, soft_max=2.0, default=1.3
-    )
-
-    radius: FloatVectorProperty(
-        name="RGB Radius",
-        description=("Mean red/green/blue scattering path length"),
-        precision=4, step=0.01, min=0.001,
-        default=(1.0,1.0,1.0), options={'ANIMATABLE'}
-    )
-
-    scale: FloatProperty(
-        name="Scale",
-        description="Object scale factor",
-        default=0.100, precision=3
-    )
-
-    texture_factor: FloatProperty(
-        name="Texture",
-        description="Texture scattering blend factor",
-        min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.0, precision=3
-    )
-
-
-class MaterialStrandSettings(PropertyGroup):
-    """Declare strand properties controllable in UI and translated to POV."""
-
-    bl_description = "Strand settings for the material",
-
-    blend_distance: FloatProperty(
-        name="Distance",
-        description="Worldspace distance over which to blend in the surface normal",
-        min=0.0, max=10.0, soft_min=0.0, soft_max=10.0, default=0.0, precision=3
-    )
-
-    root_size: FloatProperty(
-        name="Root",
-        description="Start size of strands in pixels or Blender units",
-        min=0.25, default=1.0, precision=5
-    )
-
-    shape: FloatProperty(
-        name="Shape",
-        description="Positive values make strands rounder, negative ones make strands spiky",
-        min=-0.9, max=0.9, default=0.0, precision=3
-    )
-
-    size_min: FloatProperty(
-        name="Minimum",
-        description="Minimum size of strands in pixels",
-        min=0.001, max=10.0, default=1.0, precision=3
-    )
-
-    tip_size: FloatProperty(
-        name="Tip",
-        description="End size of strands in pixels or Blender units",
-        min=0.0, default=1.0, precision=5
-    )
-
-    use_blender_units: BoolProperty(
-        name="Blender Units",
-        description="Use Blender units for widths instead of pixels",
-        default=False,
-    )
-
-    use_surface_diffuse: BoolProperty(
-        name="Surface diffuse",
-        description="Make diffuse shading more similar to shading the surface",
-        default=False,
-    )
-
-    use_tangent_shading: BoolProperty(
-        name="Tangent Shading",
-        description="Use direction of strands as normal for tangent-shading",
-        default=True,
-    )
-
-    uv_layer: StringProperty(
-        name="UV Layer",
-        # icon="GROUP_UVS",
-        description="Name of UV map to override",
-        default="",
-    )
-
-    width_fade: FloatProperty(
-        name="Width Fade",
-        description="Transparency along the width of the strand",
-        min=0.0, max=2.0, default=0.0, precision=3
-    )
-
-            # halo
-
-                # Halo settings for the material
-                # Type:	MaterialHalo, (readonly, never None)
-
-            # ambient
-
-                # Amount of global ambient color the material receives
-                # Type:	float in [0, 1], default 0.0
-
-            # darkness
-
-                # Minnaert darkness
-                # Type:	float in [0, 2], default 0.0
-
-            # diffuse_color
-
-                # Diffuse color of the material
-                # Type:	float array of 3 items in [0, inf], default (0.0, 0.0, 0.0)
-
-            # diffuse_fresnel
-
-                # Power of Fresnel
-                # Type:	float in [0, 5], default 0.0
-
-            # diffuse_fresnel_factor
-
-                # Blending factor of Fresnel
-                # Type:	float in [0, 5], default 0.0
-
-            # diffuse_intensity
-
-                # Amount of diffuse reflection
-                # Type:	float in [0, 1], default 0.0
-
-            # diffuse_ramp
-
-                # Color ramp used to affect diffuse shading
-                # Type:	ColorRamp, (readonly)
-
-            # diffuse_ramp_blend
-
-                # Blending method of the ramp and the diffuse color
-                # Type:	enum in [‘MIX’, ‘ADD’, ‘MULTIPLY’, ‘SUBTRACT’, ‘SCREEN’, ‘DIVIDE’, ‘DIFFERENCE’, ‘DARKEN’, ‘LIGHTEN’, ‘OVERLAY’, ‘DODGE’, ‘BURN’, ‘HUE’, ‘SATURATION’, ‘VALUE’, ‘COLOR’, ‘SOFT_LIGHT’, ‘LINEAR_LIGHT’], default ‘MIX’
-
-            # diffuse_ramp_factor
-
-                # Blending factor (also uses alpha in Colorband)
-                # Type:	float in [0, 1], default 0.0
-
-            # diffuse_ramp_input
-
-                # How the ramp maps on the surface
-                # Type:	enum in [‘SHADER’, ‘ENERGY’, ‘NORMAL’, ‘RESULT’], default ‘SHADER’
-
-            # diffuse_shader
-
-                    # LAMBERT Lambert, Use a Lambertian shader.
-                    # OREN_NAYAR Oren-Nayar, Use an Oren-Nayar shader.
-                    # TOON Toon, Use a toon shader.
-                    # MINNAERT Minnaert, Use a Minnaert shader.
-                    # FRESNEL Fresnel, Use a Fresnel shader.
-
-                # Type:	enum in [‘LAMBERT’, ‘OREN_NAYAR’, ‘TOON’, ‘MINNAERT’, ‘FRESNEL’], default ‘LAMBERT’
-
-            # diffuse_toon_size
-
-                # Size of diffuse toon area
-                # Type:	float in [0, 3.14], default 0.0
-
-            # diffuse_toon_smooth
-
-                # Smoothness of diffuse toon area
-                # Type:	float in [0, 1], default 0.0
-
-            # emit
-
-                # Amount of light to emit
-                # Type:	float in [0, inf], default 0.0
-
-            # game_settings
-
-                # Game material settings
-                # Type:	MaterialGameSettings, (readonly, never None)
-
-            # halo
-
-                # Halo settings for the material
-                # Type:	MaterialHalo, (readonly, never None)
-
-            # invert_z
-
-                # Render material’s faces with an inverted Z buffer (scanline only)
-                # Type:	boolean, default False
-
-            # light_group
-
-                # Limit lighting to lamps in this Group
-                # Type:	Group
-
-            # line_color
-
-                # Line color used for Freestyle line rendering
-                # Type:	float array of 4 items in [0, inf], default (0.0, 0.0, 0.0, 0.0)
-
-            # line_priority
-
-                # The line color of a higher priority is used at material boundaries
-                # Type:	int in [0, 32767], default 0
-
-            # mirror_color
-
-                # Mirror color of the material
-                # Type:	float array of 3 items in [0, inf], default (0.0, 0.0, 0.0)
-
-            # node_tree
-
-                # Node tree for node based materials
-                # Type:	NodeTree, (readonly)
-
-            # offset_z
-
-                # Give faces an artificial offset in the Z buffer for Z transparency
-                # Type:	float in [-inf, inf], default 0.0
-
-            # paint_active_slot
-
-                # Index of active texture paint slot
-                # Type:	int in [0, 32767], default 0
-
-            # paint_clone_slot
-
-                # Index of clone texture paint slot
-                # Type:	int in [0, 32767], default 0
-
-            # pass_index
-
-                # Index number for the “Material Index” render pass
-                # Type:	int in [0, 32767], default 0
-
-            # physics
-
-                # Game physics settings
-                # Type:	MaterialPhysics, (readonly, never None)
-
-            # preview_render_type
-
-                # Type of preview render
-
-                    # FLAT Flat, Flat XY plane.
-                    # SPHERE Sphere, Sphere.
-                    # CUBE Cube, Cube.
-                    # MONKEY Monkey, Monkey.
-                    # HAIR Hair, Hair strands.
-                    # SPHERE_A World Sphere, Large sphere with sky.
-
-                # Type:	enum in [‘FLAT’, ‘SPHERE’, ‘CUBE’, ‘MONKEY’, ‘HAIR’, ‘SPHERE_A’], default ‘FLAT’
-
-            # raytrace_mirror
-
-                # Raytraced reflection settings for the material
-                # Type:	MaterialRaytraceMirror, (readonly, never None)
-
-            # raytrace_transparency
-
-                # Raytraced transparency settings for the material
-                # Type:	MaterialRaytraceTransparency, (readonly, never None)
-
-            # roughness
-
-                # Oren-Nayar Roughness
-                # Type:	float in [0, 3.14], default 0.0
-
-            # shadow_buffer_bias
-
-                # Factor to multiply shadow buffer bias with (0 is ignore)
-                # Type:	float in [0, 10], default 0.0
-
-            # shadow_cast_alpha
-
-                # Shadow casting alpha, in use for Irregular and Deep shadow buffer
-                # Type:	float in [0.001, 1], default 0.0
-
-            # shadow_only_type
-
-                # How to draw shadows
-
-                    # SHADOW_ONLY_OLD Shadow and Distance, Old shadow only method.
-                    # SHADOW_ONLY Shadow Only, Improved shadow only method.
-                    # SHADOW_ONLY_SHADED Shadow and Shading, Improved shadow only method which also renders lightless areas as shadows.
-
-                # Type:	enum in [‘SHADOW_ONLY_OLD’, ‘SHADOW_ONLY’, ‘SHADOW_ONLY_SHADED’], default ‘SHADOW_ONLY_OLD’
-
-            # shadow_ray_bias
-
-                # Shadow raytracing bias to prevent terminator problems on shadow boundary
-                # Type:	float in [0, 0.25], default 0.0
-
-
-            # specular_color
-
-                # Specular color of the material
-                # Type:	float array of 3 items in [0, inf], default (0.0, 0.0, 0.0)
-
-            # specular_hardness
-
-                # How hard (sharp) the specular reflection is
-                # Type:	int in [1, 511], default 0
-
-            # specular_intensity
-
-                # How intense (bright) the specular reflection is
-                # Type:	float in [0, 1], default 0.0
-
-            # specular_ior
-
-                # Specular index of refraction
-                # Type:	float in [1, 10], default 0.0
-
-            # specular_ramp
-
-                # Color ramp used to affect specular shading
-                # Type:	ColorRamp, (readonly)
-
-            # specular_ramp_blend
-
-                # Blending method of the ramp and the specular color
-                # Type:	enum in [‘MIX’, ‘ADD’, ‘MULTIPLY’, ‘SUBTRACT’, ‘SCREEN’, ‘DIVIDE’, ‘DIFFERENCE’, ‘DARKEN’, ‘LIGHTEN’, ‘OVERLAY’, ‘DODGE’, ‘BURN’, ‘HUE’, ‘SATURATION’, ‘VALUE’, ‘COLOR’, ‘SOFT_LIGHT’, ‘LINEAR_LIGHT’], default ‘MIX’
-
-            # specular_ramp_factor
-
-                # Blending factor (also uses alpha in Colorband)
-                # Type:	float in [0, 1], default 0.0
-
-            # specular_ramp_input
-
-                # How the ramp maps on the surface
-                # Type:	enum in [‘SHADER’, ‘ENERGY’, ‘NORMAL’, ‘RESULT’], default ‘SHADER’
-            # specular_shader
-
-                    # COOKTORR CookTorr, Use a Cook-Torrance shader.
-                    # PHONG Phong, Use a Phong shader.
-                    # BLINN Blinn, Use a Blinn shader.
-                    # TOON Toon, Use a toon shader.
-                    # WARDISO WardIso, Use a Ward anisotropic shader.
-
-                # Type:	enum in [‘COOKTORR’, ‘PHONG’, ‘BLINN’, ‘TOON’, ‘WARDISO’], default ‘COOKTORR’
-
-            # specular_slope
-
-                # The standard deviation of surface slope
-                # Type:	float in [0, 0.4], default 0.0
-
-            # specular_toon_size
-
-                # Size of specular toon area
-                # Type:	float in [0, 1.53], default 0.0
-
-            # specular_toon_smooth
-
-                # Smoothness of specular toon area
-                # Type:	float in [0, 1], default 0.0
-
-            # strand
-
-                # Strand settings for the material
-                # Type:	MaterialStrand, (readonly, never None)
-
-            # subsurface_scattering
-
-                # Subsurface scattering settings for the material
-                # Type:	MaterialSubsurfaceScattering, (readonly, never None)
-
-            # texture_paint_images
-
-                # Texture images used for texture painting
-                # Type:	bpy_prop_collection of Image, (readonly)
-
-            # texture_paint_slots
-
-                # Texture slots defining the mapping and influence of textures
-                # Type:	bpy_prop_collection of TexPaintSlot, (readonly)
-
-            # texture_slots
-
-                # Texture slots defining the mapping and influence of textures
-                # Type:	MaterialTextureSlots bpy_prop_collection of MaterialTextureSlot, (readonly)
-
-            # translucency
-
-                # Amount of diffuse shading on the back side
-                # Type:	float in [0, 1], default 0.0
-
-            # transparency_method
-
-                # Method to use for rendering transparency
-
-                    # MASK Mask, Mask the background.
-                    # Z_TRANSPARENCY Z Transparency, Use alpha buffer for transparent faces.
-                    # RAYTRACE Raytrace, Use raytracing for transparent refraction rendering.
-
-                # Type:	enum in [‘MASK’, ‘Z_TRANSPARENCY’, ‘RAYTRACE’], default ‘MASK’
-
-            # type
-
-                # Material type defining how the object is rendered
-
-                    # SURFACE Surface, Render object as a surface.
-                    # WIRE Wire, Render the edges of faces as wires (not supported in raytracing).
-                    # VOLUME Volume, Render object as a volume.
-                    # HALO Halo, Render object as halo particles.
-
-                # Type:	enum in [‘SURFACE’, ‘WIRE’, ‘VOLUME’, ‘HALO’], default ‘SURFACE’
-
-            # use_cast_approximate
-
-                # Allow this material to cast shadows when using approximate ambient occlusion
-                # Type:	boolean, default False
-
-            # use_cast_buffer_shadows
-
-                # Allow this material to cast shadows from shadow buffer lamps
-                # Type:	boolean, default False
-
-            # use_cast_shadows
-
-                # Allow this material to cast shadows
-                # Type:	boolean, default False
-
-            # use_cast_shadows_only
-
-                # Make objects with this material appear invisible (not rendered), only casting shadows
-                # Type:	boolean, default False
-
-            # use_cubic
-
-                # Use cubic interpolation for diffuse values, for smoother transitions
-                # Type:	boolean, default False
-
-            # use_diffuse_ramp
-
-                # Toggle diffuse ramp operations
-                # Type:	boolean, default False
-
-            # use_face_texture
-
-                # Replace the object’s base color with color from UV map image textures
-                # Type:	boolean, default False
-
-            # use_face_texture_alpha
-
-                # Replace the object’s base alpha value with alpha from UV map image textures
-                # Type:	boolean, default False
-
-            # use_full_oversampling
-
-                # Force this material to render full shading/textures for all anti-aliasing samples
-                # Type:	boolean, default False
-
-            # use_light_group_exclusive
-
-                # Material uses the light group exclusively - these lamps are excluded from other scene lighting
-                # Type:	boolean, default False
-
-            # use_light_group_local
-
-                # When linked in, material uses local light group with the same name
-                # Type:	boolean, default False
-
-            # use_mist
-
-                # Use mist with this material (in world settings)
-                # Type:	boolean, default False
-
-            # use_nodes
-
-                # Use shader nodes to render the material
-                # Type:	boolean, default False
-
-            # use_object_color
-
-                # Modulate the result with a per-object color
-                # Type:	boolean, default False
-
-            # use_only_shadow
-
-                # Render shadows as the material’s alpha value, making the material transparent except for shadowed areas
-                # Type:	boolean, default False
-
-            # use_ray_shadow_bias
-
-                # Prevent raytraced shadow errors on surfaces with smooth shaded normals (terminator problem)
-                # Type:	boolean, default False
-
-            # use_raytrace
-
-                # Include this material and geometry that uses it in raytracing calculations
-                # Type:	boolean, default False
-
-            # use_shadeless
-
-                # Make this material insensitive to light or shadow
-                # Type:	boolean, default False
-
-            # use_shadows
-
-                # Allow this material to receive shadows
-                # Type:	boolean, default False
-
-            # use_sky
-
-                # Render this material with zero alpha, with sky background in place (scanline only)
-                # Type:	boolean, default False
-
-            # use_specular_ramp
-
-                # Toggle specular ramp operations
-                # Type:	boolean, default False
-
-            # use_tangent_shading
-
-                # Use the material’s tangent vector instead of the normal for shading - for anisotropic shading effects
-                # Type:	boolean, default False
-
-            # use_textures
-
-                # Enable/Disable each texture
-                # Type:	boolean array of 18 items, default (False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
-
-            # use_transparency
-
-                # Render material as transparent
-                # Type:	boolean, default False
-
-            # use_transparent_shadows
-
-                # Allow this object to receive transparent shadows cast through other objects
-                # Type:	boolean, default False
-
-            # use_uv_project
-
-                # Use to ensure UV interpolation is correct for camera projections (use with UV project modifier)
-                # Type:	boolean, default False
-
-            # use_vertex_color_light
-
-                # Add vertex colors as additional lighting
-                # Type:	boolean, default False
-
-            # use_vertex_color_paint
-
-                # Replace object base color with vertex colors (multiply with ‘texture face’ face assigned textures)
-                # Type:	boolean, default False
-
-            # volume
-
-                # Volume settings for the material
-                # Type:	MaterialVolume, (readonly, never None)
-    '''
-    (mat.type in {'SURFACE', 'WIRE', 'VOLUME'})
-     "use_transparency")
-
-
-
-    mat.use_transparency and mat.transparency_method == 'Z_TRANSPARENCY'
-
-
-
-
-            col.prop(mat, "use_raytrace")
-            col.prop(mat, "use_full_oversampling")
-
-            sub.prop(mat, "use_sky")
-
-
-            col.prop(mat, "use_cast_shadows", text="Cast")
-            col.prop(mat, "use_cast_shadows_only", text="Cast Only")
-            col.prop(mat, "use_cast_buffer_shadows")
-
-            sub.active = mat.use_cast_buffer_shadows
-            sub.prop(mat, "shadow_cast_alpha", text="Casting Alpha")
-            col.prop(mat, "use_cast_approximate")
-
-
-
-            col.prop(mat, "diffuse_color", text="")
-
-            sub.active = (not mat.use_shadeless)
-
-            sub.prop(mat, "diffuse_intensity", text="Intensity")
-
-
-            col.prop(mat, "diffuse_shader", text="")
-            col.prop(mat, "use_diffuse_ramp", text="Ramp")
-
-
-            if mat.diffuse_shader == 'OREN_NAYAR':
-                col.prop(mat, "roughness")
-            elif mat.diffuse_shader == 'MINNAERT':
-                col.prop(mat, "darkness")
-            elif mat.diffuse_shader == 'TOON':
-
-                row.prop(mat, "diffuse_toon_size", text="Size")
-                row.prop(mat, "diffuse_toon_smooth", text="Smooth")
-            elif mat.diffuse_shader == 'FRESNEL':
-
-                row.prop(mat, "diffuse_fresnel", text="Fresnel")
-                row.prop(mat, "diffuse_fresnel_factor", text="Factor")
-
-            if mat.use_diffuse_ramp:
-
-                col.template_color_ramp(mat, "diffuse_ramp", expand=True)
-
-
-
-                row.prop(mat, "diffuse_ramp_input", text="Input")
-                row.prop(mat, "diffuse_ramp_blend", text="Blend")
-
-                col.prop(mat, "diffuse_ramp_factor", text="Factor")
-
-
-
-
-            col.prop(mat, "specular_color", text="")
-            col.prop(mat, "specular_intensity", text="Intensity")
-
-            col.prop(mat, "specular_shader", text="")
-            col.prop(mat, "use_specular_ramp", text="Ramp")
-
-            if mat.specular_shader in {'COOKTORR', 'PHONG'}:
-                col.prop(mat, "specular_hardness", text="Hardness")
-            elif mat.specular_shader == 'BLINN':
-
-                row.prop(mat, "specular_hardness", text="Hardness")
-                row.prop(mat, "specular_ior", text="IOR")
-            elif mat.specular_shader == 'WARDISO':
-                col.prop(mat, "specular_slope", text="Slope")
-            elif mat.specular_shader == 'TOON':
-
-                row.prop(mat, "specular_toon_size", text="Size")
-                row.prop(mat, "specular_toon_smooth", text="Smooth")
-
-            if mat.use_specular_ramp:
-                layout.separator()
-                layout.template_color_ramp(mat, "specular_ramp", expand=True)
-                layout.separator()
-
-                row = layout.row()
-                row.prop(mat, "specular_ramp_input", text="Input")
-                row.prop(mat, "specular_ramp_blend", text="Blend")
-
-                layout.prop(mat, "specular_ramp_factor", text="Factor")
-
-
-    class MATERIAL_PT_shading(MaterialButtonsPanel, Panel):
-        bl_label = "Shading"
-        COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
-        @classmethod
-        def poll(cls, context):
-            mat = context.material
-            engine = context.scene.render.engine
-            return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
-
-        def draw(self, context):
-            layout = self.layout
-
-            mat = active_node_mat(context.material)
-
-            if mat.type in {'SURFACE', 'WIRE'}:
-                split = layout.split()
-
-                col = split.column()
-                sub = col.column()
-                sub.active = not mat.use_shadeless
-                sub.prop(mat, "emit")
-                sub.prop(mat, "ambient")
-                sub = col.column()
-                sub.prop(mat, "translucency")
-
-                col = split.column()
-                col.prop(mat, "use_shadeless")
-                sub = col.column()
-                sub.active = not mat.use_shadeless
-                sub.prop(mat, "use_tangent_shading")
-                sub.prop(mat, "use_cubic")
-
-
-    class MATERIAL_PT_transp(MaterialButtonsPanel, Panel):
-        bl_label = "Transparency"
-        COMPAT_ENGINES = {'BLENDER_RENDER'}
-
-        @classmethod
-        def poll(cls, context):
-            mat = context.material
-            engine = context.scene.render.engine
-            return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
-
-        def draw_header(self, context):
-            mat = context.material
-
-            if simple_material(mat):
-                self.layout.prop(mat, "use_transparency", text="")
-
-        def draw(self, context):
-            layout = self.layout
-
-            base_mat = context.material
-            mat = active_node_mat(context.material)
-            rayt = mat.raytrace_transparency
-
-            if simple_material(base_mat):
-                row = layout.row()
-                row.active = mat.use_transparency
-                row.prop(mat, "transparency_method", expand=True)
-
-            split = layout.split()
-            split.active = base_mat.use_transparency
-
-            col = split.column()
-            col.prop(mat, "alpha")
-            row = col.row()
-            row.active = (base_mat.transparency_method != 'MASK') and (not mat.use_shadeless)
-            row.prop(mat, "specular_alpha", text="Specular")
-
-            col = split.column()
-            col.active = (not mat.use_shadeless)
-            col.prop(rayt, "fresnel")
-            sub = col.column()
-            sub.active = (rayt.fresnel > 0.0)
-            sub.prop(rayt, "fresnel_factor", text="Blend")
-
-            if base_mat.transparency_method == 'RAYTRACE':
-                layout.separator()
-                split = layout.split()
-                split.active = base_mat.use_transparency
-
-                col = split.column()
-                col.prop(rayt, "ior")
-                col.prop(rayt, "filter")
-                col.prop(rayt, "falloff")
-                col.prop(rayt, "depth_max")
-                col.prop(rayt, "depth")
-
-                col = split.column()
-                col.label(text="Gloss:")
-                col.prop(rayt, "gloss_factor", text="Amount")
-                sub = col.column()
-                sub.active = rayt.gloss_factor < 1.0
-                sub.prop(rayt, "gloss_threshold", text="Threshold")
-                sub.prop(rayt, "gloss_samples", text="Samples")
-
-
-    class MATERIAL_PT_mirror(MaterialButtonsPanel, Panel):
-        bl_label = "Mirror"
-        bl_options = {'DEFAULT_CLOSED'}
-        COMPAT_ENGINES = {'BLENDER_RENDER'}
-
-        @classmethod
-        def poll(cls, context):
-            mat = context.material
-            engine = context.scene.render.engine
-            return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
-
-        def draw_header(self, context):
-            raym = active_node_mat(context.material).raytrace_mirror
-
-            self.layout.prop(raym, "use", text="")
-
-        def draw(self, context):
-            layout = self.layout
-
-            mat = active_node_mat(context.material)
-            raym = mat.raytrace_mirror
-
-            layout.active = raym.use
-
-            split = layout.split()
-
-            col = split.column()
-            col.prop(raym, "reflect_factor")
-            col.prop(mat, "mirror_color", text="")
-
-            col = split.column()
-            col.prop(raym, "fresnel")
-            sub = col.column()
-            sub.active = (raym.fresnel > 0.0)
-            sub.prop(raym, "fresnel_factor", text="Blend")
-
-            split = layout.split()
-
-            col = split.column()
-            col.separator()
-            col.prop(raym, "depth")
-            col.prop(raym, "distance", text="Max Dist")
-            col.separator()
-            sub = col.split(percentage=0.4)
-            sub.active = (raym.distance > 0.0)
-            sub.label(text="Fade To:")
-            sub.prop(raym, "fade_to", text="")
-
-            col = split.column()
-            col.label(text="Gloss:")
-            col.prop(raym, "gloss_factor", text="Amount")
-            sub = col.column()
-            sub.active = (raym.gloss_factor < 1.0)
-            sub.prop(raym, "gloss_threshold", text="Threshold")
-            sub.prop(raym, "gloss_samples", text="Samples")
-            sub.prop(raym, "gloss_anisotropic", text="Anisotropic")
-
-
-    class MATERIAL_PT_sss(MaterialButtonsPanel, Panel):
-        bl_label = "Subsurface Scattering"
-        bl_options = {'DEFAULT_CLOSED'}
-        COMPAT_ENGINES = {'BLENDER_RENDER'}
-
-        @classmethod
-        def poll(cls, context):
-            mat = context.material
-            engine = context.scene.render.engine
-            return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
-
-        def draw_header(self, context):
-            mat = active_node_mat(context.material)
-            sss = mat.subsurface_scattering
-
-            self.layout.active = (not mat.use_shadeless)
-            self.layout.prop(sss, "use", text="")
-
-        def draw(self, context):
-            layout = self.layout
-
-            mat = active_node_mat(context.material)
-            sss = mat.subsurface_scattering
-
-            layout.active = (sss.use) and (not mat.use_shadeless)
-
-            row = layout.row().split()
-            sub = row.row(align=True).split(align=True, percentage=0.75)
-            sub.menu("MATERIAL_MT_sss_presets", text=bpy.types.MATERIAL_MT_sss_presets.bl_label)
-            sub.operator("material.sss_preset_add", text="", icon='ZOOMIN')
-            sub.operator("material.sss_preset_add", text="", icon='ZOOMOUT').remove_active = True
-
-            split = layout.split()
-
-            col = split.column()
-            col.prop(sss, "ior")
-            col.prop(sss, "scale")
-            col.prop(sss, "color", text="")
-            col.prop(sss, "radius", text="RGB Radius", expand=True)
-
-            col = split.column()
-            sub = col.column(align=True)
-            sub.label(text="Blend:")
-            sub.prop(sss, "color_factor", text="Color")
-            sub.prop(sss, "texture_factor", text="Texture")
-            sub.label(text="Scattering Weight:")
-            sub.prop(sss, "front")
-            sub.prop(sss, "back")
-            col.separator()
-            col.prop(sss, "error_threshold", text="Error")
-
-
-    class MATERIAL_PT_halo(MaterialButtonsPanel, Panel):
-        bl_label = "Halo"
-        COMPAT_ENGINES = {'BLENDER_RENDER'}
-
-        @classmethod
-        def poll(cls, context):
-            mat = context.material
-            engine = context.scene.render.engine
-            return mat and (mat.type == 'HALO') and (engine in cls.COMPAT_ENGINES)
-
-        def draw(self, context):
-            layout = self.layout
-
-            mat = context.material  # don't use node material
-            halo = mat.halo
-
-            def number_but(layout, toggle, number, name, color):
-                row = layout.row(align=True)
-                row.prop(halo, toggle, text="")
-                sub = row.column(align=True)
-                sub.active = getattr(halo, toggle)
-                sub.prop(halo, number, text=name, translate=False)
-                if not color == "":
-                    sub.prop(mat, color, text="")
-
-            split = layout.split()
-
-            col = split.column()
-            col.prop(mat, "alpha")
-            col.prop(mat, "diffuse_color", text="")
-            col.prop(halo, "seed")
-
-            col = split.column()
-            col.prop(halo, "size")
-            col.prop(halo, "hardness")
-            col.prop(halo, "add")
-
-            layout.label(text="Options:")
-
-            split = layout.split()
-            col = split.column()
-            col.prop(halo, "use_texture")
-            col.prop(halo, "use_vertex_normal")
-            col.prop(halo, "use_extreme_alpha")
-            col.prop(halo, "use_shaded")
-            col.prop(halo, "use_soft")
-
-            col = split.column()
-            number_but(col, "use_ring", "ring_count", iface_("Rings"), "mirror_color")
-            number_but(col, "use_lines", "line_count", iface_("Lines"), "specular_color")
-            number_but(col, "use_star", "star_tip_count", iface_("Star Tips"), "")
-
-
-    class MATERIAL_PT_flare(MaterialButtonsPanel, Panel):
-        bl_label = "Flare"
-        COMPAT_ENGINES = {'BLENDER_RENDER'}
-
-        @classmethod
-        def poll(cls, context):
-            mat = context.material
-            engine = context.scene.render.engine
-            return mat and (mat.type == 'HALO') and (engine in cls.COMPAT_ENGINES)
-
-        def draw_header(self, context):
-            halo = context.material.halo
-
-            self.layout.prop(halo, "use_flare_mode", text="")
-
-        def draw(self, context):
-            layout = self.layout
-
-            mat = context.material  # don't use node material
-            halo = mat.halo
-
-            layout.active = halo.use_flare_mode
-
-            split = layout.split()
-
-            col = split.column()
-            col.prop(halo, "flare_size", text="Size")
-            col.prop(halo, "flare_boost", text="Boost")
-            col.prop(halo, "flare_seed", text="Seed")
-
-            col = split.column()
-            col.prop(halo, "flare_subflare_count", text="Subflares")
-            col.prop(halo, "flare_subflare_size", text="Subsize")
-
-    '''
-#######################End Old Blender Internal Props##########################
-###############################################################################
-# Povray Nodes
-###############################################################################
-
-class PovraySocketUniversal(NodeSocket):
-    bl_idname = 'PovraySocketUniversal'
-    bl_label = 'Povray Socket'
-    value_unlimited: bpy.props.FloatProperty(default=0.0)
-    value_0_1: bpy.props.FloatProperty(min=0.0,max=1.0,default=0.0)
-    value_0_10: bpy.props.FloatProperty(min=0.0,max=10.0,default=0.0)
-    value_000001_10: bpy.props.FloatProperty(min=0.000001,max=10.0,default=0.0)
-    value_1_9: bpy.props.IntProperty(min=1,max=9,default=1)
-    value_0_255: bpy.props.IntProperty(min=0,max=255,default=0)
-    percent: bpy.props.FloatProperty(min=0.0,max=100.0,default=0.0)
-    def draw(self, context, layout, node, text):
-        space = context.space_data
-        tree = space.edit_tree
-        links=tree.links
-        if self.is_linked:
-            value=[]
-            for link in links:
-                if link.from_node==node:
-                    inps=link.to_node.inputs
-                    for inp in inps:
-                        if inp.bl_idname=="PovraySocketFloat_0_1" and inp.is_linked:
-                            prop="value_0_1"
-                            if prop not in value:
-                                value.append(prop)
-                        if inp.bl_idname=="PovraySocketFloat_000001_10" and inp.is_linked:
-                            prop="value_000001_10"
-                            if prop not in value:
-                                value.append(prop)
-                        if inp.bl_idname=="PovraySocketFloat_0_10" and inp.is_linked:
-                            prop="value_0_10"
-                            if prop not in value:
-                                value.append(prop)
-                        if inp.bl_idname=="PovraySocketInt_1_9" and inp.is_linked:
-                            prop="value_1_9"
-                            if prop not in value:
-                                value.append(prop)
-                        if inp.bl_idname=="PovraySocketInt_0_255" and inp.is_linked:
-                            prop="value_0_255"
-                            if prop not in value:
-                                value.append(prop)
-                        if inp.bl_idname=="PovraySocketFloatUnlimited" and inp.is_linked:
-                            prop="value_unlimited"
-                            if prop not in value:
-                                value.append(prop)
-            if len(value)==1:
-                layout.prop(self, "%s"%value[0], text=text)
-            else:
-                layout.prop(self, "percent", text="Percent")
-        else:
-            layout.prop(self, "percent", text=text)
-    def draw_color(self, context, node):
-        return (1, 0, 0, 1)
-
-class PovraySocketFloat_0_1(NodeSocket):
-    bl_idname = 'PovraySocketFloat_0_1'
-    bl_label = 'Povray Socket'
-    default_value: bpy.props.FloatProperty(description="Input node Value_0_1",min=0,max=1,default=0)
-    def draw(self, context, layout, node, text):
-        if self.is_linked:
-            layout.label(text)
-        else:
-            layout.prop(self, "default_value", text=text, slider=True)
-
-    def draw_color(self, context, node):
-        return (0.5, 0.7, 0.7, 1)
-
-class PovraySocketFloat_0_10(NodeSocket):
-    bl_idname = 'PovraySocketFloat_0_10'
-    bl_label = 'Povray Socket'
-    default_value: bpy.props.FloatProperty(description="Input node Value_0_10",min=0,max=10,default=0)
-    def draw(self, context, layout, node, text):
-        if node.bl_idname == 'ShaderNormalMapNode' and node.inputs[2].is_linked:
-            layout.label(text='')
-            self.hide_value=True
-        if self.is_linked:
-            layout.label(text)
-        else:
-            layout.prop(self, "default_value", text=text, slider=True)
-    def draw_color(self, context, node):
-        return (0.65, 0.65, 0.65, 1)
-
-class PovraySocketFloat_10(NodeSocket):
-    bl_idname = 'PovraySocketFloat_10'
-    bl_label = 'Povray Socket'
-    default_value: bpy.props.FloatProperty(description="Input node Value_10",min=-10,max=10,default=0)
-    def draw(self, context, layout, node, text):
-        if node.bl_idname == 'ShaderNormalMapNode' and node.inputs[2].is_linked:
-            layout.label(text='')
-            self.hide_value=True
-        if self.is_linked:
-            layout.label(text)
-        else:
-            layout.prop(self, "default_value", text=text, slider=True)
-    def draw_color(self, context, node):
-        return (0.65, 0.65, 0.65, 1)
-
-class PovraySocketFloatPositive(NodeSocket):
-    bl_idname = 'PovraySocketFloatPositive'
-    bl_label = 'Povray Socket'
-    default_value: bpy.props.FloatProperty(description="Input Node Value Positive", min=0.0, default=0)
-    def draw(self, context, layout, node, text):
-        if self.is_linked:
-            layout.label(text)
-        else:
-            layout.prop(self, "default_value", text=text, slider=True)
-    def draw_color(self, context, node):
-        return (0.045, 0.005, 0.136, 1)
-
-class PovraySocketFloat_000001_10(NodeSocket):
-    bl_idname = 'PovraySocketFloat_000001_10'
-    bl_label = 'Povray Socket'
-    default_value: bpy.props.FloatProperty(min=0.000001,max=10,default=0.000001)
-    def draw(self, context, layout, node, text):
-        if self.is_output or self.is_linked:
-            layout.label(text)
-        else:
-            layout.prop(self, "default_value", text=text, slider=True)
-    def draw_color(self, context, node):
-        return (1, 0, 0, 1)
-
-class PovraySocketFloatUnlimited(NodeSocket):
-    bl_idname = 'PovraySocketFloatUnlimited'
-    bl_label = 'Povray Socket'
-    default_value: bpy.props.FloatProperty(default = 0.0)
-    def draw(self, context, layout, node, text):
-        if self.is_linked:
-            layout.label(text)
-        else:
-            layout.prop(self, "default_value", text=text, slider=True)
-    def draw_color(self, context, node):
-        return (0.7, 0.7, 1, 1)
-
-class PovraySocketInt_1_9(NodeSocket):
-    bl_idname = 'PovraySocketInt_1_9'
-    bl_label = 'Povray Socket'
-    default_value: bpy.props.IntProperty(description="Input node Value_1_9",min=1,max=9,default=6)
-    def draw(self, context, layout, node, text):
-        if self.is_linked:
-            layout.label(text)
-        else:
-            layout.prop(self, "default_value", text=text)
-    def draw_color(self, context, node):
-        return (1, 0.7, 0.7, 1)
-
-class PovraySocketInt_0_256(NodeSocket):
-    bl_idname = 'PovraySocketInt_0_256'
-    bl_label = 'Povray Socket'
-    default_value: bpy.props.IntProperty(min=0,max=255,default=0)
-    def draw(self, context, layout, node, text):
-        if self.is_linked:
-            layout.label(text)
-        else:
-            layout.prop(self, "default_value", text=text)
-    def draw_color(self, context, node):
-        return (0.5, 0.5, 0.5, 1)
-
-
-class PovraySocketPattern(NodeSocket):
-    bl_idname = 'PovraySocketPattern'
-    bl_label = 'Povray Socket'
-
-    default_value: bpy.props.EnumProperty(
-            name="Pattern",
-            description="Select the pattern",
-            items=(
-                ('boxed', "Boxed", ""),
-                ('brick', "Brick", ""),
-                ('cells', "Cells", ""),
-                ('checker', "Checker", ""),
-                ('granite', "Granite", ""),
-                ('leopard', "Leopard", ""),
-                ('marble', "Marble", ""),
-                ('onion', "Onion", ""),
-                ('planar', "Planar", ""),
-                ('quilted', "Quilted", ""),
-                ('ripples', "Ripples", ""),
-                ('radial', "Radial", ""),
-                ('spherical', "Spherical", ""),
-                ('spotted', "Spotted", ""),
-                ('waves', "Waves", ""),
-                ('wood', "Wood", ""),
-                ('wrinkles', "Wrinkles", "")
-            ),
-            default='granite')
-
-    def draw(self, context, layout, node, text):
-        if self.is_output or self.is_linked:
-            layout.label(text="Pattern")
-        else:
-            layout.prop(self, "default_value", text=text)
-
-    def draw_color(self, context, node):
-        return (1, 1, 1, 1)
-
-class PovraySocketColor(NodeSocket):
-    bl_idname = 'PovraySocketColor'
-    bl_label = 'Povray Socket'
-
-    default_value: bpy.props.FloatVectorProperty(
-            precision=4, step=0.01, min=0, soft_max=1,
-            default=(0.0, 0.0, 0.0), options={'ANIMATABLE'}, subtype='COLOR')
-
-    def draw(self, context, layout, node, text):
-        if self.is_output or self.is_linked:
-            layout.label(text)
-        else:
-            layout.prop(self, "default_value", text=text)
-
-    def draw_color(self, context, node):
-        return (1, 1, 0, 1)
-
-class PovraySocketColorRGBFT(NodeSocket):
-    bl_idname = 'PovraySocketColorRGBFT'
-    bl_label = 'Povray Socket'
-
-    default_value: bpy.props.FloatVectorProperty(
-            precision=4, step=0.01, min=0, soft_max=1,
-            default=(0.0, 0.0, 0.0), options={'ANIMATABLE'}, subtype='COLOR')
-    f: bpy.props.FloatProperty(default = 0.0,min=0.0,max=1.0)
-    t: bpy.props.FloatProperty(default = 0.0,min=0.0,max=1.0)
-    def draw(self, context, layout, node, text):
-        if self.is_output or self.is_linked:
-            layout.label(text)
-        else:
-            layout.prop(self, "default_value", text=text)
-
-    def draw_color(self, context, node):
-        return (1, 1, 0, 1)
-
-class PovraySocketTexture(NodeSocket):
-    bl_idname = 'PovraySocketTexture'
-    bl_label = 'Povray Socket'
-    default_value: bpy.props.IntProperty()
-    def draw(self, context, layout, node, text):
-        layout.label(text)
-
-    def draw_color(self, context, node):
-        return (0, 1, 0, 1)
-
-
-
-class PovraySocketTransform(NodeSocket):
-    bl_idname = 'PovraySocketTransform'
-    bl_label = 'Povray Socket'
-    default_value: bpy.props.IntProperty(min=0,max=255,default=0)
-    def draw(self, context, layout, node, text):
-        layout.label(text)
-
-    def draw_color(self, context, node):
-        return (99/255, 99/255, 199/255, 1)
-
-class PovraySocketNormal(NodeSocket):
-    bl_idname = 'PovraySocketNormal'
-    bl_label = 'Povray Socket'
-    default_value: bpy.props.IntProperty(min=0,max=255,default=0)
-    def draw(self, context, layout, node, text):
-        layout.label(text)
-
-    def draw_color(self, context, node):
-        return (0.65, 0.65, 0.65, 1)
-
-class PovraySocketSlope(NodeSocket):
-    bl_idname = 'PovraySocketSlope'
-    bl_label = 'Povray Socket'
-    default_value: bpy.props.FloatProperty(min = 0.0, max = 1.0)
-    height: bpy.props.FloatProperty(min = 0.0, max = 10.0)
-    slope: bpy.props.FloatProperty(min = -10.0, max = 10.0)
-    def draw(self, context, layout, node, text):
-        if self.is_output or self.is_linked:
-            layout.label(text)
-        else:
-            layout.prop(self,'default_value',text='')
-            layout.prop(self,'height',text='')
-            layout.prop(self,'slope',text='')
-    def draw_color(self, context, node):
-        return (0, 0, 0, 1)
-
-class PovraySocketMap(NodeSocket):
-    bl_idname = 'PovraySocketMap'
-    bl_label = 'Povray Socket'
-    default_value: bpy.props.StringProperty()
-    def draw(self, context, layout, node, text):
-        layout.label(text)
-    def draw_color(self, context, node):
-        return (0.2, 0, 0.2, 1)
-
-class PovrayShaderNodeCategory(NodeCategory):
-    @classmethod
-    def poll(cls, context):
-        return context.space_data.tree_type == 'ObjectNodeTree'
-
-class PovrayTextureNodeCategory(NodeCategory):
-    @classmethod
-    def poll(cls, context):
-        return context.space_data.tree_type == 'TextureNodeTree'
-
-class PovraySceneNodeCategory(NodeCategory):
-    @classmethod
-    def poll(cls, context):
-        return context.space_data.tree_type == 'CompositorNodeTree'
-
-node_categories = [
-
-    PovrayShaderNodeCategory("SHADEROUTPUT", "Output", items=[
-        NodeItem("PovrayOutputNode"),
-        ]),
-
-    PovrayShaderNodeCategory("SIMPLE", "Simple texture", items=[
-        NodeItem("PovrayTextureNode"),
-        ]),
-
-    PovrayShaderNodeCategory("MAPS", "Maps", items=[
-        NodeItem("PovrayBumpMapNode"),
-        NodeItem("PovrayColorImageNode"),
-        NodeItem("ShaderNormalMapNode"),
-        NodeItem("PovraySlopeNode"),
-        NodeItem("ShaderTextureMapNode"),
-        NodeItem("ShaderNodeValToRGB"),
-        ]),
-
-    PovrayShaderNodeCategory("OTHER", "Other patterns", items=[
-        NodeItem("PovrayImagePatternNode"),
-        NodeItem("ShaderPatternNode"),
-        ]),
-
-    PovrayShaderNodeCategory("COLOR", "Color", items=[
-        NodeItem("PovrayPigmentNode"),
-        ]),
-
-    PovrayShaderNodeCategory("TRANSFORM", "Transform", items=[
-        NodeItem("PovrayMappingNode"),
-        NodeItem("PovrayMultiplyNode"),
-        NodeItem("PovrayModifierNode"),
-        NodeItem("PovrayTransformNode"),
-        NodeItem("PovrayValueNode"),
-        ]),
-
-    PovrayShaderNodeCategory("FINISH", "Finish", items=[
-        NodeItem("PovrayFinishNode"),
-        NodeItem("PovrayDiffuseNode"),
-        NodeItem("PovraySpecularNode"),
-        NodeItem("PovrayPhongNode"),
-        NodeItem("PovrayAmbientNode"),
-        NodeItem("PovrayMirrorNode"),
-        NodeItem("PovrayIridescenceNode"),
-        NodeItem("PovraySubsurfaceNode"),
-        ]),
-
-    PovrayShaderNodeCategory("CYCLES", "Cycles", items=[
-        NodeItem("ShaderNodeAddShader"),
-        NodeItem("ShaderNodeAmbientOcclusion"),
-        NodeItem("ShaderNodeAttribute"),
-        NodeItem("ShaderNodeBackground"),
-        NodeItem("ShaderNodeBlackbody"),
-        NodeItem("ShaderNodeBrightContrast"),
-        NodeItem("ShaderNodeBsdfAnisotropic"),
-        NodeItem("ShaderNodeBsdfDiffuse"),
-        NodeItem("ShaderNodeBsdfGlass"),
-        NodeItem("ShaderNodeBsdfGlossy"),
-        NodeItem("ShaderNodeBsdfHair"),
-        NodeItem("ShaderNodeBsdfRefraction"),
-        NodeItem("ShaderNodeBsdfToon"),
-        NodeItem("ShaderNodeBsdfTranslucent"),
-        NodeItem("ShaderNodeBsdfTransparent"),
-        NodeItem("ShaderNodeBsdfVelvet"),
-        NodeItem("ShaderNodeBump"),
-        NodeItem("ShaderNodeCameraData"),
-        NodeItem("ShaderNodeCombineHSV"),
-        NodeItem("ShaderNodeCombineRGB"),
-        NodeItem("ShaderNodeCombineXYZ"),
-        NodeItem("ShaderNodeEmission"),
-        NodeItem("ShaderNodeExtendedMaterial"),
-        NodeItem("ShaderNodeFresnel"),
-        NodeItem("ShaderNodeGamma"),
-        NodeItem("ShaderNodeGeometry"),
-        NodeItem("ShaderNodeGroup"),
-        NodeItem("ShaderNodeHairInfo"),
-        NodeItem("ShaderNodeHoldout"),
-        NodeItem("ShaderNodeHueSaturation"),
-        NodeItem("ShaderNodeInvert"),
-        NodeItem("ShaderNodeLampData"),
-        NodeItem("ShaderNodeLayerWeight"),
-        NodeItem("ShaderNodeLightFalloff"),
-        NodeItem("ShaderNodeLightPath"),
-        NodeItem("ShaderNodeMapping"),
-        NodeItem("ShaderNodeMaterial"),
-        NodeItem("ShaderNodeMath"),
-        NodeItem("ShaderNodeMixRGB"),
-        NodeItem("ShaderNodeMixShader"),
-        NodeItem("ShaderNodeNewGeometry"),
-        NodeItem("ShaderNodeNormal"),
-        NodeItem("ShaderNodeNormalMap"),
-        NodeItem("ShaderNodeObjectInfo"),
-        NodeItem("ShaderNodeOutput"),
-        NodeItem("ShaderNodeOutputLamp"),
-        NodeItem("ShaderNodeOutputLineStyle"),
-        NodeItem("ShaderNodeOutputMaterial"),
-        NodeItem("ShaderNodeOutputWorld"),
-        NodeItem("ShaderNodeParticleInfo"),
-        NodeItem("ShaderNodeRGB"),
-        NodeItem("ShaderNodeRGBCurve"),
-        NodeItem("ShaderNodeRGBToBW"),
-        NodeItem("ShaderNodeScript"),
-        NodeItem("ShaderNodeSeparateHSV"),
-        NodeItem("ShaderNodeSeparateRGB"),
-        NodeItem("ShaderNodeSeparateXYZ"),
-        NodeItem("ShaderNodeSqueeze"),
-        NodeItem("ShaderNodeSubsurfaceScattering"),
-        NodeItem("ShaderNodeTangent"),
-        NodeItem("ShaderNodeTexBrick"),
-        NodeItem("ShaderNodeTexChecker"),
-        NodeItem("ShaderNodeTexCoord"),
-        NodeItem("ShaderNodeTexEnvironment"),
-        NodeItem("ShaderNodeTexGradient"),
-        NodeItem("ShaderNodeTexImage"),
-        NodeItem("ShaderNodeTexMagic"),
-        NodeItem("ShaderNodeTexMusgrave"),
-        NodeItem("ShaderNodeTexNoise"),
-        NodeItem("ShaderNodeTexPointDensity"),
-        NodeItem("ShaderNodeTexSky"),
-        NodeItem("ShaderNodeTexVoronoi"),
-        NodeItem("ShaderNodeTexWave"),
-        NodeItem("ShaderNodeTexture"),
-        NodeItem("ShaderNodeUVAlongStroke"),
-        NodeItem("ShaderNodeUVMap"),
-        NodeItem("ShaderNodeValToRGB"),
-        NodeItem("ShaderNodeValue"),
-        NodeItem("ShaderNodeVectorCurve"),
-        NodeItem("ShaderNodeVectorMath"),
-        NodeItem("ShaderNodeVectorTransform"),
-        NodeItem("ShaderNodeVolumeAbsorption"),
-        NodeItem("ShaderNodeVolumeScatter"),
-        NodeItem("ShaderNodeWavelength"),
-        NodeItem("ShaderNodeWireframe"),
-        ]),
-
-    PovrayTextureNodeCategory("TEXTUREOUTPUT", "Output", items=[
-        NodeItem("TextureNodeValToRGB"),
-        NodeItem("TextureOutputNode"),
-        ]),
-
-    PovraySceneNodeCategory("ISOSURFACE", "Isosurface", items=[
-        NodeItem("IsoPropsNode"),
-        ]),
-
-    PovraySceneNodeCategory("FOG", "Fog", items=[
-        NodeItem("PovrayFogNode"),
-
-        ]),
-    ]
-############### end nodes
-
-###############################################################################
-# Texture POV properties.
-###############################################################################
-
-class RenderPovSettingsTexture(PropertyGroup):
-    """Declare texture level properties controllable in UI and translated to POV."""
-
-    # former Space properties from removed Blender Internal
-    active_texture_index: IntProperty(
-        name = "Index for texture_slots",
-        min=0,
-        max=17,
-        default=0,
-    )
-
-    use_limited_texture_context: BoolProperty(
-        name="",
-        description="Use the limited version of texture user (for ‘old shading’ mode)",
-        default=True,
-    )
-
-    texture_context: EnumProperty(
-        name="Texture context",
-        description="Type of texture data to display and edit",
-        items=(
-            ('MATERIAL', "", "Show material textures", "MATERIAL",0), # "Show material textures"
-            ('WORLD', "", "Show world textures", "WORLD",1), # "Show world textures"
-            ('LAMP', "", "Show lamp textures", "LIGHT",2), # "Show lamp textures"
-            ('PARTICLES', "", "Show particles textures", "PARTICLES",3), # "Show particles textures"
-            ('LINESTYLE', "", "Show linestyle textures", "LINE_DATA",4), # "Show linestyle textures"
-            ('OTHER', "", "Show other data textures", "TEXTURE_DATA",5), # "Show other data textures"
-        ),
-        default = 'MATERIAL',
-    )
-
-    # Custom texture gamma
-    tex_gamma_enable: BoolProperty(
-        name="Enable custom texture gamma",
-        description="Notify some custom gamma for which texture has been precorrected "
-        "without the file format carrying it and only if it differs from your "
-        "OS expected standard (see pov doc)",
-        default=False,
-    )
-
-    tex_gamma_value: FloatProperty(
-        name="Custom texture gamma",
-        description="value for which the file was issued e.g. a Raw photo is gamma 1.0",
-        min=0.45, max=5.00, soft_min=1.00, soft_max=2.50, default=1.00
-    )
-
-    ##################################CustomPOV Code############################
-    # commented out below if we wanted custom pov code in texture only, inside exported material:
-    # replacement_text = StringProperty(
-    #        name="Declared name:",
-    #        description="Type the declared name in custom POV code or an external .inc "
-    #                    "it points at. pigment {} expected",
-    #        default="")
-
-    tex_pattern_type: EnumProperty(
-        name="Texture_Type",
-        description="Choose between Blender or POV parameters to specify texture",
-        items= (
-            ('agate', 'Agate', '','PLUGIN', 0),
-            ('aoi', 'Aoi', '', 'PLUGIN', 1),
-            ('average', 'Average', '', 'PLUGIN', 2),
-            ('boxed', 'Boxed', '', 'PLUGIN', 3),
-            ('bozo', 'Bozo', '', 'PLUGIN', 4),
-            ('bumps', 'Bumps', '', 'PLUGIN', 5),
-            ('cells', 'Cells', '', 'PLUGIN', 6),
-            ('crackle', 'Crackle', '', 'PLUGIN', 7),
-            ('cubic', 'Cubic', '', 'PLUGIN', 8),
-            ('cylindrical', 'Cylindrical', '', 'PLUGIN', 9),
-            ('density_file', 'Density', '(.df3)', 'PLUGIN', 10),
-            ('dents', 'Dents', '', 'PLUGIN', 11),
-            ('fractal', 'Fractal', '', 'PLUGIN', 12),
-            ('function', 'Function', '', 'PLUGIN', 13),
-            ('gradient', 'Gradient', '', 'PLUGIN', 14),
-            ('granite', 'Granite', '', 'PLUGIN', 15),
-            ('image_pattern', 'Image pattern', '', 'PLUGIN', 16),
-            ('leopard', 'Leopard', '', 'PLUGIN', 17),
-            ('marble', 'Marble', '', 'PLUGIN', 18),
-            ('onion', 'Onion', '', 'PLUGIN', 19),
-            ('pigment_pattern', 'pigment pattern', '', 'PLUGIN', 20),
-            ('planar', 'Planar', '', 'PLUGIN', 21),
-            ('quilted', 'Quilted', '', 'PLUGIN', 22),
-            ('radial', 'Radial', '', 'PLUGIN', 23),
-            ('ripples', 'Ripples', '', 'PLUGIN', 24),
-            ('slope', 'Slope', '', 'PLUGIN', 25),
-            ('spherical', 'Spherical', '', 'PLUGIN', 26),
-            ('spiral1', 'Spiral1', '', 'PLUGIN', 27),
-            ('spiral2', 'Spiral2', '', 'PLUGIN', 28),
-            ('spotted', 'Spotted', '', 'PLUGIN', 29),
-            ('waves', 'Waves', '', 'PLUGIN', 30),
-            ('wood', 'Wood', '', 'PLUGIN', 31),
-            ('wrinkles', 'Wrinkles', '', 'PLUGIN', 32),
-            ('brick', "Brick", "", 'PLUGIN', 33),
-            ('checker', "Checker", "", 'PLUGIN', 34),
-            ('hexagon', "Hexagon", "", 'PLUGIN', 35),
-            ('object', "Mesh", "", 'PLUGIN', 36),
-            ('emulator', "Blender Type Emulator", "", 'SCRIPTPLUGINS', 37)
-        ),
-        default='emulator',
-    )
-
-    magnet_style: EnumProperty(
-        name="Magnet style",
-        description="magnet or julia",
-        items=(('mandel', "Mandelbrot", ""),('julia', "Julia", "")),
-        default='julia',
-    )
-
-    magnet_type: IntProperty(
-        name="Magnet_type",
-        description="1 or 2",
-        min=1,
-        max=2,
-        default=2,
-    )
-
-    warp_types: EnumProperty(
-        name="Warp Types",
-        description="Select the type of warp",
-        items=(('PLANAR', "Planar", ""), ('CUBIC', "Cubic", ""),
-               ('SPHERICAL', "Spherical", ""), ('TOROIDAL', "Toroidal", ""),
-               ('CYLINDRICAL', "Cylindrical", ""), ('NONE', "None", "No indentation")),
-        default='NONE'
-    )
-
-    warp_orientation: EnumProperty(
-        name="Warp Orientation",
-        description="Select the orientation of warp",
-        items=(('x', "X", ""), ('y', "Y", ""), ('z', "Z", "")),
-        default='y',
-    )
-
-    wave_type: EnumProperty(
-        name="Waves type",
-        description="Select the type of waves",
-        items=(('ramp', "Ramp", ""), ('sine', "Sine", ""), ('scallop', "Scallop", ""),
-               ('cubic', "Cubic", ""), ('poly', "Poly", ""), ('triangle', 'Triangle', "")),
-        default='ramp',
-    )
-
-    gen_noise: IntProperty(
-        name="Noise Generators",
-        description="Noise Generators",
-        min=1, max=3, default=1,
-    )
-
-    warp_dist_exp: FloatProperty(
-        name="Distance exponent",
-        description="Distance exponent",
-        min=0.0, max=100.0, default=1.0,
-    )
-
-    warp_tor_major_radius: FloatProperty(
-        name="Major radius",
-        description="Torus is distance from major radius",
-        min=0.0, max=5.0, default=1.0,
-    )
-
-    warp_turbulence_x: FloatProperty(
-        name="Turbulence X",
-        description="Turbulence X",
-        min=0.0, max=5.0, default=0.0,
-    )
-
-    warp_turbulence_y: FloatProperty(
-        name="Turbulence Y",
-        description="Turbulence Y",
-        min=0.0, max=5.0, default=0.0
-    )
-
-    warp_turbulence_z: FloatProperty(
-        name="Turbulence Z",
-        description="Turbulence Z",
-        min=0.0, max=5.0, default=0.0
-    )
-
-    modifier_octaves: IntProperty(
-        name="Turbulence octaves",
-        description="Turbulence octaves",
-        min=1, max=10, default=1
-    )
-
-    modifier_lambda: FloatProperty(
-        name="Turbulence lambda",
-        description="Turbulence lambda",
-        min=0.0, max=5.0, default=1.00
-    )
-
-    modifier_omega: FloatProperty(
-        name="Turbulence omega",
-        description="Turbulence omega",
-        min=0.0, max=10.0, default=1.00
-    )
-
-    modifier_phase: FloatProperty(
-        name="Phase",
-        description="The phase value causes the map entries to be shifted so that the map "
-        "starts and ends at a different place",
-        min=0.0, max=2.0, default=0.0
-    )
-
-    modifier_frequency: FloatProperty(
-        name="Frequency",
-        description="The frequency keyword adjusts the number of times that a color map "
-        "repeats over one cycle of a pattern",
-        min=0.0, max=25.0, default=2.0
-    )
-
-    modifier_turbulence: FloatProperty(
-        name="Turbulence",
-        description="Turbulence",
-        min=0.0, max=5.0, default=2.0
-    )
-
-    modifier_numbers: IntProperty(
-        name="Numbers",
-        description="Numbers",
-        min=1, max=27, default=2
-    )
-
-    modifier_control0: IntProperty(
-        name="Control0",
-        description="Control0",
-        min=0, max=100, default=1
-    )
-
-    modifier_control1: IntProperty(
-        name="Control1",
-        description="Control1",
-        min=0, max=100, default=1
-    )
-
-    brick_size_x: FloatProperty(
-        name="Brick size x",
-        description="",
-        min=0.0000, max=1.0000, default=0.2500
-    )
-
-    brick_size_y: FloatProperty(
-        name="Brick size y",
-        description="",
-        min=0.0000, max=1.0000, default=0.0525
-    )
-
-    brick_size_z: FloatProperty(
-        name="Brick size z",
-        description="",
-        min=0.0000, max=1.0000, default=0.1250
-    )
-
-    brick_mortar: FloatProperty(
-        name="Mortar",
-        description="Mortar",
-        min=0.000, max=1.500, default=0.01
-    )
-
-    julia_complex_1: FloatProperty(
-        name="Julia Complex 1",
-        description="",
-        min=0.000, max=1.500, default=0.360
-    )
-
-    julia_complex_2: FloatProperty(
-        name="Julia Complex 2",
-        description="",
-        min=0.000, max=1.500, default=0.250
-    )
-
-    f_iter: IntProperty(
-        name="Fractal Iteration",
-        description="",
-        min=0, max=100, default=20
-    )
-
-    f_exponent: IntProperty(
-        name="Fractal Exponent",
-        description="",
-        min=2, max=33, default=2
-    )
-
-    f_ior: IntProperty(
-        name="Fractal Interior",
-        description="",
-        min=1, max=6, default=1
-    )
-
-    f_ior_fac: FloatProperty(
-        name="Fractal Interior Factor",
-        description="",
-        min=0.0, max=10.0, default=1.0
-    )
-
-    f_eor: IntProperty(
-        name="Fractal Exterior",
-        description="",
-        min=1, max=8, default=1
-    )
-
-    f_eor_fac: FloatProperty(
-        name="Fractal Exterior Factor",
-        description="",
-        min=0.0, max=10.0, default=1.0
-    )
-
-    grad_orient_x: IntProperty(
-        name="Gradient orientation X",
-        description="",
-        min=0, max=1, default=0
-    )
-
-    grad_orient_y: IntProperty(
-        name="Gradient orientation Y",
-        description="",
-        min=0, max=1, default=1
-    )
-
-    grad_orient_z: IntProperty(
-        name="Gradient orientation Z",
-        description="",
-        min=0, max=1, default=0
-    )
-
-    pave_sides: EnumProperty(
-        name="Pavement sides",
-        description="",
-        items=(
-            ('3', "3", ""),
-            ('4', "4", ""),
-            ('6', "6", "")
-        ),
-        default='3'
-    )
-
-    pave_pat_2: IntProperty(
-        name="Pavement pattern 2",
-        description="maximum: 2",
-        min=1, max=2, default=2
-    )
-
-    pave_pat_3: IntProperty(
-        name="Pavement pattern 3",
-        description="maximum: 3",
-        min=1, max=3, default=3
-    )
-
-    pave_pat_4: IntProperty(
-        name="Pavement pattern 4",
-        description="maximum: 4",
-        min=1, max=4, default=4
-    )
-
-    pave_pat_5: IntProperty(
-        name="Pavement pattern 5",
-        description="maximum: 5",
-        min=1, max=5, default=5
-    )
-
-    pave_pat_7: IntProperty(
-        name="Pavement pattern 7",
-        description="maximum: 7",
-        min=1, max=7, default=7
-    )
-
-    pave_pat_12: IntProperty(
-        name="Pavement pattern 12",
-        description="maximum: 12",
-        min=1, max=12, default=12
-    )
-
-    pave_pat_22: IntProperty(
-        name="Pavement pattern 22",
-        description="maximum: 22",
-        min=1, max=22, default=22
-    )
-
-    pave_pat_35: IntProperty(
-        name="Pavement pattern 35",
-        description="maximum: 35",
-        min=1, max=35, default=35,
-    )
-
-    pave_tiles: IntProperty(
-        name="Pavement tiles",
-        description="If sides = 6, maximum tiles 5!!!",
-        min=1, max=6, default=1
-    )
-
-    pave_form: IntProperty(
-        name="Pavement form",
-        description="",
-        min=0, max=4, default=0
-    )
-
-    #########FUNCTIONS#############################################################################
-    #########FUNCTIONS#############################################################################
-
-    func_list: EnumProperty(
-        name="Functions",
-        description="Select the function for create pattern",
-        items=(
-            ('NONE', "None", "No indentation"),
-            ("f_algbr_cyl1","Algbr cyl1",""), ("f_algbr_cyl2","Algbr cyl2",""),
-            ("f_algbr_cyl3","Algbr cyl3",""), ("f_algbr_cyl4","Algbr cyl4",""),
-            ("f_bicorn","Bicorn",""), ("f_bifolia","Bifolia",""),
-            ("f_blob","Blob",""), ("f_blob2","Blob2",""),
-            ("f_boy_surface","Boy surface",""), ("f_comma","Comma",""),
-            ("f_cross_ellipsoids","Cross ellipsoids",""),
-            ("f_crossed_trough","Crossed trough",""), ("f_cubic_saddle","Cubic saddle",""),
-            ("f_cushion","Cushion",""), ("f_devils_curve","Devils curve",""),
-            ("f_devils_curve_2d","Devils curve 2d",""),
-            ("f_dupin_cyclid","Dupin cyclid",""), ("f_ellipsoid","Ellipsoid",""),
-            ("f_enneper","Enneper",""), ("f_flange_cover","Flange cover",""),
-            ("f_folium_surface","Folium surface",""),
-            ("f_folium_surface_2d","Folium surface 2d",""), ("f_glob","Glob",""),
-            ("f_heart","Heart",""), ("f_helical_torus","Helical torus",""),
-            ("f_helix1","Helix1",""), ("f_helix2","Helix2",""), ("f_hex_x","Hex x",""),
-            ("f_hex_y","Hex y",""), ("f_hetero_mf","Hetero mf",""),
-            ("f_hunt_surface","Hunt surface",""),
-            ("f_hyperbolic_torus","Hyperbolic torus",""),
-            ("f_isect_ellipsoids","Isect ellipsoids",""),
-            ("f_kampyle_of_eudoxus","Kampyle of eudoxus",""),
-            ("f_kampyle_of_eudoxus_2d","Kampyle of eudoxus 2d",""),
-            ("f_klein_bottle","Klein bottle",""),
-            ("f_kummer_surface_v1","Kummer surface v1",""),
-            ("f_kummer_surface_v2","Kummer surface v2",""),
-            ("f_lemniscate_of_gerono","Lemniscate of gerono",""),
-            ("f_lemniscate_of_gerono_2d","Lemniscate of gerono 2d",""),
-            ("f_mesh1","Mesh1",""), ("f_mitre","Mitre",""),
-            ("f_nodal_cubic","Nodal cubic",""), ("f_noise3d","Noise3d",""),
-            ("f_noise_generator","Noise generator",""), ("f_odd","Odd",""),
-            ("f_ovals_of_cassini","Ovals of cassini",""), ("f_paraboloid","Paraboloid",""),
-            ("f_parabolic_torus","Parabolic torus",""), ("f_ph","Ph",""),
-            ("f_pillow","Pillow",""), ("f_piriform","Piriform",""),
-            ("f_piriform_2d","Piriform 2d",""), ("f_poly4","Poly4",""),
-            ("f_polytubes","Polytubes",""), ("f_quantum","Quantum",""),
-            ("f_quartic_paraboloid","Quartic paraboloid",""),
-            ("f_quartic_saddle","Quartic saddle",""),
-            ("f_quartic_cylinder","Quartic cylinder",""), ("f_r","R",""),
-            ("f_ridge","Ridge",""), ("f_ridged_mf","Ridged mf",""),
-            ("f_rounded_box","Rounded box",""), ("f_sphere","Sphere",""),
-            ("f_spikes","Spikes",""), ("f_spikes_2d","Spikes 2d",""),
-            ("f_spiral","Spiral",""), ("f_steiners_roman","Steiners roman",""),
-            ("f_strophoid","Strophoid",""), ("f_strophoid_2d","Strophoid 2d",""),
-            ("f_superellipsoid","Superellipsoid",""), ("f_th","Th",""),
-            ("f_torus","Torus",""), ("f_torus2","Torus2",""),
-            ("f_torus_gumdrop","Torus gumdrop",""), ("f_umbrella","Umbrella",""),
-            ("f_witch_of_agnesi","Witch of agnesi",""),
-            ("f_witch_of_agnesi_2d","Witch of agnesi 2d","")
-        ),
-
-        default='NONE',
-    )
-
-    func_x: FloatProperty(
-        name="FX",
-        description="",
-        min=0.0, max=25.0, default=1.0
-    )
-
-    func_plus_x: EnumProperty(
-        name="Func plus x",
-        description="",
-        items=(('NONE', "None", ""), ('increase', "*", ""), ('plus', "+", "")),
-        default='NONE',
-    )
-
-    func_y: FloatProperty(
-        name="FY",
-        description="",
-        min=0.0, max=25.0, default=1.0
-    )
-
-    func_plus_y: EnumProperty(
-        name="Func plus y",
-        description="",
-        items=(('NONE', "None", ""), ('increase', "*", ""), ('plus', "+", "")),
-        default='NONE',
-    )
-
-    func_z: FloatProperty(
-        name="FZ",
-        description="",
-        min=0.0, max=25.0, default=1.0
-    )
-
-    func_plus_z: EnumProperty(
-        name="Func plus z",
-        description="",
-        items=(
-            ('NONE', "None", ""),
-            ('increase', "*", ""),
-            ('plus', "+", "")
-        ),
-        default='NONE',
-    )
-
-    func_P0: FloatProperty(
-        name="P0",
-        description="",
-        min=0.0, max=25.0, default=1.0
-    )
-
-    func_P1: FloatProperty(
-        name="P1",
-        description="",
-        min=0.0, max=25.0, default=1.0
-    )
-
-    func_P2: FloatProperty(
-        name="P2",
-        description="",
-        min=0.0, max=25.0, default=1.0
-    )
-
-    func_P3: FloatProperty(
-        name="P3",
-        description="",
-        min=0.0, max=25.0, default=1.0
-    )
-
-    func_P4: FloatProperty(
-        name="P4",
-        description="",
-        min=0.0, max=25.0, default=1.0
-    )
-
-    func_P5: FloatProperty(
-        name="P5",
-        description="",
-        min=0.0, max=25.0, default=1.0
-    )
-
-    func_P6: FloatProperty(
-        name="P6",
-        description="",
-        min=0.0, max=25.0, default=1.0
-    )
-
-    func_P7: FloatProperty(
-        name="P7",
-        description="",
-        min=0.0, max=25.0, default=1.0
-    )
-
-    func_P8: FloatProperty(
-        name="P8",
-        description="",
-        min=0.0, max=25.0, default=1.0
-    )
-
-    func_P9: FloatProperty(
-        name="P9",
-        description="",
-        min=0.0, max=25.0, default=1.0
-    )
-
-    #########################################
-    tex_rot_x: FloatProperty(
-        name="Rotate X",
-        description="",
-        min=-180.0, max=180.0, default=0.0
-    )
-
-    tex_rot_y: FloatProperty(
-        name="Rotate Y",
-        description="",
-        min=-180.0, max=180.0, default=0.0
-    )
-
-    tex_rot_z: FloatProperty(
-        name="Rotate Z",
-        description="",
-        min=-180.0, max=180.0, default=0.0
-    )
-
-    tex_mov_x: FloatProperty(
-        name="Move X",
-        description="",
-        min=-100000.0, max=100000.0, default=0.0
-    )
-
-    tex_mov_y: FloatProperty(
-        name="Move Y",
-        description="",
-        min=-100000.0,
-        max=100000.0,
-        default=0.0,
-    )
-
-    tex_mov_z: FloatProperty(
-        name="Move Z",
-        description="",
-        min=-100000.0,
-        max=100000.0,
-        default=0.0,
-    )
-
-    tex_scale_x: FloatProperty(
-        name="Scale X",
-        description="",
-        min=0.0,
-        max=10000.0,
-        default=1.0,
-    )
-
-    tex_scale_y: FloatProperty(
-        name="Scale Y",
-        description="",
-        min=0.0,
-        max=10000.0,
-        default=1.0,
-    )
-
-    tex_scale_z: FloatProperty(
-        name="Scale Z",
-        description="",
-        min=0.0,
-        max=10000.0,
-        default=1.0,
-    )
-
-###############################################################################
-# Object POV properties.
-###############################################################################
-
-class RenderPovSettingsObject(PropertyGroup):
-    """Declare object and primitives level properties controllable in UI and translated to POV."""
-
-    # Pov inside_vector used for CSG
-    inside_vector: FloatVectorProperty(
-        name="CSG Inside Vector",
-        description="Direction to shoot CSG inside test rays at",
-        precision=4,
-        step=0.01,
-        min=0,
-        soft_max=1,
-        default=(0.001, 0.001, 0.5),
-        options={'ANIMATABLE'},
-        subtype='XYZ'
-    )
-
-    # Importance sampling
-    importance_value: FloatProperty(
-        name="Radiosity Importance",
-        description="Priority value relative to other objects for sampling radiosity rays. "
-        "Increase to get more radiosity rays at comparatively small yet "
-        "bright objects",
-        min=0.01, max=1.00, default=0.50
-    )
-
-    # Collect photons
-    collect_photons: BoolProperty(
-        name="Receive Photon Caustics",
-        description="Enable object to collect photons from other objects caustics. Turn "
-        "off for objects that don't really need to receive caustics (e.g. objects"
-        " that generate caustics often don't need to show any on themselves)",
-        default=True,
-    )
-
-    # Photons spacing_multiplier
-    spacing_multiplier: FloatProperty(
-        name="Photons Spacing Multiplier",
-        description="Multiplier value relative to global spacing of photons. "
-        "Decrease by half to get 4x more photons at surface of "
-        "this object (or 8x media photons than specified in the globals",
-        min=0.01, max=1.00, default=1.00)
-
-    ##################################CustomPOV Code############################
-    # Only DUMMIES below for now:
-    replacement_text: StringProperty(
-        name="Declared name:",
-        description="Type the declared name in custom POV code or an external .inc "
-        "it points at. Any POV shape expected e.g: isosurface {}",
-        default="",
-    )
-
-    #############POV specific object properties.############################
-    object_as: StringProperty(maxlen=1024)
-
-    imported_loc: FloatVectorProperty(
-        name="Imported Pov location",
-        precision=6,
-        default=(0.0, 0.0, 0.0),
-    )
-
-    imported_loc_cap: FloatVectorProperty(
-        name="Imported Pov location",
-        precision=6,
-        default=(0.0, 0.0, 2.0),
-    )
-
-    unlock_parameters: BoolProperty(name="Lock",default = False)
-
-    # not in UI yet but used for sor (lathe) / prism... pov primitives
-    curveshape: EnumProperty(
-        name="Povray Shape Type",
-        items=(("birail", "Birail", ""),
-               ("cairo", "Cairo", ""),
-               ("lathe", "Lathe", ""),
-               ("loft", "Loft", ""),
-               ("prism", "Prism", ""),
-               ("sphere_sweep", "Sphere Sweep", "")),
-        default="sphere_sweep",
-    )
-
-    mesh_write_as: EnumProperty(
-        name="Mesh Write As",
-        items=(("blobgrid", "Blob Grid", ""),
-               ("grid", "Grid", ""),
-               ("mesh", "Mesh", "")),
-        default="mesh",
-    )
-
-    object_ior: FloatProperty(
-        name="IOR", description="IOR",
-        min=1.0, max=10.0,default=1.0
-    )
-
-    # shape_as_light = StringProperty(name="Light",maxlen=1024)
-    # fake_caustics_power = FloatProperty(
-            # name="Power", description="Fake caustics power",
-            # min=0.0, max=10.0,default=0.0)
-    # target = BoolProperty(name="Target",description="",default=False)
-    # target_value = FloatProperty(
-            # name="Value", description="",
-            # min=0.0, max=1.0,default=1.0)
-    # refraction = BoolProperty(name="Refraction",description="",default=False)
-    # dispersion = BoolProperty(name="Dispersion",description="",default=False)
-    # dispersion_value = FloatProperty(
-            # name="Dispersion", description="Good values are 1.01 to 1.1. ",
-            # min=1.0, max=1.2,default=1.01)
-    # dispersion_samples = IntProperty(name="Samples",min=2, max=100,default=7)
-    # reflection = BoolProperty(name="Reflection",description="",default=False)
-    # pass_through = BoolProperty(name="Pass through",description="",default=False)
-    no_shadow: BoolProperty(name="No Shadow",default=False)
-
-    no_image: BoolProperty(name="No Image",default=False)
-
-    no_reflection: BoolProperty(name="No Reflection",default=False)
-
-    no_radiosity: BoolProperty(name="No Radiosity",default=False)
-
-    inverse: BoolProperty(name="Inverse",default=False)
-
-    sturm: BoolProperty(name="Sturm",default=False)
-
-    double_illuminate: BoolProperty(name="Double Illuminate",default=False)
-
-    hierarchy: BoolProperty(name="Hierarchy",default=False)
-
-    hollow: BoolProperty(name="Hollow",default=False)
-
-    boundorclip: EnumProperty(
-        name="Boundorclip",
-        items=(("none", "None", ""),
-               ("bounded_by", "Bounded_by", ""),
-               ("clipped_by", "Clipped_by", "")),
-        default="none",
-    )
-
-    boundorclipob: StringProperty(maxlen=1024)
-
-    addboundorclip: BoolProperty(description="",default=False)
-
-    blob_threshold: FloatProperty(name="Threshold",min=0.00, max=10.0, default=0.6)
-
-    blob_strength: FloatProperty(name="Strength",min=-10.00, max=10.0, default=1.00)
-
-    res_u: IntProperty(name="U",min=100, max=1000, default=500)
-
-    res_v: IntProperty(name="V",min=100, max=1000, default=500)
-
-    contained_by: EnumProperty(
-        name="Contained by",
-        items=(("box", "Box", ""),
-               ("sphere", "Sphere", "")),
-        default="box",
-    )
-
-    container_scale: FloatProperty(name="Container Scale",min=0.0, max=10.0, default=1.00)
-
-    threshold: FloatProperty(name="Threshold",min=0.0, max=10.0, default=0.00)
-
-    accuracy: FloatProperty(name="Accuracy",min=0.0001, max=0.1, default=0.001)
-
-    max_gradient: FloatProperty(name="Max Gradient",min=0.0, max=100.0, default=5.0)
-
-    all_intersections: BoolProperty(name="All Intersections",default=False)
-
-    max_trace: IntProperty(name="Max Trace",min=1, max=100,default=1)
-
-
-    def prop_update_cylinder(self, context):
-        """Update POV cylinder primitive parameters not only at creation but anytime they are changed in UI."""
-        if bpy.ops.pov.cylinder_update.poll():
-            bpy.ops.pov.cylinder_update()
-
-    cylinder_radius: FloatProperty(
-        name="Cylinder R",min=0.00, max=10.0, default=0.04, update=prop_update_cylinder)
-
-    cylinder_location_cap: FloatVectorProperty(
-        name="Cylinder Cap Location", subtype='TRANSLATION',
-        description="The position of the 'other' end of the cylinder (relative to object location)",
-        default=(0.0, 0.0, 2.0), update=prop_update_cylinder
-    )
-
-    imported_cyl_loc: FloatVectorProperty(
-        name="Imported Pov location",
-        precision=6,
-        default=(0.0, 0.0, 0.0)
-    )
-
-    imported_cyl_loc_cap: FloatVectorProperty(
-        name="Imported Pov location",
-        precision=6,
-        default=(0.0, 0.0, 2.0)
-    )
-
-    def prop_update_sphere(self, context):
-
-        """Update POV sphere primitive parameters not only at creation but anytime they are changed in UI."""
-
-        bpy.ops.pov.sphere_update()
-
-    sphere_radius: FloatProperty(
-        name="Sphere radius",min=0.00, max=10.0, default=0.5, update=prop_update_sphere)
-
-    def prop_update_cone(self, context):
-
-        """Update POV cone primitive parameters not only at creation but anytime they are changed in UI."""
-
-        bpy.ops.pov.cone_update()
-
-    cone_base_radius: FloatProperty(
-        name = "Base radius",
-        description = "The first radius of the cone",
-        default = 1.0, min = 0.01, max = 100.0, update=prop_update_cone
-    )
-
-    cone_cap_radius: FloatProperty(
-        name = "Cap radius",
-        description = "The second radius of the cone",
-        default = 0.3, min = 0.0, max = 100.0, update=prop_update_cone
-    )
-
-    cone_segments: IntProperty(
-        name = "Segments",
-        description = "Radial segmentation of proxy mesh",
-        default = 16, min = 3, max = 265, update=prop_update_cone
-    )
-
-    cone_height: FloatProperty(
-        name = "Height",
-        description = "Height of the cone",
-        default = 2.0, min = 0.01, max = 100.0, update=prop_update_cone
-    )
-
-    cone_base_z: FloatProperty()
-
-    cone_cap_z: FloatProperty()
-
-###########Parametric
-    def prop_update_parametric(self, context):
-
-        """Update POV parametric surface primitive parameters not only at creation but anytime they are changed in UI."""
-
-        bpy.ops.pov.parametric_update()
-
-    u_min: FloatProperty(
-        name = "U Min",
-        description = "",
-        default = 0.0, update=prop_update_parametric
-    )
-
-    v_min: FloatProperty(
-        name = "V Min",
-        description = "",
-        default = 0.0,
-        update=prop_update_parametric
-    )
-
-    u_max: FloatProperty(
-        name = "U Max",
-        description = "",
-        default = 6.28,
-        update=prop_update_parametric
-    )
-
-    v_max: FloatProperty(
-        name = "V Max",
-        description = "",
-        default = 12.57, update=prop_update_parametric
-    )
-
-    x_eq: StringProperty(
-        maxlen=1024,
-        default = "cos(v)*(1+cos(u))*sin(v/8)",
-        update=prop_update_parametric
-    )
-
-    y_eq: StringProperty(
-        maxlen=1024,
-        default = "sin(u)*sin(v/8)+cos(v/8)*1.5",
-        update=prop_update_parametric
-    )
-
-    z_eq: StringProperty(
-        maxlen=1024,
-        default = "sin(v)*(1+cos(u))*sin(v/8)",
-        update=prop_update_parametric
-    )
-
-    ###########Torus
-
-    def prop_update_torus(self, context):
-
-        """Update POV torus primitive parameters not only at creation but anytime they are changed in UI."""
-
-        bpy.ops.pov.torus_update()
-
-    torus_major_segments: IntProperty(
-        name = "Segments",
-        description = "Radial segmentation of proxy mesh",
-        default = 48, min = 3, max = 720, update=prop_update_torus
-    )
-
-    torus_minor_segments: IntProperty(
-        name = "Segments",
-        description = "Cross-section segmentation of proxy mesh",
-        default = 12, min = 3, max = 720, update=prop_update_torus
-    )
-
-    torus_major_radius: FloatProperty(
-        name="Major radius",
-        description="Major radius",
-        min=0.00, max=100.00, default=1.0, update=prop_update_torus
-    )
-
-    torus_minor_radius: FloatProperty(
-        name="Minor radius",
-        description="Minor radius",
-        min=0.00, max=100.00, default=0.25, update=prop_update_torus
-    )
-
-
-    ###########Rainbow
-    arc_angle: FloatProperty(
-        name = "Arc angle",
-        description = "The angle of the raynbow arc in degrees",
-        default = 360, min = 0.01, max = 360.0
-    )
-
-    falloff_angle: FloatProperty(
-        name = "Falloff angle",
-        description = "The angle after which rainbow dissolves into background",
-        default = 360, min = 0.0, max = 360
-    )
-
-    ###########HeightFields
-
-    quality: IntProperty(
-        name = "Quality",
-        description = "",
-        default = 100, min = 1, max = 100
-    )
-
-    hf_filename: StringProperty(maxlen = 1024)
-
-    hf_gamma: FloatProperty(
-        name="Gamma",
-        description="Gamma",
-        min=0.0001, max=20.0, default=1.0
-    )
-
-    hf_premultiplied: BoolProperty(
-        name="Premultiplied",
-        description="Premultiplied",
-        default=True,
-    )
-
-    hf_smooth: BoolProperty(
-        name="Smooth",
-        description="Smooth",
-        default=False,
-    )
-
-    hf_water: FloatProperty(
-        name="Water Level",
-        description="Wather Level",
-        min=0.00, max=1.00, default=0.0,
-    )
-
-    hf_hierarchy: BoolProperty(
-        name="Hierarchy",
-        description="Height field hierarchy",
-        default=True,
-    )
-
-    ##############Superellipsoid
-    def prop_update_superellipsoid(self, context):
-
-        """Update POV superellipsoid primitive parameters not only at creation but anytime they are changed in UI."""
-
-        bpy.ops.pov.superellipsoid_update()
-
-    se_param1: FloatProperty(
-        name="Parameter 1",
-        description="",
-        min=0.00, max=10.0, default=0.04
-    )
-
-    se_param2: FloatProperty(
-        name="Parameter 2",
-        description="",
-        min=0.00, max=10.0, default=0.04
-    )
-
-    se_u: IntProperty(
-        name = "U-segments",
-        description = "radial segmentation",
-        default = 20, min = 4, max = 265,
-        update=prop_update_superellipsoid
-    )
-
-    se_v: IntProperty(
-        name = "V-segments",
-        description = "lateral segmentation",
-        default = 20, min = 4, max = 265,
-        update=prop_update_superellipsoid
-    )
-
-    se_n1: FloatProperty(
-        name = "Ring manipulator",
-        description = "Manipulates the shape of the Ring",
-        default = 1.0, min = 0.01, max = 100.0,
-        update=prop_update_superellipsoid
-    )
-
-    se_n2: FloatProperty(name = "Cross manipulator",
-        description = "Manipulates the shape of the cross-section",
-        default = 1.0, min = 0.01, max = 100.0,
-        update=prop_update_superellipsoid
-    )
-
-    se_edit: EnumProperty(items=[("NOTHING", "Nothing", ""),
-                                ("NGONS", "N-Gons", ""),
-                                ("TRIANGLES", "Triangles", "")],
-        name="Fill up and down",
-        description="",
-        default='TRIANGLES',
-        update=prop_update_superellipsoid
-    )
-
-    #############Used for loft and Superellipsoid, etc.
-    curveshape: EnumProperty(
-        name="Povray Shape Type",
-        items=(
-            ("birail", "Birail", ""),
-            ("cairo", "Cairo", ""),
-            ("lathe", "Lathe", ""),
-            ("loft", "Loft", ""),
-            ("prism", "Prism", ""),
-            ("sphere_sweep", "Sphere Sweep", ""),
-            ("sor", "Surface of Revolution", "")
-        ),
-        default="sphere_sweep",
-    )
-
-#############Supertorus
-    def prop_update_supertorus(self, context):
-
-        """Update POV supertorus primitive parameters not only at creation but anytime they are changed in UI."""
-
-        bpy.ops.pov.supertorus_update()
-
-    st_major_radius: FloatProperty(
-        name="Major radius",
-        description="Major radius",
-        min=0.00,
-        max=100.00,
-        default=1.0,
-        update=prop_update_supertorus
-    )
-
-    st_minor_radius: FloatProperty(
-        name="Minor radius",
-        description="Minor radius",
-        min=0.00, max=100.00, default=0.25,
-        update=prop_update_supertorus
-    )
-
-    st_ring: FloatProperty(
-        name="Ring",
-        description="Ring manipulator",
-        min=0.0001, max=100.00, default=1.00,
-        update=prop_update_supertorus
-    )
-
-    st_cross: FloatProperty(
-        name="Cross",
-        description="Cross manipulator",
-        min=0.0001, max=100.00, default=1.00,
-        update=prop_update_supertorus
-    )
-
-    st_accuracy: FloatProperty(
-        name="Accuracy",
-        description="Supertorus accuracy",
-        min=0.00001, max=1.00, default=0.001
-    )
-
-    st_max_gradient: FloatProperty(
-        name="Gradient",
-        description="Max gradient",
-        min=0.0001, max=100.00, default=10.00,
-        update=prop_update_supertorus
-    )
-
-    st_R: FloatProperty(
-        name = "big radius",
-        description = "The radius inside the tube",
-        default = 1.0, min = 0.01, max = 100.0,
-        update=prop_update_supertorus
-    )
-
-    st_r: FloatProperty(
-        name = "small radius",
-        description = "The radius of the tube",
-        default = 0.3, min = 0.01, max = 100.0,
-        update=prop_update_supertorus
-    )
-
-    st_u: IntProperty(
-        name = "U-segments",
-        description = "radial segmentation",
-        default = 16, min = 3, max = 265,
-        update=prop_update_supertorus
-    )
-
-    st_v: IntProperty(
-        name = "V-segments",
-        description = "lateral segmentation",
-        default = 8, min = 3, max = 265,
-        update=prop_update_supertorus
-    )
-
-    st_n1: FloatProperty(
-        name = "Ring manipulator",
-        description = "Manipulates the shape of the Ring",
-        default = 1.0, min = 0.01, max = 100.0,
-        update=prop_update_supertorus
-    )
-
-    st_n2: FloatProperty(
-        name = "Cross manipulator",
-        description = "Manipulates the shape of the cross-section",
-        default = 1.0, min = 0.01, max = 100.0,
-        update=prop_update_supertorus
-    )
-
-    st_ie: BoolProperty(
-        name = "Use Int.+Ext. radii",
-        description = "Use internal and external radii",
-        default = False,
-        update=prop_update_supertorus
-    )
-
-    st_edit: BoolProperty(
-        name="",
-        description="",
-        default=False,
-        options={'HIDDEN'},
-        update=prop_update_supertorus
-    )
-
-    ########################Loft
-    loft_n: IntProperty(
-        name = "Segments",
-        description = "Vertical segments",
-        default = 16, min = 3, max = 720
-    )
-
-    loft_rings_bottom: IntProperty(
-        name = "Bottom",
-        description = "Bottom rings",
-        default = 5, min = 2, max = 100
-    )
-
-    loft_rings_side: IntProperty(
-        name = "Side",
-        description = "Side rings",
-        default = 10, min = 2, max = 100
-    )
-
-    loft_thick: FloatProperty(
-        name = "Thickness",
-        description = "Manipulates the shape of the Ring",
-        default = 0.3, min = 0.01, max = 1.0
-    )
-
-    loft_r: FloatProperty(
-        name = "Radius",
-        description = "Radius",
-        default = 1, min = 0.01, max = 10
-    )
-
-    loft_height: FloatProperty(
-        name = "Height",
-        description = "Manipulates the shape of the Ring",
-        default = 2, min = 0.01, max = 10.0
-    )
-
-    ###################Prism
-    prism_n: IntProperty(
-        name = "Sides",
-        description = "Number of sides",
-        default = 5, min = 3, max = 720
-    )
-
-    prism_r: FloatProperty(
-        name = "Radius",
-        description = "Radius",
-        default = 1.0
-    )
-
-    ##################Isosurface
-    iso_function_text: StringProperty(
-        name="Function Text",
-        maxlen=1024
-    ) #,update=iso_props_update_callback)
-
-    ##################PolygonToCircle
-    polytocircle_resolution: IntProperty(
-        name = "Resolution",
-        description = "",
-        default = 3, min = 0, max = 256
-    )
-
-    polytocircle_ngon: IntProperty(
-        name = "NGon",
-        description = "",
-        min = 3, max = 64,default = 5
-    )
-
-    polytocircle_ngonR: FloatProperty(
-        name = "NGon Radius",
-        description = "",
-        default = 0.3
-    )
-
-    polytocircle_circleR: FloatProperty(
-        name = "Circle Radius",
-        description = "",
-        default = 1.0
-    )
-
-
-###############################################################################
-# Modifiers POV properties.
-###############################################################################
-# class RenderPovSettingsModifier(PropertyGroup):
-    boolean_mod: EnumProperty(
-        name="Operation",
-        description="Choose the type of calculation for Boolean modifier",
-        items=(
-            ("BMESH", "Use the BMesh Boolean Solver", ""),
-            ("CARVE", "Use the Carve Boolean Solver", ""),
-            ("POV", "Use POV Constructive Solid Geometry", "")
-        ),
-        default="BMESH",
-    )
-
-    #################Avogadro
-    # filename_ext = ".png"
-
-    # filter_glob = StringProperty(
-            # default="*.exr;*.gif;*.hdr;*.iff;*.jpeg;*.jpg;*.pgm;*.png;*.pot;*.ppm;*.sys;*.tga;*.tiff;*.EXR;*.GIF;*.HDR;*.IFF;*.JPEG;*.JPG;*.PGM;*.PNG;*.POT;*.PPM;*.SYS;*.TGA;*.TIFF",
-            # options={'HIDDEN'},
-            # )
-
-###############################################################################
-# Camera POV properties.
-###############################################################################
-class RenderPovSettingsCamera(PropertyGroup):
-
-    """Declare camera properties controllable in UI and translated to POV."""
-
-    # DOF Toggle
-    dof_enable: BoolProperty(
-        name="Depth Of Field",
-        description="Enable POV Depth Of Field ",
-        default=False,
-    )
-
-    # Aperture (Intensity of the Blur)
-    dof_aperture: FloatProperty(
-        name="Aperture",
-        description="Similar to a real camera's aperture effect over focal blur (though not "
-        "in physical units and independent of focal length). "
-        "Increase to get more blur",
-        min=0.01, max=1.00, default=0.50
-    )
-
-    # Aperture adaptive sampling
-    dof_samples_min: IntProperty(
-        name="Samples Min",
-        description="Minimum number of rays to use for each pixel",
-        min=1, max=128, default=3
-    )
-
-    dof_samples_max: IntProperty(
-        name="Samples Max",
-        description="Maximum number of rays to use for each pixel",
-        min=1, max=128, default=9
-    )
-
-    dof_variance: IntProperty(
-        name="Variance",
-        description="Minimum threshold (fractional value) for adaptive DOF sampling (up "
-        "increases quality and render time). The value for the variance should "
-        "be in the range of the smallest displayable color difference",
-        min=1, max=100000, soft_max=10000, default=8192
-    )
-
-    dof_confidence: FloatProperty(
-        name="Confidence",
-        description="Probability to reach the real color value. Larger confidence values "
-        "will lead to more samples, slower traces and better images",
-        min=0.01, max=0.99, default=0.20
-    )
-
-    normal_enable: BoolProperty(
-        name="Perturbated Camera",
-        default=False,
-    )
-
-    cam_normal: FloatProperty(
-        name="Normal Strength",
-        min=0.0,
-        max=1.0,
-        default=0.0,
-    )
-
-    normal_patterns: EnumProperty(
-        name="Pattern",
-        description="",
-        items=(
-            ('agate', "Agate", ""),
-            ('boxed', "Boxed", ""),
-            ('bumps', "Bumps", ""),
-            ('cells', "Cells", ""),
-            ('crackle', "Crackle", ""),
-            ('dents', "Dents", ""),
-            ('granite', "Granite", ""),
-            ('leopard', "Leopard", ""),
-            ('marble', "Marble", ""),
-            ('onion', "Onion", ""),
-            ('pavement', "Pavement", ""),
-            ('planar', "Planar", ""),
-            ('quilted', "Quilted", ""),
-            ('ripples', "Ripples", ""),
-            ('radial', "Radial", ""),
-            ('spherical', "Spherical", ""),
-            ('spiral1', "Spiral1", ""),
-            ('spiral2', "Spiral2", ""),
-            ('spotted', "Spotted", ""),
-            ('square', "Square", ""),
-            ('tiling', "Tiling", ""),
-            ('waves', "Waves", ""),
-            ('wood', "Wood", ""),
-            ('wrinkles', "Wrinkles", "")
-        ),
-        default='agate',
-    )
-
-    turbulence: FloatProperty(name="Turbulence", min=0.0, max=100.0, default=0.1)
-
-    scale: FloatProperty(name="Scale", min=0.0,default=1.0)
-
-    ##################################CustomPOV Code############################
-    # Only DUMMIES below for now:
-    replacement_text: StringProperty(
-        name="Texts in blend file",
-        description="Type the declared name in custom POV code or an external .inc "
-        "it points at. camera {} expected",
-        default="",
-    )
-###############################################################################
-# Light POV properties.
-###############################################################################
-class RenderPovSettingsLight(PropertyGroup):
-
-    """Declare light properties controllable in UI and translated to POV."""
-
-    # former Space properties from  removed Blender Internal
-    use_limited_texture_context: BoolProperty(
-        name="",
-        description="Use the limited version of texture user (for ‘old shading’ mode)",
-        default=True,
-    )
-
-    texture_context: EnumProperty(
-        name="Texture context",
-        description="Type of texture data to display and edit",
-        items=(
-            ('MATERIAL', "", "Show material textures", "MATERIAL",0), # "Show material textures"
-            ('WORLD', "", "Show world textures", "WORLD",1), # "Show world textures"
-            ('LAMP', "", "Show lamp textures", "LIGHT",2), # "Show lamp textures"
-            ('PARTICLES', "", "Show particles textures", "PARTICLES",3), # "Show particles textures"
-            ('LINESTYLE', "", "Show linestyle textures", "LINE_DATA",4), # "Show linestyle textures"
-            ('OTHER', "", "Show other data textures", "TEXTURE_DATA",5), # "Show other data textures"
-        ),
-        default = 'MATERIAL',
-    )
-
-    shadow_method: EnumProperty(
-        name="Shadow",
-        description="",
-        items=(("NOSHADOW", "No Shadow", "No Shadow"),
-               ("RAY_SHADOW", "Ray Shadow", "Ray Shadow, Use ray tracing for shadow")),
-        default="RAY_SHADOW",
-    )
-
-    active_texture_index: IntProperty(
-        name = "Index for texture_slots",
-        default = 0
-    )
-
-    use_halo: BoolProperty(
-        name="Halo",
-        description="Render spotlight with a volumetric halo",
-        default=False,
-    )
-
-    halo_intensity: FloatProperty(
-        name="Halo intensity",
-        description="Brightness of the spotlight halo cone",
-        soft_min=0.0, soft_max=1.0, default=1.0
-    )
-
-    shadow_ray_samples_x: IntProperty(
-        name = "Number of samples taken extra (samples x samples)",
-        min=1, soft_max=64,
-        default = 1,
-    )
-
-    shadow_ray_samples_y: IntProperty(
-        name = "Number of samples taken extra (samples x samples)",
-        min=1, soft_max=64,
-        default = 1,
-    )
-
-    shadow_ray_sample_method: EnumProperty(
-        name="",
-        description="Method for generating shadow samples: Adaptive QMC is fastest, Constant QMC is less noisy but slower",
-        items=(
-            ('ADAPTIVE_QMC', "", "Halton samples distribution", "",0),
-            ('CONSTANT_QMC', "", "QMC samples distribution", "",1),
-            ('CONSTANT_JITTERED', "", "Uses POV jitter keyword", "",2) # "Show other data textures"
-        ),
-        default = 'CONSTANT_JITTERED',
-    )
-
-    use_jitter: BoolProperty(
-        name="Jitter",
-        description="Use noise for sampling (Constant Jittered sampling)",
-        default=False,
-    )
-
-###############################################################################
-# World POV properties.
-###############################################################################
-class RenderPovSettingsWorld(PropertyGroup):
-
-    """Declare world properties controllable in UI and translated to POV."""
-
-    # former Space properties from  removed Blender Internal
-    use_limited_texture_context: BoolProperty(
-        name="",
-        description="Use the limited version of texture user (for ‘old shading’ mode)",
-        default=True,
-    )
-
-    texture_context: EnumProperty(
-        name="Texture context",
-        description="Type of texture data to display and edit",
-        items=(
-            ('MATERIAL', "", "Show material textures", "MATERIAL",0), # "Show material textures"
-            ('WORLD', "", "Show world textures", "WORLD",1), # "Show world textures"
-            ('LIGHT', "", "Show lamp textures", "LIGHT",2), # "Show lamp textures"
-            ('PARTICLES', "", "Show particles textures", "PARTICLES",3), # "Show particles textures"
-            ('LINESTYLE', "", "Show linestyle textures", "LINE_DATA",4), # "Show linestyle textures"
-            ('OTHER', "", "Show other data textures", "TEXTURE_DATA",5), # "Show other data textures"
-        ),
-        default = 'MATERIAL',
-    )
-
-    use_sky_blend: BoolProperty(
-        name="Blend Sky",
-        description="Render background with natural progression from horizon to zenith",
-        default=False,
-    )
-
-    use_sky_paper: BoolProperty(
-        name="Paper Sky",
-        description="Flatten blend or texture coordinates",
-        default=False,
-    )
-
-    use_sky_real: BoolProperty(
-        name="Real Sky",
-        description="Render background with a real horizon, relative to the camera angle",
-        default=False,
-    )
-
-    horizon_color: FloatVectorProperty(
-        name="Horizon Color",
-        description="Color at the horizon",
-        precision=4, step=0.01, min=0, soft_max=1,
-        default=(0.0, 0.0, 0.0), options={'ANIMATABLE'}, subtype='COLOR',
-    )
-
-    zenith_color: FloatVectorProperty(
-        name="Zenith Color",
-        description="Color at the zenith",
-        precision=4, step=0.01, min=0, soft_max=1,
-        default=(0.0, 0.0, 0.0), options={'ANIMATABLE'}, subtype='COLOR',
-    )
-
-    ambient_color: FloatVectorProperty(
-        name="Ambient Color",
-        description="Ambient color of the world",
-        precision=4, step=0.01, min=0, soft_max=1,
-        default=(0.0, 0.0, 0.0), options={'ANIMATABLE'}, subtype='COLOR',
-    )
-    active_texture_index: IntProperty(
-        name = "Index for texture_slots",
-        default = 0,
-        update = brush_texture_update
-    )
-
-class WorldTextureSlot(PropertyGroup):
-    """Declare world texture slot level properties for UI and translated to POV."""
-
-    bl_idname="pov_texture_slots",
-    bl_description="Texture_slots from Blender-2.79",
-
-    # Adding a "real" texture datablock as property is not possible
-    # (or at least not easy through a dynamically populated EnumProperty).
-    # That's why we'll use a prop_search() UILayout function in ui.py.
-    # So we'll assign the name of the needed texture datablock to the below StringProperty.
-    texture : StringProperty(update=active_texture_name_from_uilist)
-    # and use another temporary StringProperty to change the linked data
-    texture_search : StringProperty(
-        name="",
-        update = active_texture_name_from_search,
-        description = "Browse Texture to be linked",
-    )
-
-    blend_factor: FloatProperty(
-        name="Blend",
-        description="Amount texture affects color progression of the "
-        "background",
-        soft_min=0.0, soft_max=1.0, default=1.0
-    )
-
-    horizon_factor: FloatProperty(
-        name="Horizon",
-        description="Amount texture affects color of the horizon",
-        soft_min=0.0, soft_max=1.0, default=1.0,
-    )
-
-    object: StringProperty(
-        name="Object",
-        description="Object to use for mapping with Object texture coordinates",
-        default="",
-    )
-
-    offset: FloatVectorProperty(
-        name="Offset",
-        description=("Fine tune of the texture mapping X, Y and Z locations "),
-        precision=4,
-        step=0.1,
-        soft_min= -100.0,
-        soft_max=100.0,
-        default=(0.0,0.0,0.0),
-        options={'ANIMATABLE'},
-        subtype='TRANSLATION',
-    )
-
-    scale: FloatVectorProperty(
-        name="Size",
-        subtype='XYZ',
-        size=3,
-        description="Set scaling for the texture’s X, Y and Z sizes ",
-        precision=4,
-        step=0.1,
-        soft_min= -100.0,
-        soft_max=100.0,
-        default=(1.0,1.0,1.0),
-        options={'ANIMATABLE'},
-    )
-
-    texture_coords: EnumProperty(
-        name="Coordinates",
-        description="Texture coordinates used to map the texture onto the background",
-        items=(
-            ("VIEW", "View", "Use view vector for the texture coordinates"),
-            ("GLOBAL", "Global", "Use global coordinates for the texture coordinates (interior mist)"),
-            ("ANGMAP", "AngMap", "Use 360 degree angular coordinates, e.g. for spherical light probes"),
-            ("SPHERE", "Sphere", "For 360 degree panorama sky, spherical mapped, only top half"),
-            ("EQUIRECT", "Equirectangular", "For 360 degree panorama sky, equirectangular mapping"),
-            ("TUBE", "Tube", "For 360 degree panorama sky, cylindrical mapped, only top half"),
-            ("OBJECT", "Object", "Use linked object’s coordinates for texture coordinates")
-        ),
-        default="VIEW",
-    )
-
-    use_map_blend: BoolProperty(
-        name="Blend Map",
-        description="Affect the color progression of the background",
-        default=True,
-    )
-
-    use_map_horizon: BoolProperty(
-        name="Horizon Map",
-        description="Affect the color of the horizon",
-        default=False,
-    )
-
-    use_map_zenith_down: BoolProperty(
-        name="",
-        description="Affect the color of the zenith below",
-        default=False,
-    )
-
-    use_map_zenith_up: BoolProperty(
-        name="Zenith Up Map",
-        description="Affect the color of the zenith above",
-        default=False,
-    )
-
-    zenith_down_factor: FloatProperty(
-        name="Zenith Down",
-        description="Amount texture affects color of the zenith below",
-        soft_min=0.0, soft_max=1.0, default=1.0
-    )
-
-    zenith_up_factor: FloatProperty(
-        name="Zenith Up",
-        description="Amount texture affects color of the zenith above",
-        soft_min=0.0, soft_max=1.0, default=1.0
-    )
-
-'''
-# class WORLD_TEXTURE_SLOTS_UL_layerlist(bpy.types.UIList):
-#    texture_slots:
-
-class WorldTextureSlots(bpy.props.PropertyGroup):
-    index = bpy.prop.PropertyInt(name='index')
-    # foo  = random prop
-
-bpy.types.World.texture_slots = bpy.props.CollectionProperty(type=PropertyGroup)
-
-for i in range(18):  # length of world texture slots
-    world.texture_slots.add()
-'''
-
-class MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist(bpy.types.UIList):
-    # texture_slots:
-    #index: bpy.props.IntProperty(name='index')
-    # foo  = random prop
-    def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
-        ob = data
-        slot = item
-        # ma = slot.name
-        # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
-        if self.layout_type in {'DEFAULT', 'COMPACT'}:
-            # You should always start your row layout by a label (icon + text), or a non-embossed text field,
-            # this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
-            # We use icon_value of label, as our given icon is an integer value, not an enum ID.
-            # Note "data" names should never be translated!
-            if slot:
-                layout.prop(item, "texture", text="", emboss=False, icon='TEXTURE')
-            else:
-                layout.label(text="New", translate=False, icon_value=icon)
-        # 'GRID' layout type should be as compact as possible (typically a single icon!).
-        elif self.layout_type in {'GRID'}:
-            layout.alignment = 'CENTER'
-            layout.label(text="", icon_value=icon)
-
-
-###############################################################################
-# Text POV properties.
-###############################################################################
-
-
-class RenderPovSettingsText(PropertyGroup):
-
-    """Declare text properties to use UI as an IDE or render text snippets to POV."""
-
-    custom_code: EnumProperty(
-        name="Custom Code",
-        description="rendered source: Both adds text at the "
-        "top of the exported POV file",
-        items=(
-            ("3dview", "View", ""),
-            ("text", "Text", ""),
-            ("both", "Both", "")
-        ),
-        default="text",
-    )
-
-###############################################################################
-# Povray Preferences.
-###############################################################################
-
-
-class PovrayPreferences(AddonPreferences):
-
-    """Declare preference variables to set up POV binary."""
-
-    bl_idname = __name__
-
-    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",
-        items= (
-            ('povray', 'Official POV-Ray', '','PLUGIN', 0),
-            ('uberpov', 'Unofficial UberPOV', '', 'PLUGIN', 1)
-        ),
-        default='povray',
-    )
-
-    filepath_povray: StringProperty(
-        name="Binary Location",
-        description="Path to renderer executable",
-        subtype='FILE_PATH',
-    )
-
-    docpath_povray: StringProperty(
-        name="Includes Location",
-        description="Path to Insert Menu files",
-        subtype='FILE_PATH',
-    )
-
-    use_sounds: BoolProperty(
-        name="Use Sound",
-        description="Signaling end of the render process at various"
-        "stages can help if you're away from monitor",
-        default=False,
-    )
-
-    # 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',
-    )
-
-    filepath_parse_error_sound: StringProperty(
-        name="Parse Error Sound",
-        description="Path to parsing time error sound file",
-        subtype='FILE_PATH',
-    )
-
-    filepath_cancel_sound: StringProperty(
-        name="Cancel Render Sound",
-        description="Path to cancelled or render time error sound file",
-        subtype='FILE_PATH',
-    )
-
-    #shall we not move this to UI file?
-    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')
-
-
-classes = (
-    PovrayPreferences,
-    RenderPovSettingsCamera,
-    RenderPovSettingsLight,
-    RenderPovSettingsWorld,
-    MaterialTextureSlot,
-    WorldTextureSlot,
-    RenderPovSettingsMaterial,
-    MaterialRaytraceTransparency,
-    MaterialRaytraceMirror,
-    MaterialSubsurfaceScattering,
-    MaterialStrandSettings,
-    RenderPovSettingsObject,
-    RenderPovSettingsScene,
-    RenderPovSettingsText,
-    RenderPovSettingsTexture,
-)
-
-
-def register():
-
-    # bpy.utils.register_module(__name__) # DEPRECATED Now imported from bpy.utils import register_class
-
-    for cls in classes:
-        register_class(cls)
-
-    render.register()
-    ui.register()
-    primitives.register()
-    nodes.register()
-
-    '''
-        bpy.types.VIEW3D_MT_add.prepend(ui.menu_func_add)
-        bpy.types.TOPBAR_MT_file_import.append(ui.menu_func_import)
-        bpy.types.TEXT_MT_templates.append(ui.menu_func_templates)
-        bpy.types.RENDER_PT_POV_radiosity.prepend(ui.rad_panel_func)
-        bpy.types.LIGHT_PT_POV_light.prepend(ui.light_panel_func)
-        bpy.types.WORLD_PT_world.prepend(ui.world_panel_func)
-        # was used for parametric objects but made the other addon unreachable on
-        # unregister for other tools to use created a user action call instead
-        # addon_utils.enable("add_mesh_extra_objects", default_set=False, persistent=True)
-
-        # bpy.types.TEXTURE_PT_context_texture.prepend(TEXTURE_PT_povray_type)
-    '''
-    bpy.types.NODE_HT_header.append(ui.menu_func_nodes)
-    nodeitems_utils.register_node_categories("POVRAYNODES", node_categories)
-    bpy.types.Scene.pov = PointerProperty(type=RenderPovSettingsScene)
-    # bpy.types.Modifier.pov = PointerProperty(type=RenderPovSettingsModifier)
-    bpy.types.Material.pov_raytrace_transparency = PointerProperty(type=MaterialRaytraceTransparency)
-    bpy.types.Material.pov = PointerProperty(type=RenderPovSettingsMaterial)
-    bpy.types.Material.pov_subsurface_scattering = PointerProperty(type=MaterialSubsurfaceScattering)
-    bpy.types.Material.strand = PointerProperty(type=MaterialStrandSettings)
-    bpy.types.Material.pov_raytrace_mirror = PointerProperty(type=MaterialRaytraceMirror)
-    bpy.types.Texture.pov = PointerProperty(type=RenderPovSettingsTexture)
-    bpy.types.Object.pov = PointerProperty(type=RenderPovSettingsObject)
-    bpy.types.Camera.pov = PointerProperty(type=RenderPovSettingsCamera)
-    bpy.types.Light.pov = PointerProperty(type=RenderPovSettingsLight)
-    bpy.types.World.pov = PointerProperty(type=RenderPovSettingsWorld)
-    bpy.types.Material.pov_texture_slots = CollectionProperty(type=MaterialTextureSlot)
-    bpy.types.World.pov_texture_slots = CollectionProperty(type=WorldTextureSlot)
-    bpy.types.Text.pov = PointerProperty(type=RenderPovSettingsText)
-
-
-def unregister():
-    del bpy.types.Scene.pov
-    del bpy.types.Material.pov
-    del bpy.types.Material.pov_subsurface_scattering
-    del bpy.types.Material.strand
-    del bpy.types.Material.pov_raytrace_mirror
-    del bpy.types.Material.pov_raytrace_transparency
-    # del bpy.types.Modifier.pov
-    del bpy.types.Texture.pov
-    del bpy.types.Object.pov
-    del bpy.types.Camera.pov
-    del bpy.types.Light.pov
-    del bpy.types.World.pov
-    del bpy.types.World.pov_texture_slots
-    del bpy.types.Material.pov_texture_slots
-    del bpy.types.Text.pov
-
-    nodeitems_utils.unregister_node_categories("POVRAYNODES")
-    bpy.types.NODE_HT_header.remove(ui.menu_func_nodes)
-    '''
-    # bpy.types.TEXTURE_PT_context_texture.remove(TEXTURE_PT_povray_type)
-    # addon_utils.disable("add_mesh_extra_objects", default_set=False)
-    bpy.types.WORLD_PT_POV_world.remove(ui.world_panel_func)
-    bpy.types.LIGHT_PT_POV_light.remove(ui.light_panel_func)
-    bpy.types.RENDER_PT_POV_radiosity.remove(ui.rad_panel_func)
-    bpy.types.TEXT_MT_templates.remove(ui.menu_func_templates)
-    bpy.types.TOPBAR_MT_file_import.remove(ui.menu_func_import)
-    bpy.types.VIEW3D_MT_add.remove(ui.menu_func_add)
-    '''
-    # bpy.utils.unregister_module(__name__)
-
-    nodes.unregister()
-    primitives.unregister()
-    ui.unregister()
-    render.unregister()
-
-    for cls in reversed(classes):
-        unregister_class(cls)
-
-
-
-if __name__ == "__main__":
-    register()
+# ------------8<---------[ BREAKPOINT ]--------------8<-----------#  Move this snippet around
+# __import__('code').interact(local=dict(globals(), **locals())) # < and uncomment this line
+# ----------------------------------------------------------------#  to inspect from Terminal
diff --git a/render_povray/base_ui.py b/render_povray/base_ui.py
new file mode 100755
index 000000000..f0e2cb2f0
--- /dev/null
+++ b/render_povray/base_ui.py
@@ -0,0 +1,307 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+"""User interface imports and preferences for the addon."""
+
+# import addon_utils
+# from time import sleep
+import bpy
+
+
+from bpy.app.handlers import persistent
+
+# from bpy.utils import register_class, unregister_class
+# from bpy.types import (
+# Operator,
+# Menu,
+# UIList,
+# Panel,
+# Brush,
+# Material,
+# Light,
+# World,
+# ParticleSettings,
+# FreestyleLineStyle,
+# )
+
+# from bl_operators.presets import AddPresetBase
+
+from . import (
+    render_gui,
+    scenography_gui,
+    object_gui,
+    shading_gui,
+    texturing_gui,
+    shading_nodes,  # for POV specific nodes
+    scripting_gui,
+)
+
+
+############# POV-Centric WORKSPACE #############
+@persistent
+def povCentricWorkspace(dummy):
+    """Set up a POV centric Workspace if addon was activated and saved as default renderer.
+
+    This would bring a ’_RestrictData’ error because UI needs to be fully loaded before
+    workspace changes so registering this function in bpy.app.handlers is needed.
+    By default handlers are freed when loading new files, but here we want the handler
+    to stay running across multiple files as part of this add-on. That is why the
+    bpy.app.handlers.persistent decorator is used (@persistent) above.
+    """
+    # Scripting workspace may have been altered from factory though, so should
+    # we put all within a Try... Except AttributeErrors ? Any better solution ?
+    # Should it simply not run when opening existing file? be a preferences operator to create
+    # Moray like workspace
+    if 'Scripting' in bpy.data.workspaces:
+
+        wsp = bpy.data.workspaces.get('Scripting')
+        context = bpy.context
+        if context.scene.render.engine == 'POVRAY_RENDER' and wsp is not None:
+            bpy.ops.workspace.duplicate({'workspace': wsp})
+            bpy.data.workspaces['Scripting.001'].name = 'POV'
+            # Already done it would seem, but explicitly make this workspace the active one
+            context.window.workspace = bpy.data.workspaces['POV']
+            pov_screen = bpy.data.workspaces['POV'].screens[0]
+            pov_workspace = pov_screen.areas
+            pov_window = context.window
+            try:
+                # Already outliners but invert both types
+                pov_workspace[1].spaces[0].display_mode = 'LIBRARIES'
+                pov_workspace[3].spaces[0].display_mode = 'VIEW_LAYER'
+            except AttributeError:
+                # But not necessarily outliners in existing blend files
+                pass
+            override = bpy.context.copy()
+
+            for area in pov_workspace:
+                if area.type == 'VIEW_3D':
+                    for region in [r for r in area.regions if r.type == 'WINDOW']:
+                        for space in area.spaces:
+                            if space.type == 'VIEW_3D':
+                                # override['screen'] = pov_screen
+                                override['area'] = area
+                                override['region'] = region
+                                # bpy.data.workspaces['POV'].screens[0].areas[6].spaces[0].width = 333 # Read only,
+                                # how do we set ?
+                                # This has a glitch:
+                                # bpy.ops.screen.area_move(override, x=(area.x + area.width), y=(area.y + 5), delta=100)
+                                # bpy.ops.screen.area_move(override, x=(area.x + 5), y=area.y, delta=-100)
+
+                                bpy.ops.screen.space_type_set_or_cycle(
+                                    override, space_type='TEXT_EDITOR'
+                                )
+                                space.show_region_ui = True
+                                # bpy.ops.screen.region_scale(override)
+                                # bpy.ops.screen.region_scale()
+                                break
+
+                elif area.type == 'CONSOLE':
+                    for region in [r for r in area.regions if r.type == 'WINDOW']:
+                        for space in area.spaces:
+                            if space.type == 'CONSOLE':
+                                override['screen'] = pov_screen
+                                override['window'] = pov_window
+                                override['area'] = area
+                                override['region'] = region
+
+                                area_x = area.x + (area.width / 2)
+                                area_y = area.y + area.height
+                                bpy.ops.screen.space_type_set_or_cycle(override, space_type='INFO')
+                                try:
+                                    if area == pov_workspace[6] and bpy.ops.screen.area_move.poll(
+                                        override
+                                    ):
+                                        # bpy.ops.screen.area_move(override, x = area_x, y = area_y, delta = -300)
+                                        pass
+                                        # pov_window.cursor_warp(area_x, area_y-300) # Is manual move emulation necessary
+                                        # despite the delta?
+                                except IndexError:
+                                    # Not necessarily so many areas in existing blend files
+                                    pass
+
+                                break
+
+                elif area.type == 'INFO':
+                    for region in [r for r in area.regions if r.type == 'WINDOW']:
+                        for space in area.spaces:
+                            if space.type == 'INFO':
+                                # override['screen'] = pov_screen
+                                override['area'] = area
+                                override['region'] = region
+                                bpy.ops.screen.space_type_set_or_cycle(
+                                    override, space_type='CONSOLE'
+                                )
+
+                                break
+
+                elif area.type == 'TEXT_EDITOR':
+                    for region in [r for r in area.regions if r.type == 'WINDOW']:
+                        for space in area.spaces:
+                            if space.type == 'TEXT_EDITOR':
+                                # override['screen'] = pov_screen
+                                override['area'] = area
+                                override['region'] = region
+                                # bpy.ops.screen.space_type_set_or_cycle(space_type='VIEW_3D')
+                                # space.type = 'VIEW_3D'
+                                bpy.ops.screen.space_type_set_or_cycle(
+                                    override, space_type='VIEW_3D'
+                                )
+
+                                # bpy.ops.screen.area_join(override, cursor=(area.x, area.y + area.height))
+
+                                break
+
+                if area.type == 'VIEW_3D':
+                    for region in [r for r in area.regions if r.type == 'WINDOW']:
+                        for space in area.spaces:
+                            if space.type == 'VIEW_3D':
+                                # override['screen'] = pov_screen
+                                override['area'] = area
+                                override['region'] = region
+                                bpy.ops.screen.region_quadview(override)
+                                space.region_3d.view_perspective = 'CAMERA'
+                                # bpy.ops.screen.space_type_set_or_cycle(override, space_type = 'TEXT_EDITOR')
+                                # bpy.ops.screen.region_quadview(override)
+
+                elif area.type == 'OUTLINER':
+                    for region in [
+                        r for r in area.regions if r.type == 'HEADER' and (r.y - area.y)
+                    ]:
+                        for space in area.spaces:
+                            if space.display_mode == 'LIBRARIES':
+                                override['area'] = area
+                                override['region'] = region
+                                override['window'] = pov_window
+                                bpy.ops.screen.region_flip(override)
+
+            bpy.data.workspaces.update()
+
+            '''
+            for window in bpy.context.window_manager.windows:
+                for area in [a for a in window.screen.areas if a.type == 'VIEW_3D']:
+                    for region in [r for r in area.regions if r.type == 'WINDOW']:
+                        context_override = {
+                            'window': window,
+                            'screen': window.screen,
+                            'area': area,
+                            'region': region,
+                            'space_data': area.spaces.active,
+                            'scene': bpy.context.scene
+                            }
+                        bpy.ops.view3d.camera_to_view(context_override)
+            '''
+
+        else:
+            print(
+                "\nPOV centric workspace available if you set render option\n"
+                "and save it in default file with CTRL+U"
+            )
+
+    else:
+        print(
+            "\nThe factory 'Scripting' workspace is needed before POV centric "
+            "\nworkspace may activate when POV is set as your default renderer"
+        )
+    ####################################UTF-8###################################
+    # Check and fix all strings in current .blend file to be valid UTF-8 Unicode
+    # sometimes needed for old, 2.4x / 2.6x area files
+    bpy.ops.wm.blend_strings_utf8_validate()
+
+
+def check_material(mat):
+    """Allow use of material properties buttons rather than nodes."""
+    if mat is not None:
+        if mat.use_nodes:
+            if not mat.node_tree:  # FORMERLY : #mat.active_node_material is not None:
+                return True
+            return False
+        return True
+    return False
+
+
+def simple_material(mat):
+    """Test if a material uses nodes."""
+    if (mat is not None) and (not mat.use_nodes):
+        return True
+    return False
+
+
+def pov_context_tex_datablock(context):
+    """Recreate texture context type as deprecated in blender 2.8."""
+    idblock = context.brush
+    if idblock and context.scene.texture_context == 'OTHER':
+        return idblock
+
+    # idblock = bpy.context.active_object.active_material
+    idblock = context.view_layer.objects.active.active_material
+    if idblock and context.scene.texture_context == 'MATERIAL':
+        return idblock
+
+    idblock = context.scene.world
+    if idblock and context.scene.texture_context == 'WORLD':
+        return idblock
+
+    idblock = context.light
+    if idblock and context.scene.texture_context == 'LIGHT':
+        return idblock
+
+    if context.particle_system and context.scene.texture_context == 'PARTICLES':
+        idblock = context.particle_system.settings
+
+    return idblock
+
+    idblock = context.line_style
+    if idblock and context.scene.texture_context == 'LINESTYLE':
+        return idblock
+
+
+# class TextureTypePanel(TextureButtonsPanel):
+
+# @classmethod
+# def poll(cls, context):
+# tex = context.texture
+# engine = context.scene.render.engine
+# return tex and ((tex.type == cls.tex_type and not tex.use_nodes) and (engine in cls.COMPAT_ENGINES))
+
+
+def register():
+    render_gui.register()
+    scenography_gui.register()
+    object_gui.register()
+    shading_gui.register()
+    texturing_gui.register()
+    shading_nodes.register()
+    scripting_gui.register()
+
+    if not povCentricWorkspace in bpy.app.handlers.load_post:
+        bpy.app.handlers.load_post.append(povCentricWorkspace)
+
+
+def unregister():
+    if povCentricWorkspace in bpy.app.handlers.load_post:
+        bpy.app.handlers.load_post.remove(povCentricWorkspace)
+
+    scripting_gui.unregister()
+    shading_nodes.unregister()
+    texturing_gui.unregister()
+    shading_gui.unregister()
+    object_gui.unregister()
+    scenography_gui.unregister()
+    render_gui.register()
diff --git a/render_povray/df3.py b/render_povray/df3_library.py
old mode 100644
new mode 100755
similarity index 57%
rename from render_povray/df3.py
rename to render_povray/df3_library.py
index b84342875..f802fb2dd
--- a/render_povray/df3.py
+++ b/render_povray/df3_library.py
@@ -52,18 +52,19 @@ import sys
 
 # -+-+-+- Start df3 Class -+-+-+-
 
+
 class df3:
     __version__ = '0.2'
 
     __arraytype__ = 'f'
 
-    __struct4byte__  = '>I'
-    __struct2byte__  = '>H'
+    __struct4byte__ = '>I'
+    __struct2byte__ = '>H'
     __struct2byte3__ = '>HHH'
-    __struct1byte__  = '>B'
-    __array4byte__   = 'I'
-    __array2byte__   = 'H'
-    __array1byte__   = 'B'
+    __struct1byte__ = '>B'
+    __array4byte__ = 'I'
+    __array2byte__ = 'H'
+    __array1byte__ = 'B'
 
     def __init__(self, x=1, y=1, z=1):
         self.maxX = x
@@ -73,7 +74,7 @@ class df3:
 
     def clone(self, indf3):
         self.voxel = array.array(self.__arraytype__)
-        for i in range(indf3.sizeX()*indf3.sizeY()*indf3.sizeZ()):
+        for i in range(indf3.sizeX() * indf3.sizeY() * indf3.sizeZ()):
             self.voxel[i] = indf3.voxel[i]
         return self
 
@@ -98,35 +99,41 @@ class df3:
     #### Voxel Access Functions
 
     def get(self, x, y, z):
-        return self.voxel[self.__voxa__(x,y,z)]
+        return self.voxel[self.__voxa__(x, y, z)]
 
     def getB(self, x, y, z):
-        if (x > self.sizeX() or x < 0): return 0
-        if (y > self.sizeX() or y < 0): return 0
-        if (z > self.sizeX() or z < 0): return 0
+        if x > self.sizeX() or x < 0:
+            return 0
+        if y > self.sizeX() or y < 0:
+            return 0
+        if z > self.sizeX() or z < 0:
+            return 0
 
-        return self.voxel[self.__voxa__(x,y,z)]
+        return self.voxel[self.__voxa__(x, y, z)]
 
     def set(self, x, y, z, val):
-        self.voxel[self.__voxa__(x,y,z)] = val
+        self.voxel[self.__voxa__(x, y, z)] = val
 
     def setB(self, x, y, z, val):
-        if (x > self.sizeX() or x < 0): return
-        if (y > self.sizeX() or y < 0): return
-        if (z > self.sizeX() or z < 0): return
+        if x > self.sizeX() or x < 0:
+            return
+        if y > self.sizeX() or y < 0:
+            return
+        if z > self.sizeX() or z < 0:
+            return
 
-        self.voxel[self.__voxa__(x,y,z)] = val
+        self.voxel[self.__voxa__(x, y, z)] = val
 
     #### Scalar Functions
 
     def mult(self, val):
-        for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
+        for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
             self.voxel[i] = self.voxel[i] * val
 
         return self
 
     def add(self, val):
-        for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
+        for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
             self.voxel[i] = self.voxel[i] + val
 
         return self
@@ -134,8 +141,8 @@ class df3:
     def max(self):
         tmp = self.voxel[0]
 
-        for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
-            if (self.voxel[i] > tmp):
+        for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
+            if self.voxel[i] > tmp:
                 tmp = self.voxel[i]
 
         return tmp
@@ -143,8 +150,8 @@ class df3:
     def min(self):
         tmp = self.voxel[0]
 
-        for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
-            if (self.voxel[i] < tmp):
+        for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
+            if self.voxel[i] < tmp:
                 tmp = self.voxel[i]
 
         return tmp
@@ -152,30 +159,31 @@ class df3:
     #### Vector Functions
 
     def compare(self, indf3):
-        if (self.__samesize__(indf3) == 0): return 0
+        if self.__samesize__(indf3) == 0:
+            return 0
 
-        if (self.voxel == indf3.voxel):
+        if self.voxel == indf3.voxel:
             return 1
 
         return 0
 
     def multV(self, indf3):
-        if (self.__samesize__(indf3) == 0):
+        if self.__samesize__(indf3) == 0:
             print("Cannot multiply voxels - not same size")
             return
 
-        for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
-            self.voxel[i] = self.voxel[i]*indf3.voxel[i]
+        for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
+            self.voxel[i] = self.voxel[i] * indf3.voxel[i]
 
         return self
 
     def addV(self, indf3):
-        if (self.__samesize__(indf3) == 0):
+        if self.__samesize__(indf3) == 0:
             print("Cannot add voxels - not same size")
             return
 
-        for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
-            self.voxel[i] = self.voxel[i]+indf3.voxel[i]
+        for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
+            self.voxel[i] = self.voxel[i] + indf3.voxel[i]
 
         return self
 
@@ -183,31 +191,31 @@ class df3:
         fx = filt.sizeX()
         fy = filt.sizeY()
         fz = filt.sizeZ()
-        if (fx % 2 != 1):
+        if fx % 2 != 1:
             print("Incompatible filter - must be odd number of X")
             return self
-        if (fy % 2 != 1):
+        if fy % 2 != 1:
             print("Incompatible filter - must be odd number of Y")
             return self
-        if (fz % 2 != 1):
+        if fz % 2 != 1:
             print("Incompatible filter - must be odd number of Z")
             return self
 
-        fdx = (fx-1)/2
-        fdy = (fy-1)/2
-        fdz = (fz-1)/2
-        flen = fx*fy*fz
+        fdx = (fx - 1) / 2
+        fdy = (fy - 1) / 2
+        fdz = (fz - 1) / 2
+        flen = fx * fy * fz
 
-        newV = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ());
+        newV = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ())
 
         for x in range(self.sizeX()):
             for y in range(self.sizeY()):
                 for z in range(self.sizeZ()):
-                    rip = self.__rip__(x-fdx, x+fdx, y-fdy, y+fdy, z-fdz, z+fdz)
+                    rip = self.__rip__(x - fdx, x + fdx, y - fdy, y + fdy, z - fdz, z + fdz)
                     tmp = 0.0
                     for i in range(flen):
-                        tmp += rip[i]*filt.voxel[i]
-                    newV[self.__voxa__(x,y,z)] = tmp
+                        tmp += rip[i] * filt.voxel[i]
+                    newV[self.__voxa__(x, y, z)] = tmp
 
         self.voxel = newV
 
@@ -221,64 +229,67 @@ class df3:
         z = self.sizeZ()
 
         try:
-            f = open(file, 'wb');
+            f = open(file, 'wb')
         except:
-            print("Could not open " + file + " for write");
+            print("Could not open " + file + " for write")
             return
 
-        f.write(struct.pack(self.__struct2byte3__, x, y, z));
+        f.write(struct.pack(self.__struct2byte3__, x, y, z))
 
-        tmp = self.__toInteger__(pow(2,depth)-1, rescale)
+        tmp = self.__toInteger__(pow(2, depth) - 1, rescale)
 
-        if (depth > 16): # 32-bit
-            for i in range( x*y*z ):
+        if depth > 16:  # 32-bit
+            for i in range(x * y * z):
                 f.write(struct.pack(self.__struct4byte__, tmp[i]))
-        elif (depth > 8): # 16-bit
-            for i in range( x*y*z ):
+        elif depth > 8:  # 16-bit
+            for i in range(x * y * z):
                 f.write(struct.pack(self.__struct2byte__, tmp[i]))
         else:
-            for i in range( x*y*z ):
+            for i in range(x * y * z):
                 f.write(struct.pack(self.__struct1byte__, tmp[i]))
 
     def importDF3(self, file, scale=1):
         try:
-            f = open(file, 'rb');
+            f = open(file, 'rb')
             size = os.stat(file)[stat.ST_SIZE]
 
         except:
-            print("Could not open " + file + " for read");
+            print("Could not open " + file + " for read")
             return []
 
-        (x, y, z) = struct.unpack(self.__struct2byte3__, f.read(6) )
+        (x, y, z) = struct.unpack(self.__struct2byte3__, f.read(6))
 
         self.voxel = self.__create__(x, y, z)
         self.maxX = x
         self.maxY = y
         self.maxZ = z
 
-        size = size-6
-        if (size == x*y*z):     format = 8
-        elif (size == 2*x*y*z): format = 16
-        elif (size == 4*x*y*z): format = 32
-
-        if (format == 32):
-            for i in range(x*y*z):
-                self.voxel[i] = float(struct.unpack(self.__struct4byte__, f.read(4) )[0])
-        elif (format == 16):
-            for i in range(x*y*z):
-                self.voxel[i] = float(struct.unpack(self.__struct2byte__, f.read(2) )[0])
-        elif (format == 8):
-            for i in range(x*y*z):
-                self.voxel[i] = float(struct.unpack(self.__struct1byte__, f.read(1) )[0])
+        size = size - 6
+        if size == x * y * z:
+            format = 8
+        elif size == 2 * x * y * z:
+            format = 16
+        elif size == 4 * x * y * z:
+            format = 32
+
+        if format == 32:
+            for i in range(x * y * z):
+                self.voxel[i] = float(struct.unpack(self.__struct4byte__, f.read(4))[0])
+        elif format == 16:
+            for i in range(x * y * z):
+                self.voxel[i] = float(struct.unpack(self.__struct2byte__, f.read(2))[0])
+        elif format == 8:
+            for i in range(x * y * z):
+                self.voxel[i] = float(struct.unpack(self.__struct1byte__, f.read(1))[0])
 
         return self
 
     #### Local classes not intended for user use
 
     def __rip__(self, minX, maxX, minY, maxY, minZ, maxZ):
-        sizeX = maxX-minX+1
-        sizeY = maxY-minY+1
-        sizeZ = maxZ-minZ+1
+        sizeX = maxX - minX + 1
+        sizeY = maxY - minY + 1
+        sizeZ = maxZ - minZ + 1
 
         tmpV = self.__create__(sizeX, sizeY, sizeZ)
 
@@ -286,95 +297,99 @@ class df3:
             for y in range(sizeY):
                 for z in range(sizeZ):
                     # Check X
-                    if ((minX + x) < 0):
-                        tmpV[(z*sizeZ+y)*sizeY+x] = 0.0
-                    elif ((minX + x) > self.sizeX()-1):
-                        tmpV[(z*sizeZ+y)*sizeY+x] = 0.0
+                    if (minX + x) < 0:
+                        tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
+                    elif (minX + x) > self.sizeX() - 1:
+                        tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
                     # Check Y
-                    elif ((minY + y) < 0):
-                        tmpV[(z*sizeZ+y)*sizeY+x] = 0.0
-                    elif ((minY + y) > self.sizeY()-1):
-                        tmpV[(z*sizeZ+y)*sizeY+x] = 0.0
+                    elif (minY + y) < 0:
+                        tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
+                    elif (minY + y) > self.sizeY() - 1:
+                        tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
                     # Check Z
-                    elif ((minZ + z) < 0):
-                        tmpV[(z*sizeZ+y)*sizeY+x] = 0.0
-                    elif ((minZ + z) > self.sizeZ()-1):
-                        tmpV[(z*sizeZ+y)*sizeY+x] = 0.0
+                    elif (minZ + z) < 0:
+                        tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
+                    elif (minZ + z) > self.sizeZ() - 1:
+                        tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
                     else:
-                        tmpV[(z*sizeZ+y)*sizeY+x] = self.get(minX+x,minY+y,minZ+z)
+                        tmpV[(z * sizeZ + y) * sizeY + x] = self.get(minX + x, minY + y, minZ + z)
 
         return tmpV
 
     def __samesize__(self, indf3):
-        if (self.sizeX() != indf3.sizeX()): return 0
-        if (self.sizeY() != indf3.sizeY()): return 0
-        if (self.sizeZ() != indf3.sizeZ()): return 0
+        if self.sizeX() != indf3.sizeX():
+            return 0
+        if self.sizeY() != indf3.sizeY():
+            return 0
+        if self.sizeZ() != indf3.sizeZ():
+            return 0
         return 1
 
     def __voxa__(self, x, y, z):
-        return ((z*self.sizeY()+y)*self.sizeX()+x)
+        return (z * self.sizeY() + y) * self.sizeX() + x
 
     def __create__(self, x, y, z, atype='0', init=1):
-        if (atype == '0'):
+        if atype == '0':
             tmp = self.__arraytype__
         else:
             tmp = atype
 
-        if (init == 1):
-            if tmp in ('f','d'):
-                voxel = array.array(tmp, [0.0 for i in range(x*y*z)])
+        if init == 1:
+            if tmp in ('f', 'd'):
+                voxel = array.array(tmp, [0.0 for i in range(x * y * z)])
             else:
-                voxel = array.array(tmp, [0 for i in range(x*y*z)])
+                voxel = array.array(tmp, [0 for i in range(x * y * z)])
         else:
             voxel = array.array(tmp)
 
         return voxel
 
     def __toInteger__(self, scale, rescale=1):
-        if (scale < pow(2,8)): # 8-bit
+        if scale < pow(2, 8):  # 8-bit
             tmp = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ(), self.__array1byte__)
-        elif (scale < pow(2,16)): # 16-bit
+        elif scale < pow(2, 16):  # 16-bit
             tmp = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ(), self.__array2byte__)
-        else: # 32-bit
+        else:  # 32-bit
             tmp = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ(), self.__array4byte__)
 
         maxVal = self.max()
 
         print(scale)
 
-        for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
-            if (rescale == 1):
-                tmp[i] = max(0,int(round(scale*self.voxel[i]/maxVal)))
+        for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
+            if rescale == 1:
+                tmp[i] = max(0, int(round(scale * self.voxel[i] / maxVal)))
             else:
-                tmp[i] = max(0,min(scale,int(round(self.voxel[i]))))
+                tmp[i] = max(0, min(scale, int(round(self.voxel[i]))))
 
         return tmp
 
+
 # -=-=-=- End df3 Class -=-=-=-
 ##########DEFAULT EXAMPLES
 # if __name__ == '__main__':
-    # localX = 80
-    # localY = 90
-    # localZ = 100
-    ## Generate an output
-    # temp = df3(localX, localY, localZ)
-
-    # for i in range(localX):
-        # for j in range(localY):
-            # for k in range(localZ):
-                # if (i >= (localX/2)):
-                    # temp.set(i, j, k, 1.0)
-
-    # temp.exportDF3('temp.df3', 16)
+# localX = 80
+# localY = 90
+# localZ = 100
+## Generate an output
+# temp = df3(localX, localY, localZ)
+
+# for i in range(localX):
+# for j in range(localY):
+# for k in range(localZ):
+# if (i >= (localX/2)):
+# temp.set(i, j, k, 1.0)
+
+# temp.exportDF3('temp.df3', 16)
 ###############################################################################
-    ## Import
-    # temp2 = df3().importDF3('temp.df3')
-    # temp2.mult(1/temp2.max())
+## Import
+# temp2 = df3().importDF3('temp.df3')
+# temp2.mult(1/temp2.max())
 
-    ## Compare
-    # print(temp2.size())
+## Compare
+# print(temp2.size())
 
-    # if (temp.compare(temp2) == 0): print("DF3's Do Not Match")
+# if (temp.compare(temp2) == 0): print("DF3's Do Not Match")
 
 ###############################################################################
 # ChangeLog
diff --git a/render_povray/nodes.py b/render_povray/nodes.py
deleted file mode 100644
index bbdb97545..000000000
--- a/render_povray/nodes.py
+++ /dev/null
@@ -1,1369 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# <pep8 compliant>
-
-import bpy
-
-from bpy.utils import register_class
-from bpy.types import (
-        Node,
-        ShaderNodeTree,
-        CompositorNodeTree,
-        TextureNodeTree,
-        #NodeSocket,
-        Operator,
-        )
-from bpy.props import (
-        StringProperty,
-        BoolProperty,
-        IntProperty,
-        FloatProperty,
-        FloatVectorProperty,
-        EnumProperty,
-        #PointerProperty,
-        #CollectionProperty,
-        )
-
-
-
-############### object
-
-class ObjectNodeTree(bpy.types.NodeTree):
-    '''Povray Material Nodes'''
-
-    bl_idname = 'ObjectNodeTree'
-    bl_label = 'Povray Object Nodes'
-    bl_icon = 'PLUGIN'
-
-    @classmethod
-    def poll(cls, context):
-        return context.scene.render.engine == 'POVRAY_RENDER'
-
-    @classmethod
-    def get_from_context(cls, context):
-        ob = context.active_object
-        if ob and ob.type not in {'LIGHT'}:
-            ma = ob.active_material
-            if ma is not None:
-                nt_name = ma.node_tree
-                if nt_name != '':
-                    return nt_name, ma, ma
-        return (None, None, None)
-
-    def update(self):
-        self.refresh = True
-################### output #############################################################################################
-
-class PovrayOutputNode(Node, ObjectNodeTree):
-    '''Output'''
-    bl_idname = 'PovrayOutputNode'
-    bl_label = 'Output'
-    bl_icon = 'SOUND'
-
-    def init(self, context):
-
-        self.inputs.new('PovraySocketTexture', "Texture")
-
-    def draw_buttons(self, context, layout):
-
-        ob=context.object
-        layout.prop(ob.pov, "object_ior",slider=True)
-
-    def draw_buttons_ext(self, context, layout):
-
-        ob=context.object
-        layout.prop(ob.pov, "object_ior",slider=True)
-
-    def draw_label(self):
-        return "Output"
-
-
-
-################### material ###########################################################################################
-class PovrayTextureNode(Node, ObjectNodeTree):
-    '''Texture'''
-    bl_idname = 'PovrayTextureNode'
-    bl_label = 'Simple texture'
-    bl_icon = 'SOUND'
-
-    def init(self, context):
-
-        color=self.inputs.new('PovraySocketColor', "Pigment")
-        color.default_value=(1,1,1)
-        normal=self.inputs.new('NodeSocketFloat', "Normal")
-        normal.hide_value=True
-        finish=self.inputs.new('NodeSocketVector', "Finish")
-        finish.hide_value=True
-
-        self.outputs.new('PovraySocketTexture', "Texture")
-
-    def draw_label(self):
-        return "Simple texture"
-
-class PovrayFinishNode(Node, ObjectNodeTree):
-    '''Finish'''
-    bl_idname = 'PovrayFinishNode'
-    bl_label = 'Finish'
-    bl_icon = 'SOUND'
-
-    def init(self, context):
-
-        self.inputs.new('PovraySocketFloat_0_1', "Emission")
-        ambient=self.inputs.new('NodeSocketVector', "Ambient")
-        ambient.hide_value=True
-        diffuse=self.inputs.new('NodeSocketVector', "Diffuse")
-        diffuse.hide_value=True
-        specular=self.inputs.new('NodeSocketVector', "Highlight")
-        specular.hide_value=True
-        mirror=self.inputs.new('NodeSocketVector', "Mirror")
-        mirror.hide_value=True
-        iridescence=self.inputs.new('NodeSocketVector', "Iridescence")
-        iridescence.hide_value=True
-        subsurface=self.inputs.new('NodeSocketVector', "Translucency")
-        subsurface.hide_value=True
-        self.outputs.new('NodeSocketVector', "Finish")
-
-    def draw_label(self):
-        return "Finish"
-
-class PovrayDiffuseNode(Node, ObjectNodeTree):
-    '''Diffuse'''
-    bl_idname = 'PovrayDiffuseNode'
-    bl_label = 'Diffuse'
-    bl_icon = 'SOUND'
-
-    def init(self, context):
-
-        intensity=self.inputs.new('PovraySocketFloat_0_1', "Intensity")
-        intensity.default_value=0.8
-        albedo=self.inputs.new('NodeSocketBool', "Albedo")
-        albedo.default_value=False
-        brilliance=self.inputs.new('PovraySocketFloat_0_10', "Brilliance")
-        brilliance.default_value=1.8
-        self.inputs.new('PovraySocketFloat_0_1', "Crand")
-        self.outputs.new('NodeSocketVector', "Diffuse")
-
-    def draw_label(self):
-        return "Diffuse"
-
-class PovrayPhongNode(Node, ObjectNodeTree):
-    '''Phong'''
-    bl_idname = 'PovrayPhongNode'
-    bl_label = 'Phong'
-    bl_icon = 'SOUND'
-
-    def init(self, context):
-
-        albedo=self.inputs.new('NodeSocketBool', "Albedo")
-        intensity=self.inputs.new('PovraySocketFloat_0_1', "Intensity")
-        intensity.default_value=0.8
-        phong_size=self.inputs.new('PovraySocketInt_0_256', "Size")
-        phong_size.default_value=60
-        metallic=self.inputs.new('PovraySocketFloat_0_1', "Metallic")
-
-        self.outputs.new('NodeSocketVector', "Phong")
-
-    def draw_label(self):
-        return "Phong"
-
-class PovraySpecularNode(Node, ObjectNodeTree):
-    '''Specular'''
-    bl_idname = 'PovraySpecularNode'
-    bl_label = 'Specular'
-    bl_icon = 'SOUND'
-
-    def init(self, context):
-
-        albedo=self.inputs.new('NodeSocketBool', "Albedo")
-        intensity=self.inputs.new('PovraySocketFloat_0_1', "Intensity")
-        intensity.default_value=0.8
-        roughness=self.inputs.new('PovraySocketFloat_0_1', "Roughness")
-        roughness.default_value=0.02
-        metallic=self.inputs.new('PovraySocketFloat_0_1', "Metallic")
-
-        self.outputs.new('NodeSocketVector', "Specular")
-
-    def draw_label(self):
-        return "Specular"
-
-class PovrayMirrorNode(Node, ObjectNodeTree):
-    '''Mirror'''
-    bl_idname = 'PovrayMirrorNode'
-    bl_label = 'Mirror'
-    bl_icon = 'SOUND'
-
-    def init(self, context):
-
-        color=self.inputs.new('PovraySocketColor', "Color")
-        color.default_value=(1,1,1)
-        metallic=self.inputs.new('PovraySocketFloat_0_1', "Metallic")
-        metallic.default_value=1.0
-        exponent=self.inputs.new('PovraySocketFloat_0_1', "Exponent")
-        exponent.default_value=1.0
-        self.inputs.new('PovraySocketFloat_0_1', "Falloff")
-        self.inputs.new('NodeSocketBool', "Fresnel")
-        self.inputs.new('NodeSocketBool', "Conserve energy")
-        self.outputs.new('NodeSocketVector', "Mirror")
-
-    def draw_label(self):
-        return "Mirror"
-
-class PovrayAmbientNode(Node, ObjectNodeTree):
-    '''Ambient'''
-    bl_idname = 'PovrayAmbientNode'
-    bl_label = 'Ambient'
-    bl_icon = 'SOUND'
-
-    def init(self, context):
-
-        self.inputs.new('PovraySocketColor', "Ambient")
-
-        self.outputs.new('NodeSocketVector', "Ambient")
-
-    def draw_label(self):
-        return "Ambient"
-
-class PovrayIridescenceNode(Node, ObjectNodeTree):
-    '''Iridescence'''
-    bl_idname = 'PovrayIridescenceNode'
-    bl_label = 'Iridescence'
-    bl_icon = 'SOUND'
-
-    def init(self, context):
-
-        amount=self.inputs.new('NodeSocketFloat', "Amount")
-        amount.default_value=0.25
-        thickness=self.inputs.new('NodeSocketFloat', "Thickness")
-        thickness.default_value=1
-        self.inputs.new('NodeSocketFloat', "Turbulence")
-
-        self.outputs.new('NodeSocketVector', "Iridescence")
-
-    def draw_label(self):
-        return "Iridescence"
-
-class PovraySubsurfaceNode(Node, ObjectNodeTree):
-    '''Subsurface'''
-    bl_idname = 'PovraySubsurfaceNode'
-    bl_label = 'Subsurface'
-    bl_icon = 'SOUND'
-
-    def init(self, context):
-
-        translucency=self.inputs.new('NodeSocketColor', "Translucency")
-        translucency.default_value=(0,0,0,1)
-        energy=self.inputs.new('PovraySocketInt_0_256', "Energy")
-        energy.default_value=20
-        self.outputs.new('NodeSocketVector', "Translucency")
-
-    def draw_buttons(self, context, layout):
-        scene=context.scene
-        layout.prop(scene.pov, "sslt_enable",text="SSLT")
-
-
-    def draw_buttons_ext(self, context, layout):
-        scene=context.scene
-        layout.prop(scene.pov, "sslt_enable",text="SSLT")
-
-    def draw_label(self):
-        return "Subsurface"
-
-#####################################################################################################
-
-class PovrayMappingNode(Node, ObjectNodeTree):
-    '''Mapping'''
-    bl_idname = 'PovrayMappingNode'
-    bl_label = 'Mapping'
-    bl_icon = 'SOUND'
-
-    warp_type: EnumProperty(
-            name="Warp Types",
-            description="Select the type of warp",
-            items=( ('cubic', "Cubic", ""),  ('cylindrical', "Cylindrical", ""),('planar', "Planar", ""),
-                    ('spherical', "Spherical", ""),('toroidal', "Toroidal", ""),
-                    ('uv_mapping', "UV", ""),
-                    ('NONE', "None", "No indentation")),
-            default='NONE')
-
-    warp_orientation: EnumProperty(
-            name="Warp Orientation",
-            description="Select the orientation of warp",
-            items=(('x', "X", ""), ('y', "Y", ""), ('z', "Z", "")),
-            default='y')
-
-    warp_dist_exp: FloatProperty(
-            name="Distance exponent",
-            description="Distance exponent",
-            min=0.0, max=100.0, default=1.0)
-
-    warp_tor_major_radius: FloatProperty(
-            name="Major radius",
-            description="Torus is distance from major radius",
-            min=0.0, max=5.0, default=1.0)
-
-    def init(self, context):
-        self.outputs.new('NodeSocketVector', "Mapping")
-
-    def draw_buttons(self, context, layout):
-
-        column=layout.column()
-        column.prop(self,"warp_type",text="Warp type")
-        if self.warp_type in {'toroidal','spherical','cylindrical','planar'}:
-            column.prop(self,"warp_orientation",text="Orientation")
-            column.prop(self,"warp_dist_exp",text="Exponent")
-        if self.warp_type=='toroidal':
-            column.prop(self,"warp_tor_major_radius",text="Major R")
-
-    def draw_buttons_ext(self, context, layout):
-
-        column=layout.column()
-        column.prop(self,"warp_type",text="Warp type")
-        if self.warp_type in {'toroidal','spherical','cylindrical','planar'}:
-            column.prop(self,"warp_orientation",text="Orientation")
-            column.prop(self,"warp_dist_exp",text="Exponent")
-        if self.warp_type=='toroidal':
-            column.prop(self,"warp_tor_major_radius",text="Major R")
-
-    def draw_label(self):
-        return "Mapping"
-
-class PovrayMultiplyNode(Node, ObjectNodeTree):
-    '''Multiply'''
-    bl_idname = 'PovrayMultiplyNode'
-    bl_label = 'Multiply'
-    bl_icon = 'SOUND'
-
-    amount_x : FloatProperty(
-            name="X",
-            description="Number of repeats",
-            min=1.0, max=10000.0, default=1.0)
-
-    amount_y : FloatProperty(
-            name="Y",
-            description="Number of repeats",
-            min=1.0, max=10000.0, default=1.0)
-
-    amount_z : FloatProperty(
-            name="Z",
-            description="Number of repeats",
-            min=1.0, max=10000.0, default=1.0)
-
-
-    def init(self, context):
-        self.outputs.new('NodeSocketVector', "Amount")
-
-    def draw_buttons(self, context, layout):
-
-        column=layout.column()
-        column.label(text="Amount")
-        row=column.row(align=True)
-        row.prop(self,"amount_x")
-        row.prop(self,"amount_y")
-        row.prop(self,"amount_z")
-
-    def draw_buttons_ext(self, context, layout):
-
-        column=layout.column()
-        column.label(text="Amount")
-        row=column.row(align=True)
-        row.prop(self,"amount_x")
-        row.prop(self,"amount_y")
-        row.prop(self,"amount_z")
-
-    def draw_label(self):
-        return "Multiply"
-
-class PovrayTransformNode(Node, ObjectNodeTree):
-    '''Transform'''
-    bl_idname = 'PovrayTransformNode'
-    bl_label = 'Transform'
-    bl_icon = 'SOUND'
-
-    def init(self, context):
-
-        self.inputs.new('PovraySocketFloatUnlimited', "Translate x")
-        self.inputs.new('PovraySocketFloatUnlimited', "Translate y")
-        self.inputs.new('PovraySocketFloatUnlimited', "Translate z")
-        self.inputs.new('PovraySocketFloatUnlimited', "Rotate x")
-        self.inputs.new('PovraySocketFloatUnlimited', "Rotate y")
-        self.inputs.new('PovraySocketFloatUnlimited', "Rotate z")
-        sX = self.inputs.new('PovraySocketFloatUnlimited', "Scale x")
-        sX.default_value = 1.0
-        sY = self.inputs.new('PovraySocketFloatUnlimited', "Scale y")
-        sY.default_value = 1.0
-        sZ = self.inputs.new('PovraySocketFloatUnlimited', "Scale z")
-        sZ.default_value = 1.0
-
-        self.outputs.new('NodeSocketVector', "Transform")
-
-    def draw_label(self):
-        return "Transform"
-
-class PovrayValueNode(Node, ObjectNodeTree):
-    '''Value'''
-    bl_idname = 'PovrayValueNode'
-    bl_label = 'Value'
-    bl_icon = 'SOUND'
-
-    def init(self, context):
-
-        self.outputs.new('PovraySocketUniversal', "Value")
-
-    def draw_label(self):
-        return "Value"
-
-class PovrayModifierNode(Node, ObjectNodeTree):
-    '''Modifier'''
-    bl_idname = 'PovrayModifierNode'
-    bl_label = 'Modifier'
-    bl_icon = 'SOUND'
-
-    def init(self, context):
-
-        turb_x=self.inputs.new('PovraySocketFloat_0_10', "Turb X")
-        turb_x.default_value=0.1
-        turb_y=self.inputs.new('PovraySocketFloat_0_10', "Turb Y")
-        turb_y.default_value=0.1
-        turb_z=self.inputs.new('PovraySocketFloat_0_10', "Turb Z")
-        turb_z.default_value=0.1
-        octaves=self.inputs.new('PovraySocketInt_1_9', "Octaves")
-        octaves.default_value=1
-        lambat=self.inputs.new('PovraySocketFloat_0_10', "Lambda")
-        lambat.default_value=2.0
-        omega=self.inputs.new('PovraySocketFloat_0_10', "Omega")
-        omega.default_value=0.5
-        freq=self.inputs.new('PovraySocketFloat_0_10', "Frequency")
-        freq.default_value=2.0
-        self.inputs.new('PovraySocketFloat_0_10', "Phase")
-
-        self.outputs.new('NodeSocketVector', "Modifier")
-
-    def draw_label(self):
-        return "Modifier"
-
-class PovrayPigmentNode(Node, ObjectNodeTree):
-    '''Pigment'''
-    bl_idname = 'PovrayPigmentNode'
-    bl_label = 'Color'
-
-    def init(self, context):
-
-        color = self.inputs.new('PovraySocketColor', "Color")
-        color.default_value = (1,1,1)
-        povfilter = self.inputs.new('PovraySocketFloat_0_1', "Filter")
-        transmit = self.inputs.new('PovraySocketFloat_0_1', "Transmit")
-        self.outputs.new('NodeSocketColor', "Pigment")
-
-    def draw_label(self):
-        return "Color"
-
-class PovrayColorImageNode(Node, ObjectNodeTree):
-    '''ColorImage'''
-    bl_idname = 'PovrayColorImageNode'
-    bl_label = 'Image map'
-
-    map_type: bpy.props.EnumProperty(
-            name="Map type",
-            description="",
-            items=( ('uv_mapping', "UV", ""),
-                    ('0', "Planar", "Default planar mapping"),
-                    ('1', "Spherical", "Spherical mapping"),
-                    ('2', "Cylindrical", "Cylindrical mapping"),
-                    ('5', "Torroidal", "Torus or donut shaped mapping")),
-            default='0')
-    image: StringProperty(maxlen=1024) # , subtype="FILE_PATH"
-    interpolate: EnumProperty(
-            name="Interpolate",
-            description="Adding the interpolate keyword can smooth the jagged look of a bitmap",
-            items=(
-                ('2', "Bilinear", "Gives bilinear interpolation"),
-                ('4', "Normalized", "Gives normalized distance"),
-            ),
-            default='2')
-    premultiplied: BoolProperty(default=False)
-    once: BoolProperty(description="Not to repeat", default=False)
-
-    def init(self, context):
-
-        gamma=self.inputs.new('PovraySocketFloat_000001_10', "Gamma")
-        gamma.default_value=2.0
-        transmit=self.inputs.new('PovraySocketFloat_0_1', "Transmit")
-        povfilter=self.inputs.new('PovraySocketFloat_0_1', "Filter")
-        mapping=self.inputs.new('NodeSocketVector', "Mapping")
-        mapping.hide_value=True
-        transform=self.inputs.new('NodeSocketVector', "Transform")
-        transform.hide_value=True
-        modifier=self.inputs.new('NodeSocketVector', "Modifier")
-        modifier.hide_value=True
-
-        self.outputs.new('NodeSocketColor', "Pigment")
-
-    def draw_buttons(self, context, layout):
-
-        column=layout.column()
-        im=None
-        for image in bpy.data.images:
-            if image.name == self.image:
-                im=image
-        split = column.split(factor=0.8,align=True)
-        split.prop_search(self,"image",context.blend_data,"images",text="")
-        split.operator("pov.imageopen",text="",icon="FILEBROWSER")
-        if im is not None:
-            column.prop(im,"source",text="")
-        column.prop(self,"map_type",text="")
-        column.prop(self,"interpolate",text="")
-        row=column.row()
-        row.prop(self,"premultiplied",text="Premul")
-        row.prop(self,"once",text="Once")
-
-    def draw_buttons_ext(self, context, layout):
-
-        column=layout.column()
-        im=None
-        for image in bpy.data.images:
-            if image.name == self.image:
-                im=image
-        split = column.split(factor=0.8,align=True)
-        split.prop_search(self,"image",context.blend_data,"images",text="")
-        split.operator("pov.imageopen",text="",icon="FILEBROWSER")
-        if im is not None:
-            column.prop(im,"source",text="")
-        column.prop(self,"map_type",text="")
-        column.prop(self,"interpolate",text="")
-        row=column.row()
-        row.prop(self,"premultiplied",text="Premul")
-        row.prop(self,"once",text="Once")
-
-    def draw_label(self):
-        return "Image map"
-
-class PovrayBumpMapNode(Node, ObjectNodeTree):
-    '''BumpMap'''
-    bl_idname = 'PovrayBumpMapNode'
-    bl_label = 'Bump map'
-    bl_icon = 'SOUND'
-
-    map_type : bpy.props.EnumProperty(
-            name="Map type",
-            description="",
-            items=(
-                ('uv_mapping', "UV", ""),
-                ('0', "Planar", "Default planar mapping"),
-                ('1', "Spherical", "Spherical mapping"),
-                ('2', "Cylindrical", "Cylindrical mapping"),
-                ('5', "Torroidal", "Torus or donut shaped mapping")
-            ),
-            default='0')
-    image : StringProperty(maxlen=1024) # , subtype="FILE_PATH"
-    interpolate : EnumProperty(
-            name="Interpolate",
-            description="Adding the interpolate keyword can smooth the jagged look of a bitmap",
-            items=(
-                ('2', "Bilinear", "Gives bilinear interpolation"),
-                ('4', "Normalized", "Gives normalized distance"),
-            ),
-            default='2')
-    once : BoolProperty(description="Not to repeat", default=False)
-
-    def init(self, context):
-
-        self.inputs.new('PovraySocketFloat_0_10', "Normal")
-        mapping=self.inputs.new('NodeSocketVector', "Mapping")
-        mapping.hide_value=True
-        transform=self.inputs.new('NodeSocketVector', "Transform")
-        transform.hide_value=True
-        modifier=self.inputs.new('NodeSocketVector', "Modifier")
-        modifier.hide_value=True
-
-        normal=self.outputs.new('NodeSocketFloat', "Normal")
-        normal.hide_value=True
-
-    def draw_buttons(self, context, layout):
-
-        column=layout.column()
-        im=None
-        for image in bpy.data.images:
-            if image.name == self.image:
-                im=image
-        split = column.split(percentage=0.8,align=True)
-        split.prop_search(self,"image",context.blend_data,"images",text="")
-        split.operator("pov.imageopen",text="",icon="FILEBROWSER")
-        if im is not None:
-            column.prop(im,"source",text="")
-        column.prop(self,"map_type",text="")
-        column.prop(self,"interpolate",text="")
-        column.prop(self,"once",text="Once")
-
-    def draw_buttons_ext(self, context, layout):
-
-        column=layout.column()
-        im=None
-        for image in bpy.data.images:
-            if image.name == self.image:
-                im=image
-        split = column.split(percentage=0.8,align=True)
-        split.prop_search(self,"image",context.blend_data,"images",text="")
-        split.operator("pov.imageopen",text="",icon="FILEBROWSER")
-        if im is not None:
-            column.prop(im,"source",text="")
-        column.prop(self,"map_type",text="")
-        column.prop(self,"interpolate",text="")
-        column.prop(self,"once",text="Once")
-
-    def draw_label(self):
-        return "Bump Map"
-
-class PovrayImagePatternNode(Node, ObjectNodeTree):
-    '''ImagePattern'''
-    bl_idname = 'PovrayImagePatternNode'
-    bl_label = 'Image pattern'
-    bl_icon = 'SOUND'
-
-    map_type: bpy.props.EnumProperty(
-            name="Map type",
-            description="",
-            items=(
-                ('uv_mapping', "UV", ""),
-                ('0', "Planar", "Default planar mapping"),
-                ('1', "Spherical", "Spherical mapping"),
-                ('2', "Cylindrical", "Cylindrical mapping"),
-                ('5', "Torroidal", "Torus or donut shaped mapping"),
-            ),
-            default='0')
-    image: StringProperty(maxlen=1024) # , subtype="FILE_PATH"
-    interpolate: EnumProperty(
-            name="Interpolate",
-            description="Adding the interpolate keyword can smooth the jagged look of a bitmap",
-            items=(
-                ('2', "Bilinear", "Gives bilinear interpolation"),
-                ('4', "Normalized", "Gives normalized distance"),
-            ),
-            default='2')
-    premultiplied: BoolProperty(default=False)
-    once: BoolProperty(description="Not to repeat", default=False)
-    use_alpha: BoolProperty(default=True)
-    def init(self, context):
-
-        gamma=self.inputs.new('PovraySocketFloat_000001_10', "Gamma")
-        gamma.default_value=2.0
-
-        self.outputs.new('PovraySocketPattern', "Pattern")
-
-    def draw_buttons(self, context, layout):
-
-        column=layout.column()
-        im=None
-        for image in bpy.data.images:
-            if image.name == self.image:
-                im=image
-        split = column.split(factor=0.8,align=True)
-        split.prop_search(self,"image",context.blend_data,"images",text="")
-        split.operator("pov.imageopen",text="",icon="FILEBROWSER")
-        if im is not None:
-            column.prop(im,"source",text="")
-        column.prop(self,"map_type",text="")
-        column.prop(self,"interpolate",text="")
-        row=column.row()
-        row.prop(self,"premultiplied",text="Premul")
-        row.prop(self,"once",text="Once")
-        column.prop(self,"use_alpha",text="Use alpha")
-
-    def draw_buttons_ext(self, context, layout):
-
-        column=layout.column()
-        im=None
-        for image in bpy.data.images:
-            if image.name == self.image:
-                im=image
-        split = column.split(factor=0.8,align=True)
-        split.prop_search(self,"image",context.blend_data,"images",text="")
-        split.operator("pov.imageopen",text="",icon="FILEBROWSER")
-        if im is not None:
-            column.prop(im,"source",text="")
-        column.prop(self,"map_type",text="")
-        column.prop(self,"interpolate",text="")
-        row=column.row()
-        row.prop(self,"premultiplied",text="Premul")
-        row.prop(self,"once",text="Once")
-
-    def draw_label(self):
-        return "Image pattern"
-
-class ShaderPatternNode(Node, ObjectNodeTree):
-    '''Pattern'''
-    bl_idname = 'ShaderPatternNode'
-    bl_label = 'Other patterns'
-
-    pattern : EnumProperty(
-            name="Pattern",
-            description="Agate, Crackle, Gradient, Pavement, Spiral, Tiling",
-            items=(('agate', "Agate", ""),('crackle', "Crackle", ""),('gradient', "Gradient", ""),
-                   ('pavement', "Pavement", ""),
-                   ('spiral1', "Spiral 1", ""),
-                   ('spiral2', "Spiral 2", ""),
-                   ('tiling', "Tiling", "")),
-            default='agate')
-
-    agate_turb : FloatProperty(
-            name="Agate turb",
-            description="Agate turbulence",
-            min=0.0, max=100.0, default=0.5)
-
-    crackle_form_x : FloatProperty(
-            name="X",
-            description="Form vector X",
-            min=-150.0, max=150.0, default=-1)
-
-    crackle_form_y : FloatProperty(
-            name="Y",
-            description="Form vector Y",
-            min=-150.0, max=150.0, default=1)
-
-    crackle_form_z : FloatProperty(
-            name="Z",
-            description="Form vector Z",
-            min=-150.0, max=150.0, default=0)
-
-    crackle_metric : FloatProperty(
-            name="Metric",
-            description="Crackle metric",
-            min=0.0, max=150.0, default=1)
-
-    crackle_solid : BoolProperty(
-            name="Solid",
-            description="Crackle solid",
-            default=False)
-
-    spiral_arms : FloatProperty(
-            name="Number",
-            description="",
-            min=0.0, max=256.0, default=2.0)
-
-    tiling_number : IntProperty(
-            name="Number",
-            description="",
-            min=1, max=27, default=1)
-
-    gradient_orient : EnumProperty(
-            name="Orient",
-            description="",
-            items=(('x', "X", ""),
-                   ('y', "Y", ""),
-                   ('z', "Z", "")),
-            default='x')
-
-    def init(self, context):
-
-        pat = self.outputs.new('PovraySocketPattern', "Pattern")
-
-    def draw_buttons(self, context, layout):
-
-        layout.prop(self, "pattern",text="")
-        if self.pattern=='agate':
-            layout.prop(self, "agate_turb")
-        if self.pattern=='crackle':
-            layout.prop(self, "crackle_metric")
-            layout.prop(self, "crackle_solid")
-            layout.label(text="Form:")
-            layout.prop(self, "crackle_form_x")
-            layout.prop(self, "crackle_form_y")
-            layout.prop(self, "crackle_form_z")
-        if self.pattern in {"spiral1","spiral2"}:
-            layout.prop(self, "spiral_arms")
-        if self.pattern in {'tiling'}:
-            layout.prop(self, "tiling_number")
-        if self.pattern in {'gradient'}:
-            layout.prop(self, "gradient_orient")
-    def draw_buttons_ext(self, context, layout):
-        pass
-
-    def draw_label(self):
-        return "Other patterns"
-
-class ShaderTextureMapNode(Node, ObjectNodeTree):
-    '''Texture Map'''
-    bl_idname = 'ShaderTextureMapNode'
-    bl_label = 'Texture map'
-
-    brick_size_x: FloatProperty(
-            name="X",
-            description="",
-            min=0.0000, max=1.0000, default=0.2500)
-
-    brick_size_y: FloatProperty(
-            name="Y",
-            description="",
-            min=0.0000, max=1.0000, default=0.0525)
-
-    brick_size_z: FloatProperty(
-            name="Z",
-            description="",
-            min=0.0000, max=1.0000, default=0.1250)
-
-    brick_mortar: FloatProperty(
-            name="Mortar",
-            description="Mortar",
-            min=0.000, max=1.500, default=0.01)
-
-    def init(self, context):
-        mat = bpy.context.object.active_material
-        self.inputs.new('PovraySocketPattern', "")
-        color = self.inputs.new('NodeSocketColor', "Color ramp")
-        color.hide_value = True
-        for i in range(0,4):
-            transform=self.inputs.new('PovraySocketTransform', "Transform")
-            transform.hide_value=True
-        number = mat.pov.inputs_number
-        for i in range(number):
-            self.inputs.new('PovraySocketTexture', "%s"%i)
-
-
-        self.outputs.new('PovraySocketTexture', "Texture")
-
-    def draw_buttons(self, context, layout):
-
-        if self.inputs[0].default_value =='brick':
-            layout.prop(self, "brick_mortar")
-            layout.label(text="Brick size:")
-            layout.prop(self, "brick_size_x")
-            layout.prop(self, "brick_size_y")
-            layout.prop(self, "brick_size_z")
-
-    def draw_buttons_ext(self, context, layout):
-
-        if self.inputs[0].default_value =='brick':
-            layout.prop(self, "brick_mortar")
-            layout.label(text="Brick size:")
-            layout.prop(self, "brick_size_x")
-            layout.prop(self, "brick_size_y")
-            layout.prop(self, "brick_size_z")
-
-    def draw_label(self):
-        return "Texture map"
-
-
-class ShaderNormalMapNode(Node, ObjectNodeTree):
-    '''Normal Map'''
-    bl_idname = 'ShaderNormalMapNode'
-    bl_label = 'Normal map'
-
-    brick_size_x : FloatProperty(
-            name="X",
-            description="",
-            min=0.0000, max=1.0000, default=0.2500)
-
-    brick_size_y : FloatProperty(
-            name="Y",
-            description="",
-            min=0.0000, max=1.0000, default=0.0525)
-
-    brick_size_z : FloatProperty(
-            name="Z",
-            description="",
-            min=0.0000, max=1.0000, default=0.1250)
-
-    brick_mortar : FloatProperty(
-            name="Mortar",
-            description="Mortar",
-            min=0.000, max=1.500, default=0.01)
-
-    def init(self, context):
-        self.inputs.new('PovraySocketPattern', "")
-        normal = self.inputs.new('PovraySocketFloat_10', "Normal")
-        slope = self.inputs.new('PovraySocketMap', "Slope map")
-        for i in range(0,4):
-            transform=self.inputs.new('PovraySocketTransform', "Transform")
-            transform.hide_value=True
-        self.outputs.new('PovraySocketNormal', "Normal")
-
-    def draw_buttons(self, context, layout):
-        #for i, inp in enumerate(self.inputs):
-
-        if self.inputs[0].default_value =='brick':
-            layout.prop(self, "brick_mortar")
-            layout.label(text="Brick size:")
-            layout.prop(self, "brick_size_x")
-            layout.prop(self, "brick_size_y")
-            layout.prop(self, "brick_size_z")
-
-    def draw_buttons_ext(self, context, layout):
-
-        if self.inputs[0].default_value =='brick':
-            layout.prop(self, "brick_mortar")
-            layout.label(text="Brick size:")
-            layout.prop(self, "brick_size_x")
-            layout.prop(self, "brick_size_y")
-            layout.prop(self, "brick_size_z")
-
-    def draw_label(self):
-        return "Normal map"
-
-class ShaderNormalMapEntryNode(Node, ObjectNodeTree):
-    '''Normal Map Entry'''
-    bl_idname = 'ShaderNormalMapEntryNode'
-    bl_label = 'Normal map entry'
-
-    def init(self, context):
-        self.inputs.new('PovraySocketFloat_0_1', "Stop")
-        self.inputs.new('PovraySocketFloat_0_1', "Gray")
-    def draw_label(self):
-        return "Normal map entry"
-
-class IsoPropsNode(Node, CompositorNodeTree):
-    '''ISO Props'''
-    bl_idname = 'IsoPropsNode'
-    bl_label = 'Iso'
-    node_label : StringProperty(maxlen=1024)
-    def init(self, context):
-        ob = bpy.context.object
-        self.node_label = ob.name
-        textName = ob.pov.function_text
-        if textName:
-            text = bpy.data.texts[textName]
-            for line in text.lines:
-                split = line.body.split()
-                if split[0] == "#declare":
-                    socket = self.inputs.new('NodeSocketFloat', "%s"%split[1])
-                    value = split[3].split(";")
-                    value = value[0]
-                    socket.default_value=float(value)
-    def draw_label(self):
-        return self.node_label
-
-class PovrayFogNode(Node, CompositorNodeTree):
-    '''Fog settings'''
-    bl_idname = 'PovrayFogNode'
-    bl_label = 'Fog'
-    def init(self, context):
-        color=self.inputs.new('NodeSocketColor', "Color")
-        color.default_value=(0.7,0.7,0.7,0.25)
-        self.inputs.new('PovraySocketFloat_0_1', "Filter")
-        distance = self.inputs.new('NodeSocketInt', "Distance")
-        distance.default_value=150
-        self.inputs.new('NodeSocketBool', "Ground")
-        fog_offset=self.inputs.new('NodeSocketFloat', "Offset")
-        fog_alt=self.inputs.new('NodeSocketFloat', "Altitude")
-        turb = self.inputs.new('NodeSocketVector', "Turbulence")
-        turb_depth=self.inputs.new('PovraySocketFloat_0_10', "Depth")
-        turb_depth.default_value=0.5
-        octaves=self.inputs.new('PovraySocketInt_1_9', "Octaves")
-        octaves.default_value=5
-        lambdat=self.inputs.new('PovraySocketFloat_0_10', "Lambda")
-        lambdat.default_value=1.25
-        omega=self.inputs.new('PovraySocketFloat_0_10', "Omega")
-        omega.default_value=0.35
-        translate = self.inputs.new('NodeSocketVector', "Translate")
-        rotate = self.inputs.new('NodeSocketVector', "Rotate")
-        scale = self.inputs.new('NodeSocketVector', "Scale")
-        scale.default_value=(1,1,1)
-    def draw_label(self):
-        return "Fog"
-
-class PovraySlopeNode(Node, TextureNodeTree):
-    '''Output'''
-    bl_idname = 'PovraySlopeNode'
-    bl_label = 'Slope Map'
-
-    def init(self, context):
-        self.use_custom_color = True
-        self.color = (0,0.2,0)
-        slope = self.inputs.new('PovraySocketSlope', "0")
-        slope = self.inputs.new('PovraySocketSlope', "1")
-        slopemap = self.outputs.new('PovraySocketMap', "Slope map")
-        output.hide_value = True
-    def draw_buttons(self, context, layout):
-
-        layout.operator("pov.nodeinputadd")
-        row = layout.row()
-        row.label(text='Value')
-        row.label(text='Height')
-        row.label(text='Slope')
-
-    def draw_buttons_ext(self, context, layout):
-
-        layout.operator("pov.nodeinputadd")
-        row = layout.row()
-        row.label(text='Value')
-        row.label(text='Height')
-        row.label(text='Slope')
-
-    def draw_label(self):
-        return "Slope Map"
-
-######################################## Texture nodes ###############################
-class TextureOutputNode(Node, TextureNodeTree):
-    '''Output'''
-    bl_idname = 'TextureOutputNode'
-    bl_label = 'Color Map'
-
-    def init(self, context):
-        tex = bpy.context.object.active_material.active_texture
-        num_sockets = int(tex.pov.density_lines/32)
-        for i in range(num_sockets):
-            color = self.inputs.new('NodeSocketColor', "%s"%i)
-            color.hide_value = True
-
-    def draw_buttons(self, context, layout):
-
-        layout.label(text="Color Ramps:")
-
-    def draw_label(self):
-        return "Color Map"
-
-
-##################################################################################
-#################################Operators########################################
-##################################################################################
-
-
-class NODE_OT_iso_add(Operator):
-    bl_idname = "pov.nodeisoadd"
-    bl_label = "Create iso props"
-
-    def execute(self, context):
-        ob = bpy.context.object
-        if bpy.context.scene.use_nodes == False:
-            bpy.context.scene.use_nodes = True
-        tree = bpy.context.scene.node_tree
-        for node in tree.nodes:
-            if node.bl_idname == "IsoPropsNode" and node.label == ob.name:
-                tree.nodes.remove(node)
-        isonode = tree.nodes.new('IsoPropsNode')
-        isonode.location = (0,0)
-        isonode.label = ob.name
-        return {'FINISHED'}
-
-class NODE_OT_map_create(Operator):
-    bl_idname = "node.map_create"
-    bl_label = "Create map"
-
-    def execute(self, context):
-        x = y = 0
-        space = context.space_data
-        tree = space.edit_tree
-        for node in tree.nodes:
-            if node.select == True:
-                x,y = node.location
-            node.select=False
-        tmap = tree.nodes.new('ShaderTextureMapNode')
-        tmap.location = (x - 200,y)
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        wm = context.window_manager
-        return wm.invoke_props_dialog(self)
-
-    def draw(self, context):
-        layout = self.layout
-        mat = context.object.active_material
-        layout.prop(mat.pov,"inputs_number")
-
-class NODE_OT_povray_node_texture_map_add(Operator):
-    bl_idname = "pov.nodetexmapadd"
-    bl_label = "Texture map"
-
-    def execute(self, context):
-        tree=bpy.context.object.active_material.node_tree
-        tmap = tree.nodes.active
-        bpy.context.object.active_material.node_tree.nodes.active=tmap
-        el=tmap.color_ramp.elements.new(0.5)
-        for el in tmap.color_ramp.elements:
-            el.color=(0,0,0,1)
-        for inp in tmap.inputs:
-            tmap.inputs.remove(inp)
-        for outp in tmap.outputs:
-            tmap.outputs.remove(outp)
-        pattern=tmap.inputs.new('NodeSocketVector', "Pattern")
-        pattern.hide_value=True
-        for i in range(0,3):
-            tmap.inputs.new('NodeSocketColor', "Shader")
-        tmap.outputs.new('NodeSocketShader', "BSDF")
-        tmap.label="Texture Map"
-        return {'FINISHED'}
-
-
-class NODE_OT_povray_node_output_add(Operator):
-    bl_idname = "pov.nodeoutputadd"
-    bl_label = "Output"
-
-    def execute(self, context):
-        tree=bpy.context.object.active_material.node_tree
-        tmap = tree.nodes.new('ShaderNodeOutputMaterial')
-        bpy.context.object.active_material.node_tree.nodes.active=tmap
-        for inp in tmap.inputs:
-            tmap.inputs.remove(inp)
-        tmap.inputs.new('NodeSocketShader', "Surface")
-        tmap.label="Output"
-        return {'FINISHED'}
-
-class NODE_OT_povray_node_layered_add(Operator):
-    bl_idname = "pov.nodelayeredadd"
-    bl_label = "Layered material"
-
-    def execute(self, context):
-        tree=bpy.context.object.active_material.node_tree
-        tmap = tree.nodes.new('ShaderNodeAddShader')
-        bpy.context.object.active_material.node_tree.nodes.active=tmap
-        tmap.label="Layered material"
-        return {'FINISHED'}
-
-class NODE_OT_povray_input_add(Operator):
-    bl_idname = "pov.nodeinputadd"
-    bl_label = "Add entry"
-
-    def execute(self, context):
-        node=bpy.context.object.active_material.node_tree.nodes.active
-        if node.type in {'VALTORGB'}:
-            number=1
-            for inp in node.inputs:
-                if inp.type=='SHADER':
-                    number+=1
-            node.inputs.new('NodeSocketShader', "%s"%number)
-            els=node.color_ramp.elements
-            pos1=els[len(els)-1].position
-            pos2=els[len(els)-2].position
-            pos=(pos1-pos2)/2+pos2
-            el=els.new(pos)
-
-        if node.bl_idname == 'PovraySlopeNode':
-            number=len(node.inputs)
-            node.inputs.new('PovraySocketSlope', "%s"%number)
-
-
-        return {'FINISHED'}
-
-class NODE_OT_povray_input_remove(Operator):
-    bl_idname = "pov.nodeinputremove"
-    bl_label = "Remove input"
-
-    def execute(self, context):
-        node=bpy.context.object.active_material.node_tree.nodes.active
-        if node.type in {'VALTORGB','ADD_SHADER'}:
-            number=len(node.inputs)-1
-            if number > 5:
-                inp=node.inputs[number]
-                node.inputs.remove(inp)
-                if node.type in {'VALTORGB'}:
-                    els=node.color_ramp.elements
-                    number=len(els)-2
-                    el=els[number]
-                    els.remove(el)
-        return {'FINISHED'}
-
-class NODE_OT_povray_image_open(Operator):
-    bl_idname = "pov.imageopen"
-    bl_label = "Open"
-
-    filepath: StringProperty(
-            name="File Path",
-            description="Open image",
-            maxlen=1024,
-            subtype='FILE_PATH',
-            )
-
-    def invoke(self, context, event):
-        context.window_manager.fileselect_add(self)
-        return {'RUNNING_MODAL'}
-
-    def execute(self, context):
-        im=bpy.data.images.load(self.filepath)
-        node=context.object.active_material.node_tree.nodes.active
-        node.image = im.name
-        return {'FINISHED'}
-
-
-# class TEXTURE_OT_povray_open_image(Operator):
-    # bl_idname = "pov.openimage"
-    # bl_label = "Open Image"
-
-    # filepath = StringProperty(
-            # name="File Path",
-            # description="Open image",
-            # maxlen=1024,
-            # subtype='FILE_PATH',
-            # )
-
-    # def invoke(self, context, event):
-        # context.window_manager.fileselect_add(self)
-        # return {'RUNNING_MODAL'}
-
-    # def execute(self, context):
-        # im=bpy.data.images.load(self.filepath)
-        # tex = context.texture
-        # tex.pov.image = im.name
-        # view_layer = context.view_layer
-        # view_layer.update()
-        # return {'FINISHED'}
-
-class PovrayPatternNode(Operator):
-    bl_idname = "pov.patternnode"
-    bl_label  = "Pattern"
-
-    add=True
-
-    def execute(self, context):
-        space = context.space_data
-        tree = space.edit_tree
-        for node in tree.nodes:
-            node.select=False
-        if self.add==True:
-            tmap = tree.nodes.new('ShaderNodeValToRGB')
-            tmap.label="Pattern"
-            for inp in tmap.inputs:
-                tmap.inputs.remove(inp)
-            for outp in tmap.outputs:
-                tmap.outputs.remove(outp)
-            pattern = tmap.inputs.new('PovraySocketPattern', "Pattern")
-            pattern.hide_value = True
-            mapping=tmap.inputs.new('NodeSocketVector', "Mapping")
-            mapping.hide_value=True
-            transform=tmap.inputs.new('NodeSocketVector', "Transform")
-            transform.hide_value=True
-            modifier=tmap.inputs.new('NodeSocketVector', "Modifier")
-            modifier.hide_value=True
-            for i in range(0,2):
-                tmap.inputs.new('NodeSocketShader', "%s"%(i+1))
-            tmap.outputs.new('NodeSocketShader', "Material")
-            tmap.outputs.new('NodeSocketColor', "Color")
-            tree.nodes.active=tmap
-            self.add=False
-        aNode=tree.nodes.active
-        aNode.select=True
-        v2d = context.region.view2d
-        x, y = v2d.region_to_view(self.x, self.y)
-        aNode.location = (x, y)
-
-    def modal(self, context, event):
-        if event.type == 'MOUSEMOVE':
-            self.x = event.mouse_region_x
-            self.y = event.mouse_region_y
-            self.execute(context)
-            return {'RUNNING_MODAL'}
-        elif event.type == 'LEFTMOUSE':
-            return {'FINISHED'}
-        elif event.type in ('RIGHTMOUSE', 'ESC'):
-            return {'CANCELLED'}
-
-        return {'RUNNING_MODAL'}
-
-    def invoke(self, context, event):
-        context.window_manager.modal_handler_add(self)
-        return {'RUNNING_MODAL'}
-
-class UpdatePreviewMaterial(Operator):
-    '''Operator update preview material'''
-    bl_idname = "node.updatepreview"
-    bl_label = "Update preview"
-
-    def execute(self, context):
-        scene=context.view_layer
-        ob=context.object
-        for obj in scene.objects:
-            if obj != ob:
-                scene.objects.active = ob
-                break
-        scene.objects.active = ob
-
-    def modal(self, context, event):
-        if event.type == 'RIGHTMOUSE':
-            self.execute(context)
-            return {'FINISHED'}
-        return {'PASS_THROUGH'}
-
-    def invoke(self, context, event):
-        context.window_manager.modal_handler_add(self)
-        return {'RUNNING_MODAL'}
-
-class UpdatePreviewKey(Operator):
-    '''Operator update preview keymap'''
-    bl_idname = "wm.updatepreviewkey"
-    bl_label = "Activate RMB"
-    @classmethod
-    def poll(cls, context):
-        conf = context.window_manager.keyconfigs.active
-        mapstr = "Node Editor"
-        map = conf.keymaps[mapstr]
-        try:
-            map.keymap_items["node.updatepreview"]
-            return False
-        except:
-            return True
-
-    def execute(self, context):
-        conf = context.window_manager.keyconfigs.active
-        mapstr = "Node Editor"
-        map = conf.keymaps[mapstr]
-        map.keymap_items.new("node.updatepreview",type='RIGHTMOUSE',value="PRESS")
-        return {'FINISHED'}
-
-classes = (
-    ObjectNodeTree,
-    PovrayOutputNode,
-    PovrayTextureNode,
-    PovrayFinishNode,
-    PovrayDiffuseNode,
-    PovrayPhongNode,
-    PovraySpecularNode,
-    PovrayMirrorNode,
-    PovrayAmbientNode,
-    PovrayIridescenceNode,
-    PovraySubsurfaceNode,
-    PovrayMappingNode,
-    PovrayMultiplyNode,
-    PovrayTransformNode,
-    PovrayValueNode,
-    PovrayModifierNode,
-    PovrayPigmentNode,
-    PovrayColorImageNode,
-    PovrayBumpMapNode,
-    PovrayImagePatternNode,
-    ShaderPatternNode,
-    ShaderTextureMapNode,
-    ShaderNormalMapNode,
-    ShaderNormalMapEntryNode,
-    IsoPropsNode,
-    PovrayFogNode,
-    PovraySlopeNode,
-    TextureOutputNode,
-    NODE_OT_iso_add,
-    NODE_OT_map_create,
-    NODE_OT_povray_node_texture_map_add,
-    NODE_OT_povray_node_output_add,
-    NODE_OT_povray_node_layered_add,
-    NODE_OT_povray_input_add,
-    NODE_OT_povray_input_remove,
-    NODE_OT_povray_image_open,
-    PovrayPatternNode,
-    UpdatePreviewMaterial,
-    UpdatePreviewKey,
-)
-
-
-def register():
-    #from bpy.utils import register_class
-
-    for cls in classes:
-        register_class(cls)
-
-
-def unregister():
-    from bpy.utils import unregister_class
-
-    for cls in classes:
-        unregister_class(cls)
diff --git a/render_povray/object_curve_topology.py b/render_povray/object_curve_topology.py
new file mode 100755
index 000000000..5fa2b277b
--- /dev/null
+++ b/render_povray/object_curve_topology.py
@@ -0,0 +1,974 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# #**** END GPL LICENSE BLOCK #****
+
+# <pep8 compliant>
+
+"""Translate to POV the control point compounded geometries like polygon
+
+meshes or curve based shapes.
+"""
+
+import bpy
+
+from .shading import write_object_material
+
+################################ LOFT, ETC.
+def export_curves(ob, string_strip_hyphen, global_matrix, tab_write):
+    """write all curves based POV primitives to exported file """
+    name_orig = "OB" + ob.name
+    dataname_orig = "DATA" + ob.data.name
+
+    name = string_strip_hyphen(bpy.path.clean_name(name_orig))
+    dataname = string_strip_hyphen(bpy.path.clean_name(dataname_orig))
+
+    matrix = global_matrix @ ob.matrix_world
+    bezier_sweep = False
+    if ob.pov.curveshape == 'sphere_sweep':
+        # inlined spheresweep macro, which itself calls Shapes.inc:
+        file.write('        #include "shapes.inc"\n')
+
+        file.write(
+            '        #macro Shape_Bezierpoints_Sphere_Sweep(_merge_shape, _resolution, _points_array, _radius_array)\n'
+        )
+        file.write('        //input adjusting and inspection\n')
+        file.write('        #if(_resolution <= 1)\n')
+        file.write('            #local res = 1;\n')
+        file.write('        #else\n')
+        file.write('            #local res = int(_resolution);\n')
+        file.write('        #end\n')
+        file.write('        #if(dimensions(_points_array) != 1 | dimensions(_radius_array) != 1)\n')
+        file.write('            #error ""\n')
+        file.write(
+            '        #elseif(div(dimension_size(_points_array,1),4) - dimension_size(_points_array,1)/4 != 0)\n'
+        )
+        file.write('            #error ""\n')
+        file.write(
+            '        #elseif(dimension_size(_points_array,1) != dimension_size(_radius_array,1))\n'
+        )
+        file.write('            #error ""\n')
+        file.write('        #else\n')
+        file.write('            #local n_of_seg = div(dimension_size(_points_array,1), 4);\n')
+        file.write('            #local ctrl_pts_array = array[n_of_seg]\n')
+        file.write('            #local ctrl_rs_array = array[n_of_seg]\n')
+        file.write('            #for(i, 0, n_of_seg-1)\n')
+        file.write(
+            '                #local ctrl_pts_array[i] = array[4] {_points_array[4*i], _points_array[4*i+1], _points_array[4*i+2], _points_array[4*i+3]}\n'
+        )
+        file.write(
+            '                #local ctrl_rs_array[i] = array[4] {abs(_radius_array[4*i]), abs(_radius_array[4*i+1]), abs(_radius_array[4*i+2]), abs(_radius_array[4*i+3])}\n'
+        )
+        file.write('            #end\n')
+        file.write('        #end\n')
+
+        file.write('        //drawing\n')
+        file.write('        #local mockup1 =\n')
+        file.write('        #if(_merge_shape) merge{ #else union{ #end\n')
+        file.write('            #for(i, 0, n_of_seg-1)\n')
+        file.write('                #local has_head = true;\n')
+        file.write('                #if(i = 0)\n')
+        file.write(
+            '                    #if(vlength(ctrl_pts_array[i][0]-ctrl_pts_array[n_of_seg-1][3]) = 0 & ctrl_rs_array[i][0]-ctrl_rs_array[n_of_seg-1][3] <= 0)\n'
+        )
+        file.write('                        #local has_head = false;\n')
+        file.write('                    #end\n')
+        file.write('                #else\n')
+        file.write(
+            '                    #if(vlength(ctrl_pts_array[i][0]-ctrl_pts_array[i-1][3]) = 0 & ctrl_rs_array[i][0]-ctrl_rs_array[i-1][3] <= 0)\n'
+        )
+        file.write('                        #local has_head = false;\n')
+        file.write('                    #end\n')
+        file.write('                #end\n')
+        file.write('                #if(has_head = true)\n')
+        file.write('                    sphere{\n')
+        file.write('                    ctrl_pts_array[i][0], ctrl_rs_array[i][0]\n')
+        file.write('                    }\n')
+        file.write('                #end\n')
+        file.write('                #local para_t = (1/2)/res;\n')
+        file.write(
+            '                #local this_point = ctrl_pts_array[i][0]*pow(1-para_t,3) + ctrl_pts_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_pts_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_pts_array[i][3]*pow(para_t,3);\n'
+        )
+        file.write(
+            '                #local this_radius = ctrl_rs_array[i][0]*pow(1-para_t,3) + ctrl_rs_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_rs_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_rs_array[i][3]*pow(para_t,3);\n'
+        )
+        file.write(
+            '                #if(vlength(this_point-ctrl_pts_array[i][0]) > abs(this_radius-ctrl_rs_array[i][0]))\n'
+        )
+        file.write('                    object{\n')
+        file.write(
+            '                    Connect_Spheres(ctrl_pts_array[i][0], ctrl_rs_array[i][0], this_point, this_radius)\n'
+        )
+        file.write('                    }\n')
+        file.write('                #end\n')
+        file.write('                sphere{\n')
+        file.write('                this_point, this_radius\n')
+        file.write('                }\n')
+        file.write('                #for(j, 1, res-1)\n')
+        file.write('                    #local last_point = this_point;\n')
+        file.write('                    #local last_radius = this_radius;\n')
+        file.write('                    #local para_t = (1/2+j)/res;\n')
+        file.write(
+            '                    #local this_point = ctrl_pts_array[i][0]*pow(1-para_t,3) + ctrl_pts_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_pts_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_pts_array[i][3]*pow(para_t,3);\n'
+        )
+        file.write(
+            '                    #local this_radius = ctrl_rs_array[i][0]*pow(1-para_t,3) + ctrl_rs_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_rs_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_rs_array[i][3]*pow(para_t,3);\n'
+        )
+        file.write(
+            '                    #if(vlength(this_point-last_point) > abs(this_radius-last_radius))\n'
+        )
+        file.write('                        object{\n')
+        file.write(
+            '                        Connect_Spheres(last_point, last_radius, this_point, this_radius)\n'
+        )
+        file.write('                        }\n')
+        file.write('                    #end\n')
+        file.write('                    sphere{\n')
+        file.write('                    this_point, this_radius\n')
+        file.write('                    }\n')
+        file.write('                #end\n')
+        file.write('                #local last_point = this_point;\n')
+        file.write('                #local last_radius = this_radius;\n')
+        file.write('                #local this_point = ctrl_pts_array[i][3];\n')
+        file.write('                #local this_radius = ctrl_rs_array[i][3];\n')
+        file.write(
+            '                #if(vlength(this_point-last_point) > abs(this_radius-last_radius))\n'
+        )
+        file.write('                    object{\n')
+        file.write(
+            '                    Connect_Spheres(last_point, last_radius, this_point, this_radius)\n'
+        )
+        file.write('                    }\n')
+        file.write('                #end\n')
+        file.write('                sphere{\n')
+        file.write('                this_point, this_radius\n')
+        file.write('                }\n')
+        file.write('            #end\n')
+        file.write('        }\n')
+        file.write('        mockup1\n')
+        file.write('        #end\n')
+
+        for spl in ob.data.splines:
+            if spl.type == "BEZIER":
+                bezier_sweep = True
+    if ob.pov.curveshape in {'loft', 'birail'}:
+        n = 0
+        for spline in ob.data.splines:
+            n += 1
+            tab_write('#declare %s%s=spline {\n' % (dataname, n))
+            tab_write('cubic_spline\n')
+            lp = len(spline.points)
+            delta = 1 / (lp)
+            d = -delta
+            point = spline.points[lp - 1]
+            x, y, z, w = point.co[:]
+            tab_write('%.6f, <%.6f,%.6f,%.6f>\n' % (d, x, y, z))
+            d += delta
+            for point in spline.points:
+                x, y, z, w = point.co[:]
+                tab_write('%.6f, <%.6f,%.6f,%.6f>\n' % (d, x, y, z))
+                d += delta
+            for i in range(2):
+                point = spline.points[i]
+                x, y, z, w = point.co[:]
+                tab_write('%.6f, <%.6f,%.6f,%.6f>\n' % (d, x, y, z))
+                d += delta
+            tab_write('}\n')
+        if ob.pov.curveshape in {'loft'}:
+            n = len(ob.data.splines)
+            tab_write('#declare %s = array[%s]{\n' % (dataname, (n + 3)))
+            tab_write('spline{%s%s},\n' % (dataname, n))
+            for i in range(n):
+                tab_write('spline{%s%s},\n' % (dataname, (i + 1)))
+            tab_write('spline{%s1},\n' % (dataname))
+            tab_write('spline{%s2}\n' % (dataname))
+            tab_write('}\n')
+        # Use some of the Meshmaker.inc macro, here inlined
+        file.write('#macro CheckFileName(FileName)\n')
+        file.write('   #local Len=strlen(FileName);\n')
+        file.write('   #if(Len>0)\n')
+        file.write('      #if(file_exists(FileName))\n')
+        file.write('         #if(Len>=4)\n')
+        file.write('            #local Ext=strlwr(substr(FileName,Len-3,4))\n')
+        file.write(
+            '            #if (strcmp(Ext,".obj")=0 | strcmp(Ext,".pcm")=0 | strcmp(Ext,".arr")=0)\n'
+        )
+        file.write('               #local Return=99;\n')
+        file.write('            #else\n')
+        file.write('               #local Return=0;\n')
+        file.write('            #end\n')
+        file.write('         #else\n')
+        file.write('            #local Return=0;\n')
+        file.write('         #end\n')
+        file.write('      #else\n')
+        file.write('         #if(Len>=4)\n')
+        file.write('            #local Ext=strlwr(substr(FileName,Len-3,4))\n')
+        file.write(
+            '            #if (strcmp(Ext,".obj")=0 | strcmp(Ext,".pcm")=0 | strcmp(Ext,".arr")=0)\n'
+        )
+        file.write('               #if (strcmp(Ext,".obj")=0)\n')
+        file.write('                  #local Return=2;\n')
+        file.write('               #end\n')
+        file.write('               #if (strcmp(Ext,".pcm")=0)\n')
+        file.write('                  #local Return=3;\n')
+        file.write('               #end\n')
+        file.write('               #if (strcmp(Ext,".arr")=0)\n')
+        file.write('                  #local Return=4;\n')
+        file.write('               #end\n')
+        file.write('            #else\n')
+        file.write('               #local Return=1;\n')
+        file.write('            #end\n')
+        file.write('         #else\n')
+        file.write('            #local Return=1;\n')
+        file.write('         #end\n')
+        file.write('      #end\n')
+        file.write('   #else\n')
+        file.write('      #local Return=1;\n')
+        file.write('   #end\n')
+        file.write('   (Return)\n')
+        file.write('#end\n')
+
+        file.write('#macro BuildSpline(Arr, SplType)\n')
+        file.write('   #local Ds=dimension_size(Arr,1);\n')
+        file.write('   #local Asc=asc(strupr(SplType));\n')
+        file.write('   #if(Asc!=67 & Asc!=76 & Asc!=81) \n')
+        file.write('      #local Asc=76;\n')
+        file.write(
+            '      #debug "\nWrong spline type defined (C/c/L/l/N/n/Q/q), using default linear_spline\\n"\n'
+        )
+        file.write('   #end\n')
+        file.write('   spline {\n')
+        file.write('      #switch (Asc)\n')
+        file.write('         #case (67) //C  cubic_spline\n')
+        file.write('            cubic_spline\n')
+        file.write('         #break\n')
+        file.write('         #case (76) //L  linear_spline\n')
+        file.write('            linear_spline\n')
+        file.write('         #break\n')
+        file.write('         #case (78) //N  linear_spline\n')
+        file.write('            natural_spline\n')
+        file.write('         #break\n')
+        file.write('         #case (81) //Q  Quadratic_spline\n')
+        file.write('            quadratic_spline\n')
+        file.write('         #break\n')
+        file.write('      #end\n')
+        file.write('      #local Add=1/((Ds-2)-1);\n')
+        file.write('      #local J=0-Add;\n')
+        file.write('      #local I=0;\n')
+        file.write('      #while (I<Ds)\n')
+        file.write('         J\n')
+        file.write('         Arr[I]\n')
+        file.write('         #local I=I+1;\n')
+        file.write('         #local J=J+Add;\n')
+        file.write('      #end\n')
+        file.write('   }\n')
+        file.write('#end\n')
+
+        file.write('#macro BuildWriteMesh2(VecArr, NormArr, UVArr, U, V, FileName)\n')
+        # suppressed some file checking from original macro because no more separate files
+        file.write(' #local Write=0;\n')
+        file.write(' #debug concat("\\n\\n Building mesh2: \\n   - vertex_vectors\\n")\n')
+        file.write('  #local NumVertices=dimension_size(VecArr,1);\n')
+        file.write('  #switch (Write)\n')
+        file.write('     #case(1)\n')
+        file.write('        #write(\n')
+        file.write('           MeshFile,\n')
+        file.write('           "  vertex_vectors {\\n",\n')
+        file.write('           "    ", str(NumVertices,0,0),"\\n    "\n')
+        file.write('        )\n')
+        file.write('     #break\n')
+        file.write('     #case(2)\n')
+        file.write('        #write(\n')
+        file.write('           MeshFile,\n')
+        file.write('           "# Vertices: ",str(NumVertices,0,0),"\\n"\n')
+        file.write('        )\n')
+        file.write('     #break\n')
+        file.write('     #case(3)\n')
+        file.write('        #write(\n')
+        file.write('           MeshFile,\n')
+        file.write('           str(2*NumVertices,0,0),",\\n"\n')
+        file.write('        )\n')
+        file.write('     #break\n')
+        file.write('     #case(4)\n')
+        file.write('        #write(\n')
+        file.write('           MeshFile,\n')
+        file.write('           "#declare VertexVectors= array[",str(NumVertices,0,0),"] {\\n  "\n')
+        file.write('        )\n')
+        file.write('     #break\n')
+        file.write('  #end\n')
+        file.write('  mesh2 {\n')
+        file.write('     vertex_vectors {\n')
+        file.write('        NumVertices\n')
+        file.write('        #local I=0;\n')
+        file.write('        #while (I<NumVertices)\n')
+        file.write('           VecArr[I]\n')
+        file.write('           #switch(Write)\n')
+        file.write('              #case(1)\n')
+        file.write('                 #write(MeshFile, VecArr[I])\n')
+        file.write('              #break\n')
+        file.write('              #case(2)\n')
+        file.write('                 #write(\n')
+        file.write('                    MeshFile,\n')
+        file.write(
+            '                    "v ", VecArr[I].x," ", VecArr[I].y," ", VecArr[I].z,"\\n"\n'
+        )
+        file.write('                 )\n')
+        file.write('              #break\n')
+        file.write('              #case(3)\n')
+        file.write('                 #write(\n')
+        file.write('                    MeshFile,\n')
+        file.write('                    VecArr[I].x,",", VecArr[I].y,",", VecArr[I].z,",\\n"\n')
+        file.write('                 )\n')
+        file.write('              #break\n')
+        file.write('              #case(4)\n')
+        file.write('                 #write(MeshFile, VecArr[I])\n')
+        file.write('              #break\n')
+        file.write('           #end\n')
+        file.write('           #local I=I+1;\n')
+        file.write('           #if(Write=1 | Write=4)\n')
+        file.write('              #if(mod(I,3)=0)\n')
+        file.write('                 #write(MeshFile,"\\n    ")\n')
+        file.write('              #end\n')
+        file.write('           #end \n')
+        file.write('        #end\n')
+        file.write('        #switch(Write)\n')
+        file.write('           #case(1)\n')
+        file.write('              #write(MeshFile,"\\n  }\\n")\n')
+        file.write('           #break\n')
+        file.write('           #case(2)\n')
+        file.write('              #write(MeshFile,"\\n")\n')
+        file.write('           #break\n')
+        file.write('           #case(3)\n')
+        file.write('              // do nothing\n')
+        file.write('           #break\n')
+        file.write('           #case(4) \n')
+        file.write('              #write(MeshFile,"\\n}\\n")\n')
+        file.write('           #break\n')
+        file.write('        #end\n')
+        file.write('     }\n')
+
+        file.write('     #debug concat("   - normal_vectors\\n")    \n')
+        file.write('     #local NumVertices=dimension_size(NormArr,1);\n')
+        file.write('     #switch(Write)\n')
+        file.write('        #case(1)\n')
+        file.write('           #write(\n')
+        file.write('              MeshFile,\n')
+        file.write('              "  normal_vectors {\\n",\n')
+        file.write('              "    ", str(NumVertices,0,0),"\\n    "\n')
+        file.write('           )\n')
+        file.write('        #break\n')
+        file.write('        #case(2)\n')
+        file.write('           #write(\n')
+        file.write('              MeshFile,\n')
+        file.write('              "# Normals: ",str(NumVertices,0,0),"\\n"\n')
+        file.write('           )\n')
+        file.write('        #break\n')
+        file.write('        #case(3)\n')
+        file.write('           // do nothing\n')
+        file.write('        #break\n')
+        file.write('        #case(4)\n')
+        file.write('           #write(\n')
+        file.write('              MeshFile,\n')
+        file.write(
+            '              "#declare NormalVectors= array[",str(NumVertices,0,0),"] {\\n  "\n'
+        )
+        file.write('           )\n')
+        file.write('        #break\n')
+        file.write('     #end\n')
+        file.write('     normal_vectors {\n')
+        file.write('        NumVertices\n')
+        file.write('        #local I=0;\n')
+        file.write('        #while (I<NumVertices)\n')
+        file.write('           NormArr[I]\n')
+        file.write('           #switch(Write)\n')
+        file.write('              #case(1)\n')
+        file.write('                 #write(MeshFile NormArr[I])\n')
+        file.write('              #break\n')
+        file.write('              #case(2)\n')
+        file.write('                 #write(\n')
+        file.write('                    MeshFile,\n')
+        file.write(
+            '                    "vn ", NormArr[I].x," ", NormArr[I].y," ", NormArr[I].z,"\\n"\n'
+        )
+        file.write('                 )\n')
+        file.write('              #break\n')
+        file.write('              #case(3)\n')
+        file.write('                 #write(\n')
+        file.write('                    MeshFile,\n')
+        file.write('                    NormArr[I].x,",", NormArr[I].y,",", NormArr[I].z,",\\n"\n')
+        file.write('                 )\n')
+        file.write('              #break\n')
+        file.write('              #case(4)\n')
+        file.write('                 #write(MeshFile NormArr[I])\n')
+        file.write('              #break\n')
+        file.write('           #end\n')
+        file.write('           #local I=I+1;\n')
+        file.write('           #if(Write=1 | Write=4) \n')
+        file.write('              #if(mod(I,3)=0)\n')
+        file.write('                 #write(MeshFile,"\\n    ")\n')
+        file.write('              #end\n')
+        file.write('           #end\n')
+        file.write('        #end\n')
+        file.write('        #switch(Write)\n')
+        file.write('           #case(1)\n')
+        file.write('              #write(MeshFile,"\\n  }\\n")\n')
+        file.write('           #break\n')
+        file.write('           #case(2)\n')
+        file.write('              #write(MeshFile,"\\n")\n')
+        file.write('           #break\n')
+        file.write('           #case(3)\n')
+        file.write('              //do nothing\n')
+        file.write('           #break\n')
+        file.write('           #case(4)\n')
+        file.write('              #write(MeshFile,"\\n}\\n")\n')
+        file.write('           #break\n')
+        file.write('        #end\n')
+        file.write('     }\n')
+
+        file.write('     #debug concat("   - uv_vectors\\n")   \n')
+        file.write('     #local NumVertices=dimension_size(UVArr,1);\n')
+        file.write('     #switch(Write)\n')
+        file.write('        #case(1)\n')
+        file.write('           #write(\n')
+        file.write('              MeshFile, \n')
+        file.write('              "  uv_vectors {\\n",\n')
+        file.write('              "    ", str(NumVertices,0,0),"\\n    "\n')
+        file.write('           )\n')
+        file.write('         #break\n')
+        file.write('         #case(2)\n')
+        file.write('           #write(\n')
+        file.write('              MeshFile,\n')
+        file.write('              "# UV-vectors: ",str(NumVertices,0,0),"\\n"\n')
+        file.write('           )\n')
+        file.write('         #break\n')
+        file.write('         #case(3)\n')
+        file.write('           // do nothing, *.pcm does not support uv-vectors\n')
+        file.write('         #break\n')
+        file.write('         #case(4)\n')
+        file.write('            #write(\n')
+        file.write('               MeshFile,\n')
+        file.write('               "#declare UVVectors= array[",str(NumVertices,0,0),"] {\\n  "\n')
+        file.write('            )\n')
+        file.write('         #break\n')
+        file.write('     #end\n')
+        file.write('     uv_vectors {\n')
+        file.write('        NumVertices\n')
+        file.write('        #local I=0;\n')
+        file.write('        #while (I<NumVertices)\n')
+        file.write('           UVArr[I]\n')
+        file.write('           #switch(Write)\n')
+        file.write('              #case(1)\n')
+        file.write('                 #write(MeshFile UVArr[I])\n')
+        file.write('              #break\n')
+        file.write('              #case(2)\n')
+        file.write('                 #write(\n')
+        file.write('                    MeshFile,\n')
+        file.write('                    "vt ", UVArr[I].u," ", UVArr[I].v,"\\n"\n')
+        file.write('                 )\n')
+        file.write('              #break\n')
+        file.write('              #case(3)\n')
+        file.write('                 //do nothing\n')
+        file.write('              #break\n')
+        file.write('              #case(4)\n')
+        file.write('                 #write(MeshFile UVArr[I])\n')
+        file.write('              #break\n')
+        file.write('           #end\n')
+        file.write('           #local I=I+1; \n')
+        file.write('           #if(Write=1 | Write=4)\n')
+        file.write('              #if(mod(I,3)=0)\n')
+        file.write('                 #write(MeshFile,"\\n    ")\n')
+        file.write('              #end \n')
+        file.write('           #end\n')
+        file.write('        #end \n')
+        file.write('        #switch(Write)\n')
+        file.write('           #case(1)\n')
+        file.write('              #write(MeshFile,"\\n  }\\n")\n')
+        file.write('           #break\n')
+        file.write('           #case(2)\n')
+        file.write('              #write(MeshFile,"\\n")\n')
+        file.write('           #break\n')
+        file.write('           #case(3)\n')
+        file.write('              //do nothing\n')
+        file.write('           #break\n')
+        file.write('           #case(4)\n')
+        file.write('              #write(MeshFile,"\\n}\\n")\n')
+        file.write('           #break\n')
+        file.write('        #end\n')
+        file.write('     }\n')
+        file.write('\n')
+        file.write('     #debug concat("   - face_indices\\n")   \n')
+        file.write('     #declare NumFaces=U*V*2;\n')
+        file.write('     #switch(Write)\n')
+        file.write('        #case(1)\n')
+        file.write('           #write(\n')
+        file.write('              MeshFile,\n')
+        file.write('              "  face_indices {\\n"\n')
+        file.write('              "    ", str(NumFaces,0,0),"\\n    "\n')
+        file.write('           )\n')
+        file.write('        #break\n')
+        file.write('        #case(2)\n')
+        file.write('           #write (\n')
+        file.write('              MeshFile,\n')
+        file.write('              "# faces: ",str(NumFaces,0,0),"\\n"\n')
+        file.write('           )\n')
+        file.write('        #break\n')
+        file.write('        #case(3)\n')
+        file.write('           #write (\n')
+        file.write('              MeshFile,\n')
+        file.write('              "0,",str(NumFaces,0,0),",\\n"\n')
+        file.write('           )\n')
+        file.write('        #break\n')
+        file.write('        #case(4)\n')
+        file.write('           #write(\n')
+        file.write('              MeshFile,\n')
+        file.write('              "#declare FaceIndices= array[",str(NumFaces,0,0),"] {\\n  "\n')
+        file.write('           )\n')
+        file.write('        #break\n')
+        file.write('     #end\n')
+        file.write('     face_indices {\n')
+        file.write('        NumFaces\n')
+        file.write('        #local I=0;\n')
+        file.write('        #local H=0;\n')
+        file.write('        #local NumVertices=dimension_size(VecArr,1);\n')
+        file.write('        #while (I<V)\n')
+        file.write('           #local J=0;\n')
+        file.write('           #while (J<U)\n')
+        file.write('              #local Ind=(I*U)+I+J;\n')
+        file.write('              <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n')
+        file.write('              #switch(Write)\n')
+        file.write('                 #case(1)\n')
+        file.write('                    #write(\n')
+        file.write('                       MeshFile,\n')
+        file.write('                       <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n')
+        file.write('                    )\n')
+        file.write('                 #break\n')
+        file.write('                 #case(2)\n')
+        file.write('                    #write(\n')
+        file.write('                       MeshFile,\n')
+        file.write(
+            '                       "f ",Ind+1,"/",Ind+1,"/",Ind+1," ",Ind+1+1,"/",Ind+1+1,"/",Ind+1+1," ",Ind+U+2+1,"/",Ind+U+2+1,"/",Ind+U+2+1,"\\n",\n'
+        )
+        file.write(
+            '                       "f ",Ind+U+1+1,"/",Ind+U+1+1,"/",Ind+U+1+1," ",Ind+1,"/",Ind+1,"/",Ind+1," ",Ind+U+2+1,"/",Ind+U+2+1,"/",Ind+U+2+1,"\\n"\n'
+        )
+        file.write('                    )\n')
+        file.write('                 #break\n')
+        file.write('                 #case(3)\n')
+        file.write('                    #write(\n')
+        file.write('                       MeshFile,\n')
+        file.write(
+            '                       Ind,",",Ind+NumVertices,",",Ind+1,",",Ind+1+NumVertices,",",Ind+U+2,",",Ind+U+2+NumVertices,",\\n"\n'
+        )
+        file.write(
+            '                       Ind+U+1,",",Ind+U+1+NumVertices,",",Ind,",",Ind+NumVertices,",",Ind+U+2,",",Ind+U+2+NumVertices,",\\n"\n'
+        )
+        file.write('                    )\n')
+        file.write('                 #break\n')
+        file.write('                 #case(4)\n')
+        file.write('                    #write(\n')
+        file.write('                       MeshFile,\n')
+        file.write('                       <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n')
+        file.write('                    )\n')
+        file.write('                 #break\n')
+        file.write('              #end\n')
+        file.write('              #local J=J+1;\n')
+        file.write('              #local H=H+1;\n')
+        file.write('              #if(Write=1 | Write=4)\n')
+        file.write('                 #if(mod(H,3)=0)\n')
+        file.write('                    #write(MeshFile,"\\n    ")\n')
+        file.write('                 #end \n')
+        file.write('              #end\n')
+        file.write('           #end\n')
+        file.write('           #local I=I+1;\n')
+        file.write('        #end\n')
+        file.write('     }\n')
+        file.write('     #switch(Write)\n')
+        file.write('        #case(1)\n')
+        file.write('           #write(MeshFile, "\\n  }\\n}")\n')
+        file.write('           #fclose MeshFile\n')
+        file.write('           #debug concat(" Done writing\\n")\n')
+        file.write('        #break\n')
+        file.write('        #case(2)\n')
+        file.write('           #fclose MeshFile\n')
+        file.write('           #debug concat(" Done writing\\n")\n')
+        file.write('        #break\n')
+        file.write('        #case(3)\n')
+        file.write('           #fclose MeshFile\n')
+        file.write('           #debug concat(" Done writing\\n")\n')
+        file.write('        #break\n')
+        file.write('        #case(4)\n')
+        file.write('           #write(MeshFile, "\\n}\\n}")\n')
+        file.write('           #fclose MeshFile\n')
+        file.write('           #debug concat(" Done writing\\n")\n')
+        file.write('        #break\n')
+        file.write('     #end\n')
+        file.write('  }\n')
+        file.write('#end\n')
+
+        file.write('#macro MSM(SplineArray, SplRes, Interp_type,  InterpRes, FileName)\n')
+        file.write('    #declare Build=CheckFileName(FileName);\n')
+        file.write('    #if(Build=0)\n')
+        file.write('        #debug concat("\\n Parsing mesh2 from file: ", FileName, "\\n")\n')
+        file.write('        #include FileName\n')
+        file.write('        object{Surface}\n')
+        file.write('    #else\n')
+        file.write('        #local NumVertices=(SplRes+1)*(InterpRes+1);\n')
+        file.write('        #local NumFaces=SplRes*InterpRes*2;\n')
+        file.write(
+            '        #debug concat("\\n Calculating ",str(NumVertices,0,0)," vertices for ", str(NumFaces,0,0)," triangles\\n\\n")\n'
+        )
+        file.write('        #local VecArr=array[NumVertices]\n')
+        file.write('        #local NormArr=array[NumVertices]\n')
+        file.write('        #local UVArr=array[NumVertices]\n')
+        file.write('        #local N=dimension_size(SplineArray,1);\n')
+        file.write('        #local TempSplArr0=array[N];\n')
+        file.write('        #local TempSplArr1=array[N];\n')
+        file.write('        #local TempSplArr2=array[N];\n')
+        file.write('        #local PosStep=1/SplRes;\n')
+        file.write('        #local InterpStep=1/InterpRes;\n')
+        file.write('        #local Count=0;\n')
+        file.write('        #local Pos=0;\n')
+        file.write('        #while(Pos<=1)\n')
+        file.write('            #local I=0;\n')
+        file.write('            #if (Pos=0)\n')
+        file.write('                #while (I<N)\n')
+        file.write('                    #local Spl=spline{SplineArray[I]}\n')
+        file.write('                    #local TempSplArr0[I]=<0,0,0>+Spl(Pos);\n')
+        file.write('                    #local TempSplArr1[I]=<0,0,0>+Spl(Pos+PosStep);\n')
+        file.write('                    #local TempSplArr2[I]=<0,0,0>+Spl(Pos-PosStep);\n')
+        file.write('                    #local I=I+1;\n')
+        file.write('                #end\n')
+        file.write('                #local S0=BuildSpline(TempSplArr0, Interp_type)\n')
+        file.write('                #local S1=BuildSpline(TempSplArr1, Interp_type)\n')
+        file.write('                #local S2=BuildSpline(TempSplArr2, Interp_type)\n')
+        file.write('            #else\n')
+        file.write('                #while (I<N)\n')
+        file.write('                    #local Spl=spline{SplineArray[I]}\n')
+        file.write('                    #local TempSplArr1[I]=<0,0,0>+Spl(Pos+PosStep);\n')
+        file.write('                    #local I=I+1;\n')
+        file.write('                #end\n')
+        file.write('                #local S1=BuildSpline(TempSplArr1, Interp_type)\n')
+        file.write('            #end\n')
+        file.write('            #local J=0;\n')
+        file.write('            #while (J<=1)\n')
+        file.write('                #local P0=<0,0,0>+S0(J);\n')
+        file.write('                #local P1=<0,0,0>+S1(J);\n')
+        file.write('                #local P2=<0,0,0>+S2(J);\n')
+        file.write('                #local P3=<0,0,0>+S0(J+InterpStep);\n')
+        file.write('                #local P4=<0,0,0>+S0(J-InterpStep);\n')
+        file.write('                #local B1=P4-P0;\n')
+        file.write('                #local B2=P2-P0;\n')
+        file.write('                #local B3=P3-P0;\n')
+        file.write('                #local B4=P1-P0;\n')
+        file.write('                #local N1=vcross(B1,B2);\n')
+        file.write('                #local N2=vcross(B2,B3);\n')
+        file.write('                #local N3=vcross(B3,B4);\n')
+        file.write('                #local N4=vcross(B4,B1);\n')
+        file.write('                #local Norm=vnormalize((N1+N2+N3+N4));\n')
+        file.write('                #local VecArr[Count]=P0;\n')
+        file.write('                #local NormArr[Count]=Norm;\n')
+        file.write('                #local UVArr[Count]=<J,Pos>;\n')
+        file.write('                #local J=J+InterpStep;\n')
+        file.write('                #local Count=Count+1;\n')
+        file.write('            #end\n')
+        file.write('            #local S2=spline{S0}\n')
+        file.write('            #local S0=spline{S1}\n')
+        file.write(
+            '            #debug concat("\\r Done ", str(Count,0,0)," vertices : ", str(100*Count/NumVertices,0,2)," %")\n'
+        )
+        file.write('            #local Pos=Pos+PosStep;\n')
+        file.write('        #end\n')
+        file.write('        BuildWriteMesh2(VecArr, NormArr, UVArr, InterpRes, SplRes, "")\n')
+        file.write('    #end\n')
+        file.write('#end\n\n')
+
+        file.write('#macro Coons(Spl1, Spl2, Spl3, Spl4, Iter_U, Iter_V, FileName)\n')
+        file.write('   #declare Build=CheckFileName(FileName);\n')
+        file.write('   #if(Build=0)\n')
+        file.write('      #debug concat("\\n Parsing mesh2 from file: ", FileName, "\\n")\n')
+        file.write('      #include FileName\n')
+        file.write('      object{Surface}\n')
+        file.write('   #else\n')
+        file.write('      #local NumVertices=(Iter_U+1)*(Iter_V+1);\n')
+        file.write('      #local NumFaces=Iter_U*Iter_V*2;\n')
+        file.write(
+            '      #debug concat("\\n Calculating ", str(NumVertices,0,0), " vertices for ",str(NumFaces,0,0), " triangles\\n\\n")\n'
+        )
+        file.write('      #declare VecArr=array[NumVertices]   \n')
+        file.write('      #declare NormArr=array[NumVertices]   \n')
+        file.write('      #local UVArr=array[NumVertices]      \n')
+        file.write('      #local Spl1_0=Spl1(0);\n')
+        file.write('      #local Spl2_0=Spl2(0);\n')
+        file.write('      #local Spl3_0=Spl3(0);\n')
+        file.write('      #local Spl4_0=Spl4(0);\n')
+        file.write('      #local UStep=1/Iter_U;\n')
+        file.write('      #local VStep=1/Iter_V;\n')
+        file.write('      #local Count=0;\n')
+        file.write('      #local I=0;\n')
+        file.write('      #while (I<=1)\n')
+        file.write('         #local Im=1-I;\n')
+        file.write('         #local J=0;\n')
+        file.write('         #while (J<=1)\n')
+        file.write('            #local Jm=1-J;\n')
+        file.write(
+            '            #local C0=Im*Jm*(Spl1_0)+Im*J*(Spl2_0)+I*J*(Spl3_0)+I*Jm*(Spl4_0);\n'
+        )
+        file.write('            #local P0=LInterpolate(I, Spl1(J), Spl3(Jm)) + \n')
+        file.write('               LInterpolate(Jm, Spl2(I), Spl4(Im))-C0;\n')
+        file.write('            #declare VecArr[Count]=P0;\n')
+        file.write('            #local UVArr[Count]=<J,I>;\n')
+        file.write('            #local J=J+UStep;\n')
+        file.write('            #local Count=Count+1;\n')
+        file.write('         #end\n')
+        file.write('         #debug concat(\n')
+        file.write('            "\r Done ", str(Count,0,0)," vertices :         ",\n')
+        file.write('            str(100*Count/NumVertices,0,2)," %"\n')
+        file.write('         )\n')
+        file.write('         #local I=I+VStep;\n')
+        file.write('      #end\n')
+        file.write('      #debug "\r Normals                                  "\n')
+        file.write('      #local Count=0;\n')
+        file.write('      #local I=0;\n')
+        file.write('      #while (I<=Iter_V)\n')
+        file.write('         #local J=0;\n')
+        file.write('         #while (J<=Iter_U)\n')
+        file.write('            #local Ind=(I*Iter_U)+I+J;\n')
+        file.write('            #local P0=VecArr[Ind];\n')
+        file.write('            #if(J=0)\n')
+        file.write('               #local P1=P0+(P0-VecArr[Ind+1]);\n')
+        file.write('            #else\n')
+        file.write('               #local P1=VecArr[Ind-1];\n')
+        file.write('            #end\n')
+        file.write('            #if (J=Iter_U)\n')
+        file.write('               #local P2=P0+(P0-VecArr[Ind-1]);\n')
+        file.write('            #else\n')
+        file.write('               #local P2=VecArr[Ind+1];\n')
+        file.write('            #end\n')
+        file.write('            #if (I=0)\n')
+        file.write('               #local P3=P0+(P0-VecArr[Ind+Iter_U+1]);\n')
+        file.write('            #else\n')
+        file.write('               #local P3=VecArr[Ind-Iter_U-1];\n')
+        file.write('            #end\n')
+        file.write('            #if (I=Iter_V)\n')
+        file.write('               #local P4=P0+(P0-VecArr[Ind-Iter_U-1]);\n')
+        file.write('            #else\n')
+        file.write('               #local P4=VecArr[Ind+Iter_U+1];\n')
+        file.write('            #end\n')
+        file.write('            #local B1=P4-P0;\n')
+        file.write('            #local B2=P2-P0;\n')
+        file.write('            #local B3=P3-P0;\n')
+        file.write('            #local B4=P1-P0;\n')
+        file.write('            #local N1=vcross(B1,B2);\n')
+        file.write('            #local N2=vcross(B2,B3);\n')
+        file.write('            #local N3=vcross(B3,B4);\n')
+        file.write('            #local N4=vcross(B4,B1);\n')
+        file.write('            #local Norm=vnormalize((N1+N2+N3+N4));\n')
+        file.write('            #declare NormArr[Count]=Norm;\n')
+        file.write('            #local J=J+1;\n')
+        file.write('            #local Count=Count+1;\n')
+        file.write('         #end\n')
+        file.write(
+            '         #debug concat("\r Done ", str(Count,0,0)," normals : ",str(100*Count/NumVertices,0,2), " %")\n'
+        )
+        file.write('         #local I=I+1;\n')
+        file.write('      #end\n')
+        file.write('      BuildWriteMesh2(VecArr, NormArr, UVArr, Iter_U, Iter_V, FileName)\n')
+        file.write('   #end\n')
+        file.write('#end\n\n')
+    # Empty curves
+    if len(ob.data.splines) == 0:
+        tab_write("\n//dummy sphere to represent empty curve location\n")
+        tab_write("#declare %s =\n" % dataname)
+        tab_write(
+            "sphere {<%.6g, %.6g, %.6g>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n\n"
+            % (ob.location.x, ob.location.y, ob.location.z)
+        )  # ob.name > povdataname)
+    # And non empty curves
+    else:
+        if not bezier_sweep:
+            tab_write("#declare %s =\n" % dataname)
+        if ob.pov.curveshape == 'sphere_sweep' and not bezier_sweep:
+            tab_write("union {\n")
+            for spl in ob.data.splines:
+                if spl.type != "BEZIER":
+                    spl_type = "linear"
+                    if spl.type == "NURBS":
+                        spl_type = "cubic"
+                    points = spl.points
+                    num_points = len(points)
+                    if spl.use_cyclic_u:
+                        num_points += 3
+
+                    tab_write("sphere_sweep { %s_spline %s,\n" % (spl_type, num_points))
+                    if spl.use_cyclic_u:
+                        pt1 = points[len(points) - 1]
+                        wpt1 = pt1.co
+                        tab_write(
+                            "<%.4g,%.4g,%.4g>,%.4g\n"
+                            % (wpt1[0], wpt1[1], wpt1[2], pt1.radius * ob.data.bevel_depth)
+                        )
+                    for pt in points:
+                        wpt = pt.co
+                        tab_write(
+                            "<%.4g,%.4g,%.4g>,%.4g\n"
+                            % (wpt[0], wpt[1], wpt[2], pt.radius * ob.data.bevel_depth)
+                        )
+                    if spl.use_cyclic_u:
+                        for i in range(0, 2):
+                            end_pt = points[i]
+                            wpt = end_pt.co
+                            tab_write(
+                                "<%.4g,%.4g,%.4g>,%.4g\n"
+                                % (wpt[0], wpt[1], wpt[2], end_pt.radius * ob.data.bevel_depth)
+                            )
+
+                tab_write("}\n")
+        # below not used yet?
+        if ob.pov.curveshape == 'sor':
+            for spl in ob.data.splines:
+                if spl.type in {'POLY', 'NURBS'}:
+                    points = spl.points
+                    num_points = len(points)
+                    tab_write("sor { %s,\n" % num_points)
+                    for pt in points:
+                        wpt = pt.co
+                        tab_write("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
+                else:
+                    tab_write("box { 0,0\n")
+        if ob.pov.curveshape in {'lathe', 'prism'}:
+            spl = ob.data.splines[0]
+            if spl.type == "BEZIER":
+                points = spl.bezier_points
+                len_cur = len(points) - 1
+                len_pts = len_cur * 4
+                ifprism = ''
+                if ob.pov.curveshape in {'prism'}:
+                    height = ob.data.extrude
+                    ifprism = '-%s, %s,' % (height, height)
+                    len_cur += 1
+                    len_pts += 4
+                tab_write("%s { bezier_spline %s %s,\n" % (ob.pov.curveshape, ifprism, len_pts))
+                for i in range(0, len_cur):
+                    p1 = points[i].co
+                    pR = points[i].handle_right
+                    end = i + 1
+                    if i == len_cur - 1 and ob.pov.curveshape in {'prism'}:
+                        end = 0
+                    pL = points[end].handle_left
+                    p2 = points[end].co
+                    line = "<%.4g,%.4g>" % (p1[0], p1[1])
+                    line += "<%.4g,%.4g>" % (pR[0], pR[1])
+                    line += "<%.4g,%.4g>" % (pL[0], pL[1])
+                    line += "<%.4g,%.4g>" % (p2[0], p2[1])
+                    tab_write("%s\n" % line)
+            else:
+                points = spl.points
+                len_cur = len(points)
+                len_pts = len_cur
+                ifprism = ''
+                if ob.pov.curveshape in {'prism'}:
+                    height = ob.data.extrude
+                    ifprism = '-%s, %s,' % (height, height)
+                    len_pts += 3
+                spl_type = 'quadratic'
+                if spl.type == 'POLY':
+                    spl_type = 'linear'
+                tab_write(
+                    "%s { %s_spline %s %s,\n" % (ob.pov.curveshape, spl_type, ifprism, len_pts)
+                )
+                if ob.pov.curveshape in {'prism'}:
+                    pt = points[len(points) - 1]
+                    wpt = pt.co
+                    tab_write("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
+                for pt in points:
+                    wpt = pt.co
+                    tab_write("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
+                if ob.pov.curveshape in {'prism'}:
+                    for i in range(2):
+                        pt = points[i]
+                        wpt = pt.co
+                        tab_write("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
+        if bezier_sweep:
+            for p in range(len(ob.data.splines)):
+                br = []
+                depth = ob.data.bevel_depth
+                spl = ob.data.splines[p]
+                points = spl.bezier_points
+                len_cur = len(points) - 1
+                num_points = len_cur * 4
+                if spl.use_cyclic_u:
+                    len_cur += 1
+                    num_points += 4
+                tab_write("#declare %s_points_%s = array[%s]{\n" % (dataname, p, num_points))
+                for i in range(len_cur):
+                    p1 = points[i].co
+                    pR = points[i].handle_right
+                    end = i + 1
+                    if spl.use_cyclic_u and i == (len_cur - 1):
+                        end = 0
+                    pL = points[end].handle_left
+                    p2 = points[end].co
+                    r3 = points[end].radius * depth
+                    r0 = points[i].radius * depth
+                    r1 = 2 / 3 * r0 + 1 / 3 * r3
+                    r2 = 1 / 3 * r0 + 2 / 3 * r3
+                    br.append((r0, r1, r2, r3))
+                    line = "<%.4g,%.4g,%.4f>" % (p1[0], p1[1], p1[2])
+                    line += "<%.4g,%.4g,%.4f>" % (pR[0], pR[1], pR[2])
+                    line += "<%.4g,%.4g,%.4f>" % (pL[0], pL[1], pL[2])
+                    line += "<%.4g,%.4g,%.4f>" % (p2[0], p2[1], p2[2])
+                    tab_write("%s\n" % line)
+                tab_write("}\n")
+                tab_write("#declare %s_radii_%s = array[%s]{\n" % (dataname, p, len(br) * 4))
+                for rad_tuple in br:
+                    tab_write(
+                        '%.4f,%.4f,%.4f,%.4f\n'
+                        % (rad_tuple[0], rad_tuple[1], rad_tuple[2], rad_tuple[3])
+                    )
+                tab_write("}\n")
+            if len(ob.data.splines) == 1:
+                tab_write('#declare %s = object{\n' % dataname)
+                tab_write(
+                    '    Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_points_%s, %s_radii_%s) \n'
+                    % (ob.data.resolution_u, dataname, p, dataname, p)
+                )
+            else:
+                tab_write('#declare %s = union{\n' % dataname)
+                for p in range(len(ob.data.splines)):
+                    tab_write(
+                        '    object{Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_points_%s, %s_radii_%s)} \n'
+                        % (ob.data.resolution_u, dataname, p, dataname, p)
+                    )
+                # tab_write('#include "bezier_spheresweep.inc"\n') #now inlined
+            # tab_write('#declare %s = object{Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_bezier_points, %.4f) \n'%(dataname,ob.data.resolution_u,dataname,ob.data.bevel_depth))
+        if ob.pov.curveshape in {'loft'}:
+            tab_write('object {MSM(%s,%s,"c",%s,"")\n' % (dataname, ob.pov.res_u, ob.pov.res_v))
+        if ob.pov.curveshape in {'birail'}:
+            splines = '%s1,%s2,%s3,%s4' % (dataname, dataname, dataname, dataname)
+            tab_write('object {Coons(%s, %s, %s, "")\n' % (splines, ob.pov.res_u, ob.pov.res_v))
+        pov_mat_name = "Default_texture"
+        if ob.active_material:
+            # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+            try:
+                material = ob.active_material
+                write_object_material(material, ob, tab_write)
+            except IndexError:
+                print(ob.data)
+        # tab_write("texture {%s}\n"%pov_mat_name)
+        if ob.pov.curveshape in {'prism'}:
+            tab_write("rotate <90,0,0>\n")
+            tab_write("scale y*-1\n")
+        tab_write("}\n")
diff --git a/render_povray/object_gui.py b/render_povray/object_gui.py
new file mode 100755
index 000000000..bc7df9f44
--- /dev/null
+++ b/render_povray/object_gui.py
@@ -0,0 +1,731 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+"""User interface for the POV tools"""
+
+import bpy
+
+from bpy.utils import register_class, unregister_class
+from bpy.types import (
+    # Operator,
+    Menu,
+    Panel,
+)
+
+
+# Example of wrapping every class 'as is'
+from bl_ui import properties_data_modifier
+
+for member in dir(properties_data_modifier):
+    subclass = getattr(properties_data_modifier, member)
+    try:
+        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+    except BaseException as e:
+        print(e.__doc__)
+        print('An exception occurred: {}'.format(e))
+del properties_data_modifier
+
+
+from bl_ui import properties_data_mesh
+
+# These panels are kept
+properties_data_mesh.DATA_PT_custom_props_mesh.COMPAT_ENGINES.add('POVRAY_RENDER')
+properties_data_mesh.DATA_PT_context_mesh.COMPAT_ENGINES.add('POVRAY_RENDER')
+
+## make some native panels contextual to some object variable
+## by recreating custom panels inheriting their properties
+
+
+from .scripting_gui import VIEW_MT_POV_import
+
+
+class ModifierButtonsPanel:
+    """Use this class to define buttons from the modifier tab of
+    properties window."""
+
+    bl_space_type = 'PROPERTIES'
+    bl_region_type = 'WINDOW'
+    bl_context = "modifier"
+    # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
+
+    @classmethod
+    def poll(cls, context):
+        mods = context.object.modifiers
+        rd = context.scene.render
+        return mods and (rd.engine in cls.COMPAT_ENGINES)
+
+
+class ObjectButtonsPanel:
+    """Use this class to define buttons from the object tab of
+    properties window."""
+
+    bl_space_type = 'PROPERTIES'
+    bl_region_type = 'WINDOW'
+    bl_context = "object"
+    # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
+
+    @classmethod
+    def poll(cls, context):
+        obj = context.object
+        rd = context.scene.render
+        return obj and (rd.engine in cls.COMPAT_ENGINES)
+
+
+class PovDataButtonsPanel(properties_data_mesh.MeshButtonsPanel):
+    """Use this class to define buttons from the edit data tab of
+    properties window."""
+
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+    POV_OBJECT_TYPES = {
+        'PLANE',
+        'BOX',
+        'SPHERE',
+        'CYLINDER',
+        'CONE',
+        'TORUS',
+        'BLOB',
+        'ISOSURFACE',
+        'SUPERELLIPSOID',
+        'SUPERTORUS',
+        'HEIGHT_FIELD',
+        'PARAMETRIC',
+        'POLYCIRCLE',
+    }
+
+    @classmethod
+    def poll(cls, context):
+        engine = context.scene.render.engine
+        obj = context.object
+        # We use our parent class poll func too, avoids to re-define too much things...
+        return (
+            super(PovDataButtonsPanel, cls).poll(context)
+            and obj
+            and obj.pov.object_as not in cls.POV_OBJECT_TYPES
+        )
+
+
+# We cannot inherit from RNA classes (like e.g. properties_data_mesh.DATA_PT_vertex_groups).
+# Complex py/bpy/rna interactions (with metaclass and all) simply do not allow it to work.
+# So we simply have to explicitly copy here the interesting bits. ;)
+class DATA_PT_POV_normals(PovDataButtonsPanel, Panel):
+    bl_label = properties_data_mesh.DATA_PT_normals.bl_label
+
+    draw = properties_data_mesh.DATA_PT_normals.draw
+
+
+class DATA_PT_POV_texture_space(PovDataButtonsPanel, Panel):
+    bl_label = properties_data_mesh.DATA_PT_texture_space.bl_label
+    bl_options = properties_data_mesh.DATA_PT_texture_space.bl_options
+
+    draw = properties_data_mesh.DATA_PT_texture_space.draw
+
+
+class DATA_PT_POV_vertex_groups(PovDataButtonsPanel, Panel):
+    bl_label = properties_data_mesh.DATA_PT_vertex_groups.bl_label
+
+    draw = properties_data_mesh.DATA_PT_vertex_groups.draw
+
+
+class DATA_PT_POV_shape_keys(PovDataButtonsPanel, Panel):
+    bl_label = properties_data_mesh.DATA_PT_shape_keys.bl_label
+
+    draw = properties_data_mesh.DATA_PT_shape_keys.draw
+
+
+class DATA_PT_POV_uv_texture(PovDataButtonsPanel, Panel):
+    bl_label = properties_data_mesh.DATA_PT_uv_texture.bl_label
+
+    draw = properties_data_mesh.DATA_PT_uv_texture.draw
+
+
+class DATA_PT_POV_vertex_colors(PovDataButtonsPanel, Panel):
+    bl_label = properties_data_mesh.DATA_PT_vertex_colors.bl_label
+
+    draw = properties_data_mesh.DATA_PT_vertex_colors.draw
+
+
+class DATA_PT_POV_customdata(PovDataButtonsPanel, Panel):
+    bl_label = properties_data_mesh.DATA_PT_customdata.bl_label
+    bl_options = properties_data_mesh.DATA_PT_customdata.bl_options
+    draw = properties_data_mesh.DATA_PT_customdata.draw
+
+
+del properties_data_mesh
+
+
+class MODIFIERS_PT_POV_modifiers(ModifierButtonsPanel, Panel):
+    """Use this class to define pov modifier buttons. (For booleans)"""
+
+    bl_label = "POV-Ray"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    # def draw_header(self, context):
+    # scene = context.scene
+    # self.layout.prop(scene.pov, "boolean_mod", text="")
+
+    def draw(self, context):
+        # scene = context.scene
+        layout = self.layout
+        ob = context.object
+        mod = ob.modifiers
+        col = layout.column()
+        # Find Boolean Modifiers for displaying CSG option
+        onceCSG = 0
+        for mod in ob.modifiers:
+            if onceCSG == 0:
+                if mod:
+                    if mod.type == 'BOOLEAN':
+                        col.prop(ob.pov, "boolean_mod")
+                        onceCSG = 1
+
+                    if ob.pov.boolean_mod == "POV":
+                        split = layout.split()
+                        col = layout.column()
+                        # Inside Vector for CSG
+                        col.prop(ob.pov, "inside_vector")
+
+
+class OBJECT_PT_POV_obj_parameters(ObjectButtonsPanel, Panel):
+    """Use this class to define pov specific object level options buttons."""
+
+    bl_label = "POV"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+
+        engine = context.scene.render.engine
+        return engine in cls.COMPAT_ENGINES
+
+    def draw(self, context):
+        layout = self.layout
+
+        obj = context.object
+
+        split = layout.split()
+
+        col = split.column(align=True)
+
+        col.label(text="Radiosity:")
+        col.prop(obj.pov, "importance_value", text="Importance")
+        col.label(text="Photons:")
+        col.prop(obj.pov, "collect_photons", text="Receive Photon Caustics")
+        if obj.pov.collect_photons:
+            col.prop(obj.pov, "spacing_multiplier", text="Photons Spacing Multiplier")
+
+        split = layout.split()
+
+        col = split.column()
+        col.prop(obj.pov, "hollow")
+        col.prop(obj.pov, "double_illuminate")
+
+        if obj.type == 'META' or obj.pov.curveshape == 'lathe':
+            # if obj.pov.curveshape == 'sor'
+            col.prop(obj.pov, "sturm")
+        col.prop(obj.pov, "no_shadow")
+        col.prop(obj.pov, "no_image")
+        col.prop(obj.pov, "no_reflection")
+        col.prop(obj.pov, "no_radiosity")
+        col.prop(obj.pov, "inverse")
+        col.prop(obj.pov, "hierarchy")
+        # col.prop(obj.pov,"boundorclip",text="Bound / Clip")
+        # if obj.pov.boundorclip != "none":
+        # col.prop_search(obj.pov,"boundorclipob",context.blend_data,"objects",text="Object")
+        # text = "Clipped by"
+        # if obj.pov.boundorclip == "clipped_by":
+        # text = "Bounded by"
+        # col.prop(obj.pov,"addboundorclip",text=text)
+
+
+class OBJECT_PT_POV_obj_sphere(PovDataButtonsPanel, Panel):
+    """Use this class to define pov sphere primitive parameters buttons."""
+
+    bl_label = "POV Sphere"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+    # bl_options = {'HIDE_HEADER'}
+    @classmethod
+    def poll(cls, context):
+        engine = context.scene.render.engine
+        obj = context.object
+        return obj and obj.pov.object_as == 'SPHERE' and (engine in cls.COMPAT_ENGINES)
+
+    def draw(self, context):
+        layout = self.layout
+
+        obj = context.object
+
+        col = layout.column()
+
+        if obj.pov.object_as == 'SPHERE':
+            if not obj.pov.unlock_parameters:
+                col.prop(
+                    obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
+                )
+                col.label(text="Sphere radius: " + str(obj.pov.sphere_radius))
+
+            else:
+                col.prop(
+                    obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
+                )
+                col.label(text="3D view proxy may get out of synch")
+                col.active = obj.pov.unlock_parameters
+
+                layout.operator("pov.sphere_update", text="Update", icon="SHADING_RENDERED")
+
+                # col.label(text="Parameters:")
+                col.prop(obj.pov, "sphere_radius", text="Radius of Sphere")
+
+
+class OBJECT_PT_POV_obj_cylinder(PovDataButtonsPanel, Panel):
+    """Use this class to define pov cylinder primitive parameters buttons."""
+
+    bl_label = "POV Cylinder"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+    # bl_options = {'HIDE_HEADER'}
+    @classmethod
+    def poll(cls, context):
+        engine = context.scene.render.engine
+        obj = context.object
+        return obj and obj.pov.object_as == 'CYLINDER' and (engine in cls.COMPAT_ENGINES)
+
+    def draw(self, context):
+        layout = self.layout
+
+        obj = context.object
+
+        col = layout.column()
+
+        if obj.pov.object_as == 'CYLINDER':
+            if not obj.pov.unlock_parameters:
+                col.prop(
+                    obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
+                )
+                col.label(text="Cylinder radius: " + str(obj.pov.cylinder_radius))
+                col.label(text="Cylinder cap location: " + str(obj.pov.cylinder_location_cap))
+
+            else:
+                col.prop(
+                    obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
+                )
+                col.label(text="3D view proxy may get out of synch")
+                col.active = obj.pov.unlock_parameters
+
+                layout.operator("pov.cylinder_update", text="Update", icon="MESH_CYLINDER")
+
+                # col.label(text="Parameters:")
+                col.prop(obj.pov, "cylinder_radius")
+                col.prop(obj.pov, "cylinder_location_cap")
+
+
+class OBJECT_PT_POV_obj_cone(PovDataButtonsPanel, Panel):
+    """Use this class to define pov cone primitive parameters buttons."""
+
+    bl_label = "POV Cone"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+    # bl_options = {'HIDE_HEADER'}
+    @classmethod
+    def poll(cls, context):
+        engine = context.scene.render.engine
+        obj = context.object
+        return obj and obj.pov.object_as == 'CONE' and (engine in cls.COMPAT_ENGINES)
+
+    def draw(self, context):
+        layout = self.layout
+
+        obj = context.object
+
+        col = layout.column()
+
+        if obj.pov.object_as == 'CONE':
+            if not obj.pov.unlock_parameters:
+                col.prop(
+                    obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
+                )
+                col.label(text="Cone base radius: " + str(obj.pov.cone_base_radius))
+                col.label(text="Cone cap radius: " + str(obj.pov.cone_cap_radius))
+                col.label(text="Cone proxy segments: " + str(obj.pov.cone_segments))
+                col.label(text="Cone height: " + str(obj.pov.cone_height))
+            else:
+                col.prop(
+                    obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
+                )
+                col.label(text="3D view proxy may get out of synch")
+                col.active = obj.pov.unlock_parameters
+
+                layout.operator("pov.cone_update", text="Update", icon="MESH_CONE")
+
+                # col.label(text="Parameters:")
+                col.prop(obj.pov, "cone_base_radius", text="Radius of Cone Base")
+                col.prop(obj.pov, "cone_cap_radius", text="Radius of Cone Cap")
+                col.prop(obj.pov, "cone_segments", text="Segmentation of Cone proxy")
+                col.prop(obj.pov, "cone_height", text="Height of the cone")
+
+
+class OBJECT_PT_POV_obj_superellipsoid(PovDataButtonsPanel, Panel):
+    """Use this class to define pov superellipsoid primitive parameters buttons."""
+
+    bl_label = "POV Superquadric ellipsoid"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+    # bl_options = {'HIDE_HEADER'}
+    @classmethod
+    def poll(cls, context):
+        engine = context.scene.render.engine
+        obj = context.object
+        return obj and obj.pov.object_as == 'SUPERELLIPSOID' and (engine in cls.COMPAT_ENGINES)
+
+    def draw(self, context):
+        layout = self.layout
+
+        obj = context.object
+
+        col = layout.column()
+
+        if obj.pov.object_as == 'SUPERELLIPSOID':
+            if not obj.pov.unlock_parameters:
+                col.prop(
+                    obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
+                )
+                col.label(text="Radial segmentation: " + str(obj.pov.se_u))
+                col.label(text="Lateral segmentation: " + str(obj.pov.se_v))
+                col.label(text="Ring shape: " + str(obj.pov.se_n1))
+                col.label(text="Cross-section shape: " + str(obj.pov.se_n2))
+                col.label(text="Fill up and down: " + str(obj.pov.se_edit))
+            else:
+                col.prop(
+                    obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
+                )
+                col.label(text="3D view proxy may get out of synch")
+                col.active = obj.pov.unlock_parameters
+
+                layout.operator("pov.superellipsoid_update", text="Update", icon="MOD_SUBSURF")
+
+                # col.label(text="Parameters:")
+                col.prop(obj.pov, "se_u")
+                col.prop(obj.pov, "se_v")
+                col.prop(obj.pov, "se_n1")
+                col.prop(obj.pov, "se_n2")
+                col.prop(obj.pov, "se_edit")
+
+
+class OBJECT_PT_POV_obj_torus(PovDataButtonsPanel, Panel):
+    """Use this class to define pov torus primitive parameters buttons."""
+
+    bl_label = "POV Torus"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+    # bl_options = {'HIDE_HEADER'}
+    @classmethod
+    def poll(cls, context):
+        engine = context.scene.render.engine
+        obj = context.object
+        return obj and obj.pov.object_as == 'TORUS' and (engine in cls.COMPAT_ENGINES)
+
+    def draw(self, context):
+        layout = self.layout
+
+        obj = context.object
+
+        col = layout.column()
+
+        if obj.pov.object_as == 'TORUS':
+            if not obj.pov.unlock_parameters:
+                col.prop(
+                    obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
+                )
+                col.label(text="Torus major radius: " + str(obj.pov.torus_major_radius))
+                col.label(text="Torus minor radius: " + str(obj.pov.torus_minor_radius))
+                col.label(text="Torus major segments: " + str(obj.pov.torus_major_segments))
+                col.label(text="Torus minor segments: " + str(obj.pov.torus_minor_segments))
+            else:
+                col.prop(
+                    obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
+                )
+                col.label(text="3D view proxy may get out of synch")
+                col.active = obj.pov.unlock_parameters
+
+                layout.operator("pov.torus_update", text="Update", icon="MESH_TORUS")
+
+                # col.label(text="Parameters:")
+                col.prop(obj.pov, "torus_major_radius")
+                col.prop(obj.pov, "torus_minor_radius")
+                col.prop(obj.pov, "torus_major_segments")
+                col.prop(obj.pov, "torus_minor_segments")
+
+
+class OBJECT_PT_POV_obj_supertorus(PovDataButtonsPanel, Panel):
+    """Use this class to define pov supertorus primitive parameters buttons."""
+
+    bl_label = "POV SuperTorus"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+    # bl_options = {'HIDE_HEADER'}
+    @classmethod
+    def poll(cls, context):
+        engine = context.scene.render.engine
+        obj = context.object
+        return obj and obj.pov.object_as == 'SUPERTORUS' and (engine in cls.COMPAT_ENGINES)
+
+    def draw(self, context):
+        layout = self.layout
+
+        obj = context.object
+
+        col = layout.column()
+
+        if obj.pov.object_as == 'SUPERTORUS':
+            if not obj.pov.unlock_parameters:
+                col.prop(
+                    obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
+                )
+                col.label(text="SuperTorus major radius: " + str(obj.pov.st_major_radius))
+                col.label(text="SuperTorus minor radius: " + str(obj.pov.st_minor_radius))
+                col.label(text="SuperTorus major segments: " + str(obj.pov.st_u))
+                col.label(text="SuperTorus minor segments: " + str(obj.pov.st_v))
+
+                col.label(text="SuperTorus Ring Manipulator: " + str(obj.pov.st_ring))
+                col.label(text="SuperTorus Cross Manipulator: " + str(obj.pov.st_cross))
+                col.label(text="SuperTorus Internal And External radii: " + str(obj.pov.st_ie))
+
+                col.label(text="SuperTorus accuracy: " + str(obj.pov.st_accuracy))
+                col.label(text="SuperTorus max gradient: " + str(obj.pov.st_max_gradient))
+
+            else:
+                col.prop(
+                    obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
+                )
+                col.label(text="3D view proxy may get out of synch")
+                col.active = obj.pov.unlock_parameters
+
+                layout.operator("pov.supertorus_update", text="Update", icon="MESH_TORUS")
+
+                # col.label(text="Parameters:")
+                col.prop(obj.pov, "st_major_radius")
+                col.prop(obj.pov, "st_minor_radius")
+                col.prop(obj.pov, "st_u")
+                col.prop(obj.pov, "st_v")
+                col.prop(obj.pov, "st_ring")
+                col.prop(obj.pov, "st_cross")
+                col.prop(obj.pov, "st_ie")
+                # col.prop(obj.pov, "st_edit") #?
+                col.prop(obj.pov, "st_accuracy")
+                col.prop(obj.pov, "st_max_gradient")
+
+
+class OBJECT_PT_POV_obj_parametric(PovDataButtonsPanel, Panel):
+    """Use this class to define pov parametric surface primitive parameters buttons."""
+
+    bl_label = "POV Parametric surface"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+    # bl_options = {'HIDE_HEADER'}
+    @classmethod
+    def poll(cls, context):
+        engine = context.scene.render.engine
+        obj = context.object
+        return obj and obj.pov.object_as == 'PARAMETRIC' and (engine in cls.COMPAT_ENGINES)
+
+    def draw(self, context):
+        layout = self.layout
+
+        obj = context.object
+
+        col = layout.column()
+
+        if obj.pov.object_as == 'PARAMETRIC':
+            if not obj.pov.unlock_parameters:
+                col.prop(
+                    obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
+                )
+                col.label(text="Minimum U: " + str(obj.pov.u_min))
+                col.label(text="Minimum V: " + str(obj.pov.v_min))
+                col.label(text="Maximum U: " + str(obj.pov.u_max))
+                col.label(text="Minimum V: " + str(obj.pov.v_min))
+                col.label(text="X Function: " + str(obj.pov.x_eq))
+                col.label(text="Y Function: " + str(obj.pov.y_eq))
+                col.label(text="Z Function: " + str(obj.pov.x_eq))
+
+            else:
+                col.prop(
+                    obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
+                )
+                col.label(text="3D view proxy may get out of synch")
+                col.active = obj.pov.unlock_parameters
+
+                layout.operator("pov.parametric_update", text="Update", icon="SCRIPTPLUGINS")
+
+                col.prop(obj.pov, "u_min", text="Minimum U")
+                col.prop(obj.pov, "v_min", text="Minimum V")
+                col.prop(obj.pov, "u_max", text="Maximum U")
+                col.prop(obj.pov, "v_max", text="Minimum V")
+                col.prop(obj.pov, "x_eq", text="X Function")
+                col.prop(obj.pov, "y_eq", text="Y Function")
+                col.prop(obj.pov, "z_eq", text="Z Function")
+
+
+class OBJECT_PT_povray_replacement_text(ObjectButtonsPanel, Panel):
+    """Use this class to define pov object replacement field."""
+
+    bl_label = "Custom POV Code"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def draw(self, context):
+        layout = self.layout
+
+        obj = context.object
+
+        col = layout.column()
+        col.label(text="Replace properties with:")
+        col.prop(obj.pov, "replacement_text", text="")
+
+
+###############################################################################
+# Add Povray Objects
+###############################################################################
+def check_add_mesh_extra_objects():
+    """Test if Add mesh extra objects addon is activated
+
+    This addon is currently used to generate the proxy for POV parametric
+    surface which is almost the same priciple as its Math xyz surface
+    """
+    if "add_mesh_extra_objects" in bpy.context.preferences.addons.keys():
+        return True
+    return False
+
+
+def menu_func_add(self, context):
+    """Append the POV primitives submenu to blender add objects menu"""
+    engine = context.scene.render.engine
+    if engine == 'POVRAY_RENDER':
+        self.layout.menu("VIEW_MT_POV_primitives_add", icon="PLUGIN")
+
+
+class VIEW_MT_POV_primitives_add(Menu):
+    """Define the primitives menu with presets"""
+
+    bl_idname = "VIEW_MT_POV_primitives_add"
+    bl_label = "Povray"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        engine = context.scene.render.engine
+        return engine == 'POVRAY_RENDER'
+
+    def draw(self, context):
+        layout = self.layout
+        layout.operator_context = 'INVOKE_REGION_WIN'
+        layout.menu(VIEW_MT_POV_Basic_Shapes.bl_idname, text="Primitives", icon="GROUP")
+        layout.menu(VIEW_MT_POV_import.bl_idname, text="Import", icon="IMPORT")
+
+
+class VIEW_MT_POV_Basic_Shapes(Menu):
+    """Use this class to sort simple primitives menu entries."""
+
+    bl_idname = "POVRAY_MT_basic_shape_tools"
+    bl_label = "Basic_shapes"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.operator_context = 'INVOKE_REGION_WIN'
+        layout.operator("pov.addplane", text="Infinite Plane", icon='MESH_PLANE')
+        layout.operator("pov.addbox", text="Box", icon='MESH_CUBE')
+        layout.operator("pov.addsphere", text="Sphere", icon='SHADING_RENDERED')
+        layout.operator("pov.addcylinder", text="Cylinder", icon="MESH_CYLINDER")
+        layout.operator("pov.cone_add", text="Cone", icon="MESH_CONE")
+        layout.operator("pov.addtorus", text="Torus", icon='MESH_TORUS')
+        layout.separator()
+        layout.operator("pov.addrainbow", text="Rainbow", icon="COLOR")
+        layout.operator("pov.addlathe", text="Lathe", icon='MOD_SCREW')
+        layout.operator("pov.addprism", text="Prism", icon='MOD_SOLIDIFY')
+        layout.operator("pov.addsuperellipsoid", text="Superquadric Ellipsoid", icon='MOD_SUBSURF')
+        layout.operator("pov.addheightfield", text="Height Field", icon="RNDCURVE")
+        layout.operator("pov.addspheresweep", text="Sphere Sweep", icon='FORCE_CURVE')
+        layout.separator()
+        layout.operator("pov.addblobsphere", text="Blob Sphere", icon='META_DATA')
+        layout.separator()
+        layout.label(text="Isosurfaces")
+        layout.operator("pov.addisosurfacebox", text="Isosurface Box", icon="META_CUBE")
+        layout.operator("pov.addisosurfacesphere", text="Isosurface Sphere", icon="META_BALL")
+        layout.operator("pov.addsupertorus", text="Supertorus", icon="SURFACE_NTORUS")
+        layout.separator()
+        layout.label(text="Macro based")
+        layout.operator(
+            "pov.addpolygontocircle", text="Polygon To Circle Blending", icon="MOD_CAST"
+        )
+        layout.operator("pov.addloft", text="Loft", icon="SURFACE_NSURFACE")
+        layout.separator()
+        # Warning if the Add Advanced Objects addon containing
+        # Add mesh extra objects is not enabled
+        if not check_add_mesh_extra_objects():
+            # col = box.column()
+            layout.label(text="Please enable Add Mesh: Extra Objects addon", icon="INFO")
+            # layout.separator()
+            layout.operator(
+                "preferences.addon_show",
+                text="Go to Add Mesh: Extra Objects addon",
+                icon="PREFERENCES",
+            ).module = "add_mesh_extra_objects"
+
+            # layout.separator()
+            return
+        layout.operator("pov.addparametric", text="Parametric", icon='SCRIPTPLUGINS')
+
+
+classes = (
+    # ObjectButtonsPanel,
+    # PovDataButtonsPanel,
+    DATA_PT_POV_normals,
+    DATA_PT_POV_texture_space,
+    DATA_PT_POV_vertex_groups,
+    DATA_PT_POV_shape_keys,
+    DATA_PT_POV_uv_texture,
+    DATA_PT_POV_vertex_colors,
+    DATA_PT_POV_customdata,
+    MODIFIERS_PT_POV_modifiers,
+    OBJECT_PT_POV_obj_parameters,
+    OBJECT_PT_POV_obj_sphere,
+    OBJECT_PT_POV_obj_cylinder,
+    OBJECT_PT_POV_obj_cone,
+    OBJECT_PT_POV_obj_superellipsoid,
+    OBJECT_PT_POV_obj_torus,
+    OBJECT_PT_POV_obj_supertorus,
+    OBJECT_PT_POV_obj_parametric,
+    OBJECT_PT_povray_replacement_text,
+    VIEW_MT_POV_primitives_add,
+    VIEW_MT_POV_Basic_Shapes,
+)
+
+
+def register():
+    # from bpy.utils import register_class
+
+    for cls in classes:
+        register_class(cls)
+
+    bpy.types.VIEW3D_MT_add.prepend(menu_func_add)
+
+    # was used for parametric objects but made the other addon unreachable on
+    # unregister for other tools to use created a user action call instead
+    # addon_utils.enable("add_mesh_extra_objects", default_set=False, persistent=True)
+
+
+def unregister():
+    # addon_utils.disable("add_mesh_extra_objects", default_set=False)
+
+    bpy.types.VIEW3D_MT_add.remove(menu_func_add)
+
+    for cls in reversed(classes):
+        unregister_class(cls)
diff --git a/render_povray/object_mesh_topology.py b/render_povray/object_mesh_topology.py
new file mode 100755
index 000000000..2b0ce008a
--- /dev/null
+++ b/render_povray/object_mesh_topology.py
@@ -0,0 +1,1540 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# #**** END GPL LICENSE BLOCK #****
+
+# <pep8 compliant>
+
+"""Translate to POV the control point compounded geometries like polygon
+
+meshes or curve based shapes."""
+
+####################
+## Faster mesh export
+import numpy as np
+
+####################
+import random  # used for hair
+import bpy
+from . import texturing  # for how textures influence shaders
+from .scenography import export_smoke
+
+
+def matrix_as_pov_string(matrix):
+    """Translate some tranform matrix from Blender UI
+    to POV syntax and return that string """
+    matrix_string = (
+        "matrix <%.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, %.6f>\n"
+        % (
+            matrix[0][0],
+            matrix[1][0],
+            matrix[2][0],
+            matrix[0][1],
+            matrix[1][1],
+            matrix[2][1],
+            matrix[0][2],
+            matrix[1][2],
+            matrix[2][2],
+            matrix[0][3],
+            matrix[1][3],
+            matrix[2][3],
+        )
+    )
+    return matrix_string
+
+
+#    objectNames = {}
+DEF_OBJ_NAME = "Default"
+
+
+def export_meshes(
+    preview_dir,
+    file,
+    scene,
+    sel,
+    csg,
+    string_strip_hyphen,
+    safety,
+    write_object_modifiers,
+    material_names_dictionary,
+    write_object_material,
+    exported_lights_count,
+    unpacked_images,
+    image_format,
+    img_map,
+    img_map_transforms,
+    path_image,
+    smoke_path,
+    global_matrix,
+    write_matrix,
+    using_uberpov,
+    comments,
+    linebreaksinlists,
+    tab,
+    tab_level,
+    tab_write,
+    info_callback,
+):
+    """write all meshes as POV mesh2{} syntax to exported file """
+    # some numpy functions to speed up mesh export NOT IN USE YET
+
+    # TODO: also write a numpy function to read matrices at object level?
+    # feed below with mesh object.data, but only after doing data.calc_loop_triangles()
+    def read_verts_co(self, mesh):
+        #'float64' would be a slower 64-bit floating-point number numpy datatype
+        # using 'float32' vert coordinates for now until any issue is reported
+        mverts_co = np.zeros((len(mesh.vertices) * 3), dtype=np.float32)
+        mesh.vertices.foreach_get("co", mverts_co)
+        return np.reshape(mverts_co, (len(mesh.vertices), 3))
+
+    def read_verts_idx(self, mesh):
+        mverts_idx = np.zeros((len(mesh.vertices)), dtype=np.int64)
+        mesh.vertices.foreach_get("index", mverts_idx)
+        return np.reshape(mverts_idx, (len(mesh.vertices), 1))
+
+    def read_verts_norms(self, mesh):
+        #'float64' would be a slower 64-bit floating-point number numpy datatype
+        # using less accurate 'float16' normals for now until any issue is reported
+        mverts_no = np.zeros((len(mesh.vertices) * 3), dtype=np.float16)
+        mesh.vertices.foreach_get("normal", mverts_no)
+        return np.reshape(mverts_no, (len(mesh.vertices), 3))
+
+    def read_faces_idx(self, mesh):
+        mfaces_idx = np.zeros((len(mesh.loop_triangles)), dtype=np.int64)
+        mesh.loop_triangles.foreach_get("index", mfaces_idx)
+        return np.reshape(mfaces_idx, (len(mesh.loop_triangles), 1))
+
+    def read_faces_verts_indices(self, mesh):
+        mfaces_verts_idx = np.zeros((len(mesh.loop_triangles) * 3), dtype=np.int64)
+        mesh.loop_triangles.foreach_get("vertices", mfaces_verts_idx)
+        return np.reshape(mfaces_verts_idx, (len(mesh.loop_triangles), 3))
+
+    # Why is below different from vertex indices?
+    def read_faces_verts_loops(self, mesh):
+        mfaces_verts_loops = np.zeros((len(mesh.loop_triangles) * 3), dtype=np.int64)
+        mesh.loop_triangles.foreach_get("loops", mfaces_verts_loops)
+        return np.reshape(mfaces_verts_loops, (len(mesh.loop_triangles), 3))
+
+    def read_faces_norms(self, mesh):
+        #'float64' would be a slower 64-bit floating-point number numpy datatype
+        # using less accurate 'float16' normals for now until any issue is reported
+        mfaces_no = np.zeros((len(mesh.loop_triangles) * 3), dtype=np.float16)
+        mesh.loop_triangles.foreach_get("normal", mfaces_no)
+        return np.reshape(mfaces_no, (len(mesh.loop_triangles), 3))
+
+    def read_faces_smooth(self, mesh):
+        mfaces_smth = np.zeros((len(mesh.loop_triangles) * 1), dtype=np.bool)
+        mesh.loop_triangles.foreach_get("use_smooth", mfaces_smth)
+        return np.reshape(mfaces_smth, (len(mesh.loop_triangles), 1))
+
+    def read_faces_material_indices(self, mesh):
+        mfaces_mats_idx = np.zeros((len(mesh.loop_triangles)), dtype=np.int16)
+        mesh.loop_triangles.foreach_get("material_index", mfaces_mats_idx)
+        return np.reshape(mfaces_mats_idx, (len(mesh.loop_triangles), 1))
+
+    #        obmatslist = []
+    #        def hasUniqueMaterial():
+    #            # Grab materials attached to object instances ...
+    #            if hasattr(ob, 'material_slots'):
+    #                for ms in ob.material_slots:
+    #                    if ms.material is not None and ms.link == 'OBJECT':
+    #                        if ms.material in obmatslist:
+    #                            return False
+    #                        else:
+    #                            obmatslist.append(ms.material)
+    #                            return True
+    #        def hasObjectMaterial(ob):
+    #            # Grab materials attached to object instances ...
+    #            if hasattr(ob, 'material_slots'):
+    #                for ms in ob.material_slots:
+    #                    if ms.material is not None and ms.link == 'OBJECT':
+    #                        # If there is at least one material slot linked to the object
+    #                        # and not the data (mesh), always create a new, "private" data instance.
+    #                        return True
+    #            return False
+    # For objects using local material(s) only!
+    # This is a mapping between a tuple (dataname, material_names_dictionary, ...), and the POV dataname.
+    # As only objects using:
+    #     * The same data.
+    #     * EXACTLY the same materials, in EXACTLY the same sockets.
+    # ... can share a same instance in POV export.
+    obmats2data = {}
+
+    def check_object_materials(ob, name, dataname):
+        """Compare other objects exported material slots to avoid rewriting duplicates"""
+        if hasattr(ob, 'material_slots'):
+            has_local_mats = False
+            key = [dataname]
+            for ms in ob.material_slots:
+                if ms.material is not None:
+                    key.append(ms.material.name)
+                    if ms.link == 'OBJECT' and not has_local_mats:
+                        has_local_mats = True
+                else:
+                    # Even if the slot is empty, it is important to grab it...
+                    key.append("")
+            if has_local_mats:
+                # If this object uses local material(s), lets find if another object
+                # using the same data and exactly the same list of materials
+                # (in the same slots) has already been processed...
+                # Note that here also, we use object name as new, unique dataname for Pov.
+                key = tuple(key)  # Lists are not hashable...
+                if key not in obmats2data:
+                    obmats2data[key] = name
+                return obmats2data[key]
+        return None
+
+    data_ref = {}
+
+    def store(scene, ob, name, dataname, matrix):
+        # The Object needs to be written at least once but if its data is
+        # already in data_ref this has already been done.
+        # This func returns the "povray" name of the data, or None
+        # if no writing is needed.
+        if ob.is_modified(scene, 'RENDER'):
+            # Data modified.
+            # Create unique entry in data_ref by using object name
+            # (always unique in Blender) as data name.
+            data_ref[name] = [(name, matrix_as_pov_string(matrix))]
+            return name
+        # Here, we replace dataname by the value returned by check_object_materials, only if
+        # it is not evaluated to False (i.e. only if the object uses some local material(s)).
+        dataname = check_object_materials(ob, name, dataname) or dataname
+        if dataname in data_ref:
+            # Data already known, just add the object instance.
+            data_ref[dataname].append((name, matrix_as_pov_string(matrix)))
+            # No need to write data
+            return None
+        # Else (no return yet): Data not yet processed, create a new entry in data_ref.
+        data_ref[dataname] = [(name, matrix_as_pov_string(matrix))]
+        return dataname
+
+    # XXX TODO : Too many nested blocks in this object loop, split hair (+particles?) to their function in own file,
+    ob_num = 0
+    for ob in sel:
+        # Using depsgraph
+        depsgraph = bpy.context.evaluated_depsgraph_get()
+        ob = bpy.data.objects[ob.name].evaluated_get(depsgraph)
+
+        # subtract original from the count of their instances as were not counted before 2.8
+        if not (ob.is_instancer and ob.original != ob):
+            ob_num += 1
+
+            # XXX I moved all those checks here, as there is no need to compute names
+            #     for object we won't export here!
+            if ob.type in {
+                'LIGHT',
+                'CAMERA',  #'EMPTY', #empties can bear dupligroups
+                'META',
+                'ARMATURE',
+                'LATTICE',
+            }:
+                continue
+            fluid_flag = False
+            for mod in ob.modifiers:
+                if mod and hasattr(mod, 'fluid_type'):
+                    fluid_flag = True
+                    if mod.fluid_type == 'DOMAIN':
+                        if mod.domain_settings.domain_type == 'GAS':
+                            export_smoke(
+                                file, ob.name, smoke_path, comments, global_matrix, write_matrix
+                            )
+                        break  # don't render domain mesh, skip to next object.
+                    if mod.fluid_type == 'FLOW':  # The domain contains all the smoke. so that's it.
+                        if mod.flow_settings.flow_type == 'SMOKE':  # Check how liquids behave
+                            break  # don't render smoke flow emitter mesh either, skip to next object.
+            if not fluid_flag:
+                # Export Hair
+                # importing here rather than at the top recommended for addons startup footprint
+                from .object_particles import export_hair
+
+                render_emitter = True
+                if hasattr(ob, 'particle_systems'):
+                    render_emitter = False
+                    if ob.show_instancer_for_render:
+                        render_emitter = True
+                    for p_sys in ob.particle_systems:
+                        for mod in [
+                            m
+                            for m in ob.modifiers
+                            if (m is not None) and (m.type == 'PARTICLE_SYSTEM')
+                        ]:
+                            if (
+                                (p_sys.settings.render_type == 'PATH')
+                                and mod.show_render
+                                and (p_sys.name == mod.particle_system.name)
+                            ):
+                                export_hair(file, ob, p_sys, global_matrix, write_matrix)
+                                if not render_emitter:
+                                    continue  # don't render mesh, skip to next object.
+
+                #############################################
+                # Generating a name for object just like materials to be able to use it
+                # (baking for now or anything else).
+                # XXX I don't understand that if we are here, sel if a non-empty iterable,
+                #     so this condition is always True, IMO -- mont29
+                if ob.data:
+                    name_orig = "OB" + ob.name
+                    dataname_orig = "DATA" + ob.data.name
+                elif ob.is_instancer:
+                    if ob.instance_type == 'COLLECTION':
+                        name_orig = "OB" + ob.name
+                        dataname_orig = "DATA" + ob.instance_collection.name
+                    else:
+                        # hoping only dupligroups have several source datablocks
+                        # ob_dupli_list_create(scene) #deprecated in 2.8
+                        depsgraph = bpy.context.evaluated_depsgraph_get()
+                        for eachduplicate in depsgraph.object_instances:
+                            # Real dupli instance filtered because
+                            # original included in list since 2.8
+                            if eachduplicate.is_instance:
+                                dataname_orig = "DATA" + eachduplicate.object.name
+                        # ob.dupli_list_clear() #just don't store any reference to instance since 2.8
+                elif ob.type == 'EMPTY':
+                    name_orig = "OB" + ob.name
+                    dataname_orig = "DATA" + ob.name
+                else:
+                    name_orig = DEF_OBJ_NAME
+                    dataname_orig = DEF_OBJ_NAME
+                name = string_strip_hyphen(bpy.path.clean_name(name_orig))
+                dataname = string_strip_hyphen(bpy.path.clean_name(dataname_orig))
+                ##            for slot in ob.material_slots:
+                ##                if slot.material is not None and slot.link == 'OBJECT':
+                ##                    obmaterial = slot.material
+
+                #############################################
+
+                if info_callback:
+                    info_callback("Object %2.d of %2.d (%s)" % (ob_num, len(sel), ob.name))
+
+                # if ob.type != 'MESH':
+                #    continue
+                # me = ob.data
+
+                matrix = global_matrix @ ob.matrix_world
+                povdataname = store(scene, ob, name, dataname, matrix)
+                if povdataname is None:
+                    print("This is an instance of " + name)
+                    continue
+
+                print("Writing Down First Occurrence of " + name)
+
+                ############################################Povray Primitives
+                # special export_curves() function takes care of writing
+                # lathe, sphere_sweep, birail, and loft except with modifiers
+                # converted to mesh
+                if not ob.is_modified(scene, 'RENDER'):
+                    if ob.type == 'CURVE' and (
+                        ob.pov.curveshape in {'lathe', 'sphere_sweep', 'loft'}
+                    ):
+                        continue  # Don't render proxy mesh, skip to next object
+
+                if ob.pov.object_as == 'ISOSURFACE':
+                    tab_write("#declare %s = isosurface{ \n" % povdataname)
+                    tab_write("function{ \n")
+                    text_name = ob.pov.iso_function_text
+                    if text_name:
+                        node_tree = bpy.context.scene.node_tree
+                        for node in node_tree.nodes:
+                            if node.bl_idname == "IsoPropsNode" and node.label == ob.name:
+                                for inp in node.inputs:
+                                    if inp:
+                                        tab_write(
+                                            "#declare %s = %.6g;\n" % (inp.name, inp.default_value)
+                                        )
+
+                        text = bpy.data.texts[text_name]
+                        for line in text.lines:
+                            split = line.body.split()
+                            if split[0] != "#declare":
+                                tab_write("%s\n" % line.body)
+                    else:
+                        tab_write("abs(x) - 2 + y")
+                    tab_write("}\n")
+                    tab_write("threshold %.6g\n" % ob.pov.threshold)
+                    tab_write("max_gradient %.6g\n" % ob.pov.max_gradient)
+                    tab_write("accuracy  %.6g\n" % ob.pov.accuracy)
+                    tab_write("contained_by { ")
+                    if ob.pov.contained_by == "sphere":
+                        tab_write("sphere {0,%.6g}}\n" % ob.pov.container_scale)
+                    else:
+                        tab_write(
+                            "box {-%.6g,%.6g}}\n" % (ob.pov.container_scale, ob.pov.container_scale)
+                        )
+                    if ob.pov.all_intersections:
+                        tab_write("all_intersections\n")
+                    else:
+                        if ob.pov.max_trace > 1:
+                            tab_write("max_trace %.6g\n" % ob.pov.max_trace)
+                    pov_mat_name = "Default_texture"
+                    if ob.active_material:
+                        # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+                        try:
+                            material = ob.active_material
+                            write_object_material(material, ob, tab_write)
+                        except IndexError:
+                            print(me)
+                    # tab_write("texture {%s}\n"%pov_mat_name)
+                    tab_write("scale %.6g\n" % (1 / ob.pov.container_scale))
+                    tab_write("}\n")
+                    continue  # Don't render proxy mesh, skip to next object
+
+                if ob.pov.object_as == 'SUPERELLIPSOID':
+                    tab_write(
+                        "#declare %s = superellipsoid{ <%.4f,%.4f>\n"
+                        % (povdataname, ob.pov.se_n2, ob.pov.se_n1)
+                    )
+                    pov_mat_name = "Default_texture"
+                    if ob.active_material:
+                        # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+                        try:
+                            material = ob.active_material
+                            write_object_material(material, ob, tab_write)
+                        except IndexError:
+                            print(me)
+                    # tab_write("texture {%s}\n"%pov_mat_name)
+                    write_object_modifiers(scene, ob, file)
+                    tab_write("}\n")
+                    continue  # Don't render proxy mesh, skip to next object
+
+                if ob.pov.object_as == 'SUPERTORUS':
+                    rad_maj = ob.pov.st_major_radius
+                    rad_min = ob.pov.st_minor_radius
+                    ring = ob.pov.st_ring
+                    cross = ob.pov.st_cross
+                    accuracy = ob.pov.st_accuracy
+                    gradient = ob.pov.st_max_gradient
+                    ############Inline Supertorus macro
+                    file.write(
+                        "#macro Supertorus(RMj, RMn, MajorControl, MinorControl, Accuracy, MaxGradient)\n"
+                    )
+                    file.write("   #local CP = 2/MinorControl;\n")
+                    file.write("   #local RP = 2/MajorControl;\n")
+                    file.write("   isosurface {\n")
+                    file.write(
+                        "      function { pow( pow(abs(pow(pow(abs(x),RP) + pow(abs(z),RP), 1/RP) - RMj),CP) + pow(abs(y),CP) ,1/CP) - RMn }\n"
+                    )
+                    file.write("      threshold 0\n")
+                    file.write(
+                        "      contained_by {box {<-RMj-RMn,-RMn,-RMj-RMn>, < RMj+RMn, RMn, RMj+RMn>}}\n"
+                    )
+                    file.write("      #if(MaxGradient >= 1)\n")
+                    file.write("         max_gradient MaxGradient\n")
+                    file.write("      #else\n")
+                    file.write("         evaluate 1, 10, 0.1\n")
+                    file.write("      #end\n")
+                    file.write("      accuracy Accuracy\n")
+                    file.write("   }\n")
+                    file.write("#end\n")
+                    ############
+                    tab_write(
+                        "#declare %s = object{ Supertorus( %.4g,%.4g,%.4g,%.4g,%.4g,%.4g)\n"
+                        % (povdataname, rad_maj, rad_min, ring, cross, accuracy, gradient)
+                    )
+                    pov_mat_name = "Default_texture"
+                    if ob.active_material:
+                        # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+                        try:
+                            material = ob.active_material
+                            write_object_material(material, ob, tab_write)
+                        except IndexError:
+                            print(me)
+                    # tab_write("texture {%s}\n"%pov_mat_name)
+                    write_object_modifiers(scene, ob, file)
+                    tab_write("rotate x*90\n")
+                    tab_write("}\n")
+                    continue  # Don't render proxy mesh, skip to next object
+
+                if ob.pov.object_as == 'PLANE':
+                    tab_write("#declare %s = plane{ <0,0,1>,1\n" % povdataname)
+                    pov_mat_name = "Default_texture"
+                    if ob.active_material:
+                        # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+                        try:
+                            material = ob.active_material
+                            write_object_material(material, ob, tab_write)
+                        except IndexError:
+                            print(me)
+                    # tab_write("texture {%s}\n"%pov_mat_name)
+                    write_object_modifiers(scene, ob, file)
+                    # tab_write("rotate x*90\n")
+                    tab_write("}\n")
+                    continue  # Don't render proxy mesh, skip to next object
+
+                if ob.pov.object_as == 'BOX':
+                    tab_write("#declare %s = box { -1,1\n" % povdataname)
+                    pov_mat_name = "Default_texture"
+                    if ob.active_material:
+                        # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+                        try:
+                            material = ob.active_material
+                            write_object_material(material, ob, tab_write)
+                        except IndexError:
+                            print(me)
+                    # tab_write("texture {%s}\n"%pov_mat_name)
+                    write_object_modifiers(scene, ob, file)
+                    # tab_write("rotate x*90\n")
+                    tab_write("}\n")
+                    continue  # Don't render proxy mesh, skip to next object
+
+                if ob.pov.object_as == 'CONE':
+                    br = ob.pov.cone_base_radius
+                    cr = ob.pov.cone_cap_radius
+                    bz = ob.pov.cone_base_z
+                    cz = ob.pov.cone_cap_z
+                    tab_write(
+                        "#declare %s = cone { <0,0,%.4f>,%.4f,<0,0,%.4f>,%.4f\n"
+                        % (povdataname, bz, br, cz, cr)
+                    )
+                    pov_mat_name = "Default_texture"
+                    if ob.active_material:
+                        # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+                        try:
+                            material = ob.active_material
+                            write_object_material(material, ob, tab_write)
+                        except IndexError:
+                            print(me)
+                    # tab_write("texture {%s}\n"%pov_mat_name)
+                    write_object_modifiers(scene, ob, file)
+                    # tab_write("rotate x*90\n")
+                    tab_write("}\n")
+                    continue  # Don't render proxy mesh, skip to next object
+
+                if ob.pov.object_as == 'CYLINDER':
+                    r = ob.pov.cylinder_radius
+                    x2 = ob.pov.cylinder_location_cap[0]
+                    y2 = ob.pov.cylinder_location_cap[1]
+                    z2 = ob.pov.cylinder_location_cap[2]
+                    tab_write(
+                        "#declare %s = cylinder { <0,0,0>,<%6f,%6f,%6f>,%6f\n"
+                        % (povdataname, x2, y2, z2, r)
+                    )
+                    pov_mat_name = "Default_texture"
+                    if ob.active_material:
+                        # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+                        try:
+                            material = ob.active_material
+                            write_object_material(material, ob, tab_write)
+                        except IndexError:
+                            print(me)
+                    # tab_write("texture {%s}\n"%pov_mat_name)
+                    # cylinders written at origin, translated below
+                    write_object_modifiers(scene, ob, file)
+                    # tab_write("rotate x*90\n")
+                    tab_write("}\n")
+                    continue  # Don't render proxy mesh, skip to next object
+
+                if ob.pov.object_as == 'HEIGHT_FIELD':
+                    data = ""
+                    filename = ob.pov.hf_filename
+                    data += '"%s"' % filename
+                    gamma = ' gamma %.4f' % ob.pov.hf_gamma
+                    data += gamma
+                    if ob.pov.hf_premultiplied:
+                        data += ' premultiplied on'
+                    if ob.pov.hf_smooth:
+                        data += ' smooth'
+                    if ob.pov.hf_water > 0:
+                        data += ' water_level %.4f' % ob.pov.hf_water
+                    # hierarchy = ob.pov.hf_hierarchy
+                    tab_write('#declare %s = height_field { %s\n' % (povdataname, data))
+                    pov_mat_name = "Default_texture"
+                    if ob.active_material:
+                        # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+                        try:
+                            material = ob.active_material
+                            write_object_material(material, ob, tab_write)
+                        except IndexError:
+                            print(me)
+                    # tab_write("texture {%s}\n"%pov_mat_name)
+                    write_object_modifiers(scene, ob, file)
+                    tab_write("rotate x*90\n")
+                    tab_write("translate <-0.5,0.5,0>\n")
+                    tab_write("scale <0,-1,0>\n")
+                    tab_write("}\n")
+                    continue  # Don't render proxy mesh, skip to next object
+
+                if ob.pov.object_as == 'SPHERE':
+
+                    tab_write(
+                        "#declare %s = sphere { 0,%6f\n" % (povdataname, ob.pov.sphere_radius)
+                    )
+                    pov_mat_name = "Default_texture"
+                    if ob.active_material:
+                        # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+                        try:
+                            material = ob.active_material
+                            write_object_material(material, ob, tab_write)
+                        except IndexError:
+                            print(me)
+                    # tab_write("texture {%s}\n"%pov_mat_name)
+                    write_object_modifiers(scene, ob, file)
+                    # tab_write("rotate x*90\n")
+                    tab_write("}\n")
+                    continue  # Don't render proxy mesh, skip to next object
+
+                if ob.pov.object_as == 'TORUS':
+                    tab_write(
+                        "#declare %s = torus { %.4f,%.4f\n"
+                        % (povdataname, ob.pov.torus_major_radius, ob.pov.torus_minor_radius)
+                    )
+                    pov_mat_name = "Default_texture"
+                    if ob.active_material:
+                        # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+                        try:
+                            material = ob.active_material
+                            write_object_material(material, ob, tab_write)
+                        except IndexError:
+                            print(me)
+                    # tab_write("texture {%s}\n"%pov_mat_name)
+                    write_object_modifiers(scene, ob, file)
+                    tab_write("rotate x*90\n")
+                    tab_write("}\n")
+                    continue  # Don't render proxy mesh, skip to next object
+
+                if ob.pov.object_as == 'PARAMETRIC':
+                    tab_write("#declare %s = parametric {\n" % povdataname)
+                    tab_write("function { %s }\n" % ob.pov.x_eq)
+                    tab_write("function { %s }\n" % ob.pov.y_eq)
+                    tab_write("function { %s }\n" % ob.pov.z_eq)
+                    tab_write(
+                        "<%.4f,%.4f>, <%.4f,%.4f>\n"
+                        % (ob.pov.u_min, ob.pov.v_min, ob.pov.u_max, ob.pov.v_max)
+                    )
+                    # Previous to 3.8 default max_gradient 1.0 was too slow
+                    tab_write("max_gradient 0.001\n")
+                    if ob.pov.contained_by == "sphere":
+                        tab_write("contained_by { sphere{0, 2} }\n")
+                    else:
+                        tab_write("contained_by { box{-2, 2} }\n")
+                    tab_write("max_gradient %.6f\n" % ob.pov.max_gradient)
+                    tab_write("accuracy %.6f\n" % ob.pov.accuracy)
+                    tab_write("precompute 10 x,y,z\n")
+                    tab_write("}\n")
+                    continue  # Don't render proxy mesh, skip to next object
+
+                if ob.pov.object_as == 'POLYCIRCLE':
+                    # TODO write below macro Once:
+                    # if write_polytocircle_macro_once == 0:
+                    file.write("/****************************\n")
+                    file.write("This macro was written by 'And'.\n")
+                    file.write("Link:(http://news.povray.org/povray.binaries.scene-files/)\n")
+                    file.write("****************************/\n")
+                    file.write("//from math.inc:\n")
+                    file.write("#macro VPerp_Adjust(V, Axis)\n")
+                    file.write("   vnormalize(vcross(vcross(Axis, V), Axis))\n")
+                    file.write("#end\n")
+                    file.write("//Then for the actual macro\n")
+                    file.write("#macro Shape_Slice_Plane_2P_1V(point1, point2, clip_direct)\n")
+                    file.write("#local p1 = point1 + <0,0,0>;\n")
+                    file.write("#local p2 = point2 + <0,0,0>;\n")
+                    file.write("#local clip_v = vnormalize(clip_direct + <0,0,0>);\n")
+                    file.write("#local direct_v1 = vnormalize(p2 - p1);\n")
+                    file.write("#if(vdot(direct_v1, clip_v) = 1)\n")
+                    file.write('    #error "Shape_Slice_Plane_2P_1V error: Can\'t decide plane"\n')
+                    file.write("#end\n\n")
+                    file.write(
+                        "#local norm = -vnormalize(clip_v - direct_v1*vdot(direct_v1,clip_v));\n"
+                    )
+                    file.write("#local d = vdot(norm, p1);\n")
+                    file.write("plane{\n")
+                    file.write("norm, d\n")
+                    file.write("}\n")
+                    file.write("#end\n\n")
+                    file.write("//polygon to circle\n")
+                    file.write(
+                        "#macro Shape_Polygon_To_Circle_Blending(_polygon_n, _side_face, _polygon_circumscribed_radius, _circle_radius, _height)\n"
+                    )
+                    file.write("#local n = int(_polygon_n);\n")
+                    file.write("#if(n < 3)\n")
+                    file.write("    #error " "\n")
+                    file.write("#end\n\n")
+                    file.write("#local front_v = VPerp_Adjust(_side_face, z);\n")
+                    file.write("#if(vdot(front_v, x) >= 0)\n")
+                    file.write("    #local face_ang = acos(vdot(-y, front_v));\n")
+                    file.write("#else\n")
+                    file.write("    #local face_ang = -acos(vdot(-y, front_v));\n")
+                    file.write("#end\n")
+                    file.write("#local polyg_ext_ang = 2*pi/n;\n")
+                    file.write("#local polyg_outer_r = _polygon_circumscribed_radius;\n")
+                    file.write("#local polyg_inner_r = polyg_outer_r*cos(polyg_ext_ang/2);\n")
+                    file.write("#local cycle_r = _circle_radius;\n")
+                    file.write("#local h = _height;\n")
+                    file.write("#if(polyg_outer_r < 0 | cycle_r < 0 | h <= 0)\n")
+                    file.write('    #error "error: each side length must be positive"\n')
+                    file.write("#end\n\n")
+                    file.write("#local multi = 1000;\n")
+                    file.write("#local poly_obj =\n")
+                    file.write("polynomial{\n")
+                    file.write("4,\n")
+                    file.write("xyz(0,2,2): multi*1,\n")
+                    file.write("xyz(2,0,1): multi*2*h,\n")
+                    file.write("xyz(1,0,2): multi*2*(polyg_inner_r-cycle_r),\n")
+                    file.write("xyz(2,0,0): multi*(-h*h),\n")
+                    file.write("xyz(0,0,2): multi*(-pow(cycle_r - polyg_inner_r, 2)),\n")
+                    file.write("xyz(1,0,1): multi*2*h*(-2*polyg_inner_r + cycle_r),\n")
+                    file.write("xyz(1,0,0): multi*2*h*h*polyg_inner_r,\n")
+                    file.write("xyz(0,0,1): multi*2*h*polyg_inner_r*(polyg_inner_r - cycle_r),\n")
+                    file.write("xyz(0,0,0): multi*(-pow(polyg_inner_r*h, 2))\n")
+                    file.write("sturm\n")
+                    file.write("}\n\n")
+                    file.write("#local mockup1 =\n")
+                    file.write("difference{\n")
+                    file.write("    cylinder{\n")
+                    file.write("    <0,0,0.0>,<0,0,h>, max(polyg_outer_r, cycle_r)\n")
+                    file.write("    }\n\n")
+                    file.write("    #for(i, 0, n-1)\n")
+                    file.write("        object{\n")
+                    file.write("        poly_obj\n")
+                    file.write("        inverse\n")
+                    file.write("        rotate <0, 0, -90 + degrees(polyg_ext_ang*i)>\n")
+                    file.write("        }\n")
+                    file.write("        object{\n")
+                    file.write(
+                        "        Shape_Slice_Plane_2P_1V(<polyg_inner_r,0,0>,<cycle_r,0,h>,x)\n"
+                    )
+                    file.write("        rotate <0, 0, -90 + degrees(polyg_ext_ang*i)>\n")
+                    file.write("        }\n")
+                    file.write("    #end\n")
+                    file.write("}\n\n")
+                    file.write("object{\n")
+                    file.write("mockup1\n")
+                    file.write("rotate <0, 0, degrees(face_ang)>\n")
+                    file.write("}\n")
+                    file.write("#end\n")
+                    # Use the macro
+                    ngon = ob.pov.polytocircle_ngon
+                    ngonR = ob.pov.polytocircle_ngonR
+                    circleR = ob.pov.polytocircle_circleR
+                    tab_write(
+                        "#declare %s = object { Shape_Polygon_To_Circle_Blending(%s, z, %.4f, %.4f, 2) rotate x*180 translate z*1\n"
+                        % (povdataname, ngon, ngonR, circleR)
+                    )
+                    tab_write("}\n")
+                    continue  # Don't render proxy mesh, skip to next object
+
+                ## In remaining cases; keep at end so no "elif" is needed,
+                #       (as not skipped by any previous "continue")
+                #           and for originals not their instances,
+                #               attempt to export mesh:
+                if not ob.is_instancer:
+                    # except duplis which should be instances groups for now but all duplis later
+                    if ob.type == 'EMPTY':
+                        # XXX Should we only write this once and instanciate the same for every
+                        # empty in the final matrix writing, or even no marix and just a comment
+                        # with empty object transforms ?
+                        tab_write("\n//dummy sphere to represent Empty location\n")
+                        tab_write(
+                            "#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n"
+                            % povdataname
+                        )
+                        continue  # Don't render empty object but this is later addition, watch it.
+
+                    depsgraph = bpy.context.evaluated_depsgraph_get()
+                    ob_eval = ob.evaluated_get(depsgraph)
+                    try:
+                        me = ob_eval.to_mesh()
+
+                    # Here identify the exception for mesh object with no data: Runtime-Error ?
+                    # So we can write something for the dataname or maybe treated "if not me" below
+                    except BaseException as e:
+                        print(e.__doc__)
+                        print('An exception occurred: {}'.format(e))
+                        # also happens when curves cant be made into meshes because of no-data
+                        continue
+
+                    importance = ob.pov.importance_value
+                    if me:
+                        me.calc_loop_triangles()
+                        me_materials = me.materials
+                        me_faces = me.loop_triangles[:]
+                        ## numpytest
+                        # me_looptris = me.loops
+
+                        ## otypes = ['int32'] is a 32-bit signed integer number numpy datatype
+                        # get_v_index = np.vectorize(lambda l: l.vertex_index, otypes = ['int32'], cache = True)
+                        # faces_verts_idx = get_v_index(me_looptris)
+
+                    # if len(me_faces)==0:
+                    # tab_write("\n//dummy sphere to represent empty mesh location\n")
+                    # tab_write("#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n" % povdataname)
+
+                    if not me or not me_faces:
+                        tab_write("\n//dummy sphere to represent empty mesh location\n")
+                        tab_write(
+                            "#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n"
+                            % povdataname
+                        )
+                        continue
+
+                    uv_layers = me.uv_layers
+                    if len(uv_layers) > 0:
+                        if me.uv_layers.active and uv_layers.active.data:
+                            uv_layer = uv_layers.active.data
+                    else:
+                        uv_layer = None
+
+                    try:
+                        # vcol_layer = me.vertex_colors.active.data
+                        vcol_layer = me.vertex_colors.active.data
+                    except AttributeError:
+                        vcol_layer = None
+
+                    faces_verts = [f.vertices[:] for f in me_faces]
+                    faces_normals = [f.normal[:] for f in me_faces]
+                    verts_normals = [v.normal[:] for v in me.vertices]
+
+                    # Use named declaration to allow reference e.g. for baking. MR
+                    file.write("\n")
+                    tab_write("#declare %s =\n" % povdataname)
+                    tab_write("mesh2 {\n")
+                    tab_write("vertex_vectors {\n")
+                    tab_write("%d" % len(me.vertices))  # vert count
+
+                    tab_str = tab * tab_level
+                    for v in me.vertices:
+                        if linebreaksinlists:
+                            file.write(",\n")
+                            file.write(tab_str + "<%.6f, %.6f, %.6f>" % v.co[:])  # vert count
+                        else:
+                            file.write(", ")
+                            file.write("<%.6f, %.6f, %.6f>" % v.co[:])  # vert count
+                        # tab_write("<%.6f, %.6f, %.6f>" % v.co[:])  # vert count
+                    file.write("\n")
+                    tab_write("}\n")
+
+                    # Build unique Normal list
+                    uniqueNormals = {}
+                    for fi, f in enumerate(me_faces):
+                        fv = faces_verts[fi]
+                        # [-1] is a dummy index, use a list so we can modify in place
+                        if f.use_smooth:  # Use vertex normals
+                            for v in fv:
+                                key = verts_normals[v]
+                                uniqueNormals[key] = [-1]
+                        else:  # Use face normal
+                            key = faces_normals[fi]
+                            uniqueNormals[key] = [-1]
+
+                    tab_write("normal_vectors {\n")
+                    tab_write("%d" % len(uniqueNormals))  # vert count
+                    idx = 0
+                    tab_str = tab * tab_level
+                    for no, index in uniqueNormals.items():
+                        if linebreaksinlists:
+                            file.write(",\n")
+                            file.write(tab_str + "<%.6f, %.6f, %.6f>" % no)  # vert count
+                        else:
+                            file.write(", ")
+                            file.write("<%.6f, %.6f, %.6f>" % no)  # vert count
+                        index[0] = idx
+                        idx += 1
+                    file.write("\n")
+                    tab_write("}\n")
+
+                    # Vertex colors
+                    vertCols = {}  # Use for material colors also.
+
+                    if uv_layer:
+                        # Generate unique UV's
+                        uniqueUVs = {}
+                        # n = 0
+                        for f in me_faces:  # me.faces in 2.7
+                            uvs = [uv_layer[l].uv[:] for l in f.loops]
+
+                            for uv in uvs:
+                                uniqueUVs[uv[:]] = [-1]
+
+                        tab_write("uv_vectors {\n")
+                        # print unique_uvs
+                        tab_write("%d" % len(uniqueUVs))  # vert count
+                        idx = 0
+                        tab_str = tab * tab_level
+                        for uv, index in uniqueUVs.items():
+                            if linebreaksinlists:
+                                file.write(",\n")
+                                file.write(tab_str + "<%.6f, %.6f>" % uv)
+                            else:
+                                file.write(", ")
+                                file.write("<%.6f, %.6f>" % uv)
+                            index[0] = idx
+                            idx += 1
+                        '''
+                        else:
+                            # Just add 1 dummy vector, no real UV's
+                            tab_write('1') # vert count
+                            file.write(',\n\t\t<0.0, 0.0>')
+                        '''
+                        file.write("\n")
+                        tab_write("}\n")
+
+                    if me.vertex_colors:
+                        # Write down vertex colors as a texture for each vertex
+                        tab_write("texture_list {\n")
+                        tab_write("%d\n" % (len(me_faces) * 3))  # assumes we have only triangles
+                        VcolIdx = 0
+                        if comments:
+                            file.write(
+                                "\n  //Vertex colors: one simple pigment texture per vertex\n"
+                            )
+                        for fi, f in enumerate(me_faces):
+                            # annoying, index may be invalid
+                            material_index = f.material_index
+                            try:
+                                material = me_materials[material_index]
+                            except BaseException as e:
+                                print(e.__doc__)
+                                print('An exception occurred: {}'.format(e))
+                                material = None
+                            if (
+                                material
+                            ):  # and material.use_vertex_color_paint: #Always use vertex color when there is some for now
+
+                                cols = [vcol_layer[l].color[:] for l in f.loops]
+
+                                for col in cols:
+                                    key = (
+                                        col[0],
+                                        col[1],
+                                        col[2],
+                                        material_index,
+                                    )  # Material index!
+                                    VcolIdx += 1
+                                    vertCols[key] = [VcolIdx]
+                                    if linebreaksinlists:
+                                        tab_write(
+                                            "texture {pigment{ color srgb <%6f,%6f,%6f> }}\n"
+                                            % (col[0], col[1], col[2])
+                                        )
+                                    else:
+                                        tab_write(
+                                            "texture {pigment{ color srgb <%6f,%6f,%6f> }}"
+                                            % (col[0], col[1], col[2])
+                                        )
+                                        tab_str = tab * tab_level
+                            else:
+                                if material:
+                                    # Multiply diffuse with SSS Color
+                                    if material.pov_subsurface_scattering.use:
+                                        diffuse_color = [
+                                            i * j
+                                            for i, j in zip(
+                                                material.pov_subsurface_scattering.color[:],
+                                                material.diffuse_color[:],
+                                            )
+                                        ]
+                                        key = (
+                                            diffuse_color[0],
+                                            diffuse_color[1],
+                                            diffuse_color[2],
+                                            material_index,
+                                        )
+                                        vertCols[key] = [-1]
+                                    else:
+                                        diffuse_color = material.diffuse_color[:]
+                                        key = (
+                                            diffuse_color[0],
+                                            diffuse_color[1],
+                                            diffuse_color[2],
+                                            material_index,
+                                        )
+                                        vertCols[key] = [-1]
+
+                        tab_write("\n}\n")
+                        # Face indices
+                        tab_write("\nface_indices {\n")
+                        tab_write("%d" % (len(me_faces)))  # faces count
+                        tab_str = tab * tab_level
+
+                        for fi, f in enumerate(me_faces):
+                            fv = faces_verts[fi]
+                            material_index = f.material_index
+
+                            if vcol_layer:
+                                cols = [vcol_layer[l].color[:] for l in f.loops]
+
+                            if (
+                                not me_materials or me_materials[material_index] is None
+                            ):  # No materials
+                                if linebreaksinlists:
+                                    file.write(",\n")
+                                    # vert count
+                                    file.write(tab_str + "<%d,%d,%d>" % (fv[0], fv[1], fv[2]))
+                                else:
+                                    file.write(", ")
+                                    file.write("<%d,%d,%d>" % (fv[0], fv[1], fv[2]))  # vert count
+                            else:
+                                material = me_materials[material_index]
+                                if me.vertex_colors:  # and material.use_vertex_color_paint:
+                                    # Color per vertex - vertex color
+
+                                    col1 = cols[0]
+                                    col2 = cols[1]
+                                    col3 = cols[2]
+
+                                    ci1 = vertCols[col1[0], col1[1], col1[2], material_index][0]
+                                    ci2 = vertCols[col2[0], col2[1], col2[2], material_index][0]
+                                    ci3 = vertCols[col3[0], col3[1], col3[2], material_index][0]
+                                else:
+                                    # Color per material - flat material color
+                                    if material.pov_subsurface_scattering.use:
+                                        diffuse_color = [
+                                            i * j
+                                            for i, j in zip(
+                                                material.pov_subsurface_scattering.color[:],
+                                                material.diffuse_color[:],
+                                            )
+                                        ]
+                                    else:
+                                        diffuse_color = material.diffuse_color[:]
+                                    ci1 = ci2 = ci3 = vertCols[
+                                        diffuse_color[0],
+                                        diffuse_color[1],
+                                        diffuse_color[2],
+                                        f.material_index,
+                                    ][0]
+                                    # ci are zero based index so we'll subtract 1 from them
+                                if linebreaksinlists:
+                                    file.write(",\n")
+                                    file.write(
+                                        tab_str
+                                        + "<%d,%d,%d>, %d,%d,%d"
+                                        % (fv[0], fv[1], fv[2], ci1 - 1, ci2 - 1, ci3 - 1)
+                                    )  # vert count
+                                else:
+                                    file.write(", ")
+                                    file.write(
+                                        "<%d,%d,%d>, %d,%d,%d"
+                                        % (fv[0], fv[1], fv[2], ci1 - 1, ci2 - 1, ci3 - 1)
+                                    )  # vert count
+
+                        file.write("\n")
+                        tab_write("}\n")
+
+                        # normal_indices indices
+                        tab_write("normal_indices {\n")
+                        tab_write("%d" % (len(me_faces)))  # faces count
+                        tab_str = tab * tab_level
+                        for fi, fv in enumerate(faces_verts):
+
+                            if me_faces[fi].use_smooth:
+                                if linebreaksinlists:
+                                    file.write(",\n")
+                                    file.write(
+                                        tab_str
+                                        + "<%d,%d,%d>"
+                                        % (
+                                            uniqueNormals[verts_normals[fv[0]]][0],
+                                            uniqueNormals[verts_normals[fv[1]]][0],
+                                            uniqueNormals[verts_normals[fv[2]]][0],
+                                        )
+                                    )  # vert count
+                                else:
+                                    file.write(", ")
+                                    file.write(
+                                        "<%d,%d,%d>"
+                                        % (
+                                            uniqueNormals[verts_normals[fv[0]]][0],
+                                            uniqueNormals[verts_normals[fv[1]]][0],
+                                            uniqueNormals[verts_normals[fv[2]]][0],
+                                        )
+                                    )  # vert count
+                            else:
+                                idx = uniqueNormals[faces_normals[fi]][0]
+                                if linebreaksinlists:
+                                    file.write(",\n")
+                                    file.write(
+                                        tab_str + "<%d,%d,%d>" % (idx, idx, idx)
+                                    )  # vert count
+                                else:
+                                    file.write(", ")
+                                    file.write("<%d,%d,%d>" % (idx, idx, idx))  # vert count
+
+                        file.write("\n")
+                        tab_write("}\n")
+
+                        if uv_layer:
+                            tab_write("uv_indices {\n")
+                            tab_write("%d" % (len(me_faces)))  # faces count
+                            tab_str = tab * tab_level
+                            for f in me_faces:
+                                uvs = [uv_layer[l].uv[:] for l in f.loops]
+
+                                if linebreaksinlists:
+                                    file.write(",\n")
+                                    file.write(
+                                        tab_str
+                                        + "<%d,%d,%d>"
+                                        % (
+                                            uniqueUVs[uvs[0]][0],
+                                            uniqueUVs[uvs[1]][0],
+                                            uniqueUVs[uvs[2]][0],
+                                        )
+                                    )
+                                else:
+                                    file.write(", ")
+                                    file.write(
+                                        "<%d,%d,%d>"
+                                        % (
+                                            uniqueUVs[uvs[0]][0],
+                                            uniqueUVs[uvs[1]][0],
+                                            uniqueUVs[uvs[2]][0],
+                                        )
+                                    )
+
+                            file.write("\n")
+                            tab_write("}\n")
+
+                        # XXX BOOLEAN
+                        onceCSG = 0
+                        for mod in ob.modifiers:
+                            if onceCSG == 0:
+                                if mod:
+                                    if mod.type == 'BOOLEAN':
+                                        if ob.pov.boolean_mod == "POV":
+                                            file.write(
+                                                "\tinside_vector <%.6g, %.6g, %.6g>\n"
+                                                % (
+                                                    ob.pov.inside_vector[0],
+                                                    ob.pov.inside_vector[1],
+                                                    ob.pov.inside_vector[2],
+                                                )
+                                            )
+                                            onceCSG = 1
+
+                        if me.materials:
+                            try:
+                                material = me.materials[0]  # dodgy
+                                write_object_material(material, ob, tab_write)
+                            except IndexError:
+                                print(me)
+
+                        # POV object modifiers such as
+                        # hollow / sturm / double_illuminate etc.
+                        write_object_modifiers(scene, ob, file)
+
+                        # Importance for radiosity sampling added here:
+                        tab_write("radiosity { \n")
+                        tab_write("importance %3g \n" % importance)
+                        tab_write("}\n")
+
+                        tab_write("}\n")  # End of mesh block
+                    else:
+                        facesMaterials = []  # WARNING!!!!!!!!!!!!!!!!!!!!!!
+                        if me_materials:
+                            for f in me_faces:
+                                if f.material_index not in facesMaterials:
+                                    facesMaterials.append(f.material_index)
+                        # No vertex colors, so write material colors as vertex colors
+                        for i, material in enumerate(me_materials):
+
+                            if (
+                                material and material.pov.material_use_nodes == False
+                            ):  # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+                                # Multiply diffuse with SSS Color
+                                if material.pov_subsurface_scattering.use:
+                                    diffuse_color = [
+                                        i * j
+                                        for i, j in zip(
+                                            material.pov_subsurface_scattering.color[:],
+                                            material.diffuse_color[:],
+                                        )
+                                    ]
+                                    key = (
+                                        diffuse_color[0],
+                                        diffuse_color[1],
+                                        diffuse_color[2],
+                                        i,
+                                    )  # i == f.mat
+                                    vertCols[key] = [-1]
+                                else:
+                                    diffuse_color = material.diffuse_color[:]
+                                    key = (
+                                        diffuse_color[0],
+                                        diffuse_color[1],
+                                        diffuse_color[2],
+                                        i,
+                                    )  # i == f.mat
+                                    vertCols[key] = [-1]
+
+                                idx = 0
+                                local_material_names = []
+                                for col, index in vertCols.items():
+                                    # if me_materials:
+                                    mater = me_materials[col[3]]
+                                    if me_materials is None:  # XXX working?
+                                        material_finish = DEF_MAT_NAME  # not working properly,
+                                        trans = 0.0
+
+                                    else:
+                                        texturing.write_texture_influence(
+                                            using_uberpov,
+                                            mater,
+                                            material_names_dictionary,
+                                            local_material_names,
+                                            path_image,
+                                            exported_lights_count,
+                                            image_format,
+                                            img_map,
+                                            img_map_transforms,
+                                            tab_write,
+                                            comments,
+                                            string_strip_hyphen,
+                                            safety,
+                                            col,
+                                            preview_dir,
+                                            unpacked_images,
+                                        )
+                                    ###################################################################
+                                    index[0] = idx
+                                    idx += 1
+
+                        # Vert Colors
+                        tab_write("texture_list {\n")
+                        # In case there's is no material slot, give at least one texture
+                        # (an empty one so it uses pov default)
+                        if len(vertCols) == 0:
+                            file.write(tab_str + "1")
+                        else:
+                            file.write(tab_str + "%s" % (len(vertCols)))  # vert count
+
+                        # below "material" alias, added check ob.active_material
+                        # to avoid variable referenced before assignment error
+                        try:
+                            material = ob.active_material
+                        except IndexError:
+                            # when no material slot exists,
+                            material = None
+
+                        # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+                        if (
+                            material
+                            and ob.active_material is not None
+                            and material.pov.material_use_nodes == False
+                        ):
+                            if material.pov.replacement_text != "":
+                                file.write("\n")
+                                file.write(" texture{%s}\n" % material.pov.replacement_text)
+
+                            else:
+                                # Loop through declared materials list
+                                for cMN in local_material_names:
+                                    if material != "Default":
+                                        file.write("\n texture{MAT_%s}\n" % cMN)
+                                        # use string_strip_hyphen(material_names_dictionary[material]))
+                                        # or Something like that to clean up the above?
+                        elif material and material.pov.material_use_nodes:
+                            for index in facesMaterials:
+                                faceMaterial = string_strip_hyphen(
+                                    bpy.path.clean_name(me_materials[index].name)
+                                )
+                                file.write("\n texture{%s}\n" % faceMaterial)
+                        # END!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+                        else:
+                            file.write(" texture{}\n")
+                        tab_write("}\n")
+
+                        # Face indices
+                        tab_write("face_indices {\n")
+                        tab_write("%d" % (len(me_faces)))  # faces count
+                        tab_str = tab * tab_level
+
+                        for fi, f in enumerate(me_faces):
+                            fv = faces_verts[fi]
+                            material_index = f.material_index
+
+                            if vcol_layer:
+                                cols = [vcol_layer[l].color[:] for l in f.loops]
+
+                            if (
+                                not me_materials or me_materials[material_index] is None
+                            ):  # No materials
+                                if linebreaksinlists:
+                                    file.write(",\n")
+                                    # vert count
+                                    file.write(tab_str + "<%d,%d,%d>" % (fv[0], fv[1], fv[2]))
+                                else:
+                                    file.write(", ")
+                                    file.write("<%d,%d,%d>" % (fv[0], fv[1], fv[2]))  # vert count
+                            else:
+                                material = me_materials[material_index]
+                                ci1 = ci2 = ci3 = f.material_index
+                                if me.vertex_colors:  # and material.use_vertex_color_paint:
+                                    # Color per vertex - vertex color
+
+                                    col1 = cols[0]
+                                    col2 = cols[1]
+                                    col3 = cols[2]
+
+                                    ci1 = vertCols[col1[0], col1[1], col1[2], material_index][0]
+                                    ci2 = vertCols[col2[0], col2[1], col2[2], material_index][0]
+                                    ci3 = vertCols[col3[0], col3[1], col3[2], material_index][0]
+                                elif material.pov.material_use_nodes:
+                                    ci1 = ci2 = ci3 = 0
+                                else:
+                                    # Color per material - flat material color
+                                    if material.pov_subsurface_scattering.use:
+                                        diffuse_color = [
+                                            i * j
+                                            for i, j in zip(
+                                                material.pov_subsurface_scattering.color[:],
+                                                material.diffuse_color[:],
+                                            )
+                                        ]
+                                    else:
+                                        diffuse_color = material.diffuse_color[:]
+                                    ci1 = ci2 = ci3 = vertCols[
+                                        diffuse_color[0],
+                                        diffuse_color[1],
+                                        diffuse_color[2],
+                                        f.material_index,
+                                    ][0]
+
+                                if linebreaksinlists:
+                                    file.write(",\n")
+                                    file.write(
+                                        tab_str
+                                        + "<%d,%d,%d>, %d,%d,%d"
+                                        % (fv[0], fv[1], fv[2], ci1, ci2, ci3)
+                                    )  # vert count
+                                else:
+                                    file.write(", ")
+                                    file.write(
+                                        "<%d,%d,%d>, %d,%d,%d"
+                                        % (fv[0], fv[1], fv[2], ci1, ci2, ci3)
+                                    )  # vert count
+
+                        file.write("\n")
+                        tab_write("}\n")
+
+                        # normal_indices indices
+                        tab_write("normal_indices {\n")
+                        tab_write("%d" % (len(me_faces)))  # faces count
+                        tab_str = tab * tab_level
+                        for fi, fv in enumerate(faces_verts):
+                            if me_faces[fi].use_smooth:
+                                if linebreaksinlists:
+                                    file.write(",\n")
+                                    file.write(
+                                        tab_str
+                                        + "<%d,%d,%d>"
+                                        % (
+                                            uniqueNormals[verts_normals[fv[0]]][0],
+                                            uniqueNormals[verts_normals[fv[1]]][0],
+                                            uniqueNormals[verts_normals[fv[2]]][0],
+                                        )
+                                    )  # vert count
+                                else:
+                                    file.write(", ")
+                                    file.write(
+                                        "<%d,%d,%d>"
+                                        % (
+                                            uniqueNormals[verts_normals[fv[0]]][0],
+                                            uniqueNormals[verts_normals[fv[1]]][0],
+                                            uniqueNormals[verts_normals[fv[2]]][0],
+                                        )
+                                    )  # vert count
+                            else:
+                                idx = uniqueNormals[faces_normals[fi]][0]
+                                if linebreaksinlists:
+                                    file.write(",\n")
+                                    file.write(
+                                        tab_str + "<%d,%d,%d>" % (idx, idx, idx)
+                                    )  # vertcount
+                                else:
+                                    file.write(", ")
+                                    file.write("<%d,%d,%d>" % (idx, idx, idx))  # vert count
+
+                        file.write("\n")
+                        tab_write("}\n")
+
+                        if uv_layer:
+                            tab_write("uv_indices {\n")
+                            tab_write("%d" % (len(me_faces)))  # faces count
+                            tab_str = tab * tab_level
+                            for f in me_faces:
+                                uvs = [uv_layer[l].uv[:] for l in f.loops]
+
+                                if linebreaksinlists:
+                                    file.write(",\n")
+                                    file.write(
+                                        tab_str
+                                        + "<%d,%d,%d>"
+                                        % (
+                                            uniqueUVs[uvs[0]][0],
+                                            uniqueUVs[uvs[1]][0],
+                                            uniqueUVs[uvs[2]][0],
+                                        )
+                                    )
+                                else:
+                                    file.write(", ")
+                                    file.write(
+                                        "<%d,%d,%d>"
+                                        % (
+                                            uniqueUVs[uvs[0]][0],
+                                            uniqueUVs[uvs[1]][0],
+                                            uniqueUVs[uvs[2]][0],
+                                        )
+                                    )
+
+                            file.write("\n")
+                            tab_write("}\n")
+
+                        # XXX BOOLEAN
+                        onceCSG = 0
+                        for mod in ob.modifiers:
+                            if onceCSG == 0:
+                                if mod:
+                                    if mod.type == 'BOOLEAN':
+                                        if ob.pov.boolean_mod == "POV":
+                                            file.write(
+                                                "\tinside_vector <%.6g, %.6g, %.6g>\n"
+                                                % (
+                                                    ob.pov.inside_vector[0],
+                                                    ob.pov.inside_vector[1],
+                                                    ob.pov.inside_vector[2],
+                                                )
+                                            )
+                                            onceCSG = 1
+
+                        if me.materials:
+                            try:
+                                material = me.materials[0]  # dodgy
+                                write_object_material(material, ob, tab_write)
+                            except IndexError:
+                                print(me)
+
+                        # POV object modifiers such as
+                        # hollow / sturm / double_illuminate etc.
+                        write_object_modifiers(scene, ob, file)
+
+                        # Importance for radiosity sampling added here:
+                        tab_write("radiosity { \n")
+                        tab_write("importance %3g \n" % importance)
+                        tab_write("}\n")
+
+                        tab_write("}\n")  # End of mesh block
+
+                    ob_eval.to_mesh_clear()
+
+    if csg:
+        duplidata_ref = []
+        _dupnames_seen = dict()  # avoid duplicate output during introspection
+        for ob in sel:
+            # matrix = global_matrix @ ob.matrix_world
+            if ob.is_instancer:
+                tab_write("\n//--DupliObjects in %s--\n\n" % ob.name)
+                # ob.dupli_list_create(scene) #deprecated in 2.8
+                depsgraph = bpy.context.evaluated_depsgraph_get()
+                dup = ""
+                if ob.is_modified(scene, 'RENDER'):
+                    # modified object always unique so using object name rather than data name
+                    dup = "#declare OB%s = union{\n" % (
+                        string_strip_hyphen(bpy.path.clean_name(ob.name))
+                    )
+                else:
+                    dup = "#declare DATA%s = union{\n" % (
+                        string_strip_hyphen(bpy.path.clean_name(ob.name))
+                    )
+                for eachduplicate in depsgraph.object_instances:
+                    if (
+                        eachduplicate.is_instance
+                    ):  # Real dupli instance filtered because original included in list since 2.8
+                        _dupname = eachduplicate.object.name
+                        _dupobj = bpy.data.objects[_dupname]
+                        # BEGIN introspection for troubleshooting purposes
+                        if not "name" in dir(_dupobj.data):
+                            if _dupname not in _dupnames_seen:
+                                print(
+                                    "WARNING: bpy.data.objects[%s].data (of type %s) has no 'name' attribute"
+                                    % (_dupname, type(_dupobj.data))
+                                )
+                                for _thing in dir(_dupobj):
+                                    print(
+                                        "||  %s.%s = %s"
+                                        % (_dupname, _thing, getattr(_dupobj, _thing))
+                                    )
+                                _dupnames_seen[_dupname] = 1
+                                print("''=>  Unparseable objects so far: %s" % (_dupnames_seen))
+                            else:
+                                _dupnames_seen[_dupname] += 1
+                            continue  # don't try to parse data objects with no name attribute
+                        # END introspection for troubleshooting purposes
+                        duplidataname = "OB" + string_strip_hyphen(
+                            bpy.path.clean_name(_dupobj.data.name)
+                        )
+                        dupmatrix = (
+                            eachduplicate.matrix_world.copy()
+                        )  # has to be copied to not store instance since 2.8
+                        dup += "\tobject {\n\t\tDATA%s\n\t\t%s\t}\n" % (
+                            string_strip_hyphen(bpy.path.clean_name(_dupobj.data.name)),
+                            matrix_as_pov_string(ob.matrix_world.inverted() @ dupmatrix),
+                        )
+                        # add object to a list so that it is not rendered for some instance_types
+                        if (
+                            ob.instance_type not in {'COLLECTION'}
+                            and duplidataname not in duplidata_ref
+                        ):
+                            duplidata_ref.append(
+                                duplidataname
+                            )  # older key [string_strip_hyphen(bpy.path.clean_name("OB"+ob.name))]
+                dup += "}\n"
+                # ob.dupli_list_clear()# just do not store any reference to instance since 2.8
+                tab_write(dup)
+            else:
+                continue
+        print("WARNING: Unparseable objects in current .blend file:\n''=> %s" % (_dupnames_seen))
+        print("duplidata_ref = %s" % (duplidata_ref))
+        for data_name, inst in data_ref.items():
+            for ob_name, matrix_str in inst:
+                if ob_name not in duplidata_ref:  # .items() for a dictionary
+                    tab_write("\n//----Blender Object Name:%s----\n" % ob_name)
+                    if ob.pov.object_as == '':
+                        tab_write("object { \n")
+                        tab_write("%s\n" % data_name)
+                        tab_write("%s\n" % matrix_str)
+                        tab_write("}\n")
+                    else:
+                        no_boolean = True
+                        for mod in ob.modifiers:
+                            if mod.type == 'BOOLEAN':
+                                operation = None
+                                no_boolean = False
+                                if mod.operation == 'INTERSECT':
+                                    operation = 'intersection'
+                                else:
+                                    operation = mod.operation.lower()
+                                mod_ob_name = string_strip_hyphen(
+                                    bpy.path.clean_name(mod.object.name)
+                                )
+                                mod_matrix = global_matrix @ mod.object.matrix_world
+                                mod_ob_matrix = matrix_as_pov_string(mod_matrix)
+                                tab_write("%s { \n" % operation)
+                                tab_write("object { \n")
+                                tab_write("%s\n" % data_name)
+                                tab_write("%s\n" % matrix_str)
+                                tab_write("}\n")
+                                tab_write("object { \n")
+                                tab_write("%s\n" % ('DATA' + mod_ob_name))
+                                tab_write("%s\n" % mod_ob_matrix)
+                                tab_write("}\n")
+                                tab_write("}\n")
+                                break
+                        if no_boolean:
+                            tab_write("object { \n")
+                            tab_write("%s\n" % data_name)
+                            tab_write("%s\n" % matrix_str)
+                            tab_write("}\n")
diff --git a/render_povray/object_particles.py b/render_povray/object_particles.py
new file mode 100755
index 000000000..2d4f0dccc
--- /dev/null
+++ b/render_povray/object_particles.py
@@ -0,0 +1,255 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+"""Get some Blender particle objects translated to POV."""
+
+import bpy
+
+
+def export_hair(file, ob, p_sys, global_matrix, write_matrix):
+    """Get Blender path particles (hair strands) objects translated to POV sphere_sweep unions."""
+    # tstart = time.time()
+    textured_hair = 0
+    if ob.material_slots[p_sys.settings.material - 1].material and ob.active_material is not None:
+        pmaterial = ob.material_slots[p_sys.settings.material - 1].material
+        # XXX Todo: replace by pov_(Particles?)_texture_slot
+        for th in pmaterial.pov_texture_slots:
+            povtex = th.texture  # slot.name
+            tex = bpy.data.textures[povtex]
+
+            if th and th.use:
+                if (tex.type == 'IMAGE' and tex.image) or tex.type != 'IMAGE':
+                    if th.use_map_color_diffuse:
+                        textured_hair = 1
+        if pmaterial.strand.use_blender_units:
+            strand_start = pmaterial.strand.root_size
+            strand_end = pmaterial.strand.tip_size
+            strand_shape = pmaterial.strand.shape
+        else:  # Blender unit conversion
+            strand_start = pmaterial.strand.root_size / 200.0
+            strand_end = pmaterial.strand.tip_size / 200.0
+            strand_shape = pmaterial.strand.shape
+    else:
+        pmaterial = "default"  # No material assigned in blender, use default one
+        strand_start = 0.01
+        strand_end = 0.01
+        strand_shape = 0.0
+    # Set the number of particles to render count rather than 3d view display
+    # p_sys.set_resolution(scene, ob, 'RENDER') # DEPRECATED
+    # When you render, the entire dependency graph will be
+    # evaluated at render resolution, including the particles.
+    # In the viewport it will be at viewport resolution.
+    # So there is no need fo render engines to use this function anymore,
+    # it's automatic now.
+    steps = p_sys.settings.display_step
+    steps = 2 ** steps  # or + 1 # Formerly : len(particle.hair_keys)
+
+    total_number_of_strands = p_sys.settings.count + p_sys.settings.rendered_child_count
+    # hairCounter = 0
+    file.write('#declare HairArray = array[%i] {\n' % total_number_of_strands)
+    for pindex in range(0, total_number_of_strands):
+
+        # if particle.is_exist and particle.is_visible:
+        # hairCounter += 1
+        # controlPointCounter = 0
+        # Each hair is represented as a separate sphere_sweep in POV-Ray.
+
+        file.write('sphere_sweep{')
+        if p_sys.settings.use_hair_bspline:
+            file.write('b_spline ')
+            file.write(
+                '%i,\n' % (steps + 2)
+            )  # +2 because the first point needs tripling to be more than a handle in POV
+        else:
+            file.write('linear_spline ')
+            file.write('%i,\n' % (steps))
+        # changing world coordinates to object local coordinates by
+        # multiplying with inverted matrix
+        init_coord = ob.matrix_world.inverted() @ (p_sys.co_hair(ob, particle_no=pindex, step=0))
+        if (
+            ob.material_slots[p_sys.settings.material - 1].material
+            and ob.active_material is not None
+        ):
+            pmaterial = ob.material_slots[p_sys.settings.material - 1].material
+            for th in pmaterial.pov_texture_slots:
+                if th and th.use and th.use_map_color_diffuse:
+                    povtex = th.texture  # slot.name
+                    tex = bpy.data.textures[povtex]
+                    # treat POV textures as bitmaps
+                    if (
+                        tex.type == 'IMAGE'
+                        and tex.image
+                        and th.texture_coords == 'UV'
+                        and ob.data.uv_textures is not None
+                    ):
+                        # or (
+                        # tex.pov.tex_pattern_type != 'emulator'
+                        # and th.texture_coords == 'UV'
+                        # and ob.data.uv_textures is not None
+                        # ):
+                        image = tex.image
+                        image_width = image.size[0]
+                        image_height = image.size[1]
+                        image_pixels = image.pixels[:]
+                        uv_co = p_sys.uv_on_emitter(mod, p_sys.particles[pindex], pindex, 0)
+                        x_co = round(uv_co[0] * (image_width - 1))
+                        y_co = round(uv_co[1] * (image_height - 1))
+                        pixelnumber = (image_width * y_co) + x_co
+                        r = image_pixels[pixelnumber * 4]
+                        g = image_pixels[pixelnumber * 4 + 1]
+                        b = image_pixels[pixelnumber * 4 + 2]
+                        a = image_pixels[pixelnumber * 4 + 3]
+                        init_color = (r, g, b, a)
+                    else:
+                        # only overwrite variable for each competing texture for now
+                        init_color = tex.evaluate((init_coord[0], init_coord[1], init_coord[2]))
+        for step in range(0, steps):
+            coord = ob.matrix_world.inverted() @ (p_sys.co_hair(ob, particle_no=pindex, step=step))
+            # for controlPoint in particle.hair_keys:
+            if p_sys.settings.clump_factor != 0:
+                hair_strand_diameter = p_sys.settings.clump_factor / 200.0 * random.uniform(0.5, 1)
+            elif step == 0:
+                hair_strand_diameter = strand_start
+            else:
+                hair_strand_diameter += (strand_end - strand_start) / (
+                    p_sys.settings.display_step + 1
+                )  # XXX +1 or not? # XXX use strand_shape in formula
+            if step == 0 and p_sys.settings.use_hair_bspline:
+                # Write three times the first point to compensate pov Bezier handling
+                file.write(
+                    '<%.6g,%.6g,%.6g>,%.7g,\n'
+                    % (coord[0], coord[1], coord[2], abs(hair_strand_diameter))
+                )
+                file.write(
+                    '<%.6g,%.6g,%.6g>,%.7g,\n'
+                    % (coord[0], coord[1], coord[2], abs(hair_strand_diameter))
+                )
+                # Useless because particle location is the tip, not the root:
+                # file.write(
+                # '<%.6g,%.6g,%.6g>,%.7g'
+                # % (
+                # particle.location[0],
+                # particle.location[1],
+                # particle.location[2],
+                # abs(hair_strand_diameter)
+                # )
+                # )
+                # file.write(',\n')
+            # controlPointCounter += 1
+            # total_number_of_strands += len(p_sys.particles)# len(particle.hair_keys)
+
+            # Each control point is written out, along with the radius of the
+            # hair at that point.
+            file.write(
+                '<%.6g,%.6g,%.6g>,%.7g' % (coord[0], coord[1], coord[2], abs(hair_strand_diameter))
+            )
+
+            # All coordinates except the last need a following comma.
+
+            if step != steps - 1:
+                file.write(',\n')
+            else:
+                if textured_hair:
+                    # Write pigment and alpha (between Pov and Blender,
+                    # alpha 0 and 1 are reversed)
+                    file.write(
+                        '\npigment{ color srgbf < %.3g, %.3g, %.3g, %.3g> }\n'
+                        % (init_color[0], init_color[1], init_color[2], 1.0 - init_color[3])
+                    )
+                # End the sphere_sweep declaration for this hair
+                file.write('}\n')
+
+        # All but the final sphere_sweep (each array element) needs a terminating comma.
+        if pindex != total_number_of_strands:
+            file.write(',\n')
+        else:
+            file.write('\n')
+
+    # End the array declaration.
+
+    file.write('}\n')
+    file.write('\n')
+
+    if not textured_hair:
+        # Pick up the hair material diffuse color and create a default POV-Ray hair texture.
+
+        file.write('#ifndef (HairTexture)\n')
+        file.write('  #declare HairTexture = texture {\n')
+        file.write(
+            '    pigment {srgbt <%s,%s,%s,%s>}\n'
+            % (
+                pmaterial.diffuse_color[0],
+                pmaterial.diffuse_color[1],
+                pmaterial.diffuse_color[2],
+                (pmaterial.strand.width_fade + 0.05),
+            )
+        )
+        file.write('  }\n')
+        file.write('#end\n')
+        file.write('\n')
+
+    # Dynamically create a union of the hairstrands (or a subset of them).
+    # By default use every hairstrand, commented line is for hand tweaking test renders.
+    file.write('//Increasing HairStep divides the amount of hair for test renders.\n')
+    file.write('#ifndef(HairStep) #declare HairStep = 1; #end\n')
+    file.write('union{\n')
+    file.write('  #local I = 0;\n')
+    file.write('  #while (I < %i)\n' % total_number_of_strands)
+    file.write('    object {HairArray[I]')
+    if not textured_hair:
+        file.write(' texture{HairTexture}\n')
+    else:
+        file.write('\n')
+    # Translucency of the hair:
+    file.write('        hollow\n')
+    file.write('        double_illuminate\n')
+    file.write('        interior {\n')
+    file.write('            ior 1.45\n')
+    file.write('            media {\n')
+    file.write('                scattering { 1, 10*<0.73, 0.35, 0.15> /*extinction 0*/ }\n')
+    file.write('                absorption 10/<0.83, 0.75, 0.15>\n')
+    file.write('                samples 1\n')
+    file.write('                method 2\n')
+    file.write('                density {cylindrical\n')
+    file.write('                    color_map {\n')
+    file.write('                        [0.0 rgb <0.83, 0.45, 0.35>]\n')
+    file.write('                        [0.5 rgb <0.8, 0.8, 0.4>]\n')
+    file.write('                        [1.0 rgb <1,1,1>]\n')
+    file.write('                    }\n')
+    file.write('                }\n')
+    file.write('            }\n')
+    file.write('        }\n')
+    file.write('    }\n')
+
+    file.write('    #local I = I + HairStep;\n')
+    file.write('  #end\n')
+
+    write_matrix(global_matrix @ ob.matrix_world)
+
+    file.write('}')
+    print('Totals hairstrands written: %i' % total_number_of_strands)
+    print('Number of tufts (particle systems)', len(ob.particle_systems))
+
+    # Set back the displayed number of particles to preview count
+    # p_sys.set_resolution(scene, ob, 'PREVIEW') #DEPRECATED
+    # When you render, the entire dependency graph will be
+    # evaluated at render resolution, including the particles.
+    # In the viewport it will be at viewport resolution.
+    # So there is no need fo render engines to use this function anymore,
+    # it's automatic now.
diff --git a/render_povray/primitives.py b/render_povray/object_primitives.py
old mode 100644
new mode 100755
similarity index 58%
rename from render_povray/primitives.py
rename to render_povray/object_primitives.py
index 6d8642203..4556f2df5
--- a/render_povray/primitives.py
+++ b/render_povray/object_primitives.py
@@ -19,13 +19,12 @@
 # <pep8 compliant>
 
 """ Get POV-Ray specific objects In and Out of Blender """
-
-import bpy
+from math import pi, cos, sin
 import os.path
+import bpy
+from bpy_extras.object_utils import object_data_add
 from bpy_extras.io_utils import ImportHelper
-from bpy_extras import object_utils
-from bpy.utils import register_class
-from math import atan, pi, degrees, sqrt, cos, sin
+from bpy.utils import register_class, unregister_class
 from bpy.types import Operator
 
 from bpy.props import (
@@ -35,8 +34,6 @@ from bpy.props import (
     FloatProperty,
     FloatVectorProperty,
     EnumProperty,
-    PointerProperty,
-    CollectionProperty,
 )
 
 from mathutils import Vector, Matrix
@@ -45,6 +42,69 @@ from mathutils import Vector, Matrix
 # import collections
 
 
+def write_object_modifiers(scene, ob, File):
+    """Translate some object level POV statements from Blender UI
+    to POV syntax and write to exported file """
+
+    # Maybe return that string to be added instead of directly written.
+
+    '''XXX WIP
+    onceCSG = 0
+    for mod in ob.modifiers:
+        if onceCSG == 0:
+            if mod :
+                if mod.type == 'BOOLEAN':
+                    if ob.pov.boolean_mod == "POV":
+                        File.write("\tinside_vector <%.6g, %.6g, %.6g>\n" %
+                                   (ob.pov.inside_vector[0],
+                                    ob.pov.inside_vector[1],
+                                    ob.pov.inside_vector[2]))
+                        onceCSG = 1
+    '''
+
+    if ob.pov.hollow:
+        File.write("\thollow\n")
+    if ob.pov.double_illuminate:
+        File.write("\tdouble_illuminate\n")
+    if ob.pov.sturm:
+        File.write("\tsturm\n")
+    if ob.pov.no_shadow:
+        File.write("\tno_shadow\n")
+    if ob.pov.no_image:
+        File.write("\tno_image\n")
+    if ob.pov.no_reflection:
+        File.write("\tno_reflection\n")
+    if ob.pov.no_radiosity:
+        File.write("\tno_radiosity\n")
+    if ob.pov.inverse:
+        File.write("\tinverse\n")
+    if ob.pov.hierarchy:
+        File.write("\thierarchy\n")
+
+    # XXX, Commented definitions
+    '''
+    if scene.pov.photon_enable:
+        File.write("photons {\n")
+        if ob.pov.target:
+            File.write("target %.4g\n"%ob.pov.target_value)
+        if ob.pov.refraction:
+            File.write("refraction on\n")
+        if ob.pov.reflection:
+            File.write("reflection on\n")
+        if ob.pov.pass_through:
+            File.write("pass_through\n")
+        File.write("}\n")
+    if ob.pov.object_ior > 1:
+        File.write("interior {\n")
+        File.write("ior %.4g\n"%ob.pov.object_ior)
+        if scene.pov.photon_enable and ob.pov.target and ob.pov.refraction and ob.pov.dispersion:
+            File.write("ior %.4g\n"%ob.pov.dispersion_value)
+            File.write("ior %s\n"%ob.pov.dispersion_samples)
+        if scene.pov.photon_enable == False:
+            File.write("caustics %.4g\n"%ob.pov.fake_caustics_power)
+    '''
+
+
 def pov_define_mesh(mesh, verts, edges, faces, name, hide_geometry=True):
     """Generate proxy mesh."""
     if mesh is None:
@@ -83,7 +143,9 @@ class POVRAY_OT_lathe_add(Operator):
         ob_data.dimensions = '2D'
         ob_data.transform(Matrix.Rotation(-pi / 2.0, 4, 'Z'))
         ob.pov.object_as = 'LATHE'
-        self.report({'INFO'}, "This native POV-Ray primitive")
+        self.report(
+            {'INFO'}, "This native POV-Ray primitive" "won't have any vertex to show in edit mode"
+        )
         ob.pov.curveshape = "lathe"
         bpy.ops.object.modifier_add(type='SCREW')
         mod = ob.modifiers[-1]
@@ -194,7 +256,7 @@ def pov_superellipsoid_define(context, op, ob):
     mesh = pov_define_mesh(mesh, verts, [], faces, "SuperEllipsoid")
 
     if not ob:
-        ob = object_utils.object_data_add(context, mesh, operator=None)
+        ob = object_data_add(context, mesh, operator=None)
         # engine = context.scene.render.engine what for?
         ob = context.object
         ob.name = ob.data.name = "PovSuperellipsoid"
@@ -222,29 +284,18 @@ class POVRAY_OT_superellipsoid_add(Operator):
     bl_options = {'REGISTER', 'UNDO'}
     COMPAT_ENGINES = {'POVRAY_RENDER'}
 
-    # XXX Keep it in sync with __init__'s RenderPovSettingsConePrimitive
+    # Keep in sync within object_properties.py section Superellipsoid
+    # as this allows interactive update
     #     If someone knows how to define operators' props from a func, I'd be delighted to learn it!
-    se_param1: FloatProperty(
-        name="Parameter 1", description="", min=0.00, max=10.0, default=0.04
-    )
+    se_param1: FloatProperty(name="Parameter 1", description="", min=0.00, max=10.0, default=0.04)
 
-    se_param2: FloatProperty(
-        name="Parameter 2", description="", min=0.00, max=10.0, default=0.04
-    )
+    se_param2: FloatProperty(name="Parameter 2", description="", min=0.00, max=10.0, default=0.04)
 
     se_u: IntProperty(
-        name="U-segments",
-        description="radial segmentation",
-        default=20,
-        min=4,
-        max=265,
+        name="U-segments", description="radial segmentation", default=20, min=4, max=265
     )
     se_v: IntProperty(
-        name="V-segments",
-        description="lateral segmentation",
-        default=20,
-        min=4,
-        max=265,
+        name="V-segments", description="lateral segmentation", default=20, min=4, max=265
     )
     se_n1: FloatProperty(
         name="Ring manipulator",
@@ -261,11 +312,7 @@ class POVRAY_OT_superellipsoid_add(Operator):
         max=100.0,
     )
     se_edit: EnumProperty(
-        items=[
-            ("NOTHING", "Nothing", ""),
-            ("NGONS", "N-Gons", ""),
-            ("TRIANGLES", "Triangles", ""),
-        ],
+        items=[("NOTHING", "Nothing", ""), ("NGONS", "N-Gons", ""), ("TRIANGLES", "Triangles", "")],
         name="Fill up and down",
         description="",
         default='TRIANGLES',
@@ -280,8 +327,7 @@ class POVRAY_OT_superellipsoid_add(Operator):
         pov_superellipsoid_define(context, self, None)
 
         self.report(
-            {'INFO'},
-            "This native POV-Ray primitive won't have any vertex to show in edit mode",
+            {'INFO'}, "This native POV-Ray primitive" "won't have any vertex to show in edit mode"
         )
 
         return {'FINISHED'}
@@ -303,12 +349,7 @@ class POVRAY_OT_superellipsoid_update(Operator):
     def poll(cls, context):
         engine = context.scene.render.engine
         ob = context.object
-        return (
-            ob
-            and ob.data
-            and ob.type == 'MESH'
-            and engine in cls.COMPAT_ENGINES
-        )
+        return ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES
 
     def execute(self, context):
         bpy.ops.object.mode_set(mode="EDIT")
@@ -322,60 +363,52 @@ class POVRAY_OT_superellipsoid_update(Operator):
         return {'FINISHED'}
 
 
-def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
+def create_faces(vert_idx_1, vert_idx_2, closed=False, flipped=False):
+    """Generate viewport proxy mesh data for some pov primitives"""
     faces = []
-    if not vertIdx1 or not vertIdx2:
+    if not vert_idx_1 or not vert_idx_2:
         return None
-    if len(vertIdx1) < 2 and len(vertIdx2) < 2:
+    if len(vert_idx_1) < 2 and len(vert_idx_2) < 2:
         return None
     fan = False
-    if len(vertIdx1) != len(vertIdx2):
-        if len(vertIdx1) == 1 and len(vertIdx2) > 1:
+    if len(vert_idx_1) != len(vert_idx_2):
+        if len(vert_idx_1) == 1 and len(vert_idx_2) > 1:
             fan = True
         else:
             return None
-    total = len(vertIdx2)
+    total = len(vert_idx_2)
     if closed:
         if flipped:
-            face = [vertIdx1[0], vertIdx2[0], vertIdx2[total - 1]]
+            face = [vert_idx_1[0], vert_idx_2[0], vert_idx_2[total - 1]]
             if not fan:
-                face.append(vertIdx1[total - 1])
+                face.append(vert_idx_1[total - 1])
             faces.append(face)
 
         else:
-            face = [vertIdx2[0], vertIdx1[0]]
+            face = [vert_idx_2[0], vert_idx_1[0]]
             if not fan:
-                face.append(vertIdx1[total - 1])
-            face.append(vertIdx2[total - 1])
+                face.append(vert_idx_1[total - 1])
+            face.append(vert_idx_2[total - 1])
             faces.append(face)
     for num in range(total - 1):
         if flipped:
             if fan:
-                face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]]
+                face = [vert_idx_2[num], vert_idx_1[0], vert_idx_2[num + 1]]
             else:
-                face = [
-                    vertIdx2[num],
-                    vertIdx1[num],
-                    vertIdx1[num + 1],
-                    vertIdx2[num + 1],
-                ]
+                face = [vert_idx_2[num], vert_idx_1[num], vert_idx_1[num + 1], vert_idx_2[num + 1]]
             faces.append(face)
         else:
             if fan:
-                face = [vertIdx1[0], vertIdx2[num], vertIdx2[num + 1]]
+                face = [vert_idx_1[0], vert_idx_2[num], vert_idx_2[num + 1]]
             else:
-                face = [
-                    vertIdx1[num],
-                    vertIdx2[num],
-                    vertIdx2[num + 1],
-                    vertIdx1[num + 1],
-                ]
+                face = [vert_idx_1[num], vert_idx_2[num], vert_idx_2[num + 1], vert_idx_1[num + 1]]
             faces.append(face)
 
     return faces
 
 
 def power(a, b):
+    """Workaround to negative a, where the math.pow() method would return a ValueError."""
     if a < 0:
         return -((-a) ** b)
     return a ** b
@@ -392,22 +425,17 @@ def supertoroid(R, r, u, v, n1, n2):
         for j in range(v):
             c2 = R + r * power(cos(j * b), n2)
             s2 = r * power(sin(j * b), n2)
-            verts.append(
-                (c * c2, s * c2, s2)
-            )  # type as a (mathutils.Vector(c*c2,s*c2,s2))?
+            verts.append((c * c2, s * c2, s2))  # type as a (mathutils.Vector(c*c2,s*c2,s2))?
         if i > 0:
-            f = createFaces(
-                range((i - 1) * v, i * v),
-                range(i * v, (i + 1) * v),
-                closed=True,
-            )
+            f = create_faces(range((i - 1) * v, i * v), range(i * v, (i + 1) * v), closed=True)
             faces.extend(f)
-    f = createFaces(range((u - 1) * v, u * v), range(v), closed=True)
+    f = create_faces(range((u - 1) * v, u * v), range(v), closed=True)
     faces.extend(f)
     return verts, faces
 
 
 def pov_supertorus_define(context, op, ob):
+    """Pick POV supertorus properties either from operator (object creation/import) or data updating """
     if op:
         mesh = None
         st_R = op.st_R
@@ -444,7 +472,7 @@ def pov_supertorus_define(context, op, ob):
     verts, faces = supertoroid(rad1, rad2, st_u, st_v, st_n1, st_n2)
     mesh = pov_define_mesh(mesh, verts, [], faces, "PovSuperTorus", True)
     if not ob:
-        ob = object_utils.object_data_add(context, mesh, operator=None)
+        ob = object_data_add(context, mesh, operator=None)
         ob.pov.object_as = 'SUPERTORUS'
         ob.pov.st_major_radius = st_R
         ob.pov.st_minor_radius = st_r
@@ -473,25 +501,13 @@ class POVRAY_OT_supertorus_add(Operator):
         max=100.0,
     )
     st_r: FloatProperty(
-        name="small radius",
-        description="The radius of the tube",
-        default=0.3,
-        min=0.01,
-        max=100.0,
+        name="small radius", description="The radius of the tube", default=0.3, min=0.01, max=100.0
     )
     st_u: IntProperty(
-        name="U-segments",
-        description="radial segmentation",
-        default=16,
-        min=3,
-        max=265,
+        name="U-segments", description="radial segmentation", default=16, min=3, max=265
     )
     st_v: IntProperty(
-        name="V-segments",
-        description="lateral segmentation",
-        default=8,
-        min=3,
-        max=265,
+        name="V-segments", description="lateral segmentation", default=8, min=3, max=265
     )
     st_n1: FloatProperty(
         name="Ring manipulator",
@@ -508,13 +524,9 @@ class POVRAY_OT_supertorus_add(Operator):
         max=100.0,
     )
     st_ie: BoolProperty(
-        name="Use Int.+Ext. radii",
-        description="Use internal and external radii",
-        default=False,
-    )
-    st_edit: BoolProperty(
-        name="", description="", default=False, options={'HIDDEN'}
+        name="Use Int.+Ext. radii", description="Use internal and external radii", default=False
     )
+    st_edit: BoolProperty(name="", description="", default=False, options={'HIDDEN'})
 
     @classmethod
     def poll(cls, context):
@@ -525,8 +537,7 @@ class POVRAY_OT_supertorus_add(Operator):
         pov_supertorus_define(context, self, None)
 
         self.report(
-            {'INFO'},
-            "This native POV-Ray primitive won't have any vertex to show in edit mode",
+            {'INFO'}, "This native POV-Ray primitive" "won't have any vertex to show in edit mode"
         )
         return {'FINISHED'}
 
@@ -547,12 +558,7 @@ class POVRAY_OT_supertorus_update(Operator):
     def poll(cls, context):
         engine = context.scene.render.engine
         ob = context.object
-        return (
-            ob
-            and ob.data
-            and ob.type == 'MESH'
-            and engine in cls.COMPAT_ENGINES
-        )
+        return ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES
 
     def execute(self, context):
         bpy.ops.object.mode_set(mode="EDIT")
@@ -577,18 +583,12 @@ class POVRAY_OT_loft_add(Operator):
     COMPAT_ENGINES = {'POVRAY_RENDER'}
 
     loft_n: IntProperty(
-        name="Segments",
-        description="Vertical segments",
-        default=16,
-        min=3,
-        max=720,
+        name="Segments", description="Vertical segments", default=16, min=3, max=720
     )
     loft_rings_bottom: IntProperty(
         name="Bottom", description="Bottom rings", default=5, min=2, max=100
     )
-    loft_rings_side: IntProperty(
-        name="Side", description="Side rings", default=10, min=2, max=100
-    )
+    loft_rings_side: IntProperty(name="Side", description="Side rings", default=10, min=2, max=100)
     loft_thick: FloatProperty(
         name="Thickness",
         description="Manipulates the shape of the Ring",
@@ -596,9 +596,7 @@ class POVRAY_OT_loft_add(Operator):
         min=0.01,
         max=1.0,
     )
-    loft_r: FloatProperty(
-        name="Radius", description="Radius", default=1, min=0.01, max=10
-    )
+    loft_r: FloatProperty(name="Radius", description="Radius", default=1, min=0.01, max=10)
     loft_height: FloatProperty(
         name="Height",
         description="Manipulates the shape of the Ring",
@@ -610,10 +608,10 @@ class POVRAY_OT_loft_add(Operator):
     def execute(self, context):
 
         props = self.properties
-        loftData = bpy.data.curves.new('Loft', type='CURVE')
-        loftData.dimensions = '3D'
-        loftData.resolution_u = 2
-        # loftData.show_normal_face = False # deprecated in 2.8
+        loft_data = bpy.data.curves.new('Loft', type='CURVE')
+        loft_data.dimensions = '3D'
+        loft_data.resolution_u = 2
+        # loft_data.show_normal_face = False # deprecated in 2.8
         n = props.loft_n
         thick = props.loft_thick
         side = props.loft_rings_side
@@ -633,11 +631,11 @@ class POVRAY_OT_loft_add(Operator):
                 coords.append((x, y, z))
                 angle += pi * 2 / n
             r0 += distB
-            nurbs = loftData.splines.new('NURBS')
+            nurbs = loft_data.splines.new('NURBS')
             nurbs.points.add(len(coords) - 1)
-            for i, coord in enumerate(coords):
+            for c, coord in enumerate(coords):
                 x, y, z = coord
-                nurbs.points[i].co = (x, y, z, 1)
+                nurbs.points[c].co = (x, y, z, 1)
             nurbs.use_cyclic_u = True
         for i in range(side):
             z += h / side
@@ -648,11 +646,11 @@ class POVRAY_OT_loft_add(Operator):
                 y = r * sin(angle)
                 coords.append((x, y, z))
                 angle += pi * 2 / n
-            nurbs = loftData.splines.new('NURBS')
+            nurbs = loft_data.splines.new('NURBS')
             nurbs.points.add(len(coords) - 1)
-            for i, coord in enumerate(coords):
+            for c, coord in enumerate(coords):
                 x, y, z = coord
-                nurbs.points[i].co = (x, y, z, 1)
+                nurbs.points[c].co = (x, y, z, 1)
             nurbs.use_cyclic_u = True
         r -= thick
         for i in range(side):
@@ -663,11 +661,11 @@ class POVRAY_OT_loft_add(Operator):
                 y = r * sin(angle)
                 coords.append((x, y, z))
                 angle += pi * 2 / n
-            nurbs = loftData.splines.new('NURBS')
+            nurbs = loft_data.splines.new('NURBS')
             nurbs.points.add(len(coords) - 1)
-            for i, coord in enumerate(coords):
+            for c, coord in enumerate(coords):
                 x, y, z = coord
-                nurbs.points[i].co = (x, y, z, 1)
+                nurbs.points[c].co = (x, y, z, 1)
             nurbs.use_cyclic_u = True
             z -= h / side
         z = (-h / 2) + thick
@@ -681,13 +679,13 @@ class POVRAY_OT_loft_add(Operator):
                 coords.append((x, y, z))
                 angle += pi * 2 / n
             r -= distB
-            nurbs = loftData.splines.new('NURBS')
+            nurbs = loft_data.splines.new('NURBS')
             nurbs.points.add(len(coords) - 1)
-            for i, coord in enumerate(coords):
+            for c, coord in enumerate(coords):
                 x, y, z = coord
-                nurbs.points[i].co = (x, y, z, 1)
+                nurbs.points[c].co = (x, y, z, 1)
             nurbs.use_cyclic_u = True
-        ob = bpy.data.objects.new('Loft_shape', loftData)
+        ob = bpy.data.objects.new('Loft_shape', loft_data)
         scn = bpy.context.scene
         scn.collection.objects.link(ob)
         context.view_layer.objects.active = ob
@@ -715,9 +713,7 @@ class POVRAY_OT_plane_add(Operator):
         ob.name = ob.data.name = 'PovInfinitePlane'
         bpy.ops.object.mode_set(mode="EDIT")
         self.report(
-            {'INFO'},
-            "This native POV-Ray primitive "
-            "won't have any vertex to show in edit mode",
+            {'INFO'}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
         )
         bpy.ops.mesh.hide(unselected=False)
         bpy.ops.object.mode_set(mode="OBJECT")
@@ -745,9 +741,7 @@ class POVRAY_OT_box_add(Operator):
         ob.name = ob.data.name = 'PovBox'
         bpy.ops.object.mode_set(mode="EDIT")
         self.report(
-            {'INFO'},
-            "This native POV-Ray primitive "
-            "won't have any vertex to show in edit mode",
+            {'INFO'}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
         )
         bpy.ops.mesh.hide(unselected=False)
         bpy.ops.object.mode_set(mode="OBJECT")
@@ -756,6 +750,7 @@ class POVRAY_OT_box_add(Operator):
 
 
 def pov_cylinder_define(context, op, ob, radius, loc, loc_cap):
+    """Pick POV cylinder properties either from creation operator, import, or data update """
     if op:
         R = op.R
         loc = bpy.context.scene.cursor.location
@@ -784,11 +779,7 @@ def pov_cylinder_define(context, op, ob, radius, loc, loc_cap):
     bpy.ops.mesh.select_all(action='SELECT')
     bpy.ops.mesh.delete(type='VERT')
     bpy.ops.mesh.primitive_cylinder_add(
-        radius=radius,
-        depth=depth,
-        location=loc,
-        rotation=roteuler,
-        end_fill_type='NGON',
+        radius=radius, depth=depth, location=loc, rotation=roteuler, end_fill_type='NGON'
     )  #'NOTHING'
     bpy.ops.transform.translate(value=trans)
 
@@ -807,7 +798,8 @@ class POVRAY_OT_cylinder_add(Operator):
     bl_description = "Add Cylinder"
     bl_options = {'REGISTER', 'UNDO'}
 
-    # XXX Keep it in sync with __init__'s cylinder Primitive
+    # Keep in sync within object_properties.py section Cylinder
+    # as this allows interactive update
     R: FloatProperty(name="Cylinder radius", min=0.00, max=10.0, default=1.0)
 
     imported_cyl_loc: FloatVectorProperty(
@@ -838,8 +830,7 @@ class POVRAY_OT_cylinder_add(Operator):
                 LOC_CAP = props.imported_cyl_loc_cap
             self.report(
                 {'INFO'},
-                "This native POV-Ray primitive "
-                "won't have any vertex to show in edit mode",
+                "This native POV-Ray primitive " "won't have any vertex to show in edit mode",
             )
 
         pov_cylinder_define(context, self, None, self.R, LOC, LOC_CAP)
@@ -906,10 +897,7 @@ def pov_sphere_define(context, op, ob, loc):
         bpy.ops.mesh.select_all(action='SELECT')
         bpy.ops.mesh.delete(type='VERT')
         bpy.ops.mesh.primitive_ico_sphere_add(
-            subdivisions=4,
-            radius=ob.pov.sphere_radius,
-            location=loc,
-            rotation=obrot,
+            subdivisions=4, radius=ob.pov.sphere_radius, location=loc, rotation=obrot
         )
         # bpy.ops.transform.rotate(axis=obrot,orient_type='GLOBAL')
         bpy.ops.transform.resize(value=obscale)
@@ -921,9 +909,7 @@ def pov_sphere_define(context, op, ob, loc):
         # bpy.ops.transform.rotate(axis=obrot,orient_type='GLOBAL')
 
     if not ob:
-        bpy.ops.mesh.primitive_ico_sphere_add(
-            subdivisions=4, radius=R, location=loc
-        )
+        bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=4, radius=R, location=loc)
         ob = context.object
         ob.name = ob.data.name = "PovSphere"
         ob.pov.object_as = "SPHERE"
@@ -943,7 +929,8 @@ class POVRAY_OT_sphere_add(Operator):
     bl_description = "Add Sphere Shape"
     bl_options = {'REGISTER', 'UNDO'}
 
-    # XXX Keep it in sync with __init__'s torus Primitive
+    # Keep in sync within object_properties.py section Sphere
+    # as this allows interactive update
     R: FloatProperty(name="Sphere radius", min=0.00, max=10.0, default=0.5)
 
     imported_loc: FloatVectorProperty(
@@ -966,8 +953,7 @@ class POVRAY_OT_sphere_add(Operator):
                 LOC = props.imported_loc
                 self.report(
                     {'INFO'},
-                    "This native POV-Ray primitive "
-                    "won't have any vertex to show in edit mode",
+                    "This native POV-Ray primitive " "won't have any vertex to show in edit mode",
                 )
         pov_sphere_define(context, self, None, LOC)
 
@@ -1006,18 +992,11 @@ class POVRAY_OT_sphere_update(Operator):
     def poll(cls, context):
         engine = context.scene.render.engine
         ob = context.object
-        return (
-            ob
-            and ob.data
-            and ob.type == 'MESH'
-            and engine in cls.COMPAT_ENGINES
-        )
+        return ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES
 
     def execute(self, context):
 
-        pov_sphere_define(
-            context, None, context.object, context.object.location
-        )
+        pov_sphere_define(context, None, context.object, context.object.location)
 
         return {'FINISHED'}
 
@@ -1076,7 +1055,7 @@ def pov_cone_define(context, op, ob):
 
     mesh = pov_define_mesh(mesh, verts, [], faces, "PovCone", True)
     if not ob:
-        ob = object_utils.object_data_add(context, mesh, operator=None)
+        ob = object_data_add(context, mesh, operator=None)
         ob.pov.object_as = "CONE"
         ob.pov.cone_base_radius = base
         ob.pov.cone_cap_radius = cap
@@ -1094,7 +1073,7 @@ class POVRAY_OT_cone_add(Operator):
     bl_options = {'REGISTER', 'UNDO'}
     COMPAT_ENGINES = {'POVRAY_RENDER'}
 
-    # XXX Keep it in sync with __init__.py's RenderPovSettingsConePrimitive
+    # Keep in sync within object_properties.py section Cone
     #     If someone knows how to define operators' props from a func, I'd be delighted to learn it!
     base: FloatProperty(
         name="Base radius",
@@ -1118,11 +1097,7 @@ class POVRAY_OT_cone_add(Operator):
         max=265,
     )
     height: FloatProperty(
-        name="Height",
-        description="Height of the cone",
-        default=2.0,
-        min=0.01,
-        max=100.0,
+        name="Height", description="Height of the cone", default=2.0, min=0.01, max=100.0
     )
 
     @classmethod
@@ -1134,8 +1109,7 @@ class POVRAY_OT_cone_add(Operator):
         pov_cone_define(context, self, None)
 
         self.report(
-            {'INFO'},
-            "This native POV-Ray primitive won't have any vertex to show in edit mode",
+            {'INFO'}, "This native POV-Ray primitive" "won't have any vertex to show in edit mode"
         )
         return {'FINISHED'}
 
@@ -1156,12 +1130,7 @@ class POVRAY_OT_cone_update(Operator):
     def poll(cls, context):
         engine = context.scene.render.engine
         ob = context.object
-        return (
-            ob
-            and ob.data
-            and ob.type == 'MESH'
-            and engine in cls.COMPAT_ENGINES
-        )
+        return ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES
 
     def execute(self, context):
         bpy.ops.object.mode_set(mode="EDIT")
@@ -1196,9 +1165,7 @@ class POVRAY_OT_isosurface_box_add(Operator):
         ob = context.object
         bpy.ops.object.mode_set(mode="EDIT")
         self.report(
-            {'INFO'},
-            "This native POV-Ray primitive "
-            "won't have any vertex to show in edit mode",
+            {'INFO'}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
         )
         bpy.ops.mesh.hide(unselected=False)
         bpy.ops.object.mode_set(mode="OBJECT")
@@ -1226,9 +1193,7 @@ class POVRAY_OT_isosurface_sphere_add(Operator):
         ob = context.object
         bpy.ops.object.mode_set(mode="EDIT")
         self.report(
-            {'INFO'},
-            "This native POV-Ray primitive "
-            "won't have any vertex to show in edit mode",
+            {'INFO'}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
         )
         bpy.ops.mesh.hide(unselected=False)
         bpy.ops.object.mode_set(mode="OBJECT")
@@ -1338,39 +1303,29 @@ class POVRAY_OT_height_field_add(bpy.types.Operator, ImportHelper):
     bl_description = "Add Height Field"
     bl_options = {'REGISTER', 'UNDO'}
 
-    # XXX Keep it in sync with __init__'s hf Primitive
+    # Keep in sync within object_properties.py section HeightFields
+    # as this allows interactive update
+
     # filename_ext = ".png"
 
     # filter_glob = StringProperty(
     # default="*.exr;*.gif;*.hdr;*.iff;*.jpeg;*.jpg;*.pgm;*.png;*.pot;*.ppm;*.sys;*.tga;*.tiff;*.EXR;*.GIF;*.HDR;*.IFF;*.JPEG;*.JPG;*.PGM;*.PNG;*.POT;*.PPM;*.SYS;*.TGA;*.TIFF",
     # options={'HIDDEN'},
     # )
-    quality: IntProperty(
-        name="Quality", description="", default=100, min=1, max=100
-    )
+    quality: IntProperty(name="Quality", description="", default=100, min=1, max=100)
     hf_filename: StringProperty(maxlen=1024)
 
-    hf_gamma: FloatProperty(
-        name="Gamma", description="Gamma", min=0.0001, max=20.0, default=1.0
-    )
+    hf_gamma: FloatProperty(name="Gamma", description="Gamma", min=0.0001, max=20.0, default=1.0)
 
-    hf_premultiplied: BoolProperty(
-        name="Premultiplied", description="Premultiplied", default=True
-    )
+    hf_premultiplied: BoolProperty(name="Premultiplied", description="Premultiplied", default=True)
 
     hf_smooth: BoolProperty(name="Smooth", description="Smooth", default=False)
 
     hf_water: FloatProperty(
-        name="Water Level",
-        description="Wather Level",
-        min=0.00,
-        max=1.00,
-        default=0.0,
+        name="Water Level", description="Wather Level", min=0.00, max=1.00, default=0.0
     )
 
-    hf_hierarchy: BoolProperty(
-        name="Hierarchy", description="Height field hierarchy", default=True
-    )
+    hf_hierarchy: BoolProperty(name="Hierarchy", description="Height field hierarchy", default=True)
 
     def execute(self, context):
         props = self.properties
@@ -1390,9 +1345,7 @@ class POVRAY_OT_height_field_add(bpy.types.Operator, ImportHelper):
         w, h = hf_tex.image.size[:]
         w = int(w / res)
         h = int(h / res)
-        bpy.ops.mesh.primitive_grid_add(
-            x_subdivisions=w, y_subdivisions=h, size=0.5
-        )
+        bpy.ops.mesh.primitive_grid_add(x_subdivisions=w, y_subdivisions=h, size=0.5)
         ob = context.object
         ob.name = ob.data.name = '%s' % im_name
         ob.data.materials.append(mat)
@@ -1409,7 +1362,9 @@ class POVRAY_OT_height_field_add(bpy.types.Operator, ImportHelper):
         bpy.ops.mesh.hide(unselected=False)
         bpy.ops.object.mode_set(mode="OBJECT")
         ob.pov.object_as = 'HEIGHT_FIELD'
-        ob.pov.hf_filename = impath
+        # POV-Ray will soon use only forwards slashes on every OS and already can
+        forward_impath = impath.replace(os.sep, '/')
+        ob.pov.hf_filename = forward_impath
         return {'FINISHED'}
 
 
@@ -1417,6 +1372,7 @@ class POVRAY_OT_height_field_add(bpy.types.Operator, ImportHelper):
 def pov_torus_define(context, op, ob):
     """Add the representation of POV torus using just a Blender torus.
 
+    Picking properties either from creation operator, import, or data update.
     But flag its primitive type with a specific pov.object_as attribute and lock edit mode
     to keep proxy consistency by hiding edit geometry."""
 
@@ -1454,10 +1410,7 @@ def pov_torus_define(context, op, ob):
 
     if not ob:
         bpy.ops.mesh.primitive_torus_add(
-            major_segments=mas,
-            minor_segments=mis,
-            major_radius=mar,
-            minor_radius=mir,
+            major_segments=mas, minor_segments=mis, major_radius=mar, minor_radius=mir
         )
         ob = context.object
         ob.name = ob.data.name = "PovTorus"
@@ -1479,13 +1432,10 @@ class POVRAY_OT_torus_add(Operator):
     bl_description = "Add Torus"
     bl_options = {'REGISTER', 'UNDO'}
 
-    # XXX Keep it in sync with __init__'s torus Primitive
-    mas: IntProperty(
-        name="Major Segments", description="", default=48, min=3, max=720
-    )
-    mis: IntProperty(
-        name="Minor Segments", description="", default=12, min=3, max=720
-    )
+    # Keep in sync within object_properties.py section Torus
+    # as this allows interactive update
+    mas: IntProperty(name="Major Segments", description="", default=48, min=3, max=720)
+    mis: IntProperty(name="Minor Segments", description="", default=12, min=3, max=720)
     mar: FloatProperty(name="Major Radius", description="", default=1.0)
     mir: FloatProperty(name="Minor Radius", description="", default=0.25)
 
@@ -1497,9 +1447,7 @@ class POVRAY_OT_torus_add(Operator):
         mis = props.mis
         pov_torus_define(context, self, None)
         self.report(
-            {'INFO'},
-            "This native POV-Ray primitive "
-            "won't have any vertex to show in edit mode",
+            {'INFO'}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
         )
         return {'FINISHED'}
 
@@ -1520,12 +1468,7 @@ class POVRAY_OT_torus_update(Operator):
     def poll(cls, context):
         engine = context.scene.render.engine
         ob = context.object
-        return (
-            ob
-            and ob.data
-            and ob.type == 'MESH'
-            and engine in cls.COMPAT_ENGINES
-        )
+        return ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES
 
     def execute(self, context):
 
@@ -1545,19 +1488,17 @@ class POVRAY_OT_prism_add(Operator):
     bl_description = "Create Prism"
     bl_options = {'REGISTER', 'UNDO'}
 
-    prism_n: IntProperty(
-        name="Sides", description="Number of sides", default=5, min=3, max=720
-    )
+    prism_n: IntProperty(name="Sides", description="Number of sides", default=5, min=3, max=720)
     prism_r: FloatProperty(name="Radius", description="Radius", default=1.0)
 
     def execute(self, context):
 
         props = self.properties
-        loftData = bpy.data.curves.new('Prism', type='CURVE')
-        loftData.dimensions = '2D'
-        loftData.resolution_u = 2
-        # loftData.show_normal_face = False
-        loftData.extrude = 2
+        loft_data = bpy.data.curves.new('Prism', type='CURVE')
+        loft_data.dimensions = '2D'
+        loft_data.resolution_u = 2
+        # loft_data.show_normal_face = False
+        loft_data.extrude = 2
         n = props.prism_n
         r = props.prism_r
         coords = []
@@ -1568,14 +1509,14 @@ class POVRAY_OT_prism_add(Operator):
             y = r * sin(angle)
             coords.append((x, y, z))
             angle += pi * 2 / n
-        poly = loftData.splines.new('POLY')
+        poly = loft_data.splines.new('POLY')
         poly.points.add(len(coords) - 1)
         for i, coord in enumerate(coords):
             x, y, z = coord
             poly.points[i].co = (x, y, z, 1)
         poly.use_cyclic_u = True
 
-        ob = bpy.data.objects.new('Prism_shape', loftData)
+        ob = bpy.data.objects.new('Prism_shape', loft_data)
         scn = bpy.context.scene
         scn.collection.objects.link(ob)
         context.view_layer.objects.active = ob
@@ -1587,8 +1528,11 @@ class POVRAY_OT_prism_add(Operator):
 
 ##############################PARAMETRIC######################################
 def pov_parametric_define(context, op, ob):
-    """Add the representation of POV parametric surfaces by math surface from add mesh extra objects addon."""
+    """Add the representation of POV parametric surfaces by math surface from add mesh extra objects addon.
 
+    Picking properties either from creation operator, import, or data update.
+    But flag its primitive type with a specific pov.object_as attribute and lock edit mode
+    to keep proxy consistency by hiding edit geometry."""
     if op:
         u_min = op.u_min
         u_max = op.u_max
@@ -1631,7 +1575,10 @@ def pov_parametric_define(context, op, ob):
         bpy.ops.mesh.select_all(action='SELECT')
         # extra work:
         bpy.ops.transform.translate(value=(obloc - curloc), proportional_size=1)
-        bpy.ops.transform.rotate(axis=obrot, proportional_size=1)
+        # XXX TODO : https://devtalk.blender.org/t/bpy-ops-transform-rotate-option-axis/6235/7
+        # to complete necessary extra work rotation, after updating from blender version > 2.92
+        # update and uncomment below, but simple axis deprecated since 2.8
+        # bpy.ops.transform.rotate(axis=obrot, proportional_size=1)
 
         bpy.ops.mesh.hide(unselected=False)
         bpy.ops.object.mode_set(mode="OBJECT")
@@ -1671,7 +1618,8 @@ class POVRAY_OT_parametric_add(Operator):
     bl_description = "Add Paramertic"
     bl_options = {'REGISTER', 'UNDO'}
 
-    # XXX Keep it in sync with __init__'s Parametric primitive
+    # Keep in sync within object_properties.py section Parametric primitive
+    # as this allows interactive update
     u_min: FloatProperty(name="U Min", description="", default=0.0)
     v_min: FloatProperty(name="V Min", description="", default=0.0)
     u_max: FloatProperty(name="U Max", description="", default=6.28)
@@ -1692,9 +1640,7 @@ class POVRAY_OT_parametric_add(Operator):
 
         pov_parametric_define(context, self, None)
         self.report(
-            {'INFO'},
-            "This native POV-Ray primitive "
-            "won't have any vertex to show in edit mode",
+            {'INFO'}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
         )
         return {'FINISHED'}
 
@@ -1715,12 +1661,7 @@ class POVRAY_OT_parametric_update(Operator):
     def poll(cls, context):
         engine = context.scene.render.engine
         ob = context.object
-        return (
-            ob
-            and ob.data
-            and ob.type == 'MESH'
-            and engine in cls.COMPAT_ENGINES
-        )
+        return ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES
 
     def execute(self, context):
 
@@ -1741,19 +1682,14 @@ class POVRAY_OT_shape_polygon_to_circle_add(Operator):
     bl_options = {'REGISTER', 'UNDO'}
     COMPAT_ENGINES = {'POVRAY_RENDER'}
 
-    # XXX Keep it in sync with __init__'s polytocircle properties
+    # Keep in sync within object_properties.py section PolygonToCircle properties
+    # as this allows interactive update
     polytocircle_resolution: IntProperty(
         name="Resolution", description="", default=3, min=0, max=256
     )
-    polytocircle_ngon: IntProperty(
-        name="NGon", description="", min=3, max=64, default=5
-    )
-    polytocircle_ngonR: FloatProperty(
-        name="NGon Radius", description="", default=0.3
-    )
-    polytocircle_circleR: FloatProperty(
-        name="Circle Radius", description="", default=1.0
-    )
+    polytocircle_ngon: IntProperty(name="NGon", description="", min=3, max=64, default=5)
+    polytocircle_ngonR: FloatProperty(name="NGon Radius", description="", default=0.3)
+    polytocircle_circleR: FloatProperty(name="Circle Radius", description="", default=1.0)
 
     def execute(self, context):
         props = self.properties
@@ -1771,10 +1707,7 @@ class POVRAY_OT_shape_polygon_to_circle_add(Operator):
         numCircleVerts = ngon + (ngon * resolution)
         bpy.ops.mesh.select_all(action='DESELECT')
         bpy.ops.mesh.primitive_circle_add(
-            vertices=numCircleVerts,
-            radius=circleR,
-            fill_type='NGON',
-            enter_editmode=True,
+            vertices=numCircleVerts, radius=circleR, fill_type='NGON', enter_editmode=True
         )
         bpy.ops.transform.translate(value=(0, 0, -1))
         bpy.ops.mesh.select_all(action='SELECT')
@@ -1782,10 +1715,7 @@ class POVRAY_OT_shape_polygon_to_circle_add(Operator):
         if ngon < 5:
             bpy.ops.mesh.select_all(action='DESELECT')
             bpy.ops.mesh.primitive_circle_add(
-                vertices=ngon,
-                radius=ngonR,
-                fill_type='TRIFAN',
-                enter_editmode=True,
+                vertices=ngon, radius=ngonR, fill_type='TRIFAN', enter_editmode=True
             )
             bpy.ops.transform.translate(value=(0, 0, 1))
             bpy.ops.mesh.select_all(action='SELECT')
@@ -1803,547 +1733,6 @@ class POVRAY_OT_shape_polygon_to_circle_add(Operator):
         return {'FINISHED'}
 
 
-#############################IMPORT
-
-
-class ImportPOV(bpy.types.Operator, ImportHelper):
-    """Load Povray files"""
-
-    bl_idname = "import_scene.pov"
-    bl_label = "POV-Ray files (.pov/.inc)"
-    bl_options = {'PRESET', 'UNDO'}
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    # -----------
-    # File props.
-    files: CollectionProperty(
-        type=bpy.types.OperatorFileListElement, options={'HIDDEN', 'SKIP_SAVE'}
-    )
-    directory: StringProperty(
-        maxlen=1024, subtype='FILE_PATH', options={'HIDDEN', 'SKIP_SAVE'}
-    )
-
-    filename_ext = {".pov", ".inc"}
-    filter_glob: StringProperty(default="*.pov;*.inc", options={'HIDDEN'})
-
-    import_at_cur: BoolProperty(
-        name="Import at Cursor Location",
-        description="Ignore Object Matrix",
-        default=False,
-    )
-
-    def execute(self, context):
-        from mathutils import Matrix
-
-        verts = []
-        faces = []
-        materials = []
-        blendMats = []  ##############
-        povMats = []  ##############
-        colors = []
-        matNames = []
-        lenverts = None
-        lenfaces = None
-        suffix = -1
-        name = 'Mesh2_%s' % suffix
-        name_search = False
-        verts_search = False
-        faces_search = False
-        plane_search = False
-        box_search = False
-        cylinder_search = False
-        sphere_search = False
-        cone_search = False
-        tex_search = False  ##################
-        cache = []
-        matrixes = {}
-        writematrix = False
-        index = None
-        value = None
-        # filepov = bpy.path.abspath(self.filepath) #was used for single files
-
-        def mat_search(cache):
-            r = g = b = 0.5
-            f = t = 0
-            color = None
-
-            for item, value in enumerate(cache):
-
-                if value == 'texture':
-                    pass
-
-                if value == 'pigment':
-
-                    if cache[item + 2] in {'rgb', 'srgb'}:
-                        pass
-
-                    elif cache[item + 2] in {'rgbf', 'srgbf'}:
-                        pass
-
-                    elif cache[item + 2] in {'rgbt', 'srgbt'}:
-                        try:
-                            r, g, b, t = (
-                                float(cache[item + 3]),
-                                float(cache[item + 4]),
-                                float(cache[item + 5]),
-                                float(cache[item + 6]),
-                            )
-                        except:
-                            r = g = b = t = float(cache[item + 2])
-                        color = (r, g, b, t)
-
-                    elif cache[item + 2] in {'rgbft', 'srgbft'}:
-                        pass
-
-                    else:
-                        pass
-
-            if colors == [] or (colors != [] and color not in colors):
-                colors.append(color)
-                name = ob.name + "_mat"
-                matNames.append(name)
-                mat = bpy.data.materials.new(name)
-                mat.diffuse_color = (r, g, b)
-                mat.alpha = 1 - t
-                if mat.alpha != 1:
-                    mat.use_transparency = True
-                ob.data.materials.append(mat)
-
-            else:
-                for i, value in enumerate(colors):
-                    if color == value:
-                        ob.data.materials.append(
-                            bpy.data.materials[matNames[i]]
-                        )
-
-        for file in self.files:
-            print("Importing file: " + file.name)
-            filepov = self.directory + file.name
-            for line in open(filepov):
-                string = line.replace("{", " ")
-                string = string.replace("}", " ")
-                string = string.replace("<", " ")
-                string = string.replace(">", " ")
-                string = string.replace(",", " ")
-                lw = string.split()
-                lenwords = len(lw)
-                if lw:
-                    if lw[0] == "object":
-                        writematrix = True
-                    if writematrix:
-                        if lw[0] not in {"object", "matrix"}:
-                            index = lw[0]
-                        if lw[0] in {"matrix"}:
-                            value = [
-                                float(lw[1]),
-                                float(lw[2]),
-                                float(lw[3]),
-                                float(lw[4]),
-                                float(lw[5]),
-                                float(lw[6]),
-                                float(lw[7]),
-                                float(lw[8]),
-                                float(lw[9]),
-                                float(lw[10]),
-                                float(lw[11]),
-                                float(lw[12]),
-                            ]
-                            matrixes[index] = value
-                            writematrix = False
-            for line in open(filepov):
-                S = line.replace("{", " { ")
-                S = S.replace("}", " } ")
-                S = S.replace(",", " ")
-                S = S.replace("<", "")
-                S = S.replace(">", " ")
-                S = S.replace("=", " = ")
-                S = S.replace(";", " ; ")
-                S = S.split()
-                lenS = len(S)
-                for i, word in enumerate(S):
-                    ##################Primitives Import##################
-                    if word == 'cone':
-                        cone_search = True
-                        name_search = False
-                    if cone_search:
-                        cache.append(word)
-                        if cache[-1] == '}':
-                            try:
-                                x0 = float(cache[2])
-                                y0 = float(cache[3])
-                                z0 = float(cache[4])
-                                r0 = float(cache[5])
-                                x1 = float(cache[6])
-                                y1 = float(cache[7])
-                                z1 = float(cache[8])
-                                r1 = float(cache[9])
-                                # Y is height in most pov files, not z
-                                bpy.ops.pov.cone_add(
-                                    base=r0, cap=r1, height=(y1 - y0)
-                                )
-                                ob = context.object
-                                ob.location = (x0, y0, z0)
-                                # ob.scale = (r,r,r)
-                                mat_search(cache)
-                            except (ValueError):
-                                pass
-                            cache = []
-                            cone_search = False
-                    if word == 'plane':
-                        plane_search = True
-                        name_search = False
-                    if plane_search:
-                        cache.append(word)
-                        if cache[-1] == '}':
-                            try:
-                                bpy.ops.pov.addplane()
-                                ob = context.object
-                                mat_search(cache)
-                            except (ValueError):
-                                pass
-                            cache = []
-                            plane_search = False
-                    if word == 'box':
-                        box_search = True
-                        name_search = False
-                    if box_search:
-                        cache.append(word)
-                        if cache[-1] == '}':
-                            try:
-                                x0 = float(cache[2])
-                                y0 = float(cache[3])
-                                z0 = float(cache[4])
-                                x1 = float(cache[5])
-                                y1 = float(cache[6])
-                                z1 = float(cache[7])
-                                # imported_corner_1=(x0, y0, z0)
-                                # imported_corner_2 =(x1, y1, z1)
-                                center = (
-                                    (x0 + x1) / 2,
-                                    (y0 + y1) / 2,
-                                    (z0 + z1) / 2,
-                                )
-                                bpy.ops.pov.addbox()
-                                ob = context.object
-                                ob.location = center
-                                mat_search(cache)
-
-                            except (ValueError):
-                                pass
-                            cache = []
-                            box_search = False
-                    if word == 'cylinder':
-                        cylinder_search = True
-                        name_search = False
-                    if cylinder_search:
-                        cache.append(word)
-                        if cache[-1] == '}':
-                            try:
-                                x0 = float(cache[2])
-                                y0 = float(cache[3])
-                                z0 = float(cache[4])
-                                x1 = float(cache[5])
-                                y1 = float(cache[6])
-                                z1 = float(cache[7])
-                                imported_cyl_loc = (x0, y0, z0)
-                                imported_cyl_loc_cap = (x1, y1, z1)
-
-                                r = float(cache[8])
-
-                                vec = Vector(imported_cyl_loc_cap) - Vector(
-                                    imported_cyl_loc
-                                )
-                                depth = vec.length
-                                rot = Vector((0, 0, 1)).rotation_difference(
-                                    vec
-                                )  # Rotation from Z axis.
-                                trans = rot @ Vector(
-                                    (0, 0, depth / 2)
-                                )  # Such that origin is at center of the base of the cylinder.
-                                # center = ((x0 + x1)/2,(y0 + y1)/2,(z0 + z1)/2)
-                                scaleZ = (
-                                    sqrt(
-                                        (x1 - x0) ** 2
-                                        + (y1 - y0) ** 2
-                                        + (z1 - z0) ** 2
-                                    )
-                                    / 2
-                                )
-                                bpy.ops.pov.addcylinder(
-                                    R=r,
-                                    imported_cyl_loc=imported_cyl_loc,
-                                    imported_cyl_loc_cap=imported_cyl_loc_cap,
-                                )
-                                ob = context.object
-                                ob.location = (x0, y0, z0)
-                                ob.rotation_euler = rot.to_euler()
-                                ob.scale = (1, 1, scaleZ)
-
-                                # scale data rather than obj?
-                                # bpy.ops.object.mode_set(mode='EDIT')
-                                # bpy.ops.mesh.reveal()
-                                # bpy.ops.mesh.select_all(action='SELECT')
-                                # bpy.ops.transform.resize(value=(1,1,scaleZ), orient_type='LOCAL')
-                                # bpy.ops.mesh.hide(unselected=False)
-                                # bpy.ops.object.mode_set(mode='OBJECT')
-
-                                mat_search(cache)
-
-                            except (ValueError):
-                                pass
-                            cache = []
-                            cylinder_search = False
-                    if word == 'sphere':
-                        sphere_search = True
-                        name_search = False
-                    if sphere_search:
-                        cache.append(word)
-                        if cache[-1] == '}':
-                            x = y = z = r = 0
-                            try:
-                                x = float(cache[2])
-                                y = float(cache[3])
-                                z = float(cache[4])
-                                r = float(cache[5])
-
-                            except (ValueError):
-                                pass
-                            except:
-                                x = y = z = float(cache[2])
-                                r = float(cache[3])
-                            bpy.ops.pov.addsphere(R=r, imported_loc=(x, y, z))
-                            ob = context.object
-                            ob.location = (x, y, z)
-                            ob.scale = (r, r, r)
-                            mat_search(cache)
-                            cache = []
-                            sphere_search = False
-                    ##################End Primitives Import##################
-                    if word == '#declare':
-                        name_search = True
-                    if name_search:
-                        cache.append(word)
-                        if word == 'mesh2':
-                            name_search = False
-                            if cache[-2] == '=':
-                                name = cache[-3]
-                            else:
-                                suffix += 1
-                            cache = []
-                        if word in {'texture', ';'}:
-                            name_search = False
-                            cache = []
-                    if word == 'vertex_vectors':
-                        verts_search = True
-                    if verts_search:
-                        cache.append(word)
-                        if word == '}':
-                            verts_search = False
-                            lenverts = cache[2]
-                            cache.pop()
-                            cache.pop(0)
-                            cache.pop(0)
-                            cache.pop(0)
-                            for i in range(int(lenverts)):
-                                x = i * 3
-                                y = (i * 3) + 1
-                                z = (i * 3) + 2
-                                verts.append(
-                                    (
-                                        float(cache[x]),
-                                        float(cache[y]),
-                                        float(cache[z]),
-                                    )
-                                )
-                            cache = []
-                    # if word == 'face_indices':
-                    # faces_search = True
-                    if word == 'texture_list':  ########
-                        tex_search = True  #######
-                    if tex_search:  #########
-                        if (
-                            word
-                            not in {
-                                'texture_list',
-                                'texture',
-                                '{',
-                                '}',
-                                'face_indices',
-                            }
-                            and word.isdigit() == False
-                        ):  ##############
-                            povMats.append(word)  #################
-                    if word == 'face_indices':
-                        tex_search = False  ################
-                        faces_search = True
-                    if faces_search:
-                        cache.append(word)
-                        if word == '}':
-                            faces_search = False
-                            lenfaces = cache[2]
-                            cache.pop()
-                            cache.pop(0)
-                            cache.pop(0)
-                            cache.pop(0)
-                            lf = int(lenfaces)
-                            var = int(len(cache) / lf)
-                            for i in range(lf):
-                                if var == 3:
-                                    v0 = i * 3
-                                    v1 = i * 3 + 1
-                                    v2 = i * 3 + 2
-                                    faces.append(
-                                        (
-                                            int(cache[v0]),
-                                            int(cache[v1]),
-                                            int(cache[v2]),
-                                        )
-                                    )
-                                if var == 4:
-                                    v0 = i * 4
-                                    v1 = i * 4 + 1
-                                    v2 = i * 4 + 2
-                                    m = i * 4 + 3
-                                    materials.append((int(cache[m])))
-                                    faces.append(
-                                        (
-                                            int(cache[v0]),
-                                            int(cache[v1]),
-                                            int(cache[v2]),
-                                        )
-                                    )
-                                if var == 6:
-                                    v0 = i * 6
-                                    v1 = i * 6 + 1
-                                    v2 = i * 6 + 2
-                                    m0 = i * 6 + 3
-                                    m1 = i * 6 + 4
-                                    m2 = i * 6 + 5
-                                    materials.append(
-                                        (
-                                            int(cache[m0]),
-                                            int(cache[m1]),
-                                            int(cache[m2]),
-                                        )
-                                    )
-                                    faces.append(
-                                        (
-                                            int(cache[v0]),
-                                            int(cache[v1]),
-                                            int(cache[v2]),
-                                        )
-                                    )
-                            # mesh = pov_define_mesh(None, verts, [], faces, name, hide_geometry=False)
-                            # ob = object_utils.object_data_add(context, mesh, operator=None)
-
-                            me = bpy.data.meshes.new(name)  ########
-                            ob = bpy.data.objects.new(name, me)  ##########
-                            bpy.context.collection.objects.link(ob)  #########
-                            me.from_pydata(verts, [], faces)  ############
-
-                            for mat in bpy.data.materials:  ##############
-                                blendMats.append(mat.name)  #############
-                            for mName in povMats:  #####################
-                                if mName not in blendMats:  ###########
-                                    povMat = bpy.data.materials.new(
-                                        mName
-                                    )  #################
-                                    mat_search(cache)
-                                ob.data.materials.append(
-                                    bpy.data.materials[mName]
-                                )  ###################
-                            if materials:  ##################
-                                for i, val in enumerate(
-                                    materials
-                                ):  ####################
-                                    try:  ###################
-                                        ob.data.polygons[
-                                            i
-                                        ].material_index = (
-                                            val
-                                        )  ####################
-                                    except TypeError:  ###################
-                                        ob.data.polygons[
-                                            i
-                                        ].material_index = int(
-                                            val[0]
-                                        )  ##################
-
-                            blendMats = []  #########################
-                            povMats = []  #########################
-                            materials = []  #########################
-                            cache = []
-                            name_search = True
-                            if name in matrixes and self.import_at_cur == False:
-                                global_matrix = Matrix.Rotation(
-                                    pi / 2.0, 4, 'X'
-                                )
-                                ob = bpy.context.object
-                                matrix = ob.matrix_world
-                                v = matrixes[name]
-                                matrix[0][0] = v[0]
-                                matrix[1][0] = v[1]
-                                matrix[2][0] = v[2]
-                                matrix[0][1] = v[3]
-                                matrix[1][1] = v[4]
-                                matrix[2][1] = v[5]
-                                matrix[0][2] = v[6]
-                                matrix[1][2] = v[7]
-                                matrix[2][2] = v[8]
-                                matrix[0][3] = v[9]
-                                matrix[1][3] = v[10]
-                                matrix[2][3] = v[11]
-                                matrix = global_matrix * ob.matrix_world
-                                ob.matrix_world = matrix
-                            verts = []
-                            faces = []
-
-                    # if word == 'pigment':
-                    # try:
-                    # #all indices have been incremented once to fit a bad test file
-                    # r,g,b,t = float(S[2]),float(S[3]),float(S[4]),float(S[5])
-                    # color = (r,g,b,t)
-
-                    # except (IndexError):
-                    # #all indices have been incremented once to fit alternate test file
-                    # r,g,b,t = float(S[3]),float(S[4]),float(S[5]),float(S[6])
-                    # color = (r,g,b,t)
-                    # except UnboundLocalError:
-                    # # In case no transmit is specified ? put it to 0
-                    # r,g,b,t = float(S[2]),float(S[3]),float(S[4],0)
-                    # color = (r,g,b,t)
-
-                    # except (ValueError):
-                    # color = (0.8,0.8,0.8,0)
-                    # pass
-
-                    # if colors == [] or (colors != [] and color not in colors):
-                    # colors.append(color)
-                    # name = ob.name+"_mat"
-                    # matNames.append(name)
-                    # mat = bpy.data.materials.new(name)
-                    # mat.diffuse_color = (r,g,b)
-                    # mat.alpha = 1-t
-                    # if mat.alpha != 1:
-                    # mat.use_transparency=True
-                    # ob.data.materials.append(mat)
-                    # print (colors)
-                    # else:
-                    # for i in range(len(colors)):
-                    # if color == colors[i]:
-                    # ob.data.materials.append(bpy.data.materials[matNames[i]])
-
-        ##To keep Avogadro Camera angle:
-        # for obj in bpy.context.view_layer.objects:
-        # if obj.type == "CAMERA":
-        # track = obj.constraints.new(type = "TRACK_TO")
-        # track.target = ob
-        # track.track_axis ="TRACK_NEGATIVE_Z"
-        # track.up_axis = "UP_Y"
-        # obj.location = (0,0,0)
-        return {'FINISHED'}
-
-
 classes = (
     POVRAY_OT_lathe_add,
     POVRAY_OT_superellipsoid_add,
@@ -2371,19 +1760,14 @@ classes = (
     POVRAY_OT_parametric_add,
     POVRAY_OT_parametric_update,
     POVRAY_OT_shape_polygon_to_circle_add,
-    ImportPOV,
 )
 
 
 def register():
-    # from bpy.utils import register_class
-
     for cls in classes:
         register_class(cls)
 
 
 def unregister():
-    from bpy.utils import unregister_class
-
     for cls in classes:
         unregister_class(cls)
diff --git a/render_povray/object_properties.py b/render_povray/object_properties.py
new file mode 100755
index 000000000..8cea49af8
--- /dev/null
+++ b/render_povray/object_properties.py
@@ -0,0 +1,670 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+"""Declare object level properties controllable in UI and translated to POV"""
+import bpy
+from bpy.utils import register_class, unregister_class
+from bpy.types import PropertyGroup
+from bpy.props import (
+    BoolProperty,
+    IntProperty,
+    FloatProperty,
+    FloatVectorProperty,
+    StringProperty,
+    EnumProperty,
+    PointerProperty,
+)
+
+
+###############################################################################
+# Object POV properties.
+###############################################################################
+
+
+class RenderPovSettingsObject(PropertyGroup):
+    """Declare object and primitives level properties controllable in UI and translated to POV."""
+
+    # Pov inside_vector used for CSG
+    inside_vector: FloatVectorProperty(
+        name="CSG Inside Vector",
+        description="Direction to shoot CSG inside test rays at",
+        precision=4,
+        step=0.01,
+        min=0,
+        soft_max=1,
+        default=(0.001, 0.001, 0.5),
+        options={"ANIMATABLE"},
+        subtype="XYZ",
+    )
+
+    # Importance sampling
+    importance_value: FloatProperty(
+        name="Radiosity Importance",
+        description="Priority value relative to other objects for sampling radiosity rays. "
+        "Increase to get more radiosity rays at comparatively small yet "
+        "bright objects",
+        min=0.01,
+        max=1.00,
+        default=0.50,
+    )
+
+    # Collect photons
+    collect_photons: BoolProperty(
+        name="Receive Photon Caustics",
+        description="Enable object to collect photons from other objects caustics. Turn "
+        "off for objects that don't really need to receive caustics (e.g. objects"
+        " that generate caustics often don't need to show any on themselves)",
+        default=True,
+    )
+
+    # Photons spacing_multiplier
+    spacing_multiplier: FloatProperty(
+        name="Photons Spacing Multiplier",
+        description="Multiplier value relative to global spacing of photons. "
+        "Decrease by half to get 4x more photons at surface of "
+        "this object (or 8x media photons than specified in the globals",
+        min=0.01,
+        max=1.00,
+        default=1.00,
+    )
+
+    ##################################CustomPOV Code############################
+    # Only DUMMIES below for now:
+    replacement_text: StringProperty(
+        name="Declared name:",
+        description="Type the declared name in custom POV code or an external .inc "
+        "it points at. Any POV shape expected e.g: isosurface {}",
+        default="",
+    )
+
+    #############POV specific object properties.############################
+    object_as: StringProperty(maxlen=1024)
+
+    imported_loc: FloatVectorProperty(
+        name="Imported Pov location", precision=6, default=(0.0, 0.0, 0.0)
+    )
+
+    imported_loc_cap: FloatVectorProperty(
+        name="Imported Pov location", precision=6, default=(0.0, 0.0, 2.0)
+    )
+
+    unlock_parameters: BoolProperty(name="Lock", default=False)
+
+    # not in UI yet but used for sor (lathe) / prism... pov primitives
+    curveshape: EnumProperty(
+        name="Povray Shape Type",
+        items=(
+            ("birail", "Birail", ""),
+            ("cairo", "Cairo", ""),
+            ("lathe", "Lathe", ""),
+            ("loft", "Loft", ""),
+            ("prism", "Prism", ""),
+            ("sphere_sweep", "Sphere Sweep", ""),
+        ),
+        default="sphere_sweep",
+    )
+
+    mesh_write_as: EnumProperty(
+        name="Mesh Write As",
+        items=(("blobgrid", "Blob Grid", ""), ("grid", "Grid", ""), ("mesh", "Mesh", "")),
+        default="mesh",
+    )
+
+    object_ior: FloatProperty(name="IOR", description="IOR", min=1.0, max=10.0, default=1.0)
+
+    # shape_as_light = StringProperty(name="Light",maxlen=1024)
+    # fake_caustics_power = FloatProperty(
+    # name="Power", description="Fake caustics power",
+    # min=0.0, max=10.0,default=0.0)
+    # target = BoolProperty(name="Target",description="",default=False)
+    # target_value = FloatProperty(
+    # name="Value", description="",
+    # min=0.0, max=1.0,default=1.0)
+    # refraction = BoolProperty(name="Refraction",description="",default=False)
+    # dispersion = BoolProperty(name="Dispersion",description="",default=False)
+    # dispersion_value = FloatProperty(
+    # name="Dispersion", description="Good values are 1.01 to 1.1. ",
+    # min=1.0, max=1.2,default=1.01)
+    # dispersion_samples = IntProperty(name="Samples",min=2, max=100,default=7)
+    # reflection = BoolProperty(name="Reflection",description="",default=False)
+    # pass_through = BoolProperty(name="Pass through",description="",default=False)
+    no_shadow: BoolProperty(name="No Shadow", default=False)
+
+    no_image: BoolProperty(name="No Image", default=False)
+
+    no_reflection: BoolProperty(name="No Reflection", default=False)
+
+    no_radiosity: BoolProperty(name="No Radiosity", default=False)
+
+    inverse: BoolProperty(name="Inverse", default=False)
+
+    sturm: BoolProperty(name="Sturm", default=False)
+
+    double_illuminate: BoolProperty(name="Double Illuminate", default=False)
+
+    hierarchy: BoolProperty(name="Hierarchy", default=False)
+
+    hollow: BoolProperty(name="Hollow", default=False)
+
+    boundorclip: EnumProperty(
+        name="Boundorclip",
+        items=(
+            ("none", "None", ""),
+            ("bounded_by", "Bounded_by", ""),
+            ("clipped_by", "Clipped_by", ""),
+        ),
+        default="none",
+    )
+
+    boundorclipob: StringProperty(maxlen=1024)
+
+    addboundorclip: BoolProperty(description="", default=False)
+
+    blob_threshold: FloatProperty(name="Threshold", min=0.00, max=10.0, default=0.6)
+
+    blob_strength: FloatProperty(name="Strength", min=-10.00, max=10.0, default=1.00)
+
+    res_u: IntProperty(name="U", min=100, max=1000, default=500)
+
+    res_v: IntProperty(name="V", min=100, max=1000, default=500)
+
+    contained_by: EnumProperty(
+        name="Contained by", items=(("box", "Box", ""), ("sphere", "Sphere", "")), default="box"
+    )
+
+    container_scale: FloatProperty(name="Container Scale", min=0.0, max=10.0, default=1.00)
+
+    threshold: FloatProperty(name="Threshold", min=0.0, max=10.0, default=0.00)
+
+    accuracy: FloatProperty(name="Accuracy", min=0.0001, max=0.1, default=0.001)
+
+    max_gradient: FloatProperty(name="Max Gradient", min=0.0, max=100.0, default=5.0)
+
+    all_intersections: BoolProperty(name="All Intersections", default=False)
+
+    max_trace: IntProperty(name="Max Trace", min=1, max=100, default=1)
+
+    ###########Cylinder
+    def prop_update_cylinder(self, context):
+        """Update POV cylinder primitive parameters not only at creation but anytime they are changed in UI."""
+        if bpy.ops.pov.cylinder_update.poll():
+            bpy.ops.pov.cylinder_update()
+
+    cylinder_radius: FloatProperty(
+        name="Cylinder R", min=0.00, max=10.0, default=0.04, update=prop_update_cylinder
+    )
+
+    cylinder_location_cap: FloatVectorProperty(
+        name="Cylinder Cap Location",
+        subtype="TRANSLATION",
+        description="The position of the 'other' end of the cylinder (relative to object location)",
+        default=(0.0, 0.0, 2.0),
+        update=prop_update_cylinder,
+    )
+
+    imported_cyl_loc: FloatVectorProperty(
+        name="Imported Pov location", precision=6, default=(0.0, 0.0, 0.0)
+    )
+
+    imported_cyl_loc_cap: FloatVectorProperty(
+        name="Imported Pov location", precision=6, default=(0.0, 0.0, 2.0)
+    )
+
+    ###########Sphere
+    def prop_update_sphere(self, context):
+
+        """Update POV sphere primitive parameters not only at creation but anytime they are changed in UI."""
+
+        bpy.ops.pov.sphere_update()
+
+    sphere_radius: FloatProperty(
+        name="Sphere radius", min=0.00, max=10.0, default=0.5, update=prop_update_sphere
+    )
+
+    ###########Cone
+    def prop_update_cone(self, context):
+
+        """Update POV cone primitive parameters not only at creation but anytime they are changed in UI."""
+
+        bpy.ops.pov.cone_update()
+
+    cone_base_radius: FloatProperty(
+        name="Base radius",
+        description="The first radius of the cone",
+        default=1.0,
+        min=0.01,
+        max=100.0,
+        update=prop_update_cone,
+    )
+
+    cone_cap_radius: FloatProperty(
+        name="Cap radius",
+        description="The second radius of the cone",
+        default=0.3,
+        min=0.0,
+        max=100.0,
+        update=prop_update_cone,
+    )
+
+    cone_segments: IntProperty(
+        name="Segments",
+        description="Radial segmentation of proxy mesh",
+        default=16,
+        min=3,
+        max=265,
+        update=prop_update_cone,
+    )
+
+    cone_height: FloatProperty(
+        name="Height",
+        description="Height of the cone",
+        default=2.0,
+        min=0.01,
+        max=100.0,
+        update=prop_update_cone,
+    )
+
+    cone_base_z: FloatProperty()
+
+    cone_cap_z: FloatProperty()
+
+    ###########Parametric
+    def prop_update_parametric(self, context):
+
+        """Update POV parametric surface primitive parameters not only at creation but anytime they are changed in UI."""
+
+        bpy.ops.pov.parametric_update()
+
+    u_min: FloatProperty(name="U Min", description="", default=0.0, update=prop_update_parametric)
+
+    v_min: FloatProperty(name="V Min", description="", default=0.0, update=prop_update_parametric)
+
+    u_max: FloatProperty(name="U Max", description="", default=6.28, update=prop_update_parametric)
+
+    v_max: FloatProperty(name="V Max", description="", default=12.57, update=prop_update_parametric)
+
+    x_eq: StringProperty(
+        maxlen=1024, default="cos(v)*(1+cos(u))*sin(v/8)", update=prop_update_parametric
+    )
+
+    y_eq: StringProperty(
+        maxlen=1024, default="sin(u)*sin(v/8)+cos(v/8)*1.5", update=prop_update_parametric
+    )
+
+    z_eq: StringProperty(
+        maxlen=1024, default="sin(v)*(1+cos(u))*sin(v/8)", update=prop_update_parametric
+    )
+
+    ###########Torus
+
+    def prop_update_torus(self, context):
+
+        """Update POV torus primitive parameters not only at creation but anytime they are changed in UI."""
+
+        bpy.ops.pov.torus_update()
+
+    torus_major_segments: IntProperty(
+        name="Segments",
+        description="Radial segmentation of proxy mesh",
+        default=48,
+        min=3,
+        max=720,
+        update=prop_update_torus,
+    )
+
+    torus_minor_segments: IntProperty(
+        name="Segments",
+        description="Cross-section segmentation of proxy mesh",
+        default=12,
+        min=3,
+        max=720,
+        update=prop_update_torus,
+    )
+
+    torus_major_radius: FloatProperty(
+        name="Major radius",
+        description="Major radius",
+        min=0.00,
+        max=100.00,
+        default=1.0,
+        update=prop_update_torus,
+    )
+
+    torus_minor_radius: FloatProperty(
+        name="Minor radius",
+        description="Minor radius",
+        min=0.00,
+        max=100.00,
+        default=0.25,
+        update=prop_update_torus,
+    )
+
+    ###########Rainbow
+    arc_angle: FloatProperty(
+        name="Arc angle",
+        description="The angle of the raynbow arc in degrees",
+        default=360,
+        min=0.01,
+        max=360.0,
+    )
+
+    falloff_angle: FloatProperty(
+        name="Falloff angle",
+        description="The angle after which rainbow dissolves into background",
+        default=360,
+        min=0.0,
+        max=360,
+    )
+
+    ###########HeightFields
+
+    quality: IntProperty(name="Quality", description="", default=100, min=1, max=100)
+
+    hf_filename: StringProperty(maxlen=1024)
+
+    hf_gamma: FloatProperty(name="Gamma", description="Gamma", min=0.0001, max=20.0, default=1.0)
+
+    hf_premultiplied: BoolProperty(name="Premultiplied", description="Premultiplied", default=True)
+
+    hf_smooth: BoolProperty(name="Smooth", description="Smooth", default=False)
+
+    hf_water: FloatProperty(
+        name="Water Level", description="Wather Level", min=0.00, max=1.00, default=0.0
+    )
+
+    hf_hierarchy: BoolProperty(name="Hierarchy", description="Height field hierarchy", default=True)
+
+    ##############Superellipsoid
+    def prop_update_superellipsoid(self, context):
+
+        """Update POV superellipsoid primitive parameters not only at creation but anytime they are changed in UI."""
+
+        bpy.ops.pov.superellipsoid_update()
+
+    se_param1: FloatProperty(name="Parameter 1", description="", min=0.00, max=10.0, default=0.04)
+
+    se_param2: FloatProperty(name="Parameter 2", description="", min=0.00, max=10.0, default=0.04)
+
+    se_u: IntProperty(
+        name="U-segments",
+        description="radial segmentation",
+        default=20,
+        min=4,
+        max=265,
+        update=prop_update_superellipsoid,
+    )
+
+    se_v: IntProperty(
+        name="V-segments",
+        description="lateral segmentation",
+        default=20,
+        min=4,
+        max=265,
+        update=prop_update_superellipsoid,
+    )
+
+    se_n1: FloatProperty(
+        name="Ring manipulator",
+        description="Manipulates the shape of the Ring",
+        default=1.0,
+        min=0.01,
+        max=100.0,
+        update=prop_update_superellipsoid,
+    )
+
+    se_n2: FloatProperty(
+        name="Cross manipulator",
+        description="Manipulates the shape of the cross-section",
+        default=1.0,
+        min=0.01,
+        max=100.0,
+        update=prop_update_superellipsoid,
+    )
+
+    se_edit: EnumProperty(
+        items=[("NOTHING", "Nothing", ""), ("NGONS", "N-Gons", ""), ("TRIANGLES", "Triangles", "")],
+        name="Fill up and down",
+        description="",
+        default="TRIANGLES",
+        update=prop_update_superellipsoid,
+    )
+
+    #############Used for loft but also Superellipsoid, etc.
+    curveshape: EnumProperty(
+        name="Povray Shape Type",
+        items=(
+            ("birail", "Birail", ""),
+            ("cairo", "Cairo", ""),
+            ("lathe", "Lathe", ""),
+            ("loft", "Loft", ""),
+            ("prism", "Prism", ""),
+            ("sphere_sweep", "Sphere Sweep", ""),
+            ("sor", "Surface of Revolution", ""),
+        ),
+        default="sphere_sweep",
+    )
+
+    #############Supertorus
+    def prop_update_supertorus(self, context):
+
+        """Update POV supertorus primitive parameters not only at creation but anytime they are changed in UI."""
+
+        bpy.ops.pov.supertorus_update()
+
+    st_major_radius: FloatProperty(
+        name="Major radius",
+        description="Major radius",
+        min=0.00,
+        max=100.00,
+        default=1.0,
+        update=prop_update_supertorus,
+    )
+
+    st_minor_radius: FloatProperty(
+        name="Minor radius",
+        description="Minor radius",
+        min=0.00,
+        max=100.00,
+        default=0.25,
+        update=prop_update_supertorus,
+    )
+
+    st_ring: FloatProperty(
+        name="Ring",
+        description="Ring manipulator",
+        min=0.0001,
+        max=100.00,
+        default=1.00,
+        update=prop_update_supertorus,
+    )
+
+    st_cross: FloatProperty(
+        name="Cross",
+        description="Cross manipulator",
+        min=0.0001,
+        max=100.00,
+        default=1.00,
+        update=prop_update_supertorus,
+    )
+
+    st_accuracy: FloatProperty(
+        name="Accuracy", description="Supertorus accuracy", min=0.00001, max=1.00, default=0.001
+    )
+
+    st_max_gradient: FloatProperty(
+        name="Gradient",
+        description="Max gradient",
+        min=0.0001,
+        max=100.00,
+        default=10.00,
+        update=prop_update_supertorus,
+    )
+
+    st_R: FloatProperty(
+        name="big radius",
+        description="The radius inside the tube",
+        default=1.0,
+        min=0.01,
+        max=100.0,
+        update=prop_update_supertorus,
+    )
+
+    st_r: FloatProperty(
+        name="small radius",
+        description="The radius of the tube",
+        default=0.3,
+        min=0.01,
+        max=100.0,
+        update=prop_update_supertorus,
+    )
+
+    st_u: IntProperty(
+        name="U-segments",
+        description="radial segmentation",
+        default=16,
+        min=3,
+        max=265,
+        update=prop_update_supertorus,
+    )
+
+    st_v: IntProperty(
+        name="V-segments",
+        description="lateral segmentation",
+        default=8,
+        min=3,
+        max=265,
+        update=prop_update_supertorus,
+    )
+
+    st_n1: FloatProperty(
+        name="Ring manipulator",
+        description="Manipulates the shape of the Ring",
+        default=1.0,
+        min=0.01,
+        max=100.0,
+        update=prop_update_supertorus,
+    )
+
+    st_n2: FloatProperty(
+        name="Cross manipulator",
+        description="Manipulates the shape of the cross-section",
+        default=1.0,
+        min=0.01,
+        max=100.0,
+        update=prop_update_supertorus,
+    )
+
+    st_ie: BoolProperty(
+        name="Use Int.+Ext. radii",
+        description="Use internal and external radii",
+        default=False,
+        update=prop_update_supertorus,
+    )
+
+    st_edit: BoolProperty(
+        name="", description="", default=False, options={"HIDDEN"}, update=prop_update_supertorus
+    )
+
+    ########################Loft
+    loft_n: IntProperty(
+        name="Segments", description="Vertical segments", default=16, min=3, max=720
+    )
+
+    loft_rings_bottom: IntProperty(
+        name="Bottom", description="Bottom rings", default=5, min=2, max=100
+    )
+
+    loft_rings_side: IntProperty(name="Side", description="Side rings", default=10, min=2, max=100)
+
+    loft_thick: FloatProperty(
+        name="Thickness",
+        description="Manipulates the shape of the Ring",
+        default=0.3,
+        min=0.01,
+        max=1.0,
+    )
+
+    loft_r: FloatProperty(name="Radius", description="Radius", default=1, min=0.01, max=10)
+
+    loft_height: FloatProperty(
+        name="Height",
+        description="Manipulates the shape of the Ring",
+        default=2,
+        min=0.01,
+        max=10.0,
+    )
+
+    ###################Prism
+    prism_n: IntProperty(name="Sides", description="Number of sides", default=5, min=3, max=720)
+
+    prism_r: FloatProperty(name="Radius", description="Radius", default=1.0)
+
+    ##################Isosurface
+    iso_function_text: StringProperty(
+        name="Function Text", maxlen=1024
+    )  # ,update=iso_props_update_callback)
+
+    ##################PolygonToCircle
+    polytocircle_resolution: IntProperty(
+        name="Resolution", description="", default=3, min=0, max=256
+    )
+
+    polytocircle_ngon: IntProperty(name="NGon", description="", min=3, max=64, default=5)
+
+    polytocircle_ngonR: FloatProperty(name="NGon Radius", description="", default=0.3)
+
+    polytocircle_circleR: FloatProperty(name="Circle Radius", description="", default=1.0)
+
+    ###############################################################################
+    # Modifiers POV properties.
+    ###############################################################################
+    # class RenderPovSettingsModifier(PropertyGroup):
+    boolean_mod: EnumProperty(
+        name="Operation",
+        description="Choose the type of calculation for Boolean modifier",
+        items=(
+            ("BMESH", "Use the BMesh Boolean Solver", ""),
+            ("CARVE", "Use the Carve Boolean Solver", ""),
+            ("POV", "Use POV Constructive Solid Geometry", ""),
+        ),
+        default="BMESH",
+    )
+
+    #################Avogadro
+    # filename_ext = ".png"
+
+    # filter_glob = StringProperty(
+    # default="*.exr;*.gif;*.hdr;*.iff;*.jpeg;*.jpg;*.pgm;*.png;*.pot;*.ppm;*.sys;*.tga;*.tiff;*.EXR;*.GIF;*.HDR;*.IFF;*.JPEG;*.JPG;*.PGM;*.PNG;*.POT;*.PPM;*.SYS;*.TGA;*.TIFF",
+    # options={'HIDDEN'},
+    # )
+
+
+classes = (RenderPovSettingsObject,)
+
+
+def register():
+    for cls in classes:
+        register_class(cls)
+    bpy.types.Object.pov = PointerProperty(type=RenderPovSettingsObject)
+
+
+def unregister():
+    del bpy.types.Object.pov
+    for cls in reversed(classes):
+        unregister_class(cls)
diff --git a/render_povray/render.py b/render_povray/render.py
old mode 100644
new mode 100755
index c4a93ebd4..45a94912b
--- a/render_povray/render.py
+++ b/render_povray/render.py
@@ -17,200 +17,79 @@
 # #**** END GPL LICENSE BLOCK #****
 
 # <pep8 compliant>
-
+"""Wirte the POV file using this file's functions and some from other modules then render it."""
 import bpy
 import subprocess
 import os
-import sys
+from sys import platform
 import time
-from math import atan, pi, degrees, sqrt, cos, sin
-####################
-## Faster mesh export
-import numpy as np
-####################
+from math import (
+    pi,
+)  # maybe move to scenography.py and topology_*****_data.py respectively with smoke and matrix
+
 import re
-import random
-import platform  #
-import subprocess  #
 import tempfile  # generate temporary files with random names
 from bpy.types import Operator
-from imghdr import what  # imghdr is a python lib to identify image file types
-from bpy.utils import register_class
+from bpy.utils import register_class, unregister_class
 
-from . import df3  # for smoke rendering
+from . import (
+    scripting,
+)  # for writing, importing and rendering directly POV Scene Description Language items
+from . import scenography  # for atmosphere, environment, effects, lighting, camera
 from . import shading  # for BI POV shaders emulation
-from . import primitives  # for import and export of POV specific primitives
-from . import nodes  # for POV specific nodes
-
-##############################SF###########################
-##############find image texture
-def imageFormat(imgF):
-    """Identify input image filetypes to transmit to POV."""
-    # First use the below explicit extensions to identify image file prospects
-    ext = {
-        'JPG': "jpeg",
-        'JPEG': "jpeg",
-        'GIF': "gif",
-        'TGA': "tga",
-        'IFF': "iff",
-        'PPM': "ppm",
-        'PNG': "png",
-        'SYS': "sys",
-        'TIFF': "tiff",
-        'TIF': "tiff",
-        'EXR': "exr",
-        'HDR': "hdr",
-    }.get(os.path.splitext(imgF)[-1].upper(), "")
-    # Then, use imghdr to really identify the filetype as it can be different
-    if not ext:
-        # maybe add a check for if path exists here?
-        print(" WARNING: texture image has no extension")  # too verbose
-
-        ext = what(imgF)  # imghdr is a python lib to identify image file types
-    return ext
-
-
-def imgMap(ts):
-    """Translate mapping type from Blender UI to POV syntax and return that string."""
-    image_map = ""
-    texdata = bpy.data.textures[ts.texture]
-    if ts.mapping == 'FLAT':
-        image_map = "map_type 0 "
-    elif ts.mapping == 'SPHERE':
-        image_map = "map_type 1 "
-    elif ts.mapping == 'TUBE':
-        image_map = "map_type 2 "
-
-    ## map_type 3 and 4 in development (?) (ENV in pov 3.8)
-    ## for POV-Ray, currently they just seem to default back to Flat (type 0)
-    # elif ts.mapping=="?":
-    #    image_map = " map_type 3 "
-    # elif ts.mapping=="?":
-    #    image_map = " map_type 4 "
-    if ts.use_interpolation: # Available if image sampling class reactivated?
-        image_map += " interpolate 2 "
-    if texdata.extension == 'CLIP':
-        image_map += " once "
-    # image_map += "}"
-    # if ts.mapping=='CUBE':
-    #    image_map+= "warp { cubic } rotate <-90,0,180>"
-    # no direct cube type mapping. Though this should work in POV 3.7
-    # it doesn't give that good results(best suited to environment maps?)
-    # if image_map == "":
-    #    print(" No texture image  found ")
-    return image_map
-
-
-def imgMapTransforms(ts):
-    """Translate mapping transformations from Blender UI to POV syntax and return that string."""
-    # XXX TODO: unchecked textures give error of variable referenced before assignment XXX
-    # POV-Ray "scale" is not a number of repetitions factor, but ,its
-    # inverse, a standard scale factor.
-    # 0.5 Offset is needed relatively to scale because center of the
-    # scale is 0.5,0.5 in blender and 0,0 in POV
-    # Strange that the translation factor for scale is not the same as for
-    # translate.
-    # TODO: verify both matches with blender internal.
-    image_map_transforms = ""
-    image_map_transforms = (
-        "scale <%.4g,%.4g,%.4g> translate <%.4g,%.4g,%.4g>"
-        % (
-            ts.scale[0],
-            ts.scale[1],
-            ts.scale[2],
-            ts.offset[0],
-            ts.offset[1],
-            ts.offset[2],
-        )
-    )
-    # image_map_transforms = (" translate <-0.5,-0.5,0.0> scale <%.4g,%.4g,%.4g> translate <%.4g,%.4g,%.4g>" % \
-    # ( 1.0 / ts.scale.x,
-    # 1.0 / ts.scale.y,
-    # 1.0 / ts.scale.z,
-    # (0.5 / ts.scale.x) + ts.offset.x,
-    # (0.5 / ts.scale.y) + ts.offset.y,
-    # ts.offset.z))
-    # image_map_transforms = ("translate <-0.5,-0.5,0> scale <-1,-1,1> * <%.4g,%.4g,%.4g> translate <0.5,0.5,0> + <%.4g,%.4g,%.4g>" % \
-    # (1.0 / ts.scale.x,
-    # 1.0 / ts.scale.y,
-    # 1.0 / ts.scale.z,
-    # ts.offset.x,
-    # ts.offset.y,
-    # ts.offset.z))
-    return image_map_transforms
-
-
-def imgMapBG(wts):
-    """Translate world mapping from Blender UI to POV syntax and return that string."""
-    tex = bpy.data.textures[wts.texture]
-    image_mapBG = ""
-    # texture_coords refers to the mapping of world textures:
-    if wts.texture_coords == 'VIEW' or wts.texture_coords == 'GLOBAL':
-        image_mapBG = " map_type 0 "
-    elif wts.texture_coords == 'ANGMAP':
-        image_mapBG = " map_type 1 "
-    elif wts.texture_coords == 'TUBE':
-        image_mapBG = " map_type 2 "
-
-    if tex.use_interpolation:
-        image_mapBG += " interpolate 2 "
-    if tex.extension == 'CLIP':
-        image_mapBG += " once "
-    # image_mapBG += "}"
-    # if wts.mapping == 'CUBE':
-    #   image_mapBG += "warp { cubic } rotate <-90,0,180>"
-    # no direct cube type mapping. Though this should work in POV 3.7
-    # it doesn't give that good results(best suited to environment maps?)
-    # if image_mapBG == "":
-    #    print(" No background texture image  found ")
-    return image_mapBG
-
-
-def path_image(image):
-    """Conform a path string to POV syntax to avoid POV errors."""
-    return bpy.path.abspath(image.filepath, library=image.library).replace(
-        "\\", "/"
-    )
-    # .replace("\\","/") to get only forward slashes as it's what POV prefers,
-    # even on windows
+from . import object_mesh_topology  # for mesh based geometry
+from . import object_curve_topology  # for curves based geometry
+
+# from . import object_primitives  # for import and export of POV specific primitives
 
 
-# end find image texture
-# -----------------------------------------------------------------------------
+from .scenography import image_format, img_map, img_map_transforms, path_image
+
+from .shading import write_object_material
+from .object_primitives import write_object_modifiers
 
 
 def string_strip_hyphen(name):
+
     """Remove hyphen characters from a string to avoid POV errors."""
+
     return name.replace("-", "")
 
 
-def safety(name, Level):
+def safety(name, ref_level_bound):
     """append suffix characters to names of various material declinations.
 
     Material declinations are necessary to POV syntax and used in shading.py
-    by the povHasnoSpecularMaps function to create the finish map trick and
+    by the pov_has_no_specular_maps function to create the finish map trick and
     the suffixes avoid name collisions.
     Keyword arguments:
     name -- the initial material name as a string
-    Level -- the enum number of the Level being written:
-        Level=1 is for texture with No specular nor Mirror reflection
-        Level=2 is for texture with translation of spec and mir levels
+    ref_level_bound -- the enum number of the ref_level_bound being written:
+        ref_level_bound=1 is for texture with No specular nor Mirror reflection
+        ref_level_bound=2 is for texture with translation of spec and mir levels
         for when no map influences them
-        Level=3 is for texture with Maximum Spec and Mirror
+        ref_level_bound=3 is for texture with Maximum Spec and Mirror
     """
-
-    try:
-        if int(name) > 0:
-            prefix = "shader"
-    except:
-        prefix = ""
+    # All the try except clause below seems useless as each time
+    # prefix rewritten even after and outside of it what was the point?
+    # It may not even be any longer possible to feed no arg from Blender UI
+    # try:
+    # if name: # if int(name) > 0: # could be zero if no argument provided
+    # # and always triggered exception so is this similar ?
+    # prefix = "shader"
+    # except BaseException as e:
+    # print(e.__doc__)
+    # print('An exXXXception occurred: {}'.format(e))
+    # prefix = "" # rewritten below...
     prefix = "shader_"
     name = string_strip_hyphen(name)
-    if Level == 2:
+    if ref_level_bound == 2:
         return prefix + name
-    elif Level == 1:
+    # implicit else-if (no return yet)
+    if ref_level_bound == 1:
         return prefix + name + "0"  # used for 0 of specular map
-    elif Level == 3:
+    # implicit else-if (no return yet)
+    if ref_level_bound == 3:
         return prefix + name + "1"  # used for 1 of specular map
 
 
@@ -220,174 +99,107 @@ def safety(name, Level):
 csg_list = []
 
 
-def is_renderable(scene, ob):
+def is_renderable(ob):
+    """test for objects flagged as hidden or boolean operands not to render"""
     return not ob.hide_render and ob not in csg_list
 
 
 def renderable_objects(scene):
-    return [ob for ob in bpy.data.objects if is_renderable(scene, ob)]
+    """test for non hidden, non boolean operands objects to render"""
+    return [ob for ob in bpy.data.objects if is_renderable(ob)]
 
 
-def no_renderable_objects(scene):
-    return [ob for ob in csg_list]
+def no_renderable_objects():
+    """Boolean operands only. Not to render"""
+    return list(csg_list)
 
 
-tabLevel = 0
+tab_level = 0
 unpacked_images = []
 
 user_dir = bpy.utils.resource_path('USER')
 preview_dir = os.path.join(user_dir, "preview")
 
 ## Make sure Preview directory exists and is empty
-smokePath = os.path.join(preview_dir, "smoke.df3")
-'''
-def write_global_setting(scene,file):
-    file.write("global_settings {\n")
-    file.write("    assumed_gamma %.6f\n"%scene.pov.assumed_gamma)
-    if scene.pov.global_settings_advanced:
-        if scene.pov.radio_enable == False:
-            file.write("    adc_bailout %.6f\n"%scene.pov.adc_bailout)
-        file.write("    ambient_light <%.6f,%.6f,%.6f>\n"%scene.pov.ambient_light[:])
-        file.write("    irid_wavelength <%.6f,%.6f,%.6f>\n"%scene.pov.irid_wavelength[:])
-        file.write("    charset %s\n"%scene.pov.charset)
-        file.write("    max_trace_level %s\n"%scene.pov.max_trace_level)
-        file.write("    max_intersections %s\n"%scene.pov.max_intersections)
-        file.write("    number_of_waves %s\n"%scene.pov.number_of_waves)
-        file.write("    noise_generator %s\n"%scene.pov.noise_generator)
-
-    # below properties not added to __init__ yet to avoid conflicts with material sss scale
-    # unless it would override then should be interfaced also in scene units property tab
-
-    # if scene.pov.sslt_enable:
-        # file.write("    mm_per_unit %s\n"%scene.pov.mm_per_unit)
-        # file.write("    subsurface {\n")
-        # file.write("        samples %s, %s\n"%(scene.pov.sslt_samples_max,scene.pov.sslt_samples_min))
-        # if scene.pov.sslt_radiosity:
-            # file.write("        radiosity on\n")
-        # file.write("}\n")
-
-    if scene.pov.radio_enable:
-        file.write("    radiosity {\n")
-        file.write("        pretrace_start %.6f\n"%scene.pov.radio_pretrace_start)
-        file.write("        pretrace_end %.6f\n"%scene.pov.radio_pretrace_end)
-        file.write("        count %s\n"%scene.pov.radio_count)
-        file.write("        nearest_count %s\n"%scene.pov.radio_nearest_count)
-        file.write("        error_bound %.6f\n"%scene.pov.radio_error_bound)
-        file.write("        recursion_limit %s\n"%scene.pov.radio_recursion_limit)
-        file.write("        low_error_factor %.6f\n"%scene.pov.radio_low_error_factor)
-        file.write("        gray_threshold %.6f\n"%scene.pov.radio_gray_threshold)
-        file.write("        maximum_reuse %.6f\n"%scene.pov.radio_maximum_reuse)
-        file.write("        minimum_reuse %.6f\n"%scene.pov.radio_minimum_reuse)
-        file.write("        brightness %.6f\n"%scene.pov.radio_brightness)
-        file.write("        adc_bailout %.6f\n"%scene.pov.radio_adc_bailout)
-        if scene.pov.radio_normal:
-            file.write("        normal on\n")
-        if scene.pov.radio_always_sample:
-            file.write("        always_sample on\n")
-        if scene.pov.radio_media:
-            file.write("        media on\n")
-        if scene.pov.radio_subsurface:
-            file.write("        subsurface on\n")
-        file.write("    }\n")
-
-    if scene.pov.photon_enable:
-        file.write("    photons {\n")
-        if scene.pov.photon_enable_count:
-            file.write("        count %s\n"%scene.pov.photon_count)
-        else:
-            file.write("        spacing %.6g\n"%scene.pov.photon_spacing)
-        if scene.pov.photon_gather:
-            file.write("        gather %s, %s\n"%(scene.pov.photon_gather_min,scene.pov.photon_gather_max))
-        if scene.pov.photon_autostop:
-            file.write("        autostop %.4g\n"%scene.pov.photon_autostop_value)
-        if scene.pov.photon_jitter_enable:
-            file.write("        jitter %.4g\n"%scene.pov.photon_jitter)
-        file.write("        max_trace_level %s\n"%scene.pov.photon_max_trace_level)
-        if scene.pov.photon_adc:
-            file.write("        adc_bailout %.6f\n"%scene.pov.photon_adc_bailout)
-        if scene.pov.photon_media_enable:
-            file.write("        media %s, %s\n"%(scene.pov.photon_media_steps,scene.pov.photon_media_factor))
-        if scene.pov.photon_map_file_save_load in {'save'}:
-            filePhName = 'Photon_map_file.ph'
-            if scene.pov.photon_map_file != '':
-                filePhName = scene.pov.photon_map_file+'.ph'
-            filePhDir = tempfile.gettempdir()
-            path = bpy.path.abspath(scene.pov.photon_map_dir)
-            if os.path.exists(path):
-                filePhDir = path
-            fullFileName = os.path.join(filePhDir,filePhName)
-            file.write('        save_file "%s"\n'%fullFileName)
-            scene.pov.photon_map_file = fullFileName
-        if scene.pov.photon_map_file_save_load in {'load'}:
-            fullFileName = bpy.path.abspath(scene.pov.photon_map_file)
-            if os.path.exists(fullFileName):
-                file.write('        load_file "%s"\n'%fullFileName)
-        file.write("}\n")
-    file.write("}\n")
+smoke_path = os.path.join(preview_dir, "smoke.df3")
+
 '''
 
+# below properties not added to __init__ yet to avoid conflicts with material sss scale
+# unless it would override then should be interfaced also in scene units property tab
 
-def write_object_modifiers(scene, ob, File):
-    """Translate some object level POV statements from Blender UI
-    to POV syntax and write to exported file """
+# if scene.pov.sslt_enable:
+    # file.write("    mm_per_unit %s\n"%scene.pov.mm_per_unit)
+    # file.write("    subsurface {\n")
+    # file.write("        samples %s, %s\n"%(scene.pov.sslt_samples_max,scene.pov.sslt_samples_min))
+    # if scene.pov.sslt_radiosity:
+        # file.write("        radiosity on\n")
+    # file.write("}\n")
 
-    # Maybe return that string to be added instead of directly written.
+'''
 
-    '''XXX WIP
-    onceCSG = 0
-    for mod in ob.modifiers:
-        if onceCSG == 0:
-            if mod :
-                if mod.type == 'BOOLEAN':
-                    if ob.pov.boolean_mod == "POV":
-                        File.write("\tinside_vector <%.6g, %.6g, %.6g>\n" %
-                                   (ob.pov.inside_vector[0],
-                                    ob.pov.inside_vector[1],
-                                    ob.pov.inside_vector[2]))
-                        onceCSG = 1
-    '''
 
-    if ob.pov.hollow:
-        File.write("\thollow\n")
-    if ob.pov.double_illuminate:
-        File.write("\tdouble_illuminate\n")
-    if ob.pov.sturm:
-        File.write("\tsturm\n")
-    if ob.pov.no_shadow:
-        File.write("\tno_shadow\n")
-    if ob.pov.no_image:
-        File.write("\tno_image\n")
-    if ob.pov.no_reflection:
-        File.write("\tno_reflection\n")
-    if ob.pov.no_radiosity:
-        File.write("\tno_radiosity\n")
-    if ob.pov.inverse:
-        File.write("\tinverse\n")
-    if ob.pov.hierarchy:
-        File.write("\thierarchy\n")
-
-    # XXX, Commented definitions
-    '''
-    if scene.pov.photon_enable:
-        File.write("photons {\n")
-        if ob.pov.target:
-            File.write("target %.4g\n"%ob.pov.target_value)
-        if ob.pov.refraction:
-            File.write("refraction on\n")
-        if ob.pov.reflection:
-            File.write("reflection on\n")
-        if ob.pov.pass_through:
-            File.write("pass_through\n")
-        File.write("}\n")
-    if ob.pov.object_ior > 1:
-        File.write("interior {\n")
-        File.write("ior %.4g\n"%ob.pov.object_ior)
-        if scene.pov.photon_enable and ob.pov.target and ob.pov.refraction and ob.pov.dispersion:
-            File.write("ior %.4g\n"%ob.pov.dispersion_value)
-            File.write("ior %s\n"%ob.pov.dispersion_samples)
-        if scene.pov.photon_enable == False:
-            File.write("caustics %.4g\n"%ob.pov.fake_caustics_power)
-    '''
+# def write_object_modifiers(scene, ob, File):
+# """Translate some object level POV statements from Blender UI
+# to POV syntax and write to exported file """
+
+# # Maybe return that string to be added instead of directly written.
+
+# '''XXX WIP
+# onceCSG = 0
+# for mod in ob.modifiers:
+# if onceCSG == 0:
+# if mod :
+# if mod.type == 'BOOLEAN':
+# if ob.pov.boolean_mod == "POV":
+# File.write("\tinside_vector <%.6g, %.6g, %.6g>\n" %
+# (ob.pov.inside_vector[0],
+# ob.pov.inside_vector[1],
+# ob.pov.inside_vector[2]))
+# onceCSG = 1
+# '''
+
+# if ob.pov.hollow:
+# File.write("\thollow\n")
+# if ob.pov.double_illuminate:
+# File.write("\tdouble_illuminate\n")
+# if ob.pov.sturm:
+# File.write("\tsturm\n")
+# if ob.pov.no_shadow:
+# File.write("\tno_shadow\n")
+# if ob.pov.no_image:
+# File.write("\tno_image\n")
+# if ob.pov.no_reflection:
+# File.write("\tno_reflection\n")
+# if ob.pov.no_radiosity:
+# File.write("\tno_radiosity\n")
+# if ob.pov.inverse:
+# File.write("\tinverse\n")
+# if ob.pov.hierarchy:
+# File.write("\thierarchy\n")
+
+# # XXX, Commented definitions
+# '''
+# if scene.pov.photon_enable:
+# File.write("photons {\n")
+# if ob.pov.target:
+# File.write("target %.4g\n"%ob.pov.target_value)
+# if ob.pov.refraction:
+# File.write("refraction on\n")
+# if ob.pov.reflection:
+# File.write("reflection on\n")
+# if ob.pov.pass_through:
+# File.write("pass_through\n")
+# File.write("}\n")
+# if ob.pov.object_ior > 1:
+# File.write("interior {\n")
+# File.write("ior %.4g\n"%ob.pov.object_ior)
+# if scene.pov.photon_enable and ob.pov.target and ob.pov.refraction and ob.pov.dispersion:
+# File.write("ior %.4g\n"%ob.pov.dispersion_value)
+# File.write("ior %s\n"%ob.pov.dispersion_samples)
+# if scene.pov.photon_enable == False:
+# File.write("caustics %.4g\n"%ob.pov.fake_caustics_power)
+# '''
 
 
 def write_pov(filename, scene=None, info_callback=None):
@@ -406,12 +218,8 @@ def write_pov(filename, scene=None, info_callback=None):
     world = scene.world
     global_matrix = mathutils.Matrix.Rotation(-pi / 2.0, 4, 'X')
     comments = scene.pov.comments_enable and not scene.pov.tempfiles_enable
-    linebreaksinlists = (
-        scene.pov.list_lf_enable and not scene.pov.tempfiles_enable
-    )
-    feature_set = bpy.context.preferences.addons[
-        __package__
-    ].preferences.branch_feature_set_povray
+    linebreaksinlists = scene.pov.list_lf_enable and not scene.pov.tempfiles_enable
+    feature_set = bpy.context.preferences.addons[__package__].preferences.branch_feature_set_povray
     using_uberpov = feature_set == 'uberpov'
     pov_binary = PovrayRender._locate_binary()
 
@@ -420,73 +228,64 @@ def write_pov(filename, scene=None, info_callback=None):
     else:
         print("Official POV-Ray 3.7 feature set chosen in preferences")
     if 'uber' in pov_binary:
-        print(
-            "The name of the binary suggests you are probably rendering with Uber POV engine"
-        )
+        print("The name of the binary suggests you are probably rendering with Uber POV engine")
     else:
-        print(
-            "The name of the binary suggests you are probably rendering with standard POV engine"
-        )
+        print("The name of the binary suggests you are probably rendering with standard POV engine")
 
-    def setTab(tabtype, spaces):
-        TabStr = ""
+    def set_tab(tabtype, spaces):
+        tab_str = ""
         if tabtype == 'NONE':
-            TabStr = ""
+            tab_str = ""
         elif tabtype == 'TAB':
-            TabStr = "\t"
+            tab_str = "\t"
         elif tabtype == 'SPACE':
-            TabStr = spaces * " "
-        return TabStr
+            tab_str = spaces * " "
+        return tab_str
 
-    tab = setTab(scene.pov.indentation_character, scene.pov.indentation_spaces)
+    tab = set_tab(scene.pov.indentation_character, scene.pov.indentation_spaces)
     if not scene.pov.tempfiles_enable:
 
-        def tabWrite(str_o):
+        def tab_write(str_o):
             """Indent POV syntax from brackets levels and write to exported file """
-            global tabLevel
-            brackets = (
-                str_o.count("{")
-                - str_o.count("}")
-                + str_o.count("[")
-                - str_o.count("]")
-            )
+            global tab_level
+            brackets = str_o.count("{") - str_o.count("}") + str_o.count("[") - str_o.count("]")
             if brackets < 0:
-                tabLevel = tabLevel + brackets
-            if tabLevel < 0:
-                print("Indentation Warning: tabLevel = %s" % tabLevel)
-                tabLevel = 0
-            if tabLevel >= 1:
-                file.write("%s" % tab * tabLevel)
+                tab_level = tab_level + brackets
+            if tab_level < 0:
+                print("Indentation Warning: tab_level = %s" % tab_level)
+                tab_level = 0
+            if tab_level >= 1:
+                file.write("%s" % tab * tab_level)
             file.write(str_o)
             if brackets > 0:
-                tabLevel = tabLevel + brackets
+                tab_level = tab_level + brackets
 
     else:
 
-        def tabWrite(str_o):
+        def tab_write(str_o):
             """write directly to exported file if user checked autonamed temp files (faster)."""
 
             file.write(str_o)
 
-    def uniqueName(name, nameSeq):
+    def unique_name(name, name_seq):
         """Increment any generated POV name that could get identical to avoid collisions"""
 
-        if name not in nameSeq:
+        if name not in name_seq:
             name = string_strip_hyphen(name)
             return name
 
         name_orig = name
         i = 1
-        while name in nameSeq:
+        while name in name_seq:
             name = "%s_%.3d" % (name_orig, i)
             i += 1
         name = string_strip_hyphen(name)
         return name
 
-    def writeMatrix(matrix):
+    def write_matrix(matrix):
         """Translate some tranform matrix from Blender UI
         to POV syntax and write to exported file """
-        tabWrite(
+        tab_write(
             "matrix <%.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, %.6f>\n"
             % (
                 matrix[0][0],
@@ -504,1539 +303,12 @@ def write_pov(filename, scene=None, info_callback=None):
             )
         )
 
-    def MatrixAsPovString(matrix):
-        """Translate some tranform matrix from Blender UI
-        to POV syntax and return that string """
-        sMatrix = (
-            "matrix <%.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, %.6f>\n"
-            % (
-                matrix[0][0],
-                matrix[1][0],
-                matrix[2][0],
-                matrix[0][1],
-                matrix[1][1],
-                matrix[2][1],
-                matrix[0][2],
-                matrix[1][2],
-                matrix[2][2],
-                matrix[0][3],
-                matrix[1][3],
-                matrix[2][3],
-            )
-        )
-        return sMatrix
-
-    def writeObjectMaterial(material, ob):
-        """Translate some object level material from Blender UI (VS data level)
-        to POV interior{} syntax and write it to exported file """
-
-        # DH - modified some variables to be function local, avoiding RNA write
-        # this should be checked to see if it is functionally correct
-
-        # Commented out: always write IOR to be able to use it for SSS, Fresnel reflections...
-        # if material and material.transparency_method == 'RAYTRACE':
-        if material:
-            # But there can be only one!
-            if (
-                material.pov_subsurface_scattering.use
-            ):  # SSS IOR get highest priority
-                tabWrite("interior {\n")
-                tabWrite("ior %.6f\n" % material.pov_subsurface_scattering.ior)
-            # Then the raytrace IOR taken from raytrace transparency properties and used for
-            # reflections if IOR Mirror option is checked.
-            elif material.pov.mirror_use_IOR:
-                tabWrite("interior {\n")
-                tabWrite("ior %.6f\n" % material.pov_raytrace_transparency.ior)
-            elif material.pov.transparency_method == 'Z_TRANSPARENCY':
-                tabWrite("interior {\n")
-                tabWrite("ior 1.0\n")
-            else:
-                tabWrite("interior {\n")
-                tabWrite("ior %.6f\n" % material.pov_raytrace_transparency.ior)
-
-            pov_fake_caustics = False
-            pov_photons_refraction = False
-            pov_photons_reflection = False
-
-            if material.pov.photons_reflection:
-                pov_photons_reflection = True
-            if not material.pov.refraction_caustics:
-                pov_fake_caustics = False
-                pov_photons_refraction = False
-            elif material.pov.refraction_type == "1":
-                pov_fake_caustics = True
-                pov_photons_refraction = False
-            elif material.pov.refraction_type == "2":
-                pov_fake_caustics = False
-                pov_photons_refraction = True
-
-            # If only Raytrace transparency is set, its IOR will be used for refraction, but user
-            # can set up 'un-physical' fresnel reflections in raytrace mirror parameters.
-            # Last, if none of the above is specified, user can set up 'un-physical' fresnel
-            # reflections in raytrace mirror parameters. And pov IOR defaults to 1.
-            if material.pov.caustics_enable:
-                if pov_fake_caustics:
-                    tabWrite(
-                        "caustics %.3g\n" % material.pov.fake_caustics_power
-                    )
-                if pov_photons_refraction:
-                    # Default of 1 means no dispersion
-                    tabWrite(
-                        "dispersion %.6f\n" % material.pov.photons_dispersion
-                    )
-                    tabWrite(
-                        "dispersion_samples %.d\n"
-                        % material.pov.photons_dispersion_samples
-                    )
-            # TODO
-            # Other interior args
-            if (
-                material.pov.use_transparency
-                and material.pov.transparency_method == 'RAYTRACE'
-            ):
-                # fade_distance
-                # In Blender this value has always been reversed compared to what tooltip says.
-                # 100.001 rather than 100 so that it does not get to 0
-                # which deactivates the feature in POV
-                tabWrite(
-                    "fade_distance %.3g\n"
-                    % (100.001 - material.pov_raytrace_transparency.depth_max)
-                )
-                # fade_power
-                tabWrite(
-                    "fade_power %.3g\n"
-                    % material.pov_raytrace_transparency.falloff
-                )
-                # fade_color
-                tabWrite(
-                    "fade_color <%.3g, %.3g, %.3g>\n"
-                    % material.pov.interior_fade_color[:]
-                )
-
-            # (variable) dispersion_samples (constant count for now)
-            tabWrite("}\n")
-            if (
-                material.pov.photons_reflection
-                or material.pov.refraction_type == "2"
-            ):
-                tabWrite("photons{")
-                tabWrite("target %.3g\n" % ob.pov.spacing_multiplier)
-                if not ob.pov.collect_photons:
-                    tabWrite("collect off\n")
-                if pov_photons_refraction:
-                    tabWrite("refraction on\n")
-                if pov_photons_reflection:
-                    tabWrite("reflection on\n")
-                tabWrite("}\n")
-
-    materialNames = {}
+    material_names_dictionary = {}
     DEF_MAT_NAME = ""  # or "Default"?
 
-    def exportCamera():
-        """Translate camera from Blender UI to POV syntax and write to exported file."""
-        camera = scene.camera
-
-        # DH disabled for now, this isn't the correct context
-        active_object = (
-            None
-        )  # bpy.context.active_object # does not always work  MR
-        matrix = global_matrix @ camera.matrix_world
-        focal_point = camera.data.dof.focus_distance
-
-        # compute resolution
-        Qsize = render.resolution_x / render.resolution_y
-        tabWrite(
-            "#declare camLocation  = <%.6f, %.6f, %.6f>;\n"
-            % matrix.translation[:]
-        )
-        tabWrite(
-            "#declare camLookAt = <%.6f, %.6f, %.6f>;\n"
-            % tuple([degrees(e) for e in matrix.to_3x3().to_euler()])
-        )
-
-        tabWrite("camera {\n")
-        if (
-            scene.pov.baking_enable
-            and active_object
-            and active_object.type == 'MESH'
-        ):
-            tabWrite(
-                "mesh_camera{ 1 3\n"
-            )  # distribution 3 is what we want here
-            tabWrite("mesh{%s}\n" % active_object.name)
-            tabWrite("}\n")
-            tabWrite("location <0,0,.01>")
-            tabWrite("direction <0,0,-1>")
-
-        else:
-            if camera.data.type == 'ORTHO':
-                SensorHeightRatio = render.resolution_x * camera.data.ortho_scale / render.resolution_y
-                tabWrite("orthographic\n")
-                # Blender angle is radian so should be converted to degrees:
-                # % (camera.data.angle * (180.0 / pi) )
-                # but actually argument is not compulsory after angle in pov ortho mode
-                tabWrite("angle\n")
-                tabWrite("right <%6f, 0, 0>\n" % -camera.data.ortho_scale)
-                tabWrite("location  <0, 0, 0>\n")
-                tabWrite("look_at  <0, 0, -1>\n")
-                tabWrite("up <0, %6f, 0>\n" % (camera.data.ortho_scale / Qsize))
-
-            elif camera.data.type == 'PANO':
-                tabWrite("panoramic\n")
-                tabWrite("location  <0, 0, 0>\n")
-                tabWrite("look_at  <0, 0, -1>\n")
-                tabWrite("right <%s, 0, 0>\n" % -Qsize)
-                tabWrite("up <0, 1, 0>\n")
-                tabWrite(
-                    "angle  %f\n" % (360.0 * atan(16.0 / camera.data.lens) / pi)
-                )
-            elif camera.data.type == 'PERSP':
-                # Standard camera otherwise would be default in pov
-                tabWrite("location  <0, 0, 0>\n")
-                tabWrite("look_at  <0, 0, -1>\n")
-                tabWrite("right <%s, 0, 0>\n" % -Qsize)
-                tabWrite("up <0, 1, 0>\n")
-                tabWrite(
-                    "angle  %f\n" % ( 2 * atan(camera.data.sensor_width / 2 / camera.data.lens) * 180.0 / pi )
-                )
-
-            tabWrite(
-                "rotate  <%.6f, %.6f, %.6f>\n"
-                % tuple([degrees(e) for e in matrix.to_3x3().to_euler()])
-            )
-            tabWrite("translate <%.6f, %.6f, %.6f>\n" % matrix.translation[:])
-            if camera.data.dof.use_dof and (
-                focal_point != 0 or camera.data.dof.focus_object
-            ):
-                tabWrite(
-                    "aperture %.3g\n"
-                    % (1 / camera.data.dof.aperture_fstop * 1000)
-                )
-                tabWrite(
-                    "blur_samples %d %d\n"
-                    % (
-                        camera.data.pov.dof_samples_min,
-                        camera.data.pov.dof_samples_max,
-                    )
-                )
-                tabWrite("variance 1/%d\n" % camera.data.pov.dof_variance)
-                tabWrite("confidence %.3g\n" % camera.data.pov.dof_confidence)
-                if camera.data.dof.focus_object:
-                    focalOb = scene.objects[camera.data.dof.focus_object.name]
-                    matrixBlur = global_matrix @ focalOb.matrix_world
-                    tabWrite(
-                        "focal_point <%.4f,%.4f,%.4f>\n"
-                        % matrixBlur.translation[:]
-                    )
-                else:
-                    tabWrite("focal_point <0, 0, %f>\n" % focal_point)
-        if camera.data.pov.normal_enable:
-            tabWrite(
-                "normal {%s %.4f turbulence %.4f scale %.4f}\n"
-                % (
-                    camera.data.pov.normal_patterns,
-                    camera.data.pov.cam_normal,
-                    camera.data.pov.turbulence,
-                    camera.data.pov.scale,
-                )
-            )
-        tabWrite("}\n")
-
-    def exportLamps(lamps):
-        """Translate lights from Blender UI to POV syntax and write to exported file."""
-
-        # Incremented after each lamp export to declare its target
-        # currently used for Fresnel diffuse shader as their slope vector:
-        global lampCount
-        lampCount = 0
-        # Get all lamps
-        for ob in lamps:
-            lamp = ob.data
-
-            matrix = global_matrix @ ob.matrix_world
-
-            # Color is no longer modified by energy
-            color = tuple([c for c in lamp.color])
-
-            tabWrite("light_source {\n")
-            tabWrite("< 0,0,0 >\n")
-            tabWrite("color srgb<%.3g, %.3g, %.3g>\n" % color)
-
-            if lamp.type == 'POINT':
-                pass
-            elif lamp.type == 'SPOT':
-                tabWrite("spotlight\n")
-
-                # Falloff is the main radius from the centre line
-                tabWrite(
-                    "falloff %.2f\n" % (degrees(lamp.spot_size) / 2.0)
-                )  # 1 TO 179 FOR BOTH
-                tabWrite(
-                    "radius %.6f\n"
-                    % (
-                        (degrees(lamp.spot_size) / 2.0)
-                        * (1.0 - lamp.spot_blend)
-                    )
-                )
-
-                # Blender does not have a tightness equivalent, 0 is most like blender default.
-                tabWrite("tightness 0\n")  # 0:10f
-
-                tabWrite("point_at  <0, 0, -1>\n")
-                if lamp.pov.use_halo:
-                    tabWrite("looks_like{\n")
-                    tabWrite("sphere{<0,0,0>,%.6f\n" % lamp.distance)
-                    tabWrite("hollow\n")
-                    tabWrite("material{\n")
-                    tabWrite("texture{\n")
-                    tabWrite(
-                        "pigment{rgbf<1,1,1,%.4f>}\n"
-                        % (lamp.pov.halo_intensity * 5.0)
-                    )
-                    tabWrite("}\n")
-                    tabWrite("interior{\n")
-                    tabWrite("media{\n")
-                    tabWrite("emission 1\n")
-                    tabWrite("scattering {1, 0.5}\n")
-                    tabWrite("density{\n")
-                    tabWrite("spherical\n")
-                    tabWrite("color_map{\n")
-                    tabWrite("[0.0 rgb <0,0,0>]\n")
-                    tabWrite("[0.5 rgb <1,1,1>]\n")
-                    tabWrite("[1.0 rgb <1,1,1>]\n")
-                    tabWrite("}\n")
-                    tabWrite("}\n")
-                    tabWrite("}\n")
-                    tabWrite("}\n")
-                    tabWrite("}\n")
-                    tabWrite("}\n")
-                    tabWrite("}\n")
-            elif lamp.type == 'SUN':
-                tabWrite("parallel\n")
-                tabWrite("point_at  <0, 0, -1>\n")  # *must* be after 'parallel'
-
-            elif lamp.type == 'AREA':
-                tabWrite("fade_distance %.6f\n" % (lamp.distance / 2.0))
-                # Area lights have no falloff type, so always use blenders lamp quad equivalent
-                # for those?
-                tabWrite("fade_power %d\n" % 2)
-                size_x = lamp.size
-                samples_x = lamp.pov.shadow_ray_samples_x
-                if lamp.shape == 'SQUARE':
-                    size_y = size_x
-                    samples_y = samples_x
-                else:
-                    size_y = lamp.size_y
-                    samples_y = lamp.pov.shadow_ray_samples_y
-
-                tabWrite(
-                    "area_light <%.6f,0,0>,<0,%.6f,0> %d, %d\n"
-                    % (size_x, size_y, samples_x, samples_y)
-                )
-                tabWrite("area_illumination\n")
-                if lamp.pov.shadow_ray_sample_method == 'CONSTANT_JITTERED':
-                    if lamp.pov.use_jitter:
-                        tabWrite("jitter\n")
-                else:
-                    tabWrite("adaptive 1\n")
-                    tabWrite("jitter\n")
-
-            # No shadow checked either at global or light level:
-            if not scene.pov.use_shadows or (
-                lamp.pov.shadow_method == 'NOSHADOW'
-            ):
-                tabWrite("shadowless\n")
-
-            # Sun shouldn't be attenuated. Area lights have no falloff attribute so they
-            # are put to type 2 attenuation a little higher above.
-            if lamp.type not in {'SUN', 'AREA'}:
-                if lamp.falloff_type == 'INVERSE_SQUARE':
-                    tabWrite(
-                        "fade_distance %.6f\n" % (sqrt(lamp.distance / 2.0))
-                    )
-                    tabWrite(
-                        "fade_power %d\n" % 2
-                    )  # Use blenders lamp quad equivalent
-                elif lamp.falloff_type == 'INVERSE_LINEAR':
-                    tabWrite("fade_distance %.6f\n" % (lamp.distance / 2.0))
-                    tabWrite("fade_power %d\n" % 1)  # Use blenders lamp linear
-                elif lamp.falloff_type == 'CONSTANT':
-                    tabWrite("fade_distance %.6f\n" % (lamp.distance / 2.0))
-                    tabWrite("fade_power %d\n" % 3)
-                    # Use blenders lamp constant equivalent no attenuation.
-                # Using Custom curve for fade power 3 for now.
-                elif lamp.falloff_type == 'CUSTOM_CURVE':
-                    tabWrite("fade_power %d\n" % 4)
-
-            writeMatrix(matrix)
-
-            tabWrite("}\n")
-
-            lampCount += 1
-
-            # v(A,B) rotates vector A about origin by vector B.
-            file.write(
-                "#declare lampTarget%s= vrotate(<%.4g,%.4g,%.4g>,<%.4g,%.4g,%.4g>);\n"
-                % (
-                    lampCount,
-                    -(ob.location.x),
-                    -(ob.location.y),
-                    -(ob.location.z),
-                    ob.rotation_euler.x,
-                    ob.rotation_euler.y,
-                    ob.rotation_euler.z,
-                )
-            )
-
-    ####################################################################################################
-    def exportRainbows(rainbows):
-        """write all POV rainbows primitives to exported file """
-        for ob in rainbows:
-            povdataname = ob.data.name  # enough?
-            angle = degrees(ob.data.spot_size / 2.5)  # radians in blender (2
-            width = ob.data.spot_blend * 10
-            distance = ob.data.shadow_buffer_clip_start
-            # eps=0.0000001
-            # angle = br/(cr+eps) * 10 #eps is small epsilon variable to avoid dividing by zero
-            # width = ob.dimensions[2] #now let's say width of rainbow is the actual proxy height
-            # formerly:
-            # cz-bz # let's say width of the rainbow is height of the cone (interfacing choice
-
-            # v(A,B) rotates vector A about origin by vector B.
-            # and avoid a 0 length vector by adding 1
-
-            # file.write("#declare %s_Target= vrotate(<%.6g,%.6g,%.6g>,<%.4g,%.4g,%.4g>);\n" % \
-            # (povdataname, -(ob.location.x+0.1), -(ob.location.y+0.1), -(ob.location.z+0.1),
-            # ob.rotation_euler.x, ob.rotation_euler.y, ob.rotation_euler.z))
-
-            direction = (
-                ob.location.x,
-                ob.location.y,
-                ob.location.z,
-            )  # not taking matrix into account
-            rmatrix = global_matrix @ ob.matrix_world
-
-            # ob.rotation_euler.to_matrix().to_4x4() * mathutils.Vector((0,0,1))
-            # XXX Is result of the below offset by 90 degrees?
-            up = ob.matrix_world.to_3x3()[1].xyz  # * global_matrix
-
-            # XXX TO CHANGE:
-            # formerly:
-            # tabWrite("#declare %s = rainbow {\n"%povdataname)
-
-            # clumsy for now but remove the rainbow from instancing
-            # system because not an object. use lamps later instead of meshes
-
-            # del data_ref[dataname]
-            tabWrite("rainbow {\n")
-
-            tabWrite("angle %.4f\n" % angle)
-            tabWrite("width %.4f\n" % width)
-            tabWrite("distance %.4f\n" % distance)
-            tabWrite("arc_angle %.4f\n" % ob.pov.arc_angle)
-            tabWrite("falloff_angle %.4f\n" % ob.pov.falloff_angle)
-            tabWrite("direction <%.4f,%.4f,%.4f>\n" % rmatrix.translation[:])
-            tabWrite("up <%.4f,%.4f,%.4f>\n" % (up[0], up[1], up[2]))
-            tabWrite("color_map {\n")
-            tabWrite("[0.000  color srgbt<1.0, 0.5, 1.0, 1.0>]\n")
-            tabWrite("[0.130  color srgbt<0.5, 0.5, 1.0, 0.9>]\n")
-            tabWrite("[0.298  color srgbt<0.2, 0.2, 1.0, 0.7>]\n")
-            tabWrite("[0.412  color srgbt<0.2, 1.0, 1.0, 0.4>]\n")
-            tabWrite("[0.526  color srgbt<0.2, 1.0, 0.2, 0.4>]\n")
-            tabWrite("[0.640  color srgbt<1.0, 1.0, 0.2, 0.4>]\n")
-            tabWrite("[0.754  color srgbt<1.0, 0.5, 0.2, 0.6>]\n")
-            tabWrite("[0.900  color srgbt<1.0, 0.2, 0.2, 0.7>]\n")
-            tabWrite("[1.000  color srgbt<1.0, 0.2, 0.2, 1.0>]\n")
-            tabWrite("}\n")
-
-            povMatName = "Default_texture"
-            # tabWrite("texture {%s}\n"%povMatName)
-            write_object_modifiers(scene, ob, file)
-            # tabWrite("rotate x*90\n")
-            # matrix = global_matrix @ ob.matrix_world
-            # writeMatrix(matrix)
-            tabWrite("}\n")
-            # continue #Don't render proxy mesh, skip to next object
-
-    ################################XXX LOFT, ETC.
-    def exportCurves(scene, ob):
-        """write all curves based POV primitives to exported file """
-        name_orig = "OB" + ob.name
-        dataname_orig = "DATA" + ob.data.name
-
-        name = string_strip_hyphen(bpy.path.clean_name(name_orig))
-        dataname = string_strip_hyphen(bpy.path.clean_name(dataname_orig))
-
-        global_matrix = mathutils.Matrix.Rotation(-pi / 2.0, 4, 'X')
-        matrix = global_matrix @ ob.matrix_world
-        bezier_sweep = False
-        if ob.pov.curveshape == 'sphere_sweep':
-            # inlined spheresweep macro, which itself calls Shapes.inc:
-            file.write('        #include "shapes.inc"\n')
-
-            file.write(
-                '        #macro Shape_Bezierpoints_Sphere_Sweep(_merge_shape, _resolution, _points_array, _radius_array)\n'
-            )
-            file.write('        //input adjusting and inspection\n')
-            file.write('        #if(_resolution <= 1)\n')
-            file.write('            #local res = 1;\n')
-            file.write('        #else\n')
-            file.write('            #local res = int(_resolution);\n')
-            file.write('        #end\n')
-            file.write(
-                '        #if(dimensions(_points_array) != 1 | dimensions(_radius_array) != 1)\n'
-            )
-            file.write('            #error ""\n')
-            file.write(
-                '        #elseif(div(dimension_size(_points_array,1),4) - dimension_size(_points_array,1)/4 != 0)\n'
-            )
-            file.write('            #error ""\n')
-            file.write(
-                '        #elseif(dimension_size(_points_array,1) != dimension_size(_radius_array,1))\n'
-            )
-            file.write('            #error ""\n')
-            file.write('        #else\n')
-            file.write(
-                '            #local n_of_seg = div(dimension_size(_points_array,1), 4);\n'
-            )
-            file.write('            #local ctrl_pts_array = array[n_of_seg]\n')
-            file.write('            #local ctrl_rs_array = array[n_of_seg]\n')
-            file.write('            #for(i, 0, n_of_seg-1)\n')
-            file.write(
-                '                #local ctrl_pts_array[i] = array[4] {_points_array[4*i], _points_array[4*i+1], _points_array[4*i+2], _points_array[4*i+3]}\n'
-            )
-            file.write(
-                '                #local ctrl_rs_array[i] = array[4] {abs(_radius_array[4*i]), abs(_radius_array[4*i+1]), abs(_radius_array[4*i+2]), abs(_radius_array[4*i+3])}\n'
-            )
-            file.write('            #end\n')
-            file.write('        #end\n')
-
-            file.write('        //drawing\n')
-            file.write('        #local mockup1 =\n')
-            file.write('        #if(_merge_shape) merge{ #else union{ #end\n')
-            file.write('            #for(i, 0, n_of_seg-1)\n')
-            file.write('                #local has_head = true;\n')
-            file.write('                #if(i = 0)\n')
-            file.write(
-                '                    #if(vlength(ctrl_pts_array[i][0]-ctrl_pts_array[n_of_seg-1][3]) = 0 & ctrl_rs_array[i][0]-ctrl_rs_array[n_of_seg-1][3] <= 0)\n'
-            )
-            file.write('                        #local has_head = false;\n')
-            file.write('                    #end\n')
-            file.write('                #else\n')
-            file.write(
-                '                    #if(vlength(ctrl_pts_array[i][0]-ctrl_pts_array[i-1][3]) = 0 & ctrl_rs_array[i][0]-ctrl_rs_array[i-1][3] <= 0)\n'
-            )
-            file.write('                        #local has_head = false;\n')
-            file.write('                    #end\n')
-            file.write('                #end\n')
-            file.write('                #if(has_head = true)\n')
-            file.write('                    sphere{\n')
-            file.write(
-                '                    ctrl_pts_array[i][0], ctrl_rs_array[i][0]\n'
-            )
-            file.write('                    }\n')
-            file.write('                #end\n')
-            file.write('                #local para_t = (1/2)/res;\n')
-            file.write(
-                '                #local this_point = ctrl_pts_array[i][0]*pow(1-para_t,3) + ctrl_pts_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_pts_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_pts_array[i][3]*pow(para_t,3);\n'
-            )
-            file.write(
-                '                #local this_radius = ctrl_rs_array[i][0]*pow(1-para_t,3) + ctrl_rs_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_rs_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_rs_array[i][3]*pow(para_t,3);\n'
-            )
-            file.write(
-                '                #if(vlength(this_point-ctrl_pts_array[i][0]) > abs(this_radius-ctrl_rs_array[i][0]))\n'
-            )
-            file.write('                    object{\n')
-            file.write(
-                '                    Connect_Spheres(ctrl_pts_array[i][0], ctrl_rs_array[i][0], this_point, this_radius)\n'
-            )
-            file.write('                    }\n')
-            file.write('                #end\n')
-            file.write('                sphere{\n')
-            file.write('                this_point, this_radius\n')
-            file.write('                }\n')
-            file.write('                #for(j, 1, res-1)\n')
-            file.write('                    #local last_point = this_point;\n')
-            file.write(
-                '                    #local last_radius = this_radius;\n'
-            )
-            file.write('                    #local para_t = (1/2+j)/res;\n')
-            file.write(
-                '                    #local this_point = ctrl_pts_array[i][0]*pow(1-para_t,3) + ctrl_pts_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_pts_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_pts_array[i][3]*pow(para_t,3);\n'
-            )
-            file.write(
-                '                    #local this_radius = ctrl_rs_array[i][0]*pow(1-para_t,3) + ctrl_rs_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_rs_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_rs_array[i][3]*pow(para_t,3);\n'
-            )
-            file.write(
-                '                    #if(vlength(this_point-last_point) > abs(this_radius-last_radius))\n'
-            )
-            file.write('                        object{\n')
-            file.write(
-                '                        Connect_Spheres(last_point, last_radius, this_point, this_radius)\n'
-            )
-            file.write('                        }\n')
-            file.write('                    #end\n')
-            file.write('                    sphere{\n')
-            file.write('                    this_point, this_radius\n')
-            file.write('                    }\n')
-            file.write('                #end\n')
-            file.write('                #local last_point = this_point;\n')
-            file.write('                #local last_radius = this_radius;\n')
-            file.write(
-                '                #local this_point = ctrl_pts_array[i][3];\n'
-            )
-            file.write(
-                '                #local this_radius = ctrl_rs_array[i][3];\n'
-            )
-            file.write(
-                '                #if(vlength(this_point-last_point) > abs(this_radius-last_radius))\n'
-            )
-            file.write('                    object{\n')
-            file.write(
-                '                    Connect_Spheres(last_point, last_radius, this_point, this_radius)\n'
-            )
-            file.write('                    }\n')
-            file.write('                #end\n')
-            file.write('                sphere{\n')
-            file.write('                this_point, this_radius\n')
-            file.write('                }\n')
-            file.write('            #end\n')
-            file.write('        }\n')
-            file.write('        mockup1\n')
-            file.write('        #end\n')
-
-            for spl in ob.data.splines:
-                if spl.type == "BEZIER":
-                    bezier_sweep = True
-        if ob.pov.curveshape in {'loft', 'birail'}:
-            n = 0
-            for spline in ob.data.splines:
-                n += 1
-                tabWrite('#declare %s%s=spline {\n' % (dataname, n))
-                tabWrite('cubic_spline\n')
-                lp = len(spline.points)
-                delta = 1 / (lp)
-                d = -delta
-                point = spline.points[lp - 1]
-                x, y, z, w = point.co[:]
-                tabWrite('%.6f, <%.6f,%.6f,%.6f>\n' % (d, x, y, z))
-                d += delta
-                for point in spline.points:
-                    x, y, z, w = point.co[:]
-                    tabWrite('%.6f, <%.6f,%.6f,%.6f>\n' % (d, x, y, z))
-                    d += delta
-                for i in range(2):
-                    point = spline.points[i]
-                    x, y, z, w = point.co[:]
-                    tabWrite('%.6f, <%.6f,%.6f,%.6f>\n' % (d, x, y, z))
-                    d += delta
-                tabWrite('}\n')
-            if ob.pov.curveshape in {'loft'}:
-                n = len(ob.data.splines)
-                tabWrite('#declare %s = array[%s]{\n' % (dataname, (n + 3)))
-                tabWrite('spline{%s%s},\n' % (dataname, n))
-                for i in range(n):
-                    tabWrite('spline{%s%s},\n' % (dataname, (i + 1)))
-                tabWrite('spline{%s1},\n' % (dataname))
-                tabWrite('spline{%s2}\n' % (dataname))
-                tabWrite('}\n')
-            # Use some of the Meshmaker.inc macro, here inlined
-            file.write('#macro CheckFileName(FileName)\n')
-            file.write('   #local Len=strlen(FileName);\n')
-            file.write('   #if(Len>0)\n')
-            file.write('      #if(file_exists(FileName))\n')
-            file.write('         #if(Len>=4)\n')
-            file.write(
-                '            #local Ext=strlwr(substr(FileName,Len-3,4))\n'
-            )
-            file.write(
-                '            #if (strcmp(Ext,".obj")=0 | strcmp(Ext,".pcm")=0 | strcmp(Ext,".arr")=0)\n'
-            )
-            file.write('               #local Return=99;\n')
-            file.write('            #else\n')
-            file.write('               #local Return=0;\n')
-            file.write('            #end\n')
-            file.write('         #else\n')
-            file.write('            #local Return=0;\n')
-            file.write('         #end\n')
-            file.write('      #else\n')
-            file.write('         #if(Len>=4)\n')
-            file.write(
-                '            #local Ext=strlwr(substr(FileName,Len-3,4))\n'
-            )
-            file.write(
-                '            #if (strcmp(Ext,".obj")=0 | strcmp(Ext,".pcm")=0 | strcmp(Ext,".arr")=0)\n'
-            )
-            file.write('               #if (strcmp(Ext,".obj")=0)\n')
-            file.write('                  #local Return=2;\n')
-            file.write('               #end\n')
-            file.write('               #if (strcmp(Ext,".pcm")=0)\n')
-            file.write('                  #local Return=3;\n')
-            file.write('               #end\n')
-            file.write('               #if (strcmp(Ext,".arr")=0)\n')
-            file.write('                  #local Return=4;\n')
-            file.write('               #end\n')
-            file.write('            #else\n')
-            file.write('               #local Return=1;\n')
-            file.write('            #end\n')
-            file.write('         #else\n')
-            file.write('            #local Return=1;\n')
-            file.write('         #end\n')
-            file.write('      #end\n')
-            file.write('   #else\n')
-            file.write('      #local Return=1;\n')
-            file.write('   #end\n')
-            file.write('   (Return)\n')
-            file.write('#end\n')
-
-            file.write('#macro BuildSpline(Arr, SplType)\n')
-            file.write('   #local Ds=dimension_size(Arr,1);\n')
-            file.write('   #local Asc=asc(strupr(SplType));\n')
-            file.write('   #if(Asc!=67 & Asc!=76 & Asc!=81) \n')
-            file.write('      #local Asc=76;\n')
-            file.write(
-                '      #debug "\nWrong spline type defined (C/c/L/l/N/n/Q/q), using default linear_spline\\n"\n'
-            )
-            file.write('   #end\n')
-            file.write('   spline {\n')
-            file.write('      #switch (Asc)\n')
-            file.write('         #case (67) //C  cubic_spline\n')
-            file.write('            cubic_spline\n')
-            file.write('         #break\n')
-            file.write('         #case (76) //L  linear_spline\n')
-            file.write('            linear_spline\n')
-            file.write('         #break\n')
-            file.write('         #case (78) //N  linear_spline\n')
-            file.write('            natural_spline\n')
-            file.write('         #break\n')
-            file.write('         #case (81) //Q  Quadratic_spline\n')
-            file.write('            quadratic_spline\n')
-            file.write('         #break\n')
-            file.write('      #end\n')
-            file.write('      #local Add=1/((Ds-2)-1);\n')
-            file.write('      #local J=0-Add;\n')
-            file.write('      #local I=0;\n')
-            file.write('      #while (I<Ds)\n')
-            file.write('         J\n')
-            file.write('         Arr[I]\n')
-            file.write('         #local I=I+1;\n')
-            file.write('         #local J=J+Add;\n')
-            file.write('      #end\n')
-            file.write('   }\n')
-            file.write('#end\n')
-
-            file.write(
-                '#macro BuildWriteMesh2(VecArr, NormArr, UVArr, U, V, FileName)\n'
-            )
-            # suppressed some file checking from original macro because no more separate files
-            file.write(' #local Write=0;\n')
-            file.write(
-                ' #debug concat("\\n\\n Building mesh2: \\n   - vertex_vectors\\n")\n'
-            )
-            file.write('  #local NumVertices=dimension_size(VecArr,1);\n')
-            file.write('  #switch (Write)\n')
-            file.write('     #case(1)\n')
-            file.write('        #write(\n')
-            file.write('           MeshFile,\n')
-            file.write('           "  vertex_vectors {\\n",\n')
-            file.write('           "    ", str(NumVertices,0,0),"\\n    "\n')
-            file.write('        )\n')
-            file.write('     #break\n')
-            file.write('     #case(2)\n')
-            file.write('        #write(\n')
-            file.write('           MeshFile,\n')
-            file.write('           "# Vertices: ",str(NumVertices,0,0),"\\n"\n')
-            file.write('        )\n')
-            file.write('     #break\n')
-            file.write('     #case(3)\n')
-            file.write('        #write(\n')
-            file.write('           MeshFile,\n')
-            file.write('           str(2*NumVertices,0,0),",\\n"\n')
-            file.write('        )\n')
-            file.write('     #break\n')
-            file.write('     #case(4)\n')
-            file.write('        #write(\n')
-            file.write('           MeshFile,\n')
-            file.write(
-                '           "#declare VertexVectors= array[",str(NumVertices,0,0),"] {\\n  "\n'
-            )
-            file.write('        )\n')
-            file.write('     #break\n')
-            file.write('  #end\n')
-            file.write('  mesh2 {\n')
-            file.write('     vertex_vectors {\n')
-            file.write('        NumVertices\n')
-            file.write('        #local I=0;\n')
-            file.write('        #while (I<NumVertices)\n')
-            file.write('           VecArr[I]\n')
-            file.write('           #switch(Write)\n')
-            file.write('              #case(1)\n')
-            file.write('                 #write(MeshFile, VecArr[I])\n')
-            file.write('              #break\n')
-            file.write('              #case(2)\n')
-            file.write('                 #write(\n')
-            file.write('                    MeshFile,\n')
-            file.write(
-                '                    "v ", VecArr[I].x," ", VecArr[I].y," ", VecArr[I].z,"\\n"\n'
-            )
-            file.write('                 )\n')
-            file.write('              #break\n')
-            file.write('              #case(3)\n')
-            file.write('                 #write(\n')
-            file.write('                    MeshFile,\n')
-            file.write(
-                '                    VecArr[I].x,",", VecArr[I].y,",", VecArr[I].z,",\\n"\n'
-            )
-            file.write('                 )\n')
-            file.write('              #break\n')
-            file.write('              #case(4)\n')
-            file.write('                 #write(MeshFile, VecArr[I])\n')
-            file.write('              #break\n')
-            file.write('           #end\n')
-            file.write('           #local I=I+1;\n')
-            file.write('           #if(Write=1 | Write=4)\n')
-            file.write('              #if(mod(I,3)=0)\n')
-            file.write('                 #write(MeshFile,"\\n    ")\n')
-            file.write('              #end\n')
-            file.write('           #end \n')
-            file.write('        #end\n')
-            file.write('        #switch(Write)\n')
-            file.write('           #case(1)\n')
-            file.write('              #write(MeshFile,"\\n  }\\n")\n')
-            file.write('           #break\n')
-            file.write('           #case(2)\n')
-            file.write('              #write(MeshFile,"\\n")\n')
-            file.write('           #break\n')
-            file.write('           #case(3)\n')
-            file.write('              // do nothing\n')
-            file.write('           #break\n')
-            file.write('           #case(4) \n')
-            file.write('              #write(MeshFile,"\\n}\\n")\n')
-            file.write('           #break\n')
-            file.write('        #end\n')
-            file.write('     }\n')
-
-            file.write('     #debug concat("   - normal_vectors\\n")    \n')
-            file.write('     #local NumVertices=dimension_size(NormArr,1);\n')
-            file.write('     #switch(Write)\n')
-            file.write('        #case(1)\n')
-            file.write('           #write(\n')
-            file.write('              MeshFile,\n')
-            file.write('              "  normal_vectors {\\n",\n')
-            file.write('              "    ", str(NumVertices,0,0),"\\n    "\n')
-            file.write('           )\n')
-            file.write('        #break\n')
-            file.write('        #case(2)\n')
-            file.write('           #write(\n')
-            file.write('              MeshFile,\n')
-            file.write(
-                '              "# Normals: ",str(NumVertices,0,0),"\\n"\n'
-            )
-            file.write('           )\n')
-            file.write('        #break\n')
-            file.write('        #case(3)\n')
-            file.write('           // do nothing\n')
-            file.write('        #break\n')
-            file.write('        #case(4)\n')
-            file.write('           #write(\n')
-            file.write('              MeshFile,\n')
-            file.write(
-                '              "#declare NormalVectors= array[",str(NumVertices,0,0),"] {\\n  "\n'
-            )
-            file.write('           )\n')
-            file.write('        #break\n')
-            file.write('     #end\n')
-            file.write('     normal_vectors {\n')
-            file.write('        NumVertices\n')
-            file.write('        #local I=0;\n')
-            file.write('        #while (I<NumVertices)\n')
-            file.write('           NormArr[I]\n')
-            file.write('           #switch(Write)\n')
-            file.write('              #case(1)\n')
-            file.write('                 #write(MeshFile NormArr[I])\n')
-            file.write('              #break\n')
-            file.write('              #case(2)\n')
-            file.write('                 #write(\n')
-            file.write('                    MeshFile,\n')
-            file.write(
-                '                    "vn ", NormArr[I].x," ", NormArr[I].y," ", NormArr[I].z,"\\n"\n'
-            )
-            file.write('                 )\n')
-            file.write('              #break\n')
-            file.write('              #case(3)\n')
-            file.write('                 #write(\n')
-            file.write('                    MeshFile,\n')
-            file.write(
-                '                    NormArr[I].x,",", NormArr[I].y,",", NormArr[I].z,",\\n"\n'
-            )
-            file.write('                 )\n')
-            file.write('              #break\n')
-            file.write('              #case(4)\n')
-            file.write('                 #write(MeshFile NormArr[I])\n')
-            file.write('              #break\n')
-            file.write('           #end\n')
-            file.write('           #local I=I+1;\n')
-            file.write('           #if(Write=1 | Write=4) \n')
-            file.write('              #if(mod(I,3)=0)\n')
-            file.write('                 #write(MeshFile,"\\n    ")\n')
-            file.write('              #end\n')
-            file.write('           #end\n')
-            file.write('        #end\n')
-            file.write('        #switch(Write)\n')
-            file.write('           #case(1)\n')
-            file.write('              #write(MeshFile,"\\n  }\\n")\n')
-            file.write('           #break\n')
-            file.write('           #case(2)\n')
-            file.write('              #write(MeshFile,"\\n")\n')
-            file.write('           #break\n')
-            file.write('           #case(3)\n')
-            file.write('              //do nothing\n')
-            file.write('           #break\n')
-            file.write('           #case(4)\n')
-            file.write('              #write(MeshFile,"\\n}\\n")\n')
-            file.write('           #break\n')
-            file.write('        #end\n')
-            file.write('     }\n')
-
-            file.write('     #debug concat("   - uv_vectors\\n")   \n')
-            file.write('     #local NumVertices=dimension_size(UVArr,1);\n')
-            file.write('     #switch(Write)\n')
-            file.write('        #case(1)\n')
-            file.write('           #write(\n')
-            file.write('              MeshFile, \n')
-            file.write('              "  uv_vectors {\\n",\n')
-            file.write('              "    ", str(NumVertices,0,0),"\\n    "\n')
-            file.write('           )\n')
-            file.write('         #break\n')
-            file.write('         #case(2)\n')
-            file.write('           #write(\n')
-            file.write('              MeshFile,\n')
-            file.write(
-                '              "# UV-vectors: ",str(NumVertices,0,0),"\\n"\n'
-            )
-            file.write('           )\n')
-            file.write('         #break\n')
-            file.write('         #case(3)\n')
-            file.write(
-                '           // do nothing, *.pcm does not support uv-vectors\n'
-            )
-            file.write('         #break\n')
-            file.write('         #case(4)\n')
-            file.write('            #write(\n')
-            file.write('               MeshFile,\n')
-            file.write(
-                '               "#declare UVVectors= array[",str(NumVertices,0,0),"] {\\n  "\n'
-            )
-            file.write('            )\n')
-            file.write('         #break\n')
-            file.write('     #end\n')
-            file.write('     uv_vectors {\n')
-            file.write('        NumVertices\n')
-            file.write('        #local I=0;\n')
-            file.write('        #while (I<NumVertices)\n')
-            file.write('           UVArr[I]\n')
-            file.write('           #switch(Write)\n')
-            file.write('              #case(1)\n')
-            file.write('                 #write(MeshFile UVArr[I])\n')
-            file.write('              #break\n')
-            file.write('              #case(2)\n')
-            file.write('                 #write(\n')
-            file.write('                    MeshFile,\n')
-            file.write(
-                '                    "vt ", UVArr[I].u," ", UVArr[I].v,"\\n"\n'
-            )
-            file.write('                 )\n')
-            file.write('              #break\n')
-            file.write('              #case(3)\n')
-            file.write('                 //do nothing\n')
-            file.write('              #break\n')
-            file.write('              #case(4)\n')
-            file.write('                 #write(MeshFile UVArr[I])\n')
-            file.write('              #break\n')
-            file.write('           #end\n')
-            file.write('           #local I=I+1; \n')
-            file.write('           #if(Write=1 | Write=4)\n')
-            file.write('              #if(mod(I,3)=0)\n')
-            file.write('                 #write(MeshFile,"\\n    ")\n')
-            file.write('              #end \n')
-            file.write('           #end\n')
-            file.write('        #end \n')
-            file.write('        #switch(Write)\n')
-            file.write('           #case(1)\n')
-            file.write('              #write(MeshFile,"\\n  }\\n")\n')
-            file.write('           #break\n')
-            file.write('           #case(2)\n')
-            file.write('              #write(MeshFile,"\\n")\n')
-            file.write('           #break\n')
-            file.write('           #case(3)\n')
-            file.write('              //do nothing\n')
-            file.write('           #break\n')
-            file.write('           #case(4)\n')
-            file.write('              #write(MeshFile,"\\n}\\n")\n')
-            file.write('           #break\n')
-            file.write('        #end\n')
-            file.write('     }\n')
-            file.write('\n')
-            file.write('     #debug concat("   - face_indices\\n")   \n')
-            file.write('     #declare NumFaces=U*V*2;\n')
-            file.write('     #switch(Write)\n')
-            file.write('        #case(1)\n')
-            file.write('           #write(\n')
-            file.write('              MeshFile,\n')
-            file.write('              "  face_indices {\\n"\n')
-            file.write('              "    ", str(NumFaces,0,0),"\\n    "\n')
-            file.write('           )\n')
-            file.write('        #break\n')
-            file.write('        #case(2)\n')
-            file.write('           #write (\n')
-            file.write('              MeshFile,\n')
-            file.write('              "# faces: ",str(NumFaces,0,0),"\\n"\n')
-            file.write('           )\n')
-            file.write('        #break\n')
-            file.write('        #case(3)\n')
-            file.write('           #write (\n')
-            file.write('              MeshFile,\n')
-            file.write('              "0,",str(NumFaces,0,0),",\\n"\n')
-            file.write('           )\n')
-            file.write('        #break\n')
-            file.write('        #case(4)\n')
-            file.write('           #write(\n')
-            file.write('              MeshFile,\n')
-            file.write(
-                '              "#declare FaceIndices= array[",str(NumFaces,0,0),"] {\\n  "\n'
-            )
-            file.write('           )\n')
-            file.write('        #break\n')
-            file.write('     #end\n')
-            file.write('     face_indices {\n')
-            file.write('        NumFaces\n')
-            file.write('        #local I=0;\n')
-            file.write('        #local H=0;\n')
-            file.write('        #local NumVertices=dimension_size(VecArr,1);\n')
-            file.write('        #while (I<V)\n')
-            file.write('           #local J=0;\n')
-            file.write('           #while (J<U)\n')
-            file.write('              #local Ind=(I*U)+I+J;\n')
-            file.write(
-                '              <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n'
-            )
-            file.write('              #switch(Write)\n')
-            file.write('                 #case(1)\n')
-            file.write('                    #write(\n')
-            file.write('                       MeshFile,\n')
-            file.write(
-                '                       <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n'
-            )
-            file.write('                    )\n')
-            file.write('                 #break\n')
-            file.write('                 #case(2)\n')
-            file.write('                    #write(\n')
-            file.write('                       MeshFile,\n')
-            file.write(
-                '                       "f ",Ind+1,"/",Ind+1,"/",Ind+1," ",Ind+1+1,"/",Ind+1+1,"/",Ind+1+1," ",Ind+U+2+1,"/",Ind+U+2+1,"/",Ind+U+2+1,"\\n",\n'
-            )
-            file.write(
-                '                       "f ",Ind+U+1+1,"/",Ind+U+1+1,"/",Ind+U+1+1," ",Ind+1,"/",Ind+1,"/",Ind+1," ",Ind+U+2+1,"/",Ind+U+2+1,"/",Ind+U+2+1,"\\n"\n'
-            )
-            file.write('                    )\n')
-            file.write('                 #break\n')
-            file.write('                 #case(3)\n')
-            file.write('                    #write(\n')
-            file.write('                       MeshFile,\n')
-            file.write(
-                '                       Ind,",",Ind+NumVertices,",",Ind+1,",",Ind+1+NumVertices,",",Ind+U+2,",",Ind+U+2+NumVertices,",\\n"\n'
-            )
-            file.write(
-                '                       Ind+U+1,",",Ind+U+1+NumVertices,",",Ind,",",Ind+NumVertices,",",Ind+U+2,",",Ind+U+2+NumVertices,",\\n"\n'
-            )
-            file.write('                    )\n')
-            file.write('                 #break\n')
-            file.write('                 #case(4)\n')
-            file.write('                    #write(\n')
-            file.write('                       MeshFile,\n')
-            file.write(
-                '                       <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n'
-            )
-            file.write('                    )\n')
-            file.write('                 #break\n')
-            file.write('              #end\n')
-            file.write('              #local J=J+1;\n')
-            file.write('              #local H=H+1;\n')
-            file.write('              #if(Write=1 | Write=4)\n')
-            file.write('                 #if(mod(H,3)=0)\n')
-            file.write('                    #write(MeshFile,"\\n    ")\n')
-            file.write('                 #end \n')
-            file.write('              #end\n')
-            file.write('           #end\n')
-            file.write('           #local I=I+1;\n')
-            file.write('        #end\n')
-            file.write('     }\n')
-            file.write('     #switch(Write)\n')
-            file.write('        #case(1)\n')
-            file.write('           #write(MeshFile, "\\n  }\\n}")\n')
-            file.write('           #fclose MeshFile\n')
-            file.write('           #debug concat(" Done writing\\n")\n')
-            file.write('        #break\n')
-            file.write('        #case(2)\n')
-            file.write('           #fclose MeshFile\n')
-            file.write('           #debug concat(" Done writing\\n")\n')
-            file.write('        #break\n')
-            file.write('        #case(3)\n')
-            file.write('           #fclose MeshFile\n')
-            file.write('           #debug concat(" Done writing\\n")\n')
-            file.write('        #break\n')
-            file.write('        #case(4)\n')
-            file.write('           #write(MeshFile, "\\n}\\n}")\n')
-            file.write('           #fclose MeshFile\n')
-            file.write('           #debug concat(" Done writing\\n")\n')
-            file.write('        #break\n')
-            file.write('     #end\n')
-            file.write('  }\n')
-            file.write('#end\n')
-
-            file.write(
-                '#macro MSM(SplineArray, SplRes, Interp_type,  InterpRes, FileName)\n'
-            )
-            file.write('    #declare Build=CheckFileName(FileName);\n')
-            file.write('    #if(Build=0)\n')
-            file.write(
-                '        #debug concat("\\n Parsing mesh2 from file: ", FileName, "\\n")\n'
-            )
-            file.write('        #include FileName\n')
-            file.write('        object{Surface}\n')
-            file.write('    #else\n')
-            file.write('        #local NumVertices=(SplRes+1)*(InterpRes+1);\n')
-            file.write('        #local NumFaces=SplRes*InterpRes*2;\n')
-            file.write(
-                '        #debug concat("\\n Calculating ",str(NumVertices,0,0)," vertices for ", str(NumFaces,0,0)," triangles\\n\\n")\n'
-            )
-            file.write('        #local VecArr=array[NumVertices]\n')
-            file.write('        #local NormArr=array[NumVertices]\n')
-            file.write('        #local UVArr=array[NumVertices]\n')
-            file.write('        #local N=dimension_size(SplineArray,1);\n')
-            file.write('        #local TempSplArr0=array[N];\n')
-            file.write('        #local TempSplArr1=array[N];\n')
-            file.write('        #local TempSplArr2=array[N];\n')
-            file.write('        #local PosStep=1/SplRes;\n')
-            file.write('        #local InterpStep=1/InterpRes;\n')
-            file.write('        #local Count=0;\n')
-            file.write('        #local Pos=0;\n')
-            file.write('        #while(Pos<=1)\n')
-            file.write('            #local I=0;\n')
-            file.write('            #if (Pos=0)\n')
-            file.write('                #while (I<N)\n')
-            file.write(
-                '                    #local Spl=spline{SplineArray[I]}\n'
-            )
-            file.write(
-                '                    #local TempSplArr0[I]=<0,0,0>+Spl(Pos);\n'
-            )
-            file.write(
-                '                    #local TempSplArr1[I]=<0,0,0>+Spl(Pos+PosStep);\n'
-            )
-            file.write(
-                '                    #local TempSplArr2[I]=<0,0,0>+Spl(Pos-PosStep);\n'
-            )
-            file.write('                    #local I=I+1;\n')
-            file.write('                #end\n')
-            file.write(
-                '                #local S0=BuildSpline(TempSplArr0, Interp_type)\n'
-            )
-            file.write(
-                '                #local S1=BuildSpline(TempSplArr1, Interp_type)\n'
-            )
-            file.write(
-                '                #local S2=BuildSpline(TempSplArr2, Interp_type)\n'
-            )
-            file.write('            #else\n')
-            file.write('                #while (I<N)\n')
-            file.write(
-                '                    #local Spl=spline{SplineArray[I]}\n'
-            )
-            file.write(
-                '                    #local TempSplArr1[I]=<0,0,0>+Spl(Pos+PosStep);\n'
-            )
-            file.write('                    #local I=I+1;\n')
-            file.write('                #end\n')
-            file.write(
-                '                #local S1=BuildSpline(TempSplArr1, Interp_type)\n'
-            )
-            file.write('            #end\n')
-            file.write('            #local J=0;\n')
-            file.write('            #while (J<=1)\n')
-            file.write('                #local P0=<0,0,0>+S0(J);\n')
-            file.write('                #local P1=<0,0,0>+S1(J);\n')
-            file.write('                #local P2=<0,0,0>+S2(J);\n')
-            file.write('                #local P3=<0,0,0>+S0(J+InterpStep);\n')
-            file.write('                #local P4=<0,0,0>+S0(J-InterpStep);\n')
-            file.write('                #local B1=P4-P0;\n')
-            file.write('                #local B2=P2-P0;\n')
-            file.write('                #local B3=P3-P0;\n')
-            file.write('                #local B4=P1-P0;\n')
-            file.write('                #local N1=vcross(B1,B2);\n')
-            file.write('                #local N2=vcross(B2,B3);\n')
-            file.write('                #local N3=vcross(B3,B4);\n')
-            file.write('                #local N4=vcross(B4,B1);\n')
-            file.write(
-                '                #local Norm=vnormalize((N1+N2+N3+N4));\n'
-            )
-            file.write('                #local VecArr[Count]=P0;\n')
-            file.write('                #local NormArr[Count]=Norm;\n')
-            file.write('                #local UVArr[Count]=<J,Pos>;\n')
-            file.write('                #local J=J+InterpStep;\n')
-            file.write('                #local Count=Count+1;\n')
-            file.write('            #end\n')
-            file.write('            #local S2=spline{S0}\n')
-            file.write('            #local S0=spline{S1}\n')
-            file.write(
-                '            #debug concat("\\r Done ", str(Count,0,0)," vertices : ", str(100*Count/NumVertices,0,2)," %")\n'
-            )
-            file.write('            #local Pos=Pos+PosStep;\n')
-            file.write('        #end\n')
-            file.write(
-                '        BuildWriteMesh2(VecArr, NormArr, UVArr, InterpRes, SplRes, "")\n'
-            )
-            file.write('    #end\n')
-            file.write('#end\n\n')
-
-            file.write(
-                '#macro Coons(Spl1, Spl2, Spl3, Spl4, Iter_U, Iter_V, FileName)\n'
-            )
-            file.write('   #declare Build=CheckFileName(FileName);\n')
-            file.write('   #if(Build=0)\n')
-            file.write(
-                '      #debug concat("\\n Parsing mesh2 from file: ", FileName, "\\n")\n'
-            )
-            file.write('      #include FileName\n')
-            file.write('      object{Surface}\n')
-            file.write('   #else\n')
-            file.write('      #local NumVertices=(Iter_U+1)*(Iter_V+1);\n')
-            file.write('      #local NumFaces=Iter_U*Iter_V*2;\n')
-            file.write(
-                '      #debug concat("\\n Calculating ", str(NumVertices,0,0), " vertices for ",str(NumFaces,0,0), " triangles\\n\\n")\n'
-            )
-            file.write('      #declare VecArr=array[NumVertices]   \n')
-            file.write('      #declare NormArr=array[NumVertices]   \n')
-            file.write('      #local UVArr=array[NumVertices]      \n')
-            file.write('      #local Spl1_0=Spl1(0);\n')
-            file.write('      #local Spl2_0=Spl2(0);\n')
-            file.write('      #local Spl3_0=Spl3(0);\n')
-            file.write('      #local Spl4_0=Spl4(0);\n')
-            file.write('      #local UStep=1/Iter_U;\n')
-            file.write('      #local VStep=1/Iter_V;\n')
-            file.write('      #local Count=0;\n')
-            file.write('      #local I=0;\n')
-            file.write('      #while (I<=1)\n')
-            file.write('         #local Im=1-I;\n')
-            file.write('         #local J=0;\n')
-            file.write('         #while (J<=1)\n')
-            file.write('            #local Jm=1-J;\n')
-            file.write(
-                '            #local C0=Im*Jm*(Spl1_0)+Im*J*(Spl2_0)+I*J*(Spl3_0)+I*Jm*(Spl4_0);\n'
-            )
-            file.write(
-                '            #local P0=LInterpolate(I, Spl1(J), Spl3(Jm)) + \n'
-            )
-            file.write(
-                '               LInterpolate(Jm, Spl2(I), Spl4(Im))-C0;\n'
-            )
-            file.write('            #declare VecArr[Count]=P0;\n')
-            file.write('            #local UVArr[Count]=<J,I>;\n')
-            file.write('            #local J=J+UStep;\n')
-            file.write('            #local Count=Count+1;\n')
-            file.write('         #end\n')
-            file.write('         #debug concat(\n')
-            file.write(
-                '            "\r Done ", str(Count,0,0)," vertices :         ",\n'
-            )
-            file.write('            str(100*Count/NumVertices,0,2)," %"\n')
-            file.write('         )\n')
-            file.write('         #local I=I+VStep;\n')
-            file.write('      #end\n')
-            file.write(
-                '      #debug "\r Normals                                  "\n'
-            )
-            file.write('      #local Count=0;\n')
-            file.write('      #local I=0;\n')
-            file.write('      #while (I<=Iter_V)\n')
-            file.write('         #local J=0;\n')
-            file.write('         #while (J<=Iter_U)\n')
-            file.write('            #local Ind=(I*Iter_U)+I+J;\n')
-            file.write('            #local P0=VecArr[Ind];\n')
-            file.write('            #if(J=0)\n')
-            file.write('               #local P1=P0+(P0-VecArr[Ind+1]);\n')
-            file.write('            #else\n')
-            file.write('               #local P1=VecArr[Ind-1];\n')
-            file.write('            #end\n')
-            file.write('            #if (J=Iter_U)\n')
-            file.write('               #local P2=P0+(P0-VecArr[Ind-1]);\n')
-            file.write('            #else\n')
-            file.write('               #local P2=VecArr[Ind+1];\n')
-            file.write('            #end\n')
-            file.write('            #if (I=0)\n')
-            file.write(
-                '               #local P3=P0+(P0-VecArr[Ind+Iter_U+1]);\n'
-            )
-            file.write('            #else\n')
-            file.write('               #local P3=VecArr[Ind-Iter_U-1];\n')
-            file.write('            #end\n')
-            file.write('            #if (I=Iter_V)\n')
-            file.write(
-                '               #local P4=P0+(P0-VecArr[Ind-Iter_U-1]);\n'
-            )
-            file.write('            #else\n')
-            file.write('               #local P4=VecArr[Ind+Iter_U+1];\n')
-            file.write('            #end\n')
-            file.write('            #local B1=P4-P0;\n')
-            file.write('            #local B2=P2-P0;\n')
-            file.write('            #local B3=P3-P0;\n')
-            file.write('            #local B4=P1-P0;\n')
-            file.write('            #local N1=vcross(B1,B2);\n')
-            file.write('            #local N2=vcross(B2,B3);\n')
-            file.write('            #local N3=vcross(B3,B4);\n')
-            file.write('            #local N4=vcross(B4,B1);\n')
-            file.write('            #local Norm=vnormalize((N1+N2+N3+N4));\n')
-            file.write('            #declare NormArr[Count]=Norm;\n')
-            file.write('            #local J=J+1;\n')
-            file.write('            #local Count=Count+1;\n')
-            file.write('         #end\n')
-            file.write(
-                '         #debug concat("\r Done ", str(Count,0,0)," normals : ",str(100*Count/NumVertices,0,2), " %")\n'
-            )
-            file.write('         #local I=I+1;\n')
-            file.write('      #end\n')
-            file.write(
-                '      BuildWriteMesh2(VecArr, NormArr, UVArr, Iter_U, Iter_V, FileName)\n'
-            )
-            file.write('   #end\n')
-            file.write('#end\n\n')
-        # Empty curves
-        if len(ob.data.splines) == 0:
-            tabWrite("\n//dummy sphere to represent empty curve location\n")
-            tabWrite("#declare %s =\n" % dataname)
-            tabWrite(
-                "sphere {<%.6g, %.6g, %.6g>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n\n"
-                % (ob.location.x, ob.location.y, ob.location.z)
-            )  # ob.name > povdataname)
-        # And non empty curves
-        else:
-            if bezier_sweep == False:
-                tabWrite("#declare %s =\n" % dataname)
-            if ob.pov.curveshape == 'sphere_sweep' and bezier_sweep == False:
-                tabWrite("union {\n")
-                for spl in ob.data.splines:
-                    if spl.type != "BEZIER":
-                        spl_type = "linear"
-                        if spl.type == "NURBS":
-                            spl_type = "cubic"
-                        points = spl.points
-                        numPoints = len(points)
-                        if spl.use_cyclic_u:
-                            numPoints += 3
-
-                        tabWrite(
-                            "sphere_sweep { %s_spline %s,\n"
-                            % (spl_type, numPoints)
-                        )
-                        if spl.use_cyclic_u:
-                            pt1 = points[len(points) - 1]
-                            wpt1 = pt1.co
-                            tabWrite(
-                                "<%.4g,%.4g,%.4g>,%.4g\n"
-                                % (
-                                    wpt1[0],
-                                    wpt1[1],
-                                    wpt1[2],
-                                    pt1.radius * ob.data.bevel_depth,
-                                )
-                            )
-                        for pt in points:
-                            wpt = pt.co
-                            tabWrite(
-                                "<%.4g,%.4g,%.4g>,%.4g\n"
-                                % (
-                                    wpt[0],
-                                    wpt[1],
-                                    wpt[2],
-                                    pt.radius * ob.data.bevel_depth,
-                                )
-                            )
-                        if spl.use_cyclic_u:
-                            for i in range(0, 2):
-                                endPt = points[i]
-                                wpt = endPt.co
-                                tabWrite(
-                                    "<%.4g,%.4g,%.4g>,%.4g\n"
-                                    % (
-                                        wpt[0],
-                                        wpt[1],
-                                        wpt[2],
-                                        endPt.radius * ob.data.bevel_depth,
-                                    )
-                                )
-
-                    tabWrite("}\n")
-            # below not used yet?
-            if ob.pov.curveshape == 'sor':
-                for spl in ob.data.splines:
-                    if spl.type in {'POLY', 'NURBS'}:
-                        points = spl.points
-                        numPoints = len(points)
-                        tabWrite("sor { %s,\n" % numPoints)
-                        for pt in points:
-                            wpt = pt.co
-                            tabWrite("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
-                    else:
-                        tabWrite("box { 0,0\n")
-            if ob.pov.curveshape in {'lathe', 'prism'}:
-                spl = ob.data.splines[0]
-                if spl.type == "BEZIER":
-                    points = spl.bezier_points
-                    lenCur = len(points) - 1
-                    lenPts = lenCur * 4
-                    ifprism = ''
-                    if ob.pov.curveshape in {'prism'}:
-                        height = ob.data.extrude
-                        ifprism = '-%s, %s,' % (height, height)
-                        lenCur += 1
-                        lenPts += 4
-                    tabWrite(
-                        "%s { bezier_spline %s %s,\n"
-                        % (ob.pov.curveshape, ifprism, lenPts)
-                    )
-                    for i in range(0, lenCur):
-                        p1 = points[i].co
-                        pR = points[i].handle_right
-                        end = i + 1
-                        if i == lenCur - 1 and ob.pov.curveshape in {'prism'}:
-                            end = 0
-                        pL = points[end].handle_left
-                        p2 = points[end].co
-                        line = "<%.4g,%.4g>" % (p1[0], p1[1])
-                        line += "<%.4g,%.4g>" % (pR[0], pR[1])
-                        line += "<%.4g,%.4g>" % (pL[0], pL[1])
-                        line += "<%.4g,%.4g>" % (p2[0], p2[1])
-                        tabWrite("%s\n" % line)
-                else:
-                    points = spl.points
-                    lenCur = len(points)
-                    lenPts = lenCur
-                    ifprism = ''
-                    if ob.pov.curveshape in {'prism'}:
-                        height = ob.data.extrude
-                        ifprism = '-%s, %s,' % (height, height)
-                        lenPts += 3
-                    spl_type = 'quadratic'
-                    if spl.type == 'POLY':
-                        spl_type = 'linear'
-                    tabWrite(
-                        "%s { %s_spline %s %s,\n"
-                        % (ob.pov.curveshape, spl_type, ifprism, lenPts)
-                    )
-                    if ob.pov.curveshape in {'prism'}:
-                        pt = points[len(points) - 1]
-                        wpt = pt.co
-                        tabWrite("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
-                    for pt in points:
-                        wpt = pt.co
-                        tabWrite("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
-                    if ob.pov.curveshape in {'prism'}:
-                        for i in range(2):
-                            pt = points[i]
-                            wpt = pt.co
-                            tabWrite("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
-            if bezier_sweep:
-                for p in range(len(ob.data.splines)):
-                    br = []
-                    depth = ob.data.bevel_depth
-                    spl = ob.data.splines[p]
-                    points = spl.bezier_points
-                    lenCur = len(points) - 1
-                    numPoints = lenCur * 4
-                    if spl.use_cyclic_u:
-                        lenCur += 1
-                        numPoints += 4
-                    tabWrite(
-                        "#declare %s_points_%s = array[%s]{\n"
-                        % (dataname, p, numPoints)
-                    )
-                    for i in range(lenCur):
-                        p1 = points[i].co
-                        pR = points[i].handle_right
-                        end = i + 1
-                        if spl.use_cyclic_u and i == (lenCur - 1):
-                            end = 0
-                        pL = points[end].handle_left
-                        p2 = points[end].co
-                        r3 = points[end].radius * depth
-                        r0 = points[i].radius * depth
-                        r1 = 2 / 3 * r0 + 1 / 3 * r3
-                        r2 = 1 / 3 * r0 + 2 / 3 * r3
-                        br.append((r0, r1, r2, r3))
-                        line = "<%.4g,%.4g,%.4f>" % (p1[0], p1[1], p1[2])
-                        line += "<%.4g,%.4g,%.4f>" % (pR[0], pR[1], pR[2])
-                        line += "<%.4g,%.4g,%.4f>" % (pL[0], pL[1], pL[2])
-                        line += "<%.4g,%.4g,%.4f>" % (p2[0], p2[1], p2[2])
-                        tabWrite("%s\n" % line)
-                    tabWrite("}\n")
-                    tabWrite(
-                        "#declare %s_radii_%s = array[%s]{\n"
-                        % (dataname, p, len(br) * 4)
-                    )
-                    for Tuple in br:
-                        tabWrite(
-                            '%.4f,%.4f,%.4f,%.4f\n'
-                            % (Tuple[0], Tuple[1], Tuple[2], Tuple[3])
-                        )
-                    tabWrite("}\n")
-                if len(ob.data.splines) == 1:
-                    tabWrite('#declare %s = object{\n' % dataname)
-                    tabWrite(
-                        '    Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_points_%s, %s_radii_%s) \n'
-                        % (ob.data.resolution_u, dataname, p, dataname, p)
-                    )
-                else:
-                    tabWrite('#declare %s = union{\n' % dataname)
-                    for p in range(len(ob.data.splines)):
-                        tabWrite(
-                            '    object{Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_points_%s, %s_radii_%s)} \n'
-                            % (ob.data.resolution_u, dataname, p, dataname, p)
-                        )
-                    # tabWrite('#include "bezier_spheresweep.inc"\n') #now inlined
-                # tabWrite('#declare %s = object{Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_bezier_points, %.4f) \n'%(dataname,ob.data.resolution_u,dataname,ob.data.bevel_depth))
-            if ob.pov.curveshape in {'loft'}:
-                tabWrite(
-                    'object {MSM(%s,%s,"c",%s,"")\n'
-                    % (dataname, ob.pov.res_u, ob.pov.res_v)
-                )
-            if ob.pov.curveshape in {'birail'}:
-                splines = '%s1,%s2,%s3,%s4' % (
-                    dataname,
-                    dataname,
-                    dataname,
-                    dataname,
-                )
-                tabWrite(
-                    'object {Coons(%s, %s, %s, "")\n'
-                    % (splines, ob.pov.res_u, ob.pov.res_v)
-                )
-            povMatName = "Default_texture"
-            if ob.active_material:
-                # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
-                try:
-                    material = ob.active_material
-                    writeObjectMaterial(material, ob)
-                except IndexError:
-                    print(me)
-            # tabWrite("texture {%s}\n"%povMatName)
-            if ob.pov.curveshape in {'prism'}:
-                tabWrite("rotate <90,0,0>\n")
-                tabWrite("scale y*-1\n")
-            tabWrite("}\n")
-
     #################################################################
 
-    def exportMeta(metas):
+    def export_meta(metas):
         """write all POV blob primitives and Blender Metas to exported file """
         # TODO - blenders 'motherball' naming is not supported.
 
@@ -2052,8 +324,7 @@ def write_pov(filename, scene=None, info_callback=None):
             elems = [
                 (elem, ob)
                 for elem in ob.data.elements
-                if elem.type
-                in {'BALL', 'ELLIPSOID', 'CAPSULE', 'CUBE', 'PLANE'}
+                if elem.type in {'BALL', 'ELLIPSOID', 'CAPSULE', 'CUBE', 'PLANE'}
             ]
             if prefix in meta_elems:
                 meta_elems[prefix].extend(elems)
@@ -2062,19 +333,16 @@ def write_pov(filename, scene=None, info_callback=None):
 
             # empty metaball
             if len(elems) == 0:
-                tabWrite("\n//dummy sphere to represent empty meta location\n")
-                tabWrite(
+                tab_write("\n//dummy sphere to represent empty meta location\n")
+                tab_write(
                     "sphere {<%.6g, %.6g, %.6g>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n\n"
                     % (ob.location.x, ob.location.y, ob.location.z)
                 )  # ob.name > povdataname)
             # other metaballs
             else:
-                for mg, ob in meta_group.items():
+                for mg, mob in meta_group.items():
                     if len(meta_elems[mg]) != 0:
-                        tabWrite(
-                            "blob{threshold %.4g // %s \n"
-                            % (ob.data.threshold, mg)
-                        )
+                        tab_write("blob{threshold %.4g // %s \n" % (mob.data.threshold, mg))
                         for elems in meta_elems[mg]:
                             elem = elems[0]
                             loc = elem.co
@@ -2082,22 +350,14 @@ def write_pov(filename, scene=None, info_callback=None):
                             if elem.use_negative:
                                 stiffness = -stiffness
                             if elem.type == 'BALL':
-                                tabWrite(
+                                tab_write(
                                     "sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g "
-                                    % (
-                                        loc.x,
-                                        loc.y,
-                                        loc.z,
-                                        elem.radius,
-                                        stiffness,
-                                    )
+                                    % (loc.x, loc.y, loc.z, elem.radius, stiffness)
                                 )
-                                writeMatrix(
-                                    global_matrix @ elems[1].matrix_world
-                                )
-                                tabWrite("}\n")
+                                write_matrix(global_matrix @ elems[1].matrix_world)
+                                tab_write("}\n")
                             elif elem.type == 'ELLIPSOID':
-                                tabWrite(
+                                tab_write(
                                     "sphere{ <%.6g, %.6g, %.6g>,%.4g,%.4g "
                                     % (
                                         loc.x / elem.size_x,
@@ -2107,16 +367,14 @@ def write_pov(filename, scene=None, info_callback=None):
                                         stiffness,
                                     )
                                 )
-                                tabWrite(
+                                tab_write(
                                     "scale <%.6g, %.6g, %.6g>"
                                     % (elem.size_x, elem.size_y, elem.size_z)
                                 )
-                                writeMatrix(
-                                    global_matrix @ elems[1].matrix_world
-                                )
-                                tabWrite("}\n")
+                                write_matrix(global_matrix @ elems[1].matrix_world)
+                                tab_write("}\n")
                             elif elem.type == 'CAPSULE':
-                                tabWrite(
+                                tab_write(
                                     "cylinder{ <%.6g, %.6g, %.6g>,<%.6g, %.6g, %.6g>,%.4g,%.4g "
                                     % (
                                         (loc.x - elem.size_x),
@@ -2129,14 +387,12 @@ def write_pov(filename, scene=None, info_callback=None):
                                         stiffness,
                                     )
                                 )
-                                # tabWrite("scale <%.6g, %.6g, %.6g>" % (elem.size_x, elem.size_y, elem.size_z))
-                                writeMatrix(
-                                    global_matrix @ elems[1].matrix_world
-                                )
-                                tabWrite("}\n")
+                                # tab_write("scale <%.6g, %.6g, %.6g>" % (elem.size_x, elem.size_y, elem.size_z))
+                                write_matrix(global_matrix @ elems[1].matrix_world)
+                                tab_write("}\n")
 
                             elif elem.type == 'CUBE':
-                                tabWrite(
+                                tab_write(
                                     "cylinder { -x*8, +x*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale  <1/4,1,1> scale <%.6g, %.6g, %.6g>\n"
                                     % (
                                         elem.radius * 2.0,
@@ -2149,11 +405,9 @@ def write_pov(filename, scene=None, info_callback=None):
                                         elem.size_z,
                                     )
                                 )
-                                writeMatrix(
-                                    global_matrix @ elems[1].matrix_world
-                                )
-                                tabWrite("}\n")
-                                tabWrite(
+                                write_matrix(global_matrix @ elems[1].matrix_world)
+                                tab_write("}\n")
+                                tab_write(
                                     "cylinder { -y*8, +y*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1,1/4,1> scale <%.6g, %.6g, %.6g>\n"
                                     % (
                                         elem.radius * 2.0,
@@ -2166,11 +420,9 @@ def write_pov(filename, scene=None, info_callback=None):
                                         elem.size_z,
                                     )
                                 )
-                                writeMatrix(
-                                    global_matrix @ elems[1].matrix_world
-                                )
-                                tabWrite("}\n")
-                                tabWrite(
+                                write_matrix(global_matrix @ elems[1].matrix_world)
+                                tab_write("}\n")
+                                tab_write(
                                     "cylinder { -z*8, +z*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1,1,1/4> scale <%.6g, %.6g, %.6g>\n"
                                     % (
                                         elem.radius * 2.0,
@@ -2183,13 +435,11 @@ def write_pov(filename, scene=None, info_callback=None):
                                         elem.size_z,
                                     )
                                 )
-                                writeMatrix(
-                                    global_matrix @ elems[1].matrix_world
-                                )
-                                tabWrite("}\n")
+                                write_matrix(global_matrix @ elems[1].matrix_world)
+                                tab_write("}\n")
 
                             elif elem.type == 'PLANE':
-                                tabWrite(
+                                tab_write(
                                     "cylinder { -x*8, +x*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale  <1/4,1,1> scale <%.6g, %.6g, %.6g>\n"
                                     % (
                                         elem.radius * 2.0,
@@ -2202,11 +452,9 @@ def write_pov(filename, scene=None, info_callback=None):
                                         elem.size_z,
                                     )
                                 )
-                                writeMatrix(
-                                    global_matrix @ elems[1].matrix_world
-                                )
-                                tabWrite("}\n")
-                                tabWrite(
+                                write_matrix(global_matrix @ elems[1].matrix_world)
+                                tab_write("}\n")
+                                tab_write(
                                     "cylinder { -y*8, +y*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1,1/4,1> scale <%.6g, %.6g, %.6g>\n"
                                     % (
                                         elem.radius * 2.0,
@@ -2219,16 +467,16 @@ def write_pov(filename, scene=None, info_callback=None):
                                         elem.size_z,
                                     )
                                 )
-                                writeMatrix(
-                                    global_matrix @ elems[1].matrix_world
-                                )
-                                tabWrite("}\n")
+                                write_matrix(global_matrix @ elems[1].matrix_world)
+                                tab_write("}\n")
 
                         try:
                             material = elems[1].data.materials[
                                 0
                             ]  # lame! - blender cant do enything else.
-                        except:
+                        except BaseException as e:
+                            print(e.__doc__)
+                            print('An exception occurred: {}'.format(e))
                             material = None
                         if material:
                             diffuse_color = material.diffuse_color
@@ -2237,40 +485,34 @@ def write_pov(filename, scene=None, info_callback=None):
                                 material.use_transparency
                                 and material.transparency_method == 'RAYTRACE'
                             ):
-                                povFilter = (
-                                    material.pov_raytrace_transparency.filter
-                                    * (1.0 - material.alpha)
+                                pov_filter = material.pov_raytrace_transparency.filter * (
+                                    1.0 - material.alpha
                                 )
-                                trans = (1.0 - material.pov.alpha) - povFilter
+                                trans = (1.0 - material.pov.alpha) - pov_filter
                             else:
-                                povFilter = 0.0
-                            material_finish = materialNames[material.name]
-                            tabWrite(
+                                pov_filter = 0.0
+                            material_finish = material_names_dictionary[material.name]
+                            tab_write(
                                 "pigment {srgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} \n"
                                 % (
                                     diffuse_color[0],
                                     diffuse_color[1],
                                     diffuse_color[2],
-                                    povFilter,
+                                    pov_filter,
                                     trans,
                                 )
                             )
-                            tabWrite(
-                                "finish{%s} " % safety(material_finish, Level=2)
-                            )
+                            tab_write("finish{%s} " % safety(material_finish, ref_level_bound=2))
                         else:
-                            tabWrite(
+                            tab_write(
                                 "pigment{srgb 1} finish{%s} "
-                                % (safety(DEF_MAT_NAME, Level=2))
+                                % (safety(DEF_MAT_NAME, ref_level_bound=2))
                             )
 
-                            writeObjectMaterial(material, ob)
-                            # writeObjectMaterial(material, elems[1])
-                            tabWrite(
-                                "radiosity{importance %3g}\n"
-                                % ob.pov.importance_value
-                            )
-                            tabWrite("}\n\n")  # End of Metaball block
+                            write_object_material(material, mob, tab_write)
+                            # write_object_material(material, elems[1])
+                            tab_write("radiosity{importance %3g}\n" % mob.pov.importance_value)
+                            tab_write("}\n\n")  # End of Metaball block
 
     '''
             meta = ob.data
@@ -2279,8 +521,8 @@ def write_pov(filename, scene=None, info_callback=None):
             elements = [elem for elem in meta.elements if elem.type in {'BALL', 'ELLIPSOID'}]
 
             if elements:
-                tabWrite("blob {\n")
-                tabWrite("threshold %.4g\n" % meta.threshold)
+                tab_write("blob {\n")
+                tab_write("threshold %.4g\n" % meta.threshold)
                 importance = ob.pov.importance_value
 
                 try:
@@ -2297,7 +539,7 @@ def write_pov(filename, scene=None, info_callback=None):
 
                     if elem.type == 'BALL':
 
-                        tabWrite("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g }\n" %
+                        tab_write("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g }\n" %
                                  (loc.x, loc.y, loc.z, elem.radius, stiffness))
 
                         # After this wecould do something simple like...
@@ -2306,2682 +548,137 @@ def write_pov(filename, scene=None, info_callback=None):
 
                     elif elem.type == 'ELLIPSOID':
                         # location is modified by scale
-                        tabWrite("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g }\n" %
+                        tab_write("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g }\n" %
                                  (loc.x / elem.size_x,
                                   loc.y / elem.size_y,
                                   loc.z / elem.size_z,
                                   elem.radius, stiffness))
-                        tabWrite("scale <%.6g, %.6g, %.6g> \n" %
+                        tab_write("scale <%.6g, %.6g, %.6g> \n" %
                                  (elem.size_x, elem.size_y, elem.size_z))
 
                 if material:
                     diffuse_color = material.diffuse_color
                     trans = 1.0 - material.pov.alpha
                     if material.use_transparency and material.transparency_method == 'RAYTRACE':
-                        povFilter = material.pov_raytrace_transparency.filter * (1.0 - material.alpha)
-                        trans = (1.0 - material.pov.alpha) - povFilter
+                        pov_filter = material.pov_raytrace_transparency.filter * (1.0 - material.alpha)
+                        trans = (1.0 - material.pov.alpha) - pov_filter
                     else:
-                        povFilter = 0.0
+                        pov_filter = 0.0
 
-                    material_finish = materialNames[material.name]
+                    material_finish = material_names_dictionary[material.name]
 
-                    tabWrite("pigment {srgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} \n" %
+                    tab_write("pigment {srgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} \n" %
                              (diffuse_color[0], diffuse_color[1], diffuse_color[2],
-                              povFilter, trans))
-                    tabWrite("finish {%s}\n" % safety(material_finish, Level=2))
+                              pov_filter, trans))
+                    tab_write("finish {%s}\n" % safety(material_finish, ref_level_bound=2))
 
                 else:
-                    tabWrite("pigment {srgb 1} \n")
+                    tab_write("pigment {srgb 1} \n")
                     # Write the finish last.
-                    tabWrite("finish {%s}\n" % (safety(DEF_MAT_NAME, Level=2)))
+                    tab_write("finish {%s}\n" % (safety(DEF_MAT_NAME, ref_level_bound=2)))
 
-                writeObjectMaterial(material, elems[1])
+                write_object_material(material, elems[1])
 
-                writeMatrix(global_matrix @ ob.matrix_world)
+                write_matrix(global_matrix @ ob.matrix_world)
                 # Importance for radiosity sampling added here
-                tabWrite("radiosity { \n")
+                tab_write("radiosity { \n")
                 # importance > ob.pov.importance_value
-                tabWrite("importance %3g \n" % importance)
-                tabWrite("}\n")
+                tab_write("importance %3g \n" % importance)
+                tab_write("}\n")
 
-                tabWrite("}\n")  # End of Metaball block
+                tab_write("}\n")  # End of Metaball block
 
                 if comments and len(metas) >= 1:
                     file.write("\n")
     '''
-    #    objectNames = {}
-    DEF_OBJ_NAME = "Default"
-
-    def exportMeshes(scene, sel, csg):
-        """write all meshes as POV mesh2{} syntax to exported file """
-        #some numpy functions to speed up mesh export
-
-        # TODO: also write a numpy function to read matrices at object level?
-        # feed below with mesh object.data, but only after doing data.calc_loop_triangles()
-        def read_verts_co(self, mesh):
-            #'float64' would be a slower 64-bit floating-point number numpy datatype
-            # using 'float32' vert coordinates for now until any issue is reported
-            mverts_co = np.zeros((len(mesh.vertices)*3), dtype=np.float32)
-            mesh.vertices.foreach_get("co", mverts_co)
-            return np.reshape(mverts_co, (len(mesh.vertices), 3))
-
-        def read_verts_idx(self, mesh):
-            mverts_idx = np.zeros((len(mesh.vertices)), dtype=np.int64)
-            mesh.vertices.foreach_get("index", mverts_idx)
-            return np.reshape(mverts_idx, (len(mesh.vertices), 1))
-
-        def read_verts_norms(self, mesh):
-            #'float64' would be a slower 64-bit floating-point number numpy datatype
-            # using less accurate 'float16' normals for now until any issue is reported
-            mverts_no = np.zeros((len(mesh.vertices)*3), dtype=np.float16)
-            mesh.vertices.foreach_get("normal", mverts_no)
-            return np.reshape(mverts_no, (len(mesh.vertices), 3))
-
-        def read_faces_idx(self, mesh):
-            mfaces_idx = np.zeros((len(mesh.loop_triangles)), dtype=np.int64)
-            mesh.loop_triangles.foreach_get("index", mfaces_idx)
-            return np.reshape(mfaces_idx, (len(mesh.loop_triangles), 1))
-
-        def read_faces_verts_indices(self, mesh):
-            mfaces_verts_idx = np.zeros((len(mesh.loop_triangles)*3), dtype=np.int64)
-            mesh.loop_triangles.foreach_get("vertices", mfaces_verts_idx)
-            return np.reshape(mfaces_verts_idx, (len(mesh.loop_triangles), 3))
-
-        #Why is below different from verex indices?
-        def read_faces_verts_loops(self, mesh):
-            mfaces_verts_loops = np.zeros((len(mesh.loop_triangles)*3), dtype=np.int64)
-            mesh.loop_triangles.foreach_get("loops", mfaces_verts_loops)
-            return np.reshape(mfaces_verts_loops, (len(mesh.loop_triangles), 3))
-
-        def read_faces_norms(self, mesh):
-            #'float64' would be a slower 64-bit floating-point number numpy datatype
-            # using less accurate 'float16' normals for now until any issue is reported
-            mfaces_no = np.zeros((len(mesh.loop_triangles)*3), dtype=np.float16)
-            mesh.loop_triangles.foreach_get("normal", mfaces_no)
-            return np.reshape(mfaces_no, (len(mesh.loop_triangles), 3))
-
-        def read_faces_smooth(self, mesh):
-            mfaces_smth = np.zeros((len(mesh.loop_triangles)*1), dtype=np.bool)
-            mesh.loop_triangles.foreach_get("use_smooth", mfaces_smth)
-            return np.reshape(mfaces_smth, (len(mesh.loop_triangles), 1))
-
-        def read_faces_material_indices(self, mesh):
-            mfaces_mats_idx = np.zeros((len(mesh.loop_triangles)), dtype=np.int16)
-            mesh.loop_triangles.foreach_get("material_index", mfaces_mats_idx)
-            return np.reshape(mfaces_mats_idx, (len(mesh.loop_triangles), 1))
-
-
-
-        #        obmatslist = []
-        #        def hasUniqueMaterial():
-        #            # Grab materials attached to object instances ...
-        #            if hasattr(ob, 'material_slots'):
-        #                for ms in ob.material_slots:
-        #                    if ms.material is not None and ms.link == 'OBJECT':
-        #                        if ms.material in obmatslist:
-        #                            return False
-        #                        else:
-        #                            obmatslist.append(ms.material)
-        #                            return True
-        #        def hasObjectMaterial(ob):
-        #            # Grab materials attached to object instances ...
-        #            if hasattr(ob, 'material_slots'):
-        #                for ms in ob.material_slots:
-        #                    if ms.material is not None and ms.link == 'OBJECT':
-        #                        # If there is at least one material slot linked to the object
-        #                        # and not the data (mesh), always create a new, "private" data instance.
-        #                        return True
-        #            return False
-        # For objects using local material(s) only!
-        # This is a mapping between a tuple (dataname, materialnames, ...), and the POV dataname.
-        # As only objects using:
-        #     * The same data.
-        #     * EXACTLY the same materials, in EXACTLY the same sockets.
-        # ... can share a same instance in POV export.
-        obmats2data = {}
-
-        def checkObjectMaterials(ob, name, dataname):
-            if hasattr(ob, 'material_slots'):
-                has_local_mats = False
-                key = [dataname]
-                for ms in ob.material_slots:
-                    if ms.material is not None:
-                        key.append(ms.material.name)
-                        if ms.link == 'OBJECT' and not has_local_mats:
-                            has_local_mats = True
-                    else:
-                        # Even if the slot is empty, it is important to grab it...
-                        key.append("")
-                if has_local_mats:
-                    # If this object uses local material(s), lets find if another object
-                    # using the same data and exactly the same list of materials
-                    # (in the same slots) has already been processed...
-                    # Note that here also, we use object name as new, unique dataname for Pov.
-                    key = tuple(key)  # Lists are not hashable...
-                    if key not in obmats2data:
-                        obmats2data[key] = name
-                    return obmats2data[key]
-            return None
-
-        data_ref = {}
-
-        def store(scene, ob, name, dataname, matrix):
-            # The Object needs to be written at least once but if its data is
-            # already in data_ref this has already been done.
-            # This func returns the "povray" name of the data, or None
-            # if no writing is needed.
-            if ob.is_modified(scene, 'RENDER'):
-                # Data modified.
-                # Create unique entry in data_ref by using object name
-                # (always unique in Blender) as data name.
-                data_ref[name] = [(name, MatrixAsPovString(matrix))]
-                return name
-            # Here, we replace dataname by the value returned by checkObjectMaterials, only if
-            # it is not evaluated to False (i.e. only if the object uses some local material(s)).
-            dataname = checkObjectMaterials(ob, name, dataname) or dataname
-            if dataname in data_ref:
-                # Data already known, just add the object instance.
-                data_ref[dataname].append((name, MatrixAsPovString(matrix)))
-                # No need to write data
-                return None
-            else:
-                # Data not yet processed, create a new entry in data_ref.
-                data_ref[dataname] = [(name, MatrixAsPovString(matrix))]
-                return dataname
-
-        def exportSmoke(smoke_obj_name):
-            # if LuxManager.CurrentScene.name == 'preview':
-            # return 1, 1, 1, 1.0
-            # else:
-            flowtype = -1
-            smoke_obj = bpy.data.objects[smoke_obj_name]
-            domain = None
-
-            # Search smoke domain target for smoke modifiers
-            for mod in smoke_obj.modifiers:
-                if mod.name == 'Smoke':
-                    if mod.smoke_type == 'FLOW':
-                        if mod.flow_settings.smoke_flow_type == 'BOTH':
-                            flowtype = 2
-                        else:
-                            if mod.flow_settings.smoke_flow_type == 'SMOKE':
-                                flowtype = 0
-                            else:
-                                if mod.flow_settings.smoke_flow_type == 'FIRE':
-                                    flowtype = 1
-
-                    if mod.smoke_type == 'DOMAIN':
-                        domain = smoke_obj
-                        smoke_modifier = mod
-
-            eps = 0.000001
-            if domain is not None:
-                # if bpy.app.version[0] >= 2 and bpy.app.version[1] >= 71:
-                # Blender version 2.71 supports direct access to smoke data structure
-                set = mod.domain_settings
-                channeldata = []
-                for v in set.density_grid:
-                    channeldata.append(v.real)
-                    print(v.real)
-                ## Usage en voxel texture:
-                # channeldata = []
-                # if channel == 'density':
-                # for v in set.density_grid:
-                # channeldata.append(v.real)
-
-                # if channel == 'fire':
-                # for v in set.flame_grid:
-                # channeldata.append(v.real)
-
-                resolution = set.resolution_max
-                big_res = []
-                big_res.append(set.domain_resolution[0])
-                big_res.append(set.domain_resolution[1])
-                big_res.append(set.domain_resolution[2])
-
-                if set.use_high_resolution:
-                    big_res[0] = big_res[0] * (set.amplify + 1)
-                    big_res[1] = big_res[1] * (set.amplify + 1)
-                    big_res[2] = big_res[2] * (set.amplify + 1)
-                # else:
-                # p = []
-                ##gather smoke domain settings
-                # BBox = domain.bound_box
-                # p.append([BBox[0][0], BBox[0][1], BBox[0][2]])
-                # p.append([BBox[6][0], BBox[6][1], BBox[6][2]])
-                # set = mod.domain_settings
-                # resolution = set.resolution_max
-                # smokecache = set.point_cache
-                # ret = read_cache(smokecache, set.use_high_resolution, set.amplify + 1, flowtype)
-                # res_x = ret[0]
-                # res_y = ret[1]
-                # res_z = ret[2]
-                # density = ret[3]
-                # fire = ret[4]
-
-                # if res_x * res_y * res_z > 0:
-                ##new cache format
-                # big_res = []
-                # big_res.append(res_x)
-                # big_res.append(res_y)
-                # big_res.append(res_z)
-                # else:
-                # max = domain.dimensions[0]
-                # if (max - domain.dimensions[1]) < -eps:
-                # max = domain.dimensions[1]
-
-                # if (max - domain.dimensions[2]) < -eps:
-                # max = domain.dimensions[2]
-
-                # big_res = [int(round(resolution * domain.dimensions[0] / max, 0)),
-                # int(round(resolution * domain.dimensions[1] / max, 0)),
-                # int(round(resolution * domain.dimensions[2] / max, 0))]
-
-                # if set.use_high_resolution:
-                # big_res = [big_res[0] * (set.amplify + 1), big_res[1] * (set.amplify + 1),
-                # big_res[2] * (set.amplify + 1)]
-
-                # if channel == 'density':
-                # channeldata = density
-
-                # if channel == 'fire':
-                # channeldata = fire
-
-                # sc_fr = '%s/%s/%s/%05d' % (efutil.export_path, efutil.scene_filename(), bpy.context.scene.name, bpy.context.scene.frame_current)
-                #               if not os.path.exists( sc_fr ):
-                #                   os.makedirs(sc_fr)
-                #
-                #               smoke_filename = '%s.smoke' % bpy.path.clean_name(domain.name)
-                #               smoke_path = '/'.join([sc_fr, smoke_filename])
-                #
-                #               with open(smoke_path, 'wb') as smoke_file:
-                #                   # Binary densitygrid file format
-                #                   #
-                #                   # File header
-                #                   smoke_file.write(b'SMOKE')        #magic number
-                #                   smoke_file.write(struct.pack('<I', big_res[0]))
-                #                   smoke_file.write(struct.pack('<I', big_res[1]))
-                #                   smoke_file.write(struct.pack('<I', big_res[2]))
-                # Density data
-                #                   smoke_file.write(struct.pack('<%df'%len(channeldata), *channeldata))
-                #
-                #               LuxLog('Binary SMOKE file written: %s' % (smoke_path))
-
-                # return big_res[0], big_res[1], big_res[2], channeldata
-
-                mydf3 = df3.df3(big_res[0], big_res[1], big_res[2])
-                sim_sizeX, sim_sizeY, sim_sizeZ = mydf3.size()
-                for x in range(sim_sizeX):
-                    for y in range(sim_sizeY):
-                        for z in range(sim_sizeZ):
-                            mydf3.set(
-                                x,
-                                y,
-                                z,
-                                channeldata[
-                                    ((z * sim_sizeY + y) * sim_sizeX + x)
-                                ],
-                            )
-
-                mydf3.exportDF3(smokePath)
-                print('Binary smoke.df3 file written in preview directory')
-                if comments:
-                    file.write("\n//--Smoke--\n\n")
-
-                # Note: We start with a default unit cube.
-                #       This is mandatory to read correctly df3 data - otherwise we could just directly use bbox
-                #       coordinates from the start, and avoid scale/translate operations at the end...
-                file.write("box{<0,0,0>, <1,1,1>\n")
-                file.write("    pigment{ rgbt 1 }\n")
-                file.write("    hollow\n")
-                file.write("    interior{ //---------------------\n")
-                file.write("        media{ method 3\n")
-                file.write(
-                    "               emission <1,1,1>*1\n"
-                )  # 0>1 for dark smoke to white vapour
-                file.write("               scattering{ 1, // Type\n")
-                file.write("                  <1,1,1>*0.1\n")
-                file.write("                } // end scattering\n")
-                file.write(
-                    "                density{density_file df3 \"%s\"\n"
-                    % (smokePath)
-                )
-                file.write("                        color_map {\n")
-                file.write("                        [0.00 rgb 0]\n")
-                file.write("                        [0.05 rgb 0]\n")
-                file.write("                        [0.20 rgb 0.2]\n")
-                file.write("                        [0.30 rgb 0.6]\n")
-                file.write("                        [0.40 rgb 1]\n")
-                file.write("                        [1.00 rgb 1]\n")
-                file.write("                       } // end color_map\n")
-                file.write("               } // end of density\n")
-                file.write(
-                    "               samples %i // higher = more precise\n"
-                    % resolution
-                )
-                file.write(
-                    "         } // end of media --------------------------\n"
-                )
-                file.write("    } // end of interior\n")
-
-                # START OF TRANSFORMATIONS
-
-                # Size to consider here are bbox dimensions (i.e. still in object space, *before* applying
-                # loc/rot/scale and other transformations (like parent stuff), aka matrix_world).
-                bbox = smoke_obj.bound_box
-                dim = [
-                    abs(bbox[6][0] - bbox[0][0]),
-                    abs(bbox[6][1] - bbox[0][1]),
-                    abs(bbox[6][2] - bbox[0][2]),
-                ]
-
-                # We scale our cube to get its final size and shapes but still in *object* space (same as Blender's bbox).
-                file.write("scale<%.6g,%.6g,%.6g>\n" % (dim[0], dim[1], dim[2]))
-
-                # We offset our cube such that (0,0,0) coordinate matches Blender's object center.
-                file.write(
-                    "translate<%.6g,%.6g,%.6g>\n"
-                    % (bbox[0][0], bbox[0][1], bbox[0][2])
-                )
-
-                # We apply object's transformations to get final loc/rot/size in world space!
-                # Note: we could combine the two previous transformations with this matrix directly...
-                writeMatrix(global_matrix @ smoke_obj.matrix_world)
-
-                # END OF TRANSFORMATIONS
-
-                file.write("}\n")
-
-                # file.write("               interpolate 1\n")
-                # file.write("               frequency 0\n")
-                # file.write("   }\n")
-                # file.write("}\n")
-
-        ob_num = 0
-        for ob in sel:
-            # subtract original from the count of their instances as were not counted before 2.8
-            if not (ob.is_instancer and ob.original != ob):
-                ob_num += 1
-
-                # XXX I moved all those checks here, as there is no need to compute names
-                #     for object we won't export here!
-                if ob.type in {
-                    'LIGHT',
-                    'CAMERA',  #'EMPTY', #empties can bear dupligroups
-                    'META',
-                    'ARMATURE',
-                    'LATTICE',
-                }:
-                    continue
-                smokeFlag = False
-                for mod in ob.modifiers:
-                    if mod and hasattr(mod, 'smoke_type'):
-                        smokeFlag = True
-                        if mod.smoke_type == 'DOMAIN':
-                            exportSmoke(ob.name)
-                        break  # don't render domain mesh or flow emitter mesh, skip to next object.
-                if not smokeFlag:
-                    # Export Hair
-                    renderEmitter = True
-                    if hasattr(ob, 'particle_systems'):
-                        renderEmitter = False
-                        if ob.show_instancer_for_render:
-                            renderEmitter = True
-                        for pSys in ob.particle_systems:
-                            for mod in [
-                                m
-                                for m in ob.modifiers
-                                if (m is not None)
-                                and (m.type == 'PARTICLE_SYSTEM')
-                            ]:
-                                if (
-                                    (pSys.settings.render_type == 'PATH')
-                                    and mod.show_render
-                                    and (pSys.name == mod.particle_system.name)
-                                ):
-                                    tstart = time.time()
-                                    texturedHair = 0
-                                    if (
-                                        ob.material_slots[
-                                            pSys.settings.material - 1
-                                        ].material
-                                        and ob.active_material is not None
-                                    ):
-                                        pmaterial = ob.material_slots[
-                                            pSys.settings.material - 1
-                                        ].material
-                                        #XXX Todo: replace by pov_(Particles?)_texture_slot
-                                        for th in pmaterial.texture_slots:
-                                            if th and th.use:
-                                                if (
-                                                    (
-                                                        th.texture.type
-                                                        == 'IMAGE'
-                                                        and th.texture.image
-                                                    )
-                                                    or th.texture.type
-                                                    != 'IMAGE'
-                                                ):
-                                                    if th.use_map_color_diffuse:
-                                                        texturedHair = 1
-                                        if pmaterial.strand.use_blender_units:
-                                            strandStart = (
-                                                pmaterial.strand.root_size
-                                            )
-                                            strandEnd = (
-                                                pmaterial.strand.tip_size
-                                            )
-                                            strandShape = pmaterial.strand.shape
-                                        else:  # Blender unit conversion
-                                            strandStart = (
-                                                pmaterial.strand.root_size
-                                                / 200.0
-                                            )
-                                            strandEnd = (
-                                                pmaterial.strand.tip_size
-                                                / 200.0
-                                            )
-                                            strandShape = pmaterial.strand.shape
-                                    else:
-                                        pmaterial = (
-                                            "default"
-                                        )  # No material assigned in blender, use default one
-                                        strandStart = 0.01
-                                        strandEnd = 0.01
-                                        strandShape = 0.0
-                                    # Set the number of particles to render count rather than 3d view display
-                                    # pSys.set_resolution(scene, ob, 'RENDER') # DEPRECATED
-                                    # When you render, the entire dependency graph will be
-                                    # evaluated at render resolution, including the particles.
-                                    # In the viewport it will be at viewport resolution.
-                                    # So there is no need fo render engines to use this function anymore,
-                                    # it's automatic now.
-                                    steps = pSys.settings.display_step
-                                    steps = (
-                                        3 ** steps
-                                    )  # or (power of 2 rather than 3) + 1 # Formerly : len(particle.hair_keys)
-
-                                    totalNumberOfHairs = (
-                                        pSys.settings.count
-                                        + pSys.settings.rendered_child_count
-                                    )
-                                    # hairCounter = 0
-                                    file.write(
-                                        '#declare HairArray = array[%i] {\n'
-                                        % totalNumberOfHairs
-                                    )
-                                    for pindex in range(0, totalNumberOfHairs):
-
-                                        # if particle.is_exist and particle.is_visible:
-                                        # hairCounter += 1
-                                        # controlPointCounter = 0
-                                        # Each hair is represented as a separate sphere_sweep in POV-Ray.
-
-                                        file.write('sphere_sweep{')
-                                        if pSys.settings.use_hair_bspline:
-                                            file.write('b_spline ')
-                                            file.write(
-                                                '%i,\n' % (steps + 2)
-                                            )  # +2 because the first point needs tripling to be more than a handle in POV
-                                        else:
-                                            file.write('linear_spline ')
-                                            file.write('%i,\n' % (steps))
-                                        # changing world coordinates to object local coordinates by multiplying with inverted matrix
-                                        initCo = ob.matrix_world.inverted() @ (
-                                            pSys.co_hair(
-                                                ob, particle_no=pindex, step=0
-                                            )
-                                        )
-                                        if (
-                                            ob.material_slots[
-                                                pSys.settings.material - 1
-                                            ].material
-                                            and ob.active_material is not None
-                                        ):
-                                            pmaterial = ob.material_slots[
-                                                pSys.settings.material - 1
-                                            ].material
-                                            for th in pmaterial.texture_slots:
-                                                if (
-                                                    th
-                                                    and th.use
-                                                    and th.use_map_color_diffuse
-                                                ):
-                                                    # treat POV textures as bitmaps
-                                                    if (
-                                                        th.texture.type
-                                                        == 'IMAGE'
-                                                        and th.texture.image
-                                                        and th.texture_coords
-                                                        == 'UV'
-                                                        and ob.data.uv_textures
-                                                        is not None
-                                                    ):  # or (th.texture.pov.tex_pattern_type != 'emulator' and th.texture_coords == 'UV' and ob.data.uv_textures is not None):
-                                                        image = th.texture.image
-                                                        image_width = image.size[
-                                                            0
-                                                        ]
-                                                        image_height = image.size[
-                                                            1
-                                                        ]
-                                                        image_pixels = image.pixels[
-                                                            :
-                                                        ]
-                                                        uv_co = pSys.uv_on_emitter(
-                                                            mod,
-                                                            pSys.particles[
-                                                                pindex
-                                                            ],
-                                                            pindex,
-                                                            0,
-                                                        )
-                                                        x_co = round(
-                                                            uv_co[0]
-                                                            * (image_width - 1)
-                                                        )
-                                                        y_co = round(
-                                                            uv_co[1]
-                                                            * (image_height - 1)
-                                                        )
-                                                        pixelnumber = (
-                                                            image_width * y_co
-                                                        ) + x_co
-                                                        r = image_pixels[
-                                                            pixelnumber * 4
-                                                        ]
-                                                        g = image_pixels[
-                                                            pixelnumber * 4 + 1
-                                                        ]
-                                                        b = image_pixels[
-                                                            pixelnumber * 4 + 2
-                                                        ]
-                                                        a = image_pixels[
-                                                            pixelnumber * 4 + 3
-                                                        ]
-                                                        initColor = (r, g, b, a)
-                                                    else:
-                                                        # only overwrite variable for each competing texture for now
-                                                        initColor = th.texture.evaluate(
-                                                            (
-                                                                initCo[0],
-                                                                initCo[1],
-                                                                initCo[2],
-                                                            )
-                                                        )
-                                        for step in range(0, steps):
-                                            co = ob.matrix_world.inverted() @ (
-                                                pSys.co_hair(
-                                                    ob,
-                                                    particle_no=pindex,
-                                                    step=step,
-                                                )
-                                            )
-                                            # for controlPoint in particle.hair_keys:
-                                            if pSys.settings.clump_factor != 0:
-                                                hDiameter = (
-                                                    pSys.settings.clump_factor
-                                                    / 200.0
-                                                    * random.uniform(0.5, 1)
-                                                )
-                                            elif step == 0:
-                                                hDiameter = strandStart
-                                            else:
-                                                hDiameter += (
-                                                    strandEnd - strandStart
-                                                ) / (
-                                                    pSys.settings.display_step
-                                                    + 1
-                                                )  # XXX +1 or not?
-                                            if (
-                                                step == 0
-                                                and pSys.settings.use_hair_bspline
-                                            ):
-                                                # Write three times the first point to compensate pov Bezier handling
-                                                file.write(
-                                                    '<%.6g,%.6g,%.6g>,%.7g,\n'
-                                                    % (
-                                                        co[0],
-                                                        co[1],
-                                                        co[2],
-                                                        abs(hDiameter),
-                                                    )
-                                                )
-                                                file.write(
-                                                    '<%.6g,%.6g,%.6g>,%.7g,\n'
-                                                    % (
-                                                        co[0],
-                                                        co[1],
-                                                        co[2],
-                                                        abs(hDiameter),
-                                                    )
-                                                )
-                                                # file.write('<%.6g,%.6g,%.6g>,%.7g' % (particle.location[0], particle.location[1], particle.location[2], abs(hDiameter))) # Useless because particle location is the tip, not the root.
-                                                # file.write(',\n')
-                                            # controlPointCounter += 1
-                                            # totalNumberOfHairs += len(pSys.particles)# len(particle.hair_keys)
-
-                                            # Each control point is written out, along with the radius of the
-                                            # hair at that point.
-                                            file.write(
-                                                '<%.6g,%.6g,%.6g>,%.7g'
-                                                % (
-                                                    co[0],
-                                                    co[1],
-                                                    co[2],
-                                                    abs(hDiameter),
-                                                )
-                                            )
 
-                                            # All coordinates except the last need a following comma.
-
-                                            if step != steps - 1:
-                                                file.write(',\n')
-                                            else:
-                                                if texturedHair:
-                                                    # Write pigment and alpha (between Pov and Blender alpha 0 and 1 are reversed)
-                                                    file.write(
-                                                        '\npigment{ color srgbf < %.3g, %.3g, %.3g, %.3g> }\n'
-                                                        % (
-                                                            initColor[0],
-                                                            initColor[1],
-                                                            initColor[2],
-                                                            1.0 - initColor[3],
-                                                        )
-                                                    )
-                                                # End the sphere_sweep declaration for this hair
-                                                file.write('}\n')
-
-                                        # All but the final sphere_sweep (each array element) needs a terminating comma.
-                                        if pindex != totalNumberOfHairs:
-                                            file.write(',\n')
-                                        else:
-                                            file.write('\n')
-
-                                    # End the array declaration.
-
-                                    file.write('}\n')
-                                    file.write('\n')
-
-                                    if not texturedHair:
-                                        # Pick up the hair material diffuse color and create a default POV-Ray hair texture.
-
-                                        file.write('#ifndef (HairTexture)\n')
-                                        file.write(
-                                            '  #declare HairTexture = texture {\n'
-                                        )
-                                        file.write(
-                                            '    pigment {srgbt <%s,%s,%s,%s>}\n'
-                                            % (
-                                                pmaterial.diffuse_color[0],
-                                                pmaterial.diffuse_color[1],
-                                                pmaterial.diffuse_color[2],
-                                                (
-                                                    pmaterial.strand.width_fade
-                                                    + 0.05
-                                                ),
-                                            )
-                                        )
-                                        file.write('  }\n')
-                                        file.write('#end\n')
-                                        file.write('\n')
-
-                                    # Dynamically create a union of the hairstrands (or a subset of them).
-                                    # By default use every hairstrand, commented line is for hand tweaking test renders.
-                                    file.write(
-                                        '//Increasing HairStep divides the amount of hair for test renders.\n'
-                                    )
-                                    file.write(
-                                        '#ifndef(HairStep) #declare HairStep = 1; #end\n'
-                                    )
-                                    file.write('union{\n')
-                                    file.write('  #local I = 0;\n')
-                                    file.write(
-                                        '  #while (I < %i)\n'
-                                        % totalNumberOfHairs
-                                    )
-                                    file.write('    object {HairArray[I]')
-                                    if not texturedHair:
-                                        file.write(' texture{HairTexture}\n')
-                                    else:
-                                        file.write('\n')
-                                    # Translucency of the hair:
-                                    file.write('        hollow\n')
-                                    file.write('        double_illuminate\n')
-                                    file.write('        interior {\n')
-                                    file.write('            ior 1.45\n')
-                                    file.write('            media {\n')
-                                    file.write(
-                                        '                scattering { 1, 10*<0.73, 0.35, 0.15> /*extinction 0*/ }\n'
-                                    )
-                                    file.write(
-                                        '                absorption 10/<0.83, 0.75, 0.15>\n'
-                                    )
-                                    file.write('                samples 1\n')
-                                    file.write('                method 2\n')
-                                    file.write(
-                                        '                density {cylindrical\n'
-                                    )
-                                    file.write(
-                                        '                    color_map {\n'
-                                    )
-                                    file.write(
-                                        '                        [0.0 rgb <0.83, 0.45, 0.35>]\n'
-                                    )
-                                    file.write(
-                                        '                        [0.5 rgb <0.8, 0.8, 0.4>]\n'
-                                    )
-                                    file.write(
-                                        '                        [1.0 rgb <1,1,1>]\n'
-                                    )
-                                    file.write('                    }\n')
-                                    file.write('                }\n')
-                                    file.write('            }\n')
-                                    file.write('        }\n')
-                                    file.write('    }\n')
-
-                                    file.write('    #local I = I + HairStep;\n')
-                                    file.write('  #end\n')
-
-                                    writeMatrix(global_matrix @ ob.matrix_world)
-
-                                    file.write('}')
-                                    print(
-                                        'Totals hairstrands written: %i'
-                                        % totalNumberOfHairs
-                                    )
-                                    print(
-                                        'Number of tufts (particle systems)',
-                                        len(ob.particle_systems),
-                                    )
-
-                                    # Set back the displayed number of particles to preview count
-                                    # pSys.set_resolution(scene, ob, 'PREVIEW') #DEPRECATED
-                                    # When you render, the entire dependency graph will be
-                                    # evaluated at render resolution, including the particles.
-                                    # In the viewport it will be at viewport resolution.
-                                    # So there is no need fo render engines to use this function anymore,
-                                    # it's automatic now.
-                                    if renderEmitter == False:
-                                        continue  # don't render mesh, skip to next object.
-
-                    #############################################
-                    # Generating a name for object just like materials to be able to use it
-                    # (baking for now or anything else).
-                    # XXX I don't understand that if we are here, sel if a non-empty iterable,
-                    #     so this condition is always True, IMO -- mont29
-                    if ob.data:
-                        name_orig = "OB" + ob.name
-                        dataname_orig = "DATA" + ob.data.name
-                    elif ob.is_instancer:
-                        if ob.instance_type == 'COLLECTION':
-                            name_orig = "OB" + ob.name
-                            dataname_orig = "DATA" + ob.instance_collection.name
-                        else:
-                            # hoping only dupligroups have several source datablocks
-                            # ob_dupli_list_create(scene) #deprecated in 2.8
-                            depsgraph = bpy.context.evaluated_depsgraph_get()
-                            for eachduplicate in depsgraph.object_instances:
-                                if (
-                                    eachduplicate.is_instance
-                                ):  # Real dupli instance filtered because original included in list since 2.8
-                                    dataname_orig = (
-                                        "DATA" + eachduplicate.object.name
-                                    )
-                            # ob.dupli_list_clear() #just don't store any reference to instance since 2.8
-                    elif ob.type == 'EMPTY':
-                        name_orig = "OB" + ob.name
-                        dataname_orig = "DATA" + ob.name
-                    else:
-                        name_orig = DEF_OBJ_NAME
-                        dataname_orig = DEF_OBJ_NAME
-                    name = string_strip_hyphen(bpy.path.clean_name(name_orig))
-                    dataname = string_strip_hyphen(
-                        bpy.path.clean_name(dataname_orig)
-                    )
-                    ##            for slot in ob.material_slots:
-                    ##                if slot.material is not None and slot.link == 'OBJECT':
-                    ##                    obmaterial = slot.material
-
-                    #############################################
-
-                    if info_callback:
-                        info_callback(
-                            "Object %2.d of %2.d (%s)"
-                            % (ob_num, len(sel), ob.name)
-                        )
-
-                    # if ob.type != 'MESH':
-                    #    continue
-                    # me = ob.data
-
-                    matrix = global_matrix @ ob.matrix_world
-                    povdataname = store(scene, ob, name, dataname, matrix)
-                    if povdataname is None:
-                        print("This is an instance of " + name)
-                        continue
-
-                    print("Writing Down First Occurrence of " + name)
-
-                    ############################################Povray Primitives
-                    # special exportCurves() function takes care of writing
-                    # lathe, sphere_sweep, birail, and loft except with modifiers
-                    # converted to mesh
-                    if not ob.is_modified(scene, 'RENDER'):
-                        if ob.type == 'CURVE' and (
-                            ob.pov.curveshape
-                            in {'lathe', 'sphere_sweep', 'loft'}
-                        ):
-                            continue  # Don't render proxy mesh, skip to next object
-
-                    if ob.pov.object_as == 'ISOSURFACE':
-                        tabWrite("#declare %s = isosurface{ \n" % povdataname)
-                        tabWrite("function{ \n")
-                        textName = ob.pov.iso_function_text
-                        if textName:
-                            node_tree = bpy.context.scene.node_tree
-                            for node in node_tree.nodes:
-                                if (
-                                    node.bl_idname == "IsoPropsNode"
-                                    and node.label == ob.name
-                                ):
-                                    for inp in node.inputs:
-                                        if inp:
-                                            tabWrite(
-                                                "#declare %s = %.6g;\n"
-                                                % (inp.name, inp.default_value)
-                                            )
-
-                            text = bpy.data.texts[textName]
-                            for line in text.lines:
-                                split = line.body.split()
-                                if split[0] != "#declare":
-                                    tabWrite("%s\n" % line.body)
-                        else:
-                            tabWrite("abs(x) - 2 + y")
-                        tabWrite("}\n")
-                        tabWrite("threshold %.6g\n" % ob.pov.threshold)
-                        tabWrite("max_gradient %.6g\n" % ob.pov.max_gradient)
-                        tabWrite("accuracy  %.6g\n" % ob.pov.accuracy)
-                        tabWrite("contained_by { ")
-                        if ob.pov.contained_by == "sphere":
-                            tabWrite(
-                                "sphere {0,%.6g}}\n" % ob.pov.container_scale
-                            )
-                        else:
-                            tabWrite(
-                                "box {-%.6g,%.6g}}\n"
-                                % (
-                                    ob.pov.container_scale,
-                                    ob.pov.container_scale,
-                                )
-                            )
-                        if ob.pov.all_intersections:
-                            tabWrite("all_intersections\n")
-                        else:
-                            if ob.pov.max_trace > 1:
-                                tabWrite("max_trace %.6g\n" % ob.pov.max_trace)
-                        povMatName = "Default_texture"
-                        if ob.active_material:
-                            # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
-                            try:
-                                material = ob.active_material
-                                writeObjectMaterial(material, ob)
-                            except IndexError:
-                                print(me)
-                        # tabWrite("texture {%s}\n"%povMatName)
-                        tabWrite("scale %.6g\n" % (1 / ob.pov.container_scale))
-                        tabWrite("}\n")
-                        continue  # Don't render proxy mesh, skip to next object
-
-                    if ob.pov.object_as == 'SUPERELLIPSOID':
-                        tabWrite(
-                            "#declare %s = superellipsoid{ <%.4f,%.4f>\n"
-                            % (povdataname, ob.pov.se_n2, ob.pov.se_n1)
-                        )
-                        povMatName = "Default_texture"
-                        if ob.active_material:
-                            # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
-                            try:
-                                material = ob.active_material
-                                writeObjectMaterial(material, ob)
-                            except IndexError:
-                                print(me)
-                        # tabWrite("texture {%s}\n"%povMatName)
-                        write_object_modifiers(scene, ob, file)
-                        tabWrite("}\n")
-                        continue  # Don't render proxy mesh, skip to next object
-
-                    if ob.pov.object_as == 'SUPERTORUS':
-                        rMajor = ob.pov.st_major_radius
-                        rMinor = ob.pov.st_minor_radius
-                        ring = ob.pov.st_ring
-                        cross = ob.pov.st_cross
-                        accuracy = ob.pov.st_accuracy
-                        gradient = ob.pov.st_max_gradient
-                        ############Inline Supertorus macro
-                        file.write(
-                            "#macro Supertorus(RMj, RMn, MajorControl, MinorControl, Accuracy, MaxGradient)\n"
-                        )
-                        file.write("   #local CP = 2/MinorControl;\n")
-                        file.write("   #local RP = 2/MajorControl;\n")
-                        file.write("   isosurface {\n")
-                        file.write(
-                            "      function { pow( pow(abs(pow(pow(abs(x),RP) + pow(abs(z),RP), 1/RP) - RMj),CP) + pow(abs(y),CP) ,1/CP) - RMn }\n"
-                        )
-                        file.write("      threshold 0\n")
-                        file.write(
-                            "      contained_by {box {<-RMj-RMn,-RMn,-RMj-RMn>, < RMj+RMn, RMn, RMj+RMn>}}\n"
-                        )
-                        file.write("      #if(MaxGradient >= 1)\n")
-                        file.write("         max_gradient MaxGradient\n")
-                        file.write("      #else\n")
-                        file.write("         evaluate 1, 10, 0.1\n")
-                        file.write("      #end\n")
-                        file.write("      accuracy Accuracy\n")
-                        file.write("   }\n")
-                        file.write("#end\n")
-                        ############
-                        tabWrite(
-                            "#declare %s = object{ Supertorus( %.4g,%.4g,%.4g,%.4g,%.4g,%.4g)\n"
-                            % (
-                                povdataname,
-                                rMajor,
-                                rMinor,
-                                ring,
-                                cross,
-                                accuracy,
-                                gradient,
-                            )
-                        )
-                        povMatName = "Default_texture"
-                        if ob.active_material:
-                            # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
-                            try:
-                                material = ob.active_material
-                                writeObjectMaterial(material, ob)
-                            except IndexError:
-                                print(me)
-                        # tabWrite("texture {%s}\n"%povMatName)
-                        write_object_modifiers(scene, ob, file)
-                        tabWrite("rotate x*90\n")
-                        tabWrite("}\n")
-                        continue  # Don't render proxy mesh, skip to next object
-
-                    if ob.pov.object_as == 'PLANE':
-                        tabWrite(
-                            "#declare %s = plane{ <0,0,1>,1\n" % povdataname
-                        )
-                        povMatName = "Default_texture"
-                        if ob.active_material:
-                            # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
-                            try:
-                                material = ob.active_material
-                                writeObjectMaterial(material, ob)
-                            except IndexError:
-                                print(me)
-                        # tabWrite("texture {%s}\n"%povMatName)
-                        write_object_modifiers(scene, ob, file)
-                        # tabWrite("rotate x*90\n")
-                        tabWrite("}\n")
-                        continue  # Don't render proxy mesh, skip to next object
-
-                    if ob.pov.object_as == 'BOX':
-                        tabWrite("#declare %s = box { -1,1\n" % povdataname)
-                        povMatName = "Default_texture"
-                        if ob.active_material:
-                            # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
-                            try:
-                                material = ob.active_material
-                                writeObjectMaterial(material, ob)
-                            except IndexError:
-                                print(me)
-                        # tabWrite("texture {%s}\n"%povMatName)
-                        write_object_modifiers(scene, ob, file)
-                        # tabWrite("rotate x*90\n")
-                        tabWrite("}\n")
-                        continue  # Don't render proxy mesh, skip to next object
-
-                    if ob.pov.object_as == 'CONE':
-                        br = ob.pov.cone_base_radius
-                        cr = ob.pov.cone_cap_radius
-                        bz = ob.pov.cone_base_z
-                        cz = ob.pov.cone_cap_z
-                        tabWrite(
-                            "#declare %s = cone { <0,0,%.4f>,%.4f,<0,0,%.4f>,%.4f\n"
-                            % (povdataname, bz, br, cz, cr)
-                        )
-                        povMatName = "Default_texture"
-                        if ob.active_material:
-                            # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
-                            try:
-                                material = ob.active_material
-                                writeObjectMaterial(material, ob)
-                            except IndexError:
-                                print(me)
-                        # tabWrite("texture {%s}\n"%povMatName)
-                        write_object_modifiers(scene, ob, file)
-                        # tabWrite("rotate x*90\n")
-                        tabWrite("}\n")
-                        continue  # Don't render proxy mesh, skip to next object
-
-                    if ob.pov.object_as == 'CYLINDER':
-                        r = ob.pov.cylinder_radius
-                        x2 = ob.pov.cylinder_location_cap[0]
-                        y2 = ob.pov.cylinder_location_cap[1]
-                        z2 = ob.pov.cylinder_location_cap[2]
-                        tabWrite(
-                            "#declare %s = cylinder { <0,0,0>,<%6f,%6f,%6f>,%6f\n"
-                            % (povdataname, x2, y2, z2, r)
-                        )
-                        povMatName = "Default_texture"
-                        if ob.active_material:
-                            # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
-                            try:
-                                material = ob.active_material
-                                writeObjectMaterial(material, ob)
-                            except IndexError:
-                                print(me)
-                        # tabWrite("texture {%s}\n"%povMatName)
-                        # cylinders written at origin, translated below
-                        write_object_modifiers(scene, ob, file)
-                        # tabWrite("rotate x*90\n")
-                        tabWrite("}\n")
-                        continue  # Don't render proxy mesh, skip to next object
-
-                    if ob.pov.object_as == 'HEIGHT_FIELD':
-                        data = ""
-                        filename = ob.pov.hf_filename
-                        data += '"%s"' % filename
-                        gamma = ' gamma %.4f' % ob.pov.hf_gamma
-                        data += gamma
-                        if ob.pov.hf_premultiplied:
-                            data += ' premultiplied on'
-                        if ob.pov.hf_smooth:
-                            data += ' smooth'
-                        if ob.pov.hf_water > 0:
-                            data += ' water_level %.4f' % ob.pov.hf_water
-                        # hierarchy = ob.pov.hf_hierarchy
-                        tabWrite(
-                            '#declare %s = height_field { %s\n'
-                            % (povdataname, data)
-                        )
-                        povMatName = "Default_texture"
-                        if ob.active_material:
-                            # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
-                            try:
-                                material = ob.active_material
-                                writeObjectMaterial(material, ob)
-                            except IndexError:
-                                print(me)
-                        # tabWrite("texture {%s}\n"%povMatName)
-                        write_object_modifiers(scene, ob, file)
-                        tabWrite("rotate x*90\n")
-                        tabWrite("translate <-0.5,0.5,0>\n")
-                        tabWrite("scale <0,-1,0>\n")
-                        tabWrite("}\n")
-                        continue  # Don't render proxy mesh, skip to next object
-
-                    if ob.pov.object_as == 'SPHERE':
-
-                        tabWrite(
-                            "#declare %s = sphere { 0,%6f\n"
-                            % (povdataname, ob.pov.sphere_radius)
-                        )
-                        povMatName = "Default_texture"
-                        if ob.active_material:
-                            # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
-                            try:
-                                material = ob.active_material
-                                writeObjectMaterial(material, ob)
-                            except IndexError:
-                                print(me)
-                        # tabWrite("texture {%s}\n"%povMatName)
-                        write_object_modifiers(scene, ob, file)
-                        # tabWrite("rotate x*90\n")
-                        tabWrite("}\n")
-                        continue  # Don't render proxy mesh, skip to next object
-
-                    if ob.pov.object_as == 'TORUS':
-                        tabWrite(
-                            "#declare %s = torus { %.4f,%.4f\n"
-                            % (
-                                povdataname,
-                                ob.pov.torus_major_radius,
-                                ob.pov.torus_minor_radius,
-                            )
-                        )
-                        povMatName = "Default_texture"
-                        if ob.active_material:
-                            # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
-                            try:
-                                material = ob.active_material
-                                writeObjectMaterial(material, ob)
-                            except IndexError:
-                                print(me)
-                        # tabWrite("texture {%s}\n"%povMatName)
-                        write_object_modifiers(scene, ob, file)
-                        tabWrite("rotate x*90\n")
-                        tabWrite("}\n")
-                        continue  # Don't render proxy mesh, skip to next object
-
-                    if ob.pov.object_as == 'PARAMETRIC':
-                        tabWrite("#declare %s = parametric {\n" % povdataname)
-                        tabWrite("function { %s }\n" % ob.pov.x_eq)
-                        tabWrite("function { %s }\n" % ob.pov.y_eq)
-                        tabWrite("function { %s }\n" % ob.pov.z_eq)
-                        tabWrite(
-                            "<%.4f,%.4f>, <%.4f,%.4f>\n"
-                            % (
-                                ob.pov.u_min,
-                                ob.pov.v_min,
-                                ob.pov.u_max,
-                                ob.pov.v_max,
-                            )
-                        )
-                        # Previous to 3.8 default max_gradient 1.0 was too slow
-                        tabWrite("max_gradient 0.001\n")
-                        if ob.pov.contained_by == "sphere":
-                            tabWrite("contained_by { sphere{0, 2} }\n")
-                        else:
-                            tabWrite("contained_by { box{-2, 2} }\n")
-                        tabWrite("max_gradient %.6f\n" % ob.pov.max_gradient)
-                        tabWrite("accuracy %.6f\n" % ob.pov.accuracy)
-                        tabWrite("precompute 10 x,y,z\n")
-                        tabWrite("}\n")
-                        continue  # Don't render proxy mesh, skip to next object
-
-                    if ob.pov.object_as == 'POLYCIRCLE':
-                        # TODO write below macro Once:
-                        # if write_polytocircle_macro_once == 0:
-                        file.write("/****************************\n")
-                        file.write("This macro was written by 'And'.\n")
-                        file.write(
-                            "Link:(http://news.povray.org/povray.binaries.scene-files/)\n"
-                        )
-                        file.write("****************************/\n")
-                        file.write("//from math.inc:\n")
-                        file.write("#macro VPerp_Adjust(V, Axis)\n")
-                        file.write(
-                            "   vnormalize(vcross(vcross(Axis, V), Axis))\n"
-                        )
-                        file.write("#end\n")
-                        file.write("//Then for the actual macro\n")
-                        file.write(
-                            "#macro Shape_Slice_Plane_2P_1V(point1, point2, clip_direct)\n"
-                        )
-                        file.write("#local p1 = point1 + <0,0,0>;\n")
-                        file.write("#local p2 = point2 + <0,0,0>;\n")
-                        file.write(
-                            "#local clip_v = vnormalize(clip_direct + <0,0,0>);\n"
-                        )
-                        file.write("#local direct_v1 = vnormalize(p2 - p1);\n")
-                        file.write("#if(vdot(direct_v1, clip_v) = 1)\n")
-                        file.write(
-                            '    #error "Shape_Slice_Plane_2P_1V error: Can\'t decide plane"\n'
-                        )
-                        file.write("#end\n\n")
-                        file.write(
-                            "#local norm = -vnormalize(clip_v - direct_v1*vdot(direct_v1,clip_v));\n"
-                        )
-                        file.write("#local d = vdot(norm, p1);\n")
-                        file.write("plane{\n")
-                        file.write("norm, d\n")
-                        file.write("}\n")
-                        file.write("#end\n\n")
-                        file.write("//polygon to circle\n")
-                        file.write(
-                            "#macro Shape_Polygon_To_Circle_Blending(_polygon_n, _side_face, _polygon_circumscribed_radius, _circle_radius, _height)\n"
-                        )
-                        file.write("#local n = int(_polygon_n);\n")
-                        file.write("#if(n < 3)\n")
-                        file.write("    #error " "\n")
-                        file.write("#end\n\n")
-                        file.write(
-                            "#local front_v = VPerp_Adjust(_side_face, z);\n"
-                        )
-                        file.write("#if(vdot(front_v, x) >= 0)\n")
-                        file.write(
-                            "    #local face_ang = acos(vdot(-y, front_v));\n"
-                        )
-                        file.write("#else\n")
-                        file.write(
-                            "    #local face_ang = -acos(vdot(-y, front_v));\n"
-                        )
-                        file.write("#end\n")
-                        file.write("#local polyg_ext_ang = 2*pi/n;\n")
-                        file.write(
-                            "#local polyg_outer_r = _polygon_circumscribed_radius;\n"
-                        )
-                        file.write(
-                            "#local polyg_inner_r = polyg_outer_r*cos(polyg_ext_ang/2);\n"
-                        )
-                        file.write("#local cycle_r = _circle_radius;\n")
-                        file.write("#local h = _height;\n")
-                        file.write(
-                            "#if(polyg_outer_r < 0 | cycle_r < 0 | h <= 0)\n"
-                        )
-                        file.write(
-                            '    #error "error: each side length must be positive"\n'
-                        )
-                        file.write("#end\n\n")
-                        file.write("#local multi = 1000;\n")
-                        file.write("#local poly_obj =\n")
-                        file.write("polynomial{\n")
-                        file.write("4,\n")
-                        file.write("xyz(0,2,2): multi*1,\n")
-                        file.write("xyz(2,0,1): multi*2*h,\n")
-                        file.write(
-                            "xyz(1,0,2): multi*2*(polyg_inner_r-cycle_r),\n"
-                        )
-                        file.write("xyz(2,0,0): multi*(-h*h),\n")
-                        file.write(
-                            "xyz(0,0,2): multi*(-pow(cycle_r - polyg_inner_r, 2)),\n"
-                        )
-                        file.write(
-                            "xyz(1,0,1): multi*2*h*(-2*polyg_inner_r + cycle_r),\n"
-                        )
-                        file.write("xyz(1,0,0): multi*2*h*h*polyg_inner_r,\n")
-                        file.write(
-                            "xyz(0,0,1): multi*2*h*polyg_inner_r*(polyg_inner_r - cycle_r),\n"
-                        )
-                        file.write(
-                            "xyz(0,0,0): multi*(-pow(polyg_inner_r*h, 2))\n"
-                        )
-                        file.write("sturm\n")
-                        file.write("}\n\n")
-                        file.write("#local mockup1 =\n")
-                        file.write("difference{\n")
-                        file.write("    cylinder{\n")
-                        file.write(
-                            "    <0,0,0.0>,<0,0,h>, max(polyg_outer_r, cycle_r)\n"
-                        )
-                        file.write("    }\n\n")
-                        file.write("    #for(i, 0, n-1)\n")
-                        file.write("        object{\n")
-                        file.write("        poly_obj\n")
-                        file.write("        inverse\n")
-                        file.write(
-                            "        rotate <0, 0, -90 + degrees(polyg_ext_ang*i)>\n"
-                        )
-                        file.write("        }\n")
-                        file.write("        object{\n")
-                        file.write(
-                            "        Shape_Slice_Plane_2P_1V(<polyg_inner_r,0,0>,<cycle_r,0,h>,x)\n"
-                        )
-                        file.write(
-                            "        rotate <0, 0, -90 + degrees(polyg_ext_ang*i)>\n"
-                        )
-                        file.write("        }\n")
-                        file.write("    #end\n")
-                        file.write("}\n\n")
-                        file.write("object{\n")
-                        file.write("mockup1\n")
-                        file.write("rotate <0, 0, degrees(face_ang)>\n")
-                        file.write("}\n")
-                        file.write("#end\n")
-                        # Use the macro
-                        ngon = ob.pov.polytocircle_ngon
-                        ngonR = ob.pov.polytocircle_ngonR
-                        circleR = ob.pov.polytocircle_circleR
-                        tabWrite(
-                            "#declare %s = object { Shape_Polygon_To_Circle_Blending(%s, z, %.4f, %.4f, 2) rotate x*180 translate z*1\n"
-                            % (povdataname, ngon, ngonR, circleR)
-                        )
-                        tabWrite("}\n")
-                        continue  # Don't render proxy mesh, skip to next object
-
-                    ############################################else try to export mesh
-                    elif (
-                        ob.is_instancer == False
-                    ):  # except duplis which should be instances groups for now but all duplis later
-                        if ob.type == 'EMPTY':
-                            tabWrite(
-                                "\n//dummy sphere to represent Empty location\n"
-                            )
-                            tabWrite(
-                                "#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n"
-                                % povdataname
-                            )
-
-                        # TODO(sergey): PovRay is a render engine, so should be using dependency graph
-                        # which was given to it via render engine API.
-                        depsgraph = bpy.context.evaluated_depsgraph_get()
-                        ob_eval = ob.evaluated_get(depsgraph)
-                        try:
-                            me = ob_eval.to_mesh()
-
-                        # XXX Here? identify the specific exception for mesh object with no data
-                        # XXX So that we can write something for the dataname !
-                        except:
-
-                            # also happens when curves cant be made into meshes because of no-data
-                            continue
-
-                        importance = ob.pov.importance_value
-                        if me:
-                            me.calc_loop_triangles()
-                            me_materials = me.materials
-                            me_faces = me.loop_triangles[:]
-                            ## numpytest
-                            #me_looptris = me.loops
-
-                            ## otypes = ['int32'] is a 32-bit signed integer number numpy datatype
-                            #get_v_index = np.vectorize(lambda l: l.vertex_index, otypes = ['int32'], cache = True)
-                            #faces_verts_idx = get_v_index(me_looptris)
-
-
-                        # if len(me_faces)==0:
-                        # tabWrite("\n//dummy sphere to represent empty mesh location\n")
-                        # tabWrite("#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n" % povdataname)
-
-                        if not me or not me_faces:
-                            tabWrite(
-                                "\n//dummy sphere to represent empty mesh location\n"
-                            )
-                            tabWrite(
-                                "#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n"
-                                % povdataname
-                            )
-                            continue
-
-                        uv_layers = me.uv_layers
-                        if len(uv_layers) > 0:
-                            if me.uv_layers.active and uv_layers.active.data:
-                                uv_layer = uv_layers.active.data
-                        else:
-                            uv_layer = None
-
-                        try:
-                            # vcol_layer = me.vertex_colors.active.data
-                            vcol_layer = me.vertex_colors.active.data
-                        except AttributeError:
-                            vcol_layer = None
-
-                        faces_verts = [f.vertices[:] for f in me_faces]
-                        faces_normals = [f.normal[:] for f in me_faces]
-                        verts_normals = [v.normal[:] for v in me.vertices]
-
-                        # Use named declaration to allow reference e.g. for baking. MR
-                        file.write("\n")
-                        tabWrite("#declare %s =\n" % povdataname)
-                        tabWrite("mesh2 {\n")
-                        tabWrite("vertex_vectors {\n")
-                        tabWrite("%d" % len(me.vertices))  # vert count
-
-                        tabStr = tab * tabLevel
-                        for v in me.vertices:
-                            if linebreaksinlists:
-                                file.write(",\n")
-                                file.write(
-                                    tabStr + "<%.6f, %.6f, %.6f>" % v.co[:]
-                                )  # vert count
-                            else:
-                                file.write(", ")
-                                file.write(
-                                    "<%.6f, %.6f, %.6f>" % v.co[:]
-                                )  # vert count
-                            # tabWrite("<%.6f, %.6f, %.6f>" % v.co[:])  # vert count
-                        file.write("\n")
-                        tabWrite("}\n")
-
-                        # Build unique Normal list
-                        uniqueNormals = {}
-                        for fi, f in enumerate(me_faces):
-                            fv = faces_verts[fi]
-                            # [-1] is a dummy index, use a list so we can modify in place
-                            if f.use_smooth:  # Use vertex normals
-                                for v in fv:
-                                    key = verts_normals[v]
-                                    uniqueNormals[key] = [-1]
-                            else:  # Use face normal
-                                key = faces_normals[fi]
-                                uniqueNormals[key] = [-1]
-
-                        tabWrite("normal_vectors {\n")
-                        tabWrite("%d" % len(uniqueNormals))  # vert count
-                        idx = 0
-                        tabStr = tab * tabLevel
-                        for no, index in uniqueNormals.items():
-                            if linebreaksinlists:
-                                file.write(",\n")
-                                file.write(
-                                    tabStr + "<%.6f, %.6f, %.6f>" % no
-                                )  # vert count
-                            else:
-                                file.write(", ")
-                                file.write(
-                                    "<%.6f, %.6f, %.6f>" % no
-                                )  # vert count
-                            index[0] = idx
-                            idx += 1
-                        file.write("\n")
-                        tabWrite("}\n")
-
-                        # Vertex colors
-                        vertCols = {}  # Use for material colors also.
-
-                        if uv_layer:
-                            # Generate unique UV's
-                            uniqueUVs = {}
-                            # n = 0
-                            for f in me_faces:  # me.faces in 2.7
-                                uvs = [uv_layer[l].uv[:] for l in f.loops]
-
-                                for uv in uvs:
-                                    uniqueUVs[uv[:]] = [-1]
-
-                            tabWrite("uv_vectors {\n")
-                            # print unique_uvs
-                            tabWrite("%d" % len(uniqueUVs))  # vert count
-                            idx = 0
-                            tabStr = tab * tabLevel
-                            for uv, index in uniqueUVs.items():
-                                if linebreaksinlists:
-                                    file.write(",\n")
-                                    file.write(tabStr + "<%.6f, %.6f>" % uv)
-                                else:
-                                    file.write(", ")
-                                    file.write("<%.6f, %.6f>" % uv)
-                                index[0] = idx
-                                idx += 1
-                            '''
-                            else:
-                                # Just add 1 dummy vector, no real UV's
-                                tabWrite('1') # vert count
-                                file.write(',\n\t\t<0.0, 0.0>')
-                            '''
-                            file.write("\n")
-                            tabWrite("}\n")
-
-                        if me.vertex_colors:
-                            # Write down vertex colors as a texture for each vertex
-                            tabWrite("texture_list {\n")
-                            tabWrite(
-                                "%d\n" % (len(me_faces) * 3)
-                            )  # assumes we have only triangles
-                            VcolIdx = 0
-                            if comments:
-                                file.write(
-                                    "\n  //Vertex colors: one simple pigment texture per vertex\n"
-                                )
-                            for fi, f in enumerate(me_faces):
-                                # annoying, index may be invalid
-                                material_index = f.material_index
-                                try:
-                                    material = me_materials[material_index]
-                                except:
-                                    material = None
-                                if (
-                                    material
-                                ):  # and material.use_vertex_color_paint: #Always use vertex color when there is some for now
-
-                                    cols = [
-                                        vcol_layer[l].color[:] for l in f.loops
-                                    ]
-
-                                    for col in cols:
-                                        key = (
-                                            col[0],
-                                            col[1],
-                                            col[2],
-                                            material_index,
-                                        )  # Material index!
-                                        VcolIdx += 1
-                                        vertCols[key] = [VcolIdx]
-                                        if linebreaksinlists:
-                                            tabWrite(
-                                                "texture {pigment{ color srgb <%6f,%6f,%6f> }}\n"
-                                                % (col[0], col[1], col[2])
-                                            )
-                                        else:
-                                            tabWrite(
-                                                "texture {pigment{ color srgb <%6f,%6f,%6f> }}"
-                                                % (col[0], col[1], col[2])
-                                            )
-                                            tabStr = tab * tabLevel
-                                else:
-                                    if material:
-                                        # Multiply diffuse with SSS Color
-                                        if (
-                                            material.pov_subsurface_scattering.use
-                                        ):
-                                            diffuse_color = [
-                                                i * j
-                                                for i, j in zip(
-                                                    material.pov_subsurface_scattering.color[
-                                                        :
-                                                    ],
-                                                    material.diffuse_color[:],
-                                                )
-                                            ]
-                                            key = (
-                                                diffuse_color[0],
-                                                diffuse_color[1],
-                                                diffuse_color[2],
-                                                material_index,
-                                            )
-                                            vertCols[key] = [-1]
-                                        else:
-                                            diffuse_color = material.diffuse_color[
-                                                :
-                                            ]
-                                            key = (
-                                                diffuse_color[0],
-                                                diffuse_color[1],
-                                                diffuse_color[2],
-                                                material_index,
-                                            )
-                                            vertCols[key] = [-1]
-
-                            tabWrite("\n}\n")
-                            # Face indices
-                            tabWrite("\nface_indices {\n")
-                            tabWrite("%d" % (len(me_faces)))  # faces count
-                            tabStr = tab * tabLevel
-
-                            for fi, f in enumerate(me_faces):
-                                fv = faces_verts[fi]
-                                material_index = f.material_index
-
-                                if vcol_layer:
-                                    cols = [
-                                        vcol_layer[l].color[:] for l in f.loops
-                                    ]
-
-                                if (
-                                    not me_materials
-                                    or me_materials[material_index] is None
-                                ):  # No materials
-                                    if linebreaksinlists:
-                                        file.write(",\n")
-                                        # vert count
-                                        file.write(
-                                            tabStr
-                                            + "<%d,%d,%d>"
-                                            % (fv[0], fv[1], fv[2])
-                                        )
-                                    else:
-                                        file.write(", ")
-                                        file.write(
-                                            "<%d,%d,%d>" % (fv[0], fv[1], fv[2])
-                                        )  # vert count
-                                else:
-                                    material = me_materials[material_index]
-                                    if (
-                                        me.vertex_colors
-                                    ):  # and material.use_vertex_color_paint:
-                                        # Color per vertex - vertex color
-
-                                        col1 = cols[0]
-                                        col2 = cols[1]
-                                        col3 = cols[2]
-
-                                        ci1 = vertCols[
-                                            col1[0],
-                                            col1[1],
-                                            col1[2],
-                                            material_index,
-                                        ][0]
-                                        ci2 = vertCols[
-                                            col2[0],
-                                            col2[1],
-                                            col2[2],
-                                            material_index,
-                                        ][0]
-                                        ci3 = vertCols[
-                                            col3[0],
-                                            col3[1],
-                                            col3[2],
-                                            material_index,
-                                        ][0]
-                                    else:
-                                        # Color per material - flat material color
-                                        if (
-                                            material.pov_subsurface_scattering.use
-                                        ):
-                                            diffuse_color = [
-                                                i * j
-                                                for i, j in zip(
-                                                    material.pov_subsurface_scattering.color[
-                                                        :
-                                                    ],
-                                                    material.diffuse_color[:],
-                                                )
-                                            ]
-                                        else:
-                                            diffuse_color = material.diffuse_color[
-                                                :
-                                            ]
-                                        ci1 = ci2 = ci3 = vertCols[
-                                            diffuse_color[0],
-                                            diffuse_color[1],
-                                            diffuse_color[2],
-                                            f.material_index,
-                                        ][0]
-                                        # ci are zero based index so we'll subtract 1 from them
-                                    if linebreaksinlists:
-                                        file.write(",\n")
-                                        file.write(
-                                            tabStr
-                                            + "<%d,%d,%d>, %d,%d,%d"
-                                            % (
-                                                fv[0],
-                                                fv[1],
-                                                fv[2],
-                                                ci1 - 1,
-                                                ci2 - 1,
-                                                ci3 - 1,
-                                            )
-                                        )  # vert count
-                                    else:
-                                        file.write(", ")
-                                        file.write(
-                                            "<%d,%d,%d>, %d,%d,%d"
-                                            % (
-                                                fv[0],
-                                                fv[1],
-                                                fv[2],
-                                                ci1 - 1,
-                                                ci2 - 1,
-                                                ci3 - 1,
-                                            )
-                                        )  # vert count
-
-                            file.write("\n")
-                            tabWrite("}\n")
-
-                            # normal_indices indices
-                            tabWrite("normal_indices {\n")
-                            tabWrite("%d" % (len(me_faces)))  # faces count
-                            tabStr = tab * tabLevel
-                            for fi, fv in enumerate(faces_verts):
-
-                                if me_faces[fi].use_smooth:
-                                    if linebreaksinlists:
-                                        file.write(",\n")
-                                        file.write(
-                                            tabStr
-                                            + "<%d,%d,%d>"
-                                            % (
-                                                uniqueNormals[
-                                                    verts_normals[fv[0]]
-                                                ][0],
-                                                uniqueNormals[
-                                                    verts_normals[fv[1]]
-                                                ][0],
-                                                uniqueNormals[
-                                                    verts_normals[fv[2]]
-                                                ][0],
-                                            )
-                                        )  # vert count
-                                    else:
-                                        file.write(", ")
-                                        file.write(
-                                            "<%d,%d,%d>"
-                                            % (
-                                                uniqueNormals[
-                                                    verts_normals[fv[0]]
-                                                ][0],
-                                                uniqueNormals[
-                                                    verts_normals[fv[1]]
-                                                ][0],
-                                                uniqueNormals[
-                                                    verts_normals[fv[2]]
-                                                ][0],
-                                            )
-                                        )  # vert count
-                                else:
-                                    idx = uniqueNormals[faces_normals[fi]][0]
-                                    if linebreaksinlists:
-                                        file.write(",\n")
-                                        file.write(
-                                            tabStr
-                                            + "<%d,%d,%d>" % (idx, idx, idx)
-                                        )  # vert count
-                                    else:
-                                        file.write(", ")
-                                        file.write(
-                                            "<%d,%d,%d>" % (idx, idx, idx)
-                                        )  # vert count
-
-                            file.write("\n")
-                            tabWrite("}\n")
-
-                            if uv_layer:
-                                tabWrite("uv_indices {\n")
-                                tabWrite("%d" % (len(me_faces)))  # faces count
-                                tabStr = tab * tabLevel
-                                for f in me_faces:
-                                    uvs = [uv_layer[l].uv[:] for l in f.loops]
-
-                                    if linebreaksinlists:
-                                        file.write(",\n")
-                                        file.write(
-                                            tabStr
-                                            + "<%d,%d,%d>"
-                                            % (
-                                                uniqueUVs[uvs[0]][0],
-                                                uniqueUVs[uvs[1]][0],
-                                                uniqueUVs[uvs[2]][0],
-                                            )
-                                        )
-                                    else:
-                                        file.write(", ")
-                                        file.write(
-                                            "<%d,%d,%d>"
-                                            % (
-                                                uniqueUVs[uvs[0]][0],
-                                                uniqueUVs[uvs[1]][0],
-                                                uniqueUVs[uvs[2]][0],
-                                            )
-                                        )
-
-                                file.write("\n")
-                                tabWrite("}\n")
-
-                            # XXX BOOLEAN
-                            onceCSG = 0
-                            for mod in ob.modifiers:
-                                if onceCSG == 0:
-                                    if mod:
-                                        if mod.type == 'BOOLEAN':
-                                            if ob.pov.boolean_mod == "POV":
-                                                file.write(
-                                                    "\tinside_vector <%.6g, %.6g, %.6g>\n"
-                                                    % (
-                                                        ob.pov.inside_vector[0],
-                                                        ob.pov.inside_vector[1],
-                                                        ob.pov.inside_vector[2],
-                                                    )
-                                                )
-                                                onceCSG = 1
-
-                            if me.materials:
-                                try:
-                                    material = me.materials[0]  # dodgy
-                                    writeObjectMaterial(material, ob)
-                                except IndexError:
-                                    print(me)
-
-                            # POV object modifiers such as
-                            # hollow / sturm / double_illuminate etc.
-                            write_object_modifiers(scene, ob, file)
-
-                            # Importance for radiosity sampling added here:
-                            tabWrite("radiosity { \n")
-                            tabWrite("importance %3g \n" % importance)
-                            tabWrite("}\n")
-
-                            tabWrite("}\n")  # End of mesh block
-                        else:
-                            facesMaterials = []  # WARNING!!!!!!!!!!!!!!!!!!!!!!
-                            if me_materials:
-                                for f in me_faces:
-                                    if f.material_index not in facesMaterials:
-                                        facesMaterials.append(f.material_index)
-                            # No vertex colors, so write material colors as vertex colors
-                            for i, material in enumerate(me_materials):
-
-                                if (
-                                    material
-                                    and material.pov.material_use_nodes == False
-                                ):  # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-                                    # Multiply diffuse with SSS Color
-                                    if material.pov_subsurface_scattering.use:
-                                        diffuse_color = [
-                                            i * j
-                                            for i, j in zip(
-                                                material.pov_subsurface_scattering.color[
-                                                    :
-                                                ],
-                                                material.diffuse_color[:],
-                                            )
-                                        ]
-                                        key = (
-                                            diffuse_color[0],
-                                            diffuse_color[1],
-                                            diffuse_color[2],
-                                            i,
-                                        )  # i == f.mat
-                                        vertCols[key] = [-1]
-                                    else:
-                                        diffuse_color = material.diffuse_color[
-                                            :
-                                        ]
-                                        key = (
-                                            diffuse_color[0],
-                                            diffuse_color[1],
-                                            diffuse_color[2],
-                                            i,
-                                        )  # i == f.mat
-                                        vertCols[key] = [-1]
-
-                                    idx = 0
-                                    LocalMaterialNames = []
-                                    for col, index in vertCols.items():
-                                        # if me_materials:
-                                        mater = me_materials[col[3]]
-                                        if me_materials is None:  # XXX working?
-                                            material_finish = (
-                                                DEF_MAT_NAME
-                                            )  # not working properly,
-                                            trans = 0.0
-
-                                        else:
-                                            shading.writeTextureInfluence(
-                                                using_uberpov,
-                                                mater,
-                                                materialNames,
-                                                LocalMaterialNames,
-                                                path_image,
-                                                lampCount,
-                                                imageFormat,
-                                                imgMap,
-                                                imgMapTransforms,
-                                                tabWrite,
-                                                comments,
-                                                string_strip_hyphen,
-                                                safety,
-                                                col,
-                                                os,
-                                                preview_dir,
-                                                unpacked_images,
-                                            )
-                                        ###################################################################
-                                        index[0] = idx
-                                        idx += 1
-
-                            # Vert Colors
-                            tabWrite("texture_list {\n")
-                            # In case there's is no material slot, give at least one texture
-                            # (an empty one so it uses pov default)
-                            if len(vertCols) == 0:
-                                file.write(tabStr + "1")
-                            else:
-                                file.write(
-                                    tabStr + "%s" % (len(vertCols))
-                                )  # vert count
-
-                            # below "material" alias, added check ob.active_material
-                            # to avoid variable referenced before assignment error
-                            try:
-                                material = ob.active_material
-                            except IndexError:
-                                # when no material slot exists,
-                                material = None
-
-                            # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-                            if (
-                                material
-                                and ob.active_material is not None
-                                and material.pov.material_use_nodes == False
-                            ):
-                                if material.pov.replacement_text != "":
-                                    file.write("\n")
-                                    file.write(
-                                        " texture{%s}\n"
-                                        % material.pov.replacement_text
-                                    )
-
-                                else:
-                                    # Loop through declared materials list
-                                    for cMN in LocalMaterialNames:
-                                        if material != "Default":
-                                            file.write(
-                                                "\n texture{MAT_%s}\n" % cMN
-                                            )
-                                            # use string_strip_hyphen(materialNames[material]))
-                                            # or Something like that to clean up the above?
-                            elif material and material.pov.material_use_nodes:
-                                for index in facesMaterials:
-                                    faceMaterial = string_strip_hyphen(
-                                        bpy.path.clean_name(
-                                            me_materials[index].name
-                                        )
-                                    )
-                                    file.write(
-                                        "\n texture{%s}\n" % faceMaterial
-                                    )
-                            # END!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-                            else:
-                                file.write(" texture{}\n")
-                            tabWrite("}\n")
-
-                            # Face indices
-                            tabWrite("face_indices {\n")
-                            tabWrite("%d" % (len(me_faces)))  # faces count
-                            tabStr = tab * tabLevel
-
-                            for fi, f in enumerate(me_faces):
-                                fv = faces_verts[fi]
-                                material_index = f.material_index
-
-                                if vcol_layer:
-                                    cols = [
-                                        vcol_layer[l].color[:] for l in f.loops
-                                    ]
-
-                                if (
-                                    not me_materials
-                                    or me_materials[material_index] is None
-                                ):  # No materials
-                                    if linebreaksinlists:
-                                        file.write(",\n")
-                                        # vert count
-                                        file.write(
-                                            tabStr
-                                            + "<%d,%d,%d>"
-                                            % (fv[0], fv[1], fv[2])
-                                        )
-                                    else:
-                                        file.write(", ")
-                                        file.write(
-                                            "<%d,%d,%d>" % (fv[0], fv[1], fv[2])
-                                        )  # vert count
-                                else:
-                                    material = me_materials[material_index]
-                                    ci1 = ci2 = ci3 = f.material_index
-                                    if (
-                                        me.vertex_colors
-                                    ):  # and material.use_vertex_color_paint:
-                                        # Color per vertex - vertex color
-
-                                        col1 = cols[0]
-                                        col2 = cols[1]
-                                        col3 = cols[2]
-
-                                        ci1 = vertCols[
-                                            col1[0],
-                                            col1[1],
-                                            col1[2],
-                                            material_index,
-                                        ][0]
-                                        ci2 = vertCols[
-                                            col2[0],
-                                            col2[1],
-                                            col2[2],
-                                            material_index,
-                                        ][0]
-                                        ci3 = vertCols[
-                                            col3[0],
-                                            col3[1],
-                                            col3[2],
-                                            material_index,
-                                        ][0]
-                                    elif material.pov.material_use_nodes:
-                                        ci1 = ci2 = ci3 = 0
-                                    else:
-                                        # Color per material - flat material color
-                                        if (
-                                            material.pov_subsurface_scattering.use
-                                        ):
-                                            diffuse_color = [
-                                                i * j
-                                                for i, j in zip(
-                                                    material.pov_subsurface_scattering.color[
-                                                        :
-                                                    ],
-                                                    material.diffuse_color[:],
-                                                )
-                                            ]
-                                        else:
-                                            diffuse_color = material.diffuse_color[
-                                                :
-                                            ]
-                                        ci1 = ci2 = ci3 = vertCols[
-                                            diffuse_color[0],
-                                            diffuse_color[1],
-                                            diffuse_color[2],
-                                            f.material_index,
-                                        ][0]
-
-                                    if linebreaksinlists:
-                                        file.write(",\n")
-                                        file.write(
-                                            tabStr
-                                            + "<%d,%d,%d>, %d,%d,%d"
-                                            % (
-                                                fv[0],
-                                                fv[1],
-                                                fv[2],
-                                                ci1,
-                                                ci2,
-                                                ci3,
-                                            )
-                                        )  # vert count
-                                    else:
-                                        file.write(", ")
-                                        file.write(
-                                            "<%d,%d,%d>, %d,%d,%d"
-                                            % (
-                                                fv[0],
-                                                fv[1],
-                                                fv[2],
-                                                ci1,
-                                                ci2,
-                                                ci3,
-                                            )
-                                        )  # vert count
-
-                            file.write("\n")
-                            tabWrite("}\n")
-
-                            # normal_indices indices
-                            tabWrite("normal_indices {\n")
-                            tabWrite("%d" % (len(me_faces)))  # faces count
-                            tabStr = tab * tabLevel
-                            for fi, fv in enumerate(faces_verts):
-                                if me_faces[fi].use_smooth:
-                                    if linebreaksinlists:
-                                        file.write(",\n")
-                                        file.write(
-                                            tabStr
-                                            + "<%d,%d,%d>"
-                                            % (
-                                                uniqueNormals[
-                                                    verts_normals[fv[0]]
-                                                ][0],
-                                                uniqueNormals[
-                                                    verts_normals[fv[1]]
-                                                ][0],
-                                                uniqueNormals[
-                                                    verts_normals[fv[2]]
-                                                ][0],
-                                            )
-                                        )  # vert count
-                                    else:
-                                        file.write(", ")
-                                        file.write(
-                                            "<%d,%d,%d>"
-                                            % (
-                                                uniqueNormals[
-                                                    verts_normals[fv[0]]
-                                                ][0],
-                                                uniqueNormals[
-                                                    verts_normals[fv[1]]
-                                                ][0],
-                                                uniqueNormals[
-                                                    verts_normals[fv[2]]
-                                                ][0],
-                                            )
-                                        )  # vert count
-                                else:
-                                    idx = uniqueNormals[faces_normals[fi]][0]
-                                    if linebreaksinlists:
-                                        file.write(",\n")
-                                        file.write(
-                                            tabStr
-                                            + "<%d,%d,%d>" % (idx, idx, idx)
-                                        )  # vertcount
-                                    else:
-                                        file.write(", ")
-                                        file.write(
-                                            "<%d,%d,%d>" % (idx, idx, idx)
-                                        )  # vert count
-
-                            file.write("\n")
-                            tabWrite("}\n")
-
-                            if uv_layer:
-                                tabWrite("uv_indices {\n")
-                                tabWrite("%d" % (len(me_faces)))  # faces count
-                                tabStr = tab * tabLevel
-                                for f in me_faces:
-                                    uvs = [uv_layer[l].uv[:] for l in f.loops]
-
-                                    if linebreaksinlists:
-                                        file.write(",\n")
-                                        file.write(
-                                            tabStr
-                                            + "<%d,%d,%d>"
-                                            % (
-                                                uniqueUVs[uvs[0]][0],
-                                                uniqueUVs[uvs[1]][0],
-                                                uniqueUVs[uvs[2]][0],
-                                            )
-                                        )
-                                    else:
-                                        file.write(", ")
-                                        file.write(
-                                            "<%d,%d,%d>"
-                                            % (
-                                                uniqueUVs[uvs[0]][0],
-                                                uniqueUVs[uvs[1]][0],
-                                                uniqueUVs[uvs[2]][0],
-                                            )
-                                        )
-
-                                file.write("\n")
-                                tabWrite("}\n")
-
-                            # XXX BOOLEAN
-                            onceCSG = 0
-                            for mod in ob.modifiers:
-                                if onceCSG == 0:
-                                    if mod:
-                                        if mod.type == 'BOOLEAN':
-                                            if ob.pov.boolean_mod == "POV":
-                                                file.write(
-                                                    "\tinside_vector <%.6g, %.6g, %.6g>\n"
-                                                    % (
-                                                        ob.pov.inside_vector[0],
-                                                        ob.pov.inside_vector[1],
-                                                        ob.pov.inside_vector[2],
-                                                    )
-                                                )
-                                                onceCSG = 1
-
-                            if me.materials:
-                                try:
-                                    material = me.materials[0]  # dodgy
-                                    writeObjectMaterial(material, ob)
-                                except IndexError:
-                                    print(me)
-
-                            # POV object modifiers such as
-                            # hollow / sturm / double_illuminate etc.
-                            write_object_modifiers(scene, ob, file)
-
-                            # Importance for radiosity sampling added here:
-                            tabWrite("radiosity { \n")
-                            tabWrite("importance %3g \n" % importance)
-                            tabWrite("}\n")
-
-                            tabWrite("}\n")  # End of mesh block
-
-                        ob_eval.to_mesh_clear()
-
-        if csg:
-            duplidata_ref = []
-            _dupnames_seen = (
-                dict()
-            )  # avoid duplicate output during introspection
-            for ob in sel:
-                # matrix = global_matrix @ ob.matrix_world
-                if ob.is_instancer:
-                    tabWrite("\n//--DupliObjects in %s--\n\n" % ob.name)
-                    # ob.dupli_list_create(scene) #deprecated in 2.8
-                    depsgraph = bpy.context.evaluated_depsgraph_get()
-                    dup = ""
-                    if ob.is_modified(scene, 'RENDER'):
-                        # modified object always unique so using object name rather than data name
-                        dup = "#declare OB%s = union{\n" % (
-                            string_strip_hyphen(bpy.path.clean_name(ob.name))
-                        )
-                    else:
-                        dup = "#declare DATA%s = union{\n" % (
-                            string_strip_hyphen(bpy.path.clean_name(ob.name))
-                        )
-                    for eachduplicate in depsgraph.object_instances:
-                        if (
-                            eachduplicate.is_instance
-                        ):  # Real dupli instance filtered because original included in list since 2.8
-                            _dupname = eachduplicate.object.name
-                            _dupobj = bpy.data.objects[_dupname]
-                            # BEGIN introspection for troubleshooting purposes
-                            if not "name" in dir(_dupobj.data):
-                                if _dupname not in _dupnames_seen:
-                                    print(
-                                        "WARNING: bpy.data.objects[%s].data (of type %s) has no 'name' attribute"
-                                        % (_dupname, type(_dupobj.data))
-                                    )
-                                    for _thing in dir(_dupobj):
-                                        print(
-                                            "||  %s.%s = %s"
-                                            % (
-                                                _dupname,
-                                                _thing,
-                                                getattr(_dupobj, _thing),
-                                            )
-                                        )
-                                    _dupnames_seen[_dupname] = 1
-                                    print(
-                                        "''=>  Unparseable objects so far: %s"
-                                        % (_dupnames_seen)
-                                    )
-                                else:
-                                    _dupnames_seen[_dupname] += 1
-                                continue  # don't try to parse data objects with no name attribute
-                            # END introspection for troubleshooting purposes
-                            duplidataname = "OB" + string_strip_hyphen(
-                                bpy.path.clean_name(_dupobj.data.name)
-                            )
-                            dupmatrix = (
-                                eachduplicate.matrix_world.copy()
-                            )  # has to be copied to not store instance since 2.8
-                            dup += "\tobject {\n\t\tDATA%s\n\t\t%s\t}\n" % (
-                                string_strip_hyphen(
-                                    bpy.path.clean_name(_dupobj.data.name)
-                                ),
-                                MatrixAsPovString(
-                                    ob.matrix_world.inverted() @ dupmatrix
-                                ),
-                            )
-                            # add object to a list so that it is not rendered for some instance_types
-                            if (
-                                ob.instance_type not in {'COLLECTION'}
-                                and duplidataname not in duplidata_ref
-                            ):
-                                duplidata_ref.append(
-                                    duplidataname
-                                )  # older key [string_strip_hyphen(bpy.path.clean_name("OB"+ob.name))]
-                    dup += "}\n"
-                    # ob.dupli_list_clear()# just do not store any reference to instance since 2.8
-                    tabWrite(dup)
-                else:
-                    continue
-            print(
-                "WARNING: Unparseable objects in current .blend file:\n''=> %s"
-                % (_dupnames_seen)
-            )
-            print("duplidata_ref = %s" % (duplidata_ref))
-            for data_name, inst in data_ref.items():
-                for ob_name, matrix_str in inst:
-                    if (
-                        ob_name not in duplidata_ref
-                    ):  # .items() for a dictionary
-                        tabWrite(
-                            "\n//----Blender Object Name:%s----\n" % ob_name
-                        )
-                        if ob.pov.object_as == '':
-                            tabWrite("object { \n")
-                            tabWrite("%s\n" % data_name)
-                            tabWrite("%s\n" % matrix_str)
-                            tabWrite("}\n")
-                        else:
-                            no_boolean = True
-                            for mod in ob.modifiers:
-                                if mod.type == 'BOOLEAN':
-                                    operation = None
-                                    no_boolean = False
-                                    if mod.operation == 'INTERSECT':
-                                        operation = 'intersection'
-                                    else:
-                                        operation = mod.operation.lower()
-                                    mod_ob_name = string_strip_hyphen(
-                                        bpy.path.clean_name(mod.object.name)
-                                    )
-                                    mod_matrix = (
-                                        global_matrix @ mod.object.matrix_world
-                                    )
-                                    mod_ob_matrix = MatrixAsPovString(
-                                        mod_matrix
-                                    )
-                                    tabWrite("%s { \n" % operation)
-                                    tabWrite("object { \n")
-                                    tabWrite("%s\n" % data_name)
-                                    tabWrite("%s\n" % matrix_str)
-                                    tabWrite("}\n")
-                                    tabWrite("object { \n")
-                                    tabWrite("%s\n" % ('DATA' + mod_ob_name))
-                                    tabWrite("%s\n" % mod_ob_matrix)
-                                    tabWrite("}\n")
-                                    tabWrite("}\n")
-                                    break
-                            if no_boolean:
-                                tabWrite("object { \n")
-                                tabWrite("%s\n" % data_name)
-                                tabWrite("%s\n" % matrix_str)
-                                tabWrite("}\n")
-
-    def exportWorld(world):
-        """write world as POV backgrounbd and sky_sphere to exported file """
-        render = scene.pov
-        camera = scene.camera
-        matrix = global_matrix @ camera.matrix_world
-        if not world:
-            return
-        #############Maurice####################################
-        # These lines added to get sky gradient (visible with PNG output)
-        if world:
-            # For simple flat background:
-            if not world.pov.use_sky_blend:
-                # Non fully transparent background could premultiply alpha and avoid anti-aliasing
-                # display issue:
-                if render.alpha_mode == 'TRANSPARENT':
-                    tabWrite(
-                        "background {rgbt<%.3g, %.3g, %.3g, 0.75>}\n"
-                        % (world.pov.horizon_color[:])
-                    )
-                # Currently using no alpha with Sky option:
-                elif render.alpha_mode == 'SKY':
-                    tabWrite(
-                        "background {rgbt<%.3g, %.3g, %.3g, 0>}\n"
-                        % (world.pov.horizon_color[:])
-                    )
-                # StraightAlpha:
-                # XXX Does not exists anymore
-                # else:
-                # tabWrite("background {rgbt<%.3g, %.3g, %.3g, 1>}\n" % (world.pov.horizon_color[:]))
-
-            worldTexCount = 0
-            # For Background image textures
-            for (
-                t
-            ) in (
-                world.pov_texture_slots
-            ):  # risk to write several sky_spheres but maybe ok.
-                if t:
-                    tex = bpy.data.textures[t.texture]
-                if tex.type is not None:
-                    worldTexCount += 1
-                    # XXX No enable checkbox for world textures yet (report it?)
-                    # if t and tex.type == 'IMAGE' and t.use:
-                    if tex.type == 'IMAGE':
-                        image_filename = path_image(tex.image)
-                        if tex.image.filepath != image_filename:
-                            tex.image.filepath = image_filename
-                        if image_filename != "" and t.use_map_blend:
-                            texturesBlend = image_filename
-                            # colvalue = t.default_value
-                            t_blend = t
-
-                        # Commented below was an idea to make the Background image oriented as camera
-                        # taken here:
-                        # http://news.pov.org/pov.newusers/thread/%3Cweb.4a5cddf4e9c9822ba2f93e20@news.pov.org%3E/
-                        # Replace 4/3 by the ratio of each image found by some custom or existing
-                        # function
-                        # mappingBlend = (" translate <%.4g,%.4g,%.4g> rotate z*degrees" \
-                        #                "(atan((camLocation - camLookAt).x/(camLocation - " \
-                        #                "camLookAt).y)) rotate x*degrees(atan((camLocation - " \
-                        #                "camLookAt).y/(camLocation - camLookAt).z)) rotate y*" \
-                        #                "degrees(atan((camLocation - camLookAt).z/(camLocation - " \
-                        #                "camLookAt).x)) scale <%.4g,%.4g,%.4g>b" % \
-                        #                (t_blend.offset.x / 10 , t_blend.offset.y / 10 ,
-                        #                 t_blend.offset.z / 10, t_blend.scale.x ,
-                        #                 t_blend.scale.y , t_blend.scale.z))
-                        # using camera rotation valuesdirectly from blender seems much easier
-                        if t_blend.texture_coords == 'ANGMAP':
-                            mappingBlend = ""
-                        else:
-                            # POV-Ray "scale" is not a number of repetitions factor, but its
-                            # inverse, a standard scale factor.
-                            # 0.5 Offset is needed relatively to scale because center of the
-                            # UV scale is 0.5,0.5 in blender and 0,0 in POV
-                            # Further Scale by 2 and translate by -1 are
-                            # required for the sky_sphere not to repeat
-
-                            mappingBlend = (
-                                "scale 2 scale <%.4g,%.4g,%.4g> translate -1 "
-                                "translate <%.4g,%.4g,%.4g> rotate<0,0,0> "
-                                % (
-                                    (1.0 / t_blend.scale.x),
-                                    (1.0 / t_blend.scale.y),
-                                    (1.0 / t_blend.scale.z),
-                                    0.5
-                                    - (0.5 / t_blend.scale.x)
-                                    - t_blend.offset.x,
-                                    0.5
-                                    - (0.5 / t_blend.scale.y)
-                                    - t_blend.offset.y,
-                                    t_blend.offset.z,
-                                )
-                            )
-
-                            # The initial position and rotation of the pov camera is probably creating
-                            # the rotation offset should look into it someday but at least background
-                            # won't rotate with the camera now.
-                        # Putting the map on a plane would not introduce the skysphere distortion and
-                        # allow for better image scale matching but also some waay to chose depth and
-                        # size of the plane relative to camera.
-                        tabWrite("sky_sphere {\n")
-                        tabWrite("pigment {\n")
-                        tabWrite(
-                            "image_map{%s \"%s\" %s}\n"
-                            % (
-                                imageFormat(texturesBlend),
-                                texturesBlend,
-                                imgMapBG(t_blend),
-                            )
-                        )
-                        tabWrite("}\n")
-                        tabWrite("%s\n" % (mappingBlend))
-                        # The following layered pigment opacifies to black over the texture for
-                        # transmit below 1 or otherwise adds to itself
-                        tabWrite(
-                            "pigment {rgb 0 transmit %s}\n" % (tex.intensity)
-                        )
-                        tabWrite("}\n")
-                        # tabWrite("scale 2\n")
-                        # tabWrite("translate -1\n")
-
-            # For only Background gradient
-
-            if worldTexCount == 0:
-                if world.pov.use_sky_blend:
-                    tabWrite("sky_sphere {\n")
-                    tabWrite("pigment {\n")
-                    # maybe Should follow the advice of POV doc about replacing gradient
-                    # for skysphere..5.5
-                    tabWrite("gradient y\n")
-                    tabWrite("color_map {\n")
-                    # XXX Does not exists anymore
-                    # if render.alpha_mode == 'STRAIGHT':
-                    # tabWrite("[0.0 rgbt<%.3g, %.3g, %.3g, 1>]\n" % (world.pov.horizon_color[:]))
-                    # tabWrite("[1.0 rgbt<%.3g, %.3g, %.3g, 1>]\n" % (world.pov.zenith_color[:]))
-                    if render.alpha_mode == 'TRANSPARENT':
-                        tabWrite(
-                            "[0.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n"
-                            % (world.pov.horizon_color[:])
-                        )
-                        # aa premult not solved with transmit 1
-                        tabWrite(
-                            "[1.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n"
-                            % (world.pov.zenith_color[:])
-                        )
-                    else:
-                        tabWrite(
-                            "[0.0 rgbt<%.3g, %.3g, %.3g, 0>]\n"
-                            % (world.pov.horizon_color[:])
-                        )
-                        tabWrite(
-                            "[1.0 rgbt<%.3g, %.3g, %.3g, 0>]\n"
-                            % (world.pov.zenith_color[:])
-                        )
-                    tabWrite("}\n")
-                    tabWrite("}\n")
-                    tabWrite("}\n")
-                    # Sky_sphere alpha (transmit) is not translating into image alpha the same
-                    # way as 'background'
-
-            # if world.pov.light_settings.use_indirect_light:
-            #    scene.pov.radio_enable=1
-
-            # Maybe change the above to a function copyInternalRenderer settings when
-            # user pushes a button, then:
-            # scene.pov.radio_enable = world.pov.light_settings.use_indirect_light
-            # and other such translations but maybe this would not be allowed either?
-
-        ###############################################################
-
-        mist = world.mist_settings
-
-        if mist.use_mist:
-            tabWrite("fog {\n")
-            if mist.falloff == 'LINEAR':
-                tabWrite(
-                    "distance %.6f\n" % ((mist.start + mist.depth) * 0.368)
-                )
-            elif mist.falloff == 'QUADRATIC':  # n**2 or squrt(n)?
-                tabWrite(
-                    "distance %.6f\n" % ((mist.start + mist.depth) ** 2 * 0.368)
-                )
-            elif mist.falloff == 'INVERSE_QUADRATIC':  # n**2 or squrt(n)?
-                tabWrite(
-                    "distance %.6f\n" % ((mist.start + mist.depth) ** 2 * 0.368)
-                )
-            tabWrite(
-                "color rgbt<%.3g, %.3g, %.3g, %.3g>\n"
-                % (*world.pov.horizon_color, 1.0 - mist.intensity)
-            )
-            # tabWrite("fog_offset %.6f\n" % mist.start) #create a pov property to prepend
-            # tabWrite("fog_alt %.6f\n" % mist.height) #XXX right?
-            # tabWrite("turbulence 0.2\n")
-            # tabWrite("turb_depth 0.3\n")
-            tabWrite("fog_type 1\n")  # type2 for height
-            tabWrite("}\n")
-        if scene.pov.media_enable:
-            tabWrite("media {\n")
-            tabWrite(
-                "scattering { %d, rgb %.12f*<%.4g, %.4g, %.4g>\n"
-                % (
-                    int(scene.pov.media_scattering_type),
-                    (scene.pov.media_diffusion_scale),
-                    *(scene.pov.media_diffusion_color[:]),
-                )
-            )
-            if scene.pov.media_scattering_type == '5':
-                tabWrite("eccentricity %.3g\n" % scene.pov.media_eccentricity)
-            tabWrite("}\n")
-            tabWrite(
-                "absorption %.12f*<%.4g, %.4g, %.4g>\n"
-                % (
-                    scene.pov.media_absorption_scale,
-                    *(scene.pov.media_absorption_color[:]),
-                )
-            )
-            tabWrite("\n")
-            tabWrite("samples %.d\n" % scene.pov.media_samples)
-            tabWrite("}\n")
-
-    def exportGlobalSettings(scene):
+    def export_global_settings(scene):
         """write all POV global settings to exported file """
-        tabWrite("global_settings {\n")
-        tabWrite("assumed_gamma 1.0\n")
-        tabWrite("max_trace_level %d\n" % scene.pov.max_trace_level)
+        tab_write("global_settings {\n")
+        tab_write("assumed_gamma 1.0\n")
+        tab_write("max_trace_level %d\n" % scene.pov.max_trace_level)
 
-        # Deprecated (autodetected in pov3.8):
-        # if scene.pov.charset != 'ascii':
-            # file.write("    charset %s\n" % scene.pov.charset)
         if scene.pov.global_settings_advanced:
-            if scene.pov.radio_enable == False:
+            if not scene.pov.radio_enable:
                 file.write("    adc_bailout %.6f\n" % scene.pov.adc_bailout)
-            file.write(
-                "    ambient_light <%.6f,%.6f,%.6f>\n"
-                % scene.pov.ambient_light[:]
-            )
-            file.write(
-                "    irid_wavelength <%.6f,%.6f,%.6f>\n"
-                % scene.pov.irid_wavelength[:]
-            )
-            file.write(
-                "    max_intersections %s\n" % scene.pov.max_intersections
-            )
+            file.write("    ambient_light <%.6f,%.6f,%.6f>\n" % scene.pov.ambient_light[:])
+            file.write("    irid_wavelength <%.6f,%.6f,%.6f>\n" % scene.pov.irid_wavelength[:])
             file.write("    number_of_waves %s\n" % scene.pov.number_of_waves)
             file.write("    noise_generator %s\n" % scene.pov.noise_generator)
         if scene.pov.radio_enable:
-            tabWrite("radiosity {\n")
-            tabWrite("adc_bailout %.4g\n" % scene.pov.radio_adc_bailout)
-            tabWrite("brightness %.4g\n" % scene.pov.radio_brightness)
-            tabWrite("count %d\n" % scene.pov.radio_count)
-            tabWrite("error_bound %.4g\n" % scene.pov.radio_error_bound)
-            tabWrite("gray_threshold %.4g\n" % scene.pov.radio_gray_threshold)
-            tabWrite(
-                "low_error_factor %.4g\n" % scene.pov.radio_low_error_factor
-            )
-            tabWrite("maximum_reuse %.4g\n" % scene.pov.radio_maximum_reuse)
-            tabWrite("minimum_reuse %.4g\n" % scene.pov.radio_minimum_reuse)
-            tabWrite("nearest_count %d\n" % scene.pov.radio_nearest_count)
-            tabWrite("pretrace_start %.3g\n" % scene.pov.radio_pretrace_start)
-            tabWrite("pretrace_end %.3g\n" % scene.pov.radio_pretrace_end)
-            tabWrite("recursion_limit %d\n" % scene.pov.radio_recursion_limit)
-            tabWrite("always_sample %d\n" % scene.pov.radio_always_sample)
-            tabWrite("normal %d\n" % scene.pov.radio_normal)
-            tabWrite("media %d\n" % scene.pov.radio_media)
-            tabWrite("subsurface %d\n" % scene.pov.radio_subsurface)
-            tabWrite("}\n")
-        onceSss = 1
-        onceAmbient = 1
-        oncePhotons = 1
+            tab_write("radiosity {\n")
+            tab_write("adc_bailout %.4g\n" % scene.pov.radio_adc_bailout)
+            tab_write("brightness %.4g\n" % scene.pov.radio_brightness)
+            tab_write("count %d\n" % scene.pov.radio_count)
+            tab_write("error_bound %.4g\n" % scene.pov.radio_error_bound)
+            tab_write("gray_threshold %.4g\n" % scene.pov.radio_gray_threshold)
+            tab_write("low_error_factor %.4g\n" % scene.pov.radio_low_error_factor)
+            tab_write("maximum_reuse %.4g\n" % scene.pov.radio_maximum_reuse)
+            tab_write("minimum_reuse %.4g\n" % scene.pov.radio_minimum_reuse)
+            tab_write("nearest_count %d\n" % scene.pov.radio_nearest_count)
+            tab_write("pretrace_start %.3g\n" % scene.pov.radio_pretrace_start)
+            tab_write("pretrace_end %.3g\n" % scene.pov.radio_pretrace_end)
+            tab_write("recursion_limit %d\n" % scene.pov.radio_recursion_limit)
+            tab_write("always_sample %d\n" % scene.pov.radio_always_sample)
+            tab_write("normal %d\n" % scene.pov.radio_normal)
+            tab_write("media %d\n" % scene.pov.radio_media)
+            tab_write("subsurface %d\n" % scene.pov.radio_subsurface)
+            tab_write("}\n")
+        once_sss = 1
+        once_ambient = 1
+        once_photons = 1
         for material in bpy.data.materials:
-            if material.pov_subsurface_scattering.use and onceSss:
+            if material.pov_subsurface_scattering.use and once_sss:
                 # In pov, the scale has reversed influence compared to blender. these number
                 # should correct that
-                tabWrite(
-                    "mm_per_unit %.6f\n"
-                    % (material.pov_subsurface_scattering.scale * 1000.0)
+                tab_write(
+                    "mm_per_unit %.6f\n" % (material.pov_subsurface_scattering.scale * 1000.0)
                 )
                 # 1000 rather than scale * (-100.0) + 15.0))
 
                 # In POV-Ray, the scale factor for all subsurface shaders needs to be the same
 
                 # formerly sslt_samples were multiplied by 100 instead of 10
-                sslt_samples = (
-                    11 - material.pov_subsurface_scattering.error_threshold
-                ) * 10
+                sslt_samples = (11 - material.pov_subsurface_scattering.error_threshold) * 10
 
-                tabWrite(
-                    "subsurface { samples %d, %d }\n"
-                    % (sslt_samples, sslt_samples / 10)
-                )
-                onceSss = 0
+                tab_write("subsurface { samples %d, %d }\n" % (sslt_samples, sslt_samples / 10))
+                once_sss = 0
 
-            if world and onceAmbient:
-                tabWrite(
-                    "ambient_light rgb<%.3g, %.3g, %.3g>\n"
-                    % world.pov.ambient_color[:]
-                )
-                onceAmbient = 0
+            if world and once_ambient:
+                tab_write("ambient_light rgb<%.3g, %.3g, %.3g>\n" % world.pov.ambient_color[:])
+                once_ambient = 0
 
             if scene.pov.photon_enable:
-                if oncePhotons and (
-                    material.pov.refraction_type == "2"
-                    or material.pov.photons_reflection == True
+                if once_photons and (
+                    material.pov.refraction_type == "2" or material.pov.photons_reflection
                 ):
-                    tabWrite("photons {\n")
-                    tabWrite("spacing %.6f\n" % scene.pov.photon_spacing)
-                    tabWrite(
-                        "max_trace_level %d\n"
-                        % scene.pov.photon_max_trace_level
-                    )
-                    tabWrite(
-                        "adc_bailout %.3g\n" % scene.pov.photon_adc_bailout
-                    )
-                    tabWrite(
+                    tab_write("photons {\n")
+                    tab_write("spacing %.6f\n" % scene.pov.photon_spacing)
+                    tab_write("max_trace_level %d\n" % scene.pov.photon_max_trace_level)
+                    tab_write("adc_bailout %.3g\n" % scene.pov.photon_adc_bailout)
+                    tab_write(
                         "gather %d, %d\n"
-                        % (
-                            scene.pov.photon_gather_min,
-                            scene.pov.photon_gather_max,
-                        )
+                        % (scene.pov.photon_gather_min, scene.pov.photon_gather_max)
                     )
                     if scene.pov.photon_map_file_save_load in {'save'}:
-                        filePhName = 'Photon_map_file.ph'
+                        ph_file_name = 'Photon_map_file.ph'
                         if scene.pov.photon_map_file != '':
-                            filePhName = scene.pov.photon_map_file + '.ph'
-                        filePhDir = tempfile.gettempdir()
+                            ph_file_name = scene.pov.photon_map_file + '.ph'
+                        ph_file_dir = tempfile.gettempdir()
                         path = bpy.path.abspath(scene.pov.photon_map_dir)
                         if os.path.exists(path):
-                            filePhDir = path
-                        fullFileName = os.path.join(filePhDir, filePhName)
-                        tabWrite('save_file "%s"\n' % fullFileName)
-                        scene.pov.photon_map_file = fullFileName
+                            ph_file_dir = path
+                        full_file_name = os.path.join(ph_file_dir, ph_file_name)
+                        tab_write('save_file "%s"\n' % full_file_name)
+                        scene.pov.photon_map_file = full_file_name
                     if scene.pov.photon_map_file_save_load in {'load'}:
-                        fullFileName = bpy.path.abspath(
-                            scene.pov.photon_map_file
-                        )
-                        if os.path.exists(fullFileName):
-                            tabWrite('load_file "%s"\n' % fullFileName)
-                    tabWrite("}\n")
-                    oncePhotons = 0
+                        full_file_name = bpy.path.abspath(scene.pov.photon_map_file)
+                        if os.path.exists(full_file_name):
+                            tab_write('load_file "%s"\n' % full_file_name)
+                    tab_write("}\n")
+                    once_photons = 0
 
-        tabWrite("}\n")
-
-    def exportCustomCode():
-        """write all POV user defined custom code to exported file """
-        # Write CurrentAnimation Frame for use in Custom POV Code
-        file.write(
-            "#declare CURFRAMENUM = %d;\n" % bpy.context.scene.frame_current
-        )
-        # Change path and uncomment to add an animated include file by hand:
-        file.write(
-            "//#include \"/home/user/directory/animation_include_file.inc\"\n"
-        )
-        for txt in bpy.data.texts:
-            if txt.pov.custom_code == 'both':
-                # Why are the newlines needed?
-                file.write("\n")
-                file.write(txt.as_string())
-                file.write("\n")
+        tab_write("}\n")
 
     # sel = renderable_objects(scene) #removed for booleans
     if comments:
@@ -4990,51 +687,44 @@ def write_pov(filename, scene=None, info_callback=None):
             "//--Exported with POV-Ray exporter for Blender--\n"
             "//----------------------------------------------\n\n"
         )
-    file.write("#version 3.7;\n")    #Switch below as soon as 3.8 beta gets easy linked
-    #file.write("#version 3.8;\n")
+    file.write("#version 3.7;\n")  # Switch below as soon as 3.8 beta gets easy linked
+    # file.write("#version 3.8;\n")
     file.write(
-        "#declare Default_texture = texture{pigment {rgb 0.8} "
-        "finish {brilliance 3.8} }\n\n"
+        "#declare Default_texture = texture{pigment {rgb 0.8} " "finish {brilliance 3.8} }\n\n"
     )
     if comments:
         file.write("\n//--Global settings--\n\n")
 
-    exportGlobalSettings(scene)
+    export_global_settings(scene)
 
     if comments:
         file.write("\n//--Custom Code--\n\n")
-    exportCustomCode()
+    scripting.export_custom_code(file)
 
     if comments:
         file.write("\n//--Patterns Definitions--\n\n")
-    LocalPatternNames = []
+    local_pattern_names = []
     for texture in bpy.data.textures:  # ok?
         if texture.users > 0:
-            currentPatName = string_strip_hyphen(
-                bpy.path.clean_name(texture.name)
-            )
+            current_pat_name = string_strip_hyphen(bpy.path.clean_name(texture.name))
             # string_strip_hyphen(patternNames[texture.name]) #maybe instead of the above
-            LocalPatternNames.append(currentPatName)
+            local_pattern_names.append(current_pat_name)
             # 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))
+                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" % current_pat_name)
+                file.write(shading.export_pattern(texture))
             file.write("\n")
     if comments:
         file.write("\n//--Background--\n\n")
 
-    exportWorld(scene.world)
+    scenography.export_world(scene.world, scene, global_matrix, tab_write)
 
     if comments:
         file.write("\n//--Cameras--\n\n")
 
-    exportCamera()
+    scenography.export_camera(scene, global_matrix, render, tab_write)
 
     if comments:
         file.write("\n//--Lamps--\n\n")
@@ -5047,20 +737,57 @@ def write_pov(filename, scene=None, info_callback=None):
                         csg_list.append(mod.object)
     if csg_list != []:
         csg = False
-        sel = no_renderable_objects(scene)
-        exportMeshes(scene, sel, csg)
+        sel = no_renderable_objects()
+        object_mesh_topology.export_meshes(
+            preview_dir,
+            file,
+            scene,
+            sel,
+            csg,
+            string_strip_hyphen,
+            safety,
+            write_object_modifiers,
+            material_names_dictionary,
+            write_object_material,
+            scenography.exported_lights_count,
+            unpacked_images,
+            image_format,
+            img_map,
+            img_map_transforms,
+            path_image,
+            smoke_path,
+            global_matrix,
+            write_matrix,
+            using_uberpov,
+            comments,
+            linebreaksinlists,
+            tab,
+            tab_level,
+            tab_write,
+            info_callback,
+        )
 
     csg = True
     sel = renderable_objects(scene)
 
-    exportLamps(
-        [L for L in sel if (L.type == 'LIGHT' and L.pov.object_as != 'RAINBOW')]
+    scenography.export_lights(
+        [L for L in sel if (L.type == 'LIGHT' and L.pov.object_as != 'RAINBOW')],
+        file,
+        scene,
+        global_matrix,
+        write_matrix,
+        tab_write,
     )
 
     if comments:
         file.write("\n//--Rainbows--\n\n")
-    exportRainbows(
-        [L for L in sel if (L.type == 'LIGHT' and L.pov.object_as == 'RAINBOW')]
+    scenography.export_rainbows(
+        [L for L in sel if (L.type == 'LIGHT' and L.pov.object_as == 'RAINBOW')],
+        file,
+        scene,
+        global_matrix,
+        write_matrix,
+        tab_write,
     )
 
     if comments:
@@ -5068,10 +795,9 @@ def write_pov(filename, scene=None, info_callback=None):
     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)
+        # Implicit else-if (as not skipped by previous "continue")
+        if c.type == 'CURVE' and (c.pov.curveshape in {'lathe', 'sphere_sweep', 'loft', 'birail'}):
+            object_curve_topology.export_curves(c, string_strip_hyphen, global_matrix, tab_write)
 
     if comments:
         file.write("\n//--Material Definitions--\n\n")
@@ -5079,84 +805,101 @@ def write_pov(filename, scene=None, info_callback=None):
     file.write("#default{ pigment{ color srgb 0.8 }}\n")
     # Convert all materials to strings we can access directly per vertex.
     # exportMaterials()
-    shading.writeMaterial(
+    shading.write_material(
         using_uberpov,
         DEF_MAT_NAME,
-        scene,
-        tabWrite,
+        tab_write,
         safety,
         comments,
-        uniqueName,
-        materialNames,
+        unique_name,
+        material_names_dictionary,
         None,
     )  # default material
     for material in bpy.data.materials:
         if material.users > 0:
+            r, g, b, a = material.diffuse_color[:]
+            pigment_color = "pigment {rgbt <%.4g,%.4g,%.4g,%.4g>}" % (r, g, b, 1 - a)
             if material.pov.material_use_nodes:
+                # Also make here other pigment_color fallback using BSDF node main color ?
                 ntree = material.node_tree
-                povMatName = string_strip_hyphen(
-                    bpy.path.clean_name(material.name)
-                )
+                pov_mat_name = string_strip_hyphen(bpy.path.clean_name(material.name))
                 if len(ntree.nodes) == 0:
-                    file.write(
-                        '#declare %s = texture {%s}\n' % (povMatName, color)
-                    )
+                    file.write('#declare %s = texture {%s}\n' % (pov_mat_name, pigment_color))
                 else:
-                    shading.write_nodes(scene, povMatName, ntree, file)
+                    shading.write_nodes(scene, pov_mat_name, 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 = (
+                                    if link.to_node.bl_idname == "PovrayOutputNode":
+                                        pov_mat_name = (
                                             string_strip_hyphen(
-                                                bpy.path.clean_name(
-                                                    link.from_node.name
-                                                )
+                                                bpy.path.clean_name(link.from_node.name)
                                             )
-                                            + "_%s" % povMatName
+                                            + "_%s" % pov_mat_name
                                         )
                             else:
                                 file.write(
-                                    '#declare %s = texture {%s}\n'
-                                    % (povMatName, color)
+                                    '#declare %s = texture {%s}\n' % (pov_mat_name, pigment_color)
                                 )
             else:
-                shading.writeMaterial(
+                shading.write_material(
                     using_uberpov,
                     DEF_MAT_NAME,
-                    scene,
-                    tabWrite,
+                    tab_write,
                     safety,
                     comments,
-                    uniqueName,
-                    materialNames,
+                    unique_name,
+                    material_names_dictionary,
                     material,
                 )
             # attributes are all the variables needed by the other python file...
     if comments:
         file.write("\n")
 
-    exportMeta([m for m in sel if m.type == 'META'])
+    export_meta([m for m in sel if m.type == 'META'])
 
     if comments:
         file.write("//--Mesh objects--\n")
 
-
-    #tbefore = time.time()
-    exportMeshes(scene, sel, csg)
-    #totime = time.time() - tbefore
-    #print("exportMeshes took" + str(totime))
+    # tbefore = time.time()
+    object_mesh_topology.export_meshes(
+        preview_dir,
+        file,
+        scene,
+        sel,
+        csg,
+        string_strip_hyphen,
+        safety,
+        write_object_modifiers,
+        material_names_dictionary,
+        write_object_material,
+        scenography.exported_lights_count,
+        unpacked_images,
+        image_format,
+        img_map,
+        img_map_transforms,
+        path_image,
+        smoke_path,
+        global_matrix,
+        write_matrix,
+        using_uberpov,
+        comments,
+        linebreaksinlists,
+        tab,
+        tab_level,
+        tab_write,
+        info_callback,
+    )
+    # totime = time.time() - tbefore
+    # print("export_meshes took" + str(totime))
 
     # What follow used to happen here:
-    # exportCamera()
-    # exportWorld(scene.world)
-    # exportGlobalSettings(scene)
+    # export_camera()
+    # scenography.export_world(scene.world, scene, global_matrix, tab_write)
+    # export_global_settings(scene)
     # MR:..and the order was important for implementing pov 3.7 baking
     #      (mesh camera) comment for the record
     # CR: Baking should be a special case than. If "baking", than we could change the order.
@@ -5166,13 +909,9 @@ def write_pov(filename, scene=None, info_callback=None):
     # print("pov file closed %s" % file.closed)
 
 
-def write_pov_ini(
-    scene, filename_ini, filename_log, filename_pov, filename_image
-):
+def write_pov_ini(scene, filename_ini, filename_log, filename_pov, filename_image):
     """Write ini file."""
-    feature_set = bpy.context.preferences.addons[
-        __package__
-    ].preferences.branch_feature_set_povray
+    feature_set = bpy.context.preferences.addons[__package__].preferences.branch_feature_set_povray
     using_uberpov = feature_set == 'uberpov'
     # scene = bpy.data.scenes[0]
     scene = bpy.context.scene
@@ -5182,7 +921,7 @@ def write_pov_ini(
     y = int(render.resolution_y * render.resolution_percentage * 0.01)
 
     file = open(filename_ini, "w")
-    file.write("Version=3.8\n")
+    file.write("Version=3.7\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:
@@ -5202,9 +941,7 @@ def write_pov_ini(
         file.write("Start_Row=%4g\n" % (1.0 - render.border_max_y))
         file.write("End_Row=%4g\n" % (1.0 - render.border_min_y))
 
-    file.write(
-        "Bounding_Method=2\n"
-    )  # The new automatic BSP is faster in most scenes
+    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)
@@ -5228,16 +965,10 @@ def write_pov_ini(
         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_Confidence=%.3g\n" % scene.pov.antialias_confidence)
         else:
-            file.write(
-                "Sampling_Method=%s\n" % method[scene.pov.antialias_method]
-            )
+            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=on\n")
@@ -5270,15 +1001,12 @@ class PovrayRender(bpy.types.RenderEngine):
         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
-                )
+            # Implicit else, as here return was still not triggered:
+            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":
+        if platform.startswith('win'):
             import winreg
 
             win_reg_key = winreg.OpenKey(
@@ -5317,36 +1045,27 @@ class PovrayRender(bpy.types.RenderEngine):
                 return pov_binary
         return ""
 
-    def _export(self, depsgraph, povPath, renderImagePath):
+    def _export(self, depsgraph, pov_path, image_render_path):
         """gather all necessary output files paths user defined and auto generated and export there"""
-        import tempfile
 
         scene = bpy.context.scene
         if scene.pov.tempfiles_enable:
-            self._temp_file_in = tempfile.NamedTemporaryFile(
-                suffix=".pov", delete=False
-            ).name
+            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=".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"
-            )
+            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"
+            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.
-            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_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
@@ -5377,17 +1096,11 @@ class PovrayRender(bpy.types.RenderEngine):
 
         pov_binary = PovrayRender._locate_binary()
         if not pov_binary:
-            print(
-                "POV-Ray 3.7: could not execute povray, possibly POV-Ray isn't installed"
-            )
+            print("POV-Ray 3.7: could not execute povray, possibly POV-Ray isn't installed")
             return False
 
         write_pov_ini(
-            scene,
-            self._temp_file_ini,
-            self._temp_file_log,
-            self._temp_file_in,
-            self._temp_file_out,
+            scene, self._temp_file_ini, self._temp_file_log, self._temp_file_in, self._temp_file_out
         )
 
         print("***-STARTING-***")
@@ -5395,11 +1108,11 @@ class PovrayRender(bpy.types.RenderEngine):
         extra_args = []
 
         if scene.pov.command_line_switches != "":
-            for newArg in scene.pov.command_line_switches.split(" "):
-                extra_args.append(newArg)
+            for new_arg in scene.pov.command_line_switches.split(" "):
+                extra_args.append(new_arg)
 
         self._is_windows = False
-        if sys.platform[:3] == "win":
+        if platform.startswith('win'):
             self._is_windows = True
             if "/EXIT" not in extra_args and not scene.pov.pov_editor:
                 extra_args.append("/EXIT")
@@ -5442,7 +1155,7 @@ class PovrayRender(bpy.types.RenderEngine):
                     # 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):
+            for j in range(5):
                 try:
                     os.unlink(i)
                     break
@@ -5453,7 +1166,6 @@ class PovrayRender(bpy.types.RenderEngine):
 
     def render(self, depsgraph):
         """Export necessary files from text editor and render image."""
-        import tempfile
 
         scene = bpy.context.scene
         r = scene.render
@@ -5475,8 +1187,11 @@ class PovrayRender(bpy.types.RenderEngine):
                 except OSError:
                     pass
                 return False
-
-            poll_result = self._process.poll()
+            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
             if poll_result is not None:
                 if poll_result < 0:
@@ -5488,27 +1203,18 @@ class PovrayRender(bpy.types.RenderEngine):
 
         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_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"
-                )
+                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)
+                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(
-                    preview_dir,
-                    (os.path.splitext(self._temp_file_in)[0] + ".INI"),
+                    preview_dir, (os.path.splitext(self._temp_file_in)[0] + ".INI")
                 )
                 self._temp_file_log = os.path.join(preview_dir, "alltext.out")
 
@@ -5533,15 +1239,11 @@ class PovrayRender(bpy.types.RenderEngine):
             pov_binary = PovrayRender._locate_binary()
 
             if not pov_binary:
-                print(
-                    "POV-Ray 3.7: could not execute povray, possibly POV-Ray isn't installed"
-                )
+                print("POV-Ray 3.7: could not execute povray, possibly POV-Ray isn't installed")
                 return False
 
             # start ini UI options export
-            self.update_stats(
-                "", "POV-Ray 3.7: Exporting ini options from Blender"
-            )
+            self.update_stats("", "POV-Ray 3.7: Exporting ini options from Blender")
 
             write_pov_ini(
                 scene,
@@ -5556,10 +1258,10 @@ class PovrayRender(bpy.types.RenderEngine):
             extra_args = []
 
             if scene.pov.command_line_switches != "":
-                for newArg in scene.pov.command_line_switches.split(" "):
-                    extra_args.append(newArg)
+                for new_arg in scene.pov.command_line_switches.split(" "):
+                    extra_args.append(new_arg)
 
-            if sys.platform[:3] == "win":
+            if platform.startswith('win'):
                 if "/EXIT" not in extra_args and not scene.pov.pov_editor:
                     extra_args.append("/EXIT")
             else:
@@ -5568,8 +1270,8 @@ class PovrayRender(bpy.types.RenderEngine):
 
             # Start Rendering!
             try:
-                if (
-                    sys.platform[:3] != "win" and scene.pov.sdl_window_enable
+                if scene.pov.sdl_window_enable and not platform.startswith(
+                    'win'
                 ):  # segfault on linux == False !!!
                     env = {'POV_DISPLAY_SCALED': 'off'}
                     env.update(os.environ)
@@ -5638,12 +1340,10 @@ class PovrayRender(bpy.types.RenderEngine):
             ##            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 = ""
+            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)
@@ -5651,54 +1351,49 @@ class PovrayRender(bpy.types.RenderEngine):
             if not scene.pov.tempfiles_enable:
 
                 # check paths
-                povPath = bpy.path.abspath(scene.pov.scene_path).replace(
-                    '\\', '/'
-                )
-                if povPath == "":
+                pov_path = bpy.path.abspath(scene.pov.scene_path).replace('\\', '/')
+                if pov_path == "":
                     if bpy.data.is_saved:
-                        povPath = bpy.path.abspath("//")
+                        pov_path = bpy.path.abspath("//")
                     else:
-                        povPath = tempfile.gettempdir()
-                elif povPath.endswith("/"):
-                    if povPath == "/":
-                        povPath = bpy.path.abspath("//")
+                        pov_path = tempfile.gettempdir()
+                elif pov_path.endswith("/"):
+                    if pov_path == "/":
+                        pov_path = bpy.path.abspath("//")
                     else:
-                        povPath = bpy.path.abspath(scene.pov.scene_path)
+                        pov_path = bpy.path.abspath(scene.pov.scene_path)
 
-                if not os.path.exists(povPath):
+                if not os.path.exists(pov_path):
                     try:
-                        os.makedirs(povPath)
-                    except:
+                        os.makedirs(pov_path)
+                    except BaseException as e:
+                        print(e.__doc__)
+                        print('An exception occurred: {}'.format(e))
                         import traceback
 
                         traceback.print_exc()
 
-                        print(
-                            "POV-Ray 3.7: Cannot create scenes directory: %r"
-                            % povPath
-                        )
+                        print("POV-Ray 3.7: Cannot create scenes directory: %r" % pov_path)
                         self.update_stats(
-                            "",
-                            "POV-Ray 3.7: Cannot create scenes directory %r"
-                            % povPath,
+                            "", "POV-Ray 3.7: Cannot create scenes directory %r" % pov_path
                         )
                         time.sleep(2.0)
                         # return
 
                 '''
                 # Bug in POV-Ray RC3
-                renderImagePath = bpy.path.abspath(scene.pov.renderimage_path).replace('\\','/')
-                if renderImagePath == "":
+                image_render_path = bpy.path.abspath(scene.pov.renderimage_path).replace('\\','/')
+                if image_render_path == "":
                     if bpy.data.is_saved:
-                        renderImagePath = bpy.path.abspath("//")
+                        image_render_path = bpy.path.abspath("//")
                     else:
-                        renderImagePath = tempfile.gettempdir()
-                    #print("Path: " + renderImagePath)
+                        image_render_path = tempfile.gettempdir()
+                    #print("Path: " + image_render_path)
                 elif path.endswith("/"):
-                    if renderImagePath == "/":
-                        renderImagePath = bpy.path.abspath("//")
+                    if image_render_path == "/":
+                        image_render_path = bpy.path.abspath("//")
                     else:
-                        renderImagePath = bpy.path.abspath(scene.pov.renderimage_path)
+                        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")
@@ -5708,38 +1403,38 @@ class PovrayRender(bpy.types.RenderEngine):
 
                 # check name
                 if scene.pov.scene_name == "":
-                    if blendSceneName != "":
-                        povSceneName = blendSceneName
+                    if blend_scene_name != "":
+                        pov_scene_name = blend_scene_name
                     else:
-                        povSceneName = "untitled"
+                        pov_scene_name = "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:
+                    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)
                         # return
-                    povSceneName = os.path.splitext(povSceneName)[0]
+                    pov_scene_name = os.path.splitext(pov_scene_name)[0]
 
-                print("Scene name: " + povSceneName)
-                print("Export path: " + povPath)
-                povPath = os.path.join(povPath, povSceneName)
-                povPath = os.path.realpath(povPath)
+                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)
 
                 # 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
+                # image_render_path = image_render_path + "\\" + pov_scene_name
+                image_render_path = pov_path  # Bugfix for POV-Ray RC3 bug
+                # image_render_path = os.path.realpath(image_render_path)  # Bugfix for POV-Ray RC3 bug
 
-                # print("Export path: %s" % povPath)
-                # print("Render Image path: %s" % renderImagePath)
+                # print("Export path: %s" % pov_path)
+                # print("Render Image path: %s" % image_render_path)
 
             # start export
             self.update_stats("", "POV-Ray 3.7: Exporting data from Blender")
-            self._export(depsgraph, povPath, renderImagePath)
+            self._export(depsgraph, pov_path, image_render_path)
             self.update_stats("", "POV-Ray 3.7: Parsing File")
 
             if not self._render(depsgraph):
@@ -5774,11 +1469,7 @@ class PovrayRender(bpy.types.RenderEngine):
                     # 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')
-                    )
+                    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
@@ -5789,11 +1480,7 @@ class PovrayRender(bpy.types.RenderEngine):
                         _pov_rendering = True
                         match = percent.findall(str(data))
                         if match:
-                            self.update_stats(
-                                "",
-                                "POV-Ray 3.7: Rendering File (%s%%)"
-                                % match[-1],
-                            )
+                            self.update_stats("", "POV-Ray 3.7: Rendering File (%s%%)" % match[-1])
                         else:
                             self.update_stats("", "POV-Ray 3.7: Rendering File")
 
@@ -5882,107 +1569,116 @@ class PovrayRender(bpy.types.RenderEngine):
 
             # print(filename_log) #bring the pov log to blender console with proper path?
             with open(
-                self._temp_file_log,
-                encoding='utf-8'
+                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')
+                # 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:
-                    if win.screen != None:
+                    if win.screen is not 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()
+                                # 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['screen'] = scr  # C.screen
                                 ctx['window'] = win
 
-                                #bpy.ops.console.banner(ctx, text = "Hello world")
+                                # bpy.ops.console.banner(ctx, text = "Hello world")
                                 bpy.ops.console.clear_line(ctx)
-                                stdmsg = msg.split('\n') #XXX todo , test and see
+                                stdmsg = msg.split('\n')  # XXX todo , test and see
                                 for i in stdmsg:
-                                    bpy.ops.console.insert(ctx, text = i)
+                                    # Crashes if no Terminal displayed on Windows
+                                    bpy.ops.console.scrollback_append(ctx, text=i, type='INFO')
+                                    # bpy.ops.console.insert(ctx, text=(i + "\n"))
 
             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
+            sound_on = bpy.context.preferences.addons[__package__].preferences.use_sounds
+            finished_render_message = "\'Render completed\'"
 
-            if sys.platform[:3] == "win" and sound_on:
+            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
-                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
+
+                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\'"
+                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
                 os.system("say %s &" % (finished_render_message))
 
+            # While Linux frequently has espeak installed or at least can suggest
+            # Maybe windows could as well ?
+            elif platform == "linux":
+                # We don't want the say command to block Python,
+                # so we add an ampersand after the message
+                os.system("echo %s | espeak &" % (finished_render_message))
+
+
 ##################################################################################
 #################################Operators########################################
 ##################################################################################
@@ -5993,82 +1689,78 @@ class RenderPovTexturePreview(Operator):
     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"
-        )
+        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)
 
-        iniPrevFile = os.path.join(preview_dir, "Preview.ini")
-        inputPrevFile = os.path.join(preview_dir, "Preview.pov")
-        outputPrevFile = os.path.join(preview_dir, texPrevName)
+        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 ##########################################
-        fileIni = open("%s" % iniPrevFile, "w")
-        fileIni.write('Version=3.8\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()
+        file_ini = open("%s" % ini_prev_file, "w")
+        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')
+        file_ini.close()
         ##################### pov ##########################################
-        filePov = open("%s" % inputPrevFile, "w")
-        PATname = "PAT_" + string_strip_hyphen(bpy.path.clean_name(tex.name))
-        filePov.write("#declare %s = \n" % PATname)
-        filePov.write(shading.exportPattern(tex, string_strip_hyphen))
-
-        filePov.write("#declare Plane =\n")
-        filePov.write("mesh {\n")
-        filePov.write(
+        file_pov = open("%s" % input_prev_file, "w")
+        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"
         )
-        filePov.write(
+        file_pov.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()
+        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")
+        file_pov.close()
         ##################### end write ##########################################
 
         pov_binary = PovrayRender._locate_binary()
 
-        if sys.platform[:3] == "win":
+        if platform.startswith('win'):
             p1 = subprocess.Popen(
-                ["%s" % pov_binary, "/EXIT", "%s" % iniPrevFile],
+                ["%s" % pov_binary, "/EXIT", "%s" % ini_prev_file],
                 stdout=subprocess.PIPE,
                 stderr=subprocess.STDOUT,
             )
         else:
             p1 = subprocess.Popen(
-                ["%s" % pov_binary, "-d", "%s" % iniPrevFile],
+                ["%s" % pov_binary, "-d", "%s" % ini_prev_file],
                 stdout=subprocess.PIPE,
                 stderr=subprocess.STDOUT,
             )
@@ -6080,9 +1772,9 @@ class RenderPovTexturePreview(Operator):
         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
+        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
@@ -6119,14 +1811,10 @@ 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
-
     for cls in reversed(classes):
         unregister_class(cls)
diff --git a/render_povray/render_gui.py b/render_povray/render_gui.py
new file mode 100755
index 000000000..5148c0d94
--- /dev/null
+++ b/render_povray/render_gui.py
@@ -0,0 +1,562 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+"""User interface for rendering parameters"""
+
+import bpy
+from sys import platform  # really import here, as in render.py?
+
+# Or todo: handle this more crossplatform using QTpovray for Linux for instance
+# from os.path import isfile
+from bl_operators.presets import AddPresetBase
+from bpy.utils import register_class, unregister_class
+from bpy.props import EnumProperty
+from bpy.types import Operator, Menu, Panel
+
+
+# Example of wrapping every class 'as is'
+from bl_ui import properties_output
+
+for member in dir(properties_output):
+    subclass = getattr(properties_output, member)
+    try:
+        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+    except BaseException as e:
+        print(e.__doc__)
+        print('An exception occurred: {}'.format(e))
+        pass
+del properties_output
+
+from bl_ui import properties_freestyle
+
+for member in dir(properties_freestyle):
+    subclass = getattr(properties_freestyle, member)
+    try:
+        if not (subclass.bl_space_type == 'PROPERTIES' and subclass.bl_context == "render"):
+            subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+            # subclass.bl_parent_id = "RENDER_PT_POV_filter"
+    except BaseException as e:
+        print(e.__doc__)
+        print('An exception occurred: {}'.format(e))
+        pass
+del properties_freestyle
+
+from bl_ui import properties_view_layer
+
+for member in dir(properties_view_layer):
+    subclass = getattr(properties_view_layer, member)
+    try:
+        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+    except BaseException as e:
+        print(e.__doc__)
+        print('An exception occurred: {}'.format(e))
+        pass
+del properties_view_layer
+
+# Use some of the existing buttons.
+from bl_ui import properties_render
+
+# DEPRECATED#properties_render.RENDER_PT_render.COMPAT_ENGINES.add('POVRAY_RENDER')
+# DEPRECATED#properties_render.RENDER_PT_dimensions.COMPAT_ENGINES.add('POVRAY_RENDER')
+# properties_render.RENDER_PT_antialiasing.COMPAT_ENGINES.add('POVRAY_RENDER')
+# TORECREATE##DEPRECATED#properties_render.RENDER_PT_shading.COMPAT_ENGINES.add('POVRAY_RENDER')
+# DEPRECATED#properties_render.RENDER_PT_output.COMPAT_ENGINES.add('POVRAY_RENDER')
+del properties_render
+
+
+def check_render_freestyle_svg():
+    """Test if Freestyle SVG Exporter addon is activated
+
+    This addon is currently used to generate the SVG lines file
+    when Freestyle is enabled alongside POV
+    """
+    if "render_freestyle_svg" in bpy.context.preferences.addons.keys():
+        return True
+    return False
+
+
+class RenderButtonsPanel:
+    """Use this class to define buttons from the render tab of
+    properties window."""
+
+    bl_space_type = 'PROPERTIES'
+    bl_region_type = 'WINDOW'
+    bl_context = "render"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        rd = context.scene.render
+        return rd.engine in cls.COMPAT_ENGINES
+
+
+class RENDER_PT_POV_export_settings(RenderButtonsPanel, Panel):
+    """Use this class to define pov ini settingss buttons."""
+
+    bl_options = {'DEFAULT_CLOSED'}
+    bl_label = "Auto Start"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def draw_header(self, context):
+        scene = context.scene
+        if scene.pov.tempfiles_enable:
+            self.layout.prop(scene.pov, "tempfiles_enable", text="", icon='AUTO')
+        else:
+            self.layout.prop(scene.pov, "tempfiles_enable", text="", icon='CONSOLE')
+
+    def draw(self, context):
+
+        layout = self.layout
+
+        scene = context.scene
+
+        layout.active = scene.pov.max_trace_level != 0
+        split = layout.split()
+
+        col = split.column()
+        col.label(text="Command line options:")
+        col.prop(scene.pov, "command_line_switches", text="", icon='RIGHTARROW')
+        split = layout.split()
+
+        # layout.active = not scene.pov.tempfiles_enable
+        if not scene.pov.tempfiles_enable:
+            split.prop(scene.pov, "deletefiles_enable", text="Delete files")
+            split.prop(scene.pov, "pov_editor", text="POV Editor")
+
+            col = layout.column()
+            col.prop(scene.pov, "scene_name", text="Name")
+            col.prop(scene.pov, "scene_path", text="Path to files")
+            # col.prop(scene.pov, "scene_path", text="Path to POV-file")
+            # col.prop(scene.pov, "renderimage_path", text="Path to image")
+
+            split = layout.split()
+            split.prop(scene.pov, "indentation_character", text="Indent")
+            if scene.pov.indentation_character == 'SPACE':
+                split.prop(scene.pov, "indentation_spaces", text="Spaces")
+
+            row = layout.row()
+            row.prop(scene.pov, "comments_enable", text="Comments")
+            row.prop(scene.pov, "list_lf_enable", text="Line breaks in lists")
+
+
+class RENDER_PT_POV_render_settings(RenderButtonsPanel, Panel):
+    """Use this class to define pov render settings buttons."""
+
+    bl_label = "Global Settings"
+    bl_icon = 'SETTINGS'
+    bl_options = {'DEFAULT_CLOSED'}
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def draw_header(self, context):
+        scene = context.scene
+        if scene.pov.global_settings_advanced:
+            self.layout.prop(scene.pov, "global_settings_advanced", text="", icon='SETTINGS')
+        else:
+            self.layout.prop(scene.pov, "global_settings_advanced", text="", icon='PREFERENCES')
+
+    def draw(self, context):
+        layout = self.layout
+
+        scene = context.scene
+        # rd = context.scene.render
+        # layout.active = (scene.pov.max_trace_level != 0)
+
+        if not platform.startswith('win'):
+            layout.prop(scene.pov, "sdl_window_enable", text="POV-Ray SDL Window")
+
+        col = layout.column()
+        col.label(text="Main Path Tracing:")
+        col.prop(scene.pov, "max_trace_level", text="Ray Depth")
+        align = True
+        layout.active = scene.pov.global_settings_advanced
+        row = layout.row(align=align)
+        row.prop(scene.pov, "adc_bailout")
+        row = layout.row(align=align)
+        row.prop(scene.pov, "ambient_light")
+        row = layout.row(align=align)
+        row.prop(scene.pov, "irid_wavelength")
+        row = layout.row(align=align)
+        row.prop(scene.pov, "number_of_waves")
+        row = layout.row(align=align)
+        row.prop(scene.pov, "noise_generator")
+
+        split = layout.split()
+        split.label(text="Shading:")
+        split = layout.split()
+
+        row = split.row(align=align)
+        row.prop(scene.pov, "use_shadows")
+        row.prop(scene.pov, "alpha_mode")
+
+
+class RENDER_PT_POV_photons(RenderButtonsPanel, Panel):
+    """Use this class to define pov photons buttons."""
+
+    bl_label = "Photons"
+    bl_options = {'DEFAULT_CLOSED'}
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    # def draw_header(self, context):
+    # self.layout.label(icon='SETTINGS')
+
+    def draw_header(self, context):
+        scene = context.scene
+        if scene.pov.photon_enable:
+            self.layout.prop(scene.pov, "photon_enable", text="", icon='PMARKER_ACT')
+        else:
+            self.layout.prop(scene.pov, "photon_enable", text="", icon='PMARKER')
+
+    def draw(self, context):
+        scene = context.scene
+        layout = self.layout
+        layout.active = scene.pov.photon_enable
+        col = layout.column()
+        # col.label(text="Global Photons:")
+        col.prop(scene.pov, "photon_max_trace_level", text="Photon Depth")
+
+        split = layout.split()
+
+        col = split.column()
+        col.prop(scene.pov, "photon_spacing", text="Spacing")
+        col.prop(scene.pov, "photon_gather_min")
+
+        col = split.column()
+        col.prop(scene.pov, "photon_adc_bailout", text="Photon ADC")
+        col.prop(scene.pov, "photon_gather_max")
+
+        box = layout.box()
+        box.label(text='Photon Map File:')
+        row = box.row()
+        row.prop(scene.pov, "photon_map_file_save_load", expand=True)
+        if scene.pov.photon_map_file_save_load in {'save'}:
+            box.prop(scene.pov, "photon_map_dir")
+            box.prop(scene.pov, "photon_map_filename")
+        if scene.pov.photon_map_file_save_load in {'load'}:
+            box.prop(scene.pov, "photon_map_file")
+        # end main photons
+
+
+class RENDER_PT_POV_antialias(RenderButtonsPanel, Panel):
+    """Use this class to define pov antialiasing buttons."""
+
+    bl_label = "Anti-Aliasing"
+    bl_options = {'DEFAULT_CLOSED'}
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def draw_header(self, context):
+        prefs = bpy.context.preferences.addons[__package__].preferences
+        scene = context.scene
+        if prefs.branch_feature_set_povray != 'uberpov' and scene.pov.antialias_method == '2':
+            self.layout.prop(scene.pov, "antialias_enable", text="", icon='ERROR')
+        elif scene.pov.antialias_enable:
+            self.layout.prop(scene.pov, "antialias_enable", text="", icon='ANTIALIASED')
+        else:
+            self.layout.prop(scene.pov, "antialias_enable", text="", icon='ALIASED')
+
+    def draw(self, context):
+        prefs = bpy.context.preferences.addons[__package__].preferences
+        layout = self.layout
+        scene = context.scene
+
+        layout.active = scene.pov.antialias_enable
+
+        row = layout.row()
+        row.prop(scene.pov, "antialias_method", text="")
+
+        if prefs.branch_feature_set_povray != 'uberpov' and scene.pov.antialias_method == '2':
+            col = layout.column()
+            col.alignment = 'CENTER'
+            col.label(text="Stochastic Anti Aliasing is")
+            col.label(text="Only Available with UberPOV")
+            col.label(text="Feature Set in User Preferences.")
+            col.label(text="Using Type 2 (recursive) instead")
+        else:
+            row.prop(scene.pov, "jitter_enable", text="Jitter")
+
+            split = layout.split()
+            col = split.column()
+            col.prop(scene.pov, "antialias_depth", text="AA Depth")
+            sub = split.column()
+            sub.prop(scene.pov, "jitter_amount", text="Jitter Amount")
+            if scene.pov.jitter_enable:
+                sub.enabled = True
+            else:
+                sub.enabled = False
+
+            row = layout.row()
+            row.prop(scene.pov, "antialias_threshold", text="AA Threshold")
+            row.prop(scene.pov, "antialias_gamma", text="AA Gamma")
+
+            if prefs.branch_feature_set_povray == 'uberpov':
+                row = layout.row()
+                row.prop(scene.pov, "antialias_confidence", text="AA Confidence")
+                if scene.pov.antialias_method == '2':
+                    row.enabled = True
+                else:
+                    row.enabled = False
+
+
+class RENDER_PT_POV_radiosity(RenderButtonsPanel, Panel):
+    """Use this class to define pov radiosity buttons."""
+
+    bl_label = "Diffuse Radiosity"
+    bl_options = {'DEFAULT_CLOSED'}
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def draw_header(self, context):
+        scene = context.scene
+        if scene.pov.radio_enable:
+            self.layout.prop(scene.pov, "radio_enable", text="", icon='OUTLINER_OB_LIGHTPROBE')
+        else:
+            self.layout.prop(scene.pov, "radio_enable", text="", icon='LIGHTPROBE_CUBEMAP')
+
+    def draw(self, context):
+        layout = self.layout
+
+        scene = context.scene
+
+        layout.active = scene.pov.radio_enable
+
+        split = layout.split()
+
+        col = split.column()
+        col.prop(scene.pov, "radio_count", text="Rays")
+        col.prop(scene.pov, "radio_recursion_limit", text="Recursions")
+
+        split.prop(scene.pov, "radio_error_bound", text="Error Bound")
+
+        layout.prop(scene.pov, "radio_display_advanced")
+
+        if scene.pov.radio_display_advanced:
+            split = layout.split()
+
+            col = split.column()
+            col.prop(scene.pov, "radio_adc_bailout", slider=True)
+            col.prop(scene.pov, "radio_minimum_reuse", text="Min Reuse")
+            col.prop(scene.pov, "radio_gray_threshold", slider=True)
+            col.prop(scene.pov, "radio_pretrace_start", slider=True)
+            col.prop(scene.pov, "radio_low_error_factor", slider=True)
+
+            col = split.column()
+            col.prop(scene.pov, "radio_brightness")
+            col.prop(scene.pov, "radio_maximum_reuse", text="Max Reuse")
+            col.prop(scene.pov, "radio_nearest_count")
+            col.prop(scene.pov, "radio_pretrace_end", slider=True)
+
+            col = layout.column()
+            col.label(text="Estimation Influence:")
+            col.prop(scene.pov, "radio_always_sample")
+            col.prop(scene.pov, "radio_normal")
+            col.prop(scene.pov, "radio_media")
+            col.prop(scene.pov, "radio_subsurface")
+
+
+class POV_RADIOSITY_MT_presets(Menu):
+    """Use this class to define pov radiosity presets menu."""
+
+    bl_label = "Radiosity Presets"
+    preset_subdir = "pov/radiosity"
+    preset_operator = "script.execute_preset"
+    draw = bpy.types.Menu.draw_preset
+
+
+class RENDER_OT_POV_radiosity_add_preset(AddPresetBase, Operator):
+    """Use this class to define pov radiosity add presets button"""
+
+    '''Add a Radiosity Preset'''
+    bl_idname = "scene.radiosity_preset_add"
+    bl_label = "Add Radiosity Preset"
+    preset_menu = "POV_RADIOSITY_MT_presets"
+
+    # variable used for all preset values
+    preset_defines = ["scene = bpy.context.scene"]
+
+    # properties to store in the preset
+    preset_values = [
+        "scene.pov.radio_display_advanced",
+        "scene.pov.radio_adc_bailout",
+        "scene.pov.radio_always_sample",
+        "scene.pov.radio_brightness",
+        "scene.pov.radio_count",
+        "scene.pov.radio_error_bound",
+        "scene.pov.radio_gray_threshold",
+        "scene.pov.radio_low_error_factor",
+        "scene.pov.radio_media",
+        "scene.pov.radio_subsurface",
+        "scene.pov.radio_minimum_reuse",
+        "scene.pov.radio_maximum_reuse",
+        "scene.pov.radio_nearest_count",
+        "scene.pov.radio_normal",
+        "scene.pov.radio_recursion_limit",
+        "scene.pov.radio_pretrace_start",
+        "scene.pov.radio_pretrace_end",
+    ]
+
+    # where to store the preset
+    preset_subdir = "pov/radiosity"
+
+
+# Draw into an existing panel
+def rad_panel_func(self, context):
+    """Display radiosity presets rolldown menu"""
+    layout = self.layout
+
+    row = layout.row(align=True)
+    row.menu(POV_RADIOSITY_MT_presets.__name__, text=POV_RADIOSITY_MT_presets.bl_label)
+    row.operator(RENDER_OT_POV_radiosity_add_preset.bl_idname, text="", icon='ADD')
+    row.operator(
+        RENDER_OT_POV_radiosity_add_preset.bl_idname, text="", icon='REMOVE'
+    ).remove_active = True
+
+
+###############################################################################
+# Freestyle
+###############################################################################
+# import addon_utils
+# addon_utils.paths()[0]
+# addon_utils.modules()
+# mod.bl_info['name'] == 'Freestyle SVG Exporter':
+bpy.utils.script_paths("addons")
+# render_freestyle_svg = os.path.join(bpy.utils.script_paths("addons"), "render_freestyle_svg.py")
+
+render_freestyle_svg = bpy.context.preferences.addons.get('render_freestyle_svg')
+# mpath=addon_utils.paths()[0].render_freestyle_svg
+# import mpath
+# from mpath import render_freestyle_svg #= addon_utils.modules(['Freestyle SVG Exporter'])
+# from scripts\\addons import render_freestyle_svg
+if check_render_freestyle_svg():
+    '''
+    snippetsWIP
+    import myscript
+    import importlib
+
+    importlib.reload(myscript)
+    myscript.main()
+    '''
+    for member in dir(render_freestyle_svg):
+        subclass = getattr(render_freestyle_svg, member)
+        try:
+            subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+            if subclass.bl_idname == "RENDER_PT_SVGExporterPanel":
+                subclass.bl_parent_id = "RENDER_PT_POV_filter"
+                subclass.bl_options = {'HIDE_HEADER'}
+                # subclass.bl_order = 11
+                print(subclass.bl_info)
+        except BaseException as e:
+            print(e.__doc__)
+            print('An exception occurred: {}'.format(e))
+            pass
+
+    # del render_freestyle_svg.RENDER_PT_SVGExporterPanel.bl_parent_id
+
+
+class RENDER_PT_POV_filter(RenderButtonsPanel, Panel):
+    """Use this class to invoke stuff like Freestyle UI."""
+
+    bl_label = "Freestyle"
+    bl_options = {'DEFAULT_CLOSED'}
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        with_freestyle = bpy.app.build_options.freestyle
+        engine = context.scene.render.engine
+        return with_freestyle and engine == 'POVRAY_RENDER'
+
+    def draw_header(self, context):
+
+        # scene = context.scene
+        rd = context.scene.render
+        layout = self.layout
+
+        if rd.use_freestyle:
+            layout.prop(rd, "use_freestyle", text="", icon='LINE_DATA')
+
+        else:
+            layout.prop(rd, "use_freestyle", text="", icon='OUTLINER_OB_IMAGE')
+
+    def draw(self, context):
+        rd = context.scene.render
+        layout = self.layout
+        layout.active = rd.use_freestyle
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+        flow = layout.grid_flow(
+            row_major=True, columns=0, even_columns=True, even_rows=False, align=True
+        )
+
+        flow.prop(rd, "line_thickness_mode", expand=True)
+
+        if rd.line_thickness_mode == 'ABSOLUTE':
+            flow.prop(rd, "line_thickness")
+
+        # Warning if the Freestyle SVG Exporter addon is not enabled
+        if not check_render_freestyle_svg():
+            # col = box.column()
+            layout.label(text="Please enable Freestyle SVG Exporter addon", icon="INFO")
+            # layout.separator()
+            layout.operator(
+                "preferences.addon_show",
+                text="Go to Render: Freestyle SVG Exporter addon",
+                icon="PREFERENCES",
+            ).module = "render_freestyle_svg"
+
+
+##class RENDER_PT_povray_baking(RenderButtonsPanel, Panel):
+##    bl_label = "Baking"
+##    COMPAT_ENGINES = {'POVRAY_RENDER'}
+##
+##    def draw_header(self, context):
+##        scene = context.scene
+##
+##        self.layout.prop(scene.pov, "baking_enable", text="")
+##
+##    def draw(self, context):
+##        layout = self.layout
+##
+##        scene = context.scene
+##        rd = scene.render
+##
+##        layout.active = scene.pov.baking_enable
+
+
+classes = (
+    RENDER_PT_POV_export_settings,
+    RENDER_PT_POV_render_settings,
+    RENDER_PT_POV_photons,
+    RENDER_PT_POV_antialias,
+    RENDER_PT_POV_radiosity,
+    RENDER_PT_POV_filter,
+    # RENDER_PT_povray_baking,
+    POV_RADIOSITY_MT_presets,
+    RENDER_OT_POV_radiosity_add_preset,
+)
+
+
+def register():
+    for cls in classes:
+        register_class(cls)
+    bpy.types.RENDER_PT_POV_radiosity.prepend(rad_panel_func)
+
+
+def unregister():
+    bpy.types.RENDER_PT_POV_radiosity.remove(rad_panel_func)
+    for cls in reversed(classes):
+        unregister_class(cls)
diff --git a/render_povray/render_properties.py b/render_povray/render_properties.py
new file mode 100755
index 000000000..9096c9864
--- /dev/null
+++ b/render_povray/render_properties.py
@@ -0,0 +1,687 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+"""Declare rendering properties controllable in UI"""
+
+import bpy
+from bpy.utils import register_class, unregister_class
+from bpy.types import PropertyGroup
+from bpy.props import (
+    BoolProperty,
+    IntProperty,
+    FloatProperty,
+    FloatVectorProperty,
+    StringProperty,
+    EnumProperty,
+    PointerProperty,
+)
+
+###############################################################################
+# Scene POV properties.
+###############################################################################
+class RenderPovSettingsScene(PropertyGroup):
+
+    """Declare scene level properties controllable in UI and translated to POV"""
+
+    # Linux SDL-window enable
+    sdl_window_enable: BoolProperty(
+        name="Enable SDL window", description="Enable the SDL window in Linux OS", default=True
+    )
+    # File Options
+    text_block: StringProperty(
+        name="Text Scene Name",
+        description="Name of POV scene to use. "
+        "Set when clicking Run to render current text only",
+        maxlen=1024,
+    )
+    tempfiles_enable: BoolProperty(
+        name="Enable Tempfiles",
+        description="Enable the OS-Tempfiles. Otherwise set the path where to save the files",
+        default=True,
+    )
+    pov_editor: BoolProperty(
+        name="POV editor",
+        description="Don't Close POV editor after rendering (Overridden by /EXIT command)",
+        default=False,
+    )
+    deletefiles_enable: BoolProperty(
+        name="Delete files",
+        description="Delete files after rendering. Doesn't work with the image",
+        default=True,
+    )
+    scene_name: StringProperty(
+        name="Scene Name",
+        description="Name of POV scene to create. Empty name will use "
+        "the name of the blend file",
+        maxlen=1024,
+    )
+    scene_path: StringProperty(
+        name="Export scene path",
+        # Bug in POV-Ray RC3
+        # description="Path to directory where the exported scene "
+        # "(POV and INI) is created",
+        description="Path to directory where the files are created",
+        maxlen=1024,
+        subtype="DIR_PATH",
+    )
+    renderimage_path: StringProperty(
+        name="Rendered image path",
+        description="Full path to directory where the rendered image is saved",
+        maxlen=1024,
+        subtype="DIR_PATH",
+    )
+    list_lf_enable: BoolProperty(
+        name="LF in lists",
+        description="Enable line breaks in lists (vectors and indices). "
+        "Disabled: lists are exported in one line",
+        default=False,
+    )
+
+    # Not a real pov option, just to know if we should write
+    radio_enable: BoolProperty(
+        name="Enable Radiosity", description="Enable POV radiosity calculation", default=True
+    )
+
+    radio_display_advanced: BoolProperty(
+        name="Advanced Options", description="Show advanced options", default=False
+    )
+
+    media_enable: BoolProperty(
+        name="Enable Media", description="Enable POV atmospheric media", default=False
+    )
+
+    media_samples: IntProperty(
+        name="Samples",
+        description="Number of samples taken from camera to first object "
+        "encountered along ray path for media calculation",
+        min=1,
+        max=100,
+        default=35,
+    )
+
+    media_scattering_type: EnumProperty(
+        name="Scattering Type",
+        description="Scattering model",
+        items=(
+            (
+                "1",
+                "1 Isotropic",
+                "The simplest form of scattering because it is independent of direction.",
+            ),
+            (
+                "2",
+                "2 Mie haze ",
+                "For relatively small particles such as "
+                "minuscule water droplets of fog, cloud "
+                "particles, and particles responsible "
+                "for the polluted sky. In this model the"
+                " scattering is extremely directional in"
+                " the forward direction i.e. the amount "
+                "of scattered light is largest when the "
+                "incident light is anti-parallel to the "
+                "viewing direction (the light goes "
+                "directly to the viewer). It is smallest"
+                " when the incident light is parallel to"
+                " the viewing direction. ",
+            ),
+            ("3", "3 Mie murky", "Like haze but much more directional"),
+            (
+                "4",
+                "4 Rayleigh",
+                "For extremely small particles such as "
+                "molecules of the air. The amount of "
+                "scattered light depends on the incident"
+                " light angle. It is largest when the "
+                "incident light is parallel or "
+                "anti-parallel to the viewing direction "
+                "and smallest when the incident light is "
+                "perpendicular to viewing direction.",
+            ),
+            (
+                "5",
+                "5 Henyey-Greenstein",
+                "The default eccentricity value "
+                "of zero defines isotropic "
+                "scattering while positive "
+                "values lead to scattering in "
+                "the direction of the light and "
+                "negative values lead to "
+                "scattering in the opposite "
+                "direction of the light. Larger "
+                "values of e (or smaller values "
+                "in the negative case) increase "
+                "the directional property of the"
+                " scattering.",
+            ),
+        ),
+        default="1",
+    )
+
+    media_diffusion_scale: FloatProperty(
+        name="Scale",
+        description="Scale factor of Media Diffusion Color",
+        precision=6,
+        step=0.00000001,
+        min=0.000000001,
+        max=1.0,
+        default=(1.0),
+    )
+
+    media_diffusion_color: FloatVectorProperty(
+        name="Media Diffusion Color",
+        description="The atmospheric media color",
+        precision=4,
+        step=0.01,
+        min=0,
+        soft_max=1,
+        default=(0.001, 0.001, 0.001),
+        options={"ANIMATABLE"},
+        subtype="COLOR",
+    )
+
+    media_absorption_scale: FloatProperty(
+        name="Scale",
+        description="Scale factor of Media Absorption Color. "
+        "use 1/depth of media volume in meters",
+        precision=6,
+        step=0.000001,
+        min=0.000000001,
+        max=1.0,
+        default=(0.00002),
+    )
+
+    media_absorption_color: FloatVectorProperty(
+        name="Media Absorption Color",
+        description="The atmospheric media absorption color",
+        precision=4,
+        step=0.01,
+        min=0,
+        soft_max=1,
+        default=(0.0, 0.0, 0.0),
+        options={"ANIMATABLE"},
+        subtype="COLOR",
+    )
+
+    media_eccentricity: FloatProperty(
+        name="Media Eccenticity Factor",
+        description="Positive values lead"
+        " to scattering in the direction of the light and negative "
+        "values lead to scattering in the opposite direction of the "
+        "light. Larger values of e (or smaller values in the negative"
+        " case) increase the directional property of the scattering",
+        precision=2,
+        step=0.01,
+        min=-1.0,
+        max=1.0,
+        default=(0.0),
+        options={"ANIMATABLE"},
+    )
+
+    baking_enable: BoolProperty(
+        name="Enable Baking", description="Enable POV texture baking", default=False
+    )
+
+    indentation_character: EnumProperty(
+        name="Indentation",
+        description="Select the indentation type",
+        items=(
+            ("NONE", "None", "No indentation"),
+            ("TAB", "Tabs", "Indentation with tabs"),
+            ("SPACE", "Spaces", "Indentation with spaces"),
+        ),
+        default="SPACE",
+    )
+
+    indentation_spaces: IntProperty(
+        name="Quantity of spaces",
+        description="The number of spaces for indentation",
+        min=1,
+        max=10,
+        default=4,
+    )
+
+    comments_enable: BoolProperty(
+        name="Enable Comments", description="Add comments to pov file", default=True
+    )
+
+    # Real pov options
+    command_line_switches: StringProperty(
+        name="Command Line Switches",
+        description="Command line switches consist of a + (plus) or - "
+        "(minus) sign, followed by one or more alphabetic "
+        "characters and possibly a numeric value",
+        maxlen=500,
+    )
+
+    antialias_enable: BoolProperty(
+        name="Anti-Alias", description="Enable Anti-Aliasing", default=True
+    )
+
+    antialias_method: EnumProperty(
+        name="Method",
+        description="AA-sampling method. Type 1 is an adaptive, "
+        "non-recursive, super-sampling (as in the plain old render "
+        "bigger and scale down trick. Type 2 is a slightly "
+        "more efficient adaptive and recursive super-sampling. "
+        "Type 3 is a stochastic halton based super-sampling method so "
+        "rather artifact free and sampling rays so depth of field can "
+        "use them at no additional cost, as do area lights and "
+        "subsurface scattering materials, making it the best "
+        "quality / time trade-off in complex scenes",
+        items=(
+            ("0", "non-recursive AA", "Type 1 Sampling in POV"),
+            ("1", "recursive AA", "Type 2 Sampling in POV"),
+            ("2", "stochastic AA", "Type 3 Sampling in POV"),
+        ),
+        default="1",
+    )
+
+    antialias_confidence: FloatProperty(
+        name="Antialias Confidence",
+        description="how surely the computed color "
+        "of a given pixel is indeed"
+        "within the threshold error margin",
+        min=0.0001,
+        max=1.0000,
+        default=0.9900,
+        precision=4,
+    )
+
+    antialias_depth: IntProperty(
+        name="Antialias Depth", description="Depth of pixel for sampling", min=1, max=9, default=2
+    )
+
+    antialias_threshold: FloatProperty(
+        name="Antialias Threshold",
+        description="Tolerance for sub-pixels",
+        min=0.0,
+        max=1.0,
+        soft_min=0.05,
+        soft_max=0.5,
+        default=0.03,
+    )
+
+    jitter_enable: BoolProperty(
+        name="Jitter",
+        description="Enable Jittering. Adds noise into the sampling "
+        "process (it should be avoided to use jitter in "
+        "animation)",
+        default=False,
+    )
+
+    jitter_amount: FloatProperty(
+        name="Jitter Amount",
+        description="Amount of jittering",
+        min=0.0,
+        max=1.0,
+        soft_min=0.01,
+        soft_max=1.0,
+        default=1.0,
+    )
+
+    antialias_gamma: FloatProperty(
+        name="Antialias Gamma",
+        description="POV-Ray compares gamma-adjusted values for super "
+        "sampling. Antialias Gamma sets the Gamma before "
+        "comparison",
+        min=0.0,
+        max=5.0,
+        soft_min=0.01,
+        soft_max=2.5,
+        default=2.5,
+    )
+
+    alpha_mode: EnumProperty(
+        name="Alpha",
+        description="Representation of alpha information in the RGBA pixels",
+        items=(
+            ("SKY", "Sky", "Transparent pixels are filled with sky color"),
+            (
+                "TRANSPARENT",
+                "Transparent",
+                "Transparent, World background is transparent with premultiplied alpha",
+            ),
+        ),
+        default="SKY",
+    )
+
+    use_shadows: BoolProperty(
+        name="Shadows", description="Calculate shadows while rendering", default=True
+    )
+
+    max_trace_level: IntProperty(
+        name="Max Trace Level",
+        description="Number of reflections/refractions allowed on ray " "path",
+        min=1,
+        max=256,
+        default=5,
+    )
+
+    adc_bailout_enable: BoolProperty(name="Enable", description="", default=False)
+
+    adc_bailout: FloatProperty(
+        name="ADC Bailout",
+        description="Adaptive Depth Control (ADC) to stop computing additional"
+        "reflected or refracted rays when their contribution is insignificant."
+        "The default value is 1/255, or approximately 0.0039, since a change "
+        "smaller than that could not be visible in a 24 bit image. Generally "
+        "this value is fine and should be left alone."
+        "Setting adc_bailout to 0 will disable ADC, relying completely on "
+        "max_trace_level to set an upper limit on the number of rays spawned. ",
+        min=0.0,
+        max=1000.0,
+        default=0.00392156862745,
+        precision=3,
+    )
+
+    ambient_light_enable: BoolProperty(name="Enable", description="", default=False)
+
+    ambient_light: FloatVectorProperty(
+        name="Ambient Light",
+        description="Ambient light is used to simulate the effect of inter-diffuse reflection",
+        precision=4,
+        step=0.01,
+        min=0,
+        soft_max=1,
+        default=(1, 1, 1),
+        options={"ANIMATABLE"},
+        subtype="COLOR",
+    )
+    global_settings_advanced: BoolProperty(name="Advanced", description="", default=False)
+
+    irid_wavelength_enable: BoolProperty(name="Enable", description="", default=False)
+
+    irid_wavelength: FloatVectorProperty(
+        name="Irid Wavelength",
+        description=(
+            "Iridescence calculations depend upon the dominant "
+            "wavelengths of the primary colors of red, green and blue light"
+        ),
+        precision=4,
+        step=0.01,
+        min=0,
+        soft_max=1,
+        default=(0.25, 0.18, 0.14),
+        options={"ANIMATABLE"},
+        subtype="COLOR",
+    )
+
+    number_of_waves_enable: BoolProperty(name="Enable", description="", default=False)
+
+    number_of_waves: IntProperty(
+        name="Number Waves",
+        description=(
+            "The waves and ripples patterns are generated by summing a series of waves, "
+            "each with a slightly different center and size"
+        ),
+        min=1,
+        max=10,
+        default=1000,
+    )
+
+    noise_generator_enable: BoolProperty(name="Enable", description="", default=False)
+
+    noise_generator: IntProperty(
+        name="Noise Generator",
+        description="There are three noise generators implemented",
+        min=1,
+        max=3,
+        default=2,
+    )
+
+    ########################### PHOTONS #######################################
+    photon_enable: BoolProperty(name="Photons", description="Enable global photons", default=False)
+
+    photon_enable_count: BoolProperty(
+        name="Spacing / Count", description="Enable count photons", default=False
+    )
+
+    photon_count: IntProperty(
+        name="Count", description="Photons count", min=1, max=100000000, default=20000
+    )
+
+    photon_spacing: FloatProperty(
+        name="Spacing",
+        description="Average distance between photons on surfaces. half "
+        "this get four times as many surface photons",
+        min=0.001,
+        max=1.000,
+        soft_min=0.001,
+        soft_max=1.000,
+        precision=3,
+        default=0.005,
+    )
+
+    photon_max_trace_level: IntProperty(
+        name="Max Trace Level",
+        description="Number of reflections/refractions allowed on ray " "path",
+        min=1,
+        max=256,
+        default=5,
+    )
+
+    photon_adc_bailout: FloatProperty(
+        name="ADC Bailout",
+        description="The adc_bailout for photons. Use adc_bailout = "
+        "0.01 / brightest_ambient_object for good results",
+        min=0.0,
+        max=1000.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        precision=3,
+        default=0.1,
+    )
+
+    photon_gather_min: IntProperty(
+        name="Gather Min",
+        description="Minimum number of photons gathered" "for each point",
+        min=1,
+        max=256,
+        default=20,
+    )
+
+    photon_gather_max: IntProperty(
+        name="Gather Max",
+        description="Maximum number of photons gathered for each point",
+        min=1,
+        max=256,
+        default=100,
+    )
+
+    photon_map_file_save_load: EnumProperty(
+        name="Operation",
+        description="Load or Save photon map file",
+        items=(("NONE", "None", ""), ("save", "Save", ""), ("load", "Load", "")),
+        default="NONE",
+    )
+
+    photon_map_filename: StringProperty(name="Filename", description="", maxlen=1024)
+
+    photon_map_dir: StringProperty(
+        name="Directory", description="", maxlen=1024, subtype="DIR_PATH"
+    )
+
+    photon_map_file: StringProperty(name="File", description="", maxlen=1024, subtype="FILE_PATH")
+
+    #########RADIOSITY########
+    radio_adc_bailout: FloatProperty(
+        name="ADC Bailout",
+        description="The adc_bailout for radiosity rays. Use "
+        "adc_bailout = 0.01 / brightest_ambient_object for good results",
+        min=0.0,
+        max=1000.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=0.0039,
+        precision=4,
+    )
+
+    radio_always_sample: BoolProperty(
+        name="Always Sample",
+        description="Only use the data from the pretrace step and not gather "
+        "any new samples during the final radiosity pass",
+        default=False,
+    )
+
+    radio_brightness: FloatProperty(
+        name="Brightness",
+        description="Amount objects are brightened before being returned "
+        "upwards to the rest of the system",
+        min=0.0,
+        max=1000.0,
+        soft_min=0.0,
+        soft_max=10.0,
+        default=1.0,
+    )
+
+    radio_count: IntProperty(
+        name="Ray Count",
+        description="Number of rays for each new radiosity value to be calculated "
+        "(halton sequence over 1600)",
+        min=1,
+        max=10000,
+        soft_max=1600,
+        default=35,
+    )
+
+    radio_error_bound: FloatProperty(
+        name="Error Bound",
+        description="One of the two main speed/quality tuning values, "
+        "lower values are more accurate",
+        min=0.0,
+        max=1000.0,
+        soft_min=0.1,
+        soft_max=10.0,
+        default=10.0,
+    )
+
+    radio_gray_threshold: FloatProperty(
+        name="Gray Threshold",
+        description="One of the two main speed/quality tuning values, "
+        "lower values are more accurate",
+        min=0.0,
+        max=1.0,
+        soft_min=0,
+        soft_max=1,
+        default=0.0,
+    )
+
+    radio_low_error_factor: FloatProperty(
+        name="Low Error Factor",
+        description="Just enough samples is slightly blotchy. Low error changes error "
+        "tolerance for less critical last refining pass",
+        min=0.000001,
+        max=1.0,
+        soft_min=0.000001,
+        soft_max=1.0,
+        default=0.5,
+    )
+
+    radio_media: BoolProperty(
+        name="Media", description="Radiosity estimation can be affected by media", default=True
+    )
+
+    radio_subsurface: BoolProperty(
+        name="Subsurface",
+        description="Radiosity estimation can be affected by Subsurface Light Transport",
+        default=False,
+    )
+
+    radio_minimum_reuse: FloatProperty(
+        name="Minimum Reuse",
+        description="Fraction of the screen width which sets the minimum radius of reuse "
+        "for each sample point (At values higher than 2% expect errors)",
+        min=0.0,
+        max=1.0,
+        soft_min=0.1,
+        soft_max=0.1,
+        default=0.015,
+        precision=3,
+    )
+
+    radio_maximum_reuse: FloatProperty(
+        name="Maximum Reuse",
+        description="The maximum reuse parameter works in conjunction with, and is similar to that of minimum reuse, "
+        "the only difference being that it is an upper bound rather than a lower one",
+        min=0.0,
+        max=1.0,
+        default=0.2,
+        precision=3,
+    )
+
+    radio_nearest_count: IntProperty(
+        name="Nearest Count",
+        description="Number of old ambient values blended together to "
+        "create a new interpolated value",
+        min=1,
+        max=20,
+        default=1,
+    )
+
+    radio_normal: BoolProperty(
+        name="Normals", description="Radiosity estimation can be affected by normals", default=False
+    )
+
+    radio_recursion_limit: IntProperty(
+        name="Recursion Limit",
+        description="how many recursion levels are used to calculate "
+        "the diffuse inter-reflection",
+        min=1,
+        max=20,
+        default=1,
+    )
+
+    radio_pretrace_start: FloatProperty(
+        name="Pretrace Start",
+        description="Fraction of the screen width which sets the size of the "
+        "blocks in the mosaic preview first pass",
+        min=0.005,
+        max=1.00,
+        soft_min=0.02,
+        soft_max=1.0,
+        default=0.04,
+    )
+    # XXX TODO set automatically to  pretrace_end = 8 / max (image_width, image_height)
+    # for non advanced mode
+    radio_pretrace_end: FloatProperty(
+        name="Pretrace End",
+        description="Fraction of the screen width which sets the size of the blocks "
+        "in the mosaic preview last pass",
+        min=0.000925,
+        max=1.00,
+        soft_min=0.01,
+        soft_max=1.00,
+        default=0.004,
+        precision=3,
+    )
+
+
+classes = (RenderPovSettingsScene,)
+
+
+def register():
+    for cls in classes:
+        register_class(cls)
+    bpy.types.Scene.pov = PointerProperty(type=RenderPovSettingsScene)
+
+
+def unregister():
+    del bpy.types.Scene.pov
+    for cls in reversed(classes):
+        unregister_class(cls)
diff --git a/render_povray/scenography.py b/render_povray/scenography.py
new file mode 100755
index 000000000..4b0c99e32
--- /dev/null
+++ b/render_povray/scenography.py
@@ -0,0 +1,847 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# #**** END GPL LICENSE BLOCK #****
+
+# <pep8 compliant>
+
+"""With respect to camera frame and optics distortions, also export environment
+
+with world, sky, atmospheric effects such as rainbows or smoke """
+
+import bpy
+from bpy.utils import register_class, unregister_class
+import os
+from imghdr import what  # imghdr is a python lib to identify image file types
+from math import atan, pi, sqrt, degrees
+from . import df3_library  # for smoke rendering
+from .object_primitives import write_object_modifiers
+
+##############find image texture # used for export_world
+def image_format(imgF):
+    """Identify input image filetypes to transmit to POV."""
+    # First use the below explicit extensions to identify image file prospects
+    ext = {
+        'JPG': "jpeg",
+        'JPEG': "jpeg",
+        'GIF': "gif",
+        'TGA': "tga",
+        'IFF': "iff",
+        'PPM': "ppm",
+        'PNG': "png",
+        'SYS': "sys",
+        'TIFF': "tiff",
+        'TIF': "tiff",
+        'EXR': "exr",
+        'HDR': "hdr",
+    }.get(os.path.splitext(imgF)[-1].upper(), "")
+    # Then, use imghdr to really identify the filetype as it can be different
+    if not ext:
+        # maybe add a check for if path exists here?
+        print(" WARNING: texture image has no extension")  # too verbose
+
+        ext = what(imgF)  # imghdr is a python lib to identify image file types
+    return ext
+
+
+def img_map(ts):
+    """Translate mapping type from Blender UI to POV syntax and return that string."""
+    image_map = ""
+    texdata = bpy.data.textures[ts.texture]
+    if ts.mapping == 'FLAT':
+        image_map = "map_type 0 "
+    elif ts.mapping == 'SPHERE':
+        image_map = "map_type 1 "
+    elif ts.mapping == 'TUBE':
+        image_map = "map_type 2 "
+
+    ## map_type 3 and 4 in development (?) (ENV in pov 3.8)
+    ## for POV-Ray, currently they just seem to default back to Flat (type 0)
+    # elif ts.mapping=="?":
+    #    image_map = " map_type 3 "
+    # elif ts.mapping=="?":
+    #    image_map = " map_type 4 "
+    if ts.use_interpolation:  # Available if image sampling class reactivated?
+        image_map += " interpolate 2 "
+    if texdata.extension == 'CLIP':
+        image_map += " once "
+    # image_map += "}"
+    # if ts.mapping=='CUBE':
+    #    image_map+= "warp { cubic } rotate <-90,0,180>"
+    # no direct cube type mapping. Though this should work in POV 3.7
+    # it doesn't give that good results(best suited to environment maps?)
+    # if image_map == "":
+    #    print(" No texture image  found ")
+    return image_map
+
+
+def img_map_transforms(ts):
+    """Translate mapping transformations from Blender UI to POV syntax and return that string."""
+    # XXX TODO: unchecked textures give error of variable referenced before assignment XXX
+    # POV-Ray "scale" is not a number of repetitions factor, but ,its
+    # inverse, a standard scale factor.
+    # 0.5 Offset is needed relatively to scale because center of the
+    # scale is 0.5,0.5 in blender and 0,0 in POV
+    # Strange that the translation factor for scale is not the same as for
+    # translate.
+    # TODO: verify both matches with other blender renderers / internal in previous versions.
+    image_map_transforms = ""
+    image_map_transforms = "scale <%.4g,%.4g,%.4g> translate <%.4g,%.4g,%.4g>" % (
+        ts.scale[0],
+        ts.scale[1],
+        ts.scale[2],
+        ts.offset[0],
+        ts.offset[1],
+        ts.offset[2],
+    )
+    # image_map_transforms = (" translate <-0.5,-0.5,0.0> scale <%.4g,%.4g,%.4g> translate <%.4g,%.4g,%.4g>" % \
+    # ( 1.0 / ts.scale.x,
+    # 1.0 / ts.scale.y,
+    # 1.0 / ts.scale.z,
+    # (0.5 / ts.scale.x) + ts.offset.x,
+    # (0.5 / ts.scale.y) + ts.offset.y,
+    # ts.offset.z))
+    # image_map_transforms = (
+    # "translate <-0.5,-0.5,0> "
+    # "scale <-1,-1,1> * <%.4g,%.4g,%.4g> "
+    # "translate <0.5,0.5,0> + <%.4g,%.4g,%.4g>" % \
+    # (1.0 / ts.scale.x,
+    # 1.0 / ts.scale.y,
+    # 1.0 / ts.scale.z,
+    # ts.offset.x,
+    # ts.offset.y,
+    # ts.offset.z)
+    # )
+    return image_map_transforms
+
+
+def img_map_bg(wts):
+    """Translate world mapping from Blender UI to POV syntax and return that string."""
+    tex = bpy.data.textures[wts.texture]
+    image_mapBG = ""
+    # texture_coords refers to the mapping of world textures:
+    if wts.texture_coords == 'VIEW' or wts.texture_coords == 'GLOBAL':
+        image_mapBG = " map_type 0 "
+    elif wts.texture_coords == 'ANGMAP':
+        image_mapBG = " map_type 1 "
+    elif wts.texture_coords == 'TUBE':
+        image_mapBG = " map_type 2 "
+
+    if tex.use_interpolation:
+        image_mapBG += " interpolate 2 "
+    if tex.extension == 'CLIP':
+        image_mapBG += " once "
+    # image_mapBG += "}"
+    # if wts.mapping == 'CUBE':
+    #   image_mapBG += "warp { cubic } rotate <-90,0,180>"
+    # no direct cube type mapping. Though this should work in POV 3.7
+    # it doesn't give that good results(best suited to environment maps?)
+    # if image_mapBG == "":
+    #    print(" No background texture image  found ")
+    return image_mapBG
+
+
+def path_image(image):
+    """Conform a path string to POV syntax to avoid POV errors."""
+    return bpy.path.abspath(image.filepath, library=image.library).replace("\\", "/")
+    # .replace("\\","/") to get only forward slashes as it's what POV prefers,
+    # even on windows
+
+
+# end find image texture
+# -----------------------------------------------------------------------------
+
+
+def export_camera(scene, global_matrix, render, tab_write):
+    """Translate camera from Blender UI to POV syntax and write to exported file."""
+    camera = scene.camera
+
+    # DH disabled for now, this isn't the correct context
+    active_object = None  # bpy.context.active_object # does not always work  MR
+    matrix = global_matrix @ camera.matrix_world
+    focal_point = camera.data.dof.focus_distance
+
+    # compute resolution
+    q_size = render.resolution_x / render.resolution_y
+    tab_write("#declare camLocation  = <%.6f, %.6f, %.6f>;\n" % matrix.translation[:])
+    tab_write(
+        "#declare camLookAt = <%.6f, %.6f, %.6f>;\n"
+        % tuple([degrees(e) for e in matrix.to_3x3().to_euler()])
+    )
+
+    tab_write("camera {\n")
+    if scene.pov.baking_enable and active_object and active_object.type == 'MESH':
+        tab_write("mesh_camera{ 1 3\n")  # distribution 3 is what we want here
+        tab_write("mesh{%s}\n" % active_object.name)
+        tab_write("}\n")
+        tab_write("location <0,0,.01>")
+        tab_write("direction <0,0,-1>")
+
+    else:
+        if camera.data.type == 'ORTHO':
+            # todo: track when SensorHeightRatio was added to see if needed (not used)
+            sensor_height_ratio = (
+                render.resolution_x * camera.data.ortho_scale / render.resolution_y
+            )
+            tab_write("orthographic\n")
+            # Blender angle is radian so should be converted to degrees:
+            # % (camera.data.angle * (180.0 / pi) )
+            # but actually argument is not compulsory after angle in pov ortho mode
+            tab_write("angle\n")
+            tab_write("right <%6f, 0, 0>\n" % -camera.data.ortho_scale)
+            tab_write("location  <0, 0, 0>\n")
+            tab_write("look_at  <0, 0, -1>\n")
+            tab_write("up <0, %6f, 0>\n" % (camera.data.ortho_scale / q_size))
+
+        elif camera.data.type == 'PANO':
+            tab_write("panoramic\n")
+            tab_write("location  <0, 0, 0>\n")
+            tab_write("look_at  <0, 0, -1>\n")
+            tab_write("right <%s, 0, 0>\n" % -q_size)
+            tab_write("up <0, 1, 0>\n")
+            tab_write("angle  %f\n" % (360.0 * atan(16.0 / camera.data.lens) / pi))
+        elif camera.data.type == 'PERSP':
+            # Standard camera otherwise would be default in pov
+            tab_write("location  <0, 0, 0>\n")
+            tab_write("look_at  <0, 0, -1>\n")
+            tab_write("right <%s, 0, 0>\n" % -q_size)
+            tab_write("up <0, 1, 0>\n")
+            tab_write(
+                "angle  %f\n"
+                % (2 * atan(camera.data.sensor_width / 2 / camera.data.lens) * 180.0 / pi)
+            )
+
+        tab_write(
+            "rotate  <%.6f, %.6f, %.6f>\n" % tuple([degrees(e) for e in matrix.to_3x3().to_euler()])
+        )
+        tab_write("translate <%.6f, %.6f, %.6f>\n" % matrix.translation[:])
+        if camera.data.dof.use_dof and (focal_point != 0 or camera.data.dof.focus_object):
+            tab_write("aperture %.3g\n" % (1 / (camera.data.dof.aperture_fstop * 10000) * 1000))
+            tab_write(
+                "blur_samples %d %d\n"
+                % (camera.data.pov.dof_samples_min, camera.data.pov.dof_samples_max)
+            )
+            tab_write("variance 1/%d\n" % camera.data.pov.dof_variance)
+            tab_write("confidence %.3g\n" % camera.data.pov.dof_confidence)
+            if camera.data.dof.focus_object:
+                focal_ob = scene.objects[camera.data.dof.focus_object.name]
+                matrix_blur = global_matrix @ focal_ob.matrix_world
+                tab_write("focal_point <%.4f,%.4f,%.4f>\n" % matrix_blur.translation[:])
+            else:
+                tab_write("focal_point <0, 0, %f>\n" % focal_point)
+    if camera.data.pov.normal_enable:
+        tab_write(
+            "normal {%s %.4f turbulence %.4f scale %.4f}\n"
+            % (
+                camera.data.pov.normal_patterns,
+                camera.data.pov.cam_normal,
+                camera.data.pov.turbulence,
+                camera.data.pov.scale,
+            )
+        )
+    tab_write("}\n")
+
+
+exported_lights_count = 0
+
+
+def export_lights(lamps, file, scene, global_matrix, write_matrix, tab_write):
+    """Translate lights from Blender UI to POV syntax and write to exported file."""
+
+    # Incremented after each lamp export to declare its target
+    # currently used for Fresnel diffuse shader as their slope vector:
+    global exported_lights_count
+    exported_lights_count = 0
+    # Get all lamps
+    for ob in lamps:
+        lamp = ob.data
+
+        matrix = global_matrix @ ob.matrix_world
+
+        # Color is no longer modified by energy
+        # any way to directly get bpy_prop_array as tuple?
+        color = tuple(lamp.color)
+
+        tab_write("light_source {\n")
+        tab_write("< 0,0,0 >\n")
+        tab_write("color srgb<%.3g, %.3g, %.3g>\n" % color)
+
+        if lamp.type == 'POINT':
+            pass
+        elif lamp.type == 'SPOT':
+            tab_write("spotlight\n")
+
+            # Falloff is the main radius from the centre line
+            tab_write("falloff %.2f\n" % (degrees(lamp.spot_size) / 2.0))  # 1 TO 179 FOR BOTH
+            tab_write("radius %.6f\n" % ((degrees(lamp.spot_size) / 2.0) * (1.0 - lamp.spot_blend)))
+
+            # Blender does not have a tightness equivalent, 0 is most like blender default.
+            tab_write("tightness 0\n")  # 0:10f
+
+            tab_write("point_at  <0, 0, -1>\n")
+            if lamp.pov.use_halo:
+                tab_write("looks_like{\n")
+                tab_write("sphere{<0,0,0>,%.6f\n" % lamp.distance)
+                tab_write("hollow\n")
+                tab_write("material{\n")
+                tab_write("texture{\n")
+                tab_write("pigment{rgbf<1,1,1,%.4f>}\n" % (lamp.pov.halo_intensity * 5.0))
+                tab_write("}\n")
+                tab_write("interior{\n")
+                tab_write("media{\n")
+                tab_write("emission 1\n")
+                tab_write("scattering {1, 0.5}\n")
+                tab_write("density{\n")
+                tab_write("spherical\n")
+                tab_write("color_map{\n")
+                tab_write("[0.0 rgb <0,0,0>]\n")
+                tab_write("[0.5 rgb <1,1,1>]\n")
+                tab_write("[1.0 rgb <1,1,1>]\n")
+                tab_write("}\n")
+                tab_write("}\n")
+                tab_write("}\n")
+                tab_write("}\n")
+                tab_write("}\n")
+                tab_write("}\n")
+                tab_write("}\n")
+        elif lamp.type == 'SUN':
+            tab_write("parallel\n")
+            tab_write("point_at  <0, 0, -1>\n")  # *must* be after 'parallel'
+
+        elif lamp.type == 'AREA':
+            tab_write("fade_distance %.6f\n" % (lamp.distance / 2.0))
+            # Area lights have no falloff type, so always use blenders lamp quad equivalent
+            # for those?
+            tab_write("fade_power %d\n" % 2)
+            size_x = lamp.size
+            samples_x = lamp.pov.shadow_ray_samples_x
+            if lamp.shape == 'SQUARE':
+                size_y = size_x
+                samples_y = samples_x
+            else:
+                size_y = lamp.size_y
+                samples_y = lamp.pov.shadow_ray_samples_y
+
+            tab_write(
+                "area_light <%.6f,0,0>,<0,%.6f,0> %d, %d\n" % (size_x, size_y, samples_x, samples_y)
+            )
+            tab_write("area_illumination\n")
+            if lamp.pov.shadow_ray_sample_method == 'CONSTANT_JITTERED':
+                if lamp.pov.use_jitter:
+                    tab_write("jitter\n")
+            else:
+                tab_write("adaptive 1\n")
+                tab_write("jitter\n")
+
+        # No shadow checked either at global or light level:
+        if not scene.pov.use_shadows or (lamp.pov.shadow_method == 'NOSHADOW'):
+            tab_write("shadowless\n")
+
+        # Sun shouldn't be attenuated. Area lights have no falloff attribute so they
+        # are put to type 2 attenuation a little higher above.
+        if lamp.type not in {'SUN', 'AREA'}:
+            if lamp.falloff_type == 'INVERSE_SQUARE':
+                tab_write("fade_distance %.6f\n" % (sqrt(lamp.distance / 2.0)))
+                tab_write("fade_power %d\n" % 2)  # Use blenders lamp quad equivalent
+            elif lamp.falloff_type == 'INVERSE_LINEAR':
+                tab_write("fade_distance %.6f\n" % (lamp.distance / 2.0))
+                tab_write("fade_power %d\n" % 1)  # Use blenders lamp linear
+            elif lamp.falloff_type == 'CONSTANT':
+                tab_write("fade_distance %.6f\n" % (lamp.distance / 2.0))
+                tab_write("fade_power %d\n" % 3)
+                # Use blenders lamp constant equivalent no attenuation.
+            # Using Custom curve for fade power 3 for now.
+            elif lamp.falloff_type == 'CUSTOM_CURVE':
+                tab_write("fade_power %d\n" % 4)
+
+        write_matrix(matrix)
+
+        tab_write("}\n")
+
+        exported_lights_count += 1
+
+        # v(A,B) rotates vector A about origin by vector B.
+        file.write(
+            "#declare lampTarget%s= vrotate(<%.4g,%.4g,%.4g>,<%.4g,%.4g,%.4g>);\n"
+            % (
+                exported_lights_count,
+                -(ob.location.x),
+                -(ob.location.y),
+                -(ob.location.z),
+                ob.rotation_euler.x,
+                ob.rotation_euler.y,
+                ob.rotation_euler.z,
+            )
+        )
+
+
+def export_world(world, scene, global_matrix, tab_write):
+    """write world as POV backgrounbd and sky_sphere to exported file """
+    render = scene.pov
+    camera = scene.camera
+    matrix = global_matrix @ camera.matrix_world  # view dependant for later use
+    if not world:
+        return
+    #############Maurice####################################
+    # These lines added to get sky gradient (visible with PNG output)
+    if world:
+        # For simple flat background:
+        if not world.pov.use_sky_blend:
+            # Non fully transparent background could premultiply alpha and avoid anti-aliasing
+            # display issue:
+            if render.alpha_mode == 'TRANSPARENT':
+                tab_write(
+                    "background {rgbt<%.3g, %.3g, %.3g, 0.75>}\n" % (world.pov.horizon_color[:])
+                )
+            # Currently using no alpha with Sky option:
+            elif render.alpha_mode == 'SKY':
+                tab_write("background {rgbt<%.3g, %.3g, %.3g, 0>}\n" % (world.pov.horizon_color[:]))
+            # StraightAlpha:
+            # XXX Does not exists anymore
+            # else:
+            # tab_write("background {rgbt<%.3g, %.3g, %.3g, 1>}\n" % (world.pov.horizon_color[:]))
+
+        world_tex_count = 0
+        # For Background image textures
+        for t in world.pov_texture_slots:  # risk to write several sky_spheres but maybe ok.
+            if t:
+                tex = bpy.data.textures[t.texture]
+            if tex.type is not None:
+                world_tex_count += 1
+                # XXX No enable checkbox for world textures yet (report it?)
+                # if t and tex.type == 'IMAGE' and t.use:
+                if tex.type == 'IMAGE':
+                    image_filename = path_image(tex.image)
+                    if tex.image.filepath != image_filename:
+                        tex.image.filepath = image_filename
+                    if image_filename != "" and t.use_map_blend:
+                        textures_blend = image_filename
+                        # colvalue = t.default_value
+                        t_blend = t
+
+                    # Commented below was an idea to make the Background image oriented as camera
+                    # taken here:
+                    # http://news.pov.org/pov.newusers/thread/%3Cweb.4a5cddf4e9c9822ba2f93e20@news.pov.org%3E/
+                    # Replace 4/3 by the ratio of each image found by some custom or existing
+                    # function
+                    # mapping_blend = (" translate <%.4g,%.4g,%.4g> rotate z*degrees" \
+                    #                "(atan((camLocation - camLookAt).x/(camLocation - " \
+                    #                "camLookAt).y)) rotate x*degrees(atan((camLocation - " \
+                    #                "camLookAt).y/(camLocation - camLookAt).z)) rotate y*" \
+                    #                "degrees(atan((camLocation - camLookAt).z/(camLocation - " \
+                    #                "camLookAt).x)) scale <%.4g,%.4g,%.4g>b" % \
+                    #                (t_blend.offset.x / 10 , t_blend.offset.y / 10 ,
+                    #                 t_blend.offset.z / 10, t_blend.scale.x ,
+                    #                 t_blend.scale.y , t_blend.scale.z))
+                    # using camera rotation valuesdirectly from blender seems much easier
+                    if t_blend.texture_coords == 'ANGMAP':
+                        mapping_blend = ""
+                    else:
+                        # POV-Ray "scale" is not a number of repetitions factor, but its
+                        # inverse, a standard scale factor.
+                        # 0.5 Offset is needed relatively to scale because center of the
+                        # UV scale is 0.5,0.5 in blender and 0,0 in POV
+                        # Further Scale by 2 and translate by -1 are
+                        # required for the sky_sphere not to repeat
+
+                        mapping_blend = (
+                            "scale 2 scale <%.4g,%.4g,%.4g> translate -1 "
+                            "translate <%.4g,%.4g,%.4g> rotate<0,0,0> "
+                            % (
+                                (1.0 / t_blend.scale.x),
+                                (1.0 / t_blend.scale.y),
+                                (1.0 / t_blend.scale.z),
+                                0.5 - (0.5 / t_blend.scale.x) - t_blend.offset.x,
+                                0.5 - (0.5 / t_blend.scale.y) - t_blend.offset.y,
+                                t_blend.offset.z,
+                            )
+                        )
+
+                        # The initial position and rotation of the pov camera is probably creating
+                        # the rotation offset should look into it someday but at least background
+                        # won't rotate with the camera now.
+                    # Putting the map on a plane would not introduce the skysphere distortion and
+                    # allow for better image scale matching but also some waay to chose depth and
+                    # size of the plane relative to camera.
+                    tab_write("sky_sphere {\n")
+                    tab_write("pigment {\n")
+                    tab_write(
+                        "image_map{%s \"%s\" %s}\n"
+                        % (image_format(textures_blend), textures_blend, img_map_bg(t_blend))
+                    )
+                    tab_write("}\n")
+                    tab_write("%s\n" % (mapping_blend))
+                    # The following layered pigment opacifies to black over the texture for
+                    # transmit below 1 or otherwise adds to itself
+                    tab_write("pigment {rgb 0 transmit %s}\n" % (tex.intensity))
+                    tab_write("}\n")
+                    # tab_write("scale 2\n")
+                    # tab_write("translate -1\n")
+
+        # For only Background gradient
+
+        if world_tex_count == 0:
+            if world.pov.use_sky_blend:
+                tab_write("sky_sphere {\n")
+                tab_write("pigment {\n")
+                # maybe Should follow the advice of POV doc about replacing gradient
+                # for skysphere..5.5
+                tab_write("gradient y\n")
+                tab_write("color_map {\n")
+                # XXX Does not exists anymore
+                # if render.alpha_mode == 'STRAIGHT':
+                # tab_write("[0.0 rgbt<%.3g, %.3g, %.3g, 1>]\n" % (world.pov.horizon_color[:]))
+                # tab_write("[1.0 rgbt<%.3g, %.3g, %.3g, 1>]\n" % (world.pov.zenith_color[:]))
+                if render.alpha_mode == 'TRANSPARENT':
+                    tab_write("[0.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n" % (world.pov.horizon_color[:]))
+                    # aa premult not solved with transmit 1
+                    tab_write("[1.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n" % (world.pov.zenith_color[:]))
+                else:
+                    tab_write("[0.0 rgbt<%.3g, %.3g, %.3g, 0>]\n" % (world.pov.horizon_color[:]))
+                    tab_write("[1.0 rgbt<%.3g, %.3g, %.3g, 0>]\n" % (world.pov.zenith_color[:]))
+                tab_write("}\n")
+                tab_write("}\n")
+                tab_write("}\n")
+                # Sky_sphere alpha (transmit) is not translating into image alpha the same
+                # way as 'background'
+
+        # if world.pov.light_settings.use_indirect_light:
+        #    scene.pov.radio_enable=1
+
+        # Maybe change the above to a function copyInternalRenderer settings when
+        # user pushes a button, then:
+        # scene.pov.radio_enable = world.pov.light_settings.use_indirect_light
+        # and other such translations but maybe this would not be allowed either?
+
+    ###############################################################
+
+    mist = world.mist_settings
+
+    if mist.use_mist:
+        tab_write("fog {\n")
+        if mist.falloff == 'LINEAR':
+            tab_write("distance %.6f\n" % ((mist.start + mist.depth) * 0.368))
+        elif mist.falloff == 'QUADRATIC':  # n**2 or squrt(n)?
+            tab_write("distance %.6f\n" % ((mist.start + mist.depth) ** 2 * 0.368))
+        elif mist.falloff == 'INVERSE_QUADRATIC':  # n**2 or squrt(n)?
+            tab_write("distance %.6f\n" % ((mist.start + mist.depth) ** 2 * 0.368))
+        tab_write(
+            "color rgbt<%.3g, %.3g, %.3g, %.3g>\n"
+            % (*world.pov.horizon_color, 1.0 - mist.intensity)
+        )
+        # tab_write("fog_offset %.6f\n" % mist.start) #create a pov property to prepend
+        # tab_write("fog_alt %.6f\n" % mist.height) #XXX right?
+        # tab_write("turbulence 0.2\n")
+        # tab_write("turb_depth 0.3\n")
+        tab_write("fog_type 1\n")  # type2 for height
+        tab_write("}\n")
+    if scene.pov.media_enable:
+        tab_write("media {\n")
+        tab_write(
+            "scattering { %d, rgb %.12f*<%.4g, %.4g, %.4g>\n"
+            % (
+                int(scene.pov.media_scattering_type),
+                (scene.pov.media_diffusion_scale),
+                *(scene.pov.media_diffusion_color[:]),
+            )
+        )
+        if scene.pov.media_scattering_type == '5':
+            tab_write("eccentricity %.3g\n" % scene.pov.media_eccentricity)
+        tab_write("}\n")
+        tab_write(
+            "absorption %.12f*<%.4g, %.4g, %.4g>\n"
+            % (scene.pov.media_absorption_scale, *(scene.pov.media_absorption_color[:]))
+        )
+        tab_write("\n")
+        tab_write("samples %.d\n" % scene.pov.media_samples)
+        tab_write("}\n")
+
+
+####################################################################################################
+def export_rainbows(rainbows, file, scene, global_matrix, write_matrix, tab_write):
+    """write all POV rainbows primitives to exported file """
+    for ob in rainbows:
+        povdataname = ob.data.name  # enough? XXX not used nor matrix fn?
+        angle = degrees(ob.data.spot_size / 2.5)  # radians in blender (2
+        width = ob.data.spot_blend * 10
+        distance = ob.data.shadow_buffer_clip_start
+        # eps=0.0000001
+        # angle = br/(cr+eps) * 10 #eps is small epsilon variable to avoid dividing by zero
+        # width = ob.dimensions[2] #now let's say width of rainbow is the actual proxy height
+        # formerly:
+        # cz-bz # let's say width of the rainbow is height of the cone (interfacing choice
+
+        # v(A,B) rotates vector A about origin by vector B.
+        # and avoid a 0 length vector by adding 1
+
+        # file.write("#declare %s_Target= vrotate(<%.6g,%.6g,%.6g>,<%.4g,%.4g,%.4g>);\n" % \
+        # (povdataname, -(ob.location.x+0.1), -(ob.location.y+0.1), -(ob.location.z+0.1),
+        # ob.rotation_euler.x, ob.rotation_euler.y, ob.rotation_euler.z))
+
+        direction = (  # XXX currently not used (replaced by track to?)
+            ob.location.x,
+            ob.location.y,
+            ob.location.z,
+        )  # not taking matrix into account
+        rmatrix = global_matrix @ ob.matrix_world
+
+        # ob.rotation_euler.to_matrix().to_4x4() * mathutils.Vector((0,0,1))
+        # XXX Is result of the below offset by 90 degrees?
+        up = ob.matrix_world.to_3x3()[1].xyz  # * global_matrix
+
+        # XXX TO CHANGE:
+        # formerly:
+        # tab_write("#declare %s = rainbow {\n"%povdataname)
+
+        # clumsy for now but remove the rainbow from instancing
+        # system because not an object. use lamps later instead of meshes
+
+        # del data_ref[dataname]
+        tab_write("rainbow {\n")
+
+        tab_write("angle %.4f\n" % angle)
+        tab_write("width %.4f\n" % width)
+        tab_write("distance %.4f\n" % distance)
+        tab_write("arc_angle %.4f\n" % ob.pov.arc_angle)
+        tab_write("falloff_angle %.4f\n" % ob.pov.falloff_angle)
+        tab_write("direction <%.4f,%.4f,%.4f>\n" % rmatrix.translation[:])
+        tab_write("up <%.4f,%.4f,%.4f>\n" % (up[0], up[1], up[2]))
+        tab_write("color_map {\n")
+        tab_write("[0.000  color srgbt<1.0, 0.5, 1.0, 1.0>]\n")
+        tab_write("[0.130  color srgbt<0.5, 0.5, 1.0, 0.9>]\n")
+        tab_write("[0.298  color srgbt<0.2, 0.2, 1.0, 0.7>]\n")
+        tab_write("[0.412  color srgbt<0.2, 1.0, 1.0, 0.4>]\n")
+        tab_write("[0.526  color srgbt<0.2, 1.0, 0.2, 0.4>]\n")
+        tab_write("[0.640  color srgbt<1.0, 1.0, 0.2, 0.4>]\n")
+        tab_write("[0.754  color srgbt<1.0, 0.5, 0.2, 0.6>]\n")
+        tab_write("[0.900  color srgbt<1.0, 0.2, 0.2, 0.7>]\n")
+        tab_write("[1.000  color srgbt<1.0, 0.2, 0.2, 1.0>]\n")
+        tab_write("}\n")
+
+        pov_mat_name = "Default_texture"
+        # tab_write("texture {%s}\n"%pov_mat_name)
+        write_object_modifiers(scene, ob, file)
+        # tab_write("rotate x*90\n")
+        # matrix = global_matrix @ ob.matrix_world
+        # write_matrix(matrix)
+        tab_write("}\n")
+        # continue #Don't render proxy mesh, skip to next object
+
+
+def export_smoke(file, smoke_obj_name, smoke_path, comments, global_matrix, write_matrix):
+    """export Blender smoke type fluids to pov media using df3 library"""
+
+    flowtype = -1  # XXX todo: not used yet? should trigger emissive for fire type
+    depsgraph = bpy.context.evaluated_depsgraph_get()
+    smoke_obj = bpy.data.objects[smoke_obj_name].evaluated_get(depsgraph)
+    domain = None
+    smoke_modifier = None
+    # Search smoke domain target for smoke modifiers
+    for mod in smoke_obj.modifiers:
+        if mod.type == 'FLUID':
+            if mod.fluid_type == 'FLOW':
+                if mod.flow_settings.flow_type == 'BOTH':
+                    flowtype = 2
+                else:
+                    if mod.flow_settings.smoke_flow_type == 'SMOKE':
+                        flowtype = 0
+                    else:
+                        if mod.flow_settings.smoke_flow_type == 'FIRE':
+                            flowtype = 1
+
+            if mod.fluid_type == 'DOMAIN':
+                domain = smoke_obj
+                smoke_modifier = mod
+
+    eps = 0.000001  # XXX not used currently. restore from corner case ... zero div?
+    if domain is not None:
+        mod_set = smoke_modifier.domain_settings
+        channeldata = []
+        for v in mod_set.density_grid:
+            channeldata.append(v.real)
+            print(v.real)
+        ## Usage en voxel texture:
+        # channeldata = []
+        # if channel == 'density':
+        # for v in mod_set.density_grid:
+        # channeldata.append(v.real)
+
+        # if channel == 'fire':
+        # for v in mod_set.flame_grid:
+        # channeldata.append(v.real)
+
+        resolution = mod_set.resolution_max
+        big_res = []
+        big_res.append(mod_set.domain_resolution[0])
+        big_res.append(mod_set.domain_resolution[1])
+        big_res.append(mod_set.domain_resolution[2])
+
+        if mod_set.use_noise:
+            big_res[0] = big_res[0] * (mod_set.noise_scale + 1)
+            big_res[1] = big_res[1] * (mod_set.noise_scale + 1)
+            big_res[2] = big_res[2] * (mod_set.noise_scale + 1)
+        # else:
+        # p = []
+        ##gather smoke domain settings
+        # BBox = domain.bound_box
+        # p.append([BBox[0][0], BBox[0][1], BBox[0][2]])
+        # p.append([BBox[6][0], BBox[6][1], BBox[6][2]])
+        # mod_set = smoke_modifier.domain_settings
+        # resolution = mod_set.resolution_max
+        # smokecache = mod_set.point_cache
+        # ret = read_cache(smokecache, mod_set.use_noise, mod_set.noise_scale + 1, flowtype)
+        # res_x = ret[0]
+        # res_y = ret[1]
+        # res_z = ret[2]
+        # density = ret[3]
+        # fire = ret[4]
+
+        # if res_x * res_y * res_z > 0:
+        ##new cache format
+        # big_res = []
+        # big_res.append(res_x)
+        # big_res.append(res_y)
+        # big_res.append(res_z)
+        # else:
+        # max = domain.dimensions[0]
+        # if (max - domain.dimensions[1]) < -eps:
+        # max = domain.dimensions[1]
+
+        # if (max - domain.dimensions[2]) < -eps:
+        # max = domain.dimensions[2]
+
+        # big_res = [int(round(resolution * domain.dimensions[0] / max, 0)),
+        # int(round(resolution * domain.dimensions[1] / max, 0)),
+        # int(round(resolution * domain.dimensions[2] / max, 0))]
+
+        # if mod_set.use_noise:
+        # big_res = [big_res[0] * (mod_set.noise_scale + 1),
+        # big_res[1] * (mod_set.noise_scale + 1),
+        # big_res[2] * (mod_set.noise_scale + 1)]
+
+        # if channel == 'density':
+        # channeldata = density
+
+        # if channel == 'fire':
+        # channeldata = fire
+
+        # sc_fr = '%s/%s/%s/%05d' % (
+        # efutil.export_path,
+        # efutil.scene_filename(),
+        # bpy.context.scene.name,
+        # bpy.context.scene.frame_current
+        # )
+        #               if not os.path.exists( sc_fr ):
+        #                   os.makedirs(sc_fr)
+        #
+        #               smoke_filename = '%s.smoke' % bpy.path.clean_name(domain.name)
+        #               smoke_path = '/'.join([sc_fr, smoke_filename])
+        #
+        #               with open(smoke_path, 'wb') as smoke_file:
+        #                   # Binary densitygrid file format
+        #                   #
+        #                   # File header
+        #                   smoke_file.write(b'SMOKE')        #magic number
+        #                   smoke_file.write(struct.pack('<I', big_res[0]))
+        #                   smoke_file.write(struct.pack('<I', big_res[1]))
+        #                   smoke_file.write(struct.pack('<I', big_res[2]))
+        # Density data
+        #                   smoke_file.write(struct.pack('<%df'%len(channeldata), *channeldata))
+        #
+        #               LuxLog('Binary SMOKE file written: %s' % (smoke_path))
+
+        # return big_res[0], big_res[1], big_res[2], channeldata
+
+        mydf3 = df3_library.df3(big_res[0], big_res[1], big_res[2])
+        sim_sizeX, sim_sizeY, sim_sizeZ = mydf3.size()
+        for x in range(sim_sizeX):
+            for y in range(sim_sizeY):
+                for z in range(sim_sizeZ):
+                    mydf3.set(x, y, z, channeldata[((z * sim_sizeY + y) * sim_sizeX + x)])
+
+        mydf3.exportDF3(smoke_path)
+        print('Binary smoke.df3 file written in preview directory')
+        if comments:
+            file.write("\n//--Smoke--\n\n")
+
+        # Note: We start with a default unit cube.
+        #       This is mandatory to read correctly df3 data - otherwise we could just directly use bbox
+        #       coordinates from the start, and avoid scale/translate operations at the end...
+        file.write("box{<0,0,0>, <1,1,1>\n")
+        file.write("    pigment{ rgbt 1 }\n")
+        file.write("    hollow\n")
+        file.write("    interior{ //---------------------\n")
+        file.write("        media{ method 3\n")
+        file.write("               emission <1,1,1>*1\n")  # 0>1 for dark smoke to white vapour
+        file.write("               scattering{ 1, // Type\n")
+        file.write("                  <1,1,1>*0.1\n")
+        file.write("                } // end scattering\n")
+        file.write("                density{density_file df3 \"%s\"\n" % (smoke_path))
+        file.write("                        color_map {\n")
+        file.write("                        [0.00 rgb 0]\n")
+        file.write("                        [0.05 rgb 0]\n")
+        file.write("                        [0.20 rgb 0.2]\n")
+        file.write("                        [0.30 rgb 0.6]\n")
+        file.write("                        [0.40 rgb 1]\n")
+        file.write("                        [1.00 rgb 1]\n")
+        file.write("                       } // end color_map\n")
+        file.write("               } // end of density\n")
+        file.write("               samples %i // higher = more precise\n" % resolution)
+        file.write("         } // end of media --------------------------\n")
+        file.write("    } // end of interior\n")
+
+        # START OF TRANSFORMATIONS
+
+        # Size to consider here are bbox dimensions (i.e. still in object space, *before* applying
+        # loc/rot/scale and other transformations (like parent stuff), aka matrix_world).
+        bbox = smoke_obj.bound_box
+        dim = [
+            abs(bbox[6][0] - bbox[0][0]),
+            abs(bbox[6][1] - bbox[0][1]),
+            abs(bbox[6][2] - bbox[0][2]),
+        ]
+
+        # We scale our cube to get its final size and shapes but still in *object* space (same as Blender's bbox).
+        file.write("scale<%.6g,%.6g,%.6g>\n" % (dim[0], dim[1], dim[2]))
+
+        # We offset our cube such that (0,0,0) coordinate matches Blender's object center.
+        file.write("translate<%.6g,%.6g,%.6g>\n" % (bbox[0][0], bbox[0][1], bbox[0][2]))
+
+        # We apply object's transformations to get final loc/rot/size in world space!
+        # Note: we could combine the two previous transformations with this matrix directly...
+        write_matrix(global_matrix @ smoke_obj.matrix_world)
+
+        # END OF TRANSFORMATIONS
+
+        file.write("}\n")
+
+        # file.write("               interpolate 1\n")
+        # file.write("               frequency 0\n")
+        # file.write("   }\n")
+        # file.write("}\n")
+
+
+classes = ()
+
+
+def register():
+    for cls in classes:
+        register_class(cls)
+
+
+def unregister():
+    for cls in classes:
+        unregister_class(cls)
diff --git a/render_povray/scenography_gui.py b/render_povray/scenography_gui.py
new file mode 100755
index 000000000..307d8f41a
--- /dev/null
+++ b/render_povray/scenography_gui.py
@@ -0,0 +1,800 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+"""User interface to camera frame, optics distortions, and environment
+
+with world, sky, atmospheric effects such as rainbows or smoke """
+
+import bpy
+from bpy.utils import register_class, unregister_class
+from bpy.types import Operator, Menu, Panel
+from bl_operators.presets import AddPresetBase
+
+from bl_ui import properties_data_camera
+
+for member in dir(properties_data_camera):
+    subclass = getattr(properties_data_camera, member)
+    try:
+        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+    except BaseException as e:
+        print(e.__doc__)
+        print('An exception occurred: {}'.format(e))
+        pass
+del properties_data_camera
+
+# ##################################
+# # Use only a subset of the world panels
+# from bl_ui import properties_world
+
+# # TORECREATE##DEPRECATED#properties_world.WORLD_PT_preview.COMPAT_ENGINES.add('POVRAY_RENDER')
+# properties_world.WORLD_PT_context_world.COMPAT_ENGINES.add('POVRAY_RENDER')
+# # TORECREATE##DEPRECATED#properties_world.WORLD_PT_world.COMPAT_ENGINES.add('POVRAY_RENDER')
+# del properties_world
+
+##################################
+# Physics Main wrapping every class 'as is'
+from bl_ui import properties_physics_common
+
+for member in dir(properties_physics_common):
+    subclass = getattr(properties_physics_common, member)
+    try:
+        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+    except BaseException as e:
+        print(e.__doc__)
+        print('An exception occurred: {}'.format(e))
+        pass
+del properties_physics_common
+
+# Physics Rigid Bodies wrapping every class 'as is'
+from bl_ui import properties_physics_rigidbody
+
+for member in dir(properties_physics_rigidbody):
+    subclass = getattr(properties_physics_rigidbody, member)
+    try:
+        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+    except BaseException as e:
+        print(e.__doc__)
+        print('An exception occurred: {}'.format(e))
+        pass
+del properties_physics_rigidbody
+
+# Physics Rigid Body Constraint wrapping every class 'as is'
+from bl_ui import properties_physics_rigidbody_constraint
+
+for member in dir(properties_physics_rigidbody_constraint):
+    subclass = getattr(properties_physics_rigidbody_constraint, member)
+    try:
+        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+    except BaseException as e:
+        print(e.__doc__)
+        print('An exception occurred: {}'.format(e))
+        pass
+del properties_physics_rigidbody_constraint
+
+# Physics Smoke and fluids wrapping every class 'as is'
+from bl_ui import properties_physics_fluid
+
+for member in dir(properties_physics_fluid):
+    subclass = getattr(properties_physics_fluid, member)
+    try:
+        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+    except BaseException as e:
+        print(e.__doc__)
+        print('An exception occurred: {}'.format(e))
+        pass
+del properties_physics_fluid
+
+# Physics softbody wrapping every class 'as is'
+from bl_ui import properties_physics_softbody
+
+for member in dir(properties_physics_softbody):
+    subclass = getattr(properties_physics_softbody, member)
+    try:
+        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+    except BaseException as e:
+        print(e.__doc__)
+        print('An exception occurred: {}'.format(e))
+        pass
+del properties_physics_softbody
+
+# Physics Field wrapping every class 'as is'
+from bl_ui import properties_physics_field
+
+for member in dir(properties_physics_field):
+    subclass = getattr(properties_physics_field, member)
+    try:
+        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+    except BaseException as e:
+        print(e.__doc__)
+        print('An exception occurred: {}'.format(e))
+        pass
+del properties_physics_field
+
+# Physics Cloth wrapping every class 'as is'
+from bl_ui import properties_physics_cloth
+
+for member in dir(properties_physics_cloth):
+    subclass = getattr(properties_physics_cloth, member)
+    try:
+        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+    except BaseException as e:
+        print(e.__doc__)
+        print('An exception occurred: {}'.format(e))
+        pass
+del properties_physics_cloth
+
+# Physics Dynamic Paint wrapping every class 'as is'
+from bl_ui import properties_physics_dynamicpaint
+
+for member in dir(properties_physics_dynamicpaint):
+    subclass = getattr(properties_physics_dynamicpaint, member)
+    try:
+        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+    except BaseException as e:
+        print(e.__doc__)
+        print('An exception occurred: {}'.format(e))
+        pass
+del properties_physics_dynamicpaint
+
+from bl_ui import properties_particle
+
+for member in dir(properties_particle):  # add all "particle" panels from blender
+    subclass = getattr(properties_particle, member)
+    try:
+        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+    except BaseException as e:
+        print(e.__doc__)
+        print('An exception occurred: {}'.format(e))
+        pass
+del properties_particle
+
+
+class CameraDataButtonsPanel:
+    """Use this class to define buttons from the camera data tab of
+    properties window."""
+
+    bl_space_type = 'PROPERTIES'
+    bl_region_type = 'WINDOW'
+    bl_context = "data"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        cam = context.camera
+        rd = context.scene.render
+        return cam and (rd.engine in cls.COMPAT_ENGINES)
+
+
+class WorldButtonsPanel:
+    """Use this class to define buttons from the world tab of
+    properties window."""
+
+    bl_space_type = 'PROPERTIES'
+    bl_region_type = 'WINDOW'
+    bl_context = "world"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        wld = context.world
+        rd = context.scene.render
+        return wld and (rd.engine in cls.COMPAT_ENGINES)
+
+
+###############################################################################
+# Camera Settings
+###############################################################################
+class CAMERA_PT_POV_cam_dof(CameraDataButtonsPanel, Panel):
+    """Use this class for camera depth of field focal blur buttons."""
+
+    bl_label = "POV Aperture"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+    bl_parent_id = "DATA_PT_camera_dof_aperture"
+    bl_options = {'HIDE_HEADER'}
+    # def draw_header(self, context):
+    # cam = context.camera
+
+    # self.layout.prop(cam.pov, "dof_enable", text="")
+
+    def draw(self, context):
+        layout = self.layout
+
+        cam = context.camera
+
+        layout.active = cam.dof.use_dof
+        layout.use_property_split = True  # Active single-column layout
+
+        flow = layout.grid_flow(
+            row_major=True, columns=0, even_columns=True, even_rows=False, align=False
+        )
+
+        col = flow.column()
+        col.label(text="F-Stop value will export as")
+        col.label(text="POV aperture : " + "%.3f" % (1 / cam.dof.aperture_fstop * 1000))
+
+        col = flow.column()
+        col.prop(cam.pov, "dof_samples_min")
+        col.prop(cam.pov, "dof_samples_max")
+        col.prop(cam.pov, "dof_variance")
+        col.prop(cam.pov, "dof_confidence")
+
+
+class CAMERA_PT_POV_cam_nor(CameraDataButtonsPanel, Panel):
+    """Use this class for camera normal perturbation buttons."""
+
+    bl_label = "POV Perturbation"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def draw_header(self, context):
+        cam = context.camera
+
+        self.layout.prop(cam.pov, "normal_enable", text="")
+
+    def draw(self, context):
+        layout = self.layout
+
+        cam = context.camera
+
+        layout.active = cam.pov.normal_enable
+
+        layout.prop(cam.pov, "normal_patterns")
+        layout.prop(cam.pov, "cam_normal")
+        layout.prop(cam.pov, "turbulence")
+        layout.prop(cam.pov, "scale")
+
+
+class CAMERA_PT_POV_replacement_text(CameraDataButtonsPanel, Panel):
+    """Use this class for camera text replacement field."""
+
+    bl_label = "Custom POV Code"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def draw(self, context):
+        layout = self.layout
+
+        cam = context.camera
+
+        col = layout.column()
+        col.label(text="Replace properties with:")
+        col.prop(cam.pov, "replacement_text", text="")
+
+
+###############################################################################
+# World background and sky sphere Settings
+###############################################################################
+
+
+class WORLD_PT_POV_world(WorldButtonsPanel, Panel):
+    """Use this class to define pov world buttons"""
+
+    bl_label = "World"
+
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def draw(self, context):
+        layout = self.layout
+
+        world = context.world.pov
+
+        row = layout.row(align=True)
+        row.menu(WORLD_MT_POV_presets.__name__, text=WORLD_MT_POV_presets.bl_label)
+        row.operator(WORLD_OT_POV_add_preset.bl_idname, text="", icon='ADD')
+        row.operator(WORLD_OT_POV_add_preset.bl_idname, text="", icon='REMOVE').remove_active = True
+
+        row = layout.row()
+        row.prop(world, "use_sky_paper")
+        row.prop(world, "use_sky_blend")
+        row.prop(world, "use_sky_real")
+
+        row = layout.row()
+        row.column().prop(world, "horizon_color")
+        col = row.column()
+        col.prop(world, "zenith_color")
+        col.active = world.use_sky_blend
+        row.column().prop(world, "ambient_color")
+
+        # row = layout.row()
+        # row.prop(world, "exposure") #Re-implement later as a light multiplier
+        # row.prop(world, "color_range")
+
+
+class WORLD_PT_POV_mist(WorldButtonsPanel, Panel):
+    """Use this class to define pov mist buttons."""
+
+    bl_label = "Mist"
+    bl_options = {'DEFAULT_CLOSED'}
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def draw_header(self, context):
+        world = context.world
+
+        self.layout.prop(world.mist_settings, "use_mist", text="")
+
+    def draw(self, context):
+        layout = self.layout
+
+        world = context.world
+
+        layout.active = world.mist_settings.use_mist
+
+        split = layout.split()
+
+        col = split.column()
+        col.prop(world.mist_settings, "intensity")
+        col.prop(world.mist_settings, "start")
+
+        col = split.column()
+        col.prop(world.mist_settings, "depth")
+        col.prop(world.mist_settings, "height")
+
+        layout.prop(world.mist_settings, "falloff")
+
+
+class WORLD_MT_POV_presets(Menu):
+    """Apply world preset to all concerned properties"""
+
+    bl_label = "World Presets"
+    preset_subdir = "pov/world"
+    preset_operator = "script.execute_preset"
+    draw = bpy.types.Menu.draw_preset
+
+
+class WORLD_OT_POV_add_preset(AddPresetBase, Operator):
+    """Add a World Preset recording current values"""
+
+    bl_idname = "object.world_preset_add"
+    bl_label = "Add World Preset"
+    preset_menu = "WORLD_MT_POV_presets"
+
+    # variable used for all preset values
+    preset_defines = ["scene = bpy.context.scene"]
+
+    # properties to store in the preset
+    preset_values = [
+        "scene.world.use_sky_blend",
+        "scene.world.horizon_color",
+        "scene.world.zenith_color",
+        "scene.world.ambient_color",
+        "scene.world.mist_settings.use_mist",
+        "scene.world.mist_settings.intensity",
+        "scene.world.mist_settings.depth",
+        "scene.world.mist_settings.start",
+        "scene.pov.media_enable",
+        "scene.pov.media_scattering_type",
+        "scene.pov.media_samples",
+        "scene.pov.media_diffusion_scale",
+        "scene.pov.media_diffusion_color",
+        "scene.pov.media_absorption_scale",
+        "scene.pov.media_absorption_color",
+        "scene.pov.media_eccentricity",
+    ]
+
+    # where to store the preset
+    preset_subdir = "pov/world"
+
+
+class RENDER_PT_POV_media(WorldButtonsPanel, Panel):
+    """Use this class to define a pov global atmospheric media buttons."""
+
+    bl_label = "Atmosphere Media"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def draw_header(self, context):
+        scene = context.scene
+
+        self.layout.prop(scene.pov, "media_enable", text="")
+
+    def draw(self, context):
+        layout = self.layout
+
+        scene = context.scene
+
+        layout.active = scene.pov.media_enable
+
+        col = layout.column()
+        col.prop(scene.pov, "media_scattering_type", text="")
+        col = layout.column()
+        col.prop(scene.pov, "media_samples", text="Samples")
+        split = layout.split()
+        col = split.column(align=True)
+        col.label(text="Scattering:")
+        col.prop(scene.pov, "media_diffusion_scale")
+        col.prop(scene.pov, "media_diffusion_color", text="")
+        col = split.column(align=True)
+        col.label(text="Absorption:")
+        col.prop(scene.pov, "media_absorption_scale")
+        col.prop(scene.pov, "media_absorption_color", text="")
+        if scene.pov.media_scattering_type == '5':
+            col = layout.column()
+            col.prop(scene.pov, "media_eccentricity", text="Eccentricity")
+
+
+###############################################################################
+# Lights settings
+###############################################################################
+
+################################################################################
+# from bl_ui import properties_data_light
+# for member in dir(properties_data_light):
+# subclass = getattr(properties_data_light, member)
+# try:
+# subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+# except BaseException as e:
+# print e.__doc__
+# print('An exception occurred: {}'.format(e))
+# pass
+# del properties_data_light
+#########################LIGHTS################################
+
+from bl_ui import properties_data_light
+
+# # These panels are kept
+# properties_data_light.DATA_PT_custom_props_light.COMPAT_ENGINES.add('POVRAY_RENDER')
+# properties_data_light.DATA_PT_context_light.COMPAT_ENGINES.add('POVRAY_RENDER')
+
+## make some native panels contextual to some object variable
+## by recreating custom panels inheriting their properties
+class PovLightButtonsPanel(properties_data_light.DataButtonsPanel):
+    """Use this class to define buttons from the light data tab of
+    properties window."""
+
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+    POV_OBJECT_TYPES = {'RAINBOW'}
+
+    @classmethod
+    def poll(cls, context):
+        obj = context.object
+        # We use our parent class poll func too, avoids to re-define too much things...
+        return (
+            super(PovLightButtonsPanel, cls).poll(context)
+            and obj
+            and obj.pov.object_as not in cls.POV_OBJECT_TYPES
+        )
+
+
+# We cannot inherit from RNA classes (like e.g. properties_data_mesh.DATA_PT_vertex_groups).
+# Complex py/bpy/rna interactions (with metaclass and all) simply do not allow it to work.
+# So we simply have to explicitly copy here the interesting bits. ;)
+from bl_ui import properties_data_light
+
+# for member in dir(properties_data_light):
+# subclass = getattr(properties_data_light, member)
+# try:
+# subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+# except BaseException as e:
+# print(e.__doc__)
+# print('An exception occurred: {}'.format(e))
+# pass
+
+# Now only These panels are kept
+properties_data_light.DATA_PT_custom_props_light.COMPAT_ENGINES.add('POVRAY_RENDER')
+properties_data_light.DATA_PT_context_light.COMPAT_ENGINES.add('POVRAY_RENDER')
+
+
+class LIGHT_PT_POV_preview(PovLightButtonsPanel, Panel):
+    # XXX Needs update and docstring
+    bl_label = properties_data_light.DATA_PT_preview.bl_label
+
+    draw = properties_data_light.DATA_PT_preview.draw
+
+
+class LIGHT_PT_POV_light(PovLightButtonsPanel, Panel):
+    """UI panel to main pov light parameters"""
+
+    # bl_label = properties_data_light.DATA_PT_light.bl_label
+
+    # draw = properties_data_light.DATA_PT_light.draw
+    # class DATA_PT_POV_light(DataButtonsPanel, Panel):
+    bl_label = "Light"
+    # COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def draw(self, context):
+        layout = self.layout
+
+        light = context.light
+
+        layout.row().prop(light, "type", expand=True)
+
+        split = layout.split()
+
+        col = split.column()
+        sub = col.column()
+        sub.prop(light, "color", text="")
+        sub.prop(light, "energy")
+
+        if light.type in {'POINT', 'SPOT'}:
+            sub.label(text="Falloff:")
+            sub.prop(light, "falloff_type", text="")
+            sub.prop(light, "distance")
+
+            if light.falloff_type == 'LINEAR_QUADRATIC_WEIGHTED':
+                col.label(text="Attenuation Factors:")
+                sub = col.column(align=True)
+                sub.prop(light, "linear_attenuation", slider=True, text="Linear")
+                sub.prop(light, "quadratic_attenuation", slider=True, text="Quadratic")
+
+            elif light.falloff_type == 'INVERSE_COEFFICIENTS':
+                col.label(text="Inverse Coefficients:")
+                sub = col.column(align=True)
+                sub.prop(light, "constant_coefficient", text="Constant")
+                sub.prop(light, "linear_coefficient", text="Linear")
+                sub.prop(light, "quadratic_coefficient", text="Quadratic")
+
+        if light.type == 'AREA':
+            col.prop(light, "distance")
+
+        # restore later as interface to POV light groups ?
+        # col = split.column()
+        # col.prop(light, "use_own_layer", text="This Layer Only")
+
+
+class LIGHT_MT_POV_presets(Menu):
+    """Use this class to define preset menu for pov lights."""
+
+    bl_label = "Lamp Presets"
+    preset_subdir = "pov/light"
+    preset_operator = "script.execute_preset"
+    draw = bpy.types.Menu.draw_preset
+
+
+class LIGHT_OT_POV_add_preset(AddPresetBase, Operator):
+    """Operator to add a Light Preset"""
+
+    bl_idname = "object.light_preset_add"
+    bl_label = "Add Light Preset"
+    preset_menu = "LIGHT_MT_POV_presets"
+
+    # variable used for all preset values
+    preset_defines = ["lightdata = bpy.context.object.data"]
+
+    # properties to store in the preset
+    preset_values = ["lightdata.type", "lightdata.color"]
+
+    # where to store the preset
+    preset_subdir = "pov/light"
+
+
+# Draw into the existing light panel
+def light_panel_func(self, context):
+    """Menu to browse and add light preset"""
+    layout = self.layout
+
+    row = layout.row(align=True)
+    row.menu(LIGHT_MT_POV_presets.__name__, text=LIGHT_MT_POV_presets.bl_label)
+    row.operator(LIGHT_OT_POV_add_preset.bl_idname, text="", icon='ADD')
+    row.operator(LIGHT_OT_POV_add_preset.bl_idname, text="", icon='REMOVE').remove_active = True
+
+
+'''#TORECREATE##DEPRECATED#
+class LIGHT_PT_POV_sunsky(PovLightButtonsPanel, Panel):
+    bl_label = properties_data_light.DATA_PT_sunsky.bl_label
+
+    @classmethod
+    def poll(cls, context):
+        lamp = context.light
+        engine = context.scene.render.engine
+        return (lamp and lamp.type == 'SUN') and (engine in cls.COMPAT_ENGINES)
+
+    draw = properties_data_light.DATA_PT_sunsky.draw
+
+'''
+
+
+class LIGHT_PT_POV_shadow(PovLightButtonsPanel, Panel):
+    # Todo : update and docstring
+    bl_label = "Shadow"
+
+    @classmethod
+    def poll(cls, context):
+        light = context.light
+        engine = context.scene.render.engine
+        return light and (engine in cls.COMPAT_ENGINES)
+
+    def draw(self, context):
+        layout = self.layout
+
+        light = context.light
+
+        layout.row().prop(light.pov, "shadow_method", expand=True)
+
+        split = layout.split()
+        col = split.column()
+
+        col.prop(light.pov, "use_halo")
+        sub = col.column(align=True)
+        sub.active = light.pov.use_halo
+        sub.prop(light.pov, "halo_intensity", text="Intensity")
+
+        if light.pov.shadow_method == 'NOSHADOW' and light.type == 'AREA':
+            split = layout.split()
+
+            col = split.column()
+            col.label(text="Form factor sampling:")
+
+            sub = col.row(align=True)
+
+            if light.shape == 'SQUARE':
+                sub.prop(light, "shadow_ray_samples_x", text="Samples")
+            elif light.shape == 'RECTANGLE':
+                sub.prop(light.pov, "shadow_ray_samples_x", text="Samples X")
+                sub.prop(light.pov, "shadow_ray_samples_y", text="Samples Y")
+
+        if light.pov.shadow_method != 'NOSHADOW':
+            split = layout.split()
+
+            col = split.column()
+            col.prop(light, "shadow_color", text="")
+
+            # col = split.column()
+            # col.prop(light.pov, "use_shadow_layer", text="This Layer Only")
+            # col.prop(light.pov, "use_only_shadow")
+
+        if light.pov.shadow_method == 'RAY_SHADOW':
+            split = layout.split()
+
+            col = split.column()
+            col.label(text="Sampling:")
+
+            if light.type in {'POINT', 'SUN', 'SPOT'}:
+                sub = col.row()
+
+                sub.prop(light.pov, "shadow_ray_samples_x", text="Samples")
+                # any equivalent in pov?
+                # sub.prop(light, "shadow_soft_size", text="Soft Size")
+
+            elif light.type == 'AREA':
+                sub = col.row(align=True)
+
+                if light.shape == 'SQUARE':
+                    sub.prop(light.pov, "shadow_ray_samples_x", text="Samples")
+                elif light.shape == 'RECTANGLE':
+                    sub.prop(light.pov, "shadow_ray_samples_x", text="Samples X")
+                    sub.prop(light.pov, "shadow_ray_samples_y", text="Samples Y")
+
+
+class LIGHT_PT_POV_area(PovLightButtonsPanel, Panel):
+    """Area light UI panel"""
+
+    bl_label = properties_data_light.DATA_PT_area.bl_label
+    bl_parent_id = "LIGHT_PT_POV_light"
+    bl_context = "data"
+
+    @classmethod
+    def poll(cls, context):
+        lamp = context.light
+        engine = context.scene.render.engine
+        return (lamp and lamp.type == 'AREA') and (engine in cls.COMPAT_ENGINES)
+
+    draw = properties_data_light.DATA_PT_area.draw
+
+
+class LIGHT_PT_POV_spot(PovLightButtonsPanel, Panel):
+    bl_label = properties_data_light.DATA_PT_spot.bl_label
+    bl_parent_id = "LIGHT_PT_POV_light"
+    bl_context = "data"
+
+    @classmethod
+    def poll(cls, context):
+        lamp = context.light
+        engine = context.scene.render.engine
+        return (lamp and lamp.type == 'SPOT') and (engine in cls.COMPAT_ENGINES)
+
+    draw = properties_data_light.DATA_PT_spot.draw
+
+
+class LIGHT_PT_POV_falloff_curve(PovLightButtonsPanel, Panel):
+    bl_label = properties_data_light.DATA_PT_falloff_curve.bl_label
+    bl_options = properties_data_light.DATA_PT_falloff_curve.bl_options
+
+    @classmethod
+    def poll(cls, context):
+        lamp = context.light
+        engine = context.scene.render.engine
+
+        return (
+            lamp and lamp.type in {'POINT', 'SPOT'} and lamp.falloff_type == 'CUSTOM_CURVE'
+        ) and (engine in cls.COMPAT_ENGINES)
+
+    draw = properties_data_light.DATA_PT_falloff_curve.draw
+
+
+class OBJECT_PT_POV_rainbow(PovLightButtonsPanel, Panel):
+    """Use this class to define buttons from the rainbow panel of
+    properties window. inheriting lamp buttons panel class"""
+
+    bl_label = "POV-Ray Rainbow"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+    # bl_options = {'HIDE_HEADER'}
+    @classmethod
+    def poll(cls, context):
+        engine = context.scene.render.engine
+        obj = context.object
+        return obj and obj.pov.object_as == 'RAINBOW' and (engine in cls.COMPAT_ENGINES)
+
+    def draw(self, context):
+        layout = self.layout
+
+        obj = context.object
+
+        col = layout.column()
+
+        if obj.pov.object_as == 'RAINBOW':
+            if not obj.pov.unlock_parameters:
+                col.prop(
+                    obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
+                )
+                col.label(text="Rainbow projection angle: " + str(obj.data.spot_size))
+                col.label(text="Rainbow width: " + str(obj.data.spot_blend))
+                col.label(text="Rainbow distance: " + str(obj.data.shadow_buffer_clip_start))
+                col.label(text="Rainbow arc angle: " + str(obj.pov.arc_angle))
+                col.label(text="Rainbow falloff angle: " + str(obj.pov.falloff_angle))
+
+            else:
+                col.prop(
+                    obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
+                )
+                col.label(text="3D view proxy may get out of synch")
+                col.active = obj.pov.unlock_parameters
+
+                layout.operator("pov.cone_update", text="Update", icon="MESH_CONE")
+
+                # col.label(text="Parameters:")
+                col.prop(obj.data, "spot_size", text="Rainbow Projection Angle")
+                col.prop(obj.data, "spot_blend", text="Rainbow width")
+                col.prop(obj.data, "shadow_buffer_clip_start", text="Visibility distance")
+                col.prop(obj.pov, "arc_angle")
+                col.prop(obj.pov, "falloff_angle")
+
+
+del properties_data_light
+
+
+classes = (
+    WORLD_PT_POV_world,
+    WORLD_MT_POV_presets,
+    WORLD_OT_POV_add_preset,
+    WORLD_PT_POV_mist,
+    RENDER_PT_POV_media,
+    LIGHT_PT_POV_preview,
+    LIGHT_PT_POV_light,
+    LIGHT_PT_POV_shadow,
+    LIGHT_PT_POV_spot,
+    LIGHT_PT_POV_area,
+    LIGHT_MT_POV_presets,
+    LIGHT_OT_POV_add_preset,
+    OBJECT_PT_POV_rainbow,
+    CAMERA_PT_POV_cam_dof,
+    CAMERA_PT_POV_cam_nor,
+    CAMERA_PT_POV_replacement_text,
+)
+
+
+def register():
+
+    for cls in classes:
+        register_class(cls)
+    bpy.types.LIGHT_PT_POV_light.prepend(light_panel_func)
+
+
+def unregister():
+
+    for cls in reversed(classes):
+        unregister_class(cls)
+    bpy.types.LIGHT_PT_POV_light.remove(light_panel_func)
diff --git a/render_povray/scenography_properties.py b/render_povray/scenography_properties.py
new file mode 100755
index 000000000..b45922eb2
--- /dev/null
+++ b/render_povray/scenography_properties.py
@@ -0,0 +1,514 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+"""Declare stage set and surrounding (camera, lights, environment) properties controllable in UI"""
+import bpy
+from bpy.utils import register_class, unregister_class
+from bpy.types import PropertyGroup
+from bpy.props import (
+    FloatVectorProperty,
+    StringProperty,
+    BoolProperty,
+    IntProperty,
+    FloatProperty,
+    EnumProperty,
+    PointerProperty,
+    CollectionProperty,
+)
+
+from .shading_properties import (
+    active_texture_name_from_uilist,
+    active_texture_name_from_search,
+    brush_texture_update,
+)
+
+###############################################################################
+# Camera POV properties.
+###############################################################################
+class RenderPovSettingsCamera(PropertyGroup):
+
+    """Declare camera properties controllable in UI and translated to POV."""
+
+    # DOF Toggle
+    dof_enable: BoolProperty(
+        name="Depth Of Field", description="Enable POV Depth Of Field ", default=False
+    )
+
+    # Aperture (Intensity of the Blur)
+    dof_aperture: FloatProperty(
+        name="Aperture",
+        description="Similar to a real camera's aperture effect over focal blur (though not "
+        "in physical units and independent of focal length). "
+        "Increase to get more blur",
+        min=0.01,
+        max=1.00,
+        default=0.50,
+    )
+
+    # Aperture adaptive sampling
+    dof_samples_min: IntProperty(
+        name="Samples Min",
+        description="Minimum number of rays to use for each pixel",
+        min=1,
+        max=128,
+        default=3,
+    )
+
+    dof_samples_max: IntProperty(
+        name="Samples Max",
+        description="Maximum number of rays to use for each pixel",
+        min=1,
+        max=128,
+        default=9,
+    )
+
+    dof_variance: IntProperty(
+        name="Variance",
+        description="Minimum threshold (fractional value) for adaptive DOF sampling (up "
+        "increases quality and render time). The value for the variance should "
+        "be in the range of the smallest displayable color difference",
+        min=1,
+        max=100000,
+        soft_max=10000,
+        default=8192,
+    )
+
+    dof_confidence: FloatProperty(
+        name="Confidence",
+        description="Probability to reach the real color value. Larger confidence values "
+        "will lead to more samples, slower traces and better images",
+        min=0.01,
+        max=0.99,
+        default=0.20,
+    )
+
+    normal_enable: BoolProperty(name="Perturbated Camera", default=False)
+
+    cam_normal: FloatProperty(name="Normal Strength", min=0.0, max=1.0, default=0.001)
+
+    normal_patterns: EnumProperty(
+        name="Pattern",
+        description="",
+        items=(
+            ("agate", "Agate", ""),
+            ("boxed", "Boxed", ""),
+            ("bumps", "Bumps", ""),
+            ("cells", "Cells", ""),
+            ("crackle", "Crackle", ""),
+            ("dents", "Dents", ""),
+            ("granite", "Granite", ""),
+            ("leopard", "Leopard", ""),
+            ("marble", "Marble", ""),
+            ("onion", "Onion", ""),
+            ("pavement", "Pavement", ""),
+            ("planar", "Planar", ""),
+            ("quilted", "Quilted", ""),
+            ("ripples", "Ripples", ""),
+            ("radial", "Radial", ""),
+            ("spherical", "Spherical", ""),
+            ("spiral1", "Spiral1", ""),
+            ("spiral2", "Spiral2", ""),
+            ("spotted", "Spotted", ""),
+            ("square", "Square", ""),
+            ("tiling", "Tiling", ""),
+            ("waves", "Waves", ""),
+            ("wood", "Wood", ""),
+            ("wrinkles", "Wrinkles", ""),
+        ),
+        default="agate",
+    )
+
+    turbulence: FloatProperty(name="Turbulence", min=0.0, max=100.0, default=0.1)
+
+    scale: FloatProperty(name="Scale", min=0.0, default=1.0)
+
+    ##################################CustomPOV Code############################
+    # Only DUMMIES below for now:
+    replacement_text: StringProperty(
+        name="Texts in blend file",
+        description="Type the declared name in custom POV code or an external .inc "
+        "it points at. camera {} expected",
+        default="",
+    )
+
+
+###############################################################################
+# Light POV properties.
+###############################################################################
+class RenderPovSettingsLight(PropertyGroup):
+
+    """Declare light properties controllable in UI and translated to POV."""
+
+    # former Space properties from  removed Blender Internal
+    use_limited_texture_context: BoolProperty(
+        name="",
+        description="Use the limited version of texture user (for ‘old shading’ mode)",
+        default=True,
+    )
+
+    texture_context: EnumProperty(
+        name="Texture context",
+        description="Type of texture data to display and edit",
+        items=(
+            ("MATERIAL", "", "Show material textures", "MATERIAL", 0),  # "Show material textures"
+            ("WORLD", "", "Show world textures", "WORLD", 1),  # "Show world textures"
+            ("LAMP", "", "Show lamp textures", "LIGHT", 2),  # "Show lamp textures"
+            (
+                "PARTICLES",
+                "",
+                "Show particles textures",
+                "PARTICLES",
+                3,
+            ),  # "Show particles textures"
+            (
+                "LINESTYLE",
+                "",
+                "Show linestyle textures",
+                "LINE_DATA",
+                4,
+            ),  # "Show linestyle textures"
+            (
+                "OTHER",
+                "",
+                "Show other data textures",
+                "TEXTURE_DATA",
+                5,
+            ),  # "Show other data textures"
+        ),
+        default="MATERIAL",
+    )
+
+    shadow_method: EnumProperty(
+        name="Shadow",
+        description="",
+        items=(
+            ("NOSHADOW", "No Shadow", "No Shadow"),
+            ("RAY_SHADOW", "Ray Shadow", "Ray Shadow, Use ray tracing for shadow"),
+        ),
+        default="RAY_SHADOW",
+    )
+
+    active_texture_index: IntProperty(name="Index for texture_slots", default=0)
+
+    use_halo: BoolProperty(
+        name="Halo", description="Render spotlight with a volumetric halo", default=False
+    )
+
+    halo_intensity: FloatProperty(
+        name="Halo intensity",
+        description="Brightness of the spotlight halo cone",
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+    )
+
+    shadow_ray_samples_x: IntProperty(
+        name="Number of samples taken extra (samples x samples)", min=1, soft_max=64, default=1
+    )
+
+    shadow_ray_samples_y: IntProperty(
+        name="Number of samples taken extra (samples x samples)", min=1, soft_max=64, default=1
+    )
+
+    shadow_ray_sample_method: EnumProperty(
+        name="",
+        description="Method for generating shadow samples: Adaptive QMC is fastest,"
+        "Constant QMC is less noisy but slower",
+        items=(
+            ("ADAPTIVE_QMC", "", "Halton samples distribution", "", 0),
+            ("CONSTANT_QMC", "", "QMC samples distribution", "", 1),
+            (
+                "CONSTANT_JITTERED",
+                "",
+                "Uses POV jitter keyword",
+                "",
+                2,
+            ),  # "Show other data textures"
+        ),
+        default="CONSTANT_JITTERED",
+    )
+
+    use_jitter: BoolProperty(
+        name="Jitter",
+        description="Use noise for sampling (Constant Jittered sampling)",
+        default=False,
+    )
+
+
+###############################################################################
+# World POV properties.
+###############################################################################
+class RenderPovSettingsWorld(PropertyGroup):
+
+    """Declare world properties controllable in UI and translated to POV."""
+
+    # former Space properties from  removed Blender Internal
+    use_limited_texture_context: BoolProperty(
+        name="",
+        description="Use the limited version of texture user (for ‘old shading’ mode)",
+        default=True,
+    )
+
+    texture_context: EnumProperty(
+        name="Texture context",
+        description="Type of texture data to display and edit",
+        items=(
+            ("MATERIAL", "", "Show material textures", "MATERIAL", 0),  # "Show material textures"
+            ("WORLD", "", "Show world textures", "WORLD", 1),  # "Show world textures"
+            ("LIGHT", "", "Show lamp textures", "LIGHT", 2),  # "Show lamp textures"
+            (
+                "PARTICLES",
+                "",
+                "Show particles textures",
+                "PARTICLES",
+                3,
+            ),  # "Show particles textures"
+            (
+                "LINESTYLE",
+                "",
+                "Show linestyle textures",
+                "LINE_DATA",
+                4,
+            ),  # "Show linestyle textures"
+            (
+                "OTHER",
+                "",
+                "Show other data textures",
+                "TEXTURE_DATA",
+                5,
+            ),  # "Show other data textures"
+        ),
+        default="MATERIAL",
+    )
+
+    use_sky_blend: BoolProperty(
+        name="Blend Sky",
+        description="Render background with natural progression from horizon to zenith",
+        default=False,
+    )
+
+    use_sky_paper: BoolProperty(
+        name="Paper Sky", description="Flatten blend or texture coordinates", default=False
+    )
+
+    use_sky_real: BoolProperty(
+        name="Real Sky",
+        description="Render background with a real horizon, relative to the camera angle",
+        default=False,
+    )
+
+    horizon_color: FloatVectorProperty(
+        name="Horizon Color",
+        description="Color at the horizon",
+        precision=4,
+        step=0.01,
+        min=0,
+        soft_max=1,
+        default=(0.050876, 0.050876, 0.050876),
+        options={"ANIMATABLE"},
+        subtype="COLOR",
+    )
+
+    zenith_color: FloatVectorProperty(
+        name="Zenith Color",
+        description="Color at the zenith",
+        precision=4,
+        step=0.01,
+        min=0,
+        soft_max=1,
+        default=(0.0, 0.0, 0.0),
+        options={"ANIMATABLE"},
+        subtype="COLOR",
+    )
+
+    ambient_color: FloatVectorProperty(
+        name="Ambient Color",
+        description="Ambient color of the world",
+        precision=4,
+        step=0.01,
+        min=0,
+        soft_max=1,
+        default=(0.0, 0.0, 0.0),
+        options={"ANIMATABLE"},
+        subtype="COLOR",
+    )
+    active_texture_index: IntProperty(
+        name="Index for texture_slots", default=0, update=brush_texture_update
+    )
+
+
+class WorldTextureSlot(PropertyGroup):
+    """Declare world texture slot level properties for UI and translated to POV."""
+
+    bl_idname = ("pov_texture_slots",)
+    bl_description = ("Texture_slots from Blender-2.79",)
+
+    # Adding a "real" texture datablock as property is not possible
+    # (or at least not easy through a dynamically populated EnumProperty).
+    # That's why we'll use a prop_search() UILayout function in texturing_gui.py.
+    # So we'll assign the name of the needed texture datablock to the below StringProperty.
+    texture: StringProperty(update=active_texture_name_from_uilist)
+    # and use another temporary StringProperty to change the linked data
+    texture_search: StringProperty(
+        name="", update=active_texture_name_from_search, description="Browse Texture to be linked"
+    )
+
+    blend_factor: FloatProperty(
+        name="Blend",
+        description="Amount texture affects color progression of the " "background",
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+    )
+
+    horizon_factor: FloatProperty(
+        name="Horizon",
+        description="Amount texture affects color of the horizon",
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+    )
+
+    object: StringProperty(
+        name="Object",
+        description="Object to use for mapping with Object texture coordinates",
+        default="",
+    )
+
+    offset: FloatVectorProperty(
+        name="Offset",
+        description=("Fine tune of the texture mapping X, Y and Z locations "),
+        precision=4,
+        step=0.1,
+        soft_min=-100.0,
+        soft_max=100.0,
+        default=(0.0, 0.0, 0.0),
+        options={"ANIMATABLE"},
+        subtype="TRANSLATION",
+    )
+
+    scale: FloatVectorProperty(
+        name="Size",
+        subtype="XYZ",
+        size=3,
+        description="Set scaling for the texture’s X, Y and Z sizes ",
+        precision=4,
+        step=0.1,
+        soft_min=-100.0,
+        soft_max=100.0,
+        default=(1.0, 1.0, 1.0),
+        options={"ANIMATABLE"},
+    )
+
+    texture_coords: EnumProperty(
+        name="Coordinates",
+        description="Texture coordinates used to map the texture onto the background",
+        items=(
+            ("VIEW", "View", "Use view vector for the texture coordinates"),
+            (
+                "GLOBAL",
+                "Global",
+                "Use global coordinates for the texture coordinates (interior mist)",
+            ),
+            (
+                "ANGMAP",
+                "AngMap",
+                "Use 360 degree angular coordinates, e.g. for spherical light probes",
+            ),
+            ("SPHERE", "Sphere", "For 360 degree panorama sky, spherical mapped, only top half"),
+            ("EQUIRECT", "Equirectangular", "For 360 degree panorama sky, equirectangular mapping"),
+            ("TUBE", "Tube", "For 360 degree panorama sky, cylindrical mapped, only top half"),
+            ("OBJECT", "Object", "Use linked object’s coordinates for texture coordinates"),
+        ),
+        default="VIEW",
+    )
+
+    use_map_blend: BoolProperty(
+        name="Blend Map", description="Affect the color progression of the background", default=True
+    )
+
+    use_map_horizon: BoolProperty(
+        name="Horizon Map", description="Affect the color of the horizon", default=False
+    )
+
+    use_map_zenith_down: BoolProperty(
+        name="", description="Affect the color of the zenith below", default=False
+    )
+
+    use_map_zenith_up: BoolProperty(
+        name="Zenith Up Map", description="Affect the color of the zenith above", default=False
+    )
+
+    zenith_down_factor: FloatProperty(
+        name="Zenith Down",
+        description="Amount texture affects color of the zenith below",
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+    )
+
+    zenith_up_factor: FloatProperty(
+        name="Zenith Up",
+        description="Amount texture affects color of the zenith above",
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+    )
+
+
+"""
+# class WORLD_TEXTURE_SLOTS_UL_layerlist(bpy.types.UIList):
+#    texture_slots:
+
+class WorldTextureSlots(bpy.props.PropertyGroup):
+    index = bpy.prop.PropertyInt(name='index')
+    # foo  = random prop
+
+bpy.types.World.texture_slots = bpy.props.CollectionProperty(type=PropertyGroup)
+
+for i in range(18):  # length of world texture slots
+    world.texture_slots.add()
+"""
+
+classes = (
+    RenderPovSettingsCamera,
+    RenderPovSettingsLight,
+    RenderPovSettingsWorld,
+    WorldTextureSlot,
+)
+
+
+def register():
+    for cls in classes:
+        register_class(cls)
+
+    bpy.types.Camera.pov = PointerProperty(type=RenderPovSettingsCamera)
+    bpy.types.Light.pov = PointerProperty(type=RenderPovSettingsLight)
+    bpy.types.World.pov = PointerProperty(type=RenderPovSettingsWorld)
+    bpy.types.World.pov_texture_slots = CollectionProperty(type=WorldTextureSlot)
+
+
+def unregister():
+    del bpy.types.Camera.pov
+    del bpy.types.Light.pov
+    del bpy.types.World.pov
+    del bpy.types.World.pov_texture_slots
+
+    for cls in reversed(classes):
+        unregister_class(cls)
diff --git a/render_povray/scripting.py b/render_povray/scripting.py
new file mode 100755
index 000000000..02ca6444b
--- /dev/null
+++ b/render_povray/scripting.py
@@ -0,0 +1,529 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# #**** END GPL LICENSE BLOCK #****
+
+# <pep8 compliant>
+
+"""Support POV Scene Description Language snippets or full includes: import,
+
+load, create or edit"""
+
+import bpy
+from bpy.props import StringProperty, BoolProperty, CollectionProperty
+from bpy_extras.io_utils import ImportHelper
+
+from mathutils import Vector
+from math import pi
+
+
+def export_custom_code(file):
+    """write all POV user defined custom code to exported file """
+    # Write CurrentAnimation Frame for use in Custom POV Code
+    file.write("#declare CURFRAMENUM = %d;\n" % bpy.context.scene.frame_current)
+    # Change path and uncomment to add an animated include file by hand:
+    file.write("//#include \"/home/user/directory/animation_include_file.inc\"\n")
+    for txt in bpy.data.texts:
+        if txt.pov.custom_code == 'both':
+            # Why are the newlines needed?
+            file.write("\n")
+            file.write(txt.as_string())
+            file.write("\n")
+
+
+#############################IMPORT
+
+
+class ImportPOV(bpy.types.Operator, ImportHelper):
+    """Load Povray files"""
+
+    bl_idname = "import_scene.pov"
+    bl_label = "POV-Ray files (.pov/.inc)"
+    bl_options = {'PRESET', 'UNDO'}
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    # -----------
+    # File props.
+    files: CollectionProperty(
+        type=bpy.types.OperatorFileListElement, options={'HIDDEN', 'SKIP_SAVE'}
+    )
+    directory: StringProperty(maxlen=1024, subtype='FILE_PATH', options={'HIDDEN', 'SKIP_SAVE'})
+
+    filename_ext = {".pov", ".inc"}
+    filter_glob: StringProperty(default="*.pov;*.inc", options={'HIDDEN'})
+
+    import_at_cur: BoolProperty(
+        name="Import at Cursor Location", description="Ignore Object Matrix", default=False
+    )
+
+    def execute(self, context):
+        from mathutils import Matrix
+
+        verts = []
+        faces = []
+        materials = []
+        blend_mats = []  ##############
+        pov_mats = []  ##############
+        colors = []
+        mat_names = []
+        lenverts = None
+        lenfaces = None
+        suffix = -1
+        name = 'Mesh2_%s' % suffix
+        name_search = False
+        verts_search = False
+        faces_search = False
+        plane_search = False
+        box_search = False
+        cylinder_search = False
+        sphere_search = False
+        cone_search = False
+        tex_search = False  ##################
+        cache = []
+        matrixes = {}
+        write_matrix = False
+        index = None
+        value = None
+        # file_pov = bpy.path.abspath(self.filepath) #was used for single files
+
+        def mat_search(cache):
+            r = g = b = 0.5
+            f = t = 0
+            color = None
+
+            for item, value in enumerate(cache):
+
+                if value == 'texture':
+                    pass
+
+                if value == 'pigment':
+
+                    if cache[item + 2] in {'rgb', 'srgb'}:
+                        pass
+
+                    elif cache[item + 2] in {'rgbf', 'srgbf'}:
+                        pass
+
+                    elif cache[item + 2] in {'rgbt', 'srgbt'}:
+                        try:
+                            r, g, b, t = (
+                                float(cache[item + 3]),
+                                float(cache[item + 4]),
+                                float(cache[item + 5]),
+                                float(cache[item + 6]),
+                            )
+                        except BaseException as e:
+                            print(e.__doc__)
+                            print('An exception occurred: {}'.format(e))
+                            r = g = b = t = float(cache[item + 2])
+                        color = (r, g, b, t)
+
+                    elif cache[item + 2] in {'rgbft', 'srgbft'}:
+                        pass
+
+                    else:
+                        pass
+
+            if colors == [] or (colors != [] and color not in colors):
+                colors.append(color)
+                name = ob.name + "_mat"
+                mat_names.append(name)
+                mat = bpy.data.materials.new(name)
+                mat.diffuse_color = (r, g, b)
+                mat.alpha = 1 - t
+                if mat.alpha != 1:
+                    mat.use_transparency = True
+                ob.data.materials.append(mat)
+
+            else:
+                for i, value in enumerate(colors):
+                    if color == value:
+                        ob.data.materials.append(bpy.data.materials[mat_names[i]])
+
+        for file in self.files:
+            print("Importing file: " + file.name)
+            file_pov = self.directory + file.name
+            for line in open(file_pov):
+                string = line.replace("{", " ")
+                string = string.replace("}", " ")
+                string = string.replace("<", " ")
+                string = string.replace(">", " ")
+                string = string.replace(",", " ")
+                lw = string.split()
+                # lenwords = len(lw) # Not used... why written?
+                if lw:
+                    if lw[0] == "object":
+                        write_matrix = True
+                    if write_matrix:
+                        if lw[0] not in {"object", "matrix"}:
+                            index = lw[0]
+                        if lw[0] in {"matrix"}:
+                            value = [
+                                float(lw[1]),
+                                float(lw[2]),
+                                float(lw[3]),
+                                float(lw[4]),
+                                float(lw[5]),
+                                float(lw[6]),
+                                float(lw[7]),
+                                float(lw[8]),
+                                float(lw[9]),
+                                float(lw[10]),
+                                float(lw[11]),
+                                float(lw[12]),
+                            ]
+                            matrixes[index] = value
+                            write_matrix = False
+            for line in open(file_pov):
+                S = line.replace("{", " { ")
+                S = S.replace("}", " } ")
+                S = S.replace(",", " ")
+                S = S.replace("<", "")
+                S = S.replace(">", " ")
+                S = S.replace("=", " = ")
+                S = S.replace(";", " ; ")
+                S = S.split()
+                # lenS = len(S) # Not used... why written?
+                for i, word in enumerate(S):
+                    ##################Primitives Import##################
+                    if word == 'cone':
+                        cone_search = True
+                        name_search = False
+                    if cone_search:
+                        cache.append(word)
+                        if cache[-1] == '}':
+                            try:
+                                x0 = float(cache[2])
+                                y0 = float(cache[3])
+                                z0 = float(cache[4])
+                                r0 = float(cache[5])
+                                x1 = float(cache[6])
+                                y1 = float(cache[7])
+                                z1 = float(cache[8])
+                                r1 = float(cache[9])
+                                # Y is height in most pov files, not z
+                                bpy.ops.pov.cone_add(base=r0, cap=r1, height=(y1 - y0))
+                                ob = context.object
+                                ob.location = (x0, y0, z0)
+                                # ob.scale = (r,r,r)
+                                mat_search(cache)
+                            except ValueError:
+                                pass
+                            cache = []
+                            cone_search = False
+                    if word == 'plane':
+                        plane_search = True
+                        name_search = False
+                    if plane_search:
+                        cache.append(word)
+                        if cache[-1] == '}':
+                            try:
+                                bpy.ops.pov.addplane()
+                                ob = context.object
+                                mat_search(cache)
+                            except ValueError:
+                                pass
+                            cache = []
+                            plane_search = False
+                    if word == 'box':
+                        box_search = True
+                        name_search = False
+                    if box_search:
+                        cache.append(word)
+                        if cache[-1] == '}':
+                            try:
+                                x0 = float(cache[2])
+                                y0 = float(cache[3])
+                                z0 = float(cache[4])
+                                x1 = float(cache[5])
+                                y1 = float(cache[6])
+                                z1 = float(cache[7])
+                                # imported_corner_1=(x0, y0, z0)
+                                # imported_corner_2 =(x1, y1, z1)
+                                center = ((x0 + x1) / 2, (y0 + y1) / 2, (z0 + z1) / 2)
+                                bpy.ops.pov.addbox()
+                                ob = context.object
+                                ob.location = center
+                                mat_search(cache)
+
+                            except ValueError:
+                                pass
+                            cache = []
+                            box_search = False
+                    if word == 'cylinder':
+                        cylinder_search = True
+                        name_search = False
+                    if cylinder_search:
+                        cache.append(word)
+                        if cache[-1] == '}':
+                            try:
+                                x0 = float(cache[2])
+                                y0 = float(cache[3])
+                                z0 = float(cache[4])
+                                x1 = float(cache[5])
+                                y1 = float(cache[6])
+                                z1 = float(cache[7])
+                                imported_cyl_loc = (x0, y0, z0)
+                                imported_cyl_loc_cap = (x1, y1, z1)
+
+                                r = float(cache[8])
+
+                                vec = Vector(imported_cyl_loc_cap) - Vector(imported_cyl_loc)
+                                depth = vec.length
+                                rot = Vector((0, 0, 1)).rotation_difference(
+                                    vec
+                                )  # Rotation from Z axis.
+                                trans = rot @ Vector(  # XXX Not used, why written?
+                                    (0, 0, depth / 2)
+                                )  # Such that origin is at center of the base of the cylinder.
+                                # center = ((x0 + x1)/2,(y0 + y1)/2,(z0 + z1)/2)
+                                scale_z = sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2 + (z1 - z0) ** 2) / 2
+                                bpy.ops.pov.addcylinder(
+                                    R=r,
+                                    imported_cyl_loc=imported_cyl_loc,
+                                    imported_cyl_loc_cap=imported_cyl_loc_cap,
+                                )
+                                ob = context.object
+                                ob.location = (x0, y0, z0)
+                                ob.rotation_euler = rot.to_euler()
+                                ob.scale = (1, 1, scale_z)
+
+                                # scale data rather than obj?
+                                # bpy.ops.object.mode_set(mode='EDIT')
+                                # bpy.ops.mesh.reveal()
+                                # bpy.ops.mesh.select_all(action='SELECT')
+                                # bpy.ops.transform.resize(value=(1,1,scale_z), orient_type='LOCAL')
+                                # bpy.ops.mesh.hide(unselected=False)
+                                # bpy.ops.object.mode_set(mode='OBJECT')
+
+                                mat_search(cache)
+
+                            except ValueError:
+                                pass
+                            cache = []
+                            cylinder_search = False
+                    if word == 'sphere':
+                        sphere_search = True
+                        name_search = False
+                    if sphere_search:
+                        cache.append(word)
+                        if cache[-1] == '}':
+                            x = y = z = r = 0
+                            try:
+                                x = float(cache[2])
+                                y = float(cache[3])
+                                z = float(cache[4])
+                                r = float(cache[5])
+
+                            except ValueError:
+                                pass
+                            except:
+                                x = y = z = float(cache[2])
+                                r = float(cache[3])
+                            bpy.ops.pov.addsphere(R=r, imported_loc=(x, y, z))
+                            ob = context.object
+                            ob.location = (x, y, z)
+                            ob.scale = (r, r, r)
+                            mat_search(cache)
+                            cache = []
+                            sphere_search = False
+                    ##################End Primitives Import##################
+                    if word == '#declare':
+                        name_search = True
+                    if name_search:
+                        cache.append(word)
+                        if word == 'mesh2':
+                            name_search = False
+                            if cache[-2] == '=':
+                                name = cache[-3]
+                            else:
+                                suffix += 1
+                            cache = []
+                        if word in {'texture', ';'}:
+                            name_search = False
+                            cache = []
+                    if word == 'vertex_vectors':
+                        verts_search = True
+                    if verts_search:
+                        cache.append(word)
+                        if word == '}':
+                            verts_search = False
+                            lenverts = cache[2]
+                            cache.pop()
+                            cache.pop(0)
+                            cache.pop(0)
+                            cache.pop(0)
+                            for j in range(int(lenverts)):
+                                x = j * 3
+                                y = (j * 3) + 1
+                                z = (j * 3) + 2
+                                verts.append((float(cache[x]), float(cache[y]), float(cache[z])))
+                            cache = []
+                    # if word == 'face_indices':
+                    # faces_search = True
+                    if word == 'texture_list':  ########
+                        tex_search = True  #######
+                    if tex_search:  #########
+                        if (
+                            word not in {'texture_list', 'texture', '{', '}', 'face_indices'}
+                            and not word.isdigit()
+                        ):  ##############
+                            pov_mats.append(word)  #################
+                    if word == 'face_indices':
+                        tex_search = False  ################
+                        faces_search = True
+                    if faces_search:
+                        cache.append(word)
+                        if word == '}':
+                            faces_search = False
+                            lenfaces = cache[2]
+                            cache.pop()
+                            cache.pop(0)
+                            cache.pop(0)
+                            cache.pop(0)
+                            lf = int(lenfaces)
+                            var = int(len(cache) / lf)
+                            for k in range(lf):
+                                if var == 3:
+                                    v0 = k * 3
+                                    v1 = k * 3 + 1
+                                    v2 = k * 3 + 2
+                                    faces.append((int(cache[v0]), int(cache[v1]), int(cache[v2])))
+                                if var == 4:
+                                    v0 = k * 4
+                                    v1 = k * 4 + 1
+                                    v2 = k * 4 + 2
+                                    m = k * 4 + 3
+                                    materials.append((int(cache[m])))
+                                    faces.append((int(cache[v0]), int(cache[v1]), int(cache[v2])))
+                                if var == 6:
+                                    v0 = k * 6
+                                    v1 = k * 6 + 1
+                                    v2 = k * 6 + 2
+                                    m0 = k * 6 + 3
+                                    m1 = k * 6 + 4
+                                    m2 = k * 6 + 5
+                                    materials.append(
+                                        (int(cache[m0]), int(cache[m1]), int(cache[m2]))
+                                    )
+                                    faces.append((int(cache[v0]), int(cache[v1]), int(cache[v2])))
+                            # mesh = pov_define_mesh(None, verts, [], faces, name, hide_geometry=False)
+                            # ob = object_utils.object_data_add(context, mesh, operator=None)
+
+                            me = bpy.data.meshes.new(name)  ########
+                            ob = bpy.data.objects.new(name, me)  ##########
+                            bpy.context.collection.objects.link(ob)  #########
+                            me.from_pydata(verts, [], faces)  ############
+
+                            for mat in bpy.data.materials:  ##############
+                                blend_mats.append(mat.name)  #############
+                            for m_name in pov_mats:  #####################
+                                if m_name not in blend_mats:  ###########
+                                    povMat = bpy.data.materials.new(m_name)  #################
+                                    mat_search(cache)
+                                ob.data.materials.append(
+                                    bpy.data.materials[m_name]
+                                )  ###################
+                            if materials:  ##################
+                                for l, val in enumerate(materials):  ####################
+                                    try:  ###################
+                                        ob.data.polygons[
+                                            l
+                                        ].material_index = val  ####################
+                                    except TypeError:  ###################
+                                        ob.data.polygons[l].material_index = int(
+                                            val[0]
+                                        )  ##################
+
+                            blend_mats = []  #########################
+                            pov_mats = []  #########################
+                            materials = []  #########################
+                            cache = []
+                            name_search = True
+                            if name in matrixes and not self.import_at_cur:
+                                global_matrix = Matrix.Rotation(pi / 2.0, 4, 'X')
+                                ob = bpy.context.object
+                                matrix = ob.matrix_world
+                                v = matrixes[name]
+                                matrix[0][0] = v[0]
+                                matrix[1][0] = v[1]
+                                matrix[2][0] = v[2]
+                                matrix[0][1] = v[3]
+                                matrix[1][1] = v[4]
+                                matrix[2][1] = v[5]
+                                matrix[0][2] = v[6]
+                                matrix[1][2] = v[7]
+                                matrix[2][2] = v[8]
+                                matrix[0][3] = v[9]
+                                matrix[1][3] = v[10]
+                                matrix[2][3] = v[11]
+                                matrix = global_matrix * ob.matrix_world
+                                ob.matrix_world = matrix
+                            verts = []
+                            faces = []
+
+                    # if word == 'pigment':
+                    # try:
+                    # #all indices have been incremented once to fit a bad test file
+                    # r,g,b,t = float(S[2]),float(S[3]),float(S[4]),float(S[5])
+                    # color = (r,g,b,t)
+
+                    # except IndexError:
+                    # #all indices have been incremented once to fit alternate test file
+                    # r,g,b,t = float(S[3]),float(S[4]),float(S[5]),float(S[6])
+                    # color = (r,g,b,t)
+                    # except UnboundLocalError:
+                    # # In case no transmit is specified ? put it to 0
+                    # r,g,b,t = float(S[2]),float(S[3]),float(S[4],0)
+                    # color = (r,g,b,t)
+
+                    # except ValueError:
+                    # color = (0.8,0.8,0.8,0)
+                    # pass
+
+                    # if colors == [] or (colors != [] and color not in colors):
+                    # colors.append(color)
+                    # name = ob.name+"_mat"
+                    # mat_names.append(name)
+                    # mat = bpy.data.materials.new(name)
+                    # mat.diffuse_color = (r,g,b)
+                    # mat.alpha = 1-t
+                    # if mat.alpha != 1:
+                    # mat.use_transparency=True
+                    # ob.data.materials.append(mat)
+                    # print (colors)
+                    # else:
+                    # for m in range(len(colors)):
+                    # if color == colors[m]:
+                    # ob.data.materials.append(bpy.data.materials[mat_names[m]])
+
+        ##To keep Avogadro Camera angle:
+        # for obj in bpy.context.view_layer.objects:
+        # if obj.type == "CAMERA":
+        # track = obj.constraints.new(type = "TRACK_TO")
+        # track.target = ob
+        # track.track_axis ="TRACK_NEGATIVE_Z"
+        # track.up_axis = "UP_Y"
+        # obj.location = (0,0,0)
+        return {'FINISHED'}
+
+
+def register():
+    bpy.utils.register_class(ImportPOV)
+
+
+def unregister():
+    bpy.utils.unregister_class(ImportPOV)
diff --git a/render_povray/scripting_gui.py b/render_povray/scripting_gui.py
new file mode 100755
index 000000000..99006af15
--- /dev/null
+++ b/render_povray/scripting_gui.py
@@ -0,0 +1,268 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+"""User interface to POV Scene Description Language snippets or full includes:
+
+import, load, create or edit """
+
+import bpy
+from bpy.utils import register_class, unregister_class
+from bpy.types import Operator, Menu, Panel
+from sys import platform  # really import here, as in ui.py and in render.py?
+import os  # really import here and in render.py?
+from os.path import isfile
+
+
+def locate_docpath():
+    """POV can be installed with some include files.
+
+    Get their path as defined in user preferences or registry keys for
+    the user to be able to invoke them."""
+
+    addon_prefs = bpy.context.preferences.addons[__package__].preferences
+    # Use the system preference if its set.
+    pov_documents = addon_prefs.docpath_povray
+    if pov_documents:
+        if os.path.exists(pov_documents):
+            return pov_documents
+        # Implicit else, as here return was still not triggered:
+        print(
+            "User Preferences path to povray documents %r NOT FOUND, checking $PATH" % pov_documents
+        )
+
+    # Windows Only
+    if platform.startswith('win'):
+        import winreg
+
+        try:
+            win_reg_key = winreg.OpenKey(
+                winreg.HKEY_CURRENT_USER, "Software\\POV-Ray\\v3.7\\Windows"
+            )
+            win_docpath = winreg.QueryValueEx(win_reg_key, "DocPath")[0]
+            pov_documents = os.path.join(win_docpath, "Insert Menu")
+            if os.path.exists(pov_documents):
+                return pov_documents
+        except FileNotFoundError:
+            return ""
+    # search the path all os's
+    pov_documents_default = "include"
+
+    os_path_ls = os.getenv("PATH").split(':') + [""]
+
+    for dir_name in os_path_ls:
+        pov_documents = os.path.join(dir_name, pov_documents_default)
+        if os.path.exists(pov_documents):
+            return pov_documents
+    return ""
+
+
+################################################################################
+class TextButtonsPanel:
+    """Use this class to define buttons from the side tab of
+    text window."""
+
+    bl_space_type = 'TEXT_EDITOR'
+    bl_region_type = 'UI'
+    bl_label = "POV-Ray"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        text = context.space_data
+        rd = context.scene.render
+        return text and (rd.engine in cls.COMPAT_ENGINES)
+
+
+###############################################################################
+# Text Povray Settings
+###############################################################################
+
+
+class TEXT_OT_POV_insert(Operator):
+    """Use this class to create blender text editor operator to insert pov snippets like other pov IDEs"""
+
+    bl_idname = "text.povray_insert"
+    bl_label = "Insert"
+
+    filepath: bpy.props.StringProperty(name="Filepath", subtype='FILE_PATH')
+
+    @classmethod
+    def poll(cls, context):
+        text = context.space_data.text
+        return context.area.type == 'TEXT_EDITOR' and text is not None
+        # return bpy.ops.text.insert.poll() this Bpy op has no poll()
+
+    def execute(self, context):
+        if self.filepath and isfile(self.filepath):
+            file = open(self.filepath, "r")
+            bpy.ops.text.insert(text=file.read())
+
+            # places the cursor at the end without scrolling -.-
+            # context.space_data.text.write(file.read())
+            file.close()
+        return {'FINISHED'}
+
+
+def validinsert(ext):
+    """Since preview images could be in same folder, filter only insertable text"""
+    return ext in {".txt", ".inc", ".pov"}
+
+
+class TEXT_MT_POV_insert(Menu):
+    """Use this class to create a menu launcher in text editor for the TEXT_OT_POV_insert operator ."""
+
+    bl_label = "Insert"
+    bl_idname = "TEXT_MT_POV_insert"
+
+    def draw(self, context):
+        pov_documents = locate_docpath()
+        prop = self.layout.operator("wm.path_open", text="Open folder", icon='FILE_FOLDER')
+        prop.filepath = pov_documents
+        self.layout.separator()
+
+        pov_insert_items_list = []
+        for root, dirs, files in os.walk(pov_documents):  # todo: structure submenus by dir
+            pov_insert_items_list.append(root)
+        print(pov_insert_items_list)
+        self.path_menu(
+            pov_insert_items_list,
+            "text.povray_insert",
+            # {"internal": True},
+            filter_ext=validinsert,
+        )
+
+
+class TEXT_PT_POV_custom_code(TextButtonsPanel, Panel):
+    """Use this class to create a panel in text editor for the user to decide if he renders text
+
+    only or adds to 3d scene."""
+
+    bl_label = "POV"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def draw(self, context):
+        layout = self.layout
+
+        text = context.space_data.text
+
+        pov_documents = locate_docpath()
+        if not pov_documents:
+            layout.label(text="Please configure ", icon="INFO")
+            layout.label(text="default pov include path ")
+            layout.label(text="in addon preferences")
+            # layout.separator()
+            layout.operator(
+                "preferences.addon_show",
+                text="Go to Render: Persistence of Vision addon",
+                icon="PREFERENCES",
+            ).module = "render_povray"
+
+            # layout.separator()
+        else:
+            # print(pov_documents)
+            layout.menu(TEXT_MT_POV_insert.bl_idname)
+
+        if text:
+            box = layout.box()
+            box.label(text='Source to render:', icon='RENDER_STILL')
+            row = box.row()
+            row.prop(text.pov, "custom_code", expand=True)
+            if text.pov.custom_code in {'3dview'}:
+                box.operator("render.render", icon='OUTLINER_DATA_ARMATURE')
+            if text.pov.custom_code in {'text'}:
+                rtext = bpy.context.space_data.text  # is r a typo ? or why written, not used
+                box.operator("text.run", icon='ARMATURE_DATA')
+            # layout.prop(text.pov, "custom_code")
+            elif text.pov.custom_code in {'both'}:
+                box.operator("render.render", icon='POSE_HLT')
+                layout.label(text="Please specify declared", icon="INFO")
+                layout.label(text="items in properties ")
+                # layout.label(text="")
+                layout.label(text="replacement fields")
+
+
+###############################################
+# Text editor templates from header menu
+
+
+class TEXT_MT_POV_templates(Menu):
+    """Use this class to create a menu for the same pov templates scenes as other pov IDEs."""
+
+    bl_label = "POV"
+
+    # We list templates on file evaluation, we can assume they are static data,
+    # and better avoid running this on every draw call.
+    template_paths = [os.path.join(os.path.dirname(__file__), "templates_pov")]
+
+    def draw(self, context):
+        self.path_menu(self.template_paths, "text.open", props_default={"internal": True})
+
+
+def menu_func_templates(self, context):
+    """Add POV files to the text editor templates menu"""
+    # Do not depend on POV being active renderer here...
+    self.layout.menu("TEXT_MT_POV_templates")
+
+
+###############################################
+# POV Import menu
+class VIEW_MT_POV_import(Menu):
+    """Use this class for the import menu."""
+
+    bl_idname = "POVRAY_MT_import_tools"
+    bl_label = "Import"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.operator_context = 'INVOKE_REGION_WIN'
+        layout.operator("import_scene.pov", icon="FORCE_LENNARDJONES")
+
+
+def menu_func_import(self, context):
+    """Add the import operator to menu"""
+    engine = context.scene.render.engine
+    if engine == 'POVRAY_RENDER':
+        self.layout.operator("import_scene.pov", icon="FORCE_LENNARDJONES")
+
+
+classes = (
+    VIEW_MT_POV_import,
+    TEXT_OT_POV_insert,
+    TEXT_MT_POV_insert,
+    TEXT_PT_POV_custom_code,
+    TEXT_MT_POV_templates,
+)
+
+
+def register():
+
+    for cls in classes:
+        register_class(cls)
+
+    bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
+    bpy.types.TEXT_MT_templates.append(menu_func_templates)
+
+
+def unregister():
+
+    bpy.types.TEXT_MT_templates.remove(menu_func_templates)
+    bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
+
+    for cls in reversed(classes):
+        unregister_class(cls)
diff --git a/render_povray/scripting_properties.py b/render_povray/scripting_properties.py
new file mode 100755
index 000000000..3e743da37
--- /dev/null
+++ b/render_povray/scripting_properties.py
@@ -0,0 +1,57 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+import bpy
+
+"""Declare pov native file syntax properties controllable in UI hooks and text blocks"""
+
+from bpy.utils import register_class, unregister_class
+from bpy.types import PropertyGroup
+from bpy.props import EnumProperty, PointerProperty
+
+###############################################################################
+# Text POV properties.
+###############################################################################
+
+
+class RenderPovSettingsText(PropertyGroup):
+
+    """Declare text properties to use UI as an IDE or render text snippets to POV."""
+
+    custom_code: EnumProperty(
+        name="Custom Code",
+        description="rendered source: Both adds text at the " "top of the exported POV file",
+        items=(("3dview", "View", ""), ("text", "Text", ""), ("both", "Both", "")),
+        default="text",
+    )
+
+
+classes = (RenderPovSettingsText,)
+
+
+def register():
+    for cls in classes:
+        register_class(cls)
+    bpy.types.Text.pov = PointerProperty(type=RenderPovSettingsText)
+
+
+def unregister():
+    del bpy.types.Text.pov
+    for cls in reversed(classes):
+        unregister_class(cls)
diff --git a/render_povray/shading.py b/render_povray/shading.py
old mode 100644
new mode 100755
index a3f907dce..680be99cd
--- a/render_povray/shading.py
+++ b/render_povray/shading.py
@@ -22,248 +22,366 @@
 
 import bpy
 
-def writeMaterial(using_uberpov, DEF_MAT_NAME, scene, tabWrite, safety, comments, uniqueName, materialNames, material):
+
+def write_object_material(material, ob, tab_write):
+    """Translate some object level material from Blender UI (VS data level)
+
+    to POV interior{} syntax and write it to exported file.
+    """
+    # DH - modified some variables to be function local, avoiding RNA write
+    # this should be checked to see if it is functionally correct
+
+    # Commented out: always write IOR to be able to use it for SSS, Fresnel reflections...
+    # if material and material.transparency_method == 'RAYTRACE':
+    if material:
+        # But there can be only one!
+        if material.pov_subsurface_scattering.use:  # SSS IOR get highest priority
+            tab_write("interior {\n")
+            tab_write("ior %.6f\n" % material.pov_subsurface_scattering.ior)
+        # Then the raytrace IOR taken from raytrace transparency properties and used for
+        # reflections if IOR Mirror option is checked.
+        elif material.pov.mirror_use_IOR:
+            tab_write("interior {\n")
+            tab_write("ior %.6f\n" % material.pov_raytrace_transparency.ior)
+        elif material.pov.transparency_method == 'Z_TRANSPARENCY':
+            tab_write("interior {\n")
+            tab_write("ior 1.0\n")
+        else:
+            tab_write("interior {\n")
+            tab_write("ior %.6f\n" % material.pov_raytrace_transparency.ior)
+
+        pov_fake_caustics = False
+        pov_photons_refraction = False
+        pov_photons_reflection = False
+
+        if material.pov.photons_reflection:
+            pov_photons_reflection = True
+        if not material.pov.refraction_caustics:
+            pov_fake_caustics = False
+            pov_photons_refraction = False
+        elif material.pov.refraction_type == "1":
+            pov_fake_caustics = True
+            pov_photons_refraction = False
+        elif material.pov.refraction_type == "2":
+            pov_fake_caustics = False
+            pov_photons_refraction = True
+
+        # If only Raytrace transparency is set, its IOR will be used for refraction, but user
+        # can set up 'un-physical' fresnel reflections in raytrace mirror parameters.
+        # Last, if none of the above is specified, user can set up 'un-physical' fresnel
+        # reflections in raytrace mirror parameters. And pov IOR defaults to 1.
+        if material.pov.caustics_enable:
+            if pov_fake_caustics:
+                tab_write("caustics %.3g\n" % material.pov.fake_caustics_power)
+            if pov_photons_refraction:
+                # Default of 1 means no dispersion
+                tab_write("dispersion %.6f\n" % material.pov.photons_dispersion)
+                tab_write("dispersion_samples %.d\n" % material.pov.photons_dispersion_samples)
+        # TODO
+        # Other interior args
+        if material.pov.use_transparency and material.pov.transparency_method == 'RAYTRACE':
+            # fade_distance
+            # In Blender this value has always been reversed compared to what tooltip says.
+            # 100.001 rather than 100 so that it does not get to 0
+            # which deactivates the feature in POV
+            tab_write(
+                "fade_distance %.3g\n" % (100.001 - material.pov_raytrace_transparency.depth_max)
+            )
+            # fade_power
+            tab_write("fade_power %.3g\n" % material.pov_raytrace_transparency.falloff)
+            # fade_color
+            tab_write("fade_color <%.3g, %.3g, %.3g>\n" % material.pov.interior_fade_color[:])
+
+        # (variable) dispersion_samples (constant count for now)
+        tab_write("}\n")
+        if material.pov.photons_reflection or material.pov.refraction_type == "2":
+            tab_write("photons{")
+            tab_write("target %.3g\n" % ob.pov.spacing_multiplier)
+            if not ob.pov.collect_photons:
+                tab_write("collect off\n")
+            if pov_photons_refraction:
+                tab_write("refraction on\n")
+            if pov_photons_reflection:
+                tab_write("reflection on\n")
+            tab_write("}\n")
+
+
+def write_material(
+    using_uberpov, DEF_MAT_NAME, tab_write, safety, comments, unique_name, material_names, material
+):
     """Translate Blender material POV texture{} block and write to exported file."""
     # Assumes only called once on each material
     if material:
         name_orig = material.name
-        name = materialNames[name_orig] = uniqueName(bpy.path.clean_name(name_orig), materialNames)
+        name = material_names[name_orig] = unique_name(
+            bpy.path.clean_name(name_orig), material_names
+        )
     else:
         name = name_orig = DEF_MAT_NAME
 
-
     if material:
         # If saturation(.s) is not zero, then color is not grey, and has a tint
-        colored_specular_found = ((material.pov.specular_color.s > 0.0) and (material.pov.diffuse_shader != 'MINNAERT'))
+        colored_specular_found = (material.pov.specular_color.s > 0.0) and (
+            material.pov.diffuse_shader != "MINNAERT"
+        )
 
     ##################
-    # Several versions of the finish: Level conditions are variations for specular/Mirror
+    # Several versions of the finish: ref_level_bound conditions are variations for specular/Mirror
     # texture channel map with alternative finish of 0 specular and no mirror reflection.
-    # Level=1 Means No specular nor Mirror reflection
-    # Level=2 Means translation of spec and mir levels for when no map influences them
-    # Level=3 Means Maximum Spec and Mirror
+    # ref_level_bound=1 Means No specular nor Mirror reflection
+    # ref_level_bound=2 Means translation of spec and mir levels for when no map influences them
+    # ref_level_bound=3 Means Maximum Spec and Mirror
 
-    def povHasnoSpecularMaps(Level):
+    def pov_has_no_specular_maps(ref_level_bound):
         """Translate Blender specular map influence to POV finish map trick and write to file."""
-        if Level == 1:
+        if ref_level_bound == 1:
             if comments:
-                tabWrite("//--No specular nor Mirror reflection--\n")
+                tab_write("//--No specular nor Mirror reflection--\n")
             else:
-                tabWrite("\n")
-            tabWrite("#declare %s = finish {\n" % safety(name, Level=1))
+                tab_write("\n")
+            tab_write("#declare %s = finish {\n" % safety(name, ref_level_bound=1))
 
-        elif Level == 2:
+        elif ref_level_bound == 2:
             if comments:
-                tabWrite("//--translation of spec and mir levels for when no map " \
-                           "influences them--\n")
+                tab_write(
+                    "//--translation of spec and mir levels for when no map " "influences them--\n"
+                )
             else:
-                tabWrite("\n")
-            tabWrite("#declare %s = finish {\n" % safety(name, Level=2))
+                tab_write("\n")
+            tab_write("#declare %s = finish {\n" % safety(name, ref_level_bound=2))
 
-        elif Level == 3:
+        elif ref_level_bound == 3:
             if comments:
-                tabWrite("//--Maximum Spec and Mirror--\n")
+                tab_write("//--Maximum Spec and Mirror--\n")
             else:
-                tabWrite("\n")
-            tabWrite("#declare %s = finish {\n" % safety(name, Level=3))
+                tab_write("\n")
+            tab_write("#declare %s = finish {\n" % safety(name, ref_level_bound=3))
         if material:
             # POV-Ray 3.7 now uses two diffuse values respectively for front and back shading
             # (the back diffuse is like blender translucency)
-            frontDiffuse = material.pov.diffuse_intensity
-            backDiffuse = material.pov.translucency
+            front_diffuse = material.pov.diffuse_intensity
+            back_diffuse = material.pov.translucency
 
             if material.pov.conserve_energy:
 
-                #Total should not go above one
-                if (frontDiffuse + backDiffuse) <= 1.0:
+                # Total should not go above one
+                if (front_diffuse + back_diffuse) <= 1.0:
                     pass
-                elif frontDiffuse == backDiffuse:
+                elif front_diffuse == back_diffuse:
                     # Try to respect the user's 'intention' by comparing the two values but
                     # bringing the total back to one.
-                    frontDiffuse = backDiffuse = 0.5
+                    front_diffuse = back_diffuse = 0.5
                 # Let the highest value stay the highest value.
-                elif frontDiffuse > backDiffuse:
+                elif front_diffuse > back_diffuse:
                     # clamps the sum below 1
-                    backDiffuse = min(backDiffuse, (1.0 - frontDiffuse))
+                    back_diffuse = min(back_diffuse, (1.0 - front_diffuse))
                 else:
-                    frontDiffuse = min(frontDiffuse, (1.0 - backDiffuse))
+                    front_diffuse = min(front_diffuse, (1.0 - back_diffuse))
 
             # map hardness between 0.0 and 1.0
-            roughness = ((1.0 - ((material.pov.specular_hardness - 1.0) / 510.0)))
+            roughness = 1.0 - ((material.pov.specular_hardness - 1.0) / 510.0)
             ## scale from 0.0 to 0.1
             roughness *= 0.1
             # add a small value because 0.0 is invalid.
-            roughness += (1.0 / 511.0)
+            roughness += 1.0 / 511.0
 
             ################################Diffuse Shader######################################
-            # Not used for Full spec (Level=3) of the shader.
-            if material.pov.diffuse_shader == 'OREN_NAYAR' and Level != 3:
+            # Not used for Full spec (ref_level_bound=3) of the shader.
+            if material.pov.diffuse_shader == "OREN_NAYAR" and ref_level_bound != 3:
                 # Blender roughness is what is generally called oren nayar Sigma,
                 # and brilliance in POV-Ray.
-                tabWrite("brilliance %.3g\n" % (0.9 + material.roughness))
+                tab_write("brilliance %.3g\n" % (0.9 + material.roughness))
 
-            if material.pov.diffuse_shader == 'TOON' and Level != 3:
-                tabWrite("brilliance %.3g\n" % (0.01 + material.diffuse_toon_smooth * 0.25))
+            if material.pov.diffuse_shader == "TOON" and ref_level_bound != 3:
+                tab_write("brilliance %.3g\n" % (0.01 + material.diffuse_toon_smooth * 0.25))
                 # Lower diffuse and increase specular for toon effect seems to look better
                 # in POV-Ray.
-                frontDiffuse *= 0.5
+                front_diffuse *= 0.5
 
-            if material.pov.diffuse_shader == 'MINNAERT' and Level != 3:
-                #tabWrite("aoi %.3g\n" % material.darkness)
+            if material.pov.diffuse_shader == "MINNAERT" and ref_level_bound != 3:
+                # tab_write("aoi %.3g\n" % material.darkness)
                 pass  # let's keep things simple for now
-            if material.pov.diffuse_shader == 'FRESNEL' and Level != 3:
-                #tabWrite("aoi %.3g\n" % material.diffuse_fresnel_factor)
+            if material.pov.diffuse_shader == "FRESNEL" and ref_level_bound != 3:
+                # tab_write("aoi %.3g\n" % material.diffuse_fresnel_factor)
                 pass  # let's keep things simple for now
-            if material.pov.diffuse_shader == 'LAMBERT' and Level != 3:
+            if material.pov.diffuse_shader == "LAMBERT" and ref_level_bound != 3:
                 # trying to best match lambert attenuation by that constant brilliance value
-                tabWrite("brilliance 1\n")
+                tab_write("brilliance 1\n")
 
-            if Level == 2:
+            if ref_level_bound == 2:
                 ###########################Specular Shader######################################
                 # No difference between phong and cook torrence in blender HaHa!
-                if (material.pov.specular_shader == 'COOKTORR' or
-                    material.pov.specular_shader == 'PHONG'):
-                    tabWrite("phong %.3g\n" % (material.pov.specular_intensity))
-                    tabWrite("phong_size %.3g\n" % (material.pov.specular_hardness /3.14))
+                if (
+                    material.pov.specular_shader == "COOKTORR"
+                    or material.pov.specular_shader == "PHONG"
+                ):
+                    tab_write("phong %.3g\n" % (material.pov.specular_intensity))
+                    tab_write("phong_size %.3g\n" % (material.pov.specular_hardness / 3.14))
 
                 # POV-Ray 'specular' keyword corresponds to a Blinn model, without the ior.
-                elif material.pov.specular_shader == 'BLINN':
+                elif material.pov.specular_shader == "BLINN":
                     # Use blender Blinn's IOR just as some factor for spec intensity
-                    tabWrite("specular %.3g\n" % (material.pov.specular_intensity *
-                                                  (material.pov.specular_ior / 4.0)))
-                    tabWrite("roughness %.3g\n" % roughness)
-                    #Could use brilliance 2(or varying around 2 depending on ior or factor) too.
-
-                elif material.pov.specular_shader == 'TOON':
-                    tabWrite("phong %.3g\n" % (material.pov.specular_intensity * 2.0))
+                    tab_write(
+                        "specular %.3g\n"
+                        % (material.pov.specular_intensity * (material.pov.specular_ior / 4.0))
+                    )
+                    tab_write("roughness %.3g\n" % roughness)
+                    # Could use brilliance 2(or varying around 2 depending on ior or factor) too.
+
+                elif material.pov.specular_shader == "TOON":
+                    tab_write("phong %.3g\n" % (material.pov.specular_intensity * 2.0))
                     # use extreme phong_size
-                    tabWrite("phong_size %.3g\n" % (0.1 + material.pov.specular_toon_smooth / 2.0))
+                    tab_write("phong_size %.3g\n" % (0.1 + material.pov.specular_toon_smooth / 2.0))
 
-                elif material.pov.specular_shader == 'WARDISO':
+                elif material.pov.specular_shader == "WARDISO":
                     # find best suited default constant for brilliance Use both phong and
                     # specular for some values.
-                    tabWrite("specular %.3g\n" % (material.pov.specular_intensity /
-                                                  (material.pov.specular_slope + 0.0005)))
+                    tab_write(
+                        "specular %.3g\n"
+                        % (material.pov.specular_intensity / (material.pov.specular_slope + 0.0005))
+                    )
                     # find best suited default constant for brilliance Use both phong and
                     # specular for some values.
-                    tabWrite("roughness %.4g\n" % (0.0005 + material.pov.specular_slope / 10.0))
+                    tab_write("roughness %.4g\n" % (0.0005 + material.pov.specular_slope / 10.0))
                     # find best suited default constant for brilliance Use both phong and
                     # specular for some values.
-                    tabWrite("brilliance %.4g\n" % (1.8 - material.pov.specular_slope * 1.8))
+                    tab_write("brilliance %.4g\n" % (1.8 - material.pov.specular_slope * 1.8))
 
             ####################################################################################
-            elif Level == 1:
-                if (material.pov.specular_shader == 'COOKTORR' or
-                    material.pov.specular_shader == 'PHONG'):
-                    tabWrite("phong 0\n")#%.3g\n" % (material.pov.specular_intensity/5))
-                    tabWrite("phong_size %.3g\n" % (material.pov.specular_hardness /3.14))
+            elif ref_level_bound == 1:
+                if (
+                    material.pov.specular_shader == "COOKTORR"
+                    or material.pov.specular_shader == "PHONG"
+                ):
+                    tab_write("phong 0\n")  #%.3g\n" % (material.pov.specular_intensity/5))
+                    tab_write("phong_size %.3g\n" % (material.pov.specular_hardness / 3.14))
 
                 # POV-Ray 'specular' keyword corresponds to a Blinn model, without the ior.
-                elif material.pov.specular_shader == 'BLINN':
+                elif material.pov.specular_shader == "BLINN":
                     # Use blender Blinn's IOR just as some factor for spec intensity
-                    tabWrite("specular %.3g\n" % (material.pov.specular_intensity *
-                                                  (material.pov.specular_ior / 4.0)))
-                    tabWrite("roughness %.3g\n" % roughness)
-                    #Could use brilliance 2(or varying around 2 depending on ior or factor) too.
-
-                elif material.pov.specular_shader == 'TOON':
-                    tabWrite("phong %.3g\n" % (material.pov.specular_intensity * 2.0))
+                    tab_write(
+                        "specular %.3g\n"
+                        % (material.pov.specular_intensity * (material.pov.specular_ior / 4.0))
+                    )
+                    tab_write("roughness %.3g\n" % roughness)
+                    # Could use brilliance 2(or varying around 2 depending on ior or factor) too.
+
+                elif material.pov.specular_shader == "TOON":
+                    tab_write("phong %.3g\n" % (material.pov.specular_intensity * 2.0))
                     # use extreme phong_size
-                    tabWrite("phong_size %.3g\n" % (0.1 + material.pov.specular_toon_smooth / 2.0))
+                    tab_write("phong_size %.3g\n" % (0.1 + material.pov.specular_toon_smooth / 2.0))
 
-                elif material.pov.specular_shader == 'WARDISO':
+                elif material.pov.specular_shader == "WARDISO":
                     # find best suited default constant for brilliance Use both phong and
                     # specular for some values.
-                    tabWrite("specular %.3g\n" % (material.pov.specular_intensity /
-                                                  (material.pov.specular_slope + 0.0005)))
+                    tab_write(
+                        "specular %.3g\n"
+                        % (material.pov.specular_intensity / (material.pov.specular_slope + 0.0005))
+                    )
                     # find best suited default constant for brilliance Use both phong and
                     # specular for some values.
-                    tabWrite("roughness %.4g\n" % (0.0005 + material.pov.specular_slope / 10.0))
+                    tab_write("roughness %.4g\n" % (0.0005 + material.pov.specular_slope / 10.0))
                     # find best suited default constant for brilliance Use both phong and
                     # specular for some values.
-                    tabWrite("brilliance %.4g\n" % (1.8 - material.pov.specular_slope * 1.8))
-            elif Level == 3:
-                # Spec must be Max at Level 3 so that white of mixing texture always shows specularity
+                    tab_write("brilliance %.4g\n" % (1.8 - material.pov.specular_slope * 1.8))
+            elif ref_level_bound == 3:
+                # Spec must be Max at ref_level_bound 3 so that white of mixing texture always shows specularity
                 # That's why it's multiplied by 255. maybe replace by texture's brightest pixel value?
-                tabWrite("specular %.3g\n" % ((material.pov.specular_intensity*material.pov.specular_color.v)*(255* slot.specular_factor)))
-                tabWrite("roughness %.3g\n" % (1/material.pov.specular_hardness))
-            tabWrite("diffuse %.3g %.3g\n" % (frontDiffuse, backDiffuse))
-
-            tabWrite("ambient %.3g\n" % material.pov.ambient)
+                tab_write(
+                    "specular %.3g\n"
+                    % (
+                        (material.pov.specular_intensity * material.pov.specular_color.v)
+                        * (255 * slot.specular_factor)
+                    )
+                )
+                tab_write("roughness %.3g\n" % (1 / material.pov.specular_hardness))
+            tab_write("diffuse %.3g %.3g\n" % (front_diffuse, back_diffuse))
+
+            tab_write("ambient %.3g\n" % material.pov.ambient)
             # POV-Ray blends the global value
-            #tabWrite("ambient rgb <%.3g, %.3g, %.3g>\n" % \
+            # tab_write("ambient rgb <%.3g, %.3g, %.3g>\n" % \
             #         tuple([c*material.pov.ambient for c in world.ambient_color]))
-            tabWrite("emission %.3g\n" % material.pov.emit)  # New in POV-Ray 3.7
+            tab_write("emission %.3g\n" % material.pov.emit)  # New in POV-Ray 3.7
 
-            #POV-Ray just ignores roughness if there's no specular keyword
-            #tabWrite("roughness %.3g\n" % roughness)
+            # POV-Ray just ignores roughness if there's no specular keyword
+            # tab_write("roughness %.3g\n" % roughness)
 
             if material.pov.conserve_energy:
                 # added for more realistic shading. Needs some checking to see if it
                 # really works. --Maurice.
-                tabWrite("conserve_energy\n")
+                tab_write("conserve_energy\n")
 
-            if colored_specular_found == True:
-                 tabWrite("metallic\n")
+            if colored_specular_found:
+                tab_write("metallic\n")
 
             # 'phong 70.0 '
-            if Level != 1:
+            if ref_level_bound != 1:
                 if material.pov_raytrace_mirror.use:
                     raytrace_mirror = material.pov_raytrace_mirror
                     if raytrace_mirror.reflect_factor:
-                        tabWrite("reflection {\n")
-                        tabWrite("rgb <%.3g, %.3g, %.3g>\n" % material.pov.mirror_color[:])
+                        tab_write("reflection {\n")
+                        tab_write("rgb <%.3g, %.3g, %.3g>\n" % material.pov.mirror_color[:])
                         if material.pov.mirror_metallic:
-                            tabWrite("metallic %.3g\n" % (raytrace_mirror.reflect_factor))
+                            tab_write("metallic %.3g\n" % (raytrace_mirror.reflect_factor))
                         # Blurry reflections for UberPOV
                         if using_uberpov and raytrace_mirror.gloss_factor < 1.0:
-                            #tabWrite("#ifdef(unofficial) #if(unofficial = \"patch\") #if(patch(\"upov-reflection-roughness\") > 0)\n")
-                            tabWrite("roughness %.6f\n" % \
-                                     (0.000001/raytrace_mirror.gloss_factor))
-                            #tabWrite("#end #end #end\n") # This and previous comment for backward compatibility, messier pov code
+                            # tab_write("#ifdef(unofficial) #if(unofficial = \"patch\") #if(patch(\"upov-reflection-roughness\") > 0)\n")
+                            tab_write(
+                                "roughness %.6f\n" % (0.000001 / raytrace_mirror.gloss_factor)
+                            )
+                            # tab_write("#end #end #end\n") # This and previous comment for backward compatibility, messier pov code
                         if material.pov.mirror_use_IOR:  # WORKING ?
                             # Removed from the line below: gives a more physically correct
                             # material but needs proper IOR. --Maurice
-                            tabWrite("fresnel 1 ")
-                        tabWrite("falloff %.3g exponent %.3g} " % \
-                                 (raytrace_mirror.fresnel, raytrace_mirror.fresnel_factor))
+                            tab_write("fresnel 1 ")
+                        tab_write(
+                            "falloff %.3g exponent %.3g} "
+                            % (raytrace_mirror.fresnel, raytrace_mirror.fresnel_factor)
+                        )
 
             if material.pov_subsurface_scattering.use:
                 subsurface_scattering = material.pov_subsurface_scattering
-                tabWrite("subsurface { translucency <%.3g, %.3g, %.3g> }\n" % (
-                         (subsurface_scattering.radius[0]),
-                         (subsurface_scattering.radius[1]),
-                         (subsurface_scattering.radius[2]),
-                         )
-                        )
+                tab_write(
+                    "subsurface { translucency <%.3g, %.3g, %.3g> }\n"
+                    % (
+                        (subsurface_scattering.radius[0]),
+                        (subsurface_scattering.radius[1]),
+                        (subsurface_scattering.radius[2]),
+                    )
+                )
 
             if material.pov.irid_enable:
-                tabWrite("irid { %.4g thickness %.4g turbulence %.4g }" % \
-                         (material.pov.irid_amount, material.pov.irid_thickness,
-                          material.pov.irid_turbulence))
+                tab_write(
+                    "irid { %.4g thickness %.4g turbulence %.4g }"
+                    % (
+                        material.pov.irid_amount,
+                        material.pov.irid_thickness,
+                        material.pov.irid_turbulence,
+                    )
+                )
 
         else:
-            tabWrite("diffuse 0.8\n")
-            tabWrite("phong 70.0\n")
+            tab_write("diffuse 0.8\n")
+            tab_write("phong 70.0\n")
 
-            #tabWrite("specular 0.2\n")
+            # tab_write("specular 0.2\n")
 
         # This is written into the object
-        '''
+        """
         if material and material.pov.transparency_method=='RAYTRACE':
             'interior { ior %.3g} ' % material.raytrace_transparency.ior
-        '''
+        """
 
-        #tabWrite("crand 1.0\n") # Sand granyness
-        #tabWrite("metallic %.6f\n" % material.spec)
-        #tabWrite("phong %.6f\n" % material.spec)
-        #tabWrite("phong_size %.6f\n" % material.spec)
-        #tabWrite("brilliance %.6f " % (material.pov.specular_hardness/256.0) # Like hardness
+        # tab_write("crand 1.0\n") # Sand granyness
+        # tab_write("metallic %.6f\n" % material.spec)
+        # tab_write("phong %.6f\n" % material.spec)
+        # tab_write("phong_size %.6f\n" % material.spec)
+        # tab_write("brilliance %.6f " % (material.pov.specular_hardness/256.0) # Like hardness
 
-        tabWrite("}\n\n")
+        tab_write("}\n\n")
 
-    # Level=2 Means translation of spec and mir levels for when no map influences them
-    povHasnoSpecularMaps(Level=2)
+    # ref_level_bound=2 Means translation of spec and mir levels for when no map influences them
+    pov_has_no_specular_maps(ref_level_bound=2)
 
     if material:
         special_texture_found = False
@@ -271,1495 +389,1181 @@ def writeMaterial(using_uberpov, DEF_MAT_NAME, scene, tabWrite, safety, comments
         for t in material.pov_texture_slots:
             tmpidx += 1
             # index = material.pov.active_texture_index
-            slot = material.pov_texture_slots[tmpidx] # [index]
-            povtex = slot.texture # slot.name
+            slot = material.pov_texture_slots[tmpidx]  # [index]
+            povtex = slot.texture  # slot.name
             tex = bpy.data.textures[povtex]
 
             if t and t.use and tex is not None:
 
-
-                if (tex.type == 'IMAGE' and tex.image) or tex.type != 'IMAGE':
-                    #validPath
-                    if(t and t.use and
-                       (t.use_map_specular or t.use_map_raymir or t.use_map_normal or t.use_map_alpha)):
+                if (tex.type == "IMAGE" and tex.image) or tex.type != "IMAGE":
+                    # validPath
+                    if (
+                        t
+                        and t.use
+                        and (
+                            t.use_map_specular
+                            or t.use_map_raymir
+                            or t.use_map_normal
+                            or t.use_map_alpha
+                        )
+                    ):
                         special_texture_found = True
                         continue  # Some texture found
 
         if special_texture_found or colored_specular_found:
-            # Level=1 Means No specular nor Mirror reflection
-            povHasnoSpecularMaps(Level=1)
+            # ref_level_bound=1 Means No specular nor Mirror reflection
+            pov_has_no_specular_maps(ref_level_bound=1)
+
+            # ref_level_bound=3 Means Maximum Spec and Mirror
+            pov_has_no_specular_maps(ref_level_bound=3)
 
-            # Level=3 Means Maximum Spec and Mirror
-            povHasnoSpecularMaps(Level=3)
 
-def exportPattern(texture, string_strip_hyphen):
+def export_pattern(texture):
     """Translate Blender procedural textures to POV patterns and write to pov file.
 
     Function Patterns can be used to better access sub components of a pattern like
-    grey values for influence mapping"""
-
-    tex=texture
+    grey values for influence mapping
+    """
+    tex = texture
     pat = tex.pov
-    PATname = "PAT_%s"%string_strip_hyphen(bpy.path.clean_name(tex.name))
-    mappingDif = ("translate <%.4g,%.4g,%.4g> scale <%.4g,%.4g,%.4g>" % \
-          (pat.tex_mov_x, pat.tex_mov_y, pat.tex_mov_z,
-           1.0 / pat.tex_scale_x, 1.0 / pat.tex_scale_y, 1.0 / pat.tex_scale_z))
-    texStrg=""
-    def exportColorRamp(texture):
-        tex=texture
+    pat_name = "PAT_%s" % string_strip_hyphen(bpy.path.clean_name(tex.name))
+    mapping_dif = "translate <%.4g,%.4g,%.4g> scale <%.4g,%.4g,%.4g>" % (
+        pat.tex_mov_x,
+        pat.tex_mov_y,
+        pat.tex_mov_z,
+        1.0 / pat.tex_scale_x,
+        1.0 / pat.tex_scale_y,
+        1.0 / pat.tex_scale_z,
+    )
+    text_strg = ""
+
+    def export_color_ramp(texture):
+        tex = texture
         pat = tex.pov
-        colRampStrg="color_map {\n"
-        numColor=0
+        col_ramp_strg = "color_map {\n"
+        num_color = 0
         for el in tex.color_ramp.elements:
-            numColor+=1
+            num_color += 1
             pos = el.position
-            col=el.color
-            colR,colG,colB,colA = col[0],col[1],col[2],1-col[3]
-            if pat.tex_pattern_type not in {'checker', 'hexagon', 'square', 'triangular', 'brick'} :
-                colRampStrg+="[%.4g color rgbf<%.4g,%.4g,%.4g,%.4g>] \n"%(pos,colR,colG,colB,colA)
-            if pat.tex_pattern_type in {'brick','checker'} and numColor < 3:
-                colRampStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
-            if pat.tex_pattern_type == 'hexagon' and numColor < 4 :
-                colRampStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
-            if pat.tex_pattern_type == 'square' and numColor < 5 :
-                colRampStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
-            if pat.tex_pattern_type == 'triangular' and numColor < 7 :
-                colRampStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
-
-        colRampStrg+="} \n"
-        #end color map
-        return colRampStrg
-    #much work to be done here only defaults translated for now:
-    #pov noise_generator 3 means perlin noise
-    if tex.type not in {'NONE', 'IMAGE'} and pat.tex_pattern_type == 'emulator':
-        texStrg+="pigment {\n"
+            col = el.color
+            col_r, col_g, col_b, col_a = col[0], col[1], col[2], 1 - col[3]
+            if pat.tex_pattern_type not in {"checker", "hexagon", "square", "triangular", "brick"}:
+                col_ramp_strg += "[%.4g color rgbf<%.4g,%.4g,%.4g,%.4g>] \n" % (
+                    pos,
+                    col_r,
+                    col_g,
+                    col_b,
+                    col_a,
+                )
+            if pat.tex_pattern_type in {"brick", "checker"} and num_color < 3:
+                col_ramp_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
+            if pat.tex_pattern_type == "hexagon" and num_color < 4:
+                col_ramp_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
+            if pat.tex_pattern_type == "square" and num_color < 5:
+                col_ramp_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
+            if pat.tex_pattern_type == "triangular" and num_color < 7:
+                col_ramp_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
+
+        col_ramp_strg += "} \n"
+        # end color map
+        return col_ramp_strg
+
+    # much work to be done here only defaults translated for now:
+    # pov noise_generator 3 means perlin noise
+    if tex.type not in {"NONE", "IMAGE"} and pat.tex_pattern_type == "emulator":
+        text_strg += "pigment {\n"
         ####################### EMULATE BLENDER VORONOI TEXTURE ####################
-        if tex.type == 'VORONOI':
-            texStrg+="crackle\n"
-            texStrg+="    offset %.4g\n"%tex.nabla
-            texStrg+="    form <%.4g,%.4g,%.4g>\n"%(tex.weight_1, tex.weight_2, tex.weight_3)
-            if tex.distance_metric == 'DISTANCE':
-                texStrg+="    metric 2.5\n"
-            if tex.distance_metric == 'DISTANCE_SQUARED':
-                texStrg+="    metric 2.5\n"
-                texStrg+="    poly_wave 2\n"
-            if tex.distance_metric == 'MINKOVSKY':
-                texStrg+="    metric %s\n"%tex.minkovsky_exponent
-            if tex.distance_metric == 'MINKOVSKY_FOUR':
-                texStrg+="    metric 4\n"
-            if tex.distance_metric == 'MINKOVSKY_HALF':
-                texStrg+="    metric 0.5\n"
-            if tex.distance_metric == 'CHEBYCHEV':
-                texStrg+="    metric 10\n"
-            if tex.distance_metric == 'MANHATTAN':
-                texStrg+="    metric 1\n"
-
-            if tex.color_mode == 'POSITION':
-                texStrg+="solid\n"
-            texStrg+="scale 0.25\n"
-            if tex.use_color_ramp == True:
-                texStrg+=exportColorRamp(tex)
+        if tex.type == "VORONOI":
+            text_strg += "crackle\n"
+            text_strg += "    offset %.4g\n" % tex.nabla
+            text_strg += "    form <%.4g,%.4g,%.4g>\n" % (tex.weight_1, tex.weight_2, tex.weight_3)
+            if tex.distance_metric == "DISTANCE":
+                text_strg += "    metric 2.5\n"
+            if tex.distance_metric == "DISTANCE_SQUARED":
+                text_strg += "    metric 2.5\n"
+                text_strg += "    poly_wave 2\n"
+            if tex.distance_metric == "MINKOVSKY":
+                text_strg += "    metric %s\n" % tex.minkovsky_exponent
+            if tex.distance_metric == "MINKOVSKY_FOUR":
+                text_strg += "    metric 4\n"
+            if tex.distance_metric == "MINKOVSKY_HALF":
+                text_strg += "    metric 0.5\n"
+            if tex.distance_metric == "CHEBYCHEV":
+                text_strg += "    metric 10\n"
+            if tex.distance_metric == "MANHATTAN":
+                text_strg += "    metric 1\n"
+
+            if tex.color_mode == "POSITION":
+                text_strg += "solid\n"
+            text_strg += "scale 0.25\n"
+            if tex.use_color_ramp:
+                text_strg += export_color_ramp(tex)
             else:
-                texStrg+="color_map {\n"
-                texStrg+="[0 color rgbt<0,0,0,1>]\n"
-                texStrg+="[1 color rgbt<1,1,1,0>]\n"
-                texStrg+="}\n"
+                text_strg += "color_map {\n"
+                text_strg += "[0 color rgbt<0,0,0,1>]\n"
+                text_strg += "[1 color rgbt<1,1,1,0>]\n"
+                text_strg += "}\n"
 
         ####################### EMULATE BLENDER CLOUDS TEXTURE ####################
-        if tex.type == 'CLOUDS':
-            if tex.noise_type == 'SOFT_NOISE':
-                texStrg+="wrinkles\n"
-                texStrg+="scale 0.25\n"
+        if tex.type == "CLOUDS":
+            if tex.noise_type == "SOFT_NOISE":
+                text_strg += "wrinkles\n"
+                text_strg += "scale 0.25\n"
             else:
-                texStrg+="granite\n"
-            if tex.use_color_ramp == True:
-                texStrg+=exportColorRamp(tex)
+                text_strg += "granite\n"
+            if tex.use_color_ramp:
+                text_strg += export_color_ramp(tex)
             else:
-                texStrg+="color_map {\n"
-                texStrg+="[0 color rgbt<0,0,0,1>]\n"
-                texStrg+="[1 color rgbt<1,1,1,0>]\n"
-                texStrg+="}\n"
+                text_strg += "color_map {\n"
+                text_strg += "[0 color rgbt<0,0,0,1>]\n"
+                text_strg += "[1 color rgbt<1,1,1,0>]\n"
+                text_strg += "}\n"
 
         ####################### EMULATE BLENDER WOOD TEXTURE ####################
-        if tex.type == 'WOOD':
-            if tex.wood_type == 'RINGS':
-                texStrg+="wood\n"
-                texStrg+="scale 0.25\n"
-            if tex.wood_type == 'RINGNOISE':
-                texStrg+="wood\n"
-                texStrg+="scale 0.25\n"
-                texStrg+="turbulence %.4g\n"%(tex.turbulence/100)
-            if tex.wood_type == 'BANDS':
-                texStrg+="marble\n"
-                texStrg+="scale 0.25\n"
-                texStrg+="rotate <45,-45,45>\n"
-            if tex.wood_type == 'BANDNOISE':
-                texStrg+="marble\n"
-                texStrg+="scale 0.25\n"
-                texStrg+="rotate <45,-45,45>\n"
-                texStrg+="turbulence %.4g\n"%(tex.turbulence/10)
-
-            if tex.noise_basis_2 == 'SIN':
-                texStrg+="sine_wave\n"
-            if tex.noise_basis_2 == 'TRI':
-                texStrg+="triangle_wave\n"
-            if tex.noise_basis_2 == 'SAW':
-                texStrg+="ramp_wave\n"
-            if tex.use_color_ramp == True:
-                texStrg+=exportColorRamp(tex)
+        if tex.type == "WOOD":
+            if tex.wood_type == "RINGS":
+                text_strg += "wood\n"
+                text_strg += "scale 0.25\n"
+            if tex.wood_type == "RINGNOISE":
+                text_strg += "wood\n"
+                text_strg += "scale 0.25\n"
+                text_strg += "turbulence %.4g\n" % (tex.turbulence / 100)
+            if tex.wood_type == "BANDS":
+                text_strg += "marble\n"
+                text_strg += "scale 0.25\n"
+                text_strg += "rotate <45,-45,45>\n"
+            if tex.wood_type == "BANDNOISE":
+                text_strg += "marble\n"
+                text_strg += "scale 0.25\n"
+                text_strg += "rotate <45,-45,45>\n"
+                text_strg += "turbulence %.4g\n" % (tex.turbulence / 10)
+
+            if tex.noise_basis_2 == "SIN":
+                text_strg += "sine_wave\n"
+            if tex.noise_basis_2 == "TRI":
+                text_strg += "triangle_wave\n"
+            if tex.noise_basis_2 == "SAW":
+                text_strg += "ramp_wave\n"
+            if tex.use_color_ramp:
+                text_strg += export_color_ramp(tex)
             else:
-                texStrg+="color_map {\n"
-                texStrg+="[0 color rgbt<0,0,0,0>]\n"
-                texStrg+="[1 color rgbt<1,1,1,0>]\n"
-                texStrg+="}\n"
+                text_strg += "color_map {\n"
+                text_strg += "[0 color rgbt<0,0,0,0>]\n"
+                text_strg += "[1 color rgbt<1,1,1,0>]\n"
+                text_strg += "}\n"
 
         ####################### EMULATE BLENDER STUCCI TEXTURE ####################
-        if tex.type == 'STUCCI':
-            texStrg+="bozo\n"
-            texStrg+="scale 0.25\n"
-            if tex.noise_type == 'HARD_NOISE':
-                texStrg+="triangle_wave\n"
-                if tex.use_color_ramp == True:
-                    texStrg+=exportColorRamp(tex)
+        if tex.type == "STUCCI":
+            text_strg += "bozo\n"
+            text_strg += "scale 0.25\n"
+            if tex.noise_type == "HARD_NOISE":
+                text_strg += "triangle_wave\n"
+                if tex.use_color_ramp:
+                    text_strg += export_color_ramp(tex)
                 else:
-                    texStrg+="color_map {\n"
-                    texStrg+="[0 color rgbf<1,1,1,0>]\n"
-                    texStrg+="[1 color rgbt<0,0,0,1>]\n"
-                    texStrg+="}\n"
+                    text_strg += "color_map {\n"
+                    text_strg += "[0 color rgbf<1,1,1,0>]\n"
+                    text_strg += "[1 color rgbt<0,0,0,1>]\n"
+                    text_strg += "}\n"
             else:
-                if tex.use_color_ramp == True:
-                    texStrg+=exportColorRamp(tex)
+                if tex.use_color_ramp:
+                    text_strg += export_color_ramp(tex)
                 else:
-                    texStrg+="color_map {\n"
-                    texStrg+="[0 color rgbf<0,0,0,1>]\n"
-                    texStrg+="[1 color rgbt<1,1,1,0>]\n"
-                    texStrg+="}\n"
+                    text_strg += "color_map {\n"
+                    text_strg += "[0 color rgbf<0,0,0,1>]\n"
+                    text_strg += "[1 color rgbt<1,1,1,0>]\n"
+                    text_strg += "}\n"
 
         ####################### EMULATE BLENDER MAGIC TEXTURE ####################
-        if tex.type == 'MAGIC':
-            texStrg+="leopard\n"
-            if tex.use_color_ramp == True:
-                texStrg+=exportColorRamp(tex)
+        if tex.type == "MAGIC":
+            text_strg += "leopard\n"
+            if tex.use_color_ramp:
+                text_strg += export_color_ramp(tex)
             else:
-                texStrg+="color_map {\n"
-                texStrg+="[0 color rgbt<1,1,1,0.5>]\n"
-                texStrg+="[0.25 color rgbf<0,1,0,0.75>]\n"
-                texStrg+="[0.5 color rgbf<0,0,1,0.75>]\n"
-                texStrg+="[0.75 color rgbf<1,0,1,0.75>]\n"
-                texStrg+="[1 color rgbf<0,1,0,0.75>]\n"
-                texStrg+="}\n"
-            texStrg+="scale 0.1\n"
+                text_strg += "color_map {\n"
+                text_strg += "[0 color rgbt<1,1,1,0.5>]\n"
+                text_strg += "[0.25 color rgbf<0,1,0,0.75>]\n"
+                text_strg += "[0.5 color rgbf<0,0,1,0.75>]\n"
+                text_strg += "[0.75 color rgbf<1,0,1,0.75>]\n"
+                text_strg += "[1 color rgbf<0,1,0,0.75>]\n"
+                text_strg += "}\n"
+            text_strg += "scale 0.1\n"
 
         ####################### EMULATE BLENDER MARBLE TEXTURE ####################
-        if tex.type == 'MARBLE':
-            texStrg+="marble\n"
-            texStrg+="turbulence 0.5\n"
-            texStrg+="noise_generator 3\n"
-            texStrg+="scale 0.75\n"
-            texStrg+="rotate <45,-45,45>\n"
-            if tex.use_color_ramp == True:
-                texStrg+=exportColorRamp(tex)
+        if tex.type == "MARBLE":
+            text_strg += "marble\n"
+            text_strg += "turbulence 0.5\n"
+            text_strg += "noise_generator 3\n"
+            text_strg += "scale 0.75\n"
+            text_strg += "rotate <45,-45,45>\n"
+            if tex.use_color_ramp:
+                text_strg += export_color_ramp(tex)
             else:
-                if tex.marble_type == 'SOFT':
-                    texStrg+="color_map {\n"
-                    texStrg+="[0 color rgbt<0,0,0,0>]\n"
-                    texStrg+="[0.05 color rgbt<0,0,0,0>]\n"
-                    texStrg+="[1 color rgbt<0.9,0.9,0.9,0>]\n"
-                    texStrg+="}\n"
-                elif tex.marble_type == 'SHARP':
-                    texStrg+="color_map {\n"
-                    texStrg+="[0 color rgbt<0,0,0,0>]\n"
-                    texStrg+="[0.025 color rgbt<0,0,0,0>]\n"
-                    texStrg+="[1 color rgbt<0.9,0.9,0.9,0>]\n"
-                    texStrg+="}\n"
+                if tex.marble_type == "SOFT":
+                    text_strg += "color_map {\n"
+                    text_strg += "[0 color rgbt<0,0,0,0>]\n"
+                    text_strg += "[0.05 color rgbt<0,0,0,0>]\n"
+                    text_strg += "[1 color rgbt<0.9,0.9,0.9,0>]\n"
+                    text_strg += "}\n"
+                elif tex.marble_type == "SHARP":
+                    text_strg += "color_map {\n"
+                    text_strg += "[0 color rgbt<0,0,0,0>]\n"
+                    text_strg += "[0.025 color rgbt<0,0,0,0>]\n"
+                    text_strg += "[1 color rgbt<0.9,0.9,0.9,0>]\n"
+                    text_strg += "}\n"
                 else:
-                    texStrg+="[0 color rgbt<0,0,0,0>]\n"
-                    texStrg+="[1 color rgbt<1,1,1,0>]\n"
-                    texStrg+="}\n"
-            if tex.noise_basis_2 == 'SIN':
-                texStrg+="sine_wave\n"
-            if tex.noise_basis_2 == 'TRI':
-                texStrg+="triangle_wave\n"
-            if tex.noise_basis_2 == 'SAW':
-                texStrg+="ramp_wave\n"
+                    text_strg += "[0 color rgbt<0,0,0,0>]\n"
+                    text_strg += "[1 color rgbt<1,1,1,0>]\n"
+                    text_strg += "}\n"
+            if tex.noise_basis_2 == "SIN":
+                text_strg += "sine_wave\n"
+            if tex.noise_basis_2 == "TRI":
+                text_strg += "triangle_wave\n"
+            if tex.noise_basis_2 == "SAW":
+                text_strg += "ramp_wave\n"
 
         ####################### EMULATE BLENDER BLEND TEXTURE ####################
-        if tex.type == 'BLEND':
-            if tex.progression=='RADIAL':
-                texStrg+="radial\n"
-                if tex.use_flip_axis=='HORIZONTAL':
-                    texStrg+="rotate x*90\n"
+        if tex.type == "BLEND":
+            if tex.progression == "RADIAL":
+                text_strg += "radial\n"
+                if tex.use_flip_axis == "HORIZONTAL":
+                    text_strg += "rotate x*90\n"
                 else:
-                    texStrg+="rotate <-90,0,90>\n"
-                texStrg+="ramp_wave\n"
-            elif tex.progression=='SPHERICAL':
-                texStrg+="spherical\n"
-                texStrg+="scale 3\n"
-                texStrg+="poly_wave 1\n"
-            elif tex.progression=='QUADRATIC_SPHERE':
-                texStrg+="spherical\n"
-                texStrg+="scale 3\n"
-                texStrg+="    poly_wave 2\n"
-            elif tex.progression=='DIAGONAL':
-                texStrg+="gradient <1,1,0>\n"
-                texStrg+="scale 3\n"
-            elif tex.use_flip_axis=='HORIZONTAL':
-                texStrg+="gradient x\n"
-                texStrg+="scale 2.01\n"
-            elif tex.use_flip_axis=='VERTICAL':
-                texStrg+="gradient y\n"
-                texStrg+="scale 2.01\n"
-            #texStrg+="ramp_wave\n"
-            #texStrg+="frequency 0.5\n"
-            texStrg+="phase 0.5\n"
-            if tex.use_color_ramp == True:
-                texStrg+=exportColorRamp(tex)
+                    text_strg += "rotate <-90,0,90>\n"
+                text_strg += "ramp_wave\n"
+            elif tex.progression == "SPHERICAL":
+                text_strg += "spherical\n"
+                text_strg += "scale 3\n"
+                text_strg += "poly_wave 1\n"
+            elif tex.progression == "QUADRATIC_SPHERE":
+                text_strg += "spherical\n"
+                text_strg += "scale 3\n"
+                text_strg += "    poly_wave 2\n"
+            elif tex.progression == "DIAGONAL":
+                text_strg += "gradient <1,1,0>\n"
+                text_strg += "scale 3\n"
+            elif tex.use_flip_axis == "HORIZONTAL":
+                text_strg += "gradient x\n"
+                text_strg += "scale 2.01\n"
+            elif tex.use_flip_axis == "VERTICAL":
+                text_strg += "gradient y\n"
+                text_strg += "scale 2.01\n"
+            # text_strg+="ramp_wave\n"
+            # text_strg+="frequency 0.5\n"
+            text_strg += "phase 0.5\n"
+            if tex.use_color_ramp:
+                text_strg += export_color_ramp(tex)
             else:
-                texStrg+="color_map {\n"
-                texStrg+="[0 color rgbt<1,1,1,0>]\n"
-                texStrg+="[1 color rgbf<0,0,0,1>]\n"
-                texStrg+="}\n"
-            if tex.progression == 'LINEAR':
-                texStrg+="    poly_wave 1\n"
-            if tex.progression == 'QUADRATIC':
-                texStrg+="    poly_wave 2\n"
-            if tex.progression == 'EASING':
-                texStrg+="    poly_wave 1.5\n"
-
+                text_strg += "color_map {\n"
+                text_strg += "[0 color rgbt<1,1,1,0>]\n"
+                text_strg += "[1 color rgbf<0,0,0,1>]\n"
+                text_strg += "}\n"
+            if tex.progression == "LINEAR":
+                text_strg += "    poly_wave 1\n"
+            if tex.progression == "QUADRATIC":
+                text_strg += "    poly_wave 2\n"
+            if tex.progression == "EASING":
+                text_strg += "    poly_wave 1.5\n"
 
         ####################### EMULATE BLENDER MUSGRAVE TEXTURE ####################
         # if tex.type == 'MUSGRAVE':
-            # texStrg+="function{ f_ridged_mf( x, y, 0, 1, 2, 9, -0.5, 3,3 )*0.5}\n"
-            # texStrg+="color_map {\n"
-            # texStrg+="[0 color rgbf<0,0,0,1>]\n"
-            # texStrg+="[1 color rgbf<1,1,1,0>]\n"
-            # texStrg+="}\n"
+        # text_strg+="function{ f_ridged_mf( x, y, 0, 1, 2, 9, -0.5, 3,3 )*0.5}\n"
+        # text_strg+="color_map {\n"
+        # text_strg+="[0 color rgbf<0,0,0,1>]\n"
+        # text_strg+="[1 color rgbf<1,1,1,0>]\n"
+        # text_strg+="}\n"
         # simplified for now:
 
-        if tex.type == 'MUSGRAVE':
-            texStrg+="bozo scale 0.25 \n"
-            if tex.use_color_ramp == True:
-                texStrg+=exportColorRamp(tex)
+        if tex.type == "MUSGRAVE":
+            text_strg += "bozo scale 0.25 \n"
+            if tex.use_color_ramp:
+                text_strg += export_color_ramp(tex)
             else:
-                texStrg+="color_map {[0.5 color rgbf<0,0,0,1>][1 color rgbt<1,1,1,0>]}ramp_wave \n"
+                text_strg += (
+                    "color_map {[0.5 color rgbf<0,0,0,1>][1 color rgbt<1,1,1,0>]}ramp_wave \n"
+                )
 
         ####################### EMULATE BLENDER DISTORTED NOISE TEXTURE ####################
-        if tex.type == 'DISTORTED_NOISE':
-            texStrg+="average\n"
-            texStrg+="  pigment_map {\n"
-            texStrg+="  [1 bozo scale 0.25 turbulence %.4g\n" %tex.distortion
-            if tex.use_color_ramp == True:
-                texStrg+=exportColorRamp(tex)
+        if tex.type == "DISTORTED_NOISE":
+            text_strg += "average\n"
+            text_strg += "  pigment_map {\n"
+            text_strg += "  [1 bozo scale 0.25 turbulence %.4g\n" % tex.distortion
+            if tex.use_color_ramp:
+                text_strg += export_color_ramp(tex)
             else:
-                texStrg+="color_map {\n"
-                texStrg+="[0 color rgbt<1,1,1,0>]\n"
-                texStrg+="[1 color rgbf<0,0,0,1>]\n"
-                texStrg+="}\n"
-            texStrg+="]\n"
-
-            if tex.noise_distortion == 'CELL_NOISE':
-                texStrg+="  [1 cells scale 0.1\n"
-                if tex.use_color_ramp == True:
-                    texStrg+=exportColorRamp(tex)
+                text_strg += "color_map {\n"
+                text_strg += "[0 color rgbt<1,1,1,0>]\n"
+                text_strg += "[1 color rgbf<0,0,0,1>]\n"
+                text_strg += "}\n"
+            text_strg += "]\n"
+
+            if tex.noise_distortion == "CELL_NOISE":
+                text_strg += "  [1 cells scale 0.1\n"
+                if tex.use_color_ramp:
+                    text_strg += export_color_ramp(tex)
                 else:
-                    texStrg+="color_map {\n"
-                    texStrg+="[0 color rgbt<1,1,1,0>]\n"
-                    texStrg+="[1 color rgbf<0,0,0,1>]\n"
-                    texStrg+="}\n"
-                texStrg+="]\n"
-            if tex.noise_distortion=='VORONOI_CRACKLE':
-                texStrg+="  [1 crackle scale 0.25\n"
-                if tex.use_color_ramp == True:
-                    texStrg+=exportColorRamp(tex)
+                    text_strg += "color_map {\n"
+                    text_strg += "[0 color rgbt<1,1,1,0>]\n"
+                    text_strg += "[1 color rgbf<0,0,0,1>]\n"
+                    text_strg += "}\n"
+                text_strg += "]\n"
+            if tex.noise_distortion == "VORONOI_CRACKLE":
+                text_strg += "  [1 crackle scale 0.25\n"
+                if tex.use_color_ramp:
+                    text_strg += export_color_ramp(tex)
                 else:
-                    texStrg+="color_map {\n"
-                    texStrg+="[0 color rgbt<1,1,1,0>]\n"
-                    texStrg+="[1 color rgbf<0,0,0,1>]\n"
-                    texStrg+="}\n"
-                texStrg+="]\n"
-            if tex.noise_distortion in ['VORONOI_F1','VORONOI_F2','VORONOI_F3','VORONOI_F4','VORONOI_F2_F1']:
-                texStrg+="  [1 crackle metric 2.5 scale 0.25 turbulence %.4g\n" %(tex.distortion/2)
-                if tex.use_color_ramp == True:
-                    texStrg+=exportColorRamp(tex)
+                    text_strg += "color_map {\n"
+                    text_strg += "[0 color rgbt<1,1,1,0>]\n"
+                    text_strg += "[1 color rgbf<0,0,0,1>]\n"
+                    text_strg += "}\n"
+                text_strg += "]\n"
+            if tex.noise_distortion in [
+                "VORONOI_F1",
+                "VORONOI_F2",
+                "VORONOI_F3",
+                "VORONOI_F4",
+                "VORONOI_F2_F1",
+            ]:
+                text_strg += "  [1 crackle metric 2.5 scale 0.25 turbulence %.4g\n" % (
+                    tex.distortion / 2
+                )
+                if tex.use_color_ramp:
+                    text_strg += export_color_ramp(tex)
                 else:
-                    texStrg+="color_map {\n"
-                    texStrg+="[0 color rgbt<1,1,1,0>]\n"
-                    texStrg+="[1 color rgbf<0,0,0,1>]\n"
-                    texStrg+="}\n"
-                texStrg+="]\n"
+                    text_strg += "color_map {\n"
+                    text_strg += "[0 color rgbt<1,1,1,0>]\n"
+                    text_strg += "[1 color rgbf<0,0,0,1>]\n"
+                    text_strg += "}\n"
+                text_strg += "]\n"
             else:
-                texStrg+="  [1 wrinkles scale 0.25\n"
-                if tex.use_color_ramp == True:
-                    texStrg+=exportColorRamp(tex)
+                text_strg += "  [1 wrinkles scale 0.25\n"
+                if tex.use_color_ramp:
+                    text_strg += export_color_ramp(tex)
                 else:
-                    texStrg+="color_map {\n"
-                    texStrg+="[0 color rgbt<1,1,1,0>]\n"
-                    texStrg+="[1 color rgbf<0,0,0,1>]\n"
-                    texStrg+="}\n"
-                texStrg+="]\n"
-            texStrg+="  }\n"
+                    text_strg += "color_map {\n"
+                    text_strg += "[0 color rgbt<1,1,1,0>]\n"
+                    text_strg += "[1 color rgbf<0,0,0,1>]\n"
+                    text_strg += "}\n"
+                text_strg += "]\n"
+            text_strg += "  }\n"
 
         ####################### EMULATE BLENDER NOISE TEXTURE ####################
-        if tex.type == 'NOISE':
-            texStrg+="cells\n"
-            texStrg+="turbulence 3\n"
-            texStrg+="omega 3\n"
-            if tex.use_color_ramp == True:
-                texStrg+=exportColorRamp(tex)
+        if tex.type == "NOISE":
+            text_strg += "cells\n"
+            text_strg += "turbulence 3\n"
+            text_strg += "omega 3\n"
+            if tex.use_color_ramp:
+                text_strg += export_color_ramp(tex)
             else:
-                texStrg+="color_map {\n"
-                texStrg+="[0.75 color rgb<0,0,0,>]\n"
-                texStrg+="[1 color rgb<1,1,1,>]\n"
-                texStrg+="}\n"
+                text_strg += "color_map {\n"
+                text_strg += "[0.75 color rgb<0,0,0,>]\n"
+                text_strg += "[1 color rgb<1,1,1,>]\n"
+                text_strg += "}\n"
 
         ####################### IGNORE OTHER BLENDER TEXTURE ####################
-        else: #non translated textures
+        else:  # non translated textures
             pass
-        texStrg+="}\n\n"
-
-        texStrg+="#declare f%s=\n"%PATname
-        texStrg+="function{pigment{%s}}\n"%PATname
-        texStrg+="\n"
-
-    elif pat.tex_pattern_type != 'emulator':
-        texStrg+="pigment {\n"
-        texStrg+="%s\n"%pat.tex_pattern_type
-        if pat.tex_pattern_type == 'agate':
-            texStrg+="agate_turb %.4g\n"%pat.modifier_turbulence
-        if pat.tex_pattern_type in {'spiral1', 'spiral2', 'tiling'}:
-            texStrg+="%s\n"%pat.modifier_numbers
-        if pat.tex_pattern_type == 'quilted':
-            texStrg+="control0 %s control1 %s\n"%(pat.modifier_control0, pat.modifier_control1)
-        if pat.tex_pattern_type == 'mandel':
-            texStrg+="%s exponent %s \n"%(pat.f_iter, pat.f_exponent)
-        if pat.tex_pattern_type == 'julia':
-            texStrg+="<%.4g, %.4g> %s exponent %s \n"%(pat.julia_complex_1, pat.julia_complex_2, pat.f_iter, pat.f_exponent)
-        if pat.tex_pattern_type == 'magnet' and pat.magnet_style == 'mandel':
-            texStrg+="%s mandel %s \n"%(pat.magnet_type, pat.f_iter)
-        if pat.tex_pattern_type == 'magnet' and pat.magnet_style == 'julia':
-            texStrg+="%s julia <%.4g, %.4g> %s\n"%(pat.magnet_type, pat.julia_complex_1, pat.julia_complex_2, pat.f_iter)
-        if pat.tex_pattern_type in {'mandel', 'julia', 'magnet'}:
-            texStrg+="interior %s, %.4g\n"%(pat.f_ior, pat.f_ior_fac)
-            texStrg+="exterior %s, %.4g\n"%(pat.f_eor, pat.f_eor_fac)
-        if pat.tex_pattern_type == 'gradient':
-            texStrg+="<%s, %s, %s> \n"%(pat.grad_orient_x, pat.grad_orient_y, pat.grad_orient_z)
-        if pat.tex_pattern_type == 'pavement':
-            numTiles=pat.pave_tiles
-            numPattern=1
-            if pat.pave_sides == '4' and pat.pave_tiles == 3:
-                 numPattern = pat.pave_pat_2
-            if pat.pave_sides == '6' and pat.pave_tiles == 3:
-                numPattern = pat.pave_pat_3
-            if pat.pave_sides == '3' and pat.pave_tiles == 4:
-                numPattern = pat.pave_pat_3
-            if pat.pave_sides == '3' and pat.pave_tiles == 5:
-                numPattern = pat.pave_pat_4
-            if pat.pave_sides == '4' and pat.pave_tiles == 4:
-                numPattern = pat.pave_pat_5
-            if pat.pave_sides == '6' and pat.pave_tiles == 4:
-                numPattern = pat.pave_pat_7
-            if pat.pave_sides == '4' and pat.pave_tiles == 5:
-                numPattern = pat.pave_pat_12
-            if pat.pave_sides == '3' and pat.pave_tiles == 6:
-                numPattern = pat.pave_pat_12
-            if pat.pave_sides == '6' and pat.pave_tiles == 5:
-                numPattern = pat.pave_pat_22
-            if pat.pave_sides == '4' and pat.pave_tiles == 6:
-                numPattern = pat.pave_pat_35
-            if pat.pave_sides == '6' and pat.pave_tiles == 6:
-                numTiles = 5
-            texStrg+="number_of_sides %s number_of_tiles %s pattern %s form %s \n"%(pat.pave_sides, numTiles, numPattern, pat.pave_form)
-        ################ functions #####################################################################################################
-        if pat.tex_pattern_type == 'function':
-            texStrg+="{ %s"%pat.func_list
-            texStrg+="(x"
+        text_strg += "}\n\n"
+
+        text_strg += "#declare f%s=\n" % pat_name
+        text_strg += "function{pigment{%s}}\n" % pat_name
+        text_strg += "\n"
+
+    elif pat.tex_pattern_type != "emulator":
+        text_strg += "pigment {\n"
+        text_strg += "%s\n" % pat.tex_pattern_type
+        if pat.tex_pattern_type == "agate":
+            text_strg += "agate_turb %.4g\n" % pat.modifier_turbulence
+        if pat.tex_pattern_type in {"spiral1", "spiral2", "tiling"}:
+            text_strg += "%s\n" % pat.modifier_numbers
+        if pat.tex_pattern_type == "quilted":
+            text_strg += "control0 %s control1 %s\n" % (
+                pat.modifier_control0,
+                pat.modifier_control1,
+            )
+        if pat.tex_pattern_type == "mandel":
+            text_strg += "%s exponent %s \n" % (pat.f_iter, pat.f_exponent)
+        if pat.tex_pattern_type == "julia":
+            text_strg += "<%.4g, %.4g> %s exponent %s \n" % (
+                pat.julia_complex_1,
+                pat.julia_complex_2,
+                pat.f_iter,
+                pat.f_exponent,
+            )
+        if pat.tex_pattern_type == "magnet" and pat.magnet_style == "mandel":
+            text_strg += "%s mandel %s \n" % (pat.magnet_type, pat.f_iter)
+        if pat.tex_pattern_type == "magnet" and pat.magnet_style == "julia":
+            text_strg += "%s julia <%.4g, %.4g> %s\n" % (
+                pat.magnet_type,
+                pat.julia_complex_1,
+                pat.julia_complex_2,
+                pat.f_iter,
+            )
+        if pat.tex_pattern_type in {"mandel", "julia", "magnet"}:
+            text_strg += "interior %s, %.4g\n" % (pat.f_ior, pat.f_ior_fac)
+            text_strg += "exterior %s, %.4g\n" % (pat.f_eor, pat.f_eor_fac)
+        if pat.tex_pattern_type == "gradient":
+            text_strg += "<%s, %s, %s> \n" % (
+                pat.grad_orient_x,
+                pat.grad_orient_y,
+                pat.grad_orient_z,
+            )
+        if pat.tex_pattern_type == "pavement":
+            num_tiles = pat.pave_tiles
+            num_pattern = 1
+            if pat.pave_sides == "4" and pat.pave_tiles == 3:
+                num_pattern = pat.pave_pat_2
+            if pat.pave_sides == "6" and pat.pave_tiles == 3:
+                num_pattern = pat.pave_pat_3
+            if pat.pave_sides == "3" and pat.pave_tiles == 4:
+                num_pattern = pat.pave_pat_3
+            if pat.pave_sides == "3" and pat.pave_tiles == 5:
+                num_pattern = pat.pave_pat_4
+            if pat.pave_sides == "4" and pat.pave_tiles == 4:
+                num_pattern = pat.pave_pat_5
+            if pat.pave_sides == "6" and pat.pave_tiles == 4:
+                num_pattern = pat.pave_pat_7
+            if pat.pave_sides == "4" and pat.pave_tiles == 5:
+                num_pattern = pat.pave_pat_12
+            if pat.pave_sides == "3" and pat.pave_tiles == 6:
+                num_pattern = pat.pave_pat_12
+            if pat.pave_sides == "6" and pat.pave_tiles == 5:
+                num_pattern = pat.pave_pat_22
+            if pat.pave_sides == "4" and pat.pave_tiles == 6:
+                num_pattern = pat.pave_pat_35
+            if pat.pave_sides == "6" and pat.pave_tiles == 6:
+                num_tiles = 5
+            text_strg += "number_of_sides %s number_of_tiles %s pattern %s form %s \n" % (
+                pat.pave_sides,
+                num_tiles,
+                num_pattern,
+                pat.pave_form,
+            )
+        ################ functions ##########################################################
+        if pat.tex_pattern_type == "function":
+            text_strg += "{ %s" % pat.func_list
+            text_strg += "(x"
             if pat.func_plus_x != "NONE":
-                if pat.func_plus_x =='increase':
-                    texStrg+="*"
-                if pat.func_plus_x =='plus':
-                    texStrg+="+"
-                texStrg+="%.4g"%pat.func_x
-            texStrg+=",y"
+                if pat.func_plus_x == "increase":
+                    text_strg += "*"
+                if pat.func_plus_x == "plus":
+                    text_strg += "+"
+                text_strg += "%.4g" % pat.func_x
+            text_strg += ",y"
             if pat.func_plus_y != "NONE":
-                if pat.func_plus_y =='increase':
-                    texStrg+="*"
-                if pat.func_plus_y =='plus':
-                    texStrg+="+"
-                texStrg+="%.4g"%pat.func_y
-            texStrg+=",z"
+                if pat.func_plus_y == "increase":
+                    text_strg += "*"
+                if pat.func_plus_y == "plus":
+                    text_strg += "+"
+                text_strg += "%.4g" % pat.func_y
+            text_strg += ",z"
             if pat.func_plus_z != "NONE":
-                if pat.func_plus_z =='increase':
-                    texStrg+="*"
-                if pat.func_plus_z =='plus':
-                    texStrg+="+"
-                texStrg+="%.4g"%pat.func_z
+                if pat.func_plus_z == "increase":
+                    text_strg += "*"
+                if pat.func_plus_z == "plus":
+                    text_strg += "+"
+                text_strg += "%.4g" % pat.func_z
             sort = -1
-            if pat.func_list in {"f_comma","f_crossed_trough","f_cubic_saddle","f_cushion","f_devils_curve",
-                                 "f_enneper","f_glob","f_heart","f_hex_x","f_hex_y","f_hunt_surface",
-                                 "f_klein_bottle","f_kummer_surface_v1","f_lemniscate_of_gerono","f_mitre",
-                                 "f_nodal_cubic","f_noise_generator","f_odd","f_paraboloid","f_pillow",
-                                 "f_piriform","f_quantum","f_quartic_paraboloid","f_quartic_saddle",
-                                 "f_sphere","f_steiners_roman","f_torus_gumdrop","f_umbrella"}:
+            if pat.func_list in {
+                "f_comma",
+                "f_crossed_trough",
+                "f_cubic_saddle",
+                "f_cushion",
+                "f_devils_curve",
+                "f_enneper",
+                "f_glob",
+                "f_heart",
+                "f_hex_x",
+                "f_hex_y",
+                "f_hunt_surface",
+                "f_klein_bottle",
+                "f_kummer_surface_v1",
+                "f_lemniscate_of_gerono",
+                "f_mitre",
+                "f_nodal_cubic",
+                "f_noise_generator",
+                "f_odd",
+                "f_paraboloid",
+                "f_pillow",
+                "f_piriform",
+                "f_quantum",
+                "f_quartic_paraboloid",
+                "f_quartic_saddle",
+                "f_sphere",
+                "f_steiners_roman",
+                "f_torus_gumdrop",
+                "f_umbrella",
+            }:
                 sort = 0
-            if pat.func_list in {"f_bicorn","f_bifolia","f_boy_surface","f_superellipsoid","f_torus"}:
+            if pat.func_list in {
+                "f_bicorn",
+                "f_bifolia",
+                "f_boy_surface",
+                "f_superellipsoid",
+                "f_torus",
+            }:
                 sort = 1
-            if pat.func_list in {"f_ellipsoid","f_folium_surface","f_hyperbolic_torus",
-                                 "f_kampyle_of_eudoxus","f_parabolic_torus","f_quartic_cylinder","f_torus2"}:
+            if pat.func_list in {
+                "f_ellipsoid",
+                "f_folium_surface",
+                "f_hyperbolic_torus",
+                "f_kampyle_of_eudoxus",
+                "f_parabolic_torus",
+                "f_quartic_cylinder",
+                "f_torus2",
+            }:
                 sort = 2
-            if pat.func_list in {"f_blob2","f_cross_ellipsoids","f_flange_cover","f_isect_ellipsoids",
-                                 "f_kummer_surface_v2","f_ovals_of_cassini","f_rounded_box","f_spikes_2d","f_strophoid"}:
+            if pat.func_list in {
+                "f_blob2",
+                "f_cross_ellipsoids",
+                "f_flange_cover",
+                "f_isect_ellipsoids",
+                "f_kummer_surface_v2",
+                "f_ovals_of_cassini",
+                "f_rounded_box",
+                "f_spikes_2d",
+                "f_strophoid",
+            }:
                 sort = 3
-            if pat.func_list in {"f_algbr_cyl1","f_algbr_cyl2","f_algbr_cyl3","f_algbr_cyl4","f_blob","f_mesh1","f_poly4","f_spikes"}:
+            if pat.func_list in {
+                "f_algbr_cyl1",
+                "f_algbr_cyl2",
+                "f_algbr_cyl3",
+                "f_algbr_cyl4",
+                "f_blob",
+                "f_mesh1",
+                "f_poly4",
+                "f_spikes",
+            }:
                 sort = 4
-            if pat.func_list in {"f_devils_curve_2d","f_dupin_cyclid","f_folium_surface_2d","f_hetero_mf","f_kampyle_of_eudoxus_2d",
-                                 "f_lemniscate_of_gerono_2d","f_polytubes","f_ridge","f_ridged_mf","f_spiral","f_witch_of_agnesi"}:
+            if pat.func_list in {
+                "f_devils_curve_2d",
+                "f_dupin_cyclid",
+                "f_folium_surface_2d",
+                "f_hetero_mf",
+                "f_kampyle_of_eudoxus_2d",
+                "f_lemniscate_of_gerono_2d",
+                "f_polytubes",
+                "f_ridge",
+                "f_ridged_mf",
+                "f_spiral",
+                "f_witch_of_agnesi",
+            }:
                 sort = 5
-            if pat.func_list in {"f_helix1","f_helix2","f_piriform_2d","f_strophoid_2d"}:
+            if pat.func_list in {"f_helix1", "f_helix2", "f_piriform_2d", "f_strophoid_2d"}:
                 sort = 6
             if pat.func_list == "f_helical_torus":
                 sort = 7
             if sort > -1:
-                texStrg+=",%.4g"%pat.func_P0
+                text_strg += ",%.4g" % pat.func_P0
             if sort > 0:
-                texStrg+=",%.4g"%pat.func_P1
+                text_strg += ",%.4g" % pat.func_P1
             if sort > 1:
-                texStrg+=",%.4g"%pat.func_P2
+                text_strg += ",%.4g" % pat.func_P2
             if sort > 2:
-                texStrg+=",%.4g"%pat.func_P3
+                text_strg += ",%.4g" % pat.func_P3
             if sort > 3:
-                texStrg+=",%.4g"%pat.func_P4
+                text_strg += ",%.4g" % pat.func_P4
             if sort > 4:
-                texStrg+=",%.4g"%pat.func_P5
+                text_strg += ",%.4g" % pat.func_P5
             if sort > 5:
-                texStrg+=",%.4g"%pat.func_P6
+                text_strg += ",%.4g" % pat.func_P6
             if sort > 6:
-                texStrg+=",%.4g"%pat.func_P7
-                texStrg+=",%.4g"%pat.func_P8
-                texStrg+=",%.4g"%pat.func_P9
-            texStrg+=")}\n"
+                text_strg += ",%.4g" % pat.func_P7
+                text_strg += ",%.4g" % pat.func_P8
+                text_strg += ",%.4g" % pat.func_P9
+            text_strg += ")}\n"
         ############## end functions ###############################################################
-        if pat.tex_pattern_type not in {'checker', 'hexagon', 'square', 'triangular', 'brick'}:
-            texStrg+="color_map {\n"
-        numColor=0
-        if tex.use_color_ramp == True:
+        if pat.tex_pattern_type not in {"checker", "hexagon", "square", "triangular", "brick"}:
+            text_strg += "color_map {\n"
+        num_color = 0
+        if tex.use_color_ramp:
             for el in tex.color_ramp.elements:
-                numColor+=1
+                num_color += 1
                 pos = el.position
-                col=el.color
-                colR,colG,colB,colA = col[0],col[1],col[2],1-col[3]
-                if pat.tex_pattern_type not in {'checker', 'hexagon', 'square', 'triangular', 'brick'} :
-                    texStrg+="[%.4g color rgbf<%.4g,%.4g,%.4g,%.4g>] \n"%(pos,colR,colG,colB,colA)
-                if pat.tex_pattern_type in {'brick','checker'} and numColor < 3:
-                    texStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
-                if pat.tex_pattern_type == 'hexagon' and numColor < 4 :
-                    texStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
-                if pat.tex_pattern_type == 'square' and numColor < 5 :
-                    texStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
-                if pat.tex_pattern_type == 'triangular' and numColor < 7 :
-                    texStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
+                col = el.color
+                col_r, col_g, col_b, col_a = col[0], col[1], col[2], 1 - col[3]
+                if pat.tex_pattern_type not in {
+                    "checker",
+                    "hexagon",
+                    "square",
+                    "triangular",
+                    "brick",
+                }:
+                    text_strg += "[%.4g color rgbf<%.4g,%.4g,%.4g,%.4g>] \n" % (
+                        pos,
+                        col_r,
+                        col_g,
+                        col_b,
+                        col_a,
+                    )
+                if pat.tex_pattern_type in {"brick", "checker"} and num_color < 3:
+                    text_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
+                if pat.tex_pattern_type == "hexagon" and num_color < 4:
+                    text_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
+                if pat.tex_pattern_type == "square" and num_color < 5:
+                    text_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
+                if pat.tex_pattern_type == "triangular" and num_color < 7:
+                    text_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
         else:
-            texStrg+="[0 color rgbf<0,0,0,1>]\n"
-            texStrg+="[1 color rgbf<1,1,1,0>]\n"
-        if pat.tex_pattern_type not in {'checker', 'hexagon', 'square', 'triangular', 'brick'} :
-            texStrg+="} \n"
-        if pat.tex_pattern_type == 'brick':
-            texStrg+="brick_size <%.4g, %.4g, %.4g> mortar %.4g \n"%(pat.brick_size_x, pat.brick_size_y, pat.brick_size_z, pat.brick_mortar)
-        texStrg+="%s \n"%mappingDif
-        texStrg+="rotate <%.4g,%.4g,%.4g> \n"%(pat.tex_rot_x, pat.tex_rot_y, pat.tex_rot_z)
-        texStrg+="turbulence <%.4g,%.4g,%.4g> \n"%(pat.warp_turbulence_x, pat.warp_turbulence_y, pat.warp_turbulence_z)
-        texStrg+="octaves %s \n"%pat.modifier_octaves
-        texStrg+="lambda %.4g \n"%pat.modifier_lambda
-        texStrg+="omega %.4g \n"%pat.modifier_omega
-        texStrg+="frequency %.4g \n"%pat.modifier_frequency
-        texStrg+="phase %.4g \n"%pat.modifier_phase
-        texStrg+="}\n\n"
-        texStrg+="#declare f%s=\n"%PATname
-        texStrg+="function{pigment{%s}}\n"%PATname
-        texStrg+="\n"
-    return(texStrg)
-
-
-def writeTextureInfluence(using_uberpov, mater, materialNames, LocalMaterialNames, path_image, lampCount,
-                            imageFormat, imgMap, imgMapTransforms, tabWrite, comments,
-                            string_strip_hyphen, safety, col, os, preview_dir, unpacked_images):
-    """Translate Blender texture influences to various POV texture tricks and write to pov file."""
-
-    material_finish = materialNames[mater.name]
-    if mater.pov.use_transparency:
-        trans = 1.0 - mater.pov.alpha
-    else:
-        trans = 0.0
-    if ((mater.pov.specular_color.s == 0.0) or (mater.pov.diffuse_shader == 'MINNAERT')):
-    # No layered texture because of aoi pattern used for minnaert and pov can't layer patterned
-        colored_specular_found = False
-    else:
-        colored_specular_found = True
-
-    if mater.pov.use_transparency and mater.pov.transparency_method == 'RAYTRACE':
-        povFilter = mater.pov_raytrace_transparency.filter * (1.0 - mater.pov.alpha)
-        trans = (1.0 - mater.pov.alpha) - povFilter
-    else:
-        povFilter = 0.0
-
-    ##############SF
-    texturesDif = ""
-    texturesSpec = ""
-    texturesNorm = ""
-    texturesAlpha = ""
-    #proceduralFlag=False
-    tmpidx = -1
-    for t in mater.pov_texture_slots:
-
-
-        tmpidx += 1
-        # index = mater.pov.active_texture_index
-        slot = mater.pov_texture_slots[tmpidx] # [index]
-        povtex = slot.texture # slot.name
-        tex = bpy.data.textures[povtex]
-
-        if t and (t.use and (tex is not None)):
-            # 'NONE' ('NONE' type texture is different from no texture covered above)
-            if (tex.type == 'NONE' and tex.pov.tex_pattern_type == 'emulator'):
-                continue # move to next slot
-            # PROCEDURAL
-            elif (tex.type != 'IMAGE' and tex.type != 'NONE'):
-                proceduralFlag=True
-                image_filename = "PAT_%s"%string_strip_hyphen(bpy.path.clean_name(tex.name))
-                if image_filename:
-                    if t.use_map_color_diffuse:
-                        texturesDif = image_filename
-                        # colvalue = t.default_value  # UNUSED
-                        t_dif = t
-                        if t_dif.texture.pov.tex_gamma_enable:
-                            imgGamma = (" gamma %.3g " % t_dif.texture.pov.tex_gamma_value)
-                    if t.use_map_specular or t.use_map_raymir:
-                        texturesSpec = image_filename
-                        # colvalue = t.default_value  # UNUSED
-                        t_spec = t
-                    if t.use_map_normal:
-                        texturesNorm = image_filename
-                        # colvalue = t.normal_factor/10 # UNUSED
-                        #textNormName=tex.image.name + ".normal"
-                        #was the above used? --MR
-                        t_nor = t
-                    if t.use_map_alpha:
-                        texturesAlpha = image_filename
-                        # colvalue = t.alpha_factor * 10.0  # UNUSED
-                        #textDispName=tex.image.name + ".displ"
-                        #was the above used? --MR
-                        t_alpha = t
-
-            # RASTER IMAGE
-            elif (tex.type == 'IMAGE' and tex.image and tex.pov.tex_pattern_type == 'emulator'):
-                proceduralFlag=False
-                #PACKED
-                if tex.image.packed_file:
-                    orig_image_filename=tex.image.filepath_raw
-                    unpackedfilename= os.path.join(preview_dir,("unpacked_img_"+(string_strip_hyphen(bpy.path.clean_name(tex.name)))))
-                    if not os.path.exists(unpackedfilename):
-                        # record which images that were newly copied and can be safely
-                        # cleaned up
-                        unpacked_images.append(unpackedfilename)
-                    tex.image.filepath_raw=unpackedfilename
-                    tex.image.save()
-                    image_filename = unpackedfilename.replace("\\","/")
-                    # .replace("\\","/") to get only forward slashes as it's what POV prefers,
-                    # even on windows
-                    tex.image.filepath_raw=orig_image_filename
-                #FILE
-                else:
-                    image_filename = path_image(tex.image)
-                # IMAGE SEQUENCE BEGINS
-                if image_filename:
-                    if bpy.data.images[tex.image.name].source == 'SEQUENCE':
-                        korvaa = "." + str(tex.image_user.frame_offset + 1).zfill(3) + "."
-                        image_filename = image_filename.replace(".001.", korvaa)
-                        print(" seq debug ")
-                        print(image_filename)
-                # IMAGE SEQUENCE ENDS
-                imgGamma = ""
-                if image_filename:
-                    texdata = bpy.data.textures[t.texture]
-                    if t.use_map_color_diffuse:
-                        texturesDif = image_filename
-                        # colvalue = t.default_value  # UNUSED
-                        t_dif = t
-                        print (texdata)
-                        if texdata.pov.tex_gamma_enable:
-                            imgGamma = (" gamma %.3g " % t_dif.texture.pov.tex_gamma_value)
-                    if t.use_map_specular or t.use_map_raymir:
-                        texturesSpec = image_filename
-                        # colvalue = t.default_value  # UNUSED
-                        t_spec = t
-                    if t.use_map_normal:
-                        texturesNorm = image_filename
-                        # colvalue = t.normal_factor/10  # UNUSED
-                        #textNormName=tex.image.name + ".normal"
-                        #was the above used? --MR
-                        t_nor = t
-                    if t.use_map_alpha:
-                        texturesAlpha = image_filename
-                        # colvalue = t.alpha_factor * 10.0  # UNUSED
-                        #textDispName=tex.image.name + ".displ"
-                        #was the above used? --MR
-                        t_alpha = t
-
-    ####################################################################################
-
-
-    tabWrite("\n")
-    # THIS AREA NEEDS TO LEAVE THE TEXTURE OPEN UNTIL ALL MAPS ARE WRITTEN DOWN.
-    # --MR
-    currentMatName = string_strip_hyphen(materialNames[mater.name])
-    LocalMaterialNames.append(currentMatName)
-    tabWrite("\n#declare MAT_%s = \ntexture{\n" % currentMatName)
-    ################################################################################
-
-    if mater.pov.replacement_text != "":
-        tabWrite("%s\n" % mater.pov.replacement_text)
-    #################################################################################
-    # XXX TODO: replace by new POV MINNAERT rather than aoi
-    if mater.pov.diffuse_shader == 'MINNAERT':
-        tabWrite("\n")
-        tabWrite("aoi\n")
-        tabWrite("texture_map {\n")
-        tabWrite("[%.3g finish {diffuse %.3g}]\n" % \
-                 (mater.darkness / 2.0, 2.0 - mater.darkness))
-        tabWrite("[%.3g\n" % (1.0 - (mater.darkness / 2.0)))
-
-    if mater.pov.diffuse_shader == 'FRESNEL':
-        # For FRESNEL diffuse in POV, we'll layer slope patterned textures
-        # with lamp vector as the slope vector and nest one slope per lamp
-        # into each texture map's entry.
-
-        c = 1
-        while (c <= lampCount):
-            tabWrite("slope { lampTarget%s }\n" % (c))
-            tabWrite("texture_map {\n")
-            # Diffuse Fresnel value and factor go up to five,
-            # other kind of values needed: used the number 5 below to remap
-            tabWrite("[%.3g finish {diffuse %.3g}]\n" % \
-                     ((5.0 - mater.diffuse_fresnel) / 5,
-                      (mater.diffuse_intensity *
-                       ((5.0 - mater.diffuse_fresnel_factor) / 5))))
-            tabWrite("[%.3g\n" % ((mater.diffuse_fresnel_factor / 5) *
-                                  (mater.diffuse_fresnel / 5.0)))
-            c += 1
-
-    # if shader is a 'FRESNEL' or 'MINNAERT': slope pigment pattern or aoi
-    # and texture map above, the rest below as one of its entry
-
-    if texturesSpec != "" or texturesAlpha != "":
-        if texturesSpec != "":
-            # tabWrite("\n")
-            tabWrite("pigment_pattern {\n")
-
-            mappingSpec =imgMapTransforms(t_spec)
-            if texturesSpec and texturesSpec.startswith("PAT_"):
-                tabWrite("function{f%s(x,y,z).grey}\n" %texturesSpec)
-                tabWrite("%s\n" % mappingSpec)
-            else:
-
-                tabWrite("uv_mapping image_map{%s \"%s\" %s}\n" % \
-                         (imageFormat(texturesSpec), texturesSpec, imgMap(t_spec)))
-                tabWrite("%s\n" % mappingSpec)
-            tabWrite("}\n")
-            tabWrite("texture_map {\n")
-            tabWrite("[0 \n")
-
-        if texturesDif == "":
-            if texturesAlpha != "":
-                tabWrite("\n")
+            text_strg += "[0 color rgbf<0,0,0,1>]\n"
+            text_strg += "[1 color rgbf<1,1,1,0>]\n"
+        if pat.tex_pattern_type not in {"checker", "hexagon", "square", "triangular", "brick"}:
+            text_strg += "} \n"
+        if pat.tex_pattern_type == "brick":
+            text_strg += "brick_size <%.4g, %.4g, %.4g> mortar %.4g \n" % (
+                pat.brick_size_x,
+                pat.brick_size_y,
+                pat.brick_size_z,
+                pat.brick_mortar,
+            )
+        text_strg += "%s \n" % mapping_dif
+        text_strg += "rotate <%.4g,%.4g,%.4g> \n" % (pat.tex_rot_x, pat.tex_rot_y, pat.tex_rot_z)
+        text_strg += "turbulence <%.4g,%.4g,%.4g> \n" % (
+            pat.warp_turbulence_x,
+            pat.warp_turbulence_y,
+            pat.warp_turbulence_z,
+        )
+        text_strg += "octaves %s \n" % pat.modifier_octaves
+        text_strg += "lambda %.4g \n" % pat.modifier_lambda
+        text_strg += "omega %.4g \n" % pat.modifier_omega
+        text_strg += "frequency %.4g \n" % pat.modifier_frequency
+        text_strg += "phase %.4g \n" % pat.modifier_phase
+        text_strg += "}\n\n"
+        text_strg += "#declare f%s=\n" % pat_name
+        text_strg += "function{pigment{%s}}\n" % pat_name
+        text_strg += "\n"
+    return text_strg
 
-                mappingAlpha = imgMapTransforms(t_alpha)
-
-                if texturesAlpha and texturesAlpha.startswith("PAT_"):
-                    tabWrite("function{f%s(x,y,z).transmit}%s\n" %(texturesAlpha, mappingAlpha))
-                else:
-
-                    tabWrite("pigment {pigment_pattern {uv_mapping image_map" \
-                             "{%s \"%s\" %s}%s" % \
-                             (imageFormat(texturesAlpha), texturesAlpha,
-                              imgMap(t_alpha), mappingAlpha))
-                tabWrite("}\n")
-                tabWrite("pigment_map {\n")
-                tabWrite("[0 color rgbft<0,0,0,1,1>]\n")
-                tabWrite("[1 color rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>]\n" % \
-                         (col[0], col[1], col[2], povFilter, trans))
-                tabWrite("}\n")
-                tabWrite("}\n")
-
-            else:
-
-                tabWrite("pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>}\n" % \
-                         (col[0], col[1], col[2], povFilter, trans))
-
-            if texturesSpec != "":
-                # Level 1 is no specular
-                tabWrite("finish {%s}\n" % (safety(material_finish, Level=1)))
-
-            else:
-                # Level 2 is translated spec
-                tabWrite("finish {%s}\n" % (safety(material_finish, Level=2)))
-
-        else:
-            mappingDif = imgMapTransforms(t_dif)
-
-            if texturesAlpha != "":
-                mappingAlpha = imgMapTransforms(t_alpha)
-
-                tabWrite("pigment {\n")
-                tabWrite("pigment_pattern {\n")
-                if texturesAlpha and texturesAlpha.startswith("PAT_"):
-                    tabWrite("function{f%s(x,y,z).transmit}%s\n" %(texturesAlpha, mappingAlpha))
-                else:
-                    tabWrite("uv_mapping image_map{%s \"%s\" %s}%s}\n" % \
-                             (imageFormat(texturesAlpha), texturesAlpha,
-                              imgMap(t_alpha), mappingAlpha))
-                tabWrite("pigment_map {\n")
-                tabWrite("[0 color rgbft<0,0,0,1,1>]\n")
-                #if texturesAlpha and texturesAlpha.startswith("PAT_"):
-                    #tabWrite("[1 pigment{%s}]\n" %texturesDif)
-                if texturesDif and not texturesDif.startswith("PAT_"):
-                    tabWrite("[1 uv_mapping image_map {%s \"%s\" %s} %s]\n" % \
-                             (imageFormat(texturesDif), texturesDif,
-                              (imgGamma + imgMap(t_dif)), mappingDif))
-                elif texturesDif and texturesDif.startswith("PAT_"):
-                    tabWrite("[1 %s]\n" %texturesDif)
-                tabWrite("}\n")
-                tabWrite("}\n")
-                if texturesAlpha and texturesAlpha.startswith("PAT_"):
-                    tabWrite("}\n")
-
-            else:
-                if texturesDif and texturesDif.startswith("PAT_"):
-                    tabWrite("pigment{%s}\n" %texturesDif)
-                else:
-                    tabWrite("pigment {uv_mapping image_map {%s \"%s\" %s}%s}\n" % \
-                             (imageFormat(texturesDif), texturesDif,
-                              (imgGamma + imgMap(t_dif)), mappingDif))
-
-            if texturesSpec != "":
-                # Level 1 is no specular
-                tabWrite("finish {%s}\n" % (safety(material_finish, Level=1)))
-
-            else:
-                # Level 2 is translated specular
-                tabWrite("finish {%s}\n" % (safety(material_finish, Level=2)))
-
-            ## scale 1 rotate y*0
-            #imageMap = ("{image_map {%s \"%s\" %s }\n" % \
-            #            (imageFormat(textures),textures,imgMap(t_dif)))
-            #tabWrite("uv_mapping pigment %s} %s finish {%s}\n" % \
-            #         (imageMap,mapping,safety(material_finish)))
-            #tabWrite("pigment {uv_mapping image_map {%s \"%s\" %s}%s} " \
-            #         "finish {%s}\n" % \
-            #         (imageFormat(texturesDif), texturesDif, imgMap(t_dif),
-            #          mappingDif, safety(material_finish)))
-        if texturesNorm != "":
-            ## scale 1 rotate y*0
-
-            mappingNor =imgMapTransforms(t_nor)
-
-            if texturesNorm and texturesNorm.startswith("PAT_"):
-                tabWrite("normal{function{f%s(x,y,z).grey} bump_size %.4g %s}\n" %(texturesNorm, ( - t_nor.normal_factor * 9.5), mappingNor))
-            else:
-                tabWrite("normal {\n")
-                # XXX TODO: fix and propagate the micro normals reflection blur below to non textured materials
-                if (mater.pov_raytrace_mirror.use and mater.pov_raytrace_mirror.gloss_factor < 1.0 and not using_uberpov):
-                    tabWrite("average\n")
-                    tabWrite("normal_map{\n")
-                    # 0.5 for entries below means a 50 percent mix
-                    # between the micro normal and user bump map
-                    # order seems indifferent as commutative
-                    tabWrite("[0.025 bumps %.4g scale 0.1*%.4g]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(10/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                    tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.1]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                    tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.15]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                    tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.2]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                    tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.25]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                    tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.3]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                    tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.35]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                    tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.4]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                    tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.45]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                    tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.5]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                    tabWrite("[1.0 ") # Proceed with user bump...
-                tabWrite("uv_mapping bump_map " \
-                         "{%s \"%s\" %s  bump_size %.4g }%s" % \
-                         (imageFormat(texturesNorm), texturesNorm, imgMap(t_nor),
-                          ( - t_nor.normal_factor * 9.5), mappingNor))
-                # ...Then close its last entry and the the normal_map itself
-                if (mater.pov_raytrace_mirror.use and mater.pov_raytrace_mirror.gloss_factor < 1.0 and not using_uberpov):
-                    tabWrite("]}}\n")
-                else:
-                    tabWrite("]}\n")
-        if texturesSpec != "":
-            tabWrite("]\n")
-        ##################Second index for mapping specular max value###############
-            tabWrite("[1 \n")
-
-    if texturesDif == "" and mater.pov.replacement_text == "":
-        if texturesAlpha != "":
-            mappingAlpha = imgMapTransforms(t_alpha)
-
-            if texturesAlpha and texturesAlpha.startswith("PAT_"):
-                tabWrite("function{f%s(x,y,z).transmit %s}\n" %(texturesAlpha, mappingAlpha))
-            else:
-                tabWrite("pigment {pigment_pattern {uv_mapping image_map" \
-                         "{%s \"%s\" %s}%s}\n" % \
-                         (imageFormat(texturesAlpha), texturesAlpha, imgMap(t_alpha),
-                          mappingAlpha))
-            tabWrite("pigment_map {\n")
-            tabWrite("[0 color rgbft<0,0,0,1,1>]\n")
-            tabWrite("[1 color rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>]\n" % \
-                     (col[0], col[1], col[2], povFilter, trans))
-            tabWrite("}\n")
-            tabWrite("}\n")
-
-        else:
-            tabWrite("pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>}\n" % \
-                     (col[0], col[1], col[2], povFilter, trans))
-
-
-        if texturesSpec != "":
-            # Level 3 is full specular
-            tabWrite("finish {%s}\n" % (safety(material_finish, Level=3)))
-
-            if mater.pov_raytrace_mirror.use and mater.pov_raytrace_mirror.gloss_factor < 1.0 and not using_uberpov:
-                tabWrite("normal {\n")
-                tabWrite("average\n")
-                tabWrite("normal_map{\n")
-                # 0.5 for entries below means a 50 percent mix
-                # between the micro normal and user bump map
-                # order seems indifferent as commutative
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(10/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.1]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.15]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.2]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.25]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.3]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.35]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.4]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.45]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.5]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-            #XXX IF USER BUMP_MAP
-            if texturesNorm != "":
-                tabWrite("[1.0 ") # Blurry reflection or not Proceed with user bump in either case...
-                tabWrite("uv_mapping bump_map " \
-                         "{%s \"%s\" %s  bump_size %.4g }%s]\n" % \
-                         (imageFormat(texturesNorm), texturesNorm, imgMap(t_nor),
-                          ( - t_nor.normal_factor * 9.5), mappingNor))
-            # ...Then close the normal_map itself if blurry reflection
-            if mater.pov_raytrace_mirror.use and mater.pov_raytrace_mirror.gloss_factor < 1.0 and not using_uberpov:
-                tabWrite("}}\n")
-            else:
-                tabWrite("}\n")
-        elif colored_specular_found:
-            # Level 1 is no specular
-            tabWrite("finish {%s}\n" % (safety(material_finish, Level=1)))
-
-        else:
-            # Level 2 is translated specular
-            tabWrite("finish {%s}\n" % (safety(material_finish, Level=2)))
-
-    elif mater.pov.replacement_text == "":
-        mappingDif = imgMapTransforms(t_dif)
-
-        if texturesAlpha != "":
-
-            mappingAlpha = imgMapTransforms(t_alpha)
-
-            if texturesAlpha and texturesAlpha.startswith("PAT_"):
-                tabWrite("pigment{pigment_pattern {function{f%s(x,y,z).transmit}%s}\n" %(texturesAlpha, mappingAlpha))
-            else:
-                tabWrite("pigment {pigment_pattern {uv_mapping image_map" \
-                         "{%s \"%s\" %s}%s}\n" % \
-                         (imageFormat(texturesAlpha), texturesAlpha, imgMap(t_alpha),
-                          mappingAlpha))
-            tabWrite("pigment_map {\n")
-            tabWrite("[0 color rgbft<0,0,0,1,1>]\n")
-            if texturesAlpha and texturesAlpha.startswith("PAT_"):
-                tabWrite("[1 function{f%s(x,y,z).transmit}%s]\n" %(texturesAlpha, mappingAlpha))
-            elif texturesDif and not texturesDif.startswith("PAT_"):
-                tabWrite("[1 uv_mapping image_map {%s \"%s\" %s} %s]\n" % \
-                         (imageFormat(texturesDif), texturesDif,
-                          (imgMap(t_dif) + imgGamma), mappingDif))
-            elif texturesDif and texturesDif.startswith("PAT_"):
-                tabWrite("[1 %s %s]\n" %(texturesDif, mappingDif))
-            tabWrite("}\n")
-            tabWrite("}\n")
-
-        else:
-            if texturesDif and texturesDif.startswith("PAT_"):
-                tabWrite("pigment{%s %s}\n" %(texturesDif, mappingDif))
-            else:
-                tabWrite("pigment {\n")
-                tabWrite("uv_mapping image_map {\n")
-                #tabWrite("%s \"%s\" %s}%s\n" % \
-                #         (imageFormat(texturesDif), texturesDif,
-                #         (imgGamma + imgMap(t_dif)),mappingDif))
-                tabWrite("%s \"%s\" \n" % (imageFormat(texturesDif), texturesDif))
-                tabWrite("%s\n" % (imgGamma + imgMap(t_dif)))
-                tabWrite("}\n")
-                tabWrite("%s\n" % mappingDif)
-                tabWrite("}\n")
-
-        if texturesSpec != "":
-            # Level 3 is full specular
-            tabWrite("finish {%s}\n" % (safety(material_finish, Level=3)))
-        else:
-            # Level 2 is translated specular
-            tabWrite("finish {%s}\n" % (safety(material_finish, Level=2)))
-
-        ## scale 1 rotate y*0
-        #imageMap = ("{image_map {%s \"%s\" %s }" % \
-        #            (imageFormat(textures), textures,imgMap(t_dif)))
-        #tabWrite("\n\t\t\tuv_mapping pigment %s} %s finish {%s}" % \
-        #           (imageMap, mapping, safety(material_finish)))
-        #tabWrite("\n\t\t\tpigment {uv_mapping image_map " \
-        #           "{%s \"%s\" %s}%s} finish {%s}" % \
-        #           (imageFormat(texturesDif), texturesDif,imgMap(t_dif),
-        #            mappingDif, safety(material_finish)))
-    if texturesNorm != "" and mater.pov.replacement_text == "":
-
-
-        mappingNor =imgMapTransforms(t_nor)
-
-        if texturesNorm and texturesNorm.startswith("PAT_"):
-            tabWrite("normal{function{f%s(x,y,z).grey} bump_size %.4g %s}\n" %(texturesNorm, ( - t_nor.normal_factor * 9.5), mappingNor))
-        else:
-            tabWrite("normal {\n")
-            # XXX TODO: fix and propagate the micro normals reflection blur below to non textured materials
-            if mater.pov_raytrace_mirror.use and mater.pov_raytrace_mirror.gloss_factor < 1.0 and not using_uberpov:
-                tabWrite("average\n")
-                tabWrite("normal_map{\n")
-                # 0.5 for entries below means a 50 percent mix
-                # between the micro normal and user bump map
-                # order seems indifferent as commutative
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(10/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.1]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.15]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.2]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.25]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.3]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.35]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.4]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.45]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.5]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
-                tabWrite("[1.0 ") # Blurry reflection or not Proceed with user bump in either case...
-            tabWrite("uv_mapping bump_map " \
-                     "{%s \"%s\" %s  bump_size %.4g }%s]\n" % \
-                     (imageFormat(texturesNorm), texturesNorm, imgMap(t_nor),
-                      ( - t_nor.normal_factor * 9.5), mappingNor))
-            # ...Then close the normal_map itself if blurry reflection
-            if mater.pov_raytrace_mirror.use and mater.pov_raytrace_mirror.gloss_factor < 1.0 and not using_uberpov:
-                tabWrite("}}\n")
-            else:
-                tabWrite("}\n")
-    if texturesSpec != "" and mater.pov.replacement_text == "":
-        tabWrite("]\n")
-
-        tabWrite("}\n")
-
-    #End of slope/ior texture_map
-    if mater.pov.diffuse_shader == 'MINNAERT' and mater.pov.replacement_text == "":
-        tabWrite("]\n")
-        tabWrite("}\n")
-    if mater.pov.diffuse_shader == 'FRESNEL' and mater.pov.replacement_text == "":
-        c = 1
-        while (c <= lampCount):
-            tabWrite("]\n")
-            tabWrite("}\n")
-            c += 1
-
-
-
-    # Close first layer of POV "texture" (Blender material)
-    tabWrite("}\n")
-
-    if ((mater.pov.specular_color.s > 0.0) and (mater.pov.diffuse_shader != 'MINNAERT')):
-
-        colored_specular_found = True
-    else:
-        colored_specular_found = False
-
-    # Write another layered texture using invisible diffuse and metallic trick
-    # to emulate colored specular highlights
-    special_texture_found = False
-    tmpidx = -1
-    for t in mater.pov_texture_slots:
-        tmpidx += 1
-        # index = mater.pov.active_texture_index
-        slot = mater.pov_texture_slots[tmpidx] # [index]
-        povtex = slot.texture # slot.name
-        tex = bpy.data.textures[povtex]
-        if(t and t.use and ((tex.type == 'IMAGE' and tex.image) or tex.type != 'IMAGE') and
-           (t.use_map_specular or t.use_map_raymir)):
-            # Specular mapped textures would conflict with colored specular
-            # because POV can't layer over or under pigment patterned textures
-            special_texture_found = True
-
-    if colored_specular_found and not special_texture_found:
-        if comments:
-            tabWrite("  // colored highlights with a stransparent metallic layer\n")
-        else:
-            tabWrite("\n")
-
-        tabWrite("texture {\n")
-        tabWrite("pigment {rgbft<%.3g, %.3g, %.3g, 0, 1>}\n" % \
-                         (mater.pov.specular_color[0], mater.pov.specular_color[1], mater.pov.specular_color[2]))
-        tabWrite("finish {%s}\n" % (safety(material_finish, Level=2))) # Level 2 is translated spec
-
-        texturesNorm = ""
-        for t in mater.pov_texture_slots:
-
-            if t and tex.pov.tex_pattern_type != 'emulator':
-                proceduralFlag=True
-                image_filename = string_strip_hyphen(bpy.path.clean_name(tex.name))
-            if (t and tex.type == 'IMAGE' and
-                    t.use and tex.image and
-                    tex.pov.tex_pattern_type == 'emulator'):
-                proceduralFlag=False
-                image_filename = path_image(tex.image)
-                imgGamma = ""
-                if image_filename:
-                    if t.use_map_normal:
-                        texturesNorm = image_filename
-                        # colvalue = t.normal_factor/10  # UNUSED   XXX *-9.5 !
-                        #textNormName=tex.image.name + ".normal"
-                        #was the above used? --MR
-                        t_nor = t
-                        if proceduralFlag:
-                            tabWrite("normal{function" \
-                                     "{f%s(x,y,z).grey} bump_size %.4g}\n" % \
-                                     (texturesNorm,
-                                     ( - t_nor.normal_factor * 9.5)))
-                        else:
-                            tabWrite("normal {uv_mapping bump_map " \
-                                     "{%s \"%s\" %s  bump_size %.4g }%s}\n" % \
-                                     (imageFormat(texturesNorm),
-                                     texturesNorm, imgMap(t_nor),
-                                     ( - t_nor.normal_factor * 9.5),
-                                     mappingNor))
-
-        tabWrite("}\n") # THEN IT CAN CLOSE LAST LAYER OF TEXTURE
 
 def string_strip_hyphen(name):
+    """POV naming schemes like to conform to most restrictive charsets."""
     return name.replace("-", "")
+
+
 # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-def write_nodes(scene,povMatName,ntree,file):
-    """translate Blender node trees to pov and write them to file"""
-    declareNodes=[]
-    scene=bpy.context.scene
+def write_nodes(scene, pov_mat_name, ntree, file):
+    """Translate Blender node trees to pov and write them to file."""
+    # such function local inlined import are official guidelines
+    # of Blender Foundation to lighten addons footprint at startup
+    from os import path
+
+    declare_nodes = []
+    scene = bpy.context.scene
     for node in ntree.nodes:
-        povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName
+        pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
         if node.bl_idname == "PovrayFinishNode" and node.outputs["Finish"].is_linked:
-            file.write('#declare %s = finish {\n'%povNodeName)
-            emission=node.inputs["Emission"].default_value
+            file.write("#declare %s = finish {\n" % pov_node_name)
+            emission = node.inputs["Emission"].default_value
             if node.inputs["Emission"].is_linked:
                 pass
-            file.write('    emission %.4g\n'%emission)
+            file.write("    emission %.4g\n" % emission)
             for link in ntree.links:
                 if link.to_node == node:
 
-                    if link.from_node.bl_idname == 'PovrayDiffuseNode':
-                        intensity=0
-                        albedo=""
-                        brilliance=0
-                        crand=0
+                    if link.from_node.bl_idname == "PovrayDiffuseNode":
+                        intensity = 0
+                        albedo = ""
+                        brilliance = 0
+                        crand = 0
                         if link.from_node.inputs["Intensity"].is_linked:
                             pass
                         else:
-                            intensity=link.from_node.inputs["Intensity"].default_value
+                            intensity = link.from_node.inputs["Intensity"].default_value
                         if link.from_node.inputs["Albedo"].is_linked:
                             pass
                         else:
-                            if link.from_node.inputs["Albedo"].default_value == True:
+                            if link.from_node.inputs["Albedo"].default_value:
                                 albedo = "albedo"
-                        file.write('    diffuse %s %.4g\n'%(albedo,intensity))
+                        file.write("    diffuse %s %.4g\n" % (albedo, intensity))
                         if link.from_node.inputs["Brilliance"].is_linked:
                             pass
                         else:
-                            brilliance=link.from_node.inputs["Brilliance"].default_value
-                        file.write('    brilliance %.4g\n'%brilliance)
+                            brilliance = link.from_node.inputs["Brilliance"].default_value
+                        file.write("    brilliance %.4g\n" % brilliance)
                         if link.from_node.inputs["Crand"].is_linked:
                             pass
                         else:
-                            crand=link.from_node.inputs["Crand"].default_value
+                            crand = link.from_node.inputs["Crand"].default_value
                         if crand > 0:
-                            file.write('    crand %.4g\n'%crand)
-
+                            file.write("    crand %.4g\n" % crand)
 
-                    if link.from_node.bl_idname == 'PovraySubsurfaceNode':
+                    if link.from_node.bl_idname == "PovraySubsurfaceNode":
                         if scene.povray.sslt_enable:
                             energy = 0
                             r = g = b = 0
                             if link.from_node.inputs["Translucency"].is_linked:
                                 pass
                             else:
-                                r,g,b,a=link.from_node.inputs["Translucency"].default_value[:]
+                                r, g, b, a = link.from_node.inputs["Translucency"].default_value[:]
                             if link.from_node.inputs["Energy"].is_linked:
                                 pass
                             else:
-                                energy=link.from_node.inputs["Energy"].default_value
-                            file.write('    subsurface { translucency <%.4g,%.4g,%.4g>*%s }\n'%(r,g,b,energy))
-
-
-
-                    if link.from_node.bl_idname in {'PovraySpecularNode','PovrayPhongNode'}:
-                        intensity=0
-                        albedo=""
-                        roughness=0
-                        metallic=0
-                        phong_size=0
-                        highlight="specular"
+                                energy = link.from_node.inputs["Energy"].default_value
+                            file.write(
+                                "    subsurface { translucency <%.4g,%.4g,%.4g>*%s }\n"
+                                % (r, g, b, energy)
+                            )
+
+                    if link.from_node.bl_idname in {"PovraySpecularNode", "PovrayPhongNode"}:
+                        intensity = 0
+                        albedo = ""
+                        roughness = 0
+                        metallic = 0
+                        phong_size = 0
+                        highlight = "specular"
                         if link.from_node.inputs["Intensity"].is_linked:
                             pass
                         else:
-                            intensity=link.from_node.inputs["Intensity"].default_value
+                            intensity = link.from_node.inputs["Intensity"].default_value
 
                         if link.from_node.inputs["Albedo"].is_linked:
                             pass
                         else:
-                            if link.from_node.inputs["Albedo"].default_value == True:
+                            if link.from_node.inputs["Albedo"].default_value:
                                 albedo = "albedo"
-                        if link.from_node.bl_idname in {'PovrayPhongNode'}:
-                            highlight="phong"
-                        file.write('    %s %s %.4g\n'%(highlight,albedo,intensity))
+                        if link.from_node.bl_idname in {"PovrayPhongNode"}:
+                            highlight = "phong"
+                        file.write("    %s %s %.4g\n" % (highlight, albedo, intensity))
 
-                        if link.from_node.bl_idname in {'PovraySpecularNode'}:
+                        if link.from_node.bl_idname in {"PovraySpecularNode"}:
                             if link.from_node.inputs["Roughness"].is_linked:
                                 pass
                             else:
-                                roughness=link.from_node.inputs["Roughness"].default_value
-                            file.write('    roughness %.6g\n'%roughness)
+                                roughness = link.from_node.inputs["Roughness"].default_value
+                            file.write("    roughness %.6g\n" % roughness)
 
-                        if link.from_node.bl_idname in {'PovrayPhongNode'}:
+                        if link.from_node.bl_idname in {"PovrayPhongNode"}:
                             if link.from_node.inputs["Size"].is_linked:
                                 pass
                             else:
-                                phong_size=link.from_node.inputs["Size"].default_value
-                            file.write('    phong_size %s\n'%phong_size)
+                                phong_size = link.from_node.inputs["Size"].default_value
+                            file.write("    phong_size %s\n" % phong_size)
 
                         if link.from_node.inputs["Metallic"].is_linked:
                             pass
                         else:
-                            metallic=link.from_node.inputs["Metallic"].default_value
-                        file.write('    metallic %.4g\n'%metallic)
-
-                    if link.from_node.bl_idname in {'PovrayMirrorNode'}:
-                        file.write('    reflection {\n')
-                        color=None
-                        exponent=0
-                        metallic=0
-                        falloff=0
-                        fresnel=""
-                        conserve=""
+                            metallic = link.from_node.inputs["Metallic"].default_value
+                        file.write("    metallic %.4g\n" % metallic)
+
+                    if link.from_node.bl_idname in {"PovrayMirrorNode"}:
+                        file.write("    reflection {\n")
+                        color = None
+                        exponent = 0
+                        metallic = 0
+                        falloff = 0
+                        fresnel = ""
+                        conserve = ""
                         if link.from_node.inputs["Color"].is_linked:
                             pass
                         else:
-                            color=link.from_node.inputs["Color"].default_value[:]
-                        file.write('    <%.4g,%.4g,%.4g>\n'%color)
+                            color = link.from_node.inputs["Color"].default_value[:]
+                        file.write("    <%.4g,%.4g,%.4g>\n" % color)
 
                         if link.from_node.inputs["Exponent"].is_linked:
                             pass
                         else:
-                            exponent=link.from_node.inputs["Exponent"].default_value
-                        file.write('    exponent %.4g\n'%exponent)
+                            exponent = link.from_node.inputs["Exponent"].default_value
+                        file.write("    exponent %.4g\n" % exponent)
 
                         if link.from_node.inputs["Falloff"].is_linked:
                             pass
                         else:
-                            falloff=link.from_node.inputs["Falloff"].default_value
-                        file.write('    falloff %.4g\n'%falloff)
+                            falloff = link.from_node.inputs["Falloff"].default_value
+                        file.write("    falloff %.4g\n" % falloff)
 
                         if link.from_node.inputs["Metallic"].is_linked:
                             pass
                         else:
-                            metallic=link.from_node.inputs["Metallic"].default_value
-                        file.write('    metallic %.4g'%metallic)
+                            metallic = link.from_node.inputs["Metallic"].default_value
+                        file.write("    metallic %.4g" % metallic)
 
                         if link.from_node.inputs["Fresnel"].is_linked:
                             pass
                         else:
-                            if link.from_node.inputs["Fresnel"].default_value==True:
-                                fresnel="fresnel"
+                            if link.from_node.inputs["Fresnel"].default_value:
+                                fresnel = "fresnel"
 
                         if link.from_node.inputs["Conserve energy"].is_linked:
                             pass
                         else:
-                            if link.from_node.inputs["Conserve energy"].default_value==True:
-                                conserve="conserve_energy"
+                            if link.from_node.inputs["Conserve energy"].default_value:
+                                conserve = "conserve_energy"
 
-                        file.write('    %s}\n    %s\n'%(fresnel,conserve))
+                        file.write("    %s}\n    %s\n" % (fresnel, conserve))
 
-                    if link.from_node.bl_idname == 'PovrayAmbientNode':
-                        ambient=(0,0,0)
+                    if link.from_node.bl_idname == "PovrayAmbientNode":
+                        ambient = (0, 0, 0)
                         if link.from_node.inputs["Ambient"].is_linked:
                             pass
                         else:
-                            ambient=link.from_node.inputs["Ambient"].default_value[:]
-                        file.write('    ambient <%.4g,%.4g,%.4g>\n'%ambient)
-
-                    if link.from_node.bl_idname in {'PovrayIridescenceNode'}:
-                        file.write('    irid {\n')
-                        amount=0
-                        thickness=0
-                        turbulence=0
+                            ambient = link.from_node.inputs["Ambient"].default_value[:]
+                        file.write("    ambient <%.4g,%.4g,%.4g>\n" % ambient)
+
+                    if link.from_node.bl_idname in {"PovrayIridescenceNode"}:
+                        file.write("    irid {\n")
+                        amount = 0
+                        thickness = 0
+                        turbulence = 0
                         if link.from_node.inputs["Amount"].is_linked:
                             pass
                         else:
-                            amount=link.from_node.inputs["Amount"].default_value
-                        file.write('    %.4g\n'%amount)
+                            amount = link.from_node.inputs["Amount"].default_value
+                        file.write("    %.4g\n" % amount)
 
                         if link.from_node.inputs["Thickness"].is_linked:
                             pass
                         else:
-                            exponent=link.from_node.inputs["Thickness"].default_value
-                        file.write('    thickness %.4g\n'%thickness)
+                            exponent = link.from_node.inputs["Thickness"].default_value
+                        file.write("    thickness %.4g\n" % thickness)
 
                         if link.from_node.inputs["Turbulence"].is_linked:
                             pass
                         else:
-                            falloff=link.from_node.inputs["Turbulence"].default_value
-                        file.write('    turbulence %.4g}\n'%turbulence)
+                            falloff = link.from_node.inputs["Turbulence"].default_value
+                        file.write("    turbulence %.4g}\n" % turbulence)
 
-            file.write('}\n')
+            file.write("}\n")
 
     for node in ntree.nodes:
-        povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName
+        pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
         if node.bl_idname == "PovrayTransformNode" and node.outputs["Transform"].is_linked:
-            tx=node.inputs["Translate x"].default_value
-            ty=node.inputs["Translate y"].default_value
-            tz=node.inputs["Translate z"].default_value
-            rx=node.inputs["Rotate x"].default_value
-            ry=node.inputs["Rotate y"].default_value
-            rz=node.inputs["Rotate z"].default_value
-            sx=node.inputs["Scale x"].default_value
-            sy=node.inputs["Scale y"].default_value
-            sz=node.inputs["Scale z"].default_value
-            file.write('#declare %s = transform {\n    translate<%.4g,%.4g,%.4g>\n    rotate<%.4g,%.4g,%.4g>\n    scale<%.4g,%.4g,%.4g>}\n'%(povNodeName,tx,ty,tz,rx,ry,rz,sx,sy,sz))
+            tx = node.inputs["Translate x"].default_value
+            ty = node.inputs["Translate y"].default_value
+            tz = node.inputs["Translate z"].default_value
+            rx = node.inputs["Rotate x"].default_value
+            ry = node.inputs["Rotate y"].default_value
+            rz = node.inputs["Rotate z"].default_value
+            sx = node.inputs["Scale x"].default_value
+            sy = node.inputs["Scale y"].default_value
+            sz = node.inputs["Scale z"].default_value
+            file.write(
+                "#declare %s = transform {\n"
+                "    translate<%.4g,%.4g,%.4g>\n"
+                "    rotate<%.4g,%.4g,%.4g>\n"
+                "    scale<%.4g,%.4g,%.4g>}\n" % (pov_node_name, tx, ty, tz, rx, ry, rz, sx, sy, sz)
+            )
 
     for node in ntree.nodes:
-        povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName
+        pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
         if node.bl_idname == "PovrayColorImageNode" and node.outputs["Pigment"].is_linked:
-            declareNodes.append(node.name)
+            declare_nodes.append(node.name)
             if node.image == "":
-                file.write('#declare %s = pigment { color rgb 0.8}\n'%(povNodeName))
+                file.write("#declare %s = pigment { color rgb 0.8}\n" % (pov_node_name))
             else:
-                im=bpy.data.images[node.image]
-                if im.filepath and os.path.exists(bpy.path.abspath(im.filepath)):
+                im = bpy.data.images[node.image]
+                if im.filepath and path.exists(bpy.path.abspath(im.filepath)):  # (os.path)
                     transform = ""
                     for link in ntree.links:
-                        if link.from_node.bl_idname=='PovrayTransformNode' and link.to_node==node:
-                            povTransName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
-                            transform="transform {%s}"%povTransName
-                    uv=""
-                    if node.map_type=="uv_mapping":
-                        uv="uv_mapping"
-                    filepath=bpy.path.abspath(im.filepath)
-                    file.write('#declare %s = pigment {%s image_map {\n'%(povNodeName,uv))
-                    premul="off"
+                        if (
+                            link.from_node.bl_idname == "PovrayTransformNode"
+                            and link.to_node == node
+                        ):
+                            pov_trans_name = (
+                                string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
+                                + "_%s" % pov_mat_name
+                            )
+                            transform = "transform {%s}" % pov_trans_name
+                    uv = ""
+                    if node.map_type == "uv_mapping":
+                        uv = "uv_mapping"
+                    filepath = bpy.path.abspath(im.filepath)
+                    file.write("#declare %s = pigment {%s image_map {\n" % (pov_node_name, uv))
+                    premul = "off"
                     if node.premultiplied:
-                        premul="on"
-                    once=""
+                        premul = "on"
+                    once = ""
                     if node.once:
-                        once="once"
-                    file.write('    "%s"\n    gamma %.6g\n    premultiplied %s\n'%(filepath,node.inputs["Gamma"].default_value,premul))
-                    file.write('    %s\n'%once)
-                    if node.map_type!="uv_mapping":
-                        file.write('    map_type %s\n'%(node.map_type))
-                    file.write('    interpolate %s\n    filter all %.4g\n    transmit all %.4g\n'%
-                        (node.interpolate,node.inputs["Filter"].default_value,node.inputs["Transmit"].default_value))
-                    file.write('    }\n')
-                    file.write('    %s\n'%transform)
-                    file.write('    }\n')
+                        once = "once"
+                    file.write(
+                        '    "%s"\n    gamma %.6g\n    premultiplied %s\n'
+                        % (filepath, node.inputs["Gamma"].default_value, premul)
+                    )
+                    file.write("    %s\n" % once)
+                    if node.map_type != "uv_mapping":
+                        file.write("    map_type %s\n" % (node.map_type))
+                    file.write(
+                        "    interpolate %s\n    filter all %.4g\n    transmit all %.4g\n"
+                        % (
+                            node.interpolate,
+                            node.inputs["Filter"].default_value,
+                            node.inputs["Transmit"].default_value,
+                        )
+                    )
+                    file.write("    }\n")
+                    file.write("    %s\n" % transform)
+                    file.write("    }\n")
 
     for node in ntree.nodes:
-        povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName
+        pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
         if node.bl_idname == "PovrayImagePatternNode" and node.outputs["Pattern"].is_linked:
-            declareNodes.append(node.name)
+            declare_nodes.append(node.name)
             if node.image != "":
-                im=bpy.data.images[node.image]
-                if im.filepath and os.path.exists(bpy.path.abspath(im.filepath)):
+                im = bpy.data.images[node.image]
+                if im.filepath and path.exists(bpy.path.abspath(im.filepath)):
                     transform = ""
                     for link in ntree.links:
-                        if link.from_node.bl_idname=='PovrayTransformNode' and link.to_node==node:
-                            povTransName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
-                            transform="transform {%s}"%povTransName
-                    uv=""
-                    if node.map_type=="uv_mapping":
-                        uv="uv_mapping"
-                    filepath=bpy.path.abspath(im.filepath)
-                    file.write('#macro %s() %s image_pattern {\n'%(povNodeName,uv))
-                    premul="off"
+                        if (
+                            link.from_node.bl_idname == "PovrayTransformNode"
+                            and link.to_node == node
+                        ):
+                            pov_trans_name = (
+                                string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
+                                + "_%s" % pov_mat_name
+                            )
+                            transform = "transform {%s}" % pov_trans_name
+                    uv = ""
+                    if node.map_type == "uv_mapping":
+                        uv = "uv_mapping"
+                    filepath = bpy.path.abspath(im.filepath)
+                    file.write("#macro %s() %s image_pattern {\n" % (pov_node_name, uv))
+                    premul = "off"
                     if node.premultiplied:
-                        premul="on"
-                    once=""
+                        premul = "on"
+                    once = ""
                     if node.once:
-                        once="once"
-                    file.write('    "%s"\n    gamma %.6g\n    premultiplied %s\n'%(filepath,node.inputs["Gamma"].default_value,premul))
-                    file.write('    %s\n'%once)
-                    if node.map_type!="uv_mapping":
-                        file.write('    map_type %s\n'%(node.map_type))
-                    file.write('    interpolate %s\n'%node.interpolate)
-                    file.write('    }\n')
-                    file.write('    %s\n'%transform)
-                    file.write('#end\n')
+                        once = "once"
+                    file.write(
+                        '    "%s"\n    gamma %.6g\n    premultiplied %s\n'
+                        % (filepath, node.inputs["Gamma"].default_value, premul)
+                    )
+                    file.write("    %s\n" % once)
+                    if node.map_type != "uv_mapping":
+                        file.write("    map_type %s\n" % (node.map_type))
+                    file.write("    interpolate %s\n" % node.interpolate)
+                    file.write("    }\n")
+                    file.write("    %s\n" % transform)
+                    file.write("#end\n")
 
     for node in ntree.nodes:
-        povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName
+        pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
         if node.bl_idname == "PovrayBumpMapNode" and node.outputs["Normal"].is_linked:
             if node.image != "":
-                im=bpy.data.images[node.image]
-                if im.filepath and os.path.exists(bpy.path.abspath(im.filepath)):
+                im = bpy.data.images[node.image]
+                if im.filepath and path.exists(bpy.path.abspath(im.filepath)):
                     transform = ""
                     for link in ntree.links:
-                        if link.from_node.bl_idname=='PovrayTransformNode' and link.to_node==node:
-                            povTransName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
-                            transform="transform {%s}"%povTransName
-                    uv=""
-                    if node.map_type=="uv_mapping":
-                        uv="uv_mapping"
-                    filepath=bpy.path.abspath(im.filepath)
-                    file.write('#declare %s = normal {%s bump_map {\n'%(povNodeName,uv))
-                    once=""
+                        if (
+                            link.from_node.bl_idname == "PovrayTransformNode"
+                            and link.to_node == node
+                        ):
+                            pov_trans_name = (
+                                string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
+                                + "_%s" % pov_mat_name
+                            )
+                            transform = "transform {%s}" % pov_trans_name
+                    uv = ""
+                    if node.map_type == "uv_mapping":
+                        uv = "uv_mapping"
+                    filepath = bpy.path.abspath(im.filepath)
+                    file.write("#declare %s = normal {%s bump_map {\n" % (pov_node_name, uv))
+                    once = ""
                     if node.once:
-                        once="once"
-                    file.write('    "%s"\n'%filepath)
-                    file.write('    %s\n'%once)
-                    if node.map_type!="uv_mapping":
-                        file.write('    map_type %s\n'%(node.map_type))
-                    bump_size=node.inputs["Normal"].default_value
+                        once = "once"
+                    file.write('    "%s"\n' % filepath)
+                    file.write("    %s\n" % once)
+                    if node.map_type != "uv_mapping":
+                        file.write("    map_type %s\n" % (node.map_type))
+                    bump_size = node.inputs["Normal"].default_value
                     if node.inputs["Normal"].is_linked:
                         pass
-                    file.write('    interpolate %s\n    bump_size %.4g\n'%(node.interpolate,bump_size))
-                    file.write('    }\n')
-                    file.write('    %s\n'%transform)
-                    file.write('    }\n')
-                    declareNodes.append(node.name)
-
-
+                    file.write(
+                        "    interpolate %s\n    bump_size %.4g\n" % (node.interpolate, bump_size)
+                    )
+                    file.write("    }\n")
+                    file.write("    %s\n" % transform)
+                    file.write("    }\n")
+                    declare_nodes.append(node.name)
 
     for node in ntree.nodes:
-        povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName
+        pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
         if node.bl_idname == "PovrayPigmentNode" and node.outputs["Pigment"].is_linked:
-            declareNodes.append(node.name)
-            r,g,b=node.inputs["Color"].default_value[:]
-            f=node.inputs["Filter"].default_value
-            t=node.inputs["Transmit"].default_value
+            declare_nodes.append(node.name)
+            r, g, b = node.inputs["Color"].default_value[:]
+            f = node.inputs["Filter"].default_value
+            t = node.inputs["Transmit"].default_value
             if node.inputs["Color"].is_linked:
                 pass
-            file.write('#declare %s = pigment{color srgbft <%.4g,%.4g,%.4g,%.4g,%.4g>}\n'%(povNodeName,r,g,b,f,t))
-
+            file.write(
+                "#declare %s = pigment{color srgbft <%.4g,%.4g,%.4g,%.4g,%.4g>}\n"
+                % (pov_node_name, r, g, b, f, t)
+            )
 
     for node in ntree.nodes:
-        povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName
+        pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
         if node.bl_idname == "PovrayTextureNode" and node.outputs["Texture"].is_linked:
-            declareNodes.append(node.name)
-            r,g,b=node.inputs["Pigment"].default_value[:]
-            povColName="color rgb <%.4g,%.4g,%.4g>"%(r,g,b)
+            declare_nodes.append(node.name)
+            r, g, b = node.inputs["Pigment"].default_value[:]
+            pov_col_name = "color rgb <%.4g,%.4g,%.4g>" % (r, g, b)
             if node.inputs["Pigment"].is_linked:
                 for link in ntree.links:
-                    if link.to_node==node and link.to_socket.name=="Pigment":
-                        povColName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
-            file.write('#declare %s = texture{\n    pigment{%s}\n'%(povNodeName,povColName))
+                    if link.to_node == node and link.to_socket.name == "Pigment":
+                        pov_col_name = (
+                            string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
+                            + "_%s" % pov_mat_name
+                        )
+            file.write("#declare %s = texture{\n    pigment{%s}\n" % (pov_node_name, pov_col_name))
             if node.inputs["Normal"].is_linked:
                 for link in ntree.links:
-                    if link.to_node==node and link.to_socket.name=="Normal" and link.from_node.name in declareNodes:
-                        povNorName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
-                        file.write('    normal{%s}\n'%povNorName)
+                    if (
+                        link.to_node == node
+                        and link.to_socket.name == "Normal"
+                        and link.from_node.name in declare_nodes
+                    ):
+                        pov_nor_name = (
+                            string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
+                            + "_%s" % pov_mat_name
+                        )
+                        file.write("    normal{%s}\n" % pov_nor_name)
             if node.inputs["Finish"].is_linked:
                 for link in ntree.links:
-                    if link.to_node==node and link.to_socket.name=="Finish":
-                        povFinName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
-                        file.write('    finish{%s}\n'%povFinName)
-            file.write('}\n')
-            declareNodes.append(node.name)
+                    if link.to_node == node and link.to_socket.name == "Finish":
+                        pov_fin_name = (
+                            string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
+                            + "_%s" % pov_mat_name
+                        )
+                        file.write("    finish{%s}\n" % pov_fin_name)
+            file.write("}\n")
+            declare_nodes.append(node.name)
 
-    for i in range(0,len(ntree.nodes)):
+    for i in range(0, len(ntree.nodes)):
         for node in ntree.nodes:
-            if node.bl_idname in {"ShaderNodeGroup","ShaderTextureMapNode"}:
+            if node.bl_idname in {"ShaderNodeGroup", "ShaderTextureMapNode"}:
                 for output in node.outputs:
-                    if output.name=="Texture" and output.is_linked and (node.name not in declareNodes):
-                        declare=True
+                    if (
+                        output.name == "Texture"
+                        and output.is_linked
+                        and (node.name not in declare_nodes)
+                    ):
+                        declare = True
                         for link in ntree.links:
-                            if link.to_node==node and link.to_socket.name not in {"","Color ramp","Mapping","Transform","Modifier"}:
-                                if link.from_node.name not in declareNodes:
-                                    declare=False
+                            if link.to_node == node and link.to_socket.name not in {
+                                "",
+                                "Color ramp",
+                                "Mapping",
+                                "Transform",
+                                "Modifier",
+                            }:
+                                if link.from_node.name not in declare_nodes:
+                                    declare = False
                         if declare:
-                            povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName
-                            uv=""
-                            warp=""
+                            pov_node_name = (
+                                string_strip_hyphen(bpy.path.clean_name(node.name))
+                                + "_%s" % pov_mat_name
+                            )
+                            uv = ""
+                            warp = ""
                             for link in ntree.links:
-                                if link.to_node==node and link.from_node.bl_idname=='PovrayMappingNode' and link.from_node.warp_type!="NONE":
+                                if (
+                                    link.to_node == node
+                                    and link.from_node.bl_idname == "PovrayMappingNode"
+                                    and link.from_node.warp_type != "NONE"
+                                ):
                                     w_type = link.from_node.warp_type
-                                    if w_type=="uv_mapping":
-                                        uv="uv_mapping"
+                                    if w_type == "uv_mapping":
+                                        uv = "uv_mapping"
                                     else:
-                                        tor=""
-                                        if w_type=="toroidal":
-                                            tor="major_radius %.4g"%link.from_node.warp_tor_major_radius
-                                        orient=link.from_node.warp_orientation
-                                        exp=link.from_node.warp_dist_exp
-                                        warp="warp{%s orientation %s dist_exp %.4g %s}"%(w_type,orient,exp,tor)
-                                        if link.from_node.warp_type=="planar":
-                                            warp="warp{%s %s %.4g}"%(w_type,orient,exp)
-                                        if link.from_node.warp_type=="cubic":
-                                            warp="warp{%s}"%w_type
-                            file.write('#declare %s = texture {%s\n'%(povNodeName,uv))
-                            pattern=node.inputs[0].default_value
-                            advanced=""
+                                        tor = ""
+                                        if w_type == "toroidal":
+                                            tor = (
+                                                "major_radius %.4g"
+                                                % link.from_node.warp_tor_major_radius
+                                            )
+                                        orient = link.from_node.warp_orientation
+                                        exp = link.from_node.warp_dist_exp
+                                        warp = "warp{%s orientation %s dist_exp %.4g %s}" % (
+                                            w_type,
+                                            orient,
+                                            exp,
+                                            tor,
+                                        )
+                                        if link.from_node.warp_type == "planar":
+                                            warp = "warp{%s %s %.4g}" % (w_type, orient, exp)
+                                        if link.from_node.warp_type == "cubic":
+                                            warp = "warp{%s}" % w_type
+                            file.write("#declare %s = texture {%s\n" % (pov_node_name, uv))
+                            pattern = node.inputs[0].default_value
+                            advanced = ""
                             if node.inputs[0].is_linked:
                                 for link in ntree.links:
-                                    if link.to_node==node and link.from_node.bl_idname=='ShaderPatternNode':
+                                    if (
+                                        link.to_node == node
+                                        and link.from_node.bl_idname == "ShaderPatternNode"
+                                    ):
                                         ########### advanced ###############################################
-                                        lfn=link.from_node
-                                        pattern=lfn.pattern
-                                        if pattern == 'agate':
-                                            advanced = 'agate_turb %.4g'%lfn.agate_turb
-                                        if pattern == 'crackle':
-                                            advanced="form <%.4g,%.4g,%.4g>"%(lfn.crackle_form_x,lfn.crackle_form_y,lfn.crackle_form_z)
-                                            advanced+=" metric %.4g"%lfn.crackle_metric
+                                        lfn = link.from_node
+                                        pattern = lfn.pattern
+                                        if pattern == "agate":
+                                            advanced = "agate_turb %.4g" % lfn.agate_turb
+                                        if pattern == "crackle":
+                                            advanced = "form <%.4g,%.4g,%.4g>" % (
+                                                lfn.crackle_form_x,
+                                                lfn.crackle_form_y,
+                                                lfn.crackle_form_z,
+                                            )
+                                            advanced += " metric %.4g" % lfn.crackle_metric
                                             if lfn.crackle_solid:
-                                                advanced+=" solid"
-                                        if pattern in {'spiral1', 'spiral2'}:
-                                            advanced='%.4g'%lfn.spiral_arms
-                                        if pattern in {'tiling'}:
-                                            advanced='%.4g'%lfn.tiling_number
-                                        if pattern in {'gradient'}:
-                                            advanced='%s'%lfn.gradient_orient
-                                    if link.to_node==node and link.from_node.bl_idname=='PovrayImagePatternNode':
-                                        povMacroName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
-                                        pattern = "%s()"%povMacroName
-                            file.write('    %s %s %s\n'%(pattern,advanced,warp))
-
-                            repeat=""
+                                                advanced += " solid"
+                                        if pattern in {"spiral1", "spiral2"}:
+                                            advanced = "%.4g" % lfn.spiral_arms
+                                        if pattern in {"tiling"}:
+                                            advanced = "%.4g" % lfn.tiling_number
+                                        if pattern in {"gradient"}:
+                                            advanced = "%s" % lfn.gradient_orient
+                                    if (
+                                        link.to_node == node
+                                        and link.from_node.bl_idname == "PovrayImagePatternNode"
+                                    ):
+                                        pov_macro_name = (
+                                            string_strip_hyphen(
+                                                bpy.path.clean_name(link.from_node.name)
+                                            )
+                                            + "_%s" % pov_mat_name
+                                        )
+                                        pattern = "%s()" % pov_macro_name
+                            file.write("    %s %s %s\n" % (pattern, advanced, warp))
+
+                            repeat = ""
                             for link in ntree.links:
-                                if link.to_node==node and link.from_node.bl_idname=='PovrayMultiplyNode':
+                                if (
+                                    link.to_node == node
+                                    and link.from_node.bl_idname == "PovrayMultiplyNode"
+                                ):
                                     if link.from_node.amount_x > 1:
-                                        repeat+="warp{repeat %.4g * x}"%link.from_node.amount_x
+                                        repeat += "warp{repeat %.4g * x}" % link.from_node.amount_x
                                     if link.from_node.amount_y > 1:
-                                        repeat+=" warp{repeat %.4g * y}"%link.from_node.amount_y
+                                        repeat += " warp{repeat %.4g * y}" % link.from_node.amount_y
                                     if link.from_node.amount_z > 1:
-                                        repeat+=" warp{repeat %.4g * z}"%link.from_node.amount_z
+                                        repeat += " warp{repeat %.4g * z}" % link.from_node.amount_z
 
-                            transform=""
+                            transform = ""
                             for link in ntree.links:
-                                if link.to_node==node and link.from_node.bl_idname=='PovrayTransformNode':
-                                    povTransName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
-                                    transform="transform {%s}"%povTransName
-                            x=0
-                            y=0
-                            z=0
-                            d=0
-                            e=0
-                            f=0
-                            g=0
-                            h=0
-                            modifier=False
+                                if (
+                                    link.to_node == node
+                                    and link.from_node.bl_idname == "PovrayTransformNode"
+                                ):
+                                    pov_trans_name = (
+                                        string_strip_hyphen(
+                                            bpy.path.clean_name(link.from_node.name)
+                                        )
+                                        + "_%s" % pov_mat_name
+                                    )
+                                    transform = "transform {%s}" % pov_trans_name
+                            x = 0
+                            y = 0
+                            z = 0
+                            d = 0
+                            e = 0
+                            f = 0
+                            g = 0
+                            h = 0
+                            modifier = False
                             for link in ntree.links:
-                                if link.to_node==node and link.from_node.bl_idname=='PovrayModifierNode':
-                                    modifier=True
+                                if (
+                                    link.to_node == node
+                                    and link.from_node.bl_idname == "PovrayModifierNode"
+                                ):
+                                    modifier = True
                                     if link.from_node.inputs["Turb X"].is_linked:
                                         pass
                                     else:
@@ -1800,66 +1604,135 @@ def write_nodes(scene,povMatName,ntree,file):
                                     else:
                                         h = link.from_node.inputs["Phase"].default_value
 
-                            turb = "turbulence <%.4g,%.4g,%.4g>"%(x,y,z)
-                            octv = "octaves %s"%d
-                            lmbd = "lambda %.4g"%e
-                            omg = "omega %.4g"%f
-                            freq = "frequency %.4g"%g
-                            pha = "phase %.4g"%h
-
-
-                            file.write('\n')
-                            if pattern not in {'checker', 'hexagon', 'square', 'triangular', 'brick'}:
-                                file.write('    texture_map {\n')
+                            turb = "turbulence <%.4g,%.4g,%.4g>" % (x, y, z)
+                            octv = "octaves %s" % d
+                            lmbd = "lambda %.4g" % e
+                            omg = "omega %.4g" % f
+                            freq = "frequency %.4g" % g
+                            pha = "phase %.4g" % h
+
+                            file.write("\n")
+                            if pattern not in {
+                                "checker",
+                                "hexagon",
+                                "square",
+                                "triangular",
+                                "brick",
+                            }:
+                                file.write("    texture_map {\n")
                             if node.inputs["Color ramp"].is_linked:
                                 for link in ntree.links:
-                                    if link.to_node==node and link.from_node.bl_idname=="ShaderNodeValToRGB":
+                                    if (
+                                        link.to_node == node
+                                        and link.from_node.bl_idname == "ShaderNodeValToRGB"
+                                    ):
                                         els = link.from_node.color_ramp.elements
-                                        n=-1
+                                        n = -1
                                         for el in els:
-                                            n+=1
-                                            povInMatName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s_%s"%(n,povMatName)
-                                            default=True
+                                            n += 1
+                                            pov_in_mat_name = string_strip_hyphen(
+                                                bpy.path.clean_name(link.from_node.name)
+                                            ) + "_%s_%s" % (n, pov_mat_name)
+                                            default = True
                                             for ilink in ntree.links:
-                                                if ilink.to_node==node and ilink.to_socket.name == str(n):
-                                                    default=False
-                                                    povInMatName=string_strip_hyphen(bpy.path.clean_name(ilink.from_node.name))+"_%s"%povMatName
+                                                if (
+                                                    ilink.to_node == node
+                                                    and ilink.to_socket.name == str(n)
+                                                ):
+                                                    default = False
+                                                    pov_in_mat_name = (
+                                                        string_strip_hyphen(
+                                                            bpy.path.clean_name(
+                                                                ilink.from_node.name
+                                                            )
+                                                        )
+                                                        + "_%s" % pov_mat_name
+                                                    )
                                             if default:
-                                                r,g,b,a=el.color[:]
-                                                file.write('    #declare %s = texture{pigment{color srgbt <%.4g,%.4g,%.4g,%.4g>}};\n'%(povInMatName,r,g,b,1-a))
-                                            file.write('    [%s %s]\n'%(el.position,povInMatName))
+                                                r, g, b, a = el.color[:]
+                                                file.write(
+                                                    "    #declare %s = texture{"
+                                                    "pigment{"
+                                                    "color srgbt <%.4g,%.4g,%.4g,%.4g>}};\n"
+                                                    % (pov_in_mat_name, r, g, b, 1 - a)
+                                                )
+                                            file.write(
+                                                "    [%s %s]\n" % (el.position, pov_in_mat_name)
+                                            )
                             else:
-                                els=[[0,0,0,0],[1,1,1,1]]
-                                for i in range(0,2):
-                                    povInMatName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s_%s"%(i,povMatName)
-                                    default=True
+                                els = [[0, 0, 0, 0], [1, 1, 1, 1]]
+                                for t in range(0, 2):
+                                    pov_in_mat_name = string_strip_hyphen(
+                                        bpy.path.clean_name(link.from_node.name)
+                                    ) + "_%s_%s" % (t, pov_mat_name)
+                                    default = True
                                     for ilink in ntree.links:
-                                        if ilink.to_node==node and ilink.to_socket.name == str(i):
-                                            default=False
-                                            povInMatName=string_strip_hyphen(bpy.path.clean_name(ilink.from_node.name))+"_%s"%povMatName
+                                        if ilink.to_node == node and ilink.to_socket.name == str(t):
+                                            default = False
+                                            pov_in_mat_name = (
+                                                string_strip_hyphen(
+                                                    bpy.path.clean_name(ilink.from_node.name)
+                                                )
+                                                + "_%s" % pov_mat_name
+                                            )
                                     if default:
-                                        r,g,b=els[i][1],els[i][2],els[i][3]
-                                        if pattern not in {'checker', 'hexagon', 'square', 'triangular', 'brick'}:
-                                            file.write('    #declare %s = texture{pigment{color rgb <%.4g,%.4g,%.4g>}};\n'%(povInMatName,r,g,b))
+                                        r, g, b = els[t][1], els[t][2], els[t][3]
+                                        if pattern not in {
+                                            "checker",
+                                            "hexagon",
+                                            "square",
+                                            "triangular",
+                                            "brick",
+                                        }:
+                                            file.write(
+                                                "    #declare %s = texture{pigment{color rgb <%.4g,%.4g,%.4g>}};\n"
+                                                % (pov_in_mat_name, r, g, b)
+                                            )
                                         else:
-                                            file.write('    texture{pigment{color rgb <%.4g,%.4g,%.4g>}}\n'%(r,g,b))
-                                    if pattern not in {'checker', 'hexagon', 'square', 'triangular', 'brick'}:
-                                        file.write('    [%s %s]\n'%(els[i][0],povInMatName))
+                                            file.write(
+                                                "    texture{pigment{color rgb <%.4g,%.4g,%.4g>}}\n"
+                                                % (r, g, b)
+                                            )
+                                    if pattern not in {
+                                        "checker",
+                                        "hexagon",
+                                        "square",
+                                        "triangular",
+                                        "brick",
+                                    }:
+                                        file.write("    [%s %s]\n" % (els[t][0], pov_in_mat_name))
                                     else:
-                                        if default==False:
-                                            file.write('    texture{%s}\n'%povInMatName)
-                            if pattern not in {'checker', 'hexagon', 'square', 'triangular', 'brick'}:
-                                file.write('}\n')
-                            if pattern == 'brick':
-                                file.write("brick_size <%.4g, %.4g, %.4g> mortar %.4g \n"%(node.brick_size_x,
-                                                        node.brick_size_y, node.brick_size_z, node.brick_mortar))
-                            file.write('    %s %s'%(repeat,transform))
+                                        if not default:
+                                            file.write("    texture{%s}\n" % pov_in_mat_name)
+                            if pattern not in {
+                                "checker",
+                                "hexagon",
+                                "square",
+                                "triangular",
+                                "brick",
+                            }:
+                                file.write("}\n")
+                            if pattern == "brick":
+                                file.write(
+                                    "brick_size <%.4g, %.4g, %.4g> mortar %.4g \n"
+                                    % (
+                                        node.brick_size_x,
+                                        node.brick_size_y,
+                                        node.brick_size_z,
+                                        node.brick_mortar,
+                                    )
+                                )
+                            file.write("    %s %s" % (repeat, transform))
                             if modifier:
-                                file.write(' %s %s %s %s %s %s'%(turb,octv,lmbd,omg,freq,pha))
-                            file.write('}\n')
-                            declareNodes.append(node.name)
+                                file.write(
+                                    " %s %s %s %s %s %s" % (turb, octv, lmbd, omg, freq, pha)
+                                )
+                            file.write("}\n")
+                            declare_nodes.append(node.name)
 
     for link in ntree.links:
-        if link.to_node.bl_idname == "PovrayOutputNode" and link.from_node.name in declareNodes:
-            povMatNodeName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
-            file.write('#declare %s = %s\n'%(povMatName,povMatNodeName))
+        if link.to_node.bl_idname == "PovrayOutputNode" and link.from_node.name in declare_nodes:
+            pov_mat_node_name = (
+                string_strip_hyphen(bpy.path.clean_name(link.from_node.name)) + "_%s" % pov_mat_name
+            )
+            file.write("#declare %s = %s\n" % (pov_mat_name, pov_mat_node_name))
diff --git a/render_povray/shading_gui.py b/render_povray/shading_gui.py
new file mode 100755
index 000000000..3df7f4a96
--- /dev/null
+++ b/render_povray/shading_gui.py
@@ -0,0 +1,688 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+""""User interface for shaders exported to POV textures."""
+
+import bpy
+from bpy.utils import register_class, unregister_class
+from bpy.types import Operator, Menu, Panel
+from bl_operators.presets import AddPresetBase
+
+# Example of wrapping every class 'as is' except some
+from bl_ui import properties_material
+
+for member in dir(properties_material):
+    subclass = getattr(properties_material, member)
+    try:
+        # mat=bpy.context.active_object.active_material
+        # if (mat and mat.pov.type == "SURFACE"
+        # and not (mat.pov.material_use_nodes or mat.use_nodes)):
+        # and (engine in cls.COMPAT_ENGINES)) if subclasses were sorted
+        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+    except BaseException as e:
+        print(e.__doc__)
+        print('An exception occurred: {}'.format(e))
+        pass
+del properties_material
+
+from .shading_properties import check_material
+
+
+def simple_material(mat):
+    """Test if a material uses nodes"""
+    if (mat is not None) and (not mat.use_nodes):
+        return True
+    return False
+
+
+class MaterialButtonsPanel:
+    """Use this class to define buttons from the material tab of
+    properties window."""
+
+    bl_space_type = 'PROPERTIES'
+    bl_region_type = 'WINDOW'
+    bl_context = "material"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        mat = context.material
+        rd = context.scene.render
+        return mat and (rd.engine in cls.COMPAT_ENGINES)
+
+
+class MATERIAL_MT_POV_sss_presets(Menu):
+    """Use this class to define pov sss preset menu."""
+
+    bl_label = "SSS Presets"
+    preset_subdir = "pov/material/sss"
+    preset_operator = "script.execute_preset"
+    draw = bpy.types.Menu.draw_preset
+
+
+class MATERIAL_OT_POV_sss_add_preset(AddPresetBase, Operator):
+    """Add an SSS Preset"""
+
+    bl_idname = "material.sss_preset_add"
+    bl_label = "Add SSS Preset"
+    preset_menu = "MATERIAL_MT_POV_sss_presets"
+
+    # variable used for all preset values
+    preset_defines = ["material = bpy.context.material"]
+
+    # properties to store in the preset
+    preset_values = [
+        "material.pov_subsurface_scattering.radius",
+        "material.pov_subsurface_scattering.color",
+    ]
+
+    # where to store the preset
+    preset_subdir = "pov/material/sss"
+
+
+class MATERIAL_PT_POV_sss(MaterialButtonsPanel, Panel):
+    """Use this class to define pov sss buttons panel."""
+
+    bl_label = "Subsurface Scattering"
+    bl_options = {'DEFAULT_CLOSED'}
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        mat = context.material
+        engine = context.scene.render.engine
+        return (
+            check_material(mat)
+            and (mat.pov.type in {'SURFACE', 'WIRE'})
+            and (engine in cls.COMPAT_ENGINES)
+        )
+
+    def draw_header(self, context):
+        mat = context.material  # FORMERLY : #active_node_mat(context.material)
+        sss = mat.pov_subsurface_scattering
+
+        self.layout.active = not mat.pov.use_shadeless
+        self.layout.prop(sss, "use", text="")
+
+    def draw(self, context):
+        layout = self.layout
+
+        mat = context.material  # FORMERLY : #active_node_mat(context.material)
+        sss = mat.pov_subsurface_scattering
+
+        layout.active = (sss.use) and (not mat.pov.use_shadeless)
+
+        row = layout.row().split()
+        sub = row.row(align=True).split(align=True, factor=0.75)
+        sub.menu(MATERIAL_MT_POV_sss_presets.__name__, text=MATERIAL_MT_POV_sss_presets.bl_label)
+        sub.operator(MATERIAL_OT_POV_sss_add_preset.bl_idname, text="", icon='ADD')
+        sub.operator(
+            MATERIAL_OT_POV_sss_add_preset.bl_idname, text="", icon='REMOVE'
+        ).remove_active = True
+
+        split = layout.split()
+
+        col = split.column()
+        col.prop(sss, "ior")
+        col.prop(sss, "scale")
+        col.prop(sss, "color", text="")
+        col.prop(sss, "radius", text="RGB Radius", expand=True)
+
+        col = split.column()
+        sub = col.column(align=True)
+        sub.label(text="Blend:")
+        sub.prop(sss, "color_factor", text="Color")
+        sub.prop(sss, "texture_factor", text="Texture")
+        sub.label(text="Scattering Weight:")
+        sub.prop(sss, "front")
+        sub.prop(sss, "back")
+        col.separator()
+        col.prop(sss, "error_threshold", text="Error")
+
+
+class MATERIAL_PT_POV_activate_node(MaterialButtonsPanel, Panel):
+    """Use this class to define an activate pov nodes button."""
+
+    bl_label = "Activate Node Settings"
+    bl_context = "material"
+    bl_options = {'HIDE_HEADER'}
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        engine = context.scene.render.engine
+        mat = context.material
+        return (
+            mat
+            and mat.pov.type == "SURFACE"
+            and (engine in cls.COMPAT_ENGINES)
+            and not (mat.pov.material_use_nodes or mat.use_nodes)
+        )
+
+    def draw(self, context):
+        layout = self.layout
+        # layout.operator("pov.material_use_nodes", icon='SOUND')#'NODETREE')
+        # the above replaced with a context hook below:
+        layout.operator(
+            "WM_OT_context_toggle", text="Use POV-Ray Nodes", icon='NODETREE'
+        ).data_path = "material.pov.material_use_nodes"
+
+
+class MATERIAL_PT_POV_active_node(MaterialButtonsPanel, Panel):
+    """Use this class to show pov active node properties buttons."""
+
+    bl_label = "Active Node Settings"
+    bl_context = "material"
+    bl_options = {'HIDE_HEADER'}
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        engine = context.scene.render.engine
+        mat = context.material
+        return (
+            mat
+            and mat.pov.type == "SURFACE"
+            and (engine in cls.COMPAT_ENGINES)
+            and mat.pov.material_use_nodes
+        )
+
+    def draw(self, context):
+        layout = self.layout
+        mat = context.material
+        node_tree = mat.node_tree
+        if node_tree:
+            node = node_tree.nodes.active
+            if mat.use_nodes:
+                if node:
+                    layout.prop(mat.pov, "material_active_node")
+                    if node.bl_idname == "PovrayMaterialNode":
+                        layout.context_pointer_set("node", node)
+                        if hasattr(node, "draw_buttons_ext"):
+                            node.draw_buttons_ext(context, layout)
+                        elif hasattr(node, "draw_buttons"):
+                            node.draw_buttons(context, layout)
+                        value_inputs = [
+                            socket
+                            for socket in node.inputs
+                            if socket.enabled and not socket.is_linked
+                        ]
+                        if value_inputs:
+                            layout.separator()
+                            layout.label(text="Inputs:")
+                            for socket in value_inputs:
+                                row = layout.row()
+                                socket.draw(context, row, node, socket.name)
+                    else:
+                        layout.context_pointer_set("node", node)
+                        if hasattr(node, "draw_buttons_ext"):
+                            node.draw_buttons_ext(context, layout)
+                        elif hasattr(node, "draw_buttons"):
+                            node.draw_buttons(context, layout)
+                        value_inputs = [
+                            socket
+                            for socket in node.inputs
+                            if socket.enabled and not socket.is_linked
+                        ]
+                        if value_inputs:
+                            layout.separator()
+                            layout.label(text="Inputs:")
+                            for socket in value_inputs:
+                                row = layout.row()
+                                socket.draw(context, row, node, socket.name)
+                else:
+                    layout.label(text="No active nodes!")
+
+
+class MATERIAL_PT_POV_specular(MaterialButtonsPanel, Panel):
+    """Use this class to define standard material specularity (highlights) buttons."""
+
+    bl_label = "Specular"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        mat = context.material
+        engine = context.scene.render.engine
+        return (
+            check_material(mat)
+            and (mat.pov.type in {'SURFACE', 'WIRE'})
+            and (engine in cls.COMPAT_ENGINES)
+        )
+
+    def draw(self, context):
+        layout = self.layout
+
+        mat = context.material.pov
+
+        layout.active = not mat.use_shadeless
+
+        split = layout.split()
+
+        col = split.column()
+        col.prop(mat, "specular_color", text="")
+        col.prop(mat, "specular_intensity", text="Intensity")
+
+        col = split.column()
+        col.prop(mat, "specular_shader", text="")
+        col.prop(mat, "use_specular_ramp", text="Ramp")
+
+        col = layout.column()
+        if mat.specular_shader in {'COOKTORR', 'PHONG'}:
+            col.prop(mat, "specular_hardness", text="Hardness")
+        elif mat.specular_shader == 'BLINN':
+            row = col.row()
+            row.prop(mat, "specular_hardness", text="Hardness")
+            row.prop(mat, "specular_ior", text="IOR")
+        elif mat.specular_shader == 'WARDISO':
+            col.prop(mat, "specular_slope", text="Slope")
+        elif mat.specular_shader == 'TOON':
+            row = col.row()
+            row.prop(mat, "specular_toon_size", text="Size")
+            row.prop(mat, "specular_toon_smooth", text="Smooth")
+
+        if mat.use_specular_ramp:
+            layout.separator()
+            layout.template_color_ramp(mat, "specular_ramp", expand=True)
+            layout.separator()
+
+            row = layout.row()
+            row.prop(mat, "specular_ramp_input", text="Input")
+            row.prop(mat, "specular_ramp_blend", text="Blend")
+
+            layout.prop(mat, "specular_ramp_factor", text="Factor")
+
+
+class MATERIAL_PT_POV_mirror(MaterialButtonsPanel, Panel):
+    """Use this class to define standard material reflectivity (mirror) buttons."""
+
+    bl_label = "Mirror"
+    bl_options = {'DEFAULT_CLOSED'}
+    bl_idname = "MATERIAL_PT_POV_raytrace_mirror"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        mat = context.material
+        engine = context.scene.render.engine
+        return (
+            check_material(mat)
+            and (mat.pov.type in {'SURFACE', 'WIRE'})
+            and (engine in cls.COMPAT_ENGINES)
+        )
+
+    def draw_header(self, context):
+        mat = context.material
+        raym = mat.pov_raytrace_mirror
+
+        self.layout.prop(raym, "use", text="")
+
+    def draw(self, context):
+        layout = self.layout
+
+        mat = context.material  # Formerly : #mat = active_node_mat(context.material)
+        raym = mat.pov_raytrace_mirror
+
+        layout.active = raym.use
+
+        split = layout.split()
+
+        col = split.column()
+        col.prop(raym, "reflect_factor")
+        col.prop(raym, "mirror_color", text="")
+
+        col = split.column()
+        col.prop(raym, "fresnel")
+        sub = col.column()
+        sub.active = raym.fresnel > 0.0
+        sub.prop(raym, "fresnel_factor", text="Blend")
+
+        split = layout.split()
+
+        col = split.column()
+        col.separator()
+        col.prop(raym, "depth")
+        col.prop(raym, "distance", text="Max Dist")
+        col.separator()
+        sub = col.split(factor=0.4)
+        sub.active = raym.distance > 0.0
+        sub.label(text="Fade To:")
+        sub.prop(raym, "fade_to", text="")
+
+        col = split.column()
+        col.label(text="Gloss:")
+        col.prop(raym, "gloss_factor", text="Amount")
+        sub = col.column()
+        sub.active = raym.gloss_factor < 1.0
+        sub.prop(raym, "gloss_threshold", text="Threshold")
+        sub.prop(raym, "gloss_samples", text="Noise")
+        sub.prop(raym, "gloss_anisotropic", text="Anisotropic")
+
+
+class MATERIAL_PT_POV_transp(MaterialButtonsPanel, Panel):
+    """Use this class to define pov material transparency (alpha) buttons."""
+
+    bl_label = "Transparency"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        mat = context.material
+        engine = context.scene.render.engine
+        return (
+            check_material(mat)
+            and (mat.pov.type in {'SURFACE', 'WIRE'})
+            and (engine in cls.COMPAT_ENGINES)
+        )
+
+    def draw_header(self, context):
+        mat = context.material
+
+        if simple_material(mat):
+            self.layout.prop(mat.pov, "use_transparency", text="")
+
+    def draw(self, context):
+        layout = self.layout
+
+        base_mat = context.material
+        mat = context.material  # FORMERLY active_node_mat(context.material)
+        rayt = mat.pov_raytrace_transparency
+
+        if simple_material(base_mat):
+            row = layout.row()
+            row.active = mat.pov.use_transparency
+            row.prop(mat.pov, "transparency_method", expand=True)
+
+        split = layout.split()
+        split.active = base_mat.pov.use_transparency
+
+        col = split.column()
+        col.prop(mat.pov, "alpha")
+        row = col.row()
+        row.active = (base_mat.pov.transparency_method != 'MASK') and (not mat.pov.use_shadeless)
+        row.prop(mat.pov, "specular_alpha", text="Specular")
+
+        col = split.column()
+        col.active = not mat.pov.use_shadeless
+        col.prop(rayt, "fresnel")
+        sub = col.column()
+        sub.active = rayt.fresnel > 0.0
+        sub.prop(rayt, "fresnel_factor", text="Blend")
+
+        if base_mat.pov.transparency_method == 'RAYTRACE':
+            layout.separator()
+            split = layout.split()
+            split.active = base_mat.pov.use_transparency
+
+            col = split.column()
+            col.prop(rayt, "ior")
+            col.prop(rayt, "filter")
+            col.prop(rayt, "falloff")
+            col.prop(rayt, "depth_max")
+            col.prop(rayt, "depth")
+
+            col = split.column()
+            col.label(text="Gloss:")
+            col.prop(rayt, "gloss_factor", text="Amount")
+            sub = col.column()
+            sub.active = rayt.gloss_factor < 1.0
+            sub.prop(rayt, "gloss_threshold", text="Threshold")
+            sub.prop(rayt, "gloss_samples", text="Samples")
+
+
+class MATERIAL_PT_POV_reflection(MaterialButtonsPanel, Panel):
+    """Use this class to define more pov specific reflectivity buttons."""
+
+    bl_label = "POV-Ray Reflection"
+    bl_parent_id = "MATERIAL_PT_POV_raytrace_mirror"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        engine = context.scene.render.engine
+        mat = context.material
+        return (
+            mat
+            and mat.pov.type == "SURFACE"
+            and (engine in cls.COMPAT_ENGINES)
+            and not (mat.pov.material_use_nodes or mat.use_nodes)
+        )
+
+    def draw(self, context):
+        layout = self.layout
+        mat = context.material
+        col = layout.column()
+        col.prop(mat.pov, "irid_enable")
+        if mat.pov.irid_enable:
+            col = layout.column()
+            col.prop(mat.pov, "irid_amount", slider=True)
+            col.prop(mat.pov, "irid_thickness", slider=True)
+            col.prop(mat.pov, "irid_turbulence", slider=True)
+        col.prop(mat.pov, "conserve_energy")
+        col2 = col.split().column()
+
+        if not mat.pov_raytrace_mirror.use:
+            col2.label(text="Please Check Mirror settings :")
+        col2.active = mat.pov_raytrace_mirror.use
+        col2.prop(mat.pov, "mirror_use_IOR")
+        if mat.pov.mirror_use_IOR:
+            col2.alignment = 'CENTER'
+            col2.label(text="The current Raytrace ")
+            col2.label(text="Transparency IOR is: " + str(mat.pov_raytrace_transparency.ior))
+        col2.prop(mat.pov, "mirror_metallic")
+
+
+'''
+#group some native Blender (SSS) and POV (Fade)settings under such a parent panel?
+class MATERIAL_PT_POV_interior(MaterialButtonsPanel, Panel):
+    bl_label = "POV-Ray Interior"
+    bl_idname = "material.pov_interior"
+    #bl_parent_id = "material.absorption"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+    @classmethod
+    def poll(cls, context):
+        engine = context.scene.render.engine
+        mat=context.material
+        return mat and mat.pov.type == "SURFACE" and (engine in cls.COMPAT_ENGINES) and not (mat.pov.material_use_nodes or mat.use_nodes)
+
+
+    def draw_header(self, context):
+        mat = context.material
+'''
+
+
+class MATERIAL_PT_POV_fade_color(MaterialButtonsPanel, Panel):
+    """Use this class to define pov fading (absorption) color buttons."""
+
+    bl_label = "POV-Ray Absorption"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+    # bl_parent_id = "material.pov_interior"
+
+    @classmethod
+    def poll(cls, context):
+        engine = context.scene.render.engine
+        mat = context.material
+        return (
+            mat
+            and mat.pov.type == "SURFACE"
+            and (engine in cls.COMPAT_ENGINES)
+            and not (mat.pov.material_use_nodes or mat.use_nodes)
+        )
+
+    def draw_header(self, context):
+        mat = context.material
+
+        self.layout.prop(mat.pov, "interior_fade_color", text="")
+
+    def draw(self, context):
+        layout = self.layout
+        mat = context.material
+        # layout.active = mat.pov.interior_fade_color
+        if mat.pov.interior_fade_color != (0.0, 0.0, 0.0):
+            layout.label(text="Raytrace transparency")
+            layout.label(text="depth max Limit needs")
+            layout.label(text="to be non zero to fade")
+
+
+class MATERIAL_PT_POV_caustics(MaterialButtonsPanel, Panel):
+    """Use this class to define pov caustics buttons."""
+
+    bl_label = "Caustics"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        engine = context.scene.render.engine
+        mat = context.material
+        return (
+            mat
+            and mat.pov.type == "SURFACE"
+            and (engine in cls.COMPAT_ENGINES)
+            and not (mat.pov.material_use_nodes or mat.use_nodes)
+        )
+
+    def draw_header(self, context):
+        mat = context.material
+        if mat.pov.caustics_enable:
+            self.layout.prop(mat.pov, "caustics_enable", text="", icon="PMARKER_SEL")
+        else:
+            self.layout.prop(mat.pov, "caustics_enable", text="", icon="PMARKER")
+
+    def draw(self, context):
+
+        layout = self.layout
+
+        mat = context.material
+        layout.active = mat.pov.caustics_enable
+        col = layout.column()
+        if mat.pov.caustics_enable:
+            col.prop(mat.pov, "refraction_caustics")
+            if mat.pov.refraction_caustics:
+
+                col.prop(mat.pov, "refraction_type", text="")
+
+                if mat.pov.refraction_type == "1":
+                    col.prop(mat.pov, "fake_caustics_power", slider=True)
+                elif mat.pov.refraction_type == "2":
+                    col.prop(mat.pov, "photons_dispersion", slider=True)
+                    col.prop(mat.pov, "photons_dispersion_samples", slider=True)
+            col.prop(mat.pov, "photons_reflection")
+
+            if not mat.pov.refraction_caustics and not mat.pov.photons_reflection:
+                col = layout.column()
+                col.alignment = 'CENTER'
+                col.label(text="Caustics override is on, ")
+                col.label(text="but you didn't chose any !")
+
+
+class MATERIAL_PT_strand(MaterialButtonsPanel, Panel):
+    """Use this class to define Blender strand antialiasing buttons."""
+
+    bl_label = "Strand"
+    bl_options = {'DEFAULT_CLOSED'}
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        mat = context.material
+        engine = context.scene.render.engine
+        return (
+            mat and (mat.pov.type in {'SURFACE', 'WIRE', 'HALO'}) and (engine in cls.COMPAT_ENGINES)
+        )
+
+    def draw(self, context):
+        layout = self.layout
+
+        mat = context.material  # don't use node material
+        tan = mat.strand
+
+        split = layout.split()
+
+        col = split.column()
+        sub = col.column(align=True)
+        sub.label(text="Size:")
+        sub.prop(tan, "root_size", text="Root")
+        sub.prop(tan, "tip_size", text="Tip")
+        sub.prop(tan, "size_min", text="Minimum")
+        sub.prop(tan, "use_blender_units")
+        sub = col.column()
+        sub.active = not mat.pov.use_shadeless
+        sub.prop(tan, "use_tangent_shading")
+        col.prop(tan, "shape")
+
+        col = split.column()
+        col.label(text="Shading:")
+        col.prop(tan, "width_fade")
+        ob = context.object
+        if ob and ob.type == 'MESH':
+            col.prop_search(tan, "uv_layer", ob.data, "uv_layers", text="")
+        else:
+            col.prop(tan, "uv_layer", text="")
+        col.separator()
+        sub = col.column()
+        sub.active = not mat.pov.use_shadeless
+        sub.label(text="Surface diffuse:")
+        sub = col.column()
+        sub.prop(tan, "blend_distance", text="Distance")
+
+
+class MATERIAL_PT_POV_replacement_text(MaterialButtonsPanel, Panel):
+    """Use this class to define pov custom code declared name field."""
+
+    bl_label = "Custom POV Code"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def draw(self, context):
+        layout = self.layout
+        mat = context.material
+        col = layout.column()
+        col.alignment = 'RIGHT'
+        col.label(text="Override properties with this")
+        col.label(text="text editor {pov code} block")
+        layout.prop(mat.pov, "replacement_text", text="#declare name", icon='SYNTAX_ON')
+
+
+classes = (
+    MATERIAL_PT_POV_sss,
+    MATERIAL_MT_POV_sss_presets,
+    MATERIAL_OT_POV_sss_add_preset,
+    MATERIAL_PT_strand,
+    MATERIAL_PT_POV_activate_node,
+    MATERIAL_PT_POV_active_node,
+    MATERIAL_PT_POV_specular,
+    MATERIAL_PT_POV_mirror,
+    MATERIAL_PT_POV_transp,
+    MATERIAL_PT_POV_reflection,
+    ## MATERIAL_PT_POV_interior,
+    MATERIAL_PT_POV_fade_color,
+    MATERIAL_PT_POV_caustics,
+    MATERIAL_PT_POV_replacement_text,
+)
+
+
+def register():
+
+    for cls in classes:
+        register_class(cls)
+
+
+def unregister():
+
+    for cls in reversed(classes):
+        unregister_class(cls)
diff --git a/render_povray/shading_nodes.py b/render_povray/shading_nodes.py
new file mode 100755
index 000000000..2e8484f9c
--- /dev/null
+++ b/render_povray/shading_nodes.py
@@ -0,0 +1,2011 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+""""Nodes based User interface for shaders exported to POV textures."""
+import bpy
+
+from bpy.utils import register_class, unregister_class
+from bpy.types import Menu, Node, NodeSocket, CompositorNodeTree, TextureNodeTree, Operator
+from bpy.props import (
+    StringProperty,
+    BoolProperty,
+    IntProperty,
+    FloatProperty,
+    FloatVectorProperty,
+    EnumProperty,
+)
+import nodeitems_utils
+from nodeitems_utils import NodeCategory, NodeItem
+
+
+###############################################################################
+# Pov Nodes init
+###############################################################################
+
+
+class PovraySocketUniversal(NodeSocket):
+    bl_idname = "PovraySocketUniversal"
+    bl_label = "Povray Socket"
+    value_unlimited: bpy.props.FloatProperty(default=0.0)
+    value_0_1: bpy.props.FloatProperty(min=0.0, max=1.0, default=0.0)
+    value_0_10: bpy.props.FloatProperty(min=0.0, max=10.0, default=0.0)
+    value_000001_10: bpy.props.FloatProperty(min=0.000001, max=10.0, default=0.0)
+    value_1_9: bpy.props.IntProperty(min=1, max=9, default=1)
+    value_0_255: bpy.props.IntProperty(min=0, max=255, default=0)
+    percent: bpy.props.FloatProperty(min=0.0, max=100.0, default=0.0)
+
+    def draw(self, context, layout, node, text):
+        space = context.space_data
+        tree = space.edit_tree
+        links = tree.links
+        if self.is_linked:
+            value = []
+            for link in links:
+                if link.from_node == node:
+                    inps = link.to_node.inputs
+                    for inp in inps:
+                        if inp.bl_idname == "PovraySocketFloat_0_1" and inp.is_linked:
+                            prop = "value_0_1"
+                            if prop not in value:
+                                value.append(prop)
+                        if inp.bl_idname == "PovraySocketFloat_000001_10" and inp.is_linked:
+                            prop = "value_000001_10"
+                            if prop not in value:
+                                value.append(prop)
+                        if inp.bl_idname == "PovraySocketFloat_0_10" and inp.is_linked:
+                            prop = "value_0_10"
+                            if prop not in value:
+                                value.append(prop)
+                        if inp.bl_idname == "PovraySocketInt_1_9" and inp.is_linked:
+                            prop = "value_1_9"
+                            if prop not in value:
+                                value.append(prop)
+                        if inp.bl_idname == "PovraySocketInt_0_255" and inp.is_linked:
+                            prop = "value_0_255"
+                            if prop not in value:
+                                value.append(prop)
+                        if inp.bl_idname == "PovraySocketFloatUnlimited" and inp.is_linked:
+                            prop = "value_unlimited"
+                            if prop not in value:
+                                value.append(prop)
+            if len(value) == 1:
+                layout.prop(self, "%s" % value[0], text=text)
+            else:
+                layout.prop(self, "percent", text="Percent")
+        else:
+            layout.prop(self, "percent", text=text)
+
+    def draw_color(self, context, node):
+        return (1, 0, 0, 1)
+
+
+class PovraySocketFloat_0_1(NodeSocket):
+    bl_idname = "PovraySocketFloat_0_1"
+    bl_label = "Povray Socket"
+    default_value: bpy.props.FloatProperty(
+        description="Input node Value_0_1", min=0, max=1, default=0
+    )
+
+    def draw(self, context, layout, node, text):
+        if self.is_linked:
+            layout.label(text=text)
+        else:
+            layout.prop(self, "default_value", text=text, slider=True)
+
+    def draw_color(self, context, node):
+        return (0.5, 0.7, 0.7, 1)
+
+
+class PovraySocketFloat_0_10(NodeSocket):
+    bl_idname = "PovraySocketFloat_0_10"
+    bl_label = "Povray Socket"
+    default_value: bpy.props.FloatProperty(
+        description="Input node Value_0_10", min=0, max=10, default=0
+    )
+
+    def draw(self, context, layout, node, text):
+        if node.bl_idname == "ShaderNormalMapNode" and node.inputs[2].is_linked:
+            layout.label(text="")
+            self.hide_value = True
+        if self.is_linked:
+            layout.label(text=text)
+        else:
+            layout.prop(self, "default_value", text=text, slider=True)
+
+    def draw_color(self, context, node):
+        return (0.65, 0.65, 0.65, 1)
+
+
+class PovraySocketFloat_10(NodeSocket):
+    bl_idname = "PovraySocketFloat_10"
+    bl_label = "Povray Socket"
+    default_value: bpy.props.FloatProperty(
+        description="Input node Value_10", min=-10, max=10, default=0
+    )
+
+    def draw(self, context, layout, node, text):
+        if node.bl_idname == "ShaderNormalMapNode" and node.inputs[2].is_linked:
+            layout.label(text="")
+            self.hide_value = True
+        if self.is_linked:
+            layout.label(text=text)
+        else:
+            layout.prop(self, "default_value", text=text, slider=True)
+
+    def draw_color(self, context, node):
+        return (0.65, 0.65, 0.65, 1)
+
+
+class PovraySocketFloatPositive(NodeSocket):
+    bl_idname = "PovraySocketFloatPositive"
+    bl_label = "Povray Socket"
+    default_value: bpy.props.FloatProperty(
+        description="Input Node Value Positive", min=0.0, default=0
+    )
+
+    def draw(self, context, layout, node, text):
+        if self.is_linked:
+            layout.label(text=text)
+        else:
+            layout.prop(self, "default_value", text=text, slider=True)
+
+    def draw_color(self, context, node):
+        return (0.045, 0.005, 0.136, 1)
+
+
+class PovraySocketFloat_000001_10(NodeSocket):
+    bl_idname = "PovraySocketFloat_000001_10"
+    bl_label = "Povray Socket"
+    default_value: bpy.props.FloatProperty(min=0.000001, max=10, default=0.000001)
+
+    def draw(self, context, layout, node, text):
+        if self.is_output or self.is_linked:
+            layout.label(text=text)
+        else:
+            layout.prop(self, "default_value", text=text, slider=True)
+
+    def draw_color(self, context, node):
+        return (1, 0, 0, 1)
+
+
+class PovraySocketFloatUnlimited(NodeSocket):
+    bl_idname = "PovraySocketFloatUnlimited"
+    bl_label = "Povray Socket"
+    default_value: bpy.props.FloatProperty(default=0.0)
+
+    def draw(self, context, layout, node, text):
+        if self.is_linked:
+            layout.label(text=text)
+        else:
+            layout.prop(self, "default_value", text=text, slider=True)
+
+    def draw_color(self, context, node):
+        return (0.7, 0.7, 1, 1)
+
+
+class PovraySocketInt_1_9(NodeSocket):
+    bl_idname = "PovraySocketInt_1_9"
+    bl_label = "Povray Socket"
+    default_value: bpy.props.IntProperty(
+        description="Input node Value_1_9", min=1, max=9, default=6
+    )
+
+    def draw(self, context, layout, node, text):
+        if self.is_linked:
+            layout.label(text=text)
+        else:
+            layout.prop(self, "default_value", text=text)
+
+    def draw_color(self, context, node):
+        return (1, 0.7, 0.7, 1)
+
+
+class PovraySocketInt_0_256(NodeSocket):
+    bl_idname = "PovraySocketInt_0_256"
+    bl_label = "Povray Socket"
+    default_value: bpy.props.IntProperty(min=0, max=255, default=0)
+
+    def draw(self, context, layout, node, text):
+        if self.is_linked:
+            layout.label(text=text)
+        else:
+            layout.prop(self, "default_value", text=text)
+
+    def draw_color(self, context, node):
+        return (0.5, 0.5, 0.5, 1)
+
+
+class PovraySocketPattern(NodeSocket):
+    bl_idname = "PovraySocketPattern"
+    bl_label = "Povray Socket"
+
+    default_value: bpy.props.EnumProperty(
+        name="Pattern",
+        description="Select the pattern",
+        items=(
+            ("boxed", "Boxed", ""),
+            ("brick", "Brick", ""),
+            ("cells", "Cells", ""),
+            ("checker", "Checker", ""),
+            ("granite", "Granite", ""),
+            ("leopard", "Leopard", ""),
+            ("marble", "Marble", ""),
+            ("onion", "Onion", ""),
+            ("planar", "Planar", ""),
+            ("quilted", "Quilted", ""),
+            ("ripples", "Ripples", ""),
+            ("radial", "Radial", ""),
+            ("spherical", "Spherical", ""),
+            ("spotted", "Spotted", ""),
+            ("waves", "Waves", ""),
+            ("wood", "Wood", ""),
+            ("wrinkles", "Wrinkles", ""),
+        ),
+        default="granite",
+    )
+
+    def draw(self, context, layout, node, text):
+        if self.is_output or self.is_linked:
+            layout.label(text="Pattern")
+        else:
+            layout.prop(self, "default_value", text=text)
+
+    def draw_color(self, context, node):
+        return (1, 1, 1, 1)
+
+
+class PovraySocketColor(NodeSocket):
+    bl_idname = "PovraySocketColor"
+    bl_label = "Povray Socket"
+
+    default_value: FloatVectorProperty(
+        precision=4,
+        step=0.01,
+        min=0,
+        soft_max=1,
+        default=(0.0, 0.0, 0.0),
+        options={"ANIMATABLE"},
+        subtype="COLOR",
+    )
+
+    def draw(self, context, layout, node, text):
+        if self.is_output or self.is_linked:
+            layout.label(text=text)
+        else:
+            layout.prop(self, "default_value", text=text)
+
+    def draw_color(self, context, node):
+        return (1, 1, 0, 1)
+
+
+class PovraySocketColorRGBFT(NodeSocket):
+    bl_idname = "PovraySocketColorRGBFT"
+    bl_label = "Povray Socket"
+
+    default_value: FloatVectorProperty(
+        precision=4,
+        step=0.01,
+        min=0,
+        soft_max=1,
+        default=(0.0, 0.0, 0.0),
+        options={"ANIMATABLE"},
+        subtype="COLOR",
+    )
+    f: bpy.props.FloatProperty(default=0.0, min=0.0, max=1.0)
+    t: bpy.props.FloatProperty(default=0.0, min=0.0, max=1.0)
+
+    def draw(self, context, layout, node, text):
+        if self.is_output or self.is_linked:
+            layout.label(text=text)
+        else:
+            layout.prop(self, "default_value", text=text)
+
+    def draw_color(self, context, node):
+        return (1, 1, 0, 1)
+
+
+class PovraySocketTexture(NodeSocket):
+    bl_idname = "PovraySocketTexture"
+    bl_label = "Povray Socket"
+    default_value: bpy.props.IntProperty()
+
+    def draw(self, context, layout, node, text):
+        layout.label(text=text)
+
+    def draw_color(self, context, node):
+        return (0, 1, 0, 1)
+
+
+class PovraySocketTransform(NodeSocket):
+    bl_idname = "PovraySocketTransform"
+    bl_label = "Povray Socket"
+    default_value: bpy.props.IntProperty(min=0, max=255, default=0)
+
+    def draw(self, context, layout, node, text):
+        layout.label(text=text)
+
+    def draw_color(self, context, node):
+        return (99 / 255, 99 / 255, 199 / 255, 1)
+
+
+class PovraySocketNormal(NodeSocket):
+    bl_idname = "PovraySocketNormal"
+    bl_label = "Povray Socket"
+    default_value: bpy.props.IntProperty(min=0, max=255, default=0)
+
+    def draw(self, context, layout, node, text):
+        layout.label(text=text)
+
+    def draw_color(self, context, node):
+        return (0.65, 0.65, 0.65, 1)
+
+
+class PovraySocketSlope(NodeSocket):
+    bl_idname = "PovraySocketSlope"
+    bl_label = "Povray Socket"
+    default_value: bpy.props.FloatProperty(min=0.0, max=1.0)
+    height: bpy.props.FloatProperty(min=0.0, max=10.0)
+    slope: bpy.props.FloatProperty(min=-10.0, max=10.0)
+
+    def draw(self, context, layout, node, text):
+        if self.is_output or self.is_linked:
+            layout.label(text=text)
+        else:
+            layout.prop(self, "default_value", text="")
+            layout.prop(self, "height", text="")
+            layout.prop(self, "slope", text="")
+
+    def draw_color(self, context, node):
+        return (0, 0, 0, 1)
+
+
+class PovraySocketMap(NodeSocket):
+    bl_idname = "PovraySocketMap"
+    bl_label = "Povray Socket"
+    default_value: bpy.props.StringProperty()
+
+    def draw(self, context, layout, node, text):
+        layout.label(text=text)
+
+    def draw_color(self, context, node):
+        return (0.2, 0, 0.2, 1)
+
+
+class PovrayShaderNodeCategory(NodeCategory):
+    @classmethod
+    def poll(cls, context):
+        return context.space_data.tree_type == "ObjectNodeTree"
+
+
+class PovrayTextureNodeCategory(NodeCategory):
+    @classmethod
+    def poll(cls, context):
+        return context.space_data.tree_type == "TextureNodeTree"
+
+
+class PovraySceneNodeCategory(NodeCategory):
+    @classmethod
+    def poll(cls, context):
+        return context.space_data.tree_type == "CompositorNodeTree"
+
+
+node_categories = [
+    PovrayShaderNodeCategory("SHADEROUTPUT", "Output", items=[NodeItem("PovrayOutputNode")]),
+    PovrayShaderNodeCategory("SIMPLE", "Simple texture", items=[NodeItem("PovrayTextureNode")]),
+    PovrayShaderNodeCategory(
+        "MAPS",
+        "Maps",
+        items=[
+            NodeItem("PovrayBumpMapNode"),
+            NodeItem("PovrayColorImageNode"),
+            NodeItem("ShaderNormalMapNode"),
+            NodeItem("PovraySlopeNode"),
+            NodeItem("ShaderTextureMapNode"),
+            NodeItem("ShaderNodeValToRGB"),
+        ],
+    ),
+    PovrayShaderNodeCategory(
+        "OTHER",
+        "Other patterns",
+        items=[NodeItem("PovrayImagePatternNode"), NodeItem("ShaderPatternNode")],
+    ),
+    PovrayShaderNodeCategory("COLOR", "Color", items=[NodeItem("PovrayPigmentNode")]),
+    PovrayShaderNodeCategory(
+        "TRANSFORM",
+        "Transform",
+        items=[
+            NodeItem("PovrayMappingNode"),
+            NodeItem("PovrayMultiplyNode"),
+            NodeItem("PovrayModifierNode"),
+            NodeItem("PovrayTransformNode"),
+            NodeItem("PovrayValueNode"),
+        ],
+    ),
+    PovrayShaderNodeCategory(
+        "FINISH",
+        "Finish",
+        items=[
+            NodeItem("PovrayFinishNode"),
+            NodeItem("PovrayDiffuseNode"),
+            NodeItem("PovraySpecularNode"),
+            NodeItem("PovrayPhongNode"),
+            NodeItem("PovrayAmbientNode"),
+            NodeItem("PovrayMirrorNode"),
+            NodeItem("PovrayIridescenceNode"),
+            NodeItem("PovraySubsurfaceNode"),
+        ],
+    ),
+    PovrayShaderNodeCategory(
+        "CYCLES",
+        "Cycles",
+        items=[
+            NodeItem("ShaderNodeAddShader"),
+            NodeItem("ShaderNodeAmbientOcclusion"),
+            NodeItem("ShaderNodeAttribute"),
+            NodeItem("ShaderNodeBackground"),
+            NodeItem("ShaderNodeBlackbody"),
+            NodeItem("ShaderNodeBrightContrast"),
+            NodeItem("ShaderNodeBsdfAnisotropic"),
+            NodeItem("ShaderNodeBsdfDiffuse"),
+            NodeItem("ShaderNodeBsdfGlass"),
+            NodeItem("ShaderNodeBsdfGlossy"),
+            NodeItem("ShaderNodeBsdfHair"),
+            NodeItem("ShaderNodeBsdfRefraction"),
+            NodeItem("ShaderNodeBsdfToon"),
+            NodeItem("ShaderNodeBsdfTranslucent"),
+            NodeItem("ShaderNodeBsdfTransparent"),
+            NodeItem("ShaderNodeBsdfVelvet"),
+            NodeItem("ShaderNodeBump"),
+            NodeItem("ShaderNodeCameraData"),
+            NodeItem("ShaderNodeCombineHSV"),
+            NodeItem("ShaderNodeCombineRGB"),
+            NodeItem("ShaderNodeCombineXYZ"),
+            NodeItem("ShaderNodeEmission"),
+            NodeItem("ShaderNodeExtendedMaterial"),
+            NodeItem("ShaderNodeFresnel"),
+            NodeItem("ShaderNodeGamma"),
+            NodeItem("ShaderNodeGeometry"),
+            NodeItem("ShaderNodeGroup"),
+            NodeItem("ShaderNodeHairInfo"),
+            NodeItem("ShaderNodeHoldout"),
+            NodeItem("ShaderNodeHueSaturation"),
+            NodeItem("ShaderNodeInvert"),
+            NodeItem("ShaderNodeLampData"),
+            NodeItem("ShaderNodeLayerWeight"),
+            NodeItem("ShaderNodeLightFalloff"),
+            NodeItem("ShaderNodeLightPath"),
+            NodeItem("ShaderNodeMapping"),
+            NodeItem("ShaderNodeMaterial"),
+            NodeItem("ShaderNodeMath"),
+            NodeItem("ShaderNodeMixRGB"),
+            NodeItem("ShaderNodeMixShader"),
+            NodeItem("ShaderNodeNewGeometry"),
+            NodeItem("ShaderNodeNormal"),
+            NodeItem("ShaderNodeNormalMap"),
+            NodeItem("ShaderNodeObjectInfo"),
+            NodeItem("ShaderNodeOutput"),
+            NodeItem("ShaderNodeOutputLamp"),
+            NodeItem("ShaderNodeOutputLineStyle"),
+            NodeItem("ShaderNodeOutputMaterial"),
+            NodeItem("ShaderNodeOutputWorld"),
+            NodeItem("ShaderNodeParticleInfo"),
+            NodeItem("ShaderNodeRGB"),
+            NodeItem("ShaderNodeRGBCurve"),
+            NodeItem("ShaderNodeRGBToBW"),
+            NodeItem("ShaderNodeScript"),
+            NodeItem("ShaderNodeSeparateHSV"),
+            NodeItem("ShaderNodeSeparateRGB"),
+            NodeItem("ShaderNodeSeparateXYZ"),
+            NodeItem("ShaderNodeSqueeze"),
+            NodeItem("ShaderNodeSubsurfaceScattering"),
+            NodeItem("ShaderNodeTangent"),
+            NodeItem("ShaderNodeTexBrick"),
+            NodeItem("ShaderNodeTexChecker"),
+            NodeItem("ShaderNodeTexCoord"),
+            NodeItem("ShaderNodeTexEnvironment"),
+            NodeItem("ShaderNodeTexGradient"),
+            NodeItem("ShaderNodeTexImage"),
+            NodeItem("ShaderNodeTexMagic"),
+            NodeItem("ShaderNodeTexMusgrave"),
+            NodeItem("ShaderNodeTexNoise"),
+            NodeItem("ShaderNodeTexPointDensity"),
+            NodeItem("ShaderNodeTexSky"),
+            NodeItem("ShaderNodeTexVoronoi"),
+            NodeItem("ShaderNodeTexWave"),
+            NodeItem("ShaderNodeTexture"),
+            NodeItem("ShaderNodeUVAlongStroke"),
+            NodeItem("ShaderNodeUVMap"),
+            NodeItem("ShaderNodeValToRGB"),
+            NodeItem("ShaderNodeValue"),
+            NodeItem("ShaderNodeVectorCurve"),
+            NodeItem("ShaderNodeVectorMath"),
+            NodeItem("ShaderNodeVectorTransform"),
+            NodeItem("ShaderNodeVolumeAbsorption"),
+            NodeItem("ShaderNodeVolumeScatter"),
+            NodeItem("ShaderNodeWavelength"),
+            NodeItem("ShaderNodeWireframe"),
+        ],
+    ),
+    PovrayTextureNodeCategory(
+        "TEXTUREOUTPUT",
+        "Output",
+        items=[NodeItem("TextureNodeValToRGB"), NodeItem("TextureOutputNode")],
+    ),
+    PovraySceneNodeCategory("ISOSURFACE", "Isosurface", items=[NodeItem("IsoPropsNode")]),
+    PovraySceneNodeCategory("FOG", "Fog", items=[NodeItem("PovrayFogNode")]),
+]
+############### end nodes init
+############### nodes ui
+##############Nodes
+
+# def find_node_input(node, name):
+# for input in node.inputs:
+# if input.name == name:
+# return input
+
+# def panel_node_draw(layout, id_data, output_type, input_name):
+# if not id_data.use_nodes:
+# #layout.operator("pov.material_use_nodes", icon='SOUND')#'NODETREE')
+# #layout.operator("pov.use_shading_nodes", icon='NODETREE')
+# layout.operator("WM_OT_context_toggle", icon='NODETREE').data_path = \
+# "material.pov.material_use_nodes"
+# return False
+
+# ntree = id_data.node_tree
+
+# node = find_node(id_data, output_type)
+# if not node:
+# layout.label(text="No output node")
+# else:
+# input = find_node_input(node, input_name)
+# layout.template_node_view(ntree, node, input)
+
+# return True
+
+
+class NODE_MT_POV_map_create(Menu):
+    """Create maps"""
+
+    bl_idname = "POVRAY_MT_node_map_create"
+    bl_label = "Create map"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.operator("node.map_create")
+
+
+def menu_func_nodes(self, context):
+    ob = context.object
+    if hasattr(ob, 'active_material'):
+        mat = context.object.active_material
+        if mat and context.space_data.tree_type == 'ObjectNodeTree':
+            self.layout.prop(mat.pov, "material_use_nodes")
+            self.layout.menu(NODE_MT_POV_map_create.bl_idname)
+            self.layout.operator("wm.updatepreviewkey")
+        if hasattr(mat, 'active_texture') and context.scene.render.engine == 'POVRAY_RENDER':
+            tex = mat.active_texture
+            if tex and context.space_data.tree_type == 'TextureNodeTree':
+                self.layout.prop(tex.pov, "texture_use_nodes")
+
+
+############### object
+
+
+class ObjectNodeTree(bpy.types.NodeTree):
+    '''Povray Material Nodes'''
+
+    bl_idname = 'ObjectNodeTree'
+    bl_label = 'Povray Object Nodes'
+    bl_icon = 'PLUGIN'
+
+    @classmethod
+    def poll(cls, context):
+        return context.scene.render.engine == 'POVRAY_RENDER'
+
+    @classmethod
+    def get_from_context(cls, context):
+        ob = context.active_object
+        if ob and ob.type not in {'LIGHT'}:
+            ma = ob.active_material
+            if ma is not None:
+                nt_name = ma.node_tree
+                if nt_name != '':
+                    return nt_name, ma, ma
+        return (None, None, None)
+
+    def update(self):
+        self.refresh = True
+
+
+################### output #############################################################################################
+
+
+class PovrayOutputNode(Node, ObjectNodeTree):
+    '''Output'''
+
+    bl_idname = 'PovrayOutputNode'
+    bl_label = 'Output'
+    bl_icon = 'SHADING_TEXTURE'
+
+    def init(self, context):
+
+        self.inputs.new('PovraySocketTexture', "Texture")
+
+    def draw_buttons(self, context, layout):
+
+        ob = context.object
+        layout.prop(ob.pov, "object_ior", slider=True)
+
+    def draw_buttons_ext(self, context, layout):
+
+        ob = context.object
+        layout.prop(ob.pov, "object_ior", slider=True)
+
+    def draw_label(self):
+        return "Output"
+
+
+################### material ###########################################################################################
+class PovrayTextureNode(Node, ObjectNodeTree):
+    '''Texture'''
+
+    bl_idname = 'PovrayTextureNode'
+    bl_label = 'Simple texture'
+    bl_icon = 'SHADING_TEXTURE'
+
+    def init(self, context):
+
+        color = self.inputs.new('PovraySocketColor', "Pigment")
+        color.default_value = (1, 1, 1)
+        normal = self.inputs.new('NodeSocketFloat', "Normal")
+        normal.hide_value = True
+        finish = self.inputs.new('NodeSocketVector', "Finish")
+        finish.hide_value = True
+
+        self.outputs.new('PovraySocketTexture', "Texture")
+
+    def draw_label(self):
+        return "Simple texture"
+
+
+class PovrayFinishNode(Node, ObjectNodeTree):
+    '''Finish'''
+
+    bl_idname = 'PovrayFinishNode'
+    bl_label = 'Finish'
+    bl_icon = 'SHADING_TEXTURE'
+
+    def init(self, context):
+
+        self.inputs.new('PovraySocketFloat_0_1', "Emission")
+        ambient = self.inputs.new('NodeSocketVector', "Ambient")
+        ambient.hide_value = True
+        diffuse = self.inputs.new('NodeSocketVector', "Diffuse")
+        diffuse.hide_value = True
+        specular = self.inputs.new('NodeSocketVector', "Highlight")
+        specular.hide_value = True
+        mirror = self.inputs.new('NodeSocketVector', "Mirror")
+        mirror.hide_value = True
+        iridescence = self.inputs.new('NodeSocketVector', "Iridescence")
+        iridescence.hide_value = True
+        subsurface = self.inputs.new('NodeSocketVector', "Translucency")
+        subsurface.hide_value = True
+        self.outputs.new('NodeSocketVector', "Finish")
+
+    def draw_label(self):
+        return "Finish"
+
+
+class PovrayDiffuseNode(Node, ObjectNodeTree):
+    '''Diffuse'''
+
+    bl_idname = 'PovrayDiffuseNode'
+    bl_label = 'Diffuse'
+    bl_icon = 'MATSPHERE'
+
+    def init(self, context):
+
+        intensity = self.inputs.new('PovraySocketFloat_0_1', "Intensity")
+        intensity.default_value = 0.8
+        albedo = self.inputs.new('NodeSocketBool', "Albedo")
+        albedo.default_value = False
+        brilliance = self.inputs.new('PovraySocketFloat_0_10', "Brilliance")
+        brilliance.default_value = 1.8
+        self.inputs.new('PovraySocketFloat_0_1', "Crand")
+        self.outputs.new('NodeSocketVector', "Diffuse")
+
+    def draw_label(self):
+        return "Diffuse"
+
+
+class PovrayPhongNode(Node, ObjectNodeTree):
+    '''Phong'''
+
+    bl_idname = 'PovrayPhongNode'
+    bl_label = 'Phong'
+    bl_icon = 'MESH_UVSPHERE'
+
+    def init(self, context):
+
+        albedo = self.inputs.new('NodeSocketBool', "Albedo")
+        intensity = self.inputs.new('PovraySocketFloat_0_1', "Intensity")
+        intensity.default_value = 0.8
+        phong_size = self.inputs.new('PovraySocketInt_0_256', "Size")
+        phong_size.default_value = 60
+        metallic = self.inputs.new('PovraySocketFloat_0_1', "Metallic")
+
+        self.outputs.new('NodeSocketVector', "Phong")
+
+    def draw_label(self):
+        return "Phong"
+
+
+class PovraySpecularNode(Node, ObjectNodeTree):
+    '''Specular'''
+
+    bl_idname = 'PovraySpecularNode'
+    bl_label = 'Specular'
+    bl_icon = 'MESH_UVSPHERE'
+
+    def init(self, context):
+
+        albedo = self.inputs.new('NodeSocketBool', "Albedo")
+        intensity = self.inputs.new('PovraySocketFloat_0_1', "Intensity")
+        intensity.default_value = 0.8
+        roughness = self.inputs.new('PovraySocketFloat_0_1', "Roughness")
+        roughness.default_value = 0.02
+        metallic = self.inputs.new('PovraySocketFloat_0_1', "Metallic")
+
+        self.outputs.new('NodeSocketVector', "Specular")
+
+    def draw_label(self):
+        return "Specular"
+
+
+class PovrayMirrorNode(Node, ObjectNodeTree):
+    '''Mirror'''
+
+    bl_idname = 'PovrayMirrorNode'
+    bl_label = 'Mirror'
+    bl_icon = 'SHADING_TEXTURE'
+
+    def init(self, context):
+
+        color = self.inputs.new('PovraySocketColor', "Color")
+        color.default_value = (1, 1, 1)
+        metallic = self.inputs.new('PovraySocketFloat_0_1', "Metallic")
+        metallic.default_value = 1.0
+        exponent = self.inputs.new('PovraySocketFloat_0_1', "Exponent")
+        exponent.default_value = 1.0
+        self.inputs.new('PovraySocketFloat_0_1', "Falloff")
+        self.inputs.new('NodeSocketBool', "Fresnel")
+        self.inputs.new('NodeSocketBool', "Conserve energy")
+        self.outputs.new('NodeSocketVector', "Mirror")
+
+    def draw_label(self):
+        return "Mirror"
+
+
+class PovrayAmbientNode(Node, ObjectNodeTree):
+    '''Ambient'''
+
+    bl_idname = 'PovrayAmbientNode'
+    bl_label = 'Ambient'
+    bl_icon = 'SHADING_SOLID'
+
+    def init(self, context):
+
+        self.inputs.new('PovraySocketColor', "Ambient")
+
+        self.outputs.new('NodeSocketVector', "Ambient")
+
+    def draw_label(self):
+        return "Ambient"
+
+
+class PovrayIridescenceNode(Node, ObjectNodeTree):
+    '''Iridescence'''
+
+    bl_idname = 'PovrayIridescenceNode'
+    bl_label = 'Iridescence'
+    bl_icon = 'MESH_UVSPHERE'
+
+    def init(self, context):
+
+        amount = self.inputs.new('NodeSocketFloat', "Amount")
+        amount.default_value = 0.25
+        thickness = self.inputs.new('NodeSocketFloat', "Thickness")
+        thickness.default_value = 1
+        self.inputs.new('NodeSocketFloat', "Turbulence")
+
+        self.outputs.new('NodeSocketVector', "Iridescence")
+
+    def draw_label(self):
+        return "Iridescence"
+
+
+class PovraySubsurfaceNode(Node, ObjectNodeTree):
+    '''Subsurface'''
+
+    bl_idname = 'PovraySubsurfaceNode'
+    bl_label = 'Subsurface'
+    bl_icon = 'MESH_UVSPHERE'
+
+    def init(self, context):
+
+        translucency = self.inputs.new('NodeSocketColor', "Translucency")
+        translucency.default_value = (0, 0, 0, 1)
+        energy = self.inputs.new('PovraySocketInt_0_256', "Energy")
+        energy.default_value = 20
+        self.outputs.new('NodeSocketVector', "Translucency")
+
+    def draw_buttons(self, context, layout):
+        scene = context.scene
+        layout.prop(scene.pov, "sslt_enable", text="SSLT")
+
+    def draw_buttons_ext(self, context, layout):
+        scene = context.scene
+        layout.prop(scene.pov, "sslt_enable", text="SSLT")
+
+    def draw_label(self):
+        return "Subsurface"
+
+
+#####################################################################################################
+
+
+class PovrayMappingNode(Node, ObjectNodeTree):
+    '''Mapping'''
+
+    bl_idname = 'PovrayMappingNode'
+    bl_label = 'Mapping'
+    bl_icon = 'NODE_TEXTURE'
+
+    warp_type: EnumProperty(
+        name="Warp Types",
+        description="Select the type of warp",
+        items=(
+            ('cubic', "Cubic", ""),
+            ('cylindrical', "Cylindrical", ""),
+            ('planar', "Planar", ""),
+            ('spherical', "Spherical", ""),
+            ('toroidal', "Toroidal", ""),
+            ('uv_mapping', "UV", ""),
+            ('NONE', "None", "No indentation"),
+        ),
+        default='NONE',
+    )
+
+    warp_orientation: EnumProperty(
+        name="Warp Orientation",
+        description="Select the orientation of warp",
+        items=(('x', "X", ""), ('y', "Y", ""), ('z', "Z", "")),
+        default='y',
+    )
+
+    warp_dist_exp: FloatProperty(
+        name="Distance exponent", description="Distance exponent", min=0.0, max=100.0, default=1.0
+    )
+
+    warp_tor_major_radius: FloatProperty(
+        name="Major radius",
+        description="Torus is distance from major radius",
+        min=0.0,
+        max=5.0,
+        default=1.0,
+    )
+
+    def init(self, context):
+        self.outputs.new('NodeSocketVector', "Mapping")
+
+    def draw_buttons(self, context, layout):
+
+        column = layout.column()
+        column.prop(self, "warp_type", text="Warp type")
+        if self.warp_type in {'toroidal', 'spherical', 'cylindrical', 'planar'}:
+            column.prop(self, "warp_orientation", text="Orientation")
+            column.prop(self, "warp_dist_exp", text="Exponent")
+        if self.warp_type == 'toroidal':
+            column.prop(self, "warp_tor_major_radius", text="Major R")
+
+    def draw_buttons_ext(self, context, layout):
+
+        column = layout.column()
+        column.prop(self, "warp_type", text="Warp type")
+        if self.warp_type in {'toroidal', 'spherical', 'cylindrical', 'planar'}:
+            column.prop(self, "warp_orientation", text="Orientation")
+            column.prop(self, "warp_dist_exp", text="Exponent")
+        if self.warp_type == 'toroidal':
+            column.prop(self, "warp_tor_major_radius", text="Major R")
+
+    def draw_label(self):
+        return "Mapping"
+
+
+class PovrayMultiplyNode(Node, ObjectNodeTree):
+    '''Multiply'''
+
+    bl_idname = 'PovrayMultiplyNode'
+    bl_label = 'Multiply'
+    bl_icon = 'SHADING_SOLID'
+
+    amount_x: FloatProperty(
+        name="X", description="Number of repeats", min=1.0, max=10000.0, default=1.0
+    )
+
+    amount_y: FloatProperty(
+        name="Y", description="Number of repeats", min=1.0, max=10000.0, default=1.0
+    )
+
+    amount_z: FloatProperty(
+        name="Z", description="Number of repeats", min=1.0, max=10000.0, default=1.0
+    )
+
+    def init(self, context):
+        self.outputs.new('NodeSocketVector', "Amount")
+
+    def draw_buttons(self, context, layout):
+
+        column = layout.column()
+        column.label(text="Amount")
+        row = column.row(align=True)
+        row.prop(self, "amount_x")
+        row.prop(self, "amount_y")
+        row.prop(self, "amount_z")
+
+    def draw_buttons_ext(self, context, layout):
+
+        column = layout.column()
+        column.label(text="Amount")
+        row = column.row(align=True)
+        row.prop(self, "amount_x")
+        row.prop(self, "amount_y")
+        row.prop(self, "amount_z")
+
+    def draw_label(self):
+        return "Multiply"
+
+
+class PovrayTransformNode(Node, ObjectNodeTree):
+    '''Transform'''
+
+    bl_idname = 'PovrayTransformNode'
+    bl_label = 'Transform'
+    bl_icon = 'NODE_TEXTURE'
+
+    def init(self, context):
+
+        self.inputs.new('PovraySocketFloatUnlimited', "Translate x")
+        self.inputs.new('PovraySocketFloatUnlimited', "Translate y")
+        self.inputs.new('PovraySocketFloatUnlimited', "Translate z")
+        self.inputs.new('PovraySocketFloatUnlimited', "Rotate x")
+        self.inputs.new('PovraySocketFloatUnlimited', "Rotate y")
+        self.inputs.new('PovraySocketFloatUnlimited', "Rotate z")
+        sX = self.inputs.new('PovraySocketFloatUnlimited', "Scale x")
+        sX.default_value = 1.0
+        sY = self.inputs.new('PovraySocketFloatUnlimited', "Scale y")
+        sY.default_value = 1.0
+        sZ = self.inputs.new('PovraySocketFloatUnlimited', "Scale z")
+        sZ.default_value = 1.0
+
+        self.outputs.new('NodeSocketVector', "Transform")
+
+    def draw_label(self):
+        return "Transform"
+
+
+class PovrayValueNode(Node, ObjectNodeTree):
+    '''Value'''
+
+    bl_idname = 'PovrayValueNode'
+    bl_label = 'Value'
+    bl_icon = 'SHADING_SOLID'
+
+    def init(self, context):
+
+        self.outputs.new('PovraySocketUniversal', "Value")
+
+    def draw_label(self):
+        return "Value"
+
+
+class PovrayModifierNode(Node, ObjectNodeTree):
+    '''Modifier'''
+
+    bl_idname = 'PovrayModifierNode'
+    bl_label = 'Modifier'
+    bl_icon = 'NODE_TEXTURE'
+
+    def init(self, context):
+
+        turb_x = self.inputs.new('PovraySocketFloat_0_10', "Turb X")
+        turb_x.default_value = 0.1
+        turb_y = self.inputs.new('PovraySocketFloat_0_10', "Turb Y")
+        turb_y.default_value = 0.1
+        turb_z = self.inputs.new('PovraySocketFloat_0_10', "Turb Z")
+        turb_z.default_value = 0.1
+        octaves = self.inputs.new('PovraySocketInt_1_9', "Octaves")
+        octaves.default_value = 1
+        lambat = self.inputs.new('PovraySocketFloat_0_10', "Lambda")
+        lambat.default_value = 2.0
+        omega = self.inputs.new('PovraySocketFloat_0_10', "Omega")
+        omega.default_value = 0.5
+        freq = self.inputs.new('PovraySocketFloat_0_10', "Frequency")
+        freq.default_value = 2.0
+        self.inputs.new('PovraySocketFloat_0_10', "Phase")
+
+        self.outputs.new('NodeSocketVector', "Modifier")
+
+    def draw_label(self):
+        return "Modifier"
+
+
+class PovrayPigmentNode(Node, ObjectNodeTree):
+    '''Pigment'''
+
+    bl_idname = 'PovrayPigmentNode'
+    bl_label = 'Color'
+    bl_icon = 'SHADING_SOLID'
+
+    def init(self, context):
+
+        color = self.inputs.new('PovraySocketColor', "Color")
+        color.default_value = (1, 1, 1)
+        pov_filter = self.inputs.new('PovraySocketFloat_0_1', "Filter")
+        transmit = self.inputs.new('PovraySocketFloat_0_1', "Transmit")
+        self.outputs.new('NodeSocketColor', "Pigment")
+
+    def draw_label(self):
+        return "Color"
+
+
+class PovrayColorImageNode(Node, ObjectNodeTree):
+    '''ColorImage'''
+
+    bl_idname = 'PovrayColorImageNode'
+    bl_label = 'Image map'
+
+    map_type: bpy.props.EnumProperty(
+        name="Map type",
+        description="",
+        items=(
+            ('uv_mapping', "UV", ""),
+            ('0', "Planar", "Default planar mapping"),
+            ('1', "Spherical", "Spherical mapping"),
+            ('2', "Cylindrical", "Cylindrical mapping"),
+            ('5', "Torroidal", "Torus or donut shaped mapping"),
+        ),
+        default='0',
+    )
+    image: StringProperty(maxlen=1024)  # , subtype="FILE_PATH"
+    interpolate: EnumProperty(
+        name="Interpolate",
+        description="Adding the interpolate keyword can smooth the jagged look of a bitmap",
+        items=(
+            ('2', "Bilinear", "Gives bilinear interpolation"),
+            ('4', "Normalized", "Gives normalized distance"),
+        ),
+        default='2',
+    )
+    premultiplied: BoolProperty(default=False)
+    once: BoolProperty(description="Not to repeat", default=False)
+
+    def init(self, context):
+
+        gamma = self.inputs.new('PovraySocketFloat_000001_10', "Gamma")
+        gamma.default_value = 2.0
+        transmit = self.inputs.new('PovraySocketFloat_0_1', "Transmit")
+        pov_filter = self.inputs.new('PovraySocketFloat_0_1', "Filter")
+        mapping = self.inputs.new('NodeSocketVector', "Mapping")
+        mapping.hide_value = True
+        transform = self.inputs.new('NodeSocketVector', "Transform")
+        transform.hide_value = True
+        modifier = self.inputs.new('NodeSocketVector', "Modifier")
+        modifier.hide_value = True
+
+        self.outputs.new('NodeSocketColor', "Pigment")
+
+    def draw_buttons(self, context, layout):
+
+        column = layout.column()
+        im = None
+        for image in bpy.data.images:
+            if image.name == self.image:
+                im = image
+        split = column.split(factor=0.8, align=True)
+        split.prop_search(self, "image", context.blend_data, "images", text="")
+        split.operator("pov.imageopen", text="", icon="FILEBROWSER")
+        if im is not None:
+            column.prop(im, "source", text="")
+        column.prop(self, "map_type", text="")
+        column.prop(self, "interpolate", text="")
+        row = column.row()
+        row.prop(self, "premultiplied", text="Premul")
+        row.prop(self, "once", text="Once")
+
+    def draw_buttons_ext(self, context, layout):
+
+        column = layout.column()
+        im = None
+        for image in bpy.data.images:
+            if image.name == self.image:
+                im = image
+        split = column.split(factor=0.8, align=True)
+        split.prop_search(self, "image", context.blend_data, "images", text="")
+        split.operator("pov.imageopen", text="", icon="FILEBROWSER")
+        if im is not None:
+            column.prop(im, "source", text="")
+        column.prop(self, "map_type", text="")
+        column.prop(self, "interpolate", text="")
+        row = column.row()
+        row.prop(self, "premultiplied", text="Premul")
+        row.prop(self, "once", text="Once")
+
+    def draw_label(self):
+        return "Image map"
+
+
+class PovrayBumpMapNode(Node, ObjectNodeTree):
+    '''BumpMap'''
+
+    bl_idname = 'PovrayBumpMapNode'
+    bl_label = 'Bump map'
+    bl_icon = 'TEXTURE'
+
+    map_type: bpy.props.EnumProperty(
+        name="Map type",
+        description="",
+        items=(
+            ('uv_mapping', "UV", ""),
+            ('0', "Planar", "Default planar mapping"),
+            ('1', "Spherical", "Spherical mapping"),
+            ('2', "Cylindrical", "Cylindrical mapping"),
+            ('5', "Torroidal", "Torus or donut shaped mapping"),
+        ),
+        default='0',
+    )
+    image: StringProperty(maxlen=1024)  # , subtype="FILE_PATH"
+    interpolate: EnumProperty(
+        name="Interpolate",
+        description="Adding the interpolate keyword can smooth the jagged look of a bitmap",
+        items=(
+            ('2', "Bilinear", "Gives bilinear interpolation"),
+            ('4', "Normalized", "Gives normalized distance"),
+        ),
+        default='2',
+    )
+    once: BoolProperty(description="Not to repeat", default=False)
+
+    def init(self, context):
+
+        self.inputs.new('PovraySocketFloat_0_10', "Normal")
+        mapping = self.inputs.new('NodeSocketVector', "Mapping")
+        mapping.hide_value = True
+        transform = self.inputs.new('NodeSocketVector', "Transform")
+        transform.hide_value = True
+        modifier = self.inputs.new('NodeSocketVector', "Modifier")
+        modifier.hide_value = True
+
+        normal = self.outputs.new('NodeSocketFloat', "Normal")
+        normal.hide_value = True
+
+    def draw_buttons(self, context, layout):
+
+        column = layout.column()
+        im = None
+        for image in bpy.data.images:
+            if image.name == self.image:
+                im = image
+        split = column.split(factor=0.8, align=True)
+        split.prop_search(self, "image", context.blend_data, "images", text="")
+        split.operator("pov.imageopen", text="", icon="FILEBROWSER")
+        if im is not None:
+            column.prop(im, "source", text="")
+        column.prop(self, "map_type", text="")
+        column.prop(self, "interpolate", text="")
+        column.prop(self, "once", text="Once")
+
+    def draw_buttons_ext(self, context, layout):
+
+        column = layout.column()
+        im = None
+        for image in bpy.data.images:
+            if image.name == self.image:
+                im = image
+        split = column.split(factor=0.8, align=True)
+        split.prop_search(self, "image", context.blend_data, "images", text="")
+        split.operator("pov.imageopen", text="", icon="FILEBROWSER")
+        if im is not None:
+            column.prop(im, "source", text="")
+        column.prop(self, "map_type", text="")
+        column.prop(self, "interpolate", text="")
+        column.prop(self, "once", text="Once")
+
+    def draw_label(self):
+        return "Bump Map"
+
+
+class PovrayImagePatternNode(Node, ObjectNodeTree):
+    '''ImagePattern'''
+
+    bl_idname = 'PovrayImagePatternNode'
+    bl_label = 'Image pattern'
+    bl_icon = 'NODE_TEXTURE'
+
+    map_type: bpy.props.EnumProperty(
+        name="Map type",
+        description="",
+        items=(
+            ('uv_mapping', "UV", ""),
+            ('0', "Planar", "Default planar mapping"),
+            ('1', "Spherical", "Spherical mapping"),
+            ('2', "Cylindrical", "Cylindrical mapping"),
+            ('5', "Torroidal", "Torus or donut shaped mapping"),
+        ),
+        default='0',
+    )
+    image: StringProperty(maxlen=1024)  # , subtype="FILE_PATH"
+    interpolate: EnumProperty(
+        name="Interpolate",
+        description="Adding the interpolate keyword can smooth the jagged look of a bitmap",
+        items=(
+            ('2', "Bilinear", "Gives bilinear interpolation"),
+            ('4', "Normalized", "Gives normalized distance"),
+        ),
+        default='2',
+    )
+    premultiplied: BoolProperty(default=False)
+    once: BoolProperty(description="Not to repeat", default=False)
+    use_alpha: BoolProperty(default=True)
+
+    def init(self, context):
+
+        gamma = self.inputs.new('PovraySocketFloat_000001_10', "Gamma")
+        gamma.default_value = 2.0
+
+        self.outputs.new('PovraySocketPattern', "Pattern")
+
+    def draw_buttons(self, context, layout):
+
+        column = layout.column()
+        im = None
+        for image in bpy.data.images:
+            if image.name == self.image:
+                im = image
+        split = column.split(factor=0.8, align=True)
+        split.prop_search(self, "image", context.blend_data, "images", text="")
+        split.operator("pov.imageopen", text="", icon="FILEBROWSER")
+        if im is not None:
+            column.prop(im, "source", text="")
+        column.prop(self, "map_type", text="")
+        column.prop(self, "interpolate", text="")
+        row = column.row()
+        row.prop(self, "premultiplied", text="Premul")
+        row.prop(self, "once", text="Once")
+        column.prop(self, "use_alpha", text="Use alpha")
+
+    def draw_buttons_ext(self, context, layout):
+
+        column = layout.column()
+        im = None
+        for image in bpy.data.images:
+            if image.name == self.image:
+                im = image
+        split = column.split(factor=0.8, align=True)
+        split.prop_search(self, "image", context.blend_data, "images", text="")
+        split.operator("pov.imageopen", text="", icon="FILEBROWSER")
+        if im is not None:
+            column.prop(im, "source", text="")
+        column.prop(self, "map_type", text="")
+        column.prop(self, "interpolate", text="")
+        row = column.row()
+        row.prop(self, "premultiplied", text="Premul")
+        row.prop(self, "once", text="Once")
+
+    def draw_label(self):
+        return "Image pattern"
+
+
+class ShaderPatternNode(Node, ObjectNodeTree):
+    '''Pattern'''
+
+    bl_idname = 'ShaderPatternNode'
+    bl_label = 'Other patterns'
+
+    pattern: EnumProperty(
+        name="Pattern",
+        description="Agate, Crackle, Gradient, Pavement, Spiral, Tiling",
+        items=(
+            ('agate', "Agate", ""),
+            ('crackle', "Crackle", ""),
+            ('gradient', "Gradient", ""),
+            ('pavement', "Pavement", ""),
+            ('spiral1', "Spiral 1", ""),
+            ('spiral2', "Spiral 2", ""),
+            ('tiling', "Tiling", ""),
+        ),
+        default='agate',
+    )
+
+    agate_turb: FloatProperty(
+        name="Agate turb", description="Agate turbulence", min=0.0, max=100.0, default=0.5
+    )
+
+    crackle_form_x: FloatProperty(
+        name="X", description="Form vector X", min=-150.0, max=150.0, default=-1
+    )
+
+    crackle_form_y: FloatProperty(
+        name="Y", description="Form vector Y", min=-150.0, max=150.0, default=1
+    )
+
+    crackle_form_z: FloatProperty(
+        name="Z", description="Form vector Z", min=-150.0, max=150.0, default=0
+    )
+
+    crackle_metric: FloatProperty(
+        name="Metric", description="Crackle metric", min=0.0, max=150.0, default=1
+    )
+
+    crackle_solid: BoolProperty(name="Solid", description="Crackle solid", default=False)
+
+    spiral_arms: FloatProperty(name="Number", description="", min=0.0, max=256.0, default=2.0)
+
+    tiling_number: IntProperty(name="Number", description="", min=1, max=27, default=1)
+
+    gradient_orient: EnumProperty(
+        name="Orient",
+        description="",
+        items=(('x', "X", ""), ('y', "Y", ""), ('z', "Z", "")),
+        default='x',
+    )
+
+    def init(self, context):
+
+        pat = self.outputs.new('PovraySocketPattern', "Pattern")
+
+    def draw_buttons(self, context, layout):
+
+        layout.prop(self, "pattern", text="")
+        if self.pattern == 'agate':
+            layout.prop(self, "agate_turb")
+        if self.pattern == 'crackle':
+            layout.prop(self, "crackle_metric")
+            layout.prop(self, "crackle_solid")
+            layout.label(text="Form:")
+            layout.prop(self, "crackle_form_x")
+            layout.prop(self, "crackle_form_y")
+            layout.prop(self, "crackle_form_z")
+        if self.pattern in {"spiral1", "spiral2"}:
+            layout.prop(self, "spiral_arms")
+        if self.pattern in {'tiling'}:
+            layout.prop(self, "tiling_number")
+        if self.pattern in {'gradient'}:
+            layout.prop(self, "gradient_orient")
+
+    def draw_buttons_ext(self, context, layout):
+        pass
+
+    def draw_label(self):
+        return "Other patterns"
+
+
+class ShaderTextureMapNode(Node, ObjectNodeTree):
+    '''Texture Map'''
+
+    bl_idname = 'ShaderTextureMapNode'
+    bl_label = 'Texture map'
+
+    brick_size_x: FloatProperty(name="X", description="", min=0.0000, max=1.0000, default=0.2500)
+
+    brick_size_y: FloatProperty(name="Y", description="", min=0.0000, max=1.0000, default=0.0525)
+
+    brick_size_z: FloatProperty(name="Z", description="", min=0.0000, max=1.0000, default=0.1250)
+
+    brick_mortar: FloatProperty(
+        name="Mortar", description="Mortar", min=0.000, max=1.500, default=0.01
+    )
+
+    def init(self, context):
+        mat = bpy.context.object.active_material
+        self.inputs.new('PovraySocketPattern', "")
+        color = self.inputs.new('NodeSocketColor', "Color ramp")
+        color.hide_value = True
+        for i in range(0, 4):
+            transform = self.inputs.new('PovraySocketTransform', "Transform")
+            transform.hide_value = True
+        number = mat.pov.inputs_number
+        for i in range(number):
+            self.inputs.new('PovraySocketTexture', "%s" % i)
+
+        self.outputs.new('PovraySocketTexture', "Texture")
+
+    def draw_buttons(self, context, layout):
+
+        if self.inputs[0].default_value == 'brick':
+            layout.prop(self, "brick_mortar")
+            layout.label(text="Brick size:")
+            layout.prop(self, "brick_size_x")
+            layout.prop(self, "brick_size_y")
+            layout.prop(self, "brick_size_z")
+
+    def draw_buttons_ext(self, context, layout):
+
+        if self.inputs[0].default_value == 'brick':
+            layout.prop(self, "brick_mortar")
+            layout.label(text="Brick size:")
+            layout.prop(self, "brick_size_x")
+            layout.prop(self, "brick_size_y")
+            layout.prop(self, "brick_size_z")
+
+    def draw_label(self):
+        return "Texture map"
+
+
+class ShaderNormalMapNode(Node, ObjectNodeTree):
+    '''Normal Map'''
+
+    bl_idname = 'ShaderNormalMapNode'
+    bl_label = 'Normal map'
+
+    brick_size_x: FloatProperty(name="X", description="", min=0.0000, max=1.0000, default=0.2500)
+
+    brick_size_y: FloatProperty(name="Y", description="", min=0.0000, max=1.0000, default=0.0525)
+
+    brick_size_z: FloatProperty(name="Z", description="", min=0.0000, max=1.0000, default=0.1250)
+
+    brick_mortar: FloatProperty(
+        name="Mortar", description="Mortar", min=0.000, max=1.500, default=0.01
+    )
+
+    def init(self, context):
+        self.inputs.new('PovraySocketPattern', "")
+        normal = self.inputs.new('PovraySocketFloat_10', "Normal")
+        slope = self.inputs.new('PovraySocketMap', "Slope map")
+        for i in range(0, 4):
+            transform = self.inputs.new('PovraySocketTransform', "Transform")
+            transform.hide_value = True
+        self.outputs.new('PovraySocketNormal', "Normal")
+
+    def draw_buttons(self, context, layout):
+        # for i, inp in enumerate(self.inputs):
+
+        if self.inputs[0].default_value == 'brick':
+            layout.prop(self, "brick_mortar")
+            layout.label(text="Brick size:")
+            layout.prop(self, "brick_size_x")
+            layout.prop(self, "brick_size_y")
+            layout.prop(self, "brick_size_z")
+
+    def draw_buttons_ext(self, context, layout):
+
+        if self.inputs[0].default_value == 'brick':
+            layout.prop(self, "brick_mortar")
+            layout.label(text="Brick size:")
+            layout.prop(self, "brick_size_x")
+            layout.prop(self, "brick_size_y")
+            layout.prop(self, "brick_size_z")
+
+    def draw_label(self):
+        return "Normal map"
+
+
+class ShaderNormalMapEntryNode(Node, ObjectNodeTree):
+    '''Normal Map Entry'''
+
+    bl_idname = 'ShaderNormalMapEntryNode'
+    bl_label = 'Normal map entry'
+
+    def init(self, context):
+        self.inputs.new('PovraySocketFloat_0_1', "Stop")
+        self.inputs.new('PovraySocketFloat_0_1', "Gray")
+
+    def draw_label(self):
+        return "Normal map entry"
+
+
+class IsoPropsNode(Node, CompositorNodeTree):
+    '''ISO Props'''
+
+    bl_idname = 'IsoPropsNode'
+    bl_label = 'Iso'
+    node_label: StringProperty(maxlen=1024)
+
+    def init(self, context):
+        ob = bpy.context.object
+        self.node_label = ob.name
+        text_name = ob.pov.function_text
+        if text_name:
+            text = bpy.data.texts[text_name]
+            for line in text.lines:
+                split = line.body.split()
+                if split[0] == "#declare":
+                    socket = self.inputs.new('NodeSocketFloat', "%s" % split[1])
+                    value = split[3].split(";")
+                    value = value[0]
+                    socket.default_value = float(value)
+
+    def draw_label(self):
+        return self.node_label
+
+
+class PovrayFogNode(Node, CompositorNodeTree):
+    '''Fog settings'''
+
+    bl_idname = 'PovrayFogNode'
+    bl_label = 'Fog'
+
+    def init(self, context):
+        color = self.inputs.new('NodeSocketColor', "Color")
+        color.default_value = (0.7, 0.7, 0.7, 0.25)
+        self.inputs.new('PovraySocketFloat_0_1', "Filter")
+        distance = self.inputs.new('NodeSocketInt', "Distance")
+        distance.default_value = 150
+        self.inputs.new('NodeSocketBool', "Ground")
+        fog_offset = self.inputs.new('NodeSocketFloat', "Offset")
+        fog_alt = self.inputs.new('NodeSocketFloat', "Altitude")
+        turb = self.inputs.new('NodeSocketVector', "Turbulence")
+        turb_depth = self.inputs.new('PovraySocketFloat_0_10', "Depth")
+        turb_depth.default_value = 0.5
+        octaves = self.inputs.new('PovraySocketInt_1_9', "Octaves")
+        octaves.default_value = 5
+        lambdat = self.inputs.new('PovraySocketFloat_0_10', "Lambda")
+        lambdat.default_value = 1.25
+        omega = self.inputs.new('PovraySocketFloat_0_10', "Omega")
+        omega.default_value = 0.35
+        translate = self.inputs.new('NodeSocketVector', "Translate")
+        rotate = self.inputs.new('NodeSocketVector', "Rotate")
+        scale = self.inputs.new('NodeSocketVector', "Scale")
+        scale.default_value = (1, 1, 1)
+
+    def draw_label(self):
+        return "Fog"
+
+
+class PovraySlopeNode(Node, TextureNodeTree):
+    '''Output'''
+
+    bl_idname = 'PovraySlopeNode'
+    bl_label = 'Slope Map'
+
+    def init(self, context):
+        self.use_custom_color = True
+        self.color = (0, 0.2, 0)
+        slope = self.inputs.new('PovraySocketSlope', "0")
+        slope = self.inputs.new('PovraySocketSlope', "1")
+        slopemap = self.outputs.new('PovraySocketMap', "Slope map")
+        output.hide_value = True
+
+    def draw_buttons(self, context, layout):
+
+        layout.operator("pov.nodeinputadd")
+        row = layout.row()
+        row.label(text='Value')
+        row.label(text='Height')
+        row.label(text='Slope')
+
+    def draw_buttons_ext(self, context, layout):
+
+        layout.operator("pov.nodeinputadd")
+        row = layout.row()
+        row.label(text='Value')
+        row.label(text='Height')
+        row.label(text='Slope')
+
+    def draw_label(self):
+        return "Slope Map"
+
+
+######################################## Texture nodes ###############################
+class TextureOutputNode(Node, TextureNodeTree):
+    '''Output'''
+
+    bl_idname = 'TextureOutputNode'
+    bl_label = 'Color Map'
+
+    def init(self, context):
+        tex = bpy.context.object.active_material.active_texture
+        num_sockets = int(tex.pov.density_lines / 32)
+        for i in range(num_sockets):
+            color = self.inputs.new('NodeSocketColor', "%s" % i)
+            color.hide_value = True
+
+    def draw_buttons(self, context, layout):
+
+        layout.label(text="Color Ramps:")
+
+    def draw_label(self):
+        return "Color Map"
+
+
+##################################################################################
+#################################Operators########################################
+##################################################################################
+
+
+class NODE_OT_iso_add(Operator):
+    bl_idname = "pov.nodeisoadd"
+    bl_label = "Create iso props"
+
+    def execute(self, context):
+        ob = bpy.context.object
+        if bpy.context.scene.use_nodes == False:
+            bpy.context.scene.use_nodes = True
+        tree = bpy.context.scene.node_tree
+        for node in tree.nodes:
+            if node.bl_idname == "IsoPropsNode" and node.label == ob.name:
+                tree.nodes.remove(node)
+        isonode = tree.nodes.new('IsoPropsNode')
+        isonode.location = (0, 0)
+        isonode.label = ob.name
+        return {'FINISHED'}
+
+
+class NODE_OT_map_create(Operator):
+    bl_idname = "node.map_create"
+    bl_label = "Create map"
+
+    def execute(self, context):
+        x = y = 0
+        space = context.space_data
+        tree = space.edit_tree
+        for node in tree.nodes:
+            if node.select == True:
+                x, y = node.location
+            node.select = False
+        tmap = tree.nodes.new('ShaderTextureMapNode')
+        tmap.location = (x - 200, y)
+        return {'FINISHED'}
+
+    def invoke(self, context, event):
+        wm = context.window_manager
+        return wm.invoke_props_dialog(self)
+
+    def draw(self, context):
+        layout = self.layout
+        mat = context.object.active_material
+        layout.prop(mat.pov, "inputs_number")
+
+
+class NODE_OT_povray_node_texture_map_add(Operator):
+    bl_idname = "pov.nodetexmapadd"
+    bl_label = "Texture map"
+
+    def execute(self, context):
+        tree = bpy.context.object.active_material.node_tree
+        tmap = tree.nodes.active
+        bpy.context.object.active_material.node_tree.nodes.active = tmap
+        el = tmap.color_ramp.elements.new(0.5)
+        for el in tmap.color_ramp.elements:
+            el.color = (0, 0, 0, 1)
+        for inp in tmap.inputs:
+            tmap.inputs.remove(inp)
+        for outp in tmap.outputs:
+            tmap.outputs.remove(outp)
+        pattern = tmap.inputs.new('NodeSocketVector', "Pattern")
+        pattern.hide_value = True
+        for i in range(0, 3):
+            tmap.inputs.new('NodeSocketColor', "Shader")
+        tmap.outputs.new('NodeSocketShader', "BSDF")
+        tmap.label = "Texture Map"
+        return {'FINISHED'}
+
+
+class NODE_OT_povray_node_output_add(Operator):
+    bl_idname = "pov.nodeoutputadd"
+    bl_label = "Output"
+
+    def execute(self, context):
+        tree = bpy.context.object.active_material.node_tree
+        tmap = tree.nodes.new('ShaderNodeOutputMaterial')
+        bpy.context.object.active_material.node_tree.nodes.active = tmap
+        for inp in tmap.inputs:
+            tmap.inputs.remove(inp)
+        tmap.inputs.new('NodeSocketShader', "Surface")
+        tmap.label = "Output"
+        return {'FINISHED'}
+
+
+class NODE_OT_povray_node_layered_add(Operator):
+    bl_idname = "pov.nodelayeredadd"
+    bl_label = "Layered material"
+
+    def execute(self, context):
+        tree = bpy.context.object.active_material.node_tree
+        tmap = tree.nodes.new('ShaderNodeAddShader')
+        bpy.context.object.active_material.node_tree.nodes.active = tmap
+        tmap.label = "Layered material"
+        return {'FINISHED'}
+
+
+class NODE_OT_povray_input_add(Operator):
+    bl_idname = "pov.nodeinputadd"
+    bl_label = "Add entry"
+
+    def execute(self, context):
+        node = bpy.context.object.active_material.node_tree.nodes.active
+        if node.type in {'VALTORGB'}:
+            number = 1
+            for inp in node.inputs:
+                if inp.type == 'SHADER':
+                    number += 1
+            node.inputs.new('NodeSocketShader', "%s" % number)
+            els = node.color_ramp.elements
+            pos1 = els[len(els) - 1].position
+            pos2 = els[len(els) - 2].position
+            pos = (pos1 - pos2) / 2 + pos2
+            el = els.new(pos)
+
+        if node.bl_idname == 'PovraySlopeNode':
+            number = len(node.inputs)
+            node.inputs.new('PovraySocketSlope', "%s" % number)
+
+        return {'FINISHED'}
+
+
+class NODE_OT_povray_input_remove(Operator):
+    bl_idname = "pov.nodeinputremove"
+    bl_label = "Remove input"
+
+    def execute(self, context):
+        node = bpy.context.object.active_material.node_tree.nodes.active
+        if node.type in {'VALTORGB', 'ADD_SHADER'}:
+            number = len(node.inputs) - 1
+            if number > 5:
+                inp = node.inputs[number]
+                node.inputs.remove(inp)
+                if node.type in {'VALTORGB'}:
+                    els = node.color_ramp.elements
+                    number = len(els) - 2
+                    el = els[number]
+                    els.remove(el)
+        return {'FINISHED'}
+
+
+class NODE_OT_povray_image_open(Operator):
+    bl_idname = "pov.imageopen"
+    bl_label = "Open"
+
+    filepath: StringProperty(
+        name="File Path", description="Open image", maxlen=1024, subtype='FILE_PATH'
+    )
+
+    def invoke(self, context, event):
+        context.window_manager.fileselect_add(self)
+        return {'RUNNING_MODAL'}
+
+    def execute(self, context):
+        im = bpy.data.images.load(self.filepath)
+        node = context.object.active_material.node_tree.nodes.active
+        node.image = im.name
+        return {'FINISHED'}
+
+
+# class TEXTURE_OT_povray_open_image(Operator):
+# bl_idname = "pov.openimage"
+# bl_label = "Open Image"
+
+# filepath = StringProperty(
+# name="File Path",
+# description="Open image",
+# maxlen=1024,
+# subtype='FILE_PATH',
+# )
+
+# def invoke(self, context, event):
+# context.window_manager.fileselect_add(self)
+# return {'RUNNING_MODAL'}
+
+# def execute(self, context):
+# im=bpy.data.images.load(self.filepath)
+# tex = context.texture
+# tex.pov.image = im.name
+# view_layer = context.view_layer
+# view_layer.update()
+# return {'FINISHED'}
+
+
+class PovrayPatternNode(Operator):
+    bl_idname = "pov.patternnode"
+    bl_label = "Pattern"
+
+    add = True
+
+    def execute(self, context):
+        space = context.space_data
+        tree = space.edit_tree
+        for node in tree.nodes:
+            node.select = False
+        if self.add == True:
+            tmap = tree.nodes.new('ShaderNodeValToRGB')
+            tmap.label = "Pattern"
+            for inp in tmap.inputs:
+                tmap.inputs.remove(inp)
+            for outp in tmap.outputs:
+                tmap.outputs.remove(outp)
+            pattern = tmap.inputs.new('PovraySocketPattern', "Pattern")
+            pattern.hide_value = True
+            mapping = tmap.inputs.new('NodeSocketVector', "Mapping")
+            mapping.hide_value = True
+            transform = tmap.inputs.new('NodeSocketVector', "Transform")
+            transform.hide_value = True
+            modifier = tmap.inputs.new('NodeSocketVector', "Modifier")
+            modifier.hide_value = True
+            for i in range(0, 2):
+                tmap.inputs.new('NodeSocketShader', "%s" % (i + 1))
+            tmap.outputs.new('NodeSocketShader', "Material")
+            tmap.outputs.new('NodeSocketColor', "Color")
+            tree.nodes.active = tmap
+            self.add = False
+        aNode = tree.nodes.active
+        aNode.select = True
+        v2d = context.region.view2d
+        x, y = v2d.region_to_view(self.x, self.y)
+        aNode.location = (x, y)
+
+    def modal(self, context, event):
+        if event.type == 'MOUSEMOVE':
+            self.x = event.mouse_region_x
+            self.y = event.mouse_region_y
+            self.execute(context)
+            return {'RUNNING_MODAL'}
+        elif event.type == 'LEFTMOUSE':
+            return {'FINISHED'}
+        elif event.type in ('RIGHTMOUSE', 'ESC'):
+            return {'CANCELLED'}
+
+        return {'RUNNING_MODAL'}
+
+    def invoke(self, context, event):
+        context.window_manager.modal_handler_add(self)
+        return {'RUNNING_MODAL'}
+
+
+class UpdatePreviewMaterial(Operator):
+    '''Operator update preview material'''
+
+    bl_idname = "node.updatepreview"
+    bl_label = "Update preview"
+
+    def execute(self, context):
+        scene = context.view_layer
+        ob = context.object
+        for obj in scene.objects:
+            if obj != ob:
+                scene.objects.active = ob
+                break
+        scene.objects.active = ob
+
+    def modal(self, context, event):
+        if event.type == 'RIGHTMOUSE':
+            self.execute(context)
+            return {'FINISHED'}
+        return {'PASS_THROUGH'}
+
+    def invoke(self, context, event):
+        context.window_manager.modal_handler_add(self)
+        return {'RUNNING_MODAL'}
+
+
+class UpdatePreviewKey(Operator):
+    '''Operator update preview keymap'''
+
+    bl_idname = "wm.updatepreviewkey"
+    bl_label = "Activate RMB"
+
+    @classmethod
+    def poll(cls, context):
+        conf = context.window_manager.keyconfigs.active
+        mapstr = "Node Editor"
+        map = conf.keymaps[mapstr]
+        try:
+            map.keymap_items["node.updatepreview"]
+            return False
+        except BaseException as e:
+            print(e.__doc__)
+            print('An exception occurred: {}'.format(e))
+            return True
+
+    def execute(self, context):
+        conf = context.window_manager.keyconfigs.active
+        mapstr = "Node Editor"
+        map = conf.keymaps[mapstr]
+        map.keymap_items.new("node.updatepreview", type='RIGHTMOUSE', value="PRESS")
+        return {'FINISHED'}
+
+
+classes = (
+    PovraySocketUniversal,
+    PovraySocketFloat_0_1,
+    PovraySocketFloat_0_10,
+    PovraySocketFloat_10,
+    PovraySocketFloatPositive,
+    PovraySocketFloat_000001_10,
+    PovraySocketFloatUnlimited,
+    PovraySocketInt_1_9,
+    PovraySocketInt_0_256,
+    PovraySocketPattern,
+    PovraySocketColor,
+    PovraySocketColorRGBFT,
+    PovraySocketTexture,
+    PovraySocketTransform,
+    PovraySocketNormal,
+    PovraySocketSlope,
+    PovraySocketMap,
+    # PovrayShaderNodeCategory, # XXX SOMETHING BROKEN from 2.8 ?
+    # PovrayTextureNodeCategory, # XXX SOMETHING BROKEN from 2.8 ?
+    # PovraySceneNodeCategory, # XXX SOMETHING BROKEN from 2.8 ?
+    NODE_MT_POV_map_create,
+    ObjectNodeTree,
+    PovrayOutputNode,
+    PovrayTextureNode,
+    PovrayFinishNode,
+    PovrayDiffuseNode,
+    PovrayPhongNode,
+    PovraySpecularNode,
+    PovrayMirrorNode,
+    PovrayAmbientNode,
+    PovrayIridescenceNode,
+    PovraySubsurfaceNode,
+    PovrayMappingNode,
+    PovrayMultiplyNode,
+    PovrayTransformNode,
+    PovrayValueNode,
+    PovrayModifierNode,
+    PovrayPigmentNode,
+    PovrayColorImageNode,
+    PovrayBumpMapNode,
+    PovrayImagePatternNode,
+    ShaderPatternNode,
+    ShaderTextureMapNode,
+    ShaderNormalMapNode,
+    ShaderNormalMapEntryNode,
+    IsoPropsNode,
+    PovrayFogNode,
+    PovraySlopeNode,
+    TextureOutputNode,
+    NODE_OT_iso_add,
+    NODE_OT_map_create,
+    NODE_OT_povray_node_texture_map_add,
+    NODE_OT_povray_node_output_add,
+    NODE_OT_povray_node_layered_add,
+    NODE_OT_povray_input_add,
+    NODE_OT_povray_input_remove,
+    NODE_OT_povray_image_open,
+    PovrayPatternNode,
+    UpdatePreviewMaterial,
+    UpdatePreviewKey,
+)
+
+
+def register():
+    # from bpy.utils import register_class
+    bpy.types.NODE_HT_header.append(menu_func_nodes)
+    nodeitems_utils.register_node_categories("POVRAYNODES", node_categories)
+    for cls in classes:
+        register_class(cls)
+
+
+def unregister():
+    # from bpy.utils import unregister_class
+
+    for cls in reversed(classes):
+        unregister_class(cls)
+    nodeitems_utils.unregister_node_categories("POVRAYNODES")
+    bpy.types.NODE_HT_header.remove(menu_func_nodes)
diff --git a/render_povray/shading_properties.py b/render_povray/shading_properties.py
new file mode 100755
index 000000000..18895eba1
--- /dev/null
+++ b/render_povray/shading_properties.py
@@ -0,0 +1,2290 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+"""Declare shading properties exported to POV textures."""
+import bpy
+from bpy.utils import register_class, unregister_class
+from bpy.types import PropertyGroup
+from bpy.props import (
+    FloatVectorProperty,
+    StringProperty,
+    BoolProperty,
+    IntProperty,
+    FloatProperty,
+    EnumProperty,
+    PointerProperty,
+)
+
+
+def check_material(mat):
+    """Check that material node tree is not empty if use node button is on"""
+    if mat is not None:
+        if mat.use_nodes:
+            if not mat.node_tree:  # FORMERLY : #mat.active_node_material is not None:
+                return True
+            return False
+        return True
+    return False
+
+
+def pov_context_tex_datablock(context):
+    """Texture context type recreated as deprecated in blender 2.8"""
+
+    idblock = context.brush
+    if idblock and context.scene.texture_context == 'OTHER':
+        return idblock
+
+    # idblock = bpy.context.active_object.active_material
+    idblock = context.view_layer.objects.active.active_material
+    if idblock and context.scene.texture_context == 'MATERIAL':
+        return idblock
+
+    idblock = context.scene.world
+    if idblock and context.scene.texture_context == 'WORLD':
+        return idblock
+
+    idblock = context.light
+    if idblock and context.scene.texture_context == 'LIGHT':
+        return idblock
+
+    if context.particle_system and context.scene.texture_context == 'PARTICLES':
+        idblock = context.particle_system.settings
+
+    return idblock
+
+    idblock = context.line_style
+    if idblock and context.scene.texture_context == 'LINESTYLE':
+        return idblock
+
+
+def active_texture_name_from_uilist(self, context):
+    """Name created texture slots the same as created texture"""
+    idblock = pov_context_tex_datablock(context)
+    # mat = context.view_layer.objects.active.active_material
+    if idblock is not None:
+        index = idblock.pov.active_texture_index
+        name = idblock.pov_texture_slots[index].name
+        newname = idblock.pov_texture_slots[index].texture
+        tex = bpy.data.textures[name]
+        tex.name = newname
+        idblock.pov_texture_slots[index].name = newname
+
+
+def active_texture_name_from_search(self, context):
+    """Texture rolldown to change the data linked by an existing texture"""
+    idblock = pov_context_tex_datablock(context)
+    # mat = context.view_layer.objects.active.active_material
+    if idblock is not None:
+        index = idblock.pov.active_texture_index
+        slot = idblock.pov_texture_slots[index]
+        name = slot.texture_search
+
+    try:
+        # tex = bpy.data.textures[name]
+        slot.name = name
+        slot.texture = name
+        # Switch paint brush to this texture so settings remain contextual
+        # bpy.context.tool_settings.image_paint.brush.texture = tex
+        # bpy.context.tool_settings.image_paint.brush.mask_texture = tex
+    except BaseException as e:
+        print(e.__doc__)
+        print('An exception occurred: {}'.format(e))
+        pass
+
+
+def brush_texture_update(self, context):
+
+    """Brush texture rolldown must show active slot texture props"""
+    idblock = pov_context_tex_datablock(context)
+    if idblock is not None:
+        # mat = context.view_layer.objects.active.active_material
+        idblock = pov_context_tex_datablock(context)
+        slot = idblock.pov_texture_slots[idblock.pov.active_texture_index]
+        tex = slot.texture
+
+        if tex:
+            # Switch paint brush to active texture so slot and settings remain contextual
+            bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[tex]
+            bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[tex]
+
+
+class RenderPovSettingsMaterial(PropertyGroup):
+    """Declare material level properties controllable in UI and translated to POV."""
+
+    ######################Begin Old Blender Internal Props#########################
+    # former Space properties from  removed Blender Internal
+    use_limited_texture_context: BoolProperty(
+        name="",
+        description="Use the limited version of texture user (for ‘old shading’ mode)",
+        default=True,
+    )
+    texture_context: EnumProperty(
+        name="Texture context",
+        description="Type of texture data to display and edit",
+        items=(
+            ("MATERIAL", "", "Show material textures", "MATERIAL", 0),  # "Show material textures"
+            ("WORLD", "", "Show world textures", "WORLD", 1),  # "Show world textures"
+            ("LAMP", "", "Show lamp textures", "LIGHT", 2),  # "Show lamp textures"
+            (
+                "PARTICLES",
+                "",
+                "Show particles textures",
+                "PARTICLES",
+                3,
+            ),  # "Show particles textures"
+            (
+                "LINESTYLE",
+                "",
+                "Show linestyle textures",
+                "LINE_DATA",
+                4,
+            ),  # "Show linestyle textures"
+            (
+                "OTHER",
+                "",
+                "Show other data textures",
+                "TEXTURE_DATA",
+                5,
+            ),  # "Show other data textures"
+        ),
+        default="MATERIAL",
+    )
+
+    active_texture_index: IntProperty(
+        name="Index for texture_slots", default=0, update=brush_texture_update
+    )
+
+    transparency_method: EnumProperty(
+        name="Specular Shader Model",
+        description="Method to use for rendering transparency",
+        items=(
+            ("MASK", "Mask", "Mask the background"),
+            ("Z_TRANSPARENCY", "Z Transparency", "Use alpha buffer for transparent faces"),
+            ("RAYTRACE", "Raytrace", "Use raytracing for transparent refraction rendering"),
+        ),
+        default="MASK",
+    )
+
+    use_transparency: BoolProperty(
+        name="Transparency", description="Render material as transparent", default=False
+    )
+
+    alpha: FloatProperty(
+        name="Alpha",
+        description="Alpha transparency of the material",
+        min=0.0,
+        max=1.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+        precision=3,
+    )
+
+    specular_alpha: FloatProperty(
+        name="Specular alpha",
+        description="Alpha transparency for specular areas",
+        min=0.0,
+        max=1.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+        precision=3,
+    )
+
+    ambient: FloatProperty(
+        name="Ambient",
+        description="Amount of global ambient color the material receives",
+        min=0.0,
+        max=1.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+        precision=3,
+    )
+
+    diffuse_color: FloatVectorProperty(
+        name="Diffuse color",
+        description=("Diffuse color of the material"),
+        precision=4,
+        step=0.01,
+        min=0,  # max=inf, soft_max=1,
+        default=(0.6, 0.6, 0.6),
+        options={"ANIMATABLE"},
+        subtype="COLOR",
+    )
+
+    darkness: FloatProperty(
+        name="Darkness",
+        description="Minnaert darkness",
+        min=0.0,
+        max=2.0,
+        soft_min=0.0,
+        soft_max=2.0,
+        default=1.0,
+        precision=3,
+    )
+
+    diffuse_fresnel: FloatProperty(
+        name="Diffuse fresnel",
+        description="Power of Fresnel",
+        min=0.0,
+        max=5.0,
+        soft_min=0.0,
+        soft_max=5.0,
+        default=1.0,
+        precision=3,
+    )
+
+    diffuse_fresnel_factor: FloatProperty(
+        name="Diffuse fresnel factor",
+        description="Blending factor of Fresnel",
+        min=0.0,
+        max=5.0,
+        soft_min=0.0,
+        soft_max=5.0,
+        default=0.5,
+        precision=3,
+    )
+
+    diffuse_intensity: FloatProperty(
+        name="Diffuse intensity",
+        description="Amount of diffuse reflection multiplying color",
+        min=0.0,
+        max=1.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=0.8,
+        precision=3,
+    )
+
+    diffuse_ramp_blend: EnumProperty(
+        name="Diffuse ramp blend",
+        description="Blending method of the ramp and the diffuse color",
+        items=(
+            ("MIX", "Mix", ""),
+            ("ADD", "Add", ""),
+            ("MULTIPLY", "Multiply", ""),
+            ("SUBTRACT", "Subtract", ""),
+            ("SCREEN", "Screen", ""),
+            ("DIVIDE", "Divide", ""),
+            ("DIFFERENCE", "Difference", ""),
+            ("DARKEN", "Darken", ""),
+            ("LIGHTEN", "Lighten", ""),
+            ("OVERLAY", "Overlay", ""),
+            ("DODGE", "Dodge", ""),
+            ("BURN", "Burn", ""),
+            ("HUE", "Hue", ""),
+            ("SATURATION", "Saturation", ""),
+            ("VALUE", "Value", ""),
+            ("COLOR", "Color", ""),
+            ("SOFT_LIGHT", "Soft light", ""),
+            ("LINEAR_LIGHT", "Linear light", ""),
+        ),
+        default="MIX",
+    )
+
+    diffuse_ramp_factor: FloatProperty(
+        name="Factor",
+        description="Blending factor (also uses alpha in Colorband)",
+        min=0.0,
+        max=1.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+        precision=3,
+    )
+
+    diffuse_ramp_input: EnumProperty(
+        name="Input",
+        description="How the ramp maps on the surface",
+        items=(
+            ("SHADER", "Shader", ""),
+            ("ENERGY", "Energy", ""),
+            ("NORMAL", "Normal", ""),
+            ("RESULT", "Result", ""),
+        ),
+        default="SHADER",
+    )
+
+    diffuse_shader: EnumProperty(
+        name="Diffuse Shader Model",
+        description="How the ramp maps on the surface",
+        items=(
+            ("LAMBERT", "Lambert", "Use a Lambertian shader"),
+            ("OREN_NAYAR", "Oren-Nayar", "Use an Oren-Nayar shader"),
+            ("MINNAERT", "Minnaert", "Use a Minnaert shader"),
+            ("FRESNEL", "Fresnel", "Use a Fresnel shader"),
+        ),
+        default="LAMBERT",
+    )
+
+    diffuse_toon_size: FloatProperty(
+        name="Size",
+        description="Size of diffuse toon area",
+        min=0.0,
+        max=3.14,
+        soft_min=0.0,
+        soft_max=3.14,
+        default=0.5,
+        precision=3,
+    )
+
+    diffuse_toon_smooth: FloatProperty(
+        name="Smooth",
+        description="Smoothness of diffuse toon area",
+        min=0.0,
+        max=1.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=0.1,
+        precision=3,
+    )
+
+    emit: FloatProperty(
+        name="Emit",
+        description="Amount of light to emit",
+        min=0.0,
+        soft_min=0.0,  # max=inf, soft_max=inf,
+        default=0.0,
+        precision=3,
+    )
+
+    mirror_color: FloatVectorProperty(
+        name="Mirror color",
+        description=("Mirror color of the material"),
+        precision=4,
+        step=0.01,
+        min=0,  # max=inf, soft_max=1,
+        default=(0.6, 0.6, 0.6),
+        options={"ANIMATABLE"},
+        subtype="COLOR",
+    )
+
+    roughness: FloatProperty(
+        name="Roughness",
+        description="Oren-Nayar Roughness",
+        min=0.0,
+        max=3.14,
+        soft_min=0.0,
+        soft_max=3.14,
+        precision=3,
+        default=0.5,
+    )
+
+    halo: BoolProperty(name="Halo", description=" Halo settings for the material", default=False)
+    # (was readonly in Blender2.79, never None)
+
+    line_color: FloatVectorProperty(
+        name="Line color",
+        description=("Line color used for Freestyle line rendering"),
+        precision=4,
+        step=0.01,
+        min=0,  # max=inf, soft_max=1,
+        default=(0.0, 0.0, 0.0),
+        options={"ANIMATABLE"},
+        subtype="COLOR",
+    )
+
+    # diffuse_ramp:
+    ## Color ramp used to affect diffuse shading
+    ## Type:    ColorRamp, (readonly)
+
+    # cr_node = bpy.data.materials['Material'].node_tree.nodes['ColorRamp']
+    # layout.template_color_ramp(cr_node, "color_ramp", expand=True)
+
+    # ou
+
+    # class bpy.types.ColorRamp(bpy_struct)
+
+    line_priority: IntProperty(
+        name="Recursion Limit",
+        description="The line color of a higher priority is used at material boundaries",
+        min=0,
+        max=32767,
+        default=0,
+    )
+
+    specular_color: FloatVectorProperty(
+        name="Specular color",
+        description=("Specular color of the material "),
+        precision=4,
+        step=0.01,
+        min=0,  # max=inf, soft_max=1,
+        default=(1.0, 1.0, 1.0),
+        options={"ANIMATABLE"},
+        subtype="COLOR",
+    )
+
+    specular_hardness: IntProperty(
+        name="Hardness",
+        description="How hard (sharp) the specular reflection is",
+        min=1,
+        max=511,
+        default=30,
+    )
+
+    specular_intensity: FloatProperty(
+        name="Intensity",
+        description="How intense (bright) the specular reflection is",
+        min=0.0,
+        max=1.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=0.1,
+        precision=3,
+    )
+
+    specular_ior: FloatProperty(
+        name="IOR",
+        description="Specular index of refraction",
+        min=-10.0,
+        max=10.0,
+        soft_min=0.0,
+        soft_max=10.0,
+        default=1.0,
+        precision=3,
+    )
+
+    ior: FloatProperty(
+        name="IOR",
+        description="Index of refraction",
+        min=-10.0,
+        max=10.0,
+        soft_min=0.0,
+        soft_max=10.0,
+        default=1.0,
+        precision=3,
+    )
+
+    specular_shader: EnumProperty(
+        name="Specular Shader Model",
+        description="How the ramp maps on the surface",
+        items=(
+            ("COOKTORR", "CookTorr", "Use a Cook-Torrance shader"),
+            ("PHONG", "Phong", "Use a Phong shader"),
+            ("BLINN", "Blinn", "Use a Blinn shader"),
+            ("TOON", "Toon", "Use a Toon shader"),
+            ("WARDISO", "WardIso", "Use a Ward anisotropic shader"),
+        ),
+        default="COOKTORR",
+    )
+
+    specular_slope: FloatProperty(
+        name="Slope",
+        description="The standard deviation of surface slope",
+        min=0.0,
+        max=0.4,
+        soft_min=0.0,
+        soft_max=0.4,
+        default=0.1,
+        precision=3,
+    )
+
+    specular_toon_size: FloatProperty(
+        name="Size",
+        description="Size of specular toon area",
+        min=0.0,
+        max=0.53,
+        soft_min=0.0,
+        soft_max=0.53,
+        default=0.5,
+        precision=3,
+    )
+
+    specular_toon_smooth: FloatProperty(
+        name="Smooth",
+        description="Smoothness of specular toon area",
+        min=0.0,
+        max=1.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=0.1,
+        precision=3,
+    )
+
+    translucency: FloatProperty(
+        name="Translucency",
+        description="Amount of diffuse shading on the back side",
+        min=0.0,
+        max=1.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=0.0,
+        precision=3,
+    )
+
+    transparency_method: EnumProperty(
+        name="Specular Shader Model",
+        description="Method to use for rendering transparency",
+        items=(
+            ("MASK", "Mask", "Mask the background"),
+            ("Z_TRANSPARENCY", "Z Transparency", "Use an ior of 1 for transparent faces"),
+            ("RAYTRACE", "Raytrace", "Use raytracing for transparent refraction rendering"),
+        ),
+        default="MASK",
+    )
+
+    type: EnumProperty(
+        name="Type",
+        description="Material type defining how the object is rendered",
+        items=(
+            ("SURFACE", "Surface", "Render object as a surface"),
+            # TO UPDATE > USE wire MACRO AND CHANGE DESCRIPTION
+            ("WIRE", "Wire", "Render the edges of faces as wires (not supported in raytracing)"),
+            ("VOLUME", "Volume", "Render object as a volume"),
+            # TO UPDATE > USE halo MACRO AND CHANGE DESCRIPTION
+            ("HALO", "Halo", "Render object as halo particles"),
+        ),
+        default="SURFACE",
+    )
+
+    use_cast_shadows: BoolProperty(
+        name="Cast", description="Allow this material to cast shadows", default=True
+    )
+
+    use_cast_shadows_only: BoolProperty(
+        name="Cast Only",
+        description="Make objects with this material "
+        "appear invisible (not rendered), only "
+        "casting shadows",
+        default=False,
+    )
+
+    use_cubic: BoolProperty(
+        name="Cubic Interpolation",
+        description="Use cubic interpolation for diffuse " "values, for smoother transitions",
+        default=False,
+    )
+
+    use_diffuse_ramp: BoolProperty(
+        name="Ramp", description="Toggle diffuse ramp operations", default=False
+    )
+
+    use_light_group_exclusive: BoolProperty(
+        name="Exclusive",
+        description="Material uses the light group exclusively"
+        "- these lamps are excluded from other "
+        "scene lighting",
+        default=False,
+    )
+
+    use_light_group_local: BoolProperty(
+        name="Local",
+        description="When linked in, material uses local light" " group with the same name",
+        default=False,
+    )
+
+    use_mist: BoolProperty(
+        name="Use Mist",
+        description="Use mist with this material " "(in world settings)",
+        default=True,
+    )
+
+    use_nodes: BoolProperty(
+        name="Nodes",
+        # Add Icon in UI or here? icon='NODES'
+        description="Use shader nodes to render the material",
+        default=False,
+    )
+
+    use_object_color: BoolProperty(
+        name="Object Color",
+        description="Modulate the result with a per-object color",
+        default=False,
+    )
+
+    use_only_shadow: BoolProperty(
+        name="Shadows Only",
+        description="Render shadows as the material’s alpha "
+        "value, making the material transparent "
+        "except for shadowed areas",
+        default=False,
+    )
+
+    use_shadeless: BoolProperty(
+        name="Shadeless",
+        description="Make this material insensitive to " "light or shadow",
+        default=False,
+    )
+
+    use_shadows: BoolProperty(
+        name="Receive", description="Allow this material to receive shadows", default=True
+    )
+
+    use_sky: BoolProperty(
+        name="Sky",
+        description="Render this material with zero alpha, "
+        "with sky background in place (scanline only)",
+        default=False,
+    )
+
+    use_specular_ramp: BoolProperty(
+        name="Ramp", description="Toggle specular ramp operations", default=False
+    )
+
+    use_tangent_shading: BoolProperty(
+        name="Tangent Shading",
+        description="Use the material’s tangent vector instead"
+        "of the normal for shading - for "
+        "anisotropic shading effects",
+        default=False,
+    )
+
+    use_transparent_shadows: BoolProperty(
+        name="Receive Transparent",
+        description="Allow this object to receive transparent " "shadows cast through other object",
+        default=False,
+    )  # linked to fake caustics
+
+    use_vertex_color_light: BoolProperty(
+        name="Vertex Color Light",
+        description="Add vertex colors as additional lighting",
+        default=False,
+    )
+
+    use_vertex_color_paint: BoolProperty(
+        name="Vertex Color Paint",
+        description="Replace object base color with vertex "
+        "colors (multiply with ‘texture face’ "
+        "face assigned textures)",
+        default=False,
+    )
+
+    specular_ramp_blend: EnumProperty(
+        name="Specular ramp blend",
+        description="Blending method of the ramp and the specular color",
+        items=(
+            ("MIX", "Mix", ""),
+            ("ADD", "Add", ""),
+            ("MULTIPLY", "Multiply", ""),
+            ("SUBTRACT", "Subtract", ""),
+            ("SCREEN", "Screen", ""),
+            ("DIVIDE", "Divide", ""),
+            ("DIFFERENCE", "Difference", ""),
+            ("DARKEN", "Darken", ""),
+            ("LIGHTEN", "Lighten", ""),
+            ("OVERLAY", "Overlay", ""),
+            ("DODGE", "Dodge", ""),
+            ("BURN", "Burn", ""),
+            ("HUE", "Hue", ""),
+            ("SATURATION", "Saturation", ""),
+            ("VALUE", "Value", ""),
+            ("COLOR", "Color", ""),
+            ("SOFT_LIGHT", "Soft light", ""),
+            ("LINEAR_LIGHT", "Linear light", ""),
+        ),
+        default="MIX",
+    )
+
+    specular_ramp_factor: FloatProperty(
+        name="Factor",
+        description="Blending factor (also uses alpha in Colorband)",
+        min=0.0,
+        max=1.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+        precision=3,
+    )
+
+    specular_ramp_input: EnumProperty(
+        name="Input",
+        description="How the ramp maps on the surface",
+        items=(
+            ("SHADER", "Shader", ""),
+            ("ENERGY", "Energy", ""),
+            ("NORMAL", "Normal", ""),
+            ("RESULT", "Result", ""),
+        ),
+        default="SHADER",
+    )
+
+    irid_enable: BoolProperty(
+        name="Iridescence coating",
+        description="Newton's thin film interference (like an oil slick on a puddle of "
+        "water or the rainbow hues of a soap bubble.)",
+        default=False,
+    )
+
+    mirror_use_IOR: BoolProperty(
+        name="Correct Reflection",
+        description="Use same IOR as raytrace transparency to calculate mirror reflections. "
+        "More physically correct",
+        default=False,
+    )
+
+    mirror_metallic: BoolProperty(
+        name="Metallic Reflection",
+        description="mirror reflections get colored as diffuse (for metallic materials)",
+        default=False,
+    )
+
+    conserve_energy: BoolProperty(
+        name="Conserve Energy",
+        description="Light transmitted is more correctly reduced by mirror reflections, "
+        "also the sum of diffuse and translucency gets reduced below one ",
+        default=True,
+    )
+
+    irid_amount: FloatProperty(
+        name="amount",
+        description="Contribution of the iridescence effect to the overall surface color. "
+        "As a rule of thumb keep to around 0.25 (25% contribution) or less, "
+        "but experiment. If the surface is coming out too white, try lowering "
+        "the diffuse and possibly the ambient values of the surface",
+        min=0.0,
+        max=1.0,
+        soft_min=0.01,
+        soft_max=1.0,
+        default=0.25,
+    )
+
+    irid_thickness: FloatProperty(
+        name="thickness",
+        description="A very thin film will have a high frequency of color changes while a "
+        "thick film will have large areas of color",
+        min=0.0,
+        max=1000.0,
+        soft_min=0.1,
+        soft_max=10.0,
+        default=1,
+    )
+
+    irid_turbulence: FloatProperty(
+        name="turbulence",
+        description="This parameter varies the thickness",
+        min=0.0,
+        max=10.0,
+        soft_min=0.000,
+        soft_max=1.0,
+        default=0,
+    )
+
+    interior_fade_color: FloatVectorProperty(
+        name="Interior Fade Color",
+        description="Color of filtered attenuation for transparent " "materials",
+        precision=4,
+        step=0.01,
+        min=0.0,
+        soft_max=1.0,
+        default=(0, 0, 0),
+        options={"ANIMATABLE"},
+        subtype="COLOR",
+    )
+
+    caustics_enable: BoolProperty(
+        name="Caustics",
+        description="use only fake refractive caustics (default) or photon based "
+        "reflective/refractive caustics",
+        default=True,
+    )
+
+    fake_caustics: BoolProperty(
+        name="Fake Caustics", description="use only (Fast) fake refractive caustics", default=True
+    )
+
+    fake_caustics_power: FloatProperty(
+        name="Fake caustics power",
+        description="Values typically range from 0.0 to 1.0 or higher. Zero is no caustics. "
+        "Low, non-zero values give broad hot-spots while higher values give "
+        "tighter, smaller simulated focal points",
+        min=0.00,
+        max=10.0,
+        soft_min=0.00,
+        soft_max=5.0,
+        default=0.15,
+    )
+
+    refraction_caustics: BoolProperty(
+        name="Refractive Caustics",
+        description="hotspots of light focused when going through the material",
+        default=True,
+    )
+
+    photons_dispersion: FloatProperty(
+        name="Chromatic Dispersion",
+        description="Light passing through will be separated according to wavelength. "
+        "This ratio of refractive indices for violet to red controls how much "
+        "the colors are spread out 1 = no dispersion, good values are 1.01 to 1.1",
+        min=1.0000,
+        max=10.000,
+        soft_min=1.0000,
+        soft_max=1.1000,
+        precision=4,
+        default=1.0000,
+    )
+
+    photons_dispersion_samples: IntProperty(
+        name="Dispersion Samples",
+        description="Number of color-steps for dispersion",
+        min=2,
+        max=128,
+        default=7,
+    )
+
+    photons_reflection: BoolProperty(
+        name="Reflective Photon Caustics",
+        description="Use this to make your Sauron's ring ;-P",
+        default=False,
+    )
+
+    refraction_type: EnumProperty(
+        items=[
+            ("1", "Z Transparency Fake Caustics", "use fake caustics"),
+            ("2", "Raytrace Photons Caustics", "use photons for refractive caustics"),
+        ],
+        name="Refraction Type:",
+        description="use fake caustics (fast) or true photons for refractive Caustics",
+        default="1",
+    )
+
+    ##################################CustomPOV Code############################
+    replacement_text: StringProperty(
+        name="Declared name:",
+        description="Type the variable name as declared either directly inlined "
+        "in your custom POV code from the text editor datablock (checked as a "
+        "source to render in it's side property panel), or this declaration can be "
+        "from an external .inc it points at. Here, name = texture {} expected",
+        default="",
+    )
+
+    # NODES
+
+    def use_material_nodes_callback(self, context):
+        """Identify if node has been added and if it is used yet or default"""
+
+        if hasattr(context.space_data, "tree_type"):
+            context.space_data.tree_type = "ObjectNodeTree"
+        mat = context.object.active_material
+        if mat.pov.material_use_nodes:
+            mat.use_nodes = True
+            tree = mat.node_tree
+            # tree.name = mat.name # XXX READONLY
+            links = tree.links
+            default = True
+            if len(tree.nodes) == 2:
+                o = 0
+                m = 0
+                for node in tree.nodes:
+                    if node.type in {"OUTPUT", "MATERIAL"}:
+                        tree.nodes.remove(node)
+                        default = True
+                for node in tree.nodes:
+                    if node.bl_idname == "PovrayOutputNode":
+                        o += 1
+                    if node.bl_idname == "PovrayTextureNode":
+                        m += 1
+                if o == 1 and m == 1:
+                    default = False
+            elif len(tree.nodes) == 0:
+                default = True
+            else:
+                default = False
+            if default:
+                output = tree.nodes.new("PovrayOutputNode")
+                output.location = 200, 200
+                tmap = tree.nodes.new("PovrayTextureNode")
+                tmap.location = 0, 200
+                links.new(tmap.outputs[0], output.inputs[0])
+                tmap.select = True
+                tree.nodes.active = tmap
+        else:
+            mat.use_nodes = False
+
+    def use_texture_nodes_callback(self, context):
+        """Identify texture nodes by filtering out output and composite ones"""
+
+        tex = context.object.active_material.active_texture
+        if tex.pov.texture_use_nodes:
+            tex.use_nodes = True
+            if len(tex.node_tree.nodes) == 2:
+                for node in tex.node_tree.nodes:
+                    if node.type in {"OUTPUT", "CHECKER"}:
+                        tex.node_tree.nodes.remove(node)
+        else:
+            tex.use_nodes = False
+
+    def node_active_callback(self, context):
+        """Synchronize active node with material before getting it"""
+
+        items = []  # XXX comment out > remove?
+        mat = context.material
+        mat.node_tree.nodes  # XXX comment out > remove?
+        for node in mat.node_tree.nodes:
+            node.select = False
+        for node in mat.node_tree.nodes:
+            if node.name == mat.pov.material_active_node:
+                node.select = True
+                mat.node_tree.nodes.active = node
+
+                return node
+
+    def node_enum_callback(self, context):
+        items = []
+        mat = context.material
+        nodes = mat.node_tree.nodes
+        for node in nodes:
+            items.append(("%s" % node.name, "%s" % node.name, ""))
+        return items
+
+    def pigment_normal_callback(self, context):
+        render = context.scene.pov.render  # XXX comment out > remove?
+        items = [("pigment", "Pigment", ""), ("normal", "Normal", "")]
+        # XXX Find any other such traces of hgpovray experiment > remove or deploy ?
+        if render == "hgpovray":
+            items = [
+                ("pigment", "Pigment", ""),
+                ("normal", "Normal", ""),
+                ("modulation", "Modulation", ""),
+            ]
+        return items
+
+    def glow_callback(self, context):
+        scene = context.scene
+        ob = context.object
+        ob.pov.mesh_write_as_old = ob.pov.mesh_write_as
+        if scene.pov.render == "uberpov" and ob.pov.glow:
+            ob.pov.mesh_write_as = "NONE"
+        else:
+            ob.pov.mesh_write_as = ob.pov.mesh_write_as_old
+
+    material_use_nodes: BoolProperty(
+        name="Use nodes", description="", update=use_material_nodes_callback, default=False
+    )
+
+    material_active_node: EnumProperty(
+        name="Active node", description="", items=node_enum_callback, update=node_active_callback
+    )
+
+    preview_settings: BoolProperty(name="Preview Settings", description="", default=False)
+
+    object_preview_transform: BoolProperty(name="Transform object", description="", default=False)
+
+    object_preview_scale: FloatProperty(name="XYZ", min=0.5, max=2.0, default=1.0)
+
+    object_preview_rotate: FloatVectorProperty(
+        name="Rotate", description="", min=-180.0, max=180.0, default=(0.0, 0.0, 0.0), subtype="XYZ"
+    )
+
+    object_preview_bgcontrast: FloatProperty(name="Contrast", min=0.0, max=1.0, default=0.5)
+
+
+class MaterialRaytraceTransparency(PropertyGroup):
+    """Declare transparency panel properties controllable in UI and translated to POV."""
+
+    depth: IntProperty(
+        name="Depth",
+        description="Maximum allowed number of light inter-refractions",
+        min=0,
+        max=32767,
+        default=2,
+    )
+
+    depth_max: FloatProperty(
+        name="Depth",
+        description="Maximum depth for light to travel through the "
+        "transparent material before becoming fully filtered (0.0 is disabled)",
+        min=0,
+        max=100,
+        default=0.0,
+    )
+
+    falloff: FloatProperty(
+        name="Falloff",
+        description="Falloff power for transmissivity filter effect (1.0 is linear)",
+        min=0.1,
+        max=10.0,
+        default=1.0,
+        precision=3,
+    )
+
+    filter: FloatProperty(
+        name="Filter",
+        description="Amount to blend in the material’s diffuse color in raytraced "
+        "transparency (simulating absorption)",
+        min=0.0,
+        max=1.0,
+        default=0.0,
+        precision=3,
+    )
+
+    fresnel: FloatProperty(
+        name="Fresnel",
+        description="Power of Fresnel for transparency (Ray or ZTransp)",
+        min=0.0,
+        max=5.0,
+        soft_min=0.0,
+        soft_max=5.0,
+        default=0.0,
+        precision=3,
+    )
+
+    fresnel_factor: FloatProperty(
+        name="Blend",
+        description="Blending factor for Fresnel",
+        min=0.0,
+        max=5.0,
+        soft_min=0.0,
+        soft_max=5.0,
+        default=1.250,
+        precision=3,
+    )
+
+    gloss_factor: FloatProperty(
+        name="Amount",
+        description="The clarity of the refraction. "
+        "(values < 1.0 give diffuse, blurry refractions)",
+        min=0.0,
+        max=1.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+        precision=3,
+    )
+
+    gloss_samples: IntProperty(
+        name="Samples",
+        description="frequency of the noise sample used for blurry refractions",
+        min=0,
+        max=1024,
+        default=18,
+    )
+
+    gloss_threshold: FloatProperty(
+        name="Threshold",
+        description="Threshold for adaptive sampling (if a sample "
+        "contributes less than this amount [as a percentage], "
+        "sampling is stopped)",
+        min=0.0,
+        max=1.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=0.005,
+        precision=3,
+    )
+
+    ior: FloatProperty(
+        name="IOR",
+        description="Sets angular index of refraction for raytraced refraction",
+        min=-0.0,
+        max=10.0,
+        soft_min=0.25,
+        soft_max=4.0,
+        default=1.3,
+    )
+
+
+class MaterialRaytraceMirror(PropertyGroup):
+    """Declare reflection panel properties controllable in UI and translated to POV."""
+
+    bl_description = ("Raytraced reflection settings for the Material",)
+
+    use: BoolProperty(name="Mirror", description="Enable raytraced reflections", default=False)
+
+    depth: IntProperty(
+        name="Depth",
+        description="Maximum allowed number of light inter-reflections",
+        min=0,
+        max=32767,
+        default=2,
+    )
+
+    distance: FloatProperty(
+        name="Max Dist",
+        description="Maximum distance of reflected rays "
+        "(reflections further than this range "
+        "fade to sky color or material color)",
+        min=0.0,
+        max=100000.0,
+        soft_min=0.0,
+        soft_max=10000.0,
+        default=0.0,
+        precision=3,
+    )
+
+    fade_to: EnumProperty(
+        items=[
+            ("FADE_TO_SKY", "Fade to sky", ""),
+            ("FADE_TO_MATERIAL", "Fade to material color", ""),
+        ],
+        name="Fade-out Color",
+        description="The color that rays with no intersection within the "
+        "Max Distance take (material color can be best for "
+        "indoor scenes, sky color for outdoor)",
+        default="FADE_TO_SKY",
+    )
+
+    fresnel: FloatProperty(
+        name="Fresnel",
+        description="Power of Fresnel for mirror reflection",
+        min=0.0,
+        max=5.0,
+        soft_min=0.0,
+        soft_max=5.0,
+        default=0.0,
+        precision=3,
+    )
+
+    fresnel_factor: FloatProperty(
+        name="Blend",
+        description="Blending factor for Fresnel",
+        min=0.0,
+        max=5.0,
+        soft_min=0.0,
+        soft_max=5.0,
+        default=1.250,
+        precision=3,
+    )
+
+    gloss_anisotropic: FloatProperty(
+        name="Anisotropic",
+        description="The shape of the reflection, from 0.0 (circular) "
+        "to 1.0 (fully stretched along the tangent",
+        min=0.0,
+        max=1.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+        precision=3,
+    )
+
+    gloss_factor: FloatProperty(
+        name="Amount",
+        description="The shininess of the reflection  "
+        "(values < 1.0 give diffuse, blurry reflections)",
+        min=0.0,
+        max=1.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+        precision=3,
+    )
+
+    gloss_samples: IntProperty(
+        name="Noise",
+        description="Frequency of the noise pattern bumps averaged for blurry reflections",
+        min=0,
+        max=1024,
+        default=18,
+    )
+
+    gloss_threshold: FloatProperty(
+        name="Threshold",
+        description="Threshold for adaptive sampling (if a sample "
+        "contributes less than this amount [as a percentage], "
+        "sampling is stopped)",
+        min=0.0,
+        max=1.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=0.005,
+        precision=3,
+    )
+
+    mirror_color: FloatVectorProperty(
+        name="Mirror color",
+        description=("Mirror color of the material"),
+        precision=4,
+        step=0.01,
+        default=(1.0, 1.0, 1.0),
+        options={"ANIMATABLE"},
+        subtype="COLOR",
+    )
+
+    reflect_factor: FloatProperty(
+        name="Reflectivity",
+        description="Amount of mirror reflection for raytrace",
+        min=0.0,
+        max=1.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+        precision=3,
+    )
+
+
+class MaterialSubsurfaceScattering(PropertyGroup):
+    r"""Declare SSS/SSTL properties controllable in UI and translated to POV."""
+
+    bl_description = ("Subsurface scattering settings for the material",)
+
+    use: BoolProperty(
+        name="Subsurface Scattering",
+        description="Enable diffuse subsurface scatting " "effects in a material",
+        default=False,
+    )
+
+    back: FloatProperty(
+        name="Back",
+        description="Back scattering weight",
+        min=0.0,
+        max=10.0,
+        soft_min=0.0,
+        soft_max=10.0,
+        default=1.0,
+        precision=3,
+    )
+
+    color: FloatVectorProperty(
+        name="Scattering color",
+        description=("Scattering color"),
+        precision=4,
+        step=0.01,
+        default=(0.604, 0.604, 0.604),
+        options={"ANIMATABLE"},
+        subtype="COLOR",
+    )
+
+    color_factor: FloatProperty(
+        name="Color",
+        description="Blend factor for SSS colors",
+        min=0.0,
+        max=1.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+        precision=3,
+    )
+
+    error_threshold: FloatProperty(
+        name="Error",
+        description="Error tolerance (low values are slower and higher quality)",
+        default=0.050,
+        precision=3,
+    )
+
+    front: FloatProperty(
+        name="Front",
+        description="Front scattering weight",
+        min=0.0,
+        max=2.0,
+        soft_min=0.0,
+        soft_max=2.0,
+        default=1.0,
+        precision=3,
+    )
+
+    ior: FloatProperty(
+        name="IOR",
+        description="Index of refraction (higher values are denser)",
+        min=-0.0,
+        max=10.0,
+        soft_min=0.1,
+        soft_max=2.0,
+        default=1.3,
+    )
+
+    radius: FloatVectorProperty(
+        name="RGB Radius",
+        description=("Mean red/green/blue scattering path length"),
+        precision=4,
+        step=0.01,
+        min=0.001,
+        default=(1.0, 1.0, 1.0),
+        options={"ANIMATABLE"},
+    )
+
+    scale: FloatProperty(
+        name="Scale", description="Object scale factor", default=0.100, precision=3
+    )
+
+    texture_factor: FloatProperty(
+        name="Texture",
+        description="Texture scattering blend factor",
+        min=0.0,
+        max=1.0,
+        soft_min=0.0,
+        soft_max=1.0,
+        default=0.0,
+        precision=3,
+    )
+
+
+class MaterialStrandSettings(PropertyGroup):
+    """Declare strand properties controllable in UI and translated to POV."""
+
+    bl_description = ("Strand settings for the material",)
+
+    blend_distance: FloatProperty(
+        name="Distance",
+        description="Worldspace distance over which to blend in the surface normal",
+        min=0.0,
+        max=10.0,
+        soft_min=0.0,
+        soft_max=10.0,
+        default=0.0,
+        precision=3,
+    )
+
+    root_size: FloatProperty(
+        name="Root",
+        description="Start size of strands in pixels or Blender units",
+        min=0.25,
+        default=1.0,
+        precision=5,
+    )
+
+    shape: FloatProperty(
+        name="Shape",
+        description="Positive values make strands rounder, negative ones make strands spiky",
+        min=-0.9,
+        max=0.9,
+        default=0.0,
+        precision=3,
+    )
+
+    size_min: FloatProperty(
+        name="Minimum",
+        description="Minimum size of strands in pixels",
+        min=0.001,
+        max=10.0,
+        default=1.0,
+        precision=3,
+    )
+
+    tip_size: FloatProperty(
+        name="Tip",
+        description="End size of strands in pixels or Blender units",
+        min=0.0,
+        default=1.0,
+        precision=5,
+    )
+
+    use_blender_units: BoolProperty(
+        name="Blender Units",
+        description="Use Blender units for widths instead of pixels",
+        default=False,
+    )
+
+    use_surface_diffuse: BoolProperty(
+        name="Surface diffuse",
+        description="Make diffuse shading more similar to shading the surface",
+        default=False,
+    )
+
+    use_tangent_shading: BoolProperty(
+        name="Tangent Shading",
+        description="Use direction of strands as normal for tangent-shading",
+        default=True,
+    )
+
+    uv_layer: StringProperty(
+        name="UV Layer",
+        # icon="GROUP_UVS",
+        description="Name of UV map to override",
+        default="",
+    )
+
+    width_fade: FloatProperty(
+        name="Width Fade",
+        description="Transparency along the width of the strand",
+        min=0.0,
+        max=2.0,
+        default=0.0,
+        precision=3,
+    )
+
+    # halo
+
+    # Halo settings for the material
+    # Type: MaterialHalo, (readonly, never None)
+
+    # ambient
+
+    # Amount of global ambient color the material receives
+    # Type: float in [0, 1], default 0.0
+
+    # darkness
+
+    # Minnaert darkness
+    # Type: float in [0, 2], default 0.0
+
+    # diffuse_color
+
+    # Diffuse color of the material
+    # Type: float array of 3 items in [0, inf], default (0.0, 0.0, 0.0)
+
+    # diffuse_fresnel
+
+    # Power of Fresnel
+    # Type: float in [0, 5], default 0.0
+
+    # diffuse_fresnel_factor
+
+    # Blending factor of Fresnel
+    # Type: float in [0, 5], default 0.0
+
+    # diffuse_intensity
+
+    # Amount of diffuse reflection
+    # Type: float in [0, 1], default 0.0
+
+    # diffuse_ramp
+
+    # Color ramp used to affect diffuse shading
+    # Type: ColorRamp, (readonly)
+
+    # diffuse_ramp_blend
+
+    # Blending method of the ramp and the diffuse color
+    # Type: enum in [‘MIX’, ‘ADD’, ‘MULTIPLY’, ‘SUBTRACT’, ‘SCREEN’, ‘DIVIDE’, ‘DIFFERENCE’, ‘DARKEN’, ‘LIGHTEN’, ‘OVERLAY’, ‘DODGE’, ‘BURN’, ‘HUE’, ‘SATURATION’, ‘VALUE’, ‘COLOR’, ‘SOFT_LIGHT’, ‘LINEAR_LIGHT’], default ‘MIX’
+
+    # diffuse_ramp_factor
+
+    # Blending factor (also uses alpha in Colorband)
+    # Type: float in [0, 1], default 0.0
+
+    # diffuse_ramp_input
+
+    # How the ramp maps on the surface
+    # Type: enum in [‘SHADER’, ‘ENERGY’, ‘NORMAL’, ‘RESULT’], default ‘SHADER’
+
+    # diffuse_shader
+
+    # LAMBERT Lambert, Use a Lambertian shader.
+    # OREN_NAYAR Oren-Nayar, Use an Oren-Nayar shader.
+    # TOON Toon, Use a toon shader.
+    # MINNAERT Minnaert, Use a Minnaert shader.
+    # FRESNEL Fresnel, Use a Fresnel shader.
+
+    # Type: enum in [‘LAMBERT’, ‘OREN_NAYAR’, ‘TOON’, ‘MINNAERT’, ‘FRESNEL’], default ‘LAMBERT’
+
+    # diffuse_toon_size
+
+    # Size of diffuse toon area
+    # Type: float in [0, 3.14], default 0.0
+
+    # diffuse_toon_smooth
+
+    # Smoothness of diffuse toon area
+    # Type: float in [0, 1], default 0.0
+
+    # emit
+
+    # Amount of light to emit
+    # Type: float in [0, inf], default 0.0
+
+    # game_settings
+
+    # Game material settings
+    # Type: MaterialGameSettings, (readonly, never None)
+
+    # halo
+
+    # Halo settings for the material
+    # Type: MaterialHalo, (readonly, never None)
+
+    # invert_z
+
+    # Render material’s faces with an inverted Z buffer (scanline only)
+    # Type: boolean, default False
+
+    # light_group
+
+    # Limit lighting to lamps in this Group
+    # Type: Group
+
+    # line_color
+
+    # Line color used for Freestyle line rendering
+    # Type: float array of 4 items in [0, inf], default (0.0, 0.0, 0.0, 0.0)
+
+    # line_priority
+
+    # The line color of a higher priority is used at material boundaries
+    # Type: int in [0, 32767], default 0
+
+    # mirror_color
+
+    # Mirror color of the material
+    # Type: float array of 3 items in [0, inf], default (0.0, 0.0, 0.0)
+
+    # node_tree
+
+    # Node tree for node based materials
+    # Type: NodeTree, (readonly)
+
+    # offset_z
+
+    # Give faces an artificial offset in the Z buffer for Z transparency
+    # Type: float in [-inf, inf], default 0.0
+
+    # paint_active_slot
+
+    # Index of active texture paint slot
+    # Type: int in [0, 32767], default 0
+
+    # paint_clone_slot
+
+    # Index of clone texture paint slot
+    # Type: int in [0, 32767], default 0
+
+    # pass_index
+
+    # Index number for the “Material Index” render pass
+    # Type: int in [0, 32767], default 0
+
+    # physics
+
+    # Game physics settings
+    # Type: MaterialPhysics, (readonly, never None)
+
+    # preview_render_type
+
+    # Type of preview render
+
+    # FLAT Flat, Flat XY plane.
+    # SPHERE Sphere, Sphere.
+    # CUBE Cube, Cube.
+    # MONKEY Monkey, Monkey.
+    # HAIR Hair, Hair strands.
+    # SPHERE_A World Sphere, Large sphere with sky.
+
+    # Type: enum in [‘FLAT’, ‘SPHERE’, ‘CUBE’, ‘MONKEY’, ‘HAIR’, ‘SPHERE_A’], default ‘FLAT’
+
+    # raytrace_mirror
+
+    # Raytraced reflection settings for the material
+    # Type: MaterialRaytraceMirror, (readonly, never None)
+
+    # raytrace_transparency
+
+    # Raytraced transparency settings for the material
+    # Type: MaterialRaytraceTransparency, (readonly, never None)
+
+    # roughness
+
+    # Oren-Nayar Roughness
+    # Type: float in [0, 3.14], default 0.0
+
+    # shadow_buffer_bias
+
+    # Factor to multiply shadow buffer bias with (0 is ignore)
+    # Type: float in [0, 10], default 0.0
+
+    # shadow_cast_alpha
+
+    # Shadow casting alpha, in use for Irregular and Deep shadow buffer
+    # Type: float in [0.001, 1], default 0.0
+
+    # shadow_only_type
+
+    # How to draw shadows
+
+    # SHADOW_ONLY_OLD Shadow and Distance, Old shadow only method.
+    # SHADOW_ONLY Shadow Only, Improved shadow only method.
+    # SHADOW_ONLY_SHADED Shadow and Shading, Improved shadow only method which also renders lightless areas as shadows.
+
+    # Type: enum in [‘SHADOW_ONLY_OLD’, ‘SHADOW_ONLY’, ‘SHADOW_ONLY_SHADED’], default ‘SHADOW_ONLY_OLD’
+
+    # shadow_ray_bias
+
+    # Shadow raytracing bias to prevent terminator problems on shadow boundary
+    # Type: float in [0, 0.25], default 0.0
+
+    # specular_color
+
+    # Specular color of the material
+    # Type: float array of 3 items in [0, inf], default (0.0, 0.0, 0.0)
+
+    # specular_hardness
+
+    # How hard (sharp) the specular reflection is
+    # Type: int in [1, 511], default 0
+
+    # specular_intensity
+
+    # How intense (bright) the specular reflection is
+    # Type: float in [0, 1], default 0.0
+
+    # specular_ior
+
+    # Specular index of refraction
+    # Type: float in [1, 10], default 0.0
+
+    # specular_ramp
+
+    # Color ramp used to affect specular shading
+    # Type: ColorRamp, (readonly)
+
+    # specular_ramp_blend
+
+    # Blending method of the ramp and the specular color
+    # Type: enum in [‘MIX’, ‘ADD’, ‘MULTIPLY’, ‘SUBTRACT’, ‘SCREEN’, ‘DIVIDE’, ‘DIFFERENCE’, ‘DARKEN’, ‘LIGHTEN’, ‘OVERLAY’, ‘DODGE’, ‘BURN’, ‘HUE’, ‘SATURATION’, ‘VALUE’, ‘COLOR’, ‘SOFT_LIGHT’, ‘LINEAR_LIGHT’], default ‘MIX’
+
+    # specular_ramp_factor
+
+    # Blending factor (also uses alpha in Colorband)
+    # Type: float in [0, 1], default 0.0
+
+    # specular_ramp_input
+
+    # How the ramp maps on the surface
+    # Type: enum in [‘SHADER’, ‘ENERGY’, ‘NORMAL’, ‘RESULT’], default ‘SHADER’
+    # specular_shader
+
+    # COOKTORR CookTorr, Use a Cook-Torrance shader.
+    # PHONG Phong, Use a Phong shader.
+    # BLINN Blinn, Use a Blinn shader.
+    # TOON Toon, Use a toon shader.
+    # WARDISO WardIso, Use a Ward anisotropic shader.
+
+    # Type: enum in [‘COOKTORR’, ‘PHONG’, ‘BLINN’, ‘TOON’, ‘WARDISO’], default ‘COOKTORR’
+
+    # specular_slope
+
+    # The standard deviation of surface slope
+    # Type: float in [0, 0.4], default 0.0
+
+    # specular_toon_size
+
+    # Size of specular toon area
+    # Type: float in [0, 1.53], default 0.0
+
+    # specular_toon_smooth
+
+    # Smoothness of specular toon area
+    # Type: float in [0, 1], default 0.0
+
+    # strand
+
+    # Strand settings for the material
+    # Type: MaterialStrand, (readonly, never None)
+
+    # subsurface_scattering
+
+    # Subsurface scattering settings for the material
+    # Type: MaterialSubsurfaceScattering, (readonly, never None)
+
+    # texture_paint_images
+
+    # Texture images used for texture painting
+    # Type: bpy_prop_collection of Image, (readonly)
+
+    # texture_paint_slots
+
+    # Texture slots defining the mapping and influence of textures
+    # Type: bpy_prop_collection of TexPaintSlot, (readonly)
+
+    # texture_slots
+
+    # Texture slots defining the mapping and influence of textures
+    # Type: MaterialTextureSlots bpy_prop_collection of MaterialTextureSlot, (readonly)
+
+    # translucency
+
+    # Amount of diffuse shading on the back side
+    # Type: float in [0, 1], default 0.0
+
+    # transparency_method
+
+    # Method to use for rendering transparency
+
+    # MASK Mask, Mask the background.
+    # Z_TRANSPARENCY Z Transparency, Use alpha buffer for transparent faces.
+    # RAYTRACE Raytrace, Use raytracing for transparent refraction rendering.
+
+    # Type: enum in [‘MASK’, ‘Z_TRANSPARENCY’, ‘RAYTRACE’], default ‘MASK’
+
+    # type
+
+    # Material type defining how the object is rendered
+
+    # SURFACE Surface, Render object as a surface.
+    # WIRE Wire, Render the edges of faces as wires (not supported in raytracing).
+    # VOLUME Volume, Render object as a volume.
+    # HALO Halo, Render object as halo particles.
+
+    # Type: enum in [‘SURFACE’, ‘WIRE’, ‘VOLUME’, ‘HALO’], default ‘SURFACE’
+
+    # use_cast_approximate
+
+    # Allow this material to cast shadows when using approximate ambient occlusion
+    # Type: boolean, default False
+
+    # use_cast_buffer_shadows
+
+    # Allow this material to cast shadows from shadow buffer lamps
+    # Type: boolean, default False
+
+    # use_cast_shadows
+
+    # Allow this material to cast shadows
+    # Type: boolean, default False
+
+    # use_cast_shadows_only
+
+    # Make objects with this material appear invisible (not rendered), only casting shadows
+    # Type: boolean, default False
+
+    # use_cubic
+
+    # Use cubic interpolation for diffuse values, for smoother transitions
+    # Type: boolean, default False
+
+    # use_diffuse_ramp
+
+    # Toggle diffuse ramp operations
+    # Type: boolean, default False
+
+    # use_face_texture
+
+    # Replace the object’s base color with color from UV map image textures
+    # Type: boolean, default False
+
+    # use_face_texture_alpha
+
+    # Replace the object’s base alpha value with alpha from UV map image textures
+    # Type: boolean, default False
+
+    # use_full_oversampling
+
+    # Force this material to render full shading/textures for all anti-aliasing samples
+    # Type: boolean, default False
+
+    # use_light_group_exclusive
+
+    # Material uses the light group exclusively - these lamps are excluded from other scene lighting
+    # Type: boolean, default False
+
+    # use_light_group_local
+
+    # When linked in, material uses local light group with the same name
+    # Type: boolean, default False
+
+    # use_mist
+
+    # Use mist with this material (in world settings)
+    # Type: boolean, default False
+
+    # use_nodes
+
+    # Use shader nodes to render the material
+    # Type: boolean, default False
+
+    # use_object_color
+
+    # Modulate the result with a per-object color
+    # Type: boolean, default False
+
+    # use_only_shadow
+
+    # Render shadows as the material’s alpha value, making the material transparent except for shadowed areas
+    # Type: boolean, default False
+
+    # use_ray_shadow_bias
+
+    # Prevent raytraced shadow errors on surfaces with smooth shaded normals (terminator problem)
+    # Type: boolean, default False
+
+    # use_raytrace
+
+    # Include this material and geometry that uses it in raytracing calculations
+    # Type: boolean, default False
+
+    # use_shadeless
+
+    # Make this material insensitive to light or shadow
+    # Type: boolean, default False
+
+    # use_shadows
+
+    # Allow this material to receive shadows
+    # Type: boolean, default False
+
+    # use_sky
+
+    # Render this material with zero alpha, with sky background in place (scanline only)
+    # Type: boolean, default False
+
+    # use_specular_ramp
+
+    # Toggle specular ramp operations
+    # Type: boolean, default False
+
+    # use_tangent_shading
+
+    # Use the material’s tangent vector instead of the normal for shading - for anisotropic shading effects
+    # Type: boolean, default False
+
+    # use_textures
+
+    # Enable/Disable each texture
+    # Type: boolean array of 18 items, default (False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
+
+    # use_transparency
+
+    # Render material as transparent
+    # Type: boolean, default False
+
+    # use_transparent_shadows
+
+    # Allow this object to receive transparent shadows cast through other objects
+    # Type: boolean, default False
+
+    # use_uv_project
+
+    # Use to ensure UV interpolation is correct for camera projections (use with UV project modifier)
+    # Type: boolean, default False
+
+    # use_vertex_color_light
+
+    # Add vertex colors as additional lighting
+    # Type: boolean, default False
+
+    # use_vertex_color_paint
+
+    # Replace object base color with vertex colors (multiply with ‘texture face’ face assigned textures)
+    # Type: boolean, default False
+
+    # volume
+
+    # Volume settings for the material
+    # Type: MaterialVolume, (readonly, never None)
+    """
+    (mat.type in {'SURFACE', 'WIRE', 'VOLUME'})
+     "use_transparency")
+
+
+
+    mat.use_transparency and mat.transparency_method == 'Z_TRANSPARENCY'
+
+
+
+
+            col.prop(mat, "use_raytrace")
+            col.prop(mat, "use_full_oversampling")
+
+            sub.prop(mat, "use_sky")
+
+
+            col.prop(mat, "use_cast_shadows", text="Cast")
+            col.prop(mat, "use_cast_shadows_only", text="Cast Only")
+            col.prop(mat, "use_cast_buffer_shadows")
+
+            sub.active = mat.use_cast_buffer_shadows
+            sub.prop(mat, "shadow_cast_alpha", text="Casting Alpha")
+            col.prop(mat, "use_cast_approximate")
+
+
+
+            col.prop(mat, "diffuse_color", text="")
+
+            sub.active = (not mat.use_shadeless)
+
+            sub.prop(mat, "diffuse_intensity", text="Intensity")
+
+
+            col.prop(mat, "diffuse_shader", text="")
+            col.prop(mat, "use_diffuse_ramp", text="Ramp")
+
+
+            if mat.diffuse_shader == 'OREN_NAYAR':
+                col.prop(mat, "roughness")
+            elif mat.diffuse_shader == 'MINNAERT':
+                col.prop(mat, "darkness")
+            elif mat.diffuse_shader == 'TOON':
+
+                row.prop(mat, "diffuse_toon_size", text="Size")
+                row.prop(mat, "diffuse_toon_smooth", text="Smooth")
+            elif mat.diffuse_shader == 'FRESNEL':
+
+                row.prop(mat, "diffuse_fresnel", text="Fresnel")
+                row.prop(mat, "diffuse_fresnel_factor", text="Factor")
+
+            if mat.use_diffuse_ramp:
+
+                col.template_color_ramp(mat, "diffuse_ramp", expand=True)
+
+
+
+                row.prop(mat, "diffuse_ramp_input", text="Input")
+                row.prop(mat, "diffuse_ramp_blend", text="Blend")
+
+                col.prop(mat, "diffuse_ramp_factor", text="Factor")
+
+
+
+
+            col.prop(mat, "specular_color", text="")
+            col.prop(mat, "specular_intensity", text="Intensity")
+
+            col.prop(mat, "specular_shader", text="")
+            col.prop(mat, "use_specular_ramp", text="Ramp")
+
+            if mat.specular_shader in {'COOKTORR', 'PHONG'}:
+                col.prop(mat, "specular_hardness", text="Hardness")
+            elif mat.specular_shader == 'BLINN':
+
+                row.prop(mat, "specular_hardness", text="Hardness")
+                row.prop(mat, "specular_ior", text="IOR")
+            elif mat.specular_shader == 'WARDISO':
+                col.prop(mat, "specular_slope", text="Slope")
+            elif mat.specular_shader == 'TOON':
+
+                row.prop(mat, "specular_toon_size", text="Size")
+                row.prop(mat, "specular_toon_smooth", text="Smooth")
+
+            if mat.use_specular_ramp:
+                layout.separator()
+                layout.template_color_ramp(mat, "specular_ramp", expand=True)
+                layout.separator()
+
+                row = layout.row()
+                row.prop(mat, "specular_ramp_input", text="Input")
+                row.prop(mat, "specular_ramp_blend", text="Blend")
+
+                layout.prop(mat, "specular_ramp_factor", text="Factor")
+
+
+    class MATERIAL_PT_shading(MaterialButtonsPanel, Panel):
+        bl_label = "Shading"
+        COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+
+        @classmethod
+        def poll(cls, context):
+            mat = context.material
+            engine = context.scene.render.engine
+            return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
+
+        def draw(self, context):
+            layout = self.layout
+
+            mat = active_node_mat(context.material)
+
+            if mat.type in {'SURFACE', 'WIRE'}:
+                split = layout.split()
+
+                col = split.column()
+                sub = col.column()
+                sub.active = not mat.use_shadeless
+                sub.prop(mat, "emit")
+                sub.prop(mat, "ambient")
+                sub = col.column()
+                sub.prop(mat, "translucency")
+
+                col = split.column()
+                col.prop(mat, "use_shadeless")
+                sub = col.column()
+                sub.active = not mat.use_shadeless
+                sub.prop(mat, "use_tangent_shading")
+                sub.prop(mat, "use_cubic")
+
+
+    class MATERIAL_PT_transp(MaterialButtonsPanel, Panel):
+        bl_label = "Transparency"
+        COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+        @classmethod
+        def poll(cls, context):
+            mat = context.material
+            engine = context.scene.render.engine
+            return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
+
+        def draw_header(self, context):
+            mat = context.material
+
+            if simple_material(mat):
+                self.layout.prop(mat, "use_transparency", text="")
+
+        def draw(self, context):
+            layout = self.layout
+
+            base_mat = context.material
+            mat = active_node_mat(context.material)
+            rayt = mat.raytrace_transparency
+
+            if simple_material(base_mat):
+                row = layout.row()
+                row.active = mat.use_transparency
+                row.prop(mat, "transparency_method", expand=True)
+
+            split = layout.split()
+            split.active = base_mat.use_transparency
+
+            col = split.column()
+            col.prop(mat, "alpha")
+            row = col.row()
+            row.active = (base_mat.transparency_method != 'MASK') and (not mat.use_shadeless)
+            row.prop(mat, "specular_alpha", text="Specular")
+
+            col = split.column()
+            col.active = (not mat.use_shadeless)
+            col.prop(rayt, "fresnel")
+            sub = col.column()
+            sub.active = (rayt.fresnel > 0.0)
+            sub.prop(rayt, "fresnel_factor", text="Blend")
+
+            if base_mat.transparency_method == 'RAYTRACE':
+                layout.separator()
+                split = layout.split()
+                split.active = base_mat.use_transparency
+
+                col = split.column()
+                col.prop(rayt, "ior")
+                col.prop(rayt, "filter")
+                col.prop(rayt, "falloff")
+                col.prop(rayt, "depth_max")
+                col.prop(rayt, "depth")
+
+                col = split.column()
+                col.label(text="Gloss:")
+                col.prop(rayt, "gloss_factor", text="Amount")
+                sub = col.column()
+                sub.active = rayt.gloss_factor < 1.0
+                sub.prop(rayt, "gloss_threshold", text="Threshold")
+                sub.prop(rayt, "gloss_samples", text="Samples")
+
+
+    class MATERIAL_PT_mirror(MaterialButtonsPanel, Panel):
+        bl_label = "Mirror"
+        bl_options = {'DEFAULT_CLOSED'}
+        COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+        @classmethod
+        def poll(cls, context):
+            mat = context.material
+            engine = context.scene.render.engine
+            return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
+
+        def draw_header(self, context):
+            raym = active_node_mat(context.material).raytrace_mirror
+
+            self.layout.prop(raym, "use", text="")
+
+        def draw(self, context):
+            layout = self.layout
+
+            mat = active_node_mat(context.material)
+            raym = mat.raytrace_mirror
+
+            layout.active = raym.use
+
+            split = layout.split()
+
+            col = split.column()
+            col.prop(raym, "reflect_factor")
+            col.prop(mat, "mirror_color", text="")
+
+            col = split.column()
+            col.prop(raym, "fresnel")
+            sub = col.column()
+            sub.active = (raym.fresnel > 0.0)
+            sub.prop(raym, "fresnel_factor", text="Blend")
+
+            split = layout.split()
+
+            col = split.column()
+            col.separator()
+            col.prop(raym, "depth")
+            col.prop(raym, "distance", text="Max Dist")
+            col.separator()
+            sub = col.split(percentage=0.4)
+            sub.active = (raym.distance > 0.0)
+            sub.label(text="Fade To:")
+            sub.prop(raym, "fade_to", text="")
+
+            col = split.column()
+            col.label(text="Gloss:")
+            col.prop(raym, "gloss_factor", text="Amount")
+            sub = col.column()
+            sub.active = (raym.gloss_factor < 1.0)
+            sub.prop(raym, "gloss_threshold", text="Threshold")
+            sub.prop(raym, "gloss_samples", text="Samples")
+            sub.prop(raym, "gloss_anisotropic", text="Anisotropic")
+
+
+    class MATERIAL_PT_sss(MaterialButtonsPanel, Panel):
+        bl_label = "Subsurface Scattering"
+        bl_options = {'DEFAULT_CLOSED'}
+        COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+        @classmethod
+        def poll(cls, context):
+            mat = context.material
+            engine = context.scene.render.engine
+            return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
+
+        def draw_header(self, context):
+            mat = active_node_mat(context.material)
+            sss = mat.subsurface_scattering
+
+            self.layout.active = (not mat.use_shadeless)
+            self.layout.prop(sss, "use", text="")
+
+        def draw(self, context):
+            layout = self.layout
+
+            mat = active_node_mat(context.material)
+            sss = mat.subsurface_scattering
+
+            layout.active = (sss.use) and (not mat.use_shadeless)
+
+            row = layout.row().split()
+            sub = row.row(align=True).split(align=True, percentage=0.75)
+            sub.menu("MATERIAL_MT_sss_presets", text=bpy.types.MATERIAL_MT_sss_presets.bl_label)
+            sub.operator("material.sss_preset_add", text="", icon='ZOOMIN')
+            sub.operator("material.sss_preset_add", text="", icon='ZOOMOUT').remove_active = True
+
+            split = layout.split()
+
+            col = split.column()
+            col.prop(sss, "ior")
+            col.prop(sss, "scale")
+            col.prop(sss, "color", text="")
+            col.prop(sss, "radius", text="RGB Radius", expand=True)
+
+            col = split.column()
+            sub = col.column(align=True)
+            sub.label(text="Blend:")
+            sub.prop(sss, "color_factor", text="Color")
+            sub.prop(sss, "texture_factor", text="Texture")
+            sub.label(text="Scattering Weight:")
+            sub.prop(sss, "front")
+            sub.prop(sss, "back")
+            col.separator()
+            col.prop(sss, "error_threshold", text="Error")
+
+
+    class MATERIAL_PT_halo(MaterialButtonsPanel, Panel):
+        bl_label = "Halo"
+        COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+        @classmethod
+        def poll(cls, context):
+            mat = context.material
+            engine = context.scene.render.engine
+            return mat and (mat.type == 'HALO') and (engine in cls.COMPAT_ENGINES)
+
+        def draw(self, context):
+            layout = self.layout
+
+            mat = context.material  # don't use node material
+            halo = mat.halo
+
+            def number_but(layout, toggle, number, name, color):
+                row = layout.row(align=True)
+                row.prop(halo, toggle, text="")
+                sub = row.column(align=True)
+                sub.active = getattr(halo, toggle)
+                sub.prop(halo, number, text=name, translate=False)
+                if not color == "":
+                    sub.prop(mat, color, text="")
+
+            split = layout.split()
+
+            col = split.column()
+            col.prop(mat, "alpha")
+            col.prop(mat, "diffuse_color", text="")
+            col.prop(halo, "seed")
+
+            col = split.column()
+            col.prop(halo, "size")
+            col.prop(halo, "hardness")
+            col.prop(halo, "add")
+
+            layout.label(text="Options:")
+
+            split = layout.split()
+            col = split.column()
+            col.prop(halo, "use_texture")
+            col.prop(halo, "use_vertex_normal")
+            col.prop(halo, "use_extreme_alpha")
+            col.prop(halo, "use_shaded")
+            col.prop(halo, "use_soft")
+
+            col = split.column()
+            number_but(col, "use_ring", "ring_count", iface_("Rings"), "mirror_color")
+            number_but(col, "use_lines", "line_count", iface_("Lines"), "specular_color")
+            number_but(col, "use_star", "star_tip_count", iface_("Star Tips"), "")
+
+
+    class MATERIAL_PT_flare(MaterialButtonsPanel, Panel):
+        bl_label = "Flare"
+        COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+        @classmethod
+        def poll(cls, context):
+            mat = context.material
+            engine = context.scene.render.engine
+            return mat and (mat.type == 'HALO') and (engine in cls.COMPAT_ENGINES)
+
+        def draw_header(self, context):
+            halo = context.material.halo
+
+            self.layout.prop(halo, "use_flare_mode", text="")
+
+        def draw(self, context):
+            layout = self.layout
+
+            mat = context.material  # don't use node material
+            halo = mat.halo
+
+            layout.active = halo.use_flare_mode
+
+            split = layout.split()
+
+            col = split.column()
+            col.prop(halo, "flare_size", text="Size")
+            col.prop(halo, "flare_boost", text="Boost")
+            col.prop(halo, "flare_seed", text="Seed")
+
+            col = split.column()
+            col.prop(halo, "flare_subflare_count", text="Subflares")
+            col.prop(halo, "flare_subflare_size", text="Subsize")
+
+    """
+
+
+#######################End Old Blender Internal Props##########################
+
+
+classes = (
+    RenderPovSettingsMaterial,
+    MaterialRaytraceTransparency,
+    MaterialRaytraceMirror,
+    MaterialSubsurfaceScattering,
+    MaterialStrandSettings,
+)
+
+
+def register():
+    for cls in classes:
+        register_class(cls)
+
+    bpy.types.Material.pov = PointerProperty(type=RenderPovSettingsMaterial)
+    bpy.types.Material.pov_raytrace_transparency = PointerProperty(
+        type=MaterialRaytraceTransparency
+    )
+    bpy.types.Material.pov_subsurface_scattering = PointerProperty(
+        type=MaterialSubsurfaceScattering
+    )
+    bpy.types.Material.strand = PointerProperty(type=MaterialStrandSettings)
+    bpy.types.Material.pov_raytrace_mirror = PointerProperty(type=MaterialRaytraceMirror)
+
+
+def unregister():
+    del bpy.types.Material.pov_subsurface_scattering
+    del bpy.types.Material.strand
+    del bpy.types.Material.pov_raytrace_mirror
+    del bpy.types.Material.pov_raytrace_transparency
+    del bpy.types.Material.pov
+
+    for cls in reversed(classes):
+        unregister_class(cls)
diff --git a/render_povray/texturing.py b/render_povray/texturing.py
new file mode 100755
index 000000000..e070dbe97
--- /dev/null
+++ b/render_povray/texturing.py
@@ -0,0 +1,902 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# #**** END GPL LICENSE BLOCK #****
+
+# <pep8 compliant>
+
+"""Translate blender texture influences into POV."""
+import os
+import bpy
+
+
+def write_texture_influence(
+    using_uberpov,
+    mater,
+    material_names_dictionary,
+    local_material_names,
+    path_image,
+    exported_lights_count,
+    image_format,
+    img_map,
+    img_map_transforms,
+    tab_write,
+    comments,
+    string_strip_hyphen,
+    safety,
+    col,
+    preview_dir,
+    unpacked_images,
+):
+    """Translate Blender texture influences to various POV texture tricks and write to pov file."""
+    material_finish = material_names_dictionary[mater.name]
+    if mater.pov.use_transparency:
+        trans = 1.0 - mater.pov.alpha
+    else:
+        trans = 0.0
+    if (mater.pov.specular_color.s == 0.0) or (mater.pov.diffuse_shader == "MINNAERT"):
+        # No layered texture because of aoi pattern used for minnaert and pov can't layer patterned
+        colored_specular_found = False
+    else:
+        colored_specular_found = True
+
+    if mater.pov.use_transparency and mater.pov.transparency_method == "RAYTRACE":
+        pov_filter = mater.pov_raytrace_transparency.filter * (1.0 - mater.pov.alpha)
+        trans = (1.0 - mater.pov.alpha) - pov_filter
+    else:
+        pov_filter = 0.0
+
+    ##############SF
+    texture_dif = ""
+    texture_spec = ""
+    texture_norm = ""
+    texture_alpha = ""
+    # procedural_flag=False
+    tmpidx = -1
+    for t in mater.pov_texture_slots:
+
+        tmpidx += 1
+        # index = mater.pov.active_texture_index
+        slot = mater.pov_texture_slots[tmpidx]  # [index]
+        povtex = slot.texture  # slot.name
+        tex = bpy.data.textures[povtex]
+
+        if t and (t.use and (tex is not None)):
+            # 'NONE' ('NONE' type texture is different from no texture covered above)
+            if tex.type == "NONE" and tex.pov.tex_pattern_type == "emulator":
+                continue  # move to next slot
+
+            # Implicit else-if (as not skipped by previous "continue")
+            # PROCEDURAL
+            if tex.type != "IMAGE" and tex.type != "NONE":
+                procedural_flag = True
+                image_filename = "PAT_%s" % string_strip_hyphen(bpy.path.clean_name(tex.name))
+                if image_filename:
+                    if t.use_map_color_diffuse:
+                        texture_dif = image_filename
+                        # colvalue = t.default_value  # UNUSED
+                        t_dif = t
+                        if t_dif.texture.pov.tex_gamma_enable:
+                            img_gamma = " gamma %.3g " % t_dif.texture.pov.tex_gamma_value
+                    if t.use_map_specular or t.use_map_raymir:
+                        texture_spec = image_filename
+                        # colvalue = t.default_value  # UNUSED
+                        t_spec = t
+                    if t.use_map_normal:
+                        texture_norm = image_filename
+                        # colvalue = t.normal_factor/10 # UNUSED
+                        # textNormName=tex.image.name + ".normal"
+                        # was the above used? --MR
+                        t_nor = t
+                    if t.use_map_alpha:
+                        texture_alpha = image_filename
+                        # colvalue = t.alpha_factor * 10.0  # UNUSED
+                        # textDispName=tex.image.name + ".displ"
+                        # was the above used? --MR
+                        t_alpha = t
+
+            # RASTER IMAGE
+            elif tex.type == "IMAGE" and tex.image and tex.pov.tex_pattern_type == "emulator":
+                procedural_flag = False
+                # PACKED
+                if tex.image.packed_file:
+                    orig_image_filename = tex.image.filepath_raw
+                    unpackedfilename = os.path.join(
+                        preview_dir,
+                        ("unpacked_img_" + (string_strip_hyphen(bpy.path.clean_name(tex.name)))),
+                    )
+                    if not os.path.exists(unpackedfilename):
+                        # record which images that were newly copied and can be safely
+                        # cleaned up
+                        unpacked_images.append(unpackedfilename)
+                    tex.image.filepath_raw = unpackedfilename
+                    tex.image.save()
+                    image_filename = unpackedfilename.replace("\\", "/")
+                    # .replace("\\","/") to get only forward slashes as it's what POV prefers,
+                    # even on windows
+                    tex.image.filepath_raw = orig_image_filename
+                # FILE
+                else:
+                    image_filename = path_image(tex.image)
+                # IMAGE SEQUENCE BEGINS
+                if image_filename:
+                    if bpy.data.images[tex.image.name].source == "SEQUENCE":
+                        korvaa = "." + str(tex.image_user.frame_offset + 1).zfill(3) + "."
+                        image_filename = image_filename.replace(".001.", korvaa)
+                        print(" seq debug ")
+                        print(image_filename)
+                # IMAGE SEQUENCE ENDS
+                img_gamma = ""
+                if image_filename:
+                    texdata = bpy.data.textures[t.texture]
+                    if t.use_map_color_diffuse:
+                        texture_dif = image_filename
+                        # colvalue = t.default_value  # UNUSED
+                        t_dif = t
+                        print(texdata)
+                        if texdata.pov.tex_gamma_enable:
+                            img_gamma = " gamma %.3g " % t_dif.texture.pov.tex_gamma_value
+                    if t.use_map_specular or t.use_map_raymir:
+                        texture_spec = image_filename
+                        # colvalue = t.default_value  # UNUSED
+                        t_spec = t
+                    if t.use_map_normal:
+                        texture_norm = image_filename
+                        # colvalue = t.normal_factor/10  # UNUSED
+                        # textNormName=tex.image.name + ".normal"
+                        # was the above used? --MR
+                        t_nor = t
+                    if t.use_map_alpha:
+                        texture_alpha = image_filename
+                        # colvalue = t.alpha_factor * 10.0  # UNUSED
+                        # textDispName=tex.image.name + ".displ"
+                        # was the above used? --MR
+                        t_alpha = t
+
+    ####################################################################################
+
+    tab_write("\n")
+    # THIS AREA NEEDS TO LEAVE THE TEXTURE OPEN UNTIL ALL MAPS ARE WRITTEN DOWN.
+    # --MR
+    current_material_name = string_strip_hyphen(material_names_dictionary[mater.name])
+    local_material_names.append(current_material_name)
+    tab_write("\n#declare MAT_%s = \ntexture{\n" % current_material_name)
+    ################################################################################
+
+    if mater.pov.replacement_text != "":
+        tab_write("%s\n" % mater.pov.replacement_text)
+    #################################################################################
+    # XXX TODO: replace by new POV MINNAERT rather than aoi
+    if mater.pov.diffuse_shader == "MINNAERT":
+        tab_write("\n")
+        tab_write("aoi\n")
+        tab_write("texture_map {\n")
+        tab_write("[%.3g finish {diffuse %.3g}]\n" % (mater.darkness / 2.0, 2.0 - mater.darkness))
+        tab_write("[%.3g\n" % (1.0 - (mater.darkness / 2.0)))
+
+    if mater.pov.diffuse_shader == "FRESNEL":
+        # For FRESNEL diffuse in POV, we'll layer slope patterned textures
+        # with lamp vector as the slope vector and nest one slope per lamp
+        # into each texture map's entry.
+
+        c = 1
+        while c <= exported_lights_count:
+            tab_write("slope { lampTarget%s }\n" % (c))
+            tab_write("texture_map {\n")
+            # Diffuse Fresnel value and factor go up to five,
+            # other kind of values needed: used the number 5 below to remap
+            tab_write(
+                "[%.3g finish {diffuse %.3g}]\n"
+                % (
+                    (5.0 - mater.diffuse_fresnel) / 5,
+                    (mater.diffuse_intensity * ((5.0 - mater.diffuse_fresnel_factor) / 5)),
+                )
+            )
+            tab_write(
+                "[%.3g\n" % ((mater.diffuse_fresnel_factor / 5) * (mater.diffuse_fresnel / 5.0))
+            )
+            c += 1
+
+    # if shader is a 'FRESNEL' or 'MINNAERT': slope pigment pattern or aoi
+    # and texture map above, the rest below as one of its entry
+
+    if texture_spec != "" or texture_alpha != "":
+        if texture_spec != "":
+            # tab_write("\n")
+            tab_write("pigment_pattern {\n")
+
+            mapping_spec = img_map_transforms(t_spec)
+            if texture_spec and texture_spec.startswith("PAT_"):
+                tab_write("function{f%s(x,y,z).grey}\n" % texture_spec)
+                tab_write("%s\n" % mapping_spec)
+            else:
+
+                tab_write(
+                    'uv_mapping image_map{%s "%s" %s}\n'
+                    % (image_format(texture_spec), texture_spec, img_map(t_spec))
+                )
+                tab_write("%s\n" % mapping_spec)
+            tab_write("}\n")
+            tab_write("texture_map {\n")
+            tab_write("[0 \n")
+
+        if texture_dif == "":
+            if texture_alpha != "":
+                tab_write("\n")
+
+                mapping_alpha = img_map_transforms(t_alpha)
+
+                if texture_alpha and texture_alpha.startswith("PAT_"):
+                    tab_write("function{f%s(x,y,z).transmit}%s\n" % (texture_alpha, mapping_alpha))
+                else:
+
+                    tab_write(
+                        "pigment {pigment_pattern {uv_mapping image_map"
+                        '{%s "%s" %s}%s'
+                        % (
+                            image_format(texture_alpha),
+                            texture_alpha,
+                            img_map(t_alpha),
+                            mapping_alpha,
+                        )
+                    )
+                tab_write("}\n")
+                tab_write("pigment_map {\n")
+                tab_write("[0 color rgbft<0,0,0,1,1>]\n")
+                tab_write(
+                    "[1 color rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>]\n"
+                    % (col[0], col[1], col[2], pov_filter, trans)
+                )
+                tab_write("}\n")
+                tab_write("}\n")
+
+            else:
+
+                tab_write(
+                    "pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>}\n"
+                    % (col[0], col[1], col[2], pov_filter, trans)
+                )
+
+            if texture_spec != "":
+                # ref_level_bound 1 is no specular
+                tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=1)))
+
+            else:
+                # ref_level_bound 2 is translated spec
+                tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=2)))
+
+        else:
+            mapping_dif = img_map_transforms(t_dif)
+
+            if texture_alpha != "":
+                mapping_alpha = img_map_transforms(t_alpha)
+
+                tab_write("pigment {\n")
+                tab_write("pigment_pattern {\n")
+                if texture_alpha and texture_alpha.startswith("PAT_"):
+                    tab_write("function{f%s(x,y,z).transmit}%s\n" % (texture_alpha, mapping_alpha))
+                else:
+                    tab_write(
+                        'uv_mapping image_map{%s "%s" %s}%s}\n'
+                        % (
+                            image_format(texture_alpha),
+                            texture_alpha,
+                            img_map(t_alpha),
+                            mapping_alpha,
+                        )
+                    )
+                tab_write("pigment_map {\n")
+                tab_write("[0 color rgbft<0,0,0,1,1>]\n")
+                # if texture_alpha and texture_alpha.startswith("PAT_"):
+                # tab_write("[1 pigment{%s}]\n" %texture_dif)
+                if texture_dif and not texture_dif.startswith("PAT_"):
+                    tab_write(
+                        '[1 uv_mapping image_map {%s "%s" %s} %s]\n'
+                        % (
+                            image_format(texture_dif),
+                            texture_dif,
+                            (img_gamma + img_map(t_dif)),
+                            mapping_dif,
+                        )
+                    )
+                elif texture_dif and texture_dif.startswith("PAT_"):
+                    tab_write("[1 %s]\n" % texture_dif)
+                tab_write("}\n")
+                tab_write("}\n")
+                if texture_alpha and texture_alpha.startswith("PAT_"):
+                    tab_write("}\n")
+
+            else:
+                if texture_dif and texture_dif.startswith("PAT_"):
+                    tab_write("pigment{%s}\n" % texture_dif)
+                else:
+                    tab_write(
+                        'pigment {uv_mapping image_map {%s "%s" %s}%s}\n'
+                        % (
+                            image_format(texture_dif),
+                            texture_dif,
+                            (img_gamma + img_map(t_dif)),
+                            mapping_dif,
+                        )
+                    )
+
+            if texture_spec != "":
+                # ref_level_bound 1 is no specular
+                tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=1)))
+
+            else:
+                # ref_level_bound 2 is translated specular
+                tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=2)))
+
+            ## scale 1 rotate y*0
+            # imageMap = ("{image_map {%s \"%s\" %s }\n" % \
+            #            (image_format(textures),textures,img_map(t_dif)))
+            # tab_write("uv_mapping pigment %s} %s finish {%s}\n" % \
+            #         (imageMap,mapping,safety(material_finish)))
+            # tab_write("pigment {uv_mapping image_map {%s \"%s\" %s}%s} " \
+            #         "finish {%s}\n" % \
+            #         (image_format(texture_dif), texture_dif, img_map(t_dif),
+            #          mapping_dif, safety(material_finish)))
+        if texture_norm != "":
+            ## scale 1 rotate y*0
+
+            mapping_normal = img_map_transforms(t_nor)
+
+            if texture_norm and texture_norm.startswith("PAT_"):
+                tab_write(
+                    "normal{function{f%s(x,y,z).grey} bump_size %.4g %s}\n"
+                    % (texture_norm, (-t_nor.normal_factor * 9.5), mapping_normal)
+                )
+            else:
+                tab_write("normal {\n")
+                # XXX TODO: fix and propagate the micro normals reflection blur below to non textured materials
+                if (
+                    mater.pov_raytrace_mirror.use
+                    and mater.pov_raytrace_mirror.gloss_factor < 1.0
+                    and not using_uberpov
+                ):
+                    tab_write("average\n")
+                    tab_write("normal_map{\n")
+                    # 0.5 for entries below means a 50 percent mix
+                    # between the micro normal and user bump map
+                    # order seems indifferent as commutative
+                    tab_write(
+                        "[0.025 bumps %.4g scale 0.1*%.4g]\n"
+                        % (
+                            (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                            (10 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                        )
+                    )  # micronormals blurring
+                    tab_write(
+                        "[0.025 bumps %.4g scale 0.1*%.4g phase 0.1]\n"
+                        % (
+                            (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                            (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                        )
+                    )  # micronormals blurring
+                    tab_write(
+                        "[0.025 bumps %.4g scale 0.1*%.4g phase 0.15]\n"
+                        % (
+                            (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                            (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                        )
+                    )  # micronormals blurring
+                    tab_write(
+                        "[0.025 bumps %.4g scale 0.1*%.4g phase 0.2]\n"
+                        % (
+                            (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                            (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                        )
+                    )  # micronormals blurring
+                    tab_write(
+                        "[0.025 bumps %.4g scale 0.1*%.4g phase 0.25]\n"
+                        % (
+                            (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                            (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                        )
+                    )  # micronormals blurring
+                    tab_write(
+                        "[0.025 bumps %.4g scale 0.1*%.4g phase 0.3]\n"
+                        % (
+                            (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                            (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                        )
+                    )  # micronormals blurring
+                    tab_write(
+                        "[0.025 bumps %.4g scale 0.1*%.4g phase 0.35]\n"
+                        % (
+                            (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                            (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                        )
+                    )  # micronormals blurring
+                    tab_write(
+                        "[0.025 bumps %.4g scale 0.1*%.4g phase 0.4]\n"
+                        % (
+                            (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                            (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                        )
+                    )  # micronormals blurring
+                    tab_write(
+                        "[0.025 bumps %.4g scale 0.1*%.4g phase 0.45]\n"
+                        % (
+                            (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                            (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                        )
+                    )  # micronormals blurring
+                    tab_write(
+                        "[0.025 bumps %.4g scale 0.1*%.4g phase 0.5]\n"
+                        % (
+                            (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                            (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                        )
+                    )  # micronormals blurring
+                    tab_write("[1.0 ")  # Proceed with user bump...
+                tab_write(
+                    "uv_mapping bump_map "
+                    '{%s "%s" %s  bump_size %.4g }%s'
+                    % (
+                        image_format(texture_norm),
+                        texture_norm,
+                        img_map(t_nor),
+                        (-t_nor.normal_factor * 9.5),
+                        mapping_normal,
+                    )
+                )
+                # ...Then close its last entry and the the normal_map itself
+                if (
+                    mater.pov_raytrace_mirror.use
+                    and mater.pov_raytrace_mirror.gloss_factor < 1.0
+                    and not using_uberpov
+                ):
+                    tab_write("]}}\n")
+                else:
+                    tab_write("]}\n")
+        if texture_spec != "":
+            tab_write("]\n")
+            ##################Second index for mapping specular max value###############
+            tab_write("[1 \n")
+
+    if texture_dif == "" and mater.pov.replacement_text == "":
+        if texture_alpha != "":
+            mapping_alpha = img_map_transforms(t_alpha)
+
+            if texture_alpha and texture_alpha.startswith("PAT_"):
+                tab_write("function{f%s(x,y,z).transmit %s}\n" % (texture_alpha, mapping_alpha))
+            else:
+                tab_write(
+                    "pigment {pigment_pattern {uv_mapping image_map"
+                    '{%s "%s" %s}%s}\n'
+                    % (image_format(texture_alpha), texture_alpha, img_map(t_alpha), mapping_alpha)
+                )
+            tab_write("pigment_map {\n")
+            tab_write("[0 color rgbft<0,0,0,1,1>]\n")
+            tab_write(
+                "[1 color rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>]\n"
+                % (col[0], col[1], col[2], pov_filter, trans)
+            )
+            tab_write("}\n")
+            tab_write("}\n")
+
+        else:
+            tab_write(
+                "pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>}\n"
+                % (col[0], col[1], col[2], pov_filter, trans)
+            )
+
+        if texture_spec != "":
+            # ref_level_bound 3 is full specular
+            tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=3)))
+
+            if (
+                mater.pov_raytrace_mirror.use
+                and mater.pov_raytrace_mirror.gloss_factor < 1.0
+                and not using_uberpov
+            ):
+                tab_write("normal {\n")
+                tab_write("average\n")
+                tab_write("normal_map{\n")
+                # 0.5 for entries below means a 50 percent mix
+                # between the micro normal and user bump map
+                # order seems indifferent as commutative
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (10 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g phase 0.1]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g phase 0.15]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g phase 0.2]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g phase 0.25]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g phase 0.3]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g phase 0.35]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g phase 0.4]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g phase 0.45]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g phase 0.5]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+            # XXX IF USER BUMP_MAP
+            if texture_norm != "":
+                tab_write(
+                    "[1.0 "
+                )  # Blurry reflection or not Proceed with user bump in either case...
+                tab_write(
+                    "uv_mapping bump_map "
+                    '{%s "%s" %s  bump_size %.4g }%s]\n'
+                    % (
+                        image_format(texture_norm),
+                        texture_norm,
+                        img_map(t_nor),
+                        (-t_nor.normal_factor * 9.5),
+                        mapping_normal,
+                    )
+                )
+            # ...Then close the normal_map itself if blurry reflection
+            if (
+                mater.pov_raytrace_mirror.use
+                and mater.pov_raytrace_mirror.gloss_factor < 1.0
+                and not using_uberpov
+            ):
+                tab_write("}}\n")
+            else:
+                tab_write("}\n")
+        elif colored_specular_found:
+            # ref_level_bound 1 is no specular
+            tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=1)))
+
+        else:
+            # ref_level_bound 2 is translated specular
+            tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=2)))
+
+    elif mater.pov.replacement_text == "":
+        mapping_dif = img_map_transforms(t_dif)
+
+        if texture_alpha != "":
+
+            mapping_alpha = img_map_transforms(t_alpha)
+
+            if texture_alpha and texture_alpha.startswith("PAT_"):
+                tab_write(
+                    "pigment{pigment_pattern {function{f%s(x,y,z).transmit}%s}\n"
+                    % (texture_alpha, mapping_alpha)
+                )
+            else:
+                tab_write(
+                    "pigment {pigment_pattern {uv_mapping image_map"
+                    '{%s "%s" %s}%s}\n'
+                    % (image_format(texture_alpha), texture_alpha, img_map(t_alpha), mapping_alpha)
+                )
+            tab_write("pigment_map {\n")
+            tab_write("[0 color rgbft<0,0,0,1,1>]\n")
+            if texture_alpha and texture_alpha.startswith("PAT_"):
+                tab_write("[1 function{f%s(x,y,z).transmit}%s]\n" % (texture_alpha, mapping_alpha))
+            elif texture_dif and not texture_dif.startswith("PAT_"):
+                tab_write(
+                    '[1 uv_mapping image_map {%s "%s" %s} %s]\n'
+                    % (
+                        image_format(texture_dif),
+                        texture_dif,
+                        (img_map(t_dif) + img_gamma),
+                        mapping_dif,
+                    )
+                )
+            elif texture_dif and texture_dif.startswith("PAT_"):
+                tab_write("[1 %s %s]\n" % (texture_dif, mapping_dif))
+            tab_write("}\n")
+            tab_write("}\n")
+
+        else:
+            if texture_dif and texture_dif.startswith("PAT_"):
+                tab_write("pigment{%s %s}\n" % (texture_dif, mapping_dif))
+            else:
+                tab_write("pigment {\n")
+                tab_write("uv_mapping image_map {\n")
+                # tab_write("%s \"%s\" %s}%s\n" % \
+                #         (image_format(texture_dif), texture_dif,
+                #         (img_gamma + img_map(t_dif)),mapping_dif))
+                tab_write('%s "%s" \n' % (image_format(texture_dif), texture_dif))
+                tab_write("%s\n" % (img_gamma + img_map(t_dif)))
+                tab_write("}\n")
+                tab_write("%s\n" % mapping_dif)
+                tab_write("}\n")
+
+        if texture_spec != "":
+            # ref_level_bound 3 is full specular
+            tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=3)))
+        else:
+            # ref_level_bound 2 is translated specular
+            tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=2)))
+
+        ## scale 1 rotate y*0
+        # imageMap = ("{image_map {%s \"%s\" %s }" % \
+        #            (image_format(textures), textures,img_map(t_dif)))
+        # tab_write("\n\t\t\tuv_mapping pigment %s} %s finish {%s}" % \
+        #           (imageMap, mapping, safety(material_finish)))
+        # tab_write("\n\t\t\tpigment {uv_mapping image_map " \
+        #           "{%s \"%s\" %s}%s} finish {%s}" % \
+        #           (image_format(texture_dif), texture_dif,img_map(t_dif),
+        #            mapping_dif, safety(material_finish)))
+    if texture_norm != "" and mater.pov.replacement_text == "":
+
+        mapping_normal = img_map_transforms(t_nor)
+
+        if texture_norm and texture_norm.startswith("PAT_"):
+            tab_write(
+                "normal{function{f%s(x,y,z).grey} bump_size %.4g %s}\n"
+                % (texture_norm, (-t_nor.normal_factor * 9.5), mapping_normal)
+            )
+        else:
+            tab_write("normal {\n")
+            # XXX TODO: fix and propagate the micro normals reflection blur below to non textured materials
+            if (
+                mater.pov_raytrace_mirror.use
+                and mater.pov_raytrace_mirror.gloss_factor < 1.0
+                and not using_uberpov
+            ):
+                tab_write("average\n")
+                tab_write("normal_map{\n")
+                # 0.5 for entries below means a 50 percent mix
+                # between the micro normal and user bump map
+                # order seems indifferent as commutative
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (10 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g phase 0.1]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g phase 0.15]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g phase 0.2]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g phase 0.25]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g phase 0.3]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g phase 0.35]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g phase 0.4]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g phase 0.45]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[0.025 bumps %.4g scale 0.1*%.4g phase 0.5]\n"
+                    % (
+                        (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+                        (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+                    )
+                )  # micronormals blurring
+                tab_write(
+                    "[1.0 "
+                )  # Blurry reflection or not Proceed with user bump in either case...
+            tab_write(
+                "uv_mapping bump_map "
+                '{%s "%s" %s  bump_size %.4g }%s]\n'
+                % (
+                    image_format(texture_norm),
+                    texture_norm,
+                    img_map(t_nor),
+                    (-t_nor.normal_factor * 9.5),
+                    mapping_normal,
+                )
+            )
+            # ...Then close the normal_map itself if blurry reflection
+            if (
+                mater.pov_raytrace_mirror.use
+                and mater.pov_raytrace_mirror.gloss_factor < 1.0
+                and not using_uberpov
+            ):
+                tab_write("}}\n")
+            else:
+                tab_write("}\n")
+    if texture_spec != "" and mater.pov.replacement_text == "":
+        tab_write("]\n")
+
+        tab_write("}\n")
+
+    # End of slope/ior texture_map
+    if mater.pov.diffuse_shader == "MINNAERT" and mater.pov.replacement_text == "":
+        tab_write("]\n")
+        tab_write("}\n")
+    if mater.pov.diffuse_shader == "FRESNEL" and mater.pov.replacement_text == "":
+        c = 1
+        while c <= exported_lights_count:
+            tab_write("]\n")
+            tab_write("}\n")
+            c += 1
+
+    # Close first layer of POV "texture" (Blender material)
+    tab_write("}\n")
+
+    colored_specular_found = bool(
+        (mater.pov.specular_color.s > 0.0) and (mater.pov.diffuse_shader != "MINNAERT")
+    )
+
+    # Write another layered texture using invisible diffuse and metallic trick
+    # to emulate colored specular highlights
+    special_texture_found = False
+    tmpidx = -1
+    for t in mater.pov_texture_slots:
+        tmpidx += 1
+        # index = mater.pov.active_texture_index
+        slot = mater.pov_texture_slots[tmpidx]  # [index]
+        povtex = slot.texture  # slot.name
+        tex = bpy.data.textures[povtex]
+        # Specular mapped textures would conflict with colored specular
+        # because POV can't layer over or under pigment patterned textures
+        special_texture_found = bool(
+            t
+            and t.use
+            and ((tex.type == "IMAGE" and tex.image) or tex.type != "IMAGE")
+            and (t.use_map_specular or t.use_map_raymir)
+        )
+    if colored_specular_found and not special_texture_found:
+        if comments:
+            tab_write("  // colored highlights with a stransparent metallic layer\n")
+        else:
+            tab_write("\n")
+
+        tab_write("texture {\n")
+        tab_write(
+            "pigment {rgbft<%.3g, %.3g, %.3g, 0, 1>}\n"
+            % (
+                mater.pov.specular_color[0],
+                mater.pov.specular_color[1],
+                mater.pov.specular_color[2],
+            )
+        )
+        tab_write(
+            "finish {%s}\n" % (safety(material_finish, ref_level_bound=2))
+        )  # ref_level_bound 2 is translated spec
+
+        texture_norm = ""
+        for t in mater.pov_texture_slots:
+
+            if t and tex.pov.tex_pattern_type != "emulator":
+                procedural_flag = True
+                image_filename = string_strip_hyphen(bpy.path.clean_name(tex.name))
+            if (
+                t
+                and tex.type == "IMAGE"
+                and t.use
+                and tex.image
+                and tex.pov.tex_pattern_type == "emulator"
+            ):
+                procedural_flag = False
+                image_filename = path_image(tex.image)
+                img_gamma = ""
+                if image_filename:
+                    if t.use_map_normal:
+                        texture_norm = image_filename
+                        # colvalue = t.normal_factor/10  # UNUSED   XXX *-9.5 !
+                        # textNormName=tex.image.name + ".normal"
+                        # was the above used? --MR
+                        t_nor = t
+                        if procedural_flag:
+                            tab_write(
+                                "normal{function"
+                                "{f%s(x,y,z).grey} bump_size %.4g}\n"
+                                % (texture_norm, (-t_nor.normal_factor * 9.5))
+                            )
+                        else:
+                            tab_write(
+                                "normal {uv_mapping bump_map "
+                                '{%s "%s" %s  bump_size %.4g }%s}\n'
+                                % (
+                                    image_format(texture_norm),
+                                    texture_norm,
+                                    img_map(t_nor),
+                                    (-t_nor.normal_factor * 9.5),
+                                    mapping_normal,
+                                )
+                            )
+
+        tab_write("}\n")  # THEN IT CAN CLOSE LAST LAYER OF TEXTURE
diff --git a/render_povray/texturing_gui.py b/render_povray/texturing_gui.py
new file mode 100755
index 000000000..6d12fb620
--- /dev/null
+++ b/render_povray/texturing_gui.py
@@ -0,0 +1,1255 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+"""User interface for texturing tools."""
+
+import bpy
+from bpy.utils import register_class, unregister_class
+from bpy.types import (
+    Operator,
+    Menu,
+    UIList,
+    Panel,
+    Brush,
+    Material,
+    Light,
+    World,
+    ParticleSettings,
+    FreestyleLineStyle,
+)
+
+# from .ui import TextureButtonsPanel
+
+from .shading_properties import pov_context_tex_datablock
+from bl_ui.properties_paint_common import brush_texture_settings
+
+# Example of wrapping every class 'as is'
+from bl_ui import properties_texture
+
+# unused, replaced by pov_context_tex_datablock (no way to use?):
+# from bl_ui.properties_texture import context_tex_datablock
+# from bl_ui.properties_texture import texture_filter_common #unused yet?
+
+for member in dir(properties_texture):
+    subclass = getattr(properties_texture, member)
+    try:
+        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+    except BaseException as e:
+        print(e.__doc__)
+        print('An exception occurred: {}'.format(e))
+        pass
+del properties_texture
+
+
+class TextureButtonsPanel:
+    """Use this class to define buttons from the texture tab properties."""
+
+    bl_space_type = 'PROPERTIES'
+    bl_region_type = 'WINDOW'
+    bl_context = "texture"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        tex = context.texture
+        rd = context.scene.render
+        return tex and (rd.engine in cls.COMPAT_ENGINES)
+
+
+class TEXTURE_MT_POV_specials(Menu):
+    """Use this class to define pov texture slot operations buttons."""
+
+    bl_label = "Texture Specials"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def draw(self, context):
+        layout = self.layout
+
+        layout.operator("texture.slot_copy", icon='COPYDOWN')
+        layout.operator("texture.slot_paste", icon='PASTEDOWN')
+
+
+class WORLD_TEXTURE_SLOTS_UL_POV_layerlist(UIList):
+    """Use this class to show pov texture slots list."""  # XXX Not used yet
+
+    index: bpy.props.IntProperty(name='index')
+    # should active_propname be index or..?
+    def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
+        world = context.scene.world  # .pov
+        active_data = world.pov
+        # tex = context.texture #may be needed later?
+
+        # We could write some code to decide which icon to use here...
+        # custom_icon = 'TEXTURE'
+
+        # ob = data
+        slot = item
+        # ma = slot.name
+        # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
+        if self.layout_type in {'DEFAULT', 'COMPACT'}:
+            # You should always start your row layout by a label (icon + text), or a non-embossed text field,
+            # this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
+            # We use icon_value of label, as our given icon is an integer value, not an enum ID.
+            # Note "data" names should never be translated!
+            if slot:
+                layout.prop(item, "texture", text="", emboss=False, icon='TEXTURE')
+            else:
+                layout.label(text="New", translate=False, icon_value=icon)
+        # 'GRID' layout type should be as compact as possible (typically a single icon!).
+        elif self.layout_type in {'GRID'}:
+            layout.alignment = 'CENTER'
+            layout.label(text="", icon_value=icon)
+
+
+class MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist(UIList):
+    """Use this class to show pov texture slots list."""
+
+    #    texture_slots:
+    index: bpy.props.IntProperty(name='index')
+    # foo  = random prop
+    def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
+        # ob = data
+        slot = item
+        # ma = slot.name
+        # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
+        if self.layout_type in {'DEFAULT', 'COMPACT'}:
+            # You should always start your row layout by a label (icon + text), or a non-embossed text field,
+            # this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
+            # We use icon_value of label, as our given icon is an integer value, not an enum ID.
+            # Note "data" names should never be translated!
+            if slot:
+                layout.prop(item, "texture", text="", emboss=False, icon='TEXTURE')
+            else:
+                layout.label(text="New", translate=False, icon_value=icon)
+        # 'GRID' layout type should be as compact as possible (typically a single icon!).
+        elif self.layout_type in {'GRID'}:
+            layout.alignment = 'CENTER'
+            layout.label(text="", icon_value=icon)
+
+
+class TEXTURE_PT_context(TextureButtonsPanel, Panel):
+    """Rewrite of this existing class to modify it."""
+
+    bl_label = ""
+    bl_context = "texture"
+    bl_options = {'HIDE_HEADER'}
+    COMPAT_ENGINES = {'POVRAY_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+    # register but not unregistered because
+    # the modified parts concern only POVRAY_RENDER
+    @classmethod
+    def poll(cls, context):
+        return (
+            context.scene.texture_context
+            not in ('MATERIAL', 'WORLD', 'LIGHT', 'PARTICLES', 'LINESTYLE')
+            or context.scene.render.engine != 'POVRAY_RENDER'
+        )
+
+    def draw(self, context):
+        layout = self.layout
+        tex = context.texture
+        space = context.space_data
+        pin_id = space.pin_id
+        use_pin_id = space.use_pin_id
+        user = context.texture_user
+
+        col = layout.column()
+
+        if not (use_pin_id and isinstance(pin_id, bpy.types.Texture)):
+            pin_id = None
+
+        if not pin_id:
+            col.template_texture_user()
+
+        if user or pin_id:
+            col.separator()
+
+            if pin_id:
+                col.template_ID(space, "pin_id")
+            else:
+                propname = context.texture_user_property.identifier
+                col.template_ID(user, propname, new="texture.new")
+
+            if tex:
+                col.separator()
+
+                split = col.split(factor=0.2)
+                split.label(text="Type")
+                split.prop(tex, "type", text="")
+
+
+class TEXTURE_PT_POV_context_texture(TextureButtonsPanel, Panel):
+    """Use this class to show pov texture context buttons."""
+
+    bl_label = ""
+    bl_options = {'HIDE_HEADER'}
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        engine = context.scene.render.engine
+        return engine in cls.COMPAT_ENGINES
+        # if not (hasattr(context, "pov_texture_slot") or hasattr(context, "texture_node")):
+        #     return False
+        return (
+            context.material
+            or context.scene.world
+            or context.light
+            or context.texture
+            or context.line_style
+            or context.particle_system
+            or isinstance(context.space_data.pin_id, ParticleSettings)
+            or context.texture_user
+        ) and (engine in cls.COMPAT_ENGINES)
+
+    def draw(self, context):
+        layout = self.layout
+
+        scene = context.scene
+        mat = context.view_layer.objects.active.active_material
+        wld = context.scene.world
+
+        layout.prop(scene, "texture_context", expand=True)
+        if scene.texture_context == 'MATERIAL' and mat is not None:
+
+            row = layout.row()
+            row.template_list(
+                "MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist",
+                "",
+                mat,
+                "pov_texture_slots",
+                mat.pov,
+                "active_texture_index",
+                rows=2,
+                maxrows=16,
+                type="DEFAULT",
+            )
+            col = row.column(align=True)
+            col.operator("pov.textureslotadd", icon='ADD', text='')
+            col.operator("pov.textureslotremove", icon='REMOVE', text='')
+            # XXX todo: recreate for pov_texture_slots?
+            # col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
+            # col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
+            col.separator()
+
+            if mat.pov_texture_slots:
+                index = mat.pov.active_texture_index
+                slot = mat.pov_texture_slots[index]
+                povtex = slot.texture  # slot.name
+                tex = bpy.data.textures[povtex]
+                col.prop(tex, 'use_fake_user', text='')
+                # layout.label(text='Linked Texture data browser:')
+                # propname = slot.texture_search
+                # if slot.texture was a pointer to texture data rather than just a name string:
+                # layout.template_ID(povtex, "texture", new="texture.new")
+
+                layout.prop_search(
+                    slot, 'texture_search', bpy.data, 'textures', text='', icon='TEXTURE'
+                )
+                try:
+                    bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[
+                        slot.texture_search
+                    ]
+                    bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[
+                        slot.texture_search
+                    ]
+                except KeyError:
+                    # texture not hand-linked by user
+                    pass
+
+                if tex:
+                    layout.separator()
+                    split = layout.split(factor=0.2)
+                    split.label(text="Type")
+                    split.prop(tex, "type", text="")
+
+            # else:
+            # for i in range(18):  # length of material texture slots
+            # mat.pov_texture_slots.add()
+        elif scene.texture_context == 'WORLD' and wld is not None:
+
+            row = layout.row()
+            row.template_list(
+                "WORLD_TEXTURE_SLOTS_UL_POV_layerlist",
+                "",
+                wld,
+                "pov_texture_slots",
+                wld.pov,
+                "active_texture_index",
+                rows=2,
+                maxrows=16,
+                type="DEFAULT",
+            )
+            col = row.column(align=True)
+            col.operator("pov.textureslotadd", icon='ADD', text='')
+            col.operator("pov.textureslotremove", icon='REMOVE', text='')
+
+            # todo: recreate for pov_texture_slots?
+            # col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
+            # col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
+            col.separator()
+
+            if wld.pov_texture_slots:
+                index = wld.pov.active_texture_index
+                slot = wld.pov_texture_slots[index]
+                povtex = slot.texture  # slot.name
+                tex = bpy.data.textures[povtex]
+                col.prop(tex, 'use_fake_user', text='')
+                # layout.label(text='Linked Texture data browser:')
+                propname = slot.texture_search
+                # if slot.texture was a pointer to texture data rather than just a name string:
+                # layout.template_ID(povtex, "texture", new="texture.new")
+
+                layout.prop_search(
+                    slot, 'texture_search', bpy.data, 'textures', text='', icon='TEXTURE'
+                )
+                try:
+                    bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[
+                        slot.texture_search
+                    ]
+                    bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[
+                        slot.texture_search
+                    ]
+                except KeyError:
+                    # texture not hand-linked by user
+                    pass
+
+                if tex:
+                    layout.separator()
+                    split = layout.split(factor=0.2)
+                    split.label(text="Type")
+                    split.prop(tex, "type", text="")
+
+
+# Commented out below is a reminder of what existed in Blender Internal
+# attributes need to be recreated
+'''
+        slot = getattr(context, "texture_slot", None)
+        node = getattr(context, "texture_node", None)
+        space = context.space_data
+
+        #attempt at replacing removed space_data
+        mtl = getattr(context, "material", None)
+        if mtl != None:
+            spacedependant = mtl
+        wld = getattr(context, "world", None)
+        if wld != None:
+            spacedependant = wld
+        lgt = getattr(context, "light", None)
+        if lgt != None:
+            spacedependant = lgt
+
+
+        #idblock = context.particle_system.settings
+
+        tex = getattr(context, "texture", None)
+        if tex != None:
+            spacedependant = tex
+
+
+
+        scene = context.scene
+        idblock = scene.pov#pov_context_tex_datablock(context)
+        pin_id = space.pin_id
+
+        #spacedependant.use_limited_texture_context = True
+
+        if space.use_pin_id and not isinstance(pin_id, Texture):
+            idblock = id_tex_datablock(pin_id)
+            pin_id = None
+
+        if not space.use_pin_id:
+            layout.row().prop(spacedependant, "texture_context", expand=True)
+            pin_id = None
+
+        if spacedependant.texture_context == 'OTHER':
+            if not pin_id:
+                layout.template_texture_user()
+            user = context.texture_user
+            if user or pin_id:
+                layout.separator()
+
+                row = layout.row()
+
+                if pin_id:
+                    row.template_ID(space, "pin_id")
+                else:
+                    propname = context.texture_user_property.identifier
+                    row.template_ID(user, propname, new="texture.new")
+
+                if tex:
+                    split = layout.split(factor=0.2)
+                    if tex.use_nodes:
+                        if slot:
+                            split.label(text="Output:")
+                            split.prop(slot, "output_node", text="")
+                    else:
+                        split.label(text="Type:")
+                        split.prop(tex, "type", text="")
+            return
+
+        tex_collection = (pin_id is None) and (node is None) and (spacedependant.texture_context not in ('LINESTYLE','OTHER'))
+
+        if tex_collection:
+
+            pov = getattr(context, "pov", None)
+            active_texture_index = getattr(spacedependant, "active_texture_index", None)
+            print (pov)
+            print(idblock)
+            print(active_texture_index)
+            row = layout.row()
+
+            row.template_list("TEXTURE_UL_texslots", "", idblock, "texture_slots",
+                              idblock, "active_texture_index", rows=2, maxrows=16, type="DEFAULT")
+
+            # row.template_list("WORLD_TEXTURE_SLOTS_UL_List", "texture_slots", world,
+                              # world.texture_slots, world, "active_texture_index", rows=2)
+
+            col = row.column(align=True)
+            col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
+            col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
+            col.menu("TEXTURE_MT_POV_specials", icon='DOWNARROW_HLT', text="")
+
+        if tex_collection:
+            layout.template_ID(idblock, "active_texture", new="texture.new")
+        elif node:
+            layout.template_ID(node, "texture", new="texture.new")
+        elif idblock:
+            layout.template_ID(idblock, "texture", new="texture.new")
+
+        if pin_id:
+            layout.template_ID(space, "pin_id")
+
+        if tex:
+            split = layout.split(factor=0.2)
+            if tex.use_nodes:
+                if slot:
+                    split.label(text="Output:")
+                    split.prop(slot, "output_node", text="")
+            else:
+                split.label(text="Type:")
+'''
+
+
+class TEXTURE_PT_colors(TextureButtonsPanel, Panel):
+    """Use this class to show pov color ramps."""
+
+    bl_label = "Colors"
+    bl_options = {'DEFAULT_CLOSED'}
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def draw(self, context):
+        layout = self.layout
+
+        tex = context.texture
+
+        layout.prop(tex, "use_color_ramp", text="Ramp")
+        if tex.use_color_ramp:
+            layout.template_color_ramp(tex, "color_ramp", expand=True)
+
+        split = layout.split()
+
+        col = split.column()
+        col.label(text="RGB Multiply:")
+        sub = col.column(align=True)
+        sub.prop(tex, "factor_red", text="R")
+        sub.prop(tex, "factor_green", text="G")
+        sub.prop(tex, "factor_blue", text="B")
+
+        col = split.column()
+        col.label(text="Adjust:")
+        col.prop(tex, "intensity")
+        col.prop(tex, "contrast")
+        col.prop(tex, "saturation")
+
+        col = layout.column()
+        col.prop(tex, "use_clamp", text="Clamp")
+
+
+# Texture Slot Panels #
+
+
+class TEXTURE_OT_POV_texture_slot_add(Operator):
+    """Use this class for the add texture slot button."""
+
+    bl_idname = "pov.textureslotadd"
+    bl_label = "Add"
+    bl_description = "Add texture_slot"
+    bl_options = {'REGISTER', 'UNDO'}
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def execute(self, context):
+        idblock = pov_context_tex_datablock(context)
+        tex = bpy.data.textures.new(name='Texture', type='IMAGE')
+        # tex.use_fake_user = True
+        # mat = context.view_layer.objects.active.active_material
+        slot = idblock.pov_texture_slots.add()
+        slot.name = tex.name
+        slot.texture = tex.name
+        slot.texture_search = tex.name
+        # Switch paint brush and paint brush mask
+        # to this texture so settings remain contextual
+        bpy.context.tool_settings.image_paint.brush.texture = tex
+        bpy.context.tool_settings.image_paint.brush.mask_texture = tex
+        idblock.pov.active_texture_index = len(idblock.pov_texture_slots) - 1
+
+        # for area in bpy.context.screen.areas:
+        # if area.type in ['PROPERTIES']:
+        # area.tag_redraw()
+
+        return {'FINISHED'}
+
+
+class TEXTURE_OT_POV_texture_slot_remove(Operator):
+    """Use this class for the remove texture slot button."""
+
+    bl_idname = "pov.textureslotremove"
+    bl_label = "Remove"
+    bl_description = "Remove texture_slot"
+    bl_options = {'REGISTER', 'UNDO'}
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def execute(self, context):
+        idblock = pov_context_tex_datablock(context)
+        # mat = context.view_layer.objects.active.active_material
+        # tex_slot = idblock.pov_texture_slots.remove(idblock.pov.active_texture_index) # not used
+        if idblock.pov.active_texture_index > 0:
+            idblock.pov.active_texture_index -= 1
+        try:
+            tex = idblock.pov_texture_slots[idblock.pov.active_texture_index].texture
+        except IndexError:
+            # No more slots
+            return {'FINISHED'}
+        # Switch paint brush to previous texture so settings remain contextual
+        # if 'tex' in locals(): # Would test is the tex variable is assigned / exists
+        bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[tex]
+        bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[tex]
+
+        return {'FINISHED'}
+
+
+class TextureSlotPanel(TextureButtonsPanel):
+    """Use this class to show pov texture slots panel."""
+
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    @classmethod
+    def poll(cls, context):
+        if not hasattr(context, "pov_texture_slot"):
+            return False
+
+        engine = context.scene.render.engine
+        # return TextureButtonsPanel.poll(cls, context) and (engine in cls.COMPAT_ENGINES)
+        return TextureButtonsPanel.poll(context) and (engine in cls.COMPAT_ENGINES)
+
+
+class TEXTURE_PT_POV_type(TextureButtonsPanel, Panel):
+    """Use this class to define pov texture type buttons."""
+
+    bl_label = "POV Textures"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+    bl_options = {'HIDE_HEADER'}
+
+    def draw(self, context):
+        layout = self.layout
+        # world = context.world # unused
+        tex = context.texture
+
+        split = layout.split(factor=0.2)
+        split.label(text="Pattern")
+        split.prop(tex.pov, "tex_pattern_type", text="")
+
+        # row = layout.row()
+        # row.template_list("WORLD_TEXTURE_SLOTS_UL_List", "texture_slots", world,
+        # world.texture_slots, world, "active_texture_index")
+
+
+class TEXTURE_PT_POV_preview(TextureButtonsPanel, Panel):
+    """Use this class to define pov texture preview panel."""
+
+    bl_label = "Preview"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+    bl_options = {'HIDE_HEADER'}
+
+    @classmethod
+    def poll(cls, context):
+        engine = context.scene.render.engine
+        if not hasattr(context, "pov_texture_slot"):
+            return False
+        tex = context.texture
+        # mat = bpy.context.active_object.active_material #unused
+        return tex and (tex.pov.tex_pattern_type != 'emulator') and (engine in cls.COMPAT_ENGINES)
+
+    def draw(self, context):
+        tex = context.texture
+        slot = getattr(context, "pov_texture_slot", None)
+        # idblock = pov_context_tex_datablock(context) # unused
+        layout = self.layout
+        # if idblock:
+        # layout.template_preview(tex, parent=idblock, slot=slot)
+        if tex.pov.tex_pattern_type != 'emulator':
+            layout.operator("tex.preview_update")
+        else:
+            layout.template_preview(tex, slot=slot)
+
+
+class TEXTURE_PT_POV_parameters(TextureButtonsPanel, Panel):
+    """Use this class to define pov texture pattern buttons."""
+
+    bl_label = "POV Pattern Options"
+    bl_options = {'HIDE_HEADER'}
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def draw(self, context):
+        # mat = bpy.context.active_object.active_material # Unused
+        layout = self.layout
+        tex = context.texture
+        align = True
+        if tex is not None and tex.pov.tex_pattern_type != 'emulator':
+            if tex.pov.tex_pattern_type == 'agate':
+                layout.prop(tex.pov, "modifier_turbulence", text="Agate Turbulence")
+            if tex.pov.tex_pattern_type in {'spiral1', 'spiral2'}:
+                layout.prop(tex.pov, "modifier_numbers", text="Number of arms")
+            if tex.pov.tex_pattern_type == 'tiling':
+                layout.prop(tex.pov, "modifier_numbers", text="Pattern number")
+            if tex.pov.tex_pattern_type == 'magnet':
+                layout.prop(tex.pov, "magnet_style", text="Magnet style")
+            if tex.pov.tex_pattern_type == 'quilted':
+                row = layout.row(align=align)
+                row.prop(tex.pov, "modifier_control0", text="Control0")
+                row.prop(tex.pov, "modifier_control1", text="Control1")
+            if tex.pov.tex_pattern_type == 'brick':
+                col = layout.column(align=align)
+                row = col.row()
+                row.prop(tex.pov, "brick_size_x", text="Brick size X")
+                row.prop(tex.pov, "brick_size_y", text="Brick size Y")
+                row = col.row()
+                row.prop(tex.pov, "brick_size_z", text="Brick size Z")
+                row.prop(tex.pov, "brick_mortar", text="Brick mortar")
+            if tex.pov.tex_pattern_type in {'julia', 'mandel', 'magnet'}:
+                col = layout.column(align=align)
+                if tex.pov.tex_pattern_type == 'julia':
+                    row = col.row()
+                    row.prop(tex.pov, "julia_complex_1", text="Complex 1")
+                    row.prop(tex.pov, "julia_complex_2", text="Complex 2")
+                if tex.pov.tex_pattern_type == 'magnet' and tex.pov.magnet_style == 'julia':
+                    row = col.row()
+                    row.prop(tex.pov, "julia_complex_1", text="Complex 1")
+                    row.prop(tex.pov, "julia_complex_2", text="Complex 2")
+                row = col.row()
+                if tex.pov.tex_pattern_type in {'julia', 'mandel'}:
+                    row.prop(tex.pov, "f_exponent", text="Exponent")
+                if tex.pov.tex_pattern_type == 'magnet':
+                    row.prop(tex.pov, "magnet_type", text="Type")
+                row.prop(tex.pov, "f_iter", text="Iterations")
+                row = col.row()
+                row.prop(tex.pov, "f_ior", text="Interior")
+                row.prop(tex.pov, "f_ior_fac", text="Factor I")
+                row = col.row()
+                row.prop(tex.pov, "f_eor", text="Exterior")
+                row.prop(tex.pov, "f_eor_fac", text="Factor E")
+            if tex.pov.tex_pattern_type == 'gradient':
+                layout.label(text="Gradient orientation:")
+                column_flow = layout.column_flow(columns=3, align=True)
+                column_flow.prop(tex.pov, "grad_orient_x", text="X")
+                column_flow.prop(tex.pov, "grad_orient_y", text="Y")
+                column_flow.prop(tex.pov, "grad_orient_z", text="Z")
+            if tex.pov.tex_pattern_type == 'pavement':
+                layout.prop(tex.pov, "pave_sides", text="Pavement:number of sides")
+                col = layout.column(align=align)
+                column_flow = col.column_flow(columns=3, align=True)
+                column_flow.prop(tex.pov, "pave_tiles", text="Tiles")
+                if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 6:
+                    column_flow.prop(tex.pov, "pave_pat_35", text="Pattern")
+                if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 5:
+                    column_flow.prop(tex.pov, "pave_pat_22", text="Pattern")
+                if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 5:
+                    column_flow.prop(tex.pov, "pave_pat_12", text="Pattern")
+                if tex.pov.pave_sides == '3' and tex.pov.pave_tiles == 6:
+                    column_flow.prop(tex.pov, "pave_pat_12", text="Pattern")
+                if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 4:
+                    column_flow.prop(tex.pov, "pave_pat_7", text="Pattern")
+                if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 4:
+                    column_flow.prop(tex.pov, "pave_pat_5", text="Pattern")
+                if tex.pov.pave_sides == '3' and tex.pov.pave_tiles == 5:
+                    column_flow.prop(tex.pov, "pave_pat_4", text="Pattern")
+                if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 3:
+                    column_flow.prop(tex.pov, "pave_pat_3", text="Pattern")
+                if tex.pov.pave_sides == '3' and tex.pov.pave_tiles == 4:
+                    column_flow.prop(tex.pov, "pave_pat_3", text="Pattern")
+                if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 3:
+                    column_flow.prop(tex.pov, "pave_pat_2", text="Pattern")
+                if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 6:
+                    column_flow.label(text="!!! 5 tiles!")
+                column_flow.prop(tex.pov, "pave_form", text="Form")
+            if tex.pov.tex_pattern_type == 'function':
+                layout.prop(tex.pov, "func_list", text="Functions")
+            if tex.pov.tex_pattern_type == 'function' and tex.pov.func_list != "NONE":
+                func = None
+                if tex.pov.func_list in {"f_noise3d", "f_ph", "f_r", "f_th"}:
+                    func = 0
+                if tex.pov.func_list in {
+                    "f_comma",
+                    "f_crossed_trough",
+                    "f_cubic_saddle",
+                    "f_cushion",
+                    "f_devils_curve",
+                    "f_enneper",
+                    "f_glob",
+                    "f_heart",
+                    "f_hex_x",
+                    "f_hex_y",
+                    "f_hunt_surface",
+                    "f_klein_bottle",
+                    "f_kummer_surface_v1",
+                    "f_lemniscate_of_gerono",
+                    "f_mitre",
+                    "f_nodal_cubic",
+                    "f_noise_generator",
+                    "f_odd",
+                    "f_paraboloid",
+                    "f_pillow",
+                    "f_piriform",
+                    "f_quantum",
+                    "f_quartic_paraboloid",
+                    "f_quartic_saddle",
+                    "f_sphere",
+                    "f_steiners_roman",
+                    "f_torus_gumdrop",
+                    "f_umbrella",
+                }:
+                    func = 1
+                if tex.pov.func_list in {
+                    "f_bicorn",
+                    "f_bifolia",
+                    "f_boy_surface",
+                    "f_superellipsoid",
+                    "f_torus",
+                }:
+                    func = 2
+                if tex.pov.func_list in {
+                    "f_ellipsoid",
+                    "f_folium_surface",
+                    "f_hyperbolic_torus",
+                    "f_kampyle_of_eudoxus",
+                    "f_parabolic_torus",
+                    "f_quartic_cylinder",
+                    "f_torus2",
+                }:
+                    func = 3
+                if tex.pov.func_list in {
+                    "f_blob2",
+                    "f_cross_ellipsoids",
+                    "f_flange_cover",
+                    "f_isect_ellipsoids",
+                    "f_kummer_surface_v2",
+                    "f_ovals_of_cassini",
+                    "f_rounded_box",
+                    "f_spikes_2d",
+                    "f_strophoid",
+                }:
+                    func = 4
+                if tex.pov.func_list in {
+                    "f_algbr_cyl1",
+                    "f_algbr_cyl2",
+                    "f_algbr_cyl3",
+                    "f_algbr_cyl4",
+                    "f_blob",
+                    "f_mesh1",
+                    "f_poly4",
+                    "f_spikes",
+                }:
+                    func = 5
+                if tex.pov.func_list in {
+                    "f_devils_curve_2d",
+                    "f_dupin_cyclid",
+                    "f_folium_surface_2d",
+                    "f_hetero_mf",
+                    "f_kampyle_of_eudoxus_2d",
+                    "f_lemniscate_of_gerono_2d",
+                    "f_polytubes",
+                    "f_ridge",
+                    "f_ridged_mf",
+                    "f_spiral",
+                    "f_witch_of_agnesi",
+                }:
+                    func = 6
+                if tex.pov.func_list in {"f_helix1", "f_helix2", "f_piriform_2d", "f_strophoid_2d"}:
+                    func = 7
+                if tex.pov.func_list == "f_helical_torus":
+                    func = 8
+                column_flow = layout.column_flow(columns=3, align=True)
+                column_flow.label(text="X")
+                column_flow.prop(tex.pov, "func_plus_x", text="")
+                column_flow.prop(tex.pov, "func_x", text="Value")
+                column_flow = layout.column_flow(columns=3, align=True)
+                column_flow.label(text="Y")
+                column_flow.prop(tex.pov, "func_plus_y", text="")
+                column_flow.prop(tex.pov, "func_y", text="Value")
+                column_flow = layout.column_flow(columns=3, align=True)
+                column_flow.label(text="Z")
+                column_flow.prop(tex.pov, "func_plus_z", text="")
+                column_flow.prop(tex.pov, "func_z", text="Value")
+                row = layout.row(align=align)
+                if func > 0:
+                    row.prop(tex.pov, "func_P0", text="P0")
+                if func > 1:
+                    row.prop(tex.pov, "func_P1", text="P1")
+                row = layout.row(align=align)
+                if func > 2:
+                    row.prop(tex.pov, "func_P2", text="P2")
+                if func > 3:
+                    row.prop(tex.pov, "func_P3", text="P3")
+                row = layout.row(align=align)
+                if func > 4:
+                    row.prop(tex.pov, "func_P4", text="P4")
+                if func > 5:
+                    row.prop(tex.pov, "func_P5", text="P5")
+                row = layout.row(align=align)
+                if func > 6:
+                    row.prop(tex.pov, "func_P6", text="P6")
+                if func > 7:
+                    row.prop(tex.pov, "func_P7", text="P7")
+                    row = layout.row(align=align)
+                    row.prop(tex.pov, "func_P8", text="P8")
+                    row.prop(tex.pov, "func_P9", text="P9")
+            ###################################################End Patterns############################
+
+            layout.prop(tex.pov, "warp_types", text="Warp types")  # warp
+            if tex.pov.warp_types == "TOROIDAL":
+                layout.prop(tex.pov, "warp_tor_major_radius", text="Major radius")
+            if tex.pov.warp_types not in {"CUBIC", "NONE"}:
+                layout.prop(tex.pov, "warp_orientation", text="Warp orientation")
+            col = layout.column(align=align)
+            row = col.row()
+            row.prop(tex.pov, "warp_dist_exp", text="Distance exponent")
+            row = col.row()
+            row.prop(tex.pov, "modifier_frequency", text="Frequency")
+            row.prop(tex.pov, "modifier_phase", text="Phase")
+
+            row = layout.row()
+
+            row.label(text="Offset:")
+            row.label(text="Scale:")
+            row.label(text="Rotate:")
+            col = layout.column(align=align)
+            row = col.row()
+            row.prop(tex.pov, "tex_mov_x", text="X")
+            row.prop(tex.pov, "tex_scale_x", text="X")
+            row.prop(tex.pov, "tex_rot_x", text="X")
+            row = col.row()
+            row.prop(tex.pov, "tex_mov_y", text="Y")
+            row.prop(tex.pov, "tex_scale_y", text="Y")
+            row.prop(tex.pov, "tex_rot_y", text="Y")
+            row = col.row()
+            row.prop(tex.pov, "tex_mov_z", text="Z")
+            row.prop(tex.pov, "tex_scale_z", text="Z")
+            row.prop(tex.pov, "tex_rot_z", text="Z")
+            row = layout.row()
+
+            row.label(text="Turbulence:")
+            col = layout.column(align=align)
+            row = col.row()
+            row.prop(tex.pov, "warp_turbulence_x", text="X")
+            row.prop(tex.pov, "modifier_octaves", text="Octaves")
+            row = col.row()
+            row.prop(tex.pov, "warp_turbulence_y", text="Y")
+            row.prop(tex.pov, "modifier_lambda", text="Lambda")
+            row = col.row()
+            row.prop(tex.pov, "warp_turbulence_z", text="Z")
+            row.prop(tex.pov, "modifier_omega", text="Omega")
+
+
+class TEXTURE_PT_POV_mapping(TextureSlotPanel, Panel):
+    """Use this class to define POV texture mapping buttons."""
+
+    bl_label = "Mapping"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+    bl_space_type = 'PROPERTIES'
+    bl_region_type = 'WINDOW'
+
+    @classmethod
+    def poll(cls, context):
+        idblock = pov_context_tex_datablock(context)
+        if isinstance(idblock, Brush) and not context.sculpt_object:
+            return False
+
+        if not getattr(context, "texture_slot", None):
+            return False
+
+        engine = context.scene.render.engine
+        return engine in cls.COMPAT_ENGINES
+
+    def draw(self, context):
+        layout = self.layout
+
+        idblock = pov_context_tex_datablock(context)
+        mat = bpy.context.active_object.active_material
+        # tex = context.texture_slot
+        tex = mat.pov_texture_slots[mat.active_texture_index]
+        if not isinstance(idblock, Brush):
+            split = layout.split(percentage=0.3)
+            col = split.column()
+            col.label(text="Coordinates:")
+            col = split.column()
+            col.prop(tex, "texture_coords", text="")
+
+            if tex.texture_coords == 'ORCO':
+                """
+                ob = context.object
+                if ob and ob.type == 'MESH':
+                    split = layout.split(percentage=0.3)
+                    split.label(text="Mesh:")
+                    split.prop(ob.data, "texco_mesh", text="")
+                """
+            elif tex.texture_coords == 'UV':
+                split = layout.split(percentage=0.3)
+                split.label(text="Map:")
+                ob = context.object
+                if ob and ob.type == 'MESH':
+                    split.prop_search(tex, "uv_layer", ob.data, "uv_textures", text="")
+                else:
+                    split.prop(tex, "uv_layer", text="")
+
+            elif tex.texture_coords == 'OBJECT':
+                split = layout.split(percentage=0.3)
+                split.label(text="Object:")
+                split.prop(tex, "object", text="")
+
+            elif tex.texture_coords == 'ALONG_STROKE':
+                split = layout.split(percentage=0.3)
+                split.label(text="Use Tips:")
+                split.prop(tex, "use_tips", text="")
+
+        if isinstance(idblock, Brush):
+            if context.sculpt_object or context.image_paint_object:
+                brush_texture_settings(layout, idblock, context.sculpt_object)
+        else:
+            if isinstance(idblock, FreestyleLineStyle):
+                split = layout.split(percentage=0.3)
+                split.label(text="Projection:")
+                split.prop(tex, "mapping", text="")
+
+                split = layout.split(percentage=0.3)
+                split.separator()
+                row = split.row()
+                row.prop(tex, "mapping_x", text="")
+                row.prop(tex, "mapping_y", text="")
+                row.prop(tex, "mapping_z", text="")
+
+            elif isinstance(idblock, Material):
+                split = layout.split(percentage=0.3)
+                split.label(text="Projection:")
+                split.prop(tex, "mapping", text="")
+
+                split = layout.split()
+
+                col = split.column()
+                if tex.texture_coords in {'ORCO', 'UV'}:
+                    col.prop(tex, "use_from_dupli")
+                    if idblock.type == 'VOLUME' and tex.texture_coords == 'ORCO':
+                        col.prop(tex, "use_map_to_bounds")
+                elif tex.texture_coords == 'OBJECT':
+                    col.prop(tex, "use_from_original")
+                    if idblock.type == 'VOLUME':
+                        col.prop(tex, "use_map_to_bounds")
+                else:
+                    col.label()
+
+                col = split.column()
+                row = col.row()
+                row.prop(tex, "mapping_x", text="")
+                row.prop(tex, "mapping_y", text="")
+                row.prop(tex, "mapping_z", text="")
+
+            row = layout.row()
+            row.column().prop(tex, "offset")
+            row.column().prop(tex, "scale")
+
+
+class TEXTURE_PT_POV_influence(TextureSlotPanel, Panel):
+    """Use this class to define pov texture influence buttons."""
+
+    bl_label = "Influence"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+    bl_space_type = 'PROPERTIES'
+    bl_region_type = 'WINDOW'
+    # bl_context = 'texture'
+    @classmethod
+    def poll(cls, context):
+        idblock = pov_context_tex_datablock(context)
+        if (
+            # isinstance(idblock, Brush) and # Brush used for everything since 2.8
+            context.scene.texture_context
+            == 'OTHER'
+        ):  # XXX replace by isinstance(idblock, bpy.types.Brush) and ...
+            return False
+
+        # Specify below also for pov_world_texture_slots, lights etc.
+        # to display for various types of slots but only when any
+        if not getattr(idblock, "pov_texture_slots", None):
+            return False
+
+        engine = context.scene.render.engine
+        return engine in cls.COMPAT_ENGINES
+
+    def draw(self, context):
+
+        layout = self.layout
+
+        idblock = pov_context_tex_datablock(context)
+        # tex = context.pov_texture_slot
+        # mat = bpy.context.active_object.active_material
+        texslot = idblock.pov_texture_slots[
+            idblock.pov.active_texture_index
+        ]  # bpy.data.textures[mat.active_texture_index]
+        # below tex is unused
+        tex = bpy.data.textures[idblock.pov_texture_slots[idblock.pov.active_texture_index].texture]
+
+        def factor_but(layout, toggle, factor, name):
+            row = layout.row(align=True)
+            row.prop(texslot, toggle, text="")
+            sub = row.row(align=True)
+            sub.active = getattr(texslot, toggle)
+            sub.prop(texslot, factor, text=name, slider=True)
+            return sub  # XXX, temp. use_map_normal needs to override.
+
+        if isinstance(idblock, Material):
+            split = layout.split()
+
+            col = split.column()
+            if idblock.pov.type in {'SURFACE', 'WIRE'}:
+
+                split = layout.split()
+
+                col = split.column()
+                col.label(text="Diffuse:")
+                factor_but(col, "use_map_diffuse", "diffuse_factor", "Intensity")
+                factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
+                factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
+                factor_but(col, "use_map_translucency", "translucency_factor", "Translucency")
+
+                col.label(text="Specular:")
+                factor_but(col, "use_map_specular", "specular_factor", "Intensity")
+                factor_but(col, "use_map_color_spec", "specular_color_factor", "Color")
+                factor_but(col, "use_map_hardness", "hardness_factor", "Hardness")
+
+                col = split.column()
+                col.label(text="Shading:")
+                factor_but(col, "use_map_ambient", "ambient_factor", "Ambient")
+                factor_but(col, "use_map_emit", "emit_factor", "Emit")
+                factor_but(col, "use_map_mirror", "mirror_factor", "Mirror")
+                factor_but(col, "use_map_raymir", "raymir_factor", "Ray Mirror")
+
+                col.label(text="Geometry:")
+                # XXX replace 'or' when displacement is fixed to not rely on normal influence value.
+                sub_tmp = factor_but(col, "use_map_normal", "normal_factor", "Normal")
+                sub_tmp.active = texslot.use_map_normal or texslot.use_map_displacement
+                # END XXX
+
+                factor_but(col, "use_map_warp", "warp_factor", "Warp")
+                factor_but(col, "use_map_displacement", "displacement_factor", "Displace")
+
+            elif idblock.pov.type == 'HALO':
+                layout.label(text="Halo:")
+
+                split = layout.split()
+
+                col = split.column()
+                factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
+                factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
+
+                col = split.column()
+                factor_but(col, "use_map_raymir", "raymir_factor", "Size")
+                factor_but(col, "use_map_hardness", "hardness_factor", "Hardness")
+                factor_but(col, "use_map_translucency", "translucency_factor", "Add")
+            elif idblock.pov.type == 'VOLUME':
+                layout.label(text="Volume:")
+
+                split = layout.split()
+
+                col = split.column()
+                factor_but(col, "use_map_density", "density_factor", "Density")
+                factor_but(col, "use_map_emission", "emission_factor", "Emission")
+                factor_but(col, "use_map_scatter", "scattering_factor", "Scattering")
+                factor_but(col, "use_map_reflect", "reflection_factor", "Reflection")
+
+                col = split.column()
+                col.label(text=" ")
+                factor_but(col, "use_map_color_emission", "emission_color_factor", "Emission Color")
+                factor_but(
+                    col,
+                    "use_map_color_transmission",
+                    "transmission_color_factor",
+                    "Transmission Color",
+                )
+                factor_but(
+                    col, "use_map_color_reflection", "reflection_color_factor", "Reflection Color"
+                )
+
+                layout.label(text="Geometry:")
+
+                split = layout.split()
+
+                col = split.column()
+                factor_but(col, "use_map_warp", "warp_factor", "Warp")
+
+                col = split.column()
+                factor_but(col, "use_map_displacement", "displacement_factor", "Displace")
+
+        elif isinstance(idblock, Light):
+            split = layout.split()
+
+            col = split.column()
+            factor_but(col, "use_map_color", "color_factor", "Color")
+
+            col = split.column()
+            factor_but(col, "use_map_shadow", "shadow_factor", "Shadow")
+
+        elif isinstance(idblock, World):
+            split = layout.split()
+
+            col = split.column()
+            factor_but(col, "use_map_blend", "blend_factor", "Blend")
+            factor_but(col, "use_map_horizon", "horizon_factor", "Horizon")
+
+            col = split.column()
+            factor_but(col, "use_map_zenith_up", "zenith_up_factor", "Zenith Up")
+            factor_but(col, "use_map_zenith_down", "zenith_down_factor", "Zenith Down")
+        elif isinstance(idblock, ParticleSettings):
+            split = layout.split()
+
+            col = split.column()
+            col.label(text="General:")
+            factor_but(col, "use_map_time", "time_factor", "Time")
+            factor_but(col, "use_map_life", "life_factor", "Lifetime")
+            factor_but(col, "use_map_density", "density_factor", "Density")
+            factor_but(col, "use_map_size", "size_factor", "Size")
+
+            col = split.column()
+            col.label(text="Physics:")
+            factor_but(col, "use_map_velocity", "velocity_factor", "Velocity")
+            factor_but(col, "use_map_damp", "damp_factor", "Damp")
+            factor_but(col, "use_map_gravity", "gravity_factor", "Gravity")
+            factor_but(col, "use_map_field", "field_factor", "Force Fields")
+
+            layout.label(text="Hair:")
+
+            split = layout.split()
+
+            col = split.column()
+            factor_but(col, "use_map_length", "length_factor", "Length")
+            factor_but(col, "use_map_clump", "clump_factor", "Clump")
+            factor_but(col, "use_map_twist", "twist_factor", "Twist")
+
+            col = split.column()
+            factor_but(col, "use_map_kink_amp", "kink_amp_factor", "Kink Amplitude")
+            factor_but(col, "use_map_kink_freq", "kink_freq_factor", "Kink Frequency")
+            factor_but(col, "use_map_rough", "rough_factor", "Rough")
+
+        elif isinstance(idblock, FreestyleLineStyle):
+            split = layout.split()
+
+            col = split.column()
+            factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
+            col = split.column()
+            factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
+
+        layout.separator()
+
+        if not isinstance(idblock, ParticleSettings):
+            split = layout.split()
+
+            col = split.column()
+            # col.prop(tex, "blend_type", text="Blend") #deprecated since 2.8
+            # col.prop(tex, "use_rgb_to_intensity") #deprecated since 2.8
+            # color is used on gray-scale textures even when use_rgb_to_intensity is disabled.
+            # col.prop(tex, "color", text="") #deprecated since 2.8
+
+            col = split.column()
+            # col.prop(tex, "invert", text="Negative") #deprecated since 2.8
+            # col.prop(tex, "use_stencil") #deprecated since 2.8
+
+        # if isinstance(idblock, (Material, World)):
+        # col.prop(tex, "default_value", text="DVar", slider=True)
+
+
+class TEXTURE_PT_POV_tex_gamma(TextureButtonsPanel, Panel):
+    """Use this class to define pov texture gamma buttons."""
+
+    bl_label = "Image Gamma"
+    COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+    def draw_header(self, context):
+        tex = context.texture
+
+        self.layout.prop(tex.pov, "tex_gamma_enable", text="", icon='SEQ_LUMA_WAVEFORM')
+
+    def draw(self, context):
+        layout = self.layout
+
+        tex = context.texture
+
+        layout.active = tex.pov.tex_gamma_enable
+        layout.prop(tex.pov, "tex_gamma_value", text="Gamma Value")
+
+
+# commented out below UI for texture only custom code inside exported material:
+# class TEXTURE_PT_povray_replacement_text(TextureButtonsPanel, Panel):
+# bl_label = "Custom POV Code"
+# COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+# def draw(self, context):
+# layout = self.layout
+
+# tex = context.texture
+
+# col = layout.column()
+# col.label(text="Replace properties with:")
+# col.prop(tex.pov, "replacement_text", text="")
+
+
+classes = (
+    WORLD_TEXTURE_SLOTS_UL_POV_layerlist,
+    TEXTURE_MT_POV_specials,
+    TEXTURE_PT_POV_context_texture,
+    TEXTURE_PT_colors,
+    TEXTURE_PT_POV_type,
+    TEXTURE_PT_POV_preview,
+    TEXTURE_PT_POV_parameters,
+    TEXTURE_PT_POV_tex_gamma,
+    MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist,
+    TEXTURE_OT_POV_texture_slot_add,
+    TEXTURE_OT_POV_texture_slot_remove,
+    TEXTURE_PT_POV_influence,
+    TEXTURE_PT_POV_mapping,
+)
+
+
+def register():
+
+    for cls in classes:
+        register_class(cls)
+
+
+def unregister():
+
+    for cls in reversed(classes):
+        if cls != TEXTURE_PT_context:
+            unregister_class(cls)
diff --git a/render_povray/texturing_properties.py b/render_povray/texturing_properties.py
new file mode 100755
index 000000000..bb89ee025
--- /dev/null
+++ b/render_povray/texturing_properties.py
@@ -0,0 +1,1137 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+"""Declare texturing properties controllable in UI."""
+
+import bpy
+from bpy.utils import register_class, unregister_class
+from bpy.types import PropertyGroup
+from bpy.props import (
+    FloatVectorProperty,
+    StringProperty,
+    BoolProperty,
+    IntProperty,
+    FloatProperty,
+    EnumProperty,
+    PointerProperty,
+    CollectionProperty,
+)
+
+from .shading_properties import active_texture_name_from_uilist, active_texture_name_from_search
+
+###############################################################################
+# Texture slots (Material context) exported as POV texture properties.
+###############################################################################
+class MaterialTextureSlot(PropertyGroup):
+    """Declare material texture slot level properties for UI and translated to POV."""
+
+    bl_idname = ("pov_texture_slots",)
+    bl_description = ("Texture_slots from Blender-2.79",)
+
+    # Adding a "real" texture datablock as property is not possible
+    # (or at least not easy through a dynamically populated EnumProperty).
+    # That's why we'll use a prop_search() UILayout function in texturing_gui.py.
+    # So we'll assign the name of the needed texture datablock to the below StringProperty.
+    texture: StringProperty(update=active_texture_name_from_uilist)
+    # and use another temporary StringProperty to change the linked data
+    texture_search: StringProperty(
+        name="", update=active_texture_name_from_search, description="Browse Texture to be linked"
+    )
+
+    alpha_factor: FloatProperty(
+        name="Alpha", description="Amount texture affects alpha", default=1.0
+    )
+
+    ambient_factor: FloatProperty(
+        name="", description="Amount texture affects ambient", default=1.0
+    )
+
+    bump_method: EnumProperty(
+        name="",
+        description="Method to use for bump mapping",
+        items=(
+            ("BUMP_ORIGINAL", "Bump Original", ""),
+            ("BUMP_COMPATIBLE", "Bump Compatible", ""),
+            ("BUMP_DEFAULT", "Bump Default", ""),
+            ("BUMP_BEST_QUALITY", "Bump Best Quality", ""),
+        ),
+        default="BUMP_ORIGINAL",
+    )
+
+    bump_objectspace: EnumProperty(
+        name="",
+        description="Space to apply bump mapping in",
+        items=(
+            ("BUMP_VIEWSPACE", "Bump Viewspace", ""),
+            ("BUMP_OBJECTSPACE", "Bump Objectspace", ""),
+            ("BUMP_TEXTURESPACE", "Bump Texturespace", ""),
+        ),
+        default="BUMP_VIEWSPACE",
+    )
+
+    density_factor: FloatProperty(
+        name="", description="Amount texture affects density", default=1.0
+    )
+
+    diffuse_color_factor: FloatProperty(
+        name="", description="Amount texture affects diffuse color", default=1.0
+    )
+
+    diffuse_factor: FloatProperty(
+        name="", description="Amount texture affects diffuse reflectivity", default=1.0
+    )
+
+    displacement_factor: FloatProperty(
+        name="", description="Amount texture displaces the surface", default=0.2
+    )
+
+    emission_color_factor: FloatProperty(
+        name="", description="Amount texture affects emission color", default=1.0
+    )
+
+    emission_factor: FloatProperty(
+        name="", description="Amount texture affects emission", default=1.0
+    )
+
+    emit_factor: FloatProperty(name="", description="Amount texture affects emission", default=1.0)
+
+    hardness_factor: FloatProperty(
+        name="", description="Amount texture affects hardness", default=1.0
+    )
+
+    mapping: EnumProperty(
+        name="",
+        description="",
+        items=(
+            ("FLAT", "Flat", ""),
+            ("CUBE", "Cube", ""),
+            ("TUBE", "Tube", ""),
+            ("SPHERE", "Sphere", ""),
+        ),
+        default="FLAT",
+    )
+
+    mapping_x: EnumProperty(
+        name="",
+        description="",
+        items=(("NONE", "", ""), ("X", "", ""), ("Y", "", ""), ("Z", "", "")),
+        default="NONE",
+    )
+
+    mapping_y: EnumProperty(
+        name="",
+        description="",
+        items=(("NONE", "", ""), ("X", "", ""), ("Y", "", ""), ("Z", "", "")),
+        default="NONE",
+    )
+
+    mapping_z: EnumProperty(
+        name="",
+        description="",
+        items=(("NONE", "", ""), ("X", "", ""), ("Y", "", ""), ("Z", "", "")),
+        default="NONE",
+    )
+
+    mirror_factor: FloatProperty(
+        name="", description="Amount texture affects mirror color", default=1.0
+    )
+
+    normal_factor: FloatProperty(
+        name="", description="Amount texture affects normal values", default=1.0
+    )
+
+    normal_map_space: EnumProperty(
+        name="",
+        description="Sets space of normal map image",
+        items=(
+            ("CAMERA", "Camera", ""),
+            ("WORLD", "World", ""),
+            ("OBJECT", "Object", ""),
+            ("TANGENT", "Tangent", ""),
+        ),
+        default="CAMERA",
+    )
+
+    object: StringProperty(
+        name="Object",
+        description="Object to use for mapping with Object texture coordinates",
+        default="",
+    )
+
+    raymir_factor: FloatProperty(
+        name="", description="Amount texture affects ray mirror", default=1.0
+    )
+
+    reflection_color_factor: FloatProperty(
+        name="", description="Amount texture affects color of out-scattered light", default=1.0
+    )
+
+    reflection_factor: FloatProperty(
+        name="", description="Amount texture affects brightness of out-scattered light", default=1.0
+    )
+
+    scattering_factor: FloatProperty(
+        name="", description="Amount texture affects scattering", default=1.0
+    )
+
+    specular_color_factor: FloatProperty(
+        name="", description="Amount texture affects specular color", default=1.0
+    )
+
+    specular_factor: FloatProperty(
+        name="", description="Amount texture affects specular reflectivity", default=1.0
+    )
+
+    offset: FloatVectorProperty(
+        name="Offset",
+        description=("Fine tune of the texture mapping X, Y and Z locations "),
+        precision=4,
+        step=0.1,
+        soft_min=-100.0,
+        soft_max=100.0,
+        default=(0.0, 0.0, 0.0),
+        options={"ANIMATABLE"},
+        subtype="TRANSLATION",
+    )
+
+    scale: FloatVectorProperty(
+        name="Size",
+        subtype="XYZ",
+        size=3,
+        description="Set scaling for the texture’s X, Y and Z sizes ",
+        precision=4,
+        step=0.1,
+        soft_min=-100.0,
+        soft_max=100.0,
+        default=(1.0, 1.0, 1.0),
+        options={"ANIMATABLE"},
+    )
+
+    texture_coords: EnumProperty(
+        name="",
+        description="",
+        items=(
+            ("GLOBAL", "Global", ""),
+            ("OBJECT", "Object", ""),
+            ("UV", "UV", ""),
+            ("ORCO", "Original Coordinates", ""),
+            ("STRAND", "Strand", ""),
+            ("STICKY", "Sticky", ""),
+            ("WINDOW", "Window", ""),
+            ("NORMAL", "Normal", ""),
+            ("REFLECTION", "Reflection", ""),
+            ("STRESS", "Stress", ""),
+            ("TANGENT", "Tangent", ""),
+        ),
+        default="GLOBAL",
+    )
+
+    translucency_factor: FloatProperty(
+        name="", description="Amount texture affects translucency", default=1.0
+    )
+
+    transmission_color_factor: FloatProperty(
+        name="",
+        description="Amount texture affects result color after light has been scattered/absorbed",
+        default=1.0,
+    )
+
+    use: BoolProperty(name="", description="Enable this material texture slot", default=True)
+
+    use_from_dupli: BoolProperty(
+        name="",
+        description="Dupli’s instanced from verts, faces or particles, "
+        "inherit texture coordinate from their parent",
+        default=False,
+    )
+
+    use_from_original: BoolProperty(
+        name="",
+        description="Dupli’s derive their object coordinates from the "
+        "original objects transformation",
+        default=False,
+    )
+
+    use_interpolation: BoolProperty(
+        name="", description="Interpolates pixels using selected filter ", default=False
+    )
+
+    use_map_alpha: BoolProperty(
+        name="", description="Causes the texture to affect the alpha value", default=False
+    )
+
+    use_map_ambient: BoolProperty(
+        name="", description="Causes the texture to affect the value of ambient", default=False
+    )
+
+    use_map_color_diffuse: BoolProperty(
+        name="",
+        description="Causes the texture to affect basic color of the material",
+        default=True,
+    )
+
+    use_map_color_emission: BoolProperty(
+        name="", description="Causes the texture to affect the color of emission", default=False
+    )
+
+    use_map_color_reflection: BoolProperty(
+        name="",
+        description="Causes the texture to affect the color of scattered light",
+        default=False,
+    )
+
+    use_map_color_spec: BoolProperty(
+        name="", description="Causes the texture to affect the specularity color", default=False
+    )
+
+    use_map_color_transmission: BoolProperty(
+        name="",
+        description="Causes the texture to affect the result color after "
+        "other light has been scattered/absorbed",
+        default=False,
+    )
+
+    use_map_density: BoolProperty(
+        name="", description="Causes the texture to affect the volume’s density", default=False
+    )
+
+    use_map_diffuse: BoolProperty(
+        name="",
+        description="Causes the texture to affect the value of the materials diffuse reflectivity",
+        default=False,
+    )
+
+    use_map_displacement: BoolProperty(
+        name="", description="Let the texture displace the surface", default=False
+    )
+
+    use_map_emission: BoolProperty(
+        name="", description="Causes the texture to affect the volume’s emission", default=False
+    )
+
+    use_map_emit: BoolProperty(
+        name="", description="Causes the texture to affect the emit value", default=False
+    )
+
+    use_map_hardness: BoolProperty(
+        name="", description="Causes the texture to affect the hardness value", default=False
+    )
+
+    use_map_mirror: BoolProperty(
+        name="", description="Causes the texture to affect the mirror color", default=False
+    )
+
+    use_map_normal: BoolProperty(
+        name="", description="Causes the texture to affect the rendered normal", default=False
+    )
+
+    use_map_raymir: BoolProperty(
+        name="", description="Causes the texture to affect the ray-mirror value", default=False
+    )
+
+    use_map_reflect: BoolProperty(
+        name="",
+        description="Causes the texture to affect the reflected light’s brightness",
+        default=False,
+    )
+
+    use_map_scatter: BoolProperty(
+        name="", description="Causes the texture to affect the volume’s scattering", default=False
+    )
+
+    use_map_specular: BoolProperty(
+        name="",
+        description="Causes the texture to affect the value of specular reflectivity",
+        default=False,
+    )
+
+    use_map_translucency: BoolProperty(
+        name="", description="Causes the texture to affect the translucency value", default=False
+    )
+
+    use_map_warp: BoolProperty(
+        name="",
+        description="Let the texture warp texture coordinates of next channels",
+        default=False,
+    )
+
+    uv_layer: StringProperty(
+        name="", description="UV layer to use for mapping with UV texture coordinates", default=""
+    )
+
+    warp_factor: FloatProperty(
+        name="",
+        description="Amount texture affects texture coordinates of next channels",
+        default=0.0,
+    )
+
+    #######################################
+
+    blend_factor: FloatProperty(
+        name="Blend",
+        description="Amount texture affects color progression of the " "background",
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+    )
+
+    horizon_factor: FloatProperty(
+        name="Horizon",
+        description="Amount texture affects color of the horizon" "",
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+    )
+
+    object: StringProperty(
+        name="Object",
+        description="Object to use for mapping with Object texture coordinates",
+        default="",
+    )
+
+    texture_coords: EnumProperty(
+        name="Coordinates",
+        description="Texture coordinates used to map the texture onto the background",
+        items=(
+            ("VIEW", "View", "Use view vector for the texture coordinates"),
+            (
+                "GLOBAL",
+                "Global",
+                "Use global coordinates for the texture coordinates (interior mist)",
+            ),
+            (
+                "ANGMAP",
+                "AngMap",
+                "Use 360 degree angular coordinates, e.g. for spherical light probes",
+            ),
+            ("SPHERE", "Sphere", "For 360 degree panorama sky, spherical mapped, only top half"),
+            ("EQUIRECT", "Equirectangular", "For 360 degree panorama sky, equirectangular mapping"),
+            ("TUBE", "Tube", "For 360 degree panorama sky, cylindrical mapped, only top half"),
+            ("OBJECT", "Object", "Use linked object’s coordinates for texture coordinates"),
+        ),
+        default="VIEW",
+    )
+
+    use_map_blend: BoolProperty(
+        name="Blend Map", description="Affect the color progression of the background", default=True
+    )
+
+    use_map_horizon: BoolProperty(
+        name="Horizon Map", description="Affect the color of the horizon", default=False
+    )
+
+    use_map_zenith_down: BoolProperty(
+        name="", description="Affect the color of the zenith below", default=False
+    )
+
+    use_map_zenith_up: BoolProperty(
+        name="Zenith Up Map", description="Affect the color of the zenith above", default=False
+    )
+
+    zenith_down_factor: FloatProperty(
+        name="Zenith Down",
+        description="Amount texture affects color of the zenith below",
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+    )
+
+    zenith_up_factor: FloatProperty(
+        name="Zenith Up",
+        description="Amount texture affects color of the zenith above",
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+    )
+
+
+###############################################################################
+# Texture slots (World context) exported as POV texture properties.
+###############################################################################
+class WorldTextureSlot(PropertyGroup):
+    """Declare world texture slot level properties for UI and translated to POV."""
+
+    bl_idname = ("pov_texture_slots",)
+    bl_description = ("Texture_slots from Blender-2.79",)
+
+    # Adding a "real" texture datablock as property is not possible
+    # (or at least not easy through a dynamically populated EnumProperty).
+    # That's why we'll use a prop_search() UILayout function in ui.py.
+    # So we'll assign the name of the needed texture datablock to the below StringProperty.
+    texture: StringProperty(update=active_texture_name_from_uilist)
+    # and use another temporary StringProperty to change the linked data
+    texture_search: StringProperty(
+        name="", update=active_texture_name_from_search, description="Browse Texture to be linked"
+    )
+
+    blend_factor: FloatProperty(
+        name="Blend",
+        description="Amount texture affects color progression of the " "background",
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+    )
+
+    horizon_factor: FloatProperty(
+        name="Horizon",
+        description="Amount texture affects color of the horizon",
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+    )
+
+    object: StringProperty(
+        name="Object",
+        description="Object to use for mapping with Object texture coordinates",
+        default="",
+    )
+
+    offset: FloatVectorProperty(
+        name="Offset",
+        description=("Fine tune of the texture mapping X, Y and Z locations "),
+        precision=4,
+        step=0.1,
+        soft_min=-100.0,
+        soft_max=100.0,
+        default=(0.0, 0.0, 0.0),
+        options={"ANIMATABLE"},
+        subtype="TRANSLATION",
+    )
+
+    scale: FloatVectorProperty(
+        name="Size",
+        subtype="XYZ",
+        size=3,
+        description="Set scaling for the texture’s X, Y and Z sizes ",
+        precision=4,
+        step=0.1,
+        soft_min=-100.0,
+        soft_max=100.0,
+        default=(1.0, 1.0, 1.0),
+        options={"ANIMATABLE"},
+    )
+
+    texture_coords: EnumProperty(
+        name="Coordinates",
+        description="Texture coordinates used to map the texture onto the background",
+        items=(
+            ("VIEW", "View", "Use view vector for the texture coordinates"),
+            (
+                "GLOBAL",
+                "Global",
+                "Use global coordinates for the texture coordinates (interior mist)",
+            ),
+            (
+                "ANGMAP",
+                "AngMap",
+                "Use 360 degree angular coordinates, e.g. for spherical light probes",
+            ),
+            ("SPHERE", "Sphere", "For 360 degree panorama sky, spherical mapped, only top half"),
+            ("EQUIRECT", "Equirectangular", "For 360 degree panorama sky, equirectangular mapping"),
+            ("TUBE", "Tube", "For 360 degree panorama sky, cylindrical mapped, only top half"),
+            ("OBJECT", "Object", "Use linked object’s coordinates for texture coordinates"),
+        ),
+        default="VIEW",
+    )
+
+    use_map_blend: BoolProperty(
+        name="Blend Map", description="Affect the color progression of the background", default=True
+    )
+
+    use_map_horizon: BoolProperty(
+        name="Horizon Map", description="Affect the color of the horizon", default=False
+    )
+
+    use_map_zenith_down: BoolProperty(
+        name="", description="Affect the color of the zenith below", default=False
+    )
+
+    use_map_zenith_up: BoolProperty(
+        name="Zenith Up Map", description="Affect the color of the zenith above", default=False
+    )
+
+    zenith_down_factor: FloatProperty(
+        name="Zenith Down",
+        description="Amount texture affects color of the zenith below",
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+    )
+
+    zenith_up_factor: FloatProperty(
+        name="Zenith Up",
+        description="Amount texture affects color of the zenith above",
+        soft_min=0.0,
+        soft_max=1.0,
+        default=1.0,
+    )
+
+
+###############################################################################
+# Space properties from  removed former Blender Internal
+###############################################################################
+
+# added below at superclass level so as to be available in World, Material,
+# and Light, for texture slots use
+
+bpy.types.ID.use_limited_texture_context = BoolProperty(
+    name="",
+    description="Use the limited version of texture user (for ‘old shading’ mode)",
+    default=True,
+)
+bpy.types.ID.texture_context = EnumProperty(
+    name="Texture context",
+    description="Type of texture data to display and edit",
+    items=(
+        ("MATERIAL", "", "Show material textures", "MATERIAL", 0),  # "Show material textures"
+        ("WORLD", "", "Show world textures", "WORLD", 1),  # "Show world textures"
+        ("LIGHT", "", "Show lamp textures", "LIGHT", 2),  # "Show lamp textures"
+        ("PARTICLES", "", "Show particles textures", "PARTICLES", 3),  # "Show particles textures"
+        ("LINESTYLE", "", "Show linestyle textures", "LINE_DATA", 4),  # "Show linestyle textures"
+        ("OTHER", "", "Show other data textures", "TEXTURE_DATA", 5),  # "Show other data textures"
+    ),
+    default="MATERIAL",
+)
+# bpy.types.ID.active_texture_index = IntProperty(
+# name = "Index for texture_slots",
+# default = 0,
+# )
+
+
+###############################################################################
+# Texture POV properties.
+###############################################################################
+
+
+class RenderPovSettingsTexture(PropertyGroup):
+    """Declare texture level properties controllable in UI and translated to POV."""
+
+    # former Space properties from removed Blender Internal
+    active_texture_index: IntProperty(name="Index for texture_slots", min=0, max=17, default=0)
+
+    use_limited_texture_context: BoolProperty(
+        name="",
+        description="Use the limited version of texture user (for ‘old shading’ mode)",
+        default=True,
+    )
+
+    texture_context: EnumProperty(
+        name="Texture context",
+        description="Type of texture data to display and edit",
+        items=(
+            ("MATERIAL", "", "Show material textures", "MATERIAL", 0),  # "Show material textures"
+            ("WORLD", "", "Show world textures", "WORLD", 1),  # "Show world textures"
+            ("LAMP", "", "Show lamp textures", "LIGHT", 2),  # "Show lamp textures"
+            (
+                "PARTICLES",
+                "",
+                "Show particles textures",
+                "PARTICLES",
+                3,
+            ),  # "Show particles textures"
+            (
+                "LINESTYLE",
+                "",
+                "Show linestyle textures",
+                "LINE_DATA",
+                4,
+            ),  # "Show linestyle textures"
+            (
+                "OTHER",
+                "",
+                "Show other data textures",
+                "TEXTURE_DATA",
+                5,
+            ),  # "Show other data textures"
+        ),
+        default="MATERIAL",
+    )
+
+    # Custom texture gamma
+    tex_gamma_enable: BoolProperty(
+        name="Enable custom texture gamma",
+        description="Notify some custom gamma for which texture has been precorrected "
+        "without the file format carrying it and only if it differs from your "
+        "OS expected standard (see pov doc)",
+        default=False,
+    )
+
+    tex_gamma_value: FloatProperty(
+        name="Custom texture gamma",
+        description="value for which the file was issued e.g. a Raw photo is gamma 1.0",
+        min=0.45,
+        max=5.00,
+        soft_min=1.00,
+        soft_max=2.50,
+        default=1.00,
+    )
+
+    ##################################CustomPOV Code############################
+    # commented out below if we wanted custom pov code in texture only, inside exported material:
+    # replacement_text = StringProperty(
+    #        name="Declared name:",
+    #        description="Type the declared name in custom POV code or an external .inc "
+    #                    "it points at. pigment {} expected",
+    #        default="")
+
+    tex_pattern_type: EnumProperty(
+        name="Texture_Type",
+        description="Choose between Blender or POV parameters to specify texture",
+        items=(
+            ("agate", "Agate", "", "PLUGIN", 0),
+            ("aoi", "Aoi", "", "PLUGIN", 1),
+            ("average", "Average", "", "PLUGIN", 2),
+            ("boxed", "Boxed", "", "PLUGIN", 3),
+            ("bozo", "Bozo", "", "PLUGIN", 4),
+            ("bumps", "Bumps", "", "PLUGIN", 5),
+            ("cells", "Cells", "", "PLUGIN", 6),
+            ("crackle", "Crackle", "", "PLUGIN", 7),
+            ("cubic", "Cubic", "", "PLUGIN", 8),
+            ("cylindrical", "Cylindrical", "", "PLUGIN", 9),
+            ("density_file", "Density", "(.df3)", "PLUGIN", 10),
+            ("dents", "Dents", "", "PLUGIN", 11),
+            ("fractal", "Fractal", "", "PLUGIN", 12),
+            ("function", "Function", "", "PLUGIN", 13),
+            ("gradient", "Gradient", "", "PLUGIN", 14),
+            ("granite", "Granite", "", "PLUGIN", 15),
+            ("image_pattern", "Image pattern", "", "PLUGIN", 16),
+            ("leopard", "Leopard", "", "PLUGIN", 17),
+            ("marble", "Marble", "", "PLUGIN", 18),
+            ("onion", "Onion", "", "PLUGIN", 19),
+            ("pigment_pattern", "pigment pattern", "", "PLUGIN", 20),
+            ("planar", "Planar", "", "PLUGIN", 21),
+            ("quilted", "Quilted", "", "PLUGIN", 22),
+            ("radial", "Radial", "", "PLUGIN", 23),
+            ("ripples", "Ripples", "", "PLUGIN", 24),
+            ("slope", "Slope", "", "PLUGIN", 25),
+            ("spherical", "Spherical", "", "PLUGIN", 26),
+            ("spiral1", "Spiral1", "", "PLUGIN", 27),
+            ("spiral2", "Spiral2", "", "PLUGIN", 28),
+            ("spotted", "Spotted", "", "PLUGIN", 29),
+            ("waves", "Waves", "", "PLUGIN", 30),
+            ("wood", "Wood", "", "PLUGIN", 31),
+            ("wrinkles", "Wrinkles", "", "PLUGIN", 32),
+            ("brick", "Brick", "", "PLUGIN", 33),
+            ("checker", "Checker", "", "PLUGIN", 34),
+            ("hexagon", "Hexagon", "", "PLUGIN", 35),
+            ("object", "Mesh", "", "PLUGIN", 36),
+            ("emulator", "Blender Type Emulator", "", "SCRIPTPLUGINS", 37),
+        ),
+        default="emulator",
+    )
+
+    magnet_style: EnumProperty(
+        name="Magnet style",
+        description="magnet or julia",
+        items=(("mandel", "Mandelbrot", ""), ("julia", "Julia", "")),
+        default="julia",
+    )
+
+    magnet_type: IntProperty(name="Magnet_type", description="1 or 2", min=1, max=2, default=2)
+
+    warp_types: EnumProperty(
+        name="Warp Types",
+        description="Select the type of warp",
+        items=(
+            ("PLANAR", "Planar", ""),
+            ("CUBIC", "Cubic", ""),
+            ("SPHERICAL", "Spherical", ""),
+            ("TOROIDAL", "Toroidal", ""),
+            ("CYLINDRICAL", "Cylindrical", ""),
+            ("NONE", "None", "No indentation"),
+        ),
+        default="NONE",
+    )
+
+    warp_orientation: EnumProperty(
+        name="Warp Orientation",
+        description="Select the orientation of warp",
+        items=(("x", "X", ""), ("y", "Y", ""), ("z", "Z", "")),
+        default="y",
+    )
+
+    wave_type: EnumProperty(
+        name="Waves type",
+        description="Select the type of waves",
+        items=(
+            ("ramp", "Ramp", ""),
+            ("sine", "Sine", ""),
+            ("scallop", "Scallop", ""),
+            ("cubic", "Cubic", ""),
+            ("poly", "Poly", ""),
+            ("triangle", "Triangle", ""),
+        ),
+        default="ramp",
+    )
+
+    gen_noise: IntProperty(
+        name="Noise Generators", description="Noise Generators", min=1, max=3, default=1
+    )
+
+    warp_dist_exp: FloatProperty(
+        name="Distance exponent", description="Distance exponent", min=0.0, max=100.0, default=1.0
+    )
+
+    warp_tor_major_radius: FloatProperty(
+        name="Major radius",
+        description="Torus is distance from major radius",
+        min=0.0,
+        max=5.0,
+        default=1.0,
+    )
+
+    warp_turbulence_x: FloatProperty(
+        name="Turbulence X", description="Turbulence X", min=0.0, max=5.0, default=0.0
+    )
+
+    warp_turbulence_y: FloatProperty(
+        name="Turbulence Y", description="Turbulence Y", min=0.0, max=5.0, default=0.0
+    )
+
+    warp_turbulence_z: FloatProperty(
+        name="Turbulence Z", description="Turbulence Z", min=0.0, max=5.0, default=0.0
+    )
+
+    modifier_octaves: IntProperty(
+        name="Turbulence octaves", description="Turbulence octaves", min=1, max=10, default=1
+    )
+
+    modifier_lambda: FloatProperty(
+        name="Turbulence lambda", description="Turbulence lambda", min=0.0, max=5.0, default=1.00
+    )
+
+    modifier_omega: FloatProperty(
+        name="Turbulence omega", description="Turbulence omega", min=0.0, max=10.0, default=1.00
+    )
+
+    modifier_phase: FloatProperty(
+        name="Phase",
+        description="The phase value causes the map entries to be shifted so that the map "
+        "starts and ends at a different place",
+        min=0.0,
+        max=2.0,
+        default=0.0,
+    )
+
+    modifier_frequency: FloatProperty(
+        name="Frequency",
+        description="The frequency keyword adjusts the number of times that a color map "
+        "repeats over one cycle of a pattern",
+        min=0.0,
+        max=25.0,
+        default=2.0,
+    )
+
+    modifier_turbulence: FloatProperty(
+        name="Turbulence", description="Turbulence", min=0.0, max=5.0, default=2.0
+    )
+
+    modifier_numbers: IntProperty(name="Numbers", description="Numbers", min=1, max=27, default=2)
+
+    modifier_control0: IntProperty(
+        name="Control0", description="Control0", min=0, max=100, default=1
+    )
+
+    modifier_control1: IntProperty(
+        name="Control1", description="Control1", min=0, max=100, default=1
+    )
+
+    brick_size_x: FloatProperty(
+        name="Brick size x", description="", min=0.0000, max=1.0000, default=0.2500
+    )
+
+    brick_size_y: FloatProperty(
+        name="Brick size y", description="", min=0.0000, max=1.0000, default=0.0525
+    )
+
+    brick_size_z: FloatProperty(
+        name="Brick size z", description="", min=0.0000, max=1.0000, default=0.1250
+    )
+
+    brick_mortar: FloatProperty(
+        name="Mortar", description="Mortar", min=0.000, max=1.500, default=0.01
+    )
+
+    julia_complex_1: FloatProperty(
+        name="Julia Complex 1", description="", min=0.000, max=1.500, default=0.360
+    )
+
+    julia_complex_2: FloatProperty(
+        name="Julia Complex 2", description="", min=0.000, max=1.500, default=0.250
+    )
+
+    f_iter: IntProperty(name="Fractal Iteration", description="", min=0, max=100, default=20)
+
+    f_exponent: IntProperty(name="Fractal Exponent", description="", min=2, max=33, default=2)
+
+    f_ior: IntProperty(name="Fractal Interior", description="", min=1, max=6, default=1)
+
+    f_ior_fac: FloatProperty(
+        name="Fractal Interior Factor", description="", min=0.0, max=10.0, default=1.0
+    )
+
+    f_eor: IntProperty(name="Fractal Exterior", description="", min=1, max=8, default=1)
+
+    f_eor_fac: FloatProperty(
+        name="Fractal Exterior Factor", description="", min=0.0, max=10.0, default=1.0
+    )
+
+    grad_orient_x: IntProperty(
+        name="Gradient orientation X", description="", min=0, max=1, default=0
+    )
+
+    grad_orient_y: IntProperty(
+        name="Gradient orientation Y", description="", min=0, max=1, default=1
+    )
+
+    grad_orient_z: IntProperty(
+        name="Gradient orientation Z", description="", min=0, max=1, default=0
+    )
+
+    pave_sides: EnumProperty(
+        name="Pavement sides",
+        description="",
+        items=(("3", "3", ""), ("4", "4", ""), ("6", "6", "")),
+        default="3",
+    )
+
+    pave_pat_2: IntProperty(
+        name="Pavement pattern 2", description="maximum: 2", min=1, max=2, default=2
+    )
+
+    pave_pat_3: IntProperty(
+        name="Pavement pattern 3", description="maximum: 3", min=1, max=3, default=3
+    )
+
+    pave_pat_4: IntProperty(
+        name="Pavement pattern 4", description="maximum: 4", min=1, max=4, default=4
+    )
+
+    pave_pat_5: IntProperty(
+        name="Pavement pattern 5", description="maximum: 5", min=1, max=5, default=5
+    )
+
+    pave_pat_7: IntProperty(
+        name="Pavement pattern 7", description="maximum: 7", min=1, max=7, default=7
+    )
+
+    pave_pat_12: IntProperty(
+        name="Pavement pattern 12", description="maximum: 12", min=1, max=12, default=12
+    )
+
+    pave_pat_22: IntProperty(
+        name="Pavement pattern 22", description="maximum: 22", min=1, max=22, default=22
+    )
+
+    pave_pat_35: IntProperty(
+        name="Pavement pattern 35", description="maximum: 35", min=1, max=35, default=35
+    )
+
+    pave_tiles: IntProperty(
+        name="Pavement tiles",
+        description="If sides = 6, maximum tiles 5!!!",
+        min=1,
+        max=6,
+        default=1,
+    )
+
+    pave_form: IntProperty(name="Pavement form", description="", min=0, max=4, default=0)
+
+    #########FUNCTIONS#############################################################################
+    #########FUNCTIONS#############################################################################
+
+    func_list: EnumProperty(
+        name="Functions",
+        description="Select the function for create pattern",
+        items=(
+            ("NONE", "None", "No indentation"),
+            ("f_algbr_cyl1", "Algbr cyl1", ""),
+            ("f_algbr_cyl2", "Algbr cyl2", ""),
+            ("f_algbr_cyl3", "Algbr cyl3", ""),
+            ("f_algbr_cyl4", "Algbr cyl4", ""),
+            ("f_bicorn", "Bicorn", ""),
+            ("f_bifolia", "Bifolia", ""),
+            ("f_blob", "Blob", ""),
+            ("f_blob2", "Blob2", ""),
+            ("f_boy_surface", "Boy surface", ""),
+            ("f_comma", "Comma", ""),
+            ("f_cross_ellipsoids", "Cross ellipsoids", ""),
+            ("f_crossed_trough", "Crossed trough", ""),
+            ("f_cubic_saddle", "Cubic saddle", ""),
+            ("f_cushion", "Cushion", ""),
+            ("f_devils_curve", "Devils curve", ""),
+            ("f_devils_curve_2d", "Devils curve 2d", ""),
+            ("f_dupin_cyclid", "Dupin cyclid", ""),
+            ("f_ellipsoid", "Ellipsoid", ""),
+            ("f_enneper", "Enneper", ""),
+            ("f_flange_cover", "Flange cover", ""),
+            ("f_folium_surface", "Folium surface", ""),
+            ("f_folium_surface_2d", "Folium surface 2d", ""),
+            ("f_glob", "Glob", ""),
+            ("f_heart", "Heart", ""),
+            ("f_helical_torus", "Helical torus", ""),
+            ("f_helix1", "Helix1", ""),
+            ("f_helix2", "Helix2", ""),
+            ("f_hex_x", "Hex x", ""),
+            ("f_hex_y", "Hex y", ""),
+            ("f_hetero_mf", "Hetero mf", ""),
+            ("f_hunt_surface", "Hunt surface", ""),
+            ("f_hyperbolic_torus", "Hyperbolic torus", ""),
+            ("f_isect_ellipsoids", "Isect ellipsoids", ""),
+            ("f_kampyle_of_eudoxus", "Kampyle of eudoxus", ""),
+            ("f_kampyle_of_eudoxus_2d", "Kampyle of eudoxus 2d", ""),
+            ("f_klein_bottle", "Klein bottle", ""),
+            ("f_kummer_surface_v1", "Kummer surface v1", ""),
+            ("f_kummer_surface_v2", "Kummer surface v2", ""),
+            ("f_lemniscate_of_gerono", "Lemniscate of gerono", ""),
+            ("f_lemniscate_of_gerono_2d", "Lemniscate of gerono 2d", ""),
+            ("f_mesh1", "Mesh1", ""),
+            ("f_mitre", "Mitre", ""),
+            ("f_nodal_cubic", "Nodal cubic", ""),
+            ("f_noise3d", "Noise3d", ""),
+            ("f_noise_generator", "Noise generator", ""),
+            ("f_odd", "Odd", ""),
+            ("f_ovals_of_cassini", "Ovals of cassini", ""),
+            ("f_paraboloid", "Paraboloid", ""),
+            ("f_parabolic_torus", "Parabolic torus", ""),
+            ("f_ph", "Ph", ""),
+            ("f_pillow", "Pillow", ""),
+            ("f_piriform", "Piriform", ""),
+            ("f_piriform_2d", "Piriform 2d", ""),
+            ("f_poly4", "Poly4", ""),
+            ("f_polytubes", "Polytubes", ""),
+            ("f_quantum", "Quantum", ""),
+            ("f_quartic_paraboloid", "Quartic paraboloid", ""),
+            ("f_quartic_saddle", "Quartic saddle", ""),
+            ("f_quartic_cylinder", "Quartic cylinder", ""),
+            ("f_r", "R", ""),
+            ("f_ridge", "Ridge", ""),
+            ("f_ridged_mf", "Ridged mf", ""),
+            ("f_rounded_box", "Rounded box", ""),
+            ("f_sphere", "Sphere", ""),
+            ("f_spikes", "Spikes", ""),
+            ("f_spikes_2d", "Spikes 2d", ""),
+            ("f_spiral", "Spiral", ""),
+            ("f_steiners_roman", "Steiners roman", ""),
+            ("f_strophoid", "Strophoid", ""),
+            ("f_strophoid_2d", "Strophoid 2d", ""),
+            ("f_superellipsoid", "Superellipsoid", ""),
+            ("f_th", "Th", ""),
+            ("f_torus", "Torus", ""),
+            ("f_torus2", "Torus2", ""),
+            ("f_torus_gumdrop", "Torus gumdrop", ""),
+            ("f_umbrella", "Umbrella", ""),
+            ("f_witch_of_agnesi", "Witch of agnesi", ""),
+            ("f_witch_of_agnesi_2d", "Witch of agnesi 2d", ""),
+        ),
+        default="NONE",
+    )
+
+    func_x: FloatProperty(name="FX", description="", min=0.0, max=25.0, default=1.0)
+
+    func_plus_x: EnumProperty(
+        name="Func plus x",
+        description="",
+        items=(("NONE", "None", ""), ("increase", "*", ""), ("plus", "+", "")),
+        default="NONE",
+    )
+
+    func_y: FloatProperty(name="FY", description="", min=0.0, max=25.0, default=1.0)
+
+    func_plus_y: EnumProperty(
+        name="Func plus y",
+        description="",
+        items=(("NONE", "None", ""), ("increase", "*", ""), ("plus", "+", "")),
+        default="NONE",
+    )
+
+    func_z: FloatProperty(name="FZ", description="", min=0.0, max=25.0, default=1.0)
+
+    func_plus_z: EnumProperty(
+        name="Func plus z",
+        description="",
+        items=(("NONE", "None", ""), ("increase", "*", ""), ("plus", "+", "")),
+        default="NONE",
+    )
+
+    func_P0: FloatProperty(name="P0", description="", min=0.0, max=25.0, default=1.0)
+
+    func_P1: FloatProperty(name="P1", description="", min=0.0, max=25.0, default=1.0)
+
+    func_P2: FloatProperty(name="P2", description="", min=0.0, max=25.0, default=1.0)
+
+    func_P3: FloatProperty(name="P3", description="", min=0.0, max=25.0, default=1.0)
+
+    func_P4: FloatProperty(name="P4", description="", min=0.0, max=25.0, default=1.0)
+
+    func_P5: FloatProperty(name="P5", description="", min=0.0, max=25.0, default=1.0)
+
+    func_P6: FloatProperty(name="P6", description="", min=0.0, max=25.0, default=1.0)
+
+    func_P7: FloatProperty(name="P7", description="", min=0.0, max=25.0, default=1.0)
+
+    func_P8: FloatProperty(name="P8", description="", min=0.0, max=25.0, default=1.0)
+
+    func_P9: FloatProperty(name="P9", description="", min=0.0, max=25.0, default=1.0)
+
+    #########################################
+    tex_rot_x: FloatProperty(name="Rotate X", description="", min=-180.0, max=180.0, default=0.0)
+
+    tex_rot_y: FloatProperty(name="Rotate Y", description="", min=-180.0, max=180.0, default=0.0)
+
+    tex_rot_z: FloatProperty(name="Rotate Z", description="", min=-180.0, max=180.0, default=0.0)
+
+    tex_mov_x: FloatProperty(
+        name="Move X", description="", min=-100000.0, max=100000.0, default=0.0
+    )
+
+    tex_mov_y: FloatProperty(
+        name="Move Y", description="", min=-100000.0, max=100000.0, default=0.0
+    )
+
+    tex_mov_z: FloatProperty(
+        name="Move Z", description="", min=-100000.0, max=100000.0, default=0.0
+    )
+
+    tex_scale_x: FloatProperty(name="Scale X", description="", min=0.0, max=10000.0, default=1.0)
+
+    tex_scale_y: FloatProperty(name="Scale Y", description="", min=0.0, max=10000.0, default=1.0)
+
+    tex_scale_z: FloatProperty(name="Scale Z", description="", min=0.0, max=10000.0, default=1.0)
+
+
+classes = (MaterialTextureSlot, WorldTextureSlot, RenderPovSettingsTexture)
+
+
+def register():
+    for cls in classes:
+        register_class(cls)
+
+    bpy.types.Material.pov_texture_slots = CollectionProperty(type=MaterialTextureSlot)
+    bpy.types.World.pov_texture_slots = CollectionProperty(type=WorldTextureSlot)
+    bpy.types.Texture.pov = PointerProperty(type=RenderPovSettingsTexture)
+
+
+def unregister():
+    del bpy.types.Texture.pov
+    del bpy.types.World.pov_texture_slots
+    del bpy.types.Material.pov_texture_slots
+
+    for cls in reversed(classes):
+        unregister_class(cls)
diff --git a/render_povray/ui.py b/render_povray/ui.py
deleted file mode 100644
index 297c2e0d8..000000000
--- a/render_povray/ui.py
+++ /dev/null
@@ -1,4719 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# <pep8 compliant>
-"""User interface for the POV tools"""
-
-import bpy
-import sys  # really import here and in render.py?
-import os  # really import here and in render.py?
-import addon_utils
-from time import sleep
-from os.path import isfile
-from bpy.app.handlers import persistent
-from bl_operators.presets import AddPresetBase
-from bpy.utils import register_class, unregister_class
-from bpy.types import (
-    Operator,
-    Menu,
-    UIList,
-    Panel,
-    Brush,
-    Material,
-    Light,
-    World,
-    ParticleSettings,
-    FreestyleLineStyle,
-)
-
-# Example of wrapping every class 'as is'
-from bl_ui import properties_output
-
-for member in dir(properties_output):
-    subclass = getattr(properties_output, member)
-    try:
-        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-    except:
-        pass
-del properties_output
-
-from bl_ui import properties_freestyle
-for member in dir(properties_freestyle):
-    subclass = getattr(properties_freestyle, member)
-    try:
-        if not (subclass.bl_space_type == 'PROPERTIES'
-            and subclass.bl_context == "render"):
-            subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-            #subclass.bl_parent_id = "RENDER_PT_POV_filter"
-    except:
-        pass
-del properties_freestyle
-
-from bl_ui import properties_view_layer
-
-for member in dir(properties_view_layer):
-    subclass = getattr(properties_view_layer, member)
-    try:
-        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-    except:
-        pass
-del properties_view_layer
-
-# Use some of the existing buttons.
-from bl_ui import properties_render
-
-# DEPRECATED#properties_render.RENDER_PT_render.COMPAT_ENGINES.add('POVRAY_RENDER')
-# DEPRECATED#properties_render.RENDER_PT_dimensions.COMPAT_ENGINES.add('POVRAY_RENDER')
-# properties_render.RENDER_PT_antialiasing.COMPAT_ENGINES.add('POVRAY_RENDER')
-# TORECREATE##DEPRECATED#properties_render.RENDER_PT_shading.COMPAT_ENGINES.add('POVRAY_RENDER')
-# DEPRECATED#properties_render.RENDER_PT_output.COMPAT_ENGINES.add('POVRAY_RENDER')
-del properties_render
-
-
-# Use only a subset of the world panels
-from bl_ui import properties_world
-
-# TORECREATE##DEPRECATED#properties_world.WORLD_PT_preview.COMPAT_ENGINES.add('POVRAY_RENDER')
-properties_world.WORLD_PT_context_world.COMPAT_ENGINES.add('POVRAY_RENDER')
-# TORECREATE##DEPRECATED#properties_world.WORLD_PT_world.COMPAT_ENGINES.add('POVRAY_RENDER')
-# TORECREATE##DEPRECATED#properties_world.WORLD_PT_mist.COMPAT_ENGINES.add('POVRAY_RENDER')
-del properties_world
-
-
-# Example of wrapping every class 'as is'
-from bl_ui import properties_texture
-from bl_ui.properties_texture import context_tex_datablock
-from bl_ui.properties_texture import texture_filter_common
-
-for member in dir(properties_texture):
-    subclass = getattr(properties_texture, member)
-    try:
-        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-    except:
-        pass
-del properties_texture
-
-# Physics Main wrapping every class 'as is'
-from bl_ui import properties_physics_common
-
-for member in dir(properties_physics_common):
-    subclass = getattr(properties_physics_common, member)
-    try:
-        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-    except:
-        pass
-del properties_physics_common
-
-# Physics Rigid Bodies wrapping every class 'as is'
-from bl_ui import properties_physics_rigidbody
-
-for member in dir(properties_physics_rigidbody):
-    subclass = getattr(properties_physics_rigidbody, member)
-    try:
-        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-    except:
-        pass
-del properties_physics_rigidbody
-
-# Physics Rigid Body Constraint wrapping every class 'as is'
-from bl_ui import properties_physics_rigidbody_constraint
-
-for member in dir(properties_physics_rigidbody_constraint):
-    subclass = getattr(properties_physics_rigidbody_constraint, member)
-    try:
-        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-    except:
-        pass
-del properties_physics_rigidbody_constraint
-
-# Physics Smoke wrapping every class 'as is'
-from bl_ui import properties_physics_fluid
-
-for member in dir(properties_physics_fluid):
-    subclass = getattr(properties_physics_fluid, member)
-    try:
-        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-    except:
-        pass
-del properties_physics_fluid
-
-# Physics softbody wrapping every class 'as is'
-from bl_ui import properties_physics_softbody
-
-for member in dir(properties_physics_softbody):
-    subclass = getattr(properties_physics_softbody, member)
-    try:
-        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-    except:
-        pass
-del properties_physics_softbody
-
-# Physics Fluid wrapping every class 'as is'
-from bl_ui import properties_physics_fluid
-
-for member in dir(properties_physics_fluid):
-    subclass = getattr(properties_physics_fluid, member)
-    try:
-        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-    except:
-        pass
-del properties_physics_fluid
-
-# Physics Field wrapping every class 'as is'
-from bl_ui import properties_physics_field
-
-for member in dir(properties_physics_field):
-    subclass = getattr(properties_physics_field, member)
-    try:
-        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-    except:
-        pass
-del properties_physics_field
-
-# Physics Cloth wrapping every class 'as is'
-from bl_ui import properties_physics_cloth
-
-for member in dir(properties_physics_cloth):
-    subclass = getattr(properties_physics_cloth, member)
-    try:
-        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-    except:
-        pass
-del properties_physics_cloth
-
-# Physics Dynamic Paint wrapping every class 'as is'
-from bl_ui import properties_physics_dynamicpaint
-
-for member in dir(properties_physics_dynamicpaint):
-    subclass = getattr(properties_physics_dynamicpaint, member)
-    try:
-        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-    except:
-        pass
-del properties_physics_dynamicpaint
-
-
-# Example of wrapping every class 'as is'
-from bl_ui import properties_data_modifier
-
-for member in dir(properties_data_modifier):
-    subclass = getattr(properties_data_modifier, member)
-    try:
-        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-    except:
-        pass
-del properties_data_modifier
-
-# Example of wrapping every class 'as is' except some
-from bl_ui import properties_material
-
-for member in dir(properties_material):
-    subclass = getattr(properties_material, member)
-    try:
-        # mat=bpy.context.active_object.active_material
-        # if (mat and mat.pov.type == "SURFACE"
-        # and not (mat.pov.material_use_nodes or mat.use_nodes)):
-        # and (engine in cls.COMPAT_ENGINES)) if subclasses were sorted
-        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-    except:
-        pass
-del properties_material
-
-
-from bl_ui import properties_data_camera
-
-for member in dir(properties_data_camera):
-    subclass = getattr(properties_data_camera, member)
-    try:
-        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-    except:
-        pass
-del properties_data_camera
-
-
-from bl_ui import properties_particle as properties_particle
-
-for member in dir(
-    properties_particle
-):  # add all "particle" panels from blender
-    subclass = getattr(properties_particle, member)
-    try:
-        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-    except:
-        pass
-del properties_particle
-
-
-############# POV-Centric WORSPACE #############
-@persistent
-def povCentricWorkspace(dummy):
-    """Set up a POV centric Workspace if addon was activated and saved as default renderer
-
-    This would bring a ’_RestrictData’ error because UI needs to be fully loaded before
-    workspace changes so registering this function in bpy.app.handlers is needed.
-    By default handlers are freed when loading new files, but here we want the handler
-    to stay running across multiple files as part of this add-on. That is why the the
-    bpy.app.handlers.persistent decorator is used (@persistent) above.
-    """
-
-    wsp = bpy.data.workspaces.get('Scripting')
-    context = bpy.context
-    if wsp is not None and context.scene.render.engine == 'POVRAY_RENDER':
-        new_wsp = bpy.ops.workspace.duplicate({'workspace': wsp})
-        bpy.data.workspaces['Scripting.001'].name='POV'
-        # Already done it would seem, but explicitly make this workspaces the active one
-        context.window.workspace = bpy.data.workspaces['POV']
-        pov_screen = bpy.data.workspaces['POV'].screens[0]
-        pov_workspace = pov_screen.areas
-
-
-        override = bpy.context.copy()
-
-        for area in pov_workspace:
-            if area.type == 'VIEW_3D':
-                for region in [r for r in area.regions if r.type == 'WINDOW']:
-                    for space in area.spaces:
-                        if space.type == 'VIEW_3D':
-                            #override['screen'] = pov_screen
-                            override['area'] = area
-                            override['region']= region
-                            #bpy.data.workspaces['POV'].screens[0].areas[6].spaces[0].width = 333 # Read only, how do we set ?
-                            #This has a glitch:
-                            #bpy.ops.screen.area_move(override, x=(area.x + area.width), y=(area.y + 5), delta=100)
-                            #bpy.ops.screen.area_move(override, x=(area.x + 5), y=area.y, delta=-100)
-
-                            bpy.ops.screen.space_type_set_or_cycle(override, space_type = 'TEXT_EDITOR')
-                            space.show_region_ui = True
-                            #bpy.ops.screen.region_scale(override)
-                            #bpy.ops.screen.region_scale()
-                            break
-
-            elif area.type == 'CONSOLE':
-                for region in [r for r in area.regions if r.type == 'WINDOW']:
-                    for space in area.spaces:
-                        if space.type == 'CONSOLE':
-                            #override['screen'] = pov_screen
-                            override['area'] = area
-                            override['region']= region
-                            bpy.ops.screen.space_type_set_or_cycle(override, space_type = 'INFO')
-
-                            break
-            elif area.type == 'INFO':
-                for region in [r for r in area.regions if r.type == 'WINDOW']:
-                    for space in area.spaces:
-                        if space.type == 'INFO':
-                            #override['screen'] = pov_screen
-                            override['area'] = area
-                            override['region']= region
-                            bpy.ops.screen.space_type_set_or_cycle(override, space_type = 'CONSOLE')
-
-                            break
-
-            elif area.type == 'TEXT_EDITOR':
-                for region in [r for r in area.regions if r.type == 'WINDOW']:
-                    for space in area.spaces:
-                        if space.type == 'TEXT_EDITOR':
-                            #override['screen'] = pov_screen
-                            override['area'] = area
-                            override['region']= region
-                            #bpy.ops.screen.space_type_set_or_cycle(space_type='VIEW_3D')
-                            #space.type = 'VIEW_3D'
-                            bpy.ops.screen.space_type_set_or_cycle(override, space_type = 'VIEW_3D')
-
-                            #bpy.ops.screen.area_join(override, cursor=(area.x, area.y + area.height))
-
-                            break
-
-
-            if area.type == 'VIEW_3D':
-                for region in [r for r in area.regions if r.type == 'WINDOW']:
-                    for space in area.spaces:
-                        if space.type == 'VIEW_3D':
-                            #override['screen'] = pov_screen
-                            override['area'] = area
-                            override['region']= region
-                            bpy.ops.screen.region_quadview(override)
-                            space.region_3d.view_perspective = 'CAMERA'
-                            #bpy.ops.screen.space_type_set_or_cycle(override, space_type = 'TEXT_EDITOR')
-                            #bpy.ops.screen.region_quadview(override)
-
-
-
-
-
-
-        bpy.data.workspaces.update()
-        # Already outliners but invert both types
-        pov_workspace[1].spaces[0].display_mode = 'LIBRARIES'
-        pov_workspace[3].spaces[0].display_mode = 'VIEW_LAYER'
-
-        '''
-        for window in bpy.context.window_manager.windows:
-            for area in [a for a in window.screen.areas if a.type == 'VIEW_3D']:
-                for region in [r for r in area.regions if r.type == 'WINDOW']:
-                    context_override = {
-                        'window': window,
-                        'screen': window.screen,
-                        'area': area,
-                        'region': region,
-                        'space_data': area.spaces.active,
-                        'scene': bpy.context.scene
-                        }
-                    bpy.ops.view3d.camera_to_view(context_override)
-        '''
-
-
-    else:
-        print("default 'Scripting' workspace needed for POV centric Workspace")
-
-
-
-
-
-
-
-class WORLD_MT_POV_presets(Menu):
-    bl_label = "World Presets"
-    preset_subdir = "pov/world"
-    preset_operator = "script.execute_preset"
-    draw = bpy.types.Menu.draw_preset
-
-
-class WORLD_OT_POV_add_preset(AddPresetBase, Operator):
-    """Add a World Preset"""
-
-    bl_idname = "object.world_preset_add"
-    bl_label = "Add World Preset"
-    preset_menu = "WORLD_MT_POV_presets"
-
-    # variable used for all preset values
-    preset_defines = ["scene = bpy.context.scene"]
-
-    # properties to store in the preset
-    preset_values = [
-        "scene.world.use_sky_blend",
-        "scene.world.horizon_color",
-        "scene.world.zenith_color",
-        "scene.world.ambient_color",
-        "scene.world.mist_settings.use_mist",
-        "scene.world.mist_settings.intensity",
-        "scene.world.mist_settings.depth",
-        "scene.world.mist_settings.start",
-        "scene.pov.media_enable",
-        "scene.pov.media_scattering_type",
-        "scene.pov.media_samples",
-        "scene.pov.media_diffusion_scale",
-        "scene.pov.media_diffusion_color",
-        "scene.pov.media_absorption_scale",
-        "scene.pov.media_absorption_color",
-        "scene.pov.media_eccentricity",
-    ]
-
-    # where to store the preset
-    preset_subdir = "pov/world"
-
-
-def check_material(mat):
-    if mat is not None:
-        if mat.use_nodes:
-            if (
-                not mat.node_tree
-            ):  # FORMERLY : #mat.active_node_material is not None:
-                return True
-            return False
-        return True
-    return False
-
-
-def simple_material(mat):
-    """Test if a material uses nodes"""
-    if (mat is not None) and (not mat.use_nodes):
-        return True
-    return False
-
-
-def check_add_mesh_extra_objects():
-    """Test if Add mesh extra objects addon is activated
-
-    This addon is currently used to generate the proxy for POV parametric
-    surface which is almost the same priciple as its Math xyz surface
-    """
-    if "add_mesh_extra_objects" in bpy.context.preferences.addons.keys():
-        return True
-    return False
-
-def check_render_freestyle_svg():
-    """Test if Freestyle SVG Exporter addon is activated
-
-    This addon is currently used to generate the SVG lines file
-    when Freestyle is enabled alongside POV
-    """
-    if "render_freestyle_svg" in bpy.context.preferences.addons.keys():
-        return True
-    return False
-
-def locate_docpath():
-    """POV can be installed with some include files.
-
-    Get their path as defined in user preferences or registry keys for
-    the user to be able to invoke them."""
-
-    addon_prefs = bpy.context.preferences.addons[__package__].preferences
-    # Use the system preference if its set.
-    pov_documents = addon_prefs.docpath_povray
-    if pov_documents:
-        if os.path.exists(pov_documents):
-            return pov_documents
-        else:
-            print(
-                "User Preferences path to povray documents %r NOT FOUND, checking $PATH"
-                % pov_documents
-            )
-
-    # Windows Only
-    if sys.platform[:3] == "win":
-        import winreg
-
-        try:
-            win_reg_key = winreg.OpenKey(
-                winreg.HKEY_CURRENT_USER, "Software\\POV-Ray\\v3.7\\Windows"
-            )
-            win_docpath = winreg.QueryValueEx(win_reg_key, "DocPath")[0]
-            pov_documents = os.path.join(win_docpath, "Insert Menu")
-            if os.path.exists(pov_documents):
-                return pov_documents
-        except FileNotFoundError:
-            return ""
-    # search the path all os's
-    pov_documents_default = "include"
-
-    os_path_ls = os.getenv("PATH").split(':') + [""]
-
-    for dir_name in os_path_ls:
-        pov_documents = os.path.join(dir_name, pov_documents_default)
-        if os.path.exists(pov_documents):
-            return pov_documents
-    return ""
-
-
-def pov_context_tex_datablock(context):
-    """Texture context type recreated as deprecated in blender 2.8"""
-
-    idblock = context.brush
-    if idblock and context.scene.texture_context == 'OTHER':
-        return idblock
-
-    # idblock = bpy.context.active_object.active_material
-    idblock = context.view_layer.objects.active.active_material
-    if idblock and context.scene.texture_context == 'MATERIAL':
-        return idblock
-
-    idblock = context.scene.world
-    if idblock and context.scene.texture_context == 'WORLD':
-        return idblock
-
-    idblock = context.light
-    if idblock and context.scene.texture_context == 'LIGHT':
-        return idblock
-
-    if context.particle_system and context.scene.texture_context == 'PARTICLES':
-        idblock = context.particle_system.settings
-
-    return idblock
-
-    idblock = context.line_style
-    if idblock and context.scene.texture_context == 'LINESTYLE':
-        return idblock
-
-
-class RenderButtonsPanel:
-    """Use this class to define buttons from the render tab of
-    properties window."""
-
-    bl_space_type = 'PROPERTIES'
-    bl_region_type = 'WINDOW'
-    bl_context = "render"
-    # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
-
-    @classmethod
-    def poll(cls, context):
-        rd = context.scene.render
-        return rd.engine in cls.COMPAT_ENGINES
-
-
-class ModifierButtonsPanel:
-    """Use this class to define buttons from the modifier tab of
-    properties window."""
-
-    bl_space_type = 'PROPERTIES'
-    bl_region_type = 'WINDOW'
-    bl_context = "modifier"
-    # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
-
-    @classmethod
-    def poll(cls, context):
-        mods = context.object.modifiers
-        rd = context.scene.render
-        return mods and (rd.engine in cls.COMPAT_ENGINES)
-
-
-class MaterialButtonsPanel:
-    """Use this class to define buttons from the material tab of
-    properties window."""
-
-    bl_space_type = 'PROPERTIES'
-    bl_region_type = 'WINDOW'
-    bl_context = "material"
-    # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
-
-    @classmethod
-    def poll(cls, context):
-        mat = context.material
-        rd = context.scene.render
-        return mat and (rd.engine in cls.COMPAT_ENGINES)
-
-
-class TextureButtonsPanel:
-    """Use this class to define buttons from the texture tab of
-    properties window."""
-
-    bl_space_type = 'PROPERTIES'
-    bl_region_type = 'WINDOW'
-    bl_context = "texture"
-    # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
-
-    @classmethod
-    def poll(cls, context):
-        tex = context.texture
-        rd = context.scene.render
-        return tex and (rd.engine in cls.COMPAT_ENGINES)
-
-
-# class TextureTypePanel(TextureButtonsPanel):
-
-# @classmethod
-# def poll(cls, context):
-# tex = context.texture
-# engine = context.scene.render.engine
-# return tex and ((tex.type == cls.tex_type and not tex.use_nodes) and (engine in cls.COMPAT_ENGINES))
-
-
-class ObjectButtonsPanel:
-    """Use this class to define buttons from the object tab of
-    properties window."""
-
-    bl_space_type = 'PROPERTIES'
-    bl_region_type = 'WINDOW'
-    bl_context = "object"
-    # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
-
-    @classmethod
-    def poll(cls, context):
-        obj = context.object
-        rd = context.scene.render
-        return obj and (rd.engine in cls.COMPAT_ENGINES)
-
-
-class CameraDataButtonsPanel:
-    """Use this class to define buttons from the camera data tab of
-    properties window."""
-
-    bl_space_type = 'PROPERTIES'
-    bl_region_type = 'WINDOW'
-    bl_context = "data"
-    # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
-
-    @classmethod
-    def poll(cls, context):
-        cam = context.camera
-        rd = context.scene.render
-        return cam and (rd.engine in cls.COMPAT_ENGINES)
-
-
-class WorldButtonsPanel:
-    """Use this class to define buttons from the world tab of
-    properties window."""
-
-    bl_space_type = 'PROPERTIES'
-    bl_region_type = 'WINDOW'
-    bl_context = "world"
-    # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
-
-    @classmethod
-    def poll(cls, context):
-        wld = context.world
-        rd = context.scene.render
-        return wld and (rd.engine in cls.COMPAT_ENGINES)
-
-
-class TextButtonsPanel:
-    """Use this class to define buttons from the side tab of
-    text window."""
-
-    bl_space_type = 'TEXT_EDITOR'
-    bl_region_type = 'UI'
-    bl_label = "POV-Ray"
-    # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
-
-    @classmethod
-    def poll(cls, context):
-        text = context.space_data
-        rd = context.scene.render
-        return text and (rd.engine in cls.COMPAT_ENGINES)
-
-
-from bl_ui import properties_data_mesh
-
-# These panels are kept
-properties_data_mesh.DATA_PT_custom_props_mesh.COMPAT_ENGINES.add(
-    'POVRAY_RENDER'
-)
-properties_data_mesh.DATA_PT_context_mesh.COMPAT_ENGINES.add('POVRAY_RENDER')
-
-## make some native panels contextual to some object variable
-## by recreating custom panels inheriting their properties
-
-
-class PovDataButtonsPanel(properties_data_mesh.MeshButtonsPanel):
-    """Use this class to define buttons from the edit data tab of
-    properties window."""
-
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-    POV_OBJECT_TYPES = {
-        'PLANE',
-        'BOX',
-        'SPHERE',
-        'CYLINDER',
-        'CONE',
-        'TORUS',
-        'BLOB',
-        'ISOSURFACE',
-        'SUPERELLIPSOID',
-        'SUPERTORUS',
-        'HEIGHT_FIELD',
-        'PARAMETRIC',
-        'POLYCIRCLE',
-    }
-
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        obj = context.object
-        # We use our parent class poll func too, avoids to re-define too much things...
-        return (
-            super(PovDataButtonsPanel, cls).poll(context)
-            and obj
-            and obj.pov.object_as not in cls.POV_OBJECT_TYPES
-        )
-
-
-# We cannot inherit from RNA classes (like e.g. properties_data_mesh.DATA_PT_vertex_groups).
-# Complex py/bpy/rna interactions (with metaclass and all) simply do not allow it to work.
-# So we simply have to explicitly copy here the interesting bits. ;)
-class DATA_PT_POV_normals(PovDataButtonsPanel, Panel):
-    bl_label = properties_data_mesh.DATA_PT_normals.bl_label
-
-    draw = properties_data_mesh.DATA_PT_normals.draw
-
-
-class DATA_PT_POV_texture_space(PovDataButtonsPanel, Panel):
-    bl_label = properties_data_mesh.DATA_PT_texture_space.bl_label
-    bl_options = properties_data_mesh.DATA_PT_texture_space.bl_options
-
-    draw = properties_data_mesh.DATA_PT_texture_space.draw
-
-
-class DATA_PT_POV_vertex_groups(PovDataButtonsPanel, Panel):
-    bl_label = properties_data_mesh.DATA_PT_vertex_groups.bl_label
-
-    draw = properties_data_mesh.DATA_PT_vertex_groups.draw
-
-
-class DATA_PT_POV_shape_keys(PovDataButtonsPanel, Panel):
-    bl_label = properties_data_mesh.DATA_PT_shape_keys.bl_label
-
-    draw = properties_data_mesh.DATA_PT_shape_keys.draw
-
-
-class DATA_PT_POV_uv_texture(PovDataButtonsPanel, Panel):
-    bl_label = properties_data_mesh.DATA_PT_uv_texture.bl_label
-
-    draw = properties_data_mesh.DATA_PT_uv_texture.draw
-
-
-class DATA_PT_POV_vertex_colors(PovDataButtonsPanel, Panel):
-    bl_label = properties_data_mesh.DATA_PT_vertex_colors.bl_label
-
-    draw = properties_data_mesh.DATA_PT_vertex_colors.draw
-
-
-class DATA_PT_POV_customdata(PovDataButtonsPanel, Panel):
-    bl_label = properties_data_mesh.DATA_PT_customdata.bl_label
-    bl_options = properties_data_mesh.DATA_PT_customdata.bl_options
-    draw = properties_data_mesh.DATA_PT_customdata.draw
-
-
-del properties_data_mesh
-
-
-################################################################################
-# from bl_ui import properties_data_light
-# for member in dir(properties_data_light):
-# subclass = getattr(properties_data_light, member)
-# try:
-# subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-# except:
-# pass
-# del properties_data_light
-#########################LIGHTS################################
-
-from bl_ui import properties_data_light
-
-# These panels are kept
-properties_data_light.DATA_PT_custom_props_light.COMPAT_ENGINES.add(
-    'POVRAY_RENDER'
-)
-properties_data_light.DATA_PT_context_light.COMPAT_ENGINES.add('POVRAY_RENDER')
-
-## make some native panels contextual to some object variable
-## by recreating custom panels inheriting their properties
-class PovLampButtonsPanel(properties_data_light.DataButtonsPanel):
-    """Use this class to define buttons from the light data tab of
-    properties window."""
-
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-    POV_OBJECT_TYPES = {'RAINBOW'}
-
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        obj = context.object
-        # We use our parent class poll func too, avoids to re-define too much things...
-        return (
-            super(PovLampButtonsPanel, cls).poll(context)
-            and obj
-            and obj.pov.object_as not in cls.POV_OBJECT_TYPES
-        )
-
-
-# We cannot inherit from RNA classes (like e.g. properties_data_mesh.DATA_PT_vertex_groups).
-# Complex py/bpy/rna interactions (with metaclass and all) simply do not allow it to work.
-# So we simply have to explicitly copy here the interesting bits. ;)
-
-
-class LIGHT_PT_POV_preview(PovLampButtonsPanel, Panel):
-    bl_label = properties_data_light.DATA_PT_preview.bl_label
-
-    draw = properties_data_light.DATA_PT_preview.draw
-
-
-class LIGHT_PT_POV_light(PovLampButtonsPanel, Panel):
-    bl_label = properties_data_light.DATA_PT_light.bl_label
-
-    draw = properties_data_light.DATA_PT_light.draw
-
-
-class LIGHT_MT_POV_presets(Menu):
-    """Use this class to define preset menu for pov lights."""
-
-    bl_label = "Lamp Presets"
-    preset_subdir = "pov/light"
-    preset_operator = "script.execute_preset"
-    draw = bpy.types.Menu.draw_preset
-
-
-class LIGHT_OT_POV_add_preset(AddPresetBase, Operator):
-    """Use this class to define pov world buttons"""
-
-    '''Add a Light Preset'''
-    bl_idname = "object.light_preset_add"
-    bl_label = "Add Light Preset"
-    preset_menu = "LIGHT_MT_POV_presets"
-
-    # variable used for all preset values
-    preset_defines = ["lightdata = bpy.context.object.data"]
-
-    # properties to store in the preset
-    preset_values = ["lightdata.type", "lightdata.color"]
-
-    # where to store the preset
-    preset_subdir = "pov/light"
-
-
-# Draw into the existing light panel
-def light_panel_func(self, context):
-    layout = self.layout
-
-    row = layout.row(align=True)
-    row.menu(LIGHT_MT_POV_presets.__name__, text=LIGHT_MT_POV_presets.bl_label)
-    row.operator(LIGHT_OT_POV_add_preset.bl_idname, text="", icon='ADD')
-    row.operator(
-        LIGHT_OT_POV_add_preset.bl_idname, text="", icon='REMOVE'
-    ).remove_active = True
-
-
-'''#TORECREATE##DEPRECATED#
-class LIGHT_PT_POV_sunsky(PovLampButtonsPanel, Panel):
-    bl_label = properties_data_light.DATA_PT_sunsky.bl_label
-
-    @classmethod
-    def poll(cls, context):
-        lamp = context.light
-        engine = context.scene.render.engine
-        return (lamp and lamp.type == 'SUN') and (engine in cls.COMPAT_ENGINES)
-
-    draw = properties_data_light.DATA_PT_sunsky.draw
-
-'''
-
-
-class LIGHT_PT_POV_shadow(PovLampButtonsPanel, Panel):
-    bl_label = "Shadow"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    @classmethod
-    def poll(cls, context):
-        lamp = context.lamp
-        engine = context.scene.render.engine
-        return lamp and (engine in cls.COMPAT_ENGINES)
-
-    def draw(self, context):
-        layout = self.layout
-
-        lamp = context.lamp
-
-        layout.row().prop(lamp, "shadow_method", expand=True)
-
-        split = layout.split()
-
-        col = split.column()
-        sub = col.column()
-        sub.prop(lamp, "spot_size", text="Size")
-        sub.prop(lamp, "spot_blend", text="Blend", slider=True)
-        col.prop(lamp, "use_square")
-        col.prop(lamp, "show_cone")
-
-        col = split.column()
-
-        col.active = (
-            lamp.shadow_method != 'BUFFER_SHADOW'
-            or lamp.shadow_buffer_type != 'DEEP'
-        )
-        col.prop(lamp, "use_halo")
-        sub = col.column(align=True)
-        sub.active = lamp.use_halo
-        sub.prop(lamp, "halo_intensity", text="Intensity")
-        if lamp.shadow_method == 'BUFFER_SHADOW':
-            sub.prop(lamp, "halo_step", text="Step")
-        if lamp.shadow_method == 'NOSHADOW' and lamp.type == 'AREA':
-            split = layout.split()
-
-            col = split.column()
-            col.label(text="Form factor sampling:")
-
-            sub = col.row(align=True)
-
-            if lamp.shape == 'SQUARE':
-                sub.prop(lamp, "shadow_ray_samples_x", text="Samples")
-            elif lamp.shape == 'RECTANGLE':
-                sub.prop(lamp.pov, "shadow_ray_samples_x", text="Samples X")
-                sub.prop(lamp.pov, "shadow_ray_samples_y", text="Samples Y")
-
-        if lamp.shadow_method != 'NOSHADOW':
-            split = layout.split()
-
-            col = split.column()
-            col.prop(lamp, "shadow_color", text="")
-
-            col = split.column()
-            col.prop(lamp, "use_shadow_layer", text="This Layer Only")
-            col.prop(lamp, "use_only_shadow")
-
-        if lamp.shadow_method == 'RAY_SHADOW':
-            split = layout.split()
-
-            col = split.column()
-            col.label(text="Sampling:")
-
-            if lamp.type in {'POINT', 'SUN', 'SPOT'}:
-                sub = col.row()
-
-                sub.prop(lamp, "shadow_ray_samples", text="Samples")
-                sub.prop(lamp, "shadow_soft_size", text="Soft Size")
-
-            elif lamp.type == 'AREA':
-                sub = col.row(align=True)
-
-                if lamp.shape == 'SQUARE':
-                    sub.prop(lamp, "shadow_ray_samples_x", text="Samples")
-                elif lamp.shape == 'RECTANGLE':
-                    sub.prop(lamp, "shadow_ray_samples_x", text="Samples X")
-                    sub.prop(lamp, "shadow_ray_samples_y", text="Samples Y")
-
-
-'''
-        if lamp.shadow_method == 'NOSHADOW' and lamp.type == 'AREA':
-            split = layout.split()
-
-            col = split.column()
-            col.label(text="Form factor sampling:")
-
-            sub = col.row(align=True)
-
-            if lamp.shape == 'SQUARE':
-                sub.prop(lamp, "shadow_ray_samples_x", text="Samples")
-            elif lamp.shape == 'RECTANGLE':
-                sub.prop(lamp, "shadow_ray_samples_x", text="Samples X")
-                sub.prop(lamp, "shadow_ray_samples_y", text="Samples Y")
-
-        if lamp.shadow_method != 'NOSHADOW':
-            split = layout.split()
-
-            col = split.column()
-            col.prop(lamp, "shadow_color", text="")
-
-            col = split.column()
-            col.prop(lamp, "use_shadow_layer", text="This Layer Only")
-            col.prop(lamp, "use_only_shadow")
-
-        if lamp.shadow_method == 'RAY_SHADOW':
-            split = layout.split()
-
-            col = split.column()
-            col.label(text="Sampling:")
-
-            if lamp.type in {'POINT', 'SUN', 'SPOT'}:
-                sub = col.row()
-
-                sub.prop(lamp, "shadow_ray_samples", text="Samples")
-                sub.prop(lamp, "shadow_soft_size", text="Soft Size")
-
-            elif lamp.type == 'AREA':
-                sub = col.row(align=True)
-
-                if lamp.shape == 'SQUARE':
-                    sub.prop(lamp, "shadow_ray_samples_x", text="Samples")
-                elif lamp.shape == 'RECTANGLE':
-                    sub.prop(lamp, "shadow_ray_samples_x", text="Samples X")
-                    sub.prop(lamp, "shadow_ray_samples_y", text="Samples Y")
-
-            col.row().prop(lamp, "shadow_ray_sample_method", expand=True)
-
-            if lamp.shadow_ray_sample_method == 'ADAPTIVE_QMC':
-                layout.prop(lamp, "shadow_adaptive_threshold", text="Threshold")
-
-            if lamp.type == 'AREA' and lamp.shadow_ray_sample_method == 'CONSTANT_JITTERED':
-                row = layout.row()
-                row.prop(lamp, "use_umbra")
-                row.prop(lamp, "use_dither")
-                row.prop(lamp, "use_jitter")
-
-        elif lamp.shadow_method == 'BUFFER_SHADOW':
-            col = layout.column()
-            col.label(text="Buffer Type:")
-            col.row().prop(lamp, "shadow_buffer_type", expand=True)
-
-            if lamp.shadow_buffer_type in {'REGULAR', 'HALFWAY', 'DEEP'}:
-                split = layout.split()
-
-                col = split.column()
-                col.label(text="Filter Type:")
-                col.prop(lamp, "shadow_filter_type", text="")
-                sub = col.column(align=True)
-                sub.prop(lamp, "shadow_buffer_soft", text="Soft")
-                sub.prop(lamp, "shadow_buffer_bias", text="Bias")
-
-                col = split.column()
-                col.label(text="Sample Buffers:")
-                col.prop(lamp, "shadow_sample_buffers", text="")
-                sub = col.column(align=True)
-                sub.prop(lamp, "shadow_buffer_size", text="Size")
-                sub.prop(lamp, "shadow_buffer_samples", text="Samples")
-                if lamp.shadow_buffer_type == 'DEEP':
-                    col.prop(lamp, "compression_threshold")
-
-            elif lamp.shadow_buffer_type == 'IRREGULAR':
-                layout.prop(lamp, "shadow_buffer_bias", text="Bias")
-
-            split = layout.split()
-
-            col = split.column()
-            col.prop(lamp, "use_auto_clip_start", text="Autoclip Start")
-            sub = col.column()
-            sub.active = not lamp.use_auto_clip_start
-            sub.prop(lamp, "shadow_buffer_clip_start", text="Clip Start")
-
-            col = split.column()
-            col.prop(lamp, "use_auto_clip_end", text="Autoclip End")
-            sub = col.column()
-            sub.active = not lamp.use_auto_clip_end
-            sub.prop(lamp, "shadow_buffer_clip_end", text=" Clip End")
-'''
-
-
-class LIGHT_PT_POV_area(PovLampButtonsPanel, Panel):
-    bl_label = properties_data_light.DATA_PT_area.bl_label
-
-    @classmethod
-    def poll(cls, context):
-        lamp = context.light
-        engine = context.scene.render.engine
-        return (lamp and lamp.type == 'AREA') and (engine in cls.COMPAT_ENGINES)
-
-    draw = properties_data_light.DATA_PT_area.draw
-
-
-class LIGHT_PT_POV_spot(PovLampButtonsPanel, Panel):
-    bl_label = properties_data_light.DATA_PT_spot.bl_label
-
-    @classmethod
-    def poll(cls, context):
-        lamp = context.light
-        engine = context.scene.render.engine
-        return (lamp and lamp.type == 'SPOT') and (engine in cls.COMPAT_ENGINES)
-
-    draw = properties_data_light.DATA_PT_spot.draw
-
-
-class LIGHT_PT_POV_falloff_curve(PovLampButtonsPanel, Panel):
-    bl_label = properties_data_light.DATA_PT_falloff_curve.bl_label
-    bl_options = properties_data_light.DATA_PT_falloff_curve.bl_options
-
-    @classmethod
-    def poll(cls, context):
-        lamp = context.light
-        engine = context.scene.render.engine
-
-        return (
-            lamp
-            and lamp.type in {'POINT', 'SPOT'}
-            and lamp.falloff_type == 'CUSTOM_CURVE'
-        ) and (engine in cls.COMPAT_ENGINES)
-
-    draw = properties_data_light.DATA_PT_falloff_curve.draw
-
-
-class OBJECT_PT_POV_rainbow(PovLampButtonsPanel, Panel):
-    """Use this class to define buttons from the rainbow panel of
-    properties window. inheriting lamp buttons panel class"""
-
-    bl_label = "POV-Ray Rainbow"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-    # bl_options = {'HIDE_HEADER'}
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        obj = context.object
-        return (
-            obj
-            and obj.pov.object_as == 'RAINBOW'
-            and (engine in cls.COMPAT_ENGINES)
-        )
-
-    def draw(self, context):
-        layout = self.layout
-
-        obj = context.object
-
-        col = layout.column()
-
-        if obj.pov.object_as == 'RAINBOW':
-            if obj.pov.unlock_parameters == False:
-                col.prop(
-                    obj.pov,
-                    "unlock_parameters",
-                    text="Exported parameters below",
-                    icon='LOCKED',
-                )
-                col.label(
-                    text="Rainbow projection angle: " + str(obj.data.spot_size)
-                )
-                col.label(text="Rainbow width: " + str(obj.data.spot_blend))
-                col.label(
-                    text="Rainbow distance: "
-                    + str(obj.data.shadow_buffer_clip_start)
-                )
-                col.label(text="Rainbow arc angle: " + str(obj.pov.arc_angle))
-                col.label(
-                    text="Rainbow falloff angle: " + str(obj.pov.falloff_angle)
-                )
-
-            else:
-                col.prop(
-                    obj.pov,
-                    "unlock_parameters",
-                    text="Edit exported parameters",
-                    icon='UNLOCKED',
-                )
-                col.label(text="3D view proxy may get out of synch")
-                col.active = obj.pov.unlock_parameters
-
-                layout.operator(
-                    "pov.cone_update", text="Update", icon="MESH_CONE"
-                )
-
-                # col.label(text="Parameters:")
-                col.prop(obj.data, "spot_size", text="Rainbow Projection Angle")
-                col.prop(obj.data, "spot_blend", text="Rainbow width")
-                col.prop(
-                    obj.data,
-                    "shadow_buffer_clip_start",
-                    text="Visibility distance",
-                )
-                col.prop(obj.pov, "arc_angle")
-                col.prop(obj.pov, "falloff_angle")
-
-
-del properties_data_light
-###############################################################################
-
-
-class WORLD_PT_POV_world(WorldButtonsPanel, Panel):
-    """Use this class to define pov world buttons"""
-
-    bl_label = "World"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    def draw(self, context):
-        layout = self.layout
-
-        world = context.world.pov
-
-        row = layout.row(align=True)
-        row.menu(
-            WORLD_MT_POV_presets.__name__, text=WORLD_MT_POV_presets.bl_label
-        )
-        row.operator(WORLD_OT_POV_add_preset.bl_idname, text="", icon='ADD')
-        row.operator(
-            WORLD_OT_POV_add_preset.bl_idname, text="", icon='REMOVE'
-        ).remove_active = True
-
-        row = layout.row()
-        row.prop(world, "use_sky_paper")
-        row.prop(world, "use_sky_blend")
-        row.prop(world, "use_sky_real")
-
-        row = layout.row()
-        row.column().prop(world, "horizon_color")
-        col = row.column()
-        col.prop(world, "zenith_color")
-        col.active = world.use_sky_blend
-        row.column().prop(world, "ambient_color")
-
-        # row = layout.row()
-        # row.prop(world, "exposure") #Re-implement later as a light multiplier
-        # row.prop(world, "color_range")
-
-
-class WORLD_PT_POV_mist(WorldButtonsPanel, Panel):
-    """Use this class to define pov mist buttons."""
-
-    bl_label = "Mist"
-    bl_options = {'DEFAULT_CLOSED'}
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    def draw_header(self, context):
-        world = context.world
-
-        self.layout.prop(world.mist_settings, "use_mist", text="")
-
-    def draw(self, context):
-        layout = self.layout
-
-        world = context.world
-
-        layout.active = world.mist_settings.use_mist
-
-        split = layout.split()
-
-        col = split.column()
-        col.prop(world.mist_settings, "intensity")
-        col.prop(world.mist_settings, "start")
-
-        col = split.column()
-        col.prop(world.mist_settings, "depth")
-        col.prop(world.mist_settings, "height")
-
-        layout.prop(world.mist_settings, "falloff")
-
-
-class RENDER_PT_POV_export_settings(RenderButtonsPanel, Panel):
-    """Use this class to define pov ini settingss buttons."""
-    bl_options = {'DEFAULT_CLOSED'}
-    bl_label = "Auto Start"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    def draw_header(self, context):
-        scene = context.scene
-        if scene.pov.tempfiles_enable:
-            self.layout.prop(
-                scene.pov, "tempfiles_enable", text="", icon='AUTO'
-            )
-        else:
-            self.layout.prop(
-                scene.pov, "tempfiles_enable", text="", icon='CONSOLE'
-            )
-
-    def draw(self, context):
-
-        layout = self.layout
-
-        scene = context.scene
-
-        layout.active = scene.pov.max_trace_level != 0
-        split = layout.split()
-
-        col = split.column()
-        col.label(text="Command line switches:")
-        col.prop(scene.pov, "command_line_switches", text="")
-        split = layout.split()
-
-        #layout.active = not scene.pov.tempfiles_enable
-        if not scene.pov.tempfiles_enable:
-            split.prop(scene.pov, "deletefiles_enable", text="Delete files")
-            split.prop(scene.pov, "pov_editor", text="POV Editor")
-
-            col = layout.column()
-            col.prop(scene.pov, "scene_name", text="Name")
-            col.prop(scene.pov, "scene_path", text="Path to files")
-            # col.prop(scene.pov, "scene_path", text="Path to POV-file")
-            # col.prop(scene.pov, "renderimage_path", text="Path to image")
-
-            split = layout.split()
-            split.prop(scene.pov, "indentation_character", text="Indent")
-            if scene.pov.indentation_character == 'SPACE':
-                split.prop(scene.pov, "indentation_spaces", text="Spaces")
-
-            row = layout.row()
-            row.prop(scene.pov, "comments_enable", text="Comments")
-            row.prop(scene.pov, "list_lf_enable", text="Line breaks in lists")
-
-
-class RENDER_PT_POV_render_settings(RenderButtonsPanel, Panel):
-    """Use this class to define pov render settings buttons."""
-
-    bl_label = "Global Settings"
-    bl_icon = 'SETTINGS'
-    bl_options = {'DEFAULT_CLOSED'}
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    def draw_header(self, context):
-        scene = context.scene
-        if scene.pov.global_settings_advanced:
-            self.layout.prop(
-                scene.pov, "global_settings_advanced", text="", icon='SETTINGS'
-            )
-        else:
-            self.layout.prop(
-                scene.pov,
-                "global_settings_advanced",
-                text="",
-                icon='PREFERENCES',
-            )
-
-    def draw(self, context):
-        layout = self.layout
-
-        scene = context.scene
-        rd = context.scene.render
-        # layout.active = (scene.pov.max_trace_level != 0)
-
-        if sys.platform[:3] != "win":
-            layout.prop(
-                scene.pov, "sdl_window_enable", text="POV-Ray SDL Window"
-            )
-
-        col = layout.column()
-        col.label(text="Main Path Tracing:")
-        col.prop(scene.pov, "max_trace_level", text="Ray Depth")
-        align = True
-        layout.active = scene.pov.global_settings_advanced
-        # Deprecated (autodetected in pov3.8):
-        # layout.prop(scene.pov, "charset")
-        row = layout.row(align=align)
-        row.prop(scene.pov, "adc_bailout")
-        row = layout.row(align=align)
-        row.prop(scene.pov, "ambient_light")
-        row = layout.row(align=align)
-        row.prop(scene.pov, "irid_wavelength")
-        row = layout.row(align=align)
-        row.prop(scene.pov, "max_intersections")
-        row = layout.row(align=align)
-        row.prop(scene.pov, "number_of_waves")
-        row = layout.row(align=align)
-        row.prop(scene.pov, "noise_generator")
-
-        split = layout.split()
-        split.label(text="Shading:")
-        split = layout.split()
-
-        row = split.row(align=align)
-        row.prop(scene.pov, "use_shadows")
-        row.prop(scene.pov, "alpha_mode")
-
-
-class RENDER_PT_POV_photons(RenderButtonsPanel, Panel):
-    """Use this class to define pov photons buttons."""
-
-    bl_label = "Photons"
-    bl_options = {'DEFAULT_CLOSED'}
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    # def draw_header(self, context):
-    # self.layout.label(icon='SETTINGS')
-
-    def draw_header(self, context):
-        scene = context.scene
-        if scene.pov.photon_enable:
-            self.layout.prop(
-                scene.pov, "photon_enable", text="", icon='PMARKER_ACT'
-            )
-        else:
-            self.layout.prop(
-                scene.pov, "photon_enable", text="", icon='PMARKER'
-            )
-
-    def draw(self, context):
-        scene = context.scene
-        layout = self.layout
-        layout.active = scene.pov.photon_enable
-        col = layout.column()
-        # col.label(text="Global Photons:")
-        col.prop(scene.pov, "photon_max_trace_level", text="Photon Depth")
-
-        split = layout.split()
-
-        col = split.column()
-        col.prop(scene.pov, "photon_spacing", text="Spacing")
-        col.prop(scene.pov, "photon_gather_min")
-
-        col = split.column()
-        col.prop(scene.pov, "photon_adc_bailout", text="Photon ADC")
-        col.prop(scene.pov, "photon_gather_max")
-
-        box = layout.box()
-        box.label(text='Photon Map File:')
-        row = box.row()
-        row.prop(scene.pov, "photon_map_file_save_load", expand=True)
-        if scene.pov.photon_map_file_save_load in {'save'}:
-            box.prop(scene.pov, "photon_map_dir")
-            box.prop(scene.pov, "photon_map_filename")
-        if scene.pov.photon_map_file_save_load in {'load'}:
-            box.prop(scene.pov, "photon_map_file")
-        # end main photons
-
-
-class RENDER_PT_POV_antialias(RenderButtonsPanel, Panel):
-    """Use this class to define pov antialiasing buttons."""
-
-    bl_label = "Anti-Aliasing"
-    bl_options = {'DEFAULT_CLOSED'}
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    def draw_header(self, context):
-        prefs = bpy.context.preferences.addons[__package__].preferences
-        scene = context.scene
-        if (
-            prefs.branch_feature_set_povray != 'uberpov'
-            and scene.pov.antialias_method == '2'
-        ):
-            self.layout.prop(
-                scene.pov, "antialias_enable", text="", icon='ERROR'
-            )
-        elif scene.pov.antialias_enable:
-            self.layout.prop(
-                scene.pov, "antialias_enable", text="", icon='ANTIALIASED'
-            )
-        else:
-            self.layout.prop(
-                scene.pov, "antialias_enable", text="", icon='ALIASED'
-            )
-
-    def draw(self, context):
-        prefs = bpy.context.preferences.addons[__package__].preferences
-        layout = self.layout
-        scene = context.scene
-
-        layout.active = scene.pov.antialias_enable
-
-        row = layout.row()
-        row.prop(scene.pov, "antialias_method", text="")
-
-        if (
-            prefs.branch_feature_set_povray != 'uberpov'
-            and scene.pov.antialias_method == '2'
-        ):
-            col = layout.column()
-            col.alignment = 'CENTER'
-            col.label(text="Stochastic Anti Aliasing is")
-            col.label(text="Only Available with UberPOV")
-            col.label(text="Feature Set in User Preferences.")
-            col.label(text="Using Type 2 (recursive) instead")
-        else:
-            row.prop(scene.pov, "jitter_enable", text="Jitter")
-
-            split = layout.split()
-            col = split.column()
-            col.prop(scene.pov, "antialias_depth", text="AA Depth")
-            sub = split.column()
-            sub.prop(scene.pov, "jitter_amount", text="Jitter Amount")
-            if scene.pov.jitter_enable:
-                sub.enabled = True
-            else:
-                sub.enabled = False
-
-            row = layout.row()
-            row.prop(scene.pov, "antialias_threshold", text="AA Threshold")
-            row.prop(scene.pov, "antialias_gamma", text="AA Gamma")
-
-            if prefs.branch_feature_set_povray == 'uberpov':
-                row = layout.row()
-                row.prop(
-                    scene.pov, "antialias_confidence", text="AA Confidence"
-                )
-                if scene.pov.antialias_method == '2':
-                    row.enabled = True
-                else:
-                    row.enabled = False
-
-
-class RENDER_PT_POV_radiosity(RenderButtonsPanel, Panel):
-    """Use this class to define pov radiosity buttons."""
-
-    bl_label = "Diffuse Radiosity"
-    bl_options = {'DEFAULT_CLOSED'}
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    def draw_header(self, context):
-        scene = context.scene
-        if scene.pov.radio_enable:
-            self.layout.prop(
-                scene.pov,
-                "radio_enable",
-                text="",
-                icon='OUTLINER_OB_LIGHTPROBE',
-            )
-        else:
-            self.layout.prop(
-                scene.pov, "radio_enable", text="", icon='LIGHTPROBE_CUBEMAP'
-            )
-
-    def draw(self, context):
-        layout = self.layout
-
-        scene = context.scene
-
-        layout.active = scene.pov.radio_enable
-
-        split = layout.split()
-
-        col = split.column()
-        col.prop(scene.pov, "radio_count", text="Rays")
-        col.prop(scene.pov, "radio_recursion_limit", text="Recursions")
-
-        split.prop(scene.pov, "radio_error_bound", text="Error Bound")
-
-        layout.prop(scene.pov, "radio_display_advanced")
-
-        if scene.pov.radio_display_advanced:
-            split = layout.split()
-
-            col = split.column()
-            col.prop(scene.pov, "radio_adc_bailout", slider=True)
-            col.prop(scene.pov, "radio_minimum_reuse", text="Min Reuse")
-            col.prop(scene.pov, "radio_gray_threshold", slider=True)
-            col.prop(scene.pov, "radio_pretrace_start", slider=True)
-            col.prop(scene.pov, "radio_low_error_factor", slider=True)
-
-            col = split.column()
-            col.prop(scene.pov, "radio_brightness")
-            col.prop(scene.pov, "radio_maximum_reuse", text="Max Reuse")
-            col.prop(scene.pov, "radio_nearest_count")
-            col.prop(scene.pov, "radio_pretrace_end", slider=True)
-
-            col = layout.column()
-            col.label(text="Estimation Influence:")
-            col.prop(scene.pov, "radio_always_sample")
-            col.prop(scene.pov, "radio_normal")
-            col.prop(scene.pov, "radio_media")
-            col.prop(scene.pov, "radio_subsurface")
-
-
-class POV_RADIOSITY_MT_presets(Menu):
-    """Use this class to define pov radiosity presets menu."""
-
-    bl_label = "Radiosity Presets"
-    preset_subdir = "pov/radiosity"
-    preset_operator = "script.execute_preset"
-    draw = bpy.types.Menu.draw_preset
-
-
-class RENDER_OT_POV_radiosity_add_preset(AddPresetBase, Operator):
-    """Use this class to define pov radiosity add presets button"""
-
-    '''Add a Radiosity Preset'''
-    bl_idname = "scene.radiosity_preset_add"
-    bl_label = "Add Radiosity Preset"
-    preset_menu = "POV_RADIOSITY_MT_presets"
-
-    # variable used for all preset values
-    preset_defines = ["scene = bpy.context.scene"]
-
-    # properties to store in the preset
-    preset_values = [
-        "scene.pov.radio_display_advanced",
-        "scene.pov.radio_adc_bailout",
-        "scene.pov.radio_always_sample",
-        "scene.pov.radio_brightness",
-        "scene.pov.radio_count",
-        "scene.pov.radio_error_bound",
-        "scene.pov.radio_gray_threshold",
-        "scene.pov.radio_low_error_factor",
-        "scene.pov.radio_media",
-        "scene.pov.radio_subsurface",
-        "scene.pov.radio_minimum_reuse",
-        "scene.pov.radio_maximum_reuse",
-        "scene.pov.radio_nearest_count",
-        "scene.pov.radio_normal",
-        "scene.pov.radio_recursion_limit",
-        "scene.pov.radio_pretrace_start",
-        "scene.pov.radio_pretrace_end",
-    ]
-
-    # where to store the preset
-    preset_subdir = "pov/radiosity"
-
-
-# Draw into an existing panel
-def rad_panel_func(self, context):
-    layout = self.layout
-
-    row = layout.row(align=True)
-    row.menu(
-        POV_RADIOSITY_MT_presets.__name__,
-        text=POV_RADIOSITY_MT_presets.bl_label,
-    )
-    row.operator(
-        RENDER_OT_POV_radiosity_add_preset.bl_idname, text="", icon='ADD'
-    )
-    row.operator(
-        RENDER_OT_POV_radiosity_add_preset.bl_idname, text="", icon='REMOVE'
-    ).remove_active = True
-
-
-class RENDER_PT_POV_media(WorldButtonsPanel, Panel):
-    """Use this class to define a pov global atmospheric media buttons."""
-
-    bl_label = "Atmosphere Media"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    def draw_header(self, context):
-        scene = context.scene
-
-        self.layout.prop(scene.pov, "media_enable", text="")
-
-    def draw(self, context):
-        layout = self.layout
-
-        scene = context.scene
-
-        layout.active = scene.pov.media_enable
-
-        col = layout.column()
-        col.prop(scene.pov, "media_scattering_type", text="")
-        col = layout.column()
-        col.prop(scene.pov, "media_samples", text="Samples")
-        split = layout.split()
-        col = split.column(align=True)
-        col.label(text="Scattering:")
-        col.prop(scene.pov, "media_diffusion_scale")
-        col.prop(scene.pov, "media_diffusion_color", text="")
-        col = split.column(align=True)
-        col.label(text="Absorption:")
-        col.prop(scene.pov, "media_absorption_scale")
-        col.prop(scene.pov, "media_absorption_color", text="")
-        if scene.pov.media_scattering_type == '5':
-            col = layout.column()
-            col.prop(scene.pov, "media_eccentricity", text="Eccentricity")
-
-
-##class RENDER_PT_povray_baking(RenderButtonsPanel, Panel):
-##    bl_label = "Baking"
-##    COMPAT_ENGINES = {'POVRAY_RENDER'}
-##
-##    def draw_header(self, context):
-##        scene = context.scene
-##
-##        self.layout.prop(scene.pov, "baking_enable", text="")
-##
-##    def draw(self, context):
-##        layout = self.layout
-##
-##        scene = context.scene
-##        rd = scene.render
-##
-##        layout.active = scene.pov.baking_enable
-
-
-class MODIFIERS_PT_POV_modifiers(ModifierButtonsPanel, Panel):
-    """Use this class to define pov modifier buttons. (For booleans)"""
-
-    bl_label = "POV-Ray"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    # def draw_header(self, context):
-    # scene = context.scene
-    # self.layout.prop(scene.pov, "boolean_mod", text="")
-
-    def draw(self, context):
-        scene = context.scene
-        layout = self.layout
-        ob = context.object
-        mod = ob.modifiers
-        col = layout.column()
-        # Find Boolean Modifiers for displaying CSG option
-        onceCSG = 0
-        for mod in ob.modifiers:
-            if onceCSG == 0:
-                if mod:
-                    if mod.type == 'BOOLEAN':
-                        col.prop(ob.pov, "boolean_mod")
-                        onceCSG = 1
-
-                    if ob.pov.boolean_mod == "POV":
-                        split = layout.split()
-                        col = layout.column()
-                        # Inside Vector for CSG
-                        col.prop(ob.pov, "inside_vector")
-
-
-class MATERIAL_MT_POV_sss_presets(Menu):
-    """Use this class to define pov sss preset menu."""
-
-    bl_label = "SSS Presets"
-    preset_subdir = "pov/material/sss"
-    preset_operator = "script.execute_preset"
-    draw = bpy.types.Menu.draw_preset
-
-
-class MATERIAL_OT_POV_sss_add_preset(AddPresetBase, Operator):
-    """Add an SSS Preset"""
-
-    bl_idname = "material.sss_preset_add"
-    bl_label = "Add SSS Preset"
-    preset_menu = "MATERIAL_MT_POV_sss_presets"
-
-    # variable used for all preset values
-    preset_defines = ["material = bpy.context.material"]
-
-    # properties to store in the preset
-    preset_values = [
-        "material.pov_subsurface_scattering.radius",
-        "material.pov_subsurface_scattering.color",
-    ]
-
-    # where to store the preset
-    preset_subdir = "pov/material/sss"
-
-
-class MATERIAL_PT_POV_sss(MaterialButtonsPanel, Panel):
-    """Use this class to define pov sss buttons panel."""
-
-    bl_label = "Subsurface Scattering"
-    bl_options = {'DEFAULT_CLOSED'}
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    @classmethod
-    def poll(cls, context):
-        mat = context.material
-        engine = context.scene.render.engine
-        return (
-            check_material(mat)
-            and (mat.pov.type in {'SURFACE', 'WIRE'})
-            and (engine in cls.COMPAT_ENGINES)
-        )
-
-    def draw_header(self, context):
-        mat = context.material  # FORMERLY : #active_node_mat(context.material)
-        sss = mat.pov_subsurface_scattering
-
-        self.layout.active = not mat.pov.use_shadeless
-        self.layout.prop(sss, "use", text="")
-
-    def draw(self, context):
-        layout = self.layout
-
-        mat = context.material  # FORMERLY : #active_node_mat(context.material)
-        sss = mat.pov_subsurface_scattering
-
-        layout.active = (sss.use) and (not mat.pov.use_shadeless)
-
-        row = layout.row().split()
-        sub = row.row(align=True).split(align=True, factor=0.75)
-        sub.menu(
-            MATERIAL_MT_POV_sss_presets.__name__,
-            text=MATERIAL_MT_POV_sss_presets.bl_label,
-        )
-        sub.operator(
-            MATERIAL_OT_POV_sss_add_preset.bl_idname, text="", icon='ADD'
-        )
-        sub.operator(
-            MATERIAL_OT_POV_sss_add_preset.bl_idname, text="", icon='REMOVE'
-        ).remove_active = True
-
-        split = layout.split()
-
-        col = split.column()
-        col.prop(sss, "ior")
-        col.prop(sss, "scale")
-        col.prop(sss, "color", text="")
-        col.prop(sss, "radius", text="RGB Radius", expand=True)
-
-        col = split.column()
-        sub = col.column(align=True)
-        sub.label(text="Blend:")
-        sub.prop(sss, "color_factor", text="Color")
-        sub.prop(sss, "texture_factor", text="Texture")
-        sub.label(text="Scattering Weight:")
-        sub.prop(sss, "front")
-        sub.prop(sss, "back")
-        col.separator()
-        col.prop(sss, "error_threshold", text="Error")
-
-
-class MATERIAL_PT_POV_activate_node(MaterialButtonsPanel, Panel):
-    """Use this class to define an activate pov nodes button."""
-
-    bl_label = "Activate Node Settings"
-    bl_context = "material"
-    bl_options = {'HIDE_HEADER'}
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        mat = context.material
-        ob = context.object
-        return (
-            mat
-            and mat.pov.type == "SURFACE"
-            and (engine in cls.COMPAT_ENGINES)
-            and not (mat.pov.material_use_nodes or mat.use_nodes)
-        )
-
-    def draw(self, context):
-        layout = self.layout
-        # layout.operator("pov.material_use_nodes", icon='SOUND')#'NODETREE')
-        # the above replaced with a context hook below:
-        layout.operator(
-            "WM_OT_context_toggle", text="Use POV-Ray Nodes", icon='NODETREE'
-        ).data_path = "material.pov.material_use_nodes"
-
-
-class MATERIAL_PT_POV_active_node(MaterialButtonsPanel, Panel):
-    """Use this class to show pov active node properties buttons."""
-
-    bl_label = "Active Node Settings"
-    bl_context = "material"
-    bl_options = {'HIDE_HEADER'}
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        mat = context.material
-        ob = context.object
-        return (
-            mat
-            and mat.pov.type == "SURFACE"
-            and (engine in cls.COMPAT_ENGINES)
-            and mat.pov.material_use_nodes
-        )
-
-    def draw(self, context):
-        layout = self.layout
-        mat = context.material
-        node_tree = mat.node_tree
-        if node_tree:
-            node = node_tree.nodes.active
-            if mat.use_nodes:
-                if node:
-                    layout.prop(mat.pov, "material_active_node")
-                    if node.bl_idname == "PovrayMaterialNode":
-                        layout.context_pointer_set("node", node)
-                        if hasattr(node, "draw_buttons_ext"):
-                            node.draw_buttons_ext(context, layout)
-                        elif hasattr(node, "draw_buttons"):
-                            node.draw_buttons(context, layout)
-                        value_inputs = [
-                            socket
-                            for socket in node.inputs
-                            if socket.enabled and not socket.is_linked
-                        ]
-                        if value_inputs:
-                            layout.separator()
-                            layout.label(text="Inputs:")
-                            for socket in value_inputs:
-                                row = layout.row()
-                                socket.draw(context, row, node, socket.name)
-                    else:
-                        layout.context_pointer_set("node", node)
-                        if hasattr(node, "draw_buttons_ext"):
-                            node.draw_buttons_ext(context, layout)
-                        elif hasattr(node, "draw_buttons"):
-                            node.draw_buttons(context, layout)
-                        value_inputs = [
-                            socket
-                            for socket in node.inputs
-                            if socket.enabled and not socket.is_linked
-                        ]
-                        if value_inputs:
-                            layout.separator()
-                            layout.label(text="Inputs:")
-                            for socket in value_inputs:
-                                row = layout.row()
-                                socket.draw(context, row, node, socket.name)
-                else:
-                    layout.label(text="No active nodes!")
-
-class MATERIAL_PT_POV_specular(MaterialButtonsPanel, Panel):
-    """Use this class to define standard material specularity (highlights) buttons."""
-
-    bl_label = "Specular"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    @classmethod
-    def poll(cls, context):
-        mat = context.material
-        engine = context.scene.render.engine
-        return (
-            check_material(mat)
-            and (mat.pov.type in {'SURFACE', 'WIRE'})
-            and (engine in cls.COMPAT_ENGINES)
-        )
-    def draw(self, context):
-        layout = self.layout
-
-        mat = context.material.pov
-
-        layout.active = (not mat.use_shadeless)
-
-        split = layout.split()
-
-        col = split.column()
-        col.prop(mat, "specular_color", text="")
-        col.prop(mat, "specular_intensity", text="Intensity")
-
-        col = split.column()
-        col.prop(mat, "specular_shader", text="")
-        col.prop(mat, "use_specular_ramp", text="Ramp")
-
-        col = layout.column()
-        if mat.specular_shader in {'COOKTORR', 'PHONG'}:
-            col.prop(mat, "specular_hardness", text="Hardness")
-        elif mat.specular_shader == 'BLINN':
-            row = col.row()
-            row.prop(mat, "specular_hardness", text="Hardness")
-            row.prop(mat, "specular_ior", text="IOR")
-        elif mat.specular_shader == 'WARDISO':
-            col.prop(mat, "specular_slope", text="Slope")
-        elif mat.specular_shader == 'TOON':
-            row = col.row()
-            row.prop(mat, "specular_toon_size", text="Size")
-            row.prop(mat, "specular_toon_smooth", text="Smooth")
-
-        if mat.use_specular_ramp:
-            layout.separator()
-            layout.template_color_ramp(mat, "specular_ramp", expand=True)
-            layout.separator()
-
-            row = layout.row()
-            row.prop(mat, "specular_ramp_input", text="Input")
-            row.prop(mat, "specular_ramp_blend", text="Blend")
-
-            layout.prop(mat, "specular_ramp_factor", text="Factor")
-
-class MATERIAL_PT_POV_mirror(MaterialButtonsPanel, Panel):
-    """Use this class to define standard material reflectivity (mirror) buttons."""
-
-    bl_label = "Mirror"
-    bl_options = {'DEFAULT_CLOSED'}
-    bl_idname = "MATERIAL_PT_POV_raytrace_mirror"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    @classmethod
-    def poll(cls, context):
-        mat = context.material
-        engine = context.scene.render.engine
-        return (
-            check_material(mat)
-            and (mat.pov.type in {'SURFACE', 'WIRE'})
-            and (engine in cls.COMPAT_ENGINES)
-        )
-
-    def draw_header(self, context):
-        mat = context.material
-        raym = mat.pov_raytrace_mirror
-
-        self.layout.prop(raym, "use", text="")
-
-    def draw(self, context):
-        layout = self.layout
-
-        mat = (
-            context.material
-        )  # Formerly : #mat = active_node_mat(context.material)
-        raym = mat.pov_raytrace_mirror
-
-        layout.active = raym.use
-
-        split = layout.split()
-
-        col = split.column()
-        col.prop(raym, "reflect_factor")
-        col.prop(raym, "mirror_color", text="")
-
-        col = split.column()
-        col.prop(raym, "fresnel")
-        sub = col.column()
-        sub.active = raym.fresnel > 0.0
-        sub.prop(raym, "fresnel_factor", text="Blend")
-
-        split = layout.split()
-
-        col = split.column()
-        col.separator()
-        col.prop(raym, "depth")
-        col.prop(raym, "distance", text="Max Dist")
-        col.separator()
-        sub = col.split(factor=0.4)
-        sub.active = raym.distance > 0.0
-        sub.label(text="Fade To:")
-        sub.prop(raym, "fade_to", text="")
-
-        col = split.column()
-        col.label(text="Gloss:")
-        col.prop(raym, "gloss_factor", text="Amount")
-        sub = col.column()
-        sub.active = raym.gloss_factor < 1.0
-        sub.prop(raym, "gloss_threshold", text="Threshold")
-        sub.prop(raym, "gloss_samples", text="Noise")
-        sub.prop(raym, "gloss_anisotropic", text="Anisotropic")
-
-
-class MATERIAL_PT_POV_transp(MaterialButtonsPanel, Panel):
-    """Use this class to define pov material transparency (alpha) buttons."""
-
-    bl_label = "Transparency"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    @classmethod
-    def poll(cls, context):
-        mat = context.material
-        engine = context.scene.render.engine
-        return (
-            check_material(mat)
-            and (mat.pov.type in {'SURFACE', 'WIRE'})
-            and (engine in cls.COMPAT_ENGINES)
-        )
-
-    def draw_header(self, context):
-        mat = context.material
-
-        if simple_material(mat):
-            self.layout.prop(mat.pov, "use_transparency", text="")
-
-    def draw(self, context):
-        layout = self.layout
-
-        base_mat = context.material
-        mat = context.material  # FORMERLY active_node_mat(context.material)
-        rayt = mat.pov_raytrace_transparency
-
-        if simple_material(base_mat):
-            row = layout.row()
-            row.active = mat.pov.use_transparency
-            row.prop(mat.pov, "transparency_method", expand=True)
-
-        split = layout.split()
-        split.active = base_mat.pov.use_transparency
-
-        col = split.column()
-        col.prop(mat.pov, "alpha")
-        row = col.row()
-        row.active = (base_mat.pov.transparency_method != 'MASK') and (
-            not mat.pov.use_shadeless
-        )
-        row.prop(mat.pov, "specular_alpha", text="Specular")
-
-        col = split.column()
-        col.active = not mat.pov.use_shadeless
-        col.prop(rayt, "fresnel")
-        sub = col.column()
-        sub.active = rayt.fresnel > 0.0
-        sub.prop(rayt, "fresnel_factor", text="Blend")
-
-        if base_mat.pov.transparency_method == 'RAYTRACE':
-            layout.separator()
-            split = layout.split()
-            split.active = base_mat.pov.use_transparency
-
-            col = split.column()
-            col.prop(rayt, "ior")
-            col.prop(rayt, "filter")
-            col.prop(rayt, "falloff")
-            col.prop(rayt, "depth_max")
-            col.prop(rayt, "depth")
-
-            col = split.column()
-            col.label(text="Gloss:")
-            col.prop(rayt, "gloss_factor", text="Amount")
-            sub = col.column()
-            sub.active = rayt.gloss_factor < 1.0
-            sub.prop(rayt, "gloss_threshold", text="Threshold")
-            sub.prop(rayt, "gloss_samples", text="Samples")
-
-
-class MATERIAL_PT_POV_reflection(MaterialButtonsPanel, Panel):
-    """Use this class to define more pov specific reflectivity buttons."""
-
-    bl_label = "POV-Ray Reflection"
-    bl_parent_id = "MATERIAL_PT_POV_raytrace_mirror"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        mat = context.material
-        ob = context.object
-        return (
-            mat
-            and mat.pov.type == "SURFACE"
-            and (engine in cls.COMPAT_ENGINES)
-            and not (mat.pov.material_use_nodes or mat.use_nodes)
-        )
-
-    def draw(self, context):
-        layout = self.layout
-        mat = context.material
-        col = layout.column()
-        col.prop(mat.pov, "irid_enable")
-        if mat.pov.irid_enable:
-            col = layout.column()
-            col.prop(mat.pov, "irid_amount", slider=True)
-            col.prop(mat.pov, "irid_thickness", slider=True)
-            col.prop(mat.pov, "irid_turbulence", slider=True)
-        col.prop(mat.pov, "conserve_energy")
-        col2 = col.split().column()
-
-        if not mat.pov_raytrace_mirror.use:
-            col2.label(text="Please Check Mirror settings :")
-        col2.active = mat.pov_raytrace_mirror.use
-        col2.prop(mat.pov, "mirror_use_IOR")
-        if mat.pov.mirror_use_IOR:
-            col2.alignment = 'CENTER'
-            col2.label(text="The current Raytrace ")
-            col2.label(text="Transparency IOR is: " + str(mat.pov.ior))
-        col2.prop(mat.pov, "mirror_metallic")
-
-
-'''
-#group some native Blender (SSS) and POV (Fade)settings under such a parent panel?
-class MATERIAL_PT_POV_interior(MaterialButtonsPanel, Panel):
-    bl_label = "POV-Ray Interior"
-    bl_idname = "material.pov_interior"
-    #bl_parent_id = "material.absorption"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        mat=context.material
-        ob = context.object
-        return mat and mat.pov.type == "SURFACE" and (engine in cls.COMPAT_ENGINES) and not (mat.pov.material_use_nodes or mat.use_nodes)
-
-
-    def draw_header(self, context):
-        mat = context.material
-'''
-
-
-class MATERIAL_PT_POV_fade_color(MaterialButtonsPanel, Panel):
-    """Use this class to define pov fading (absorption) color buttons."""
-
-    bl_label = "POV-Ray Absorption"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-    # bl_parent_id = "material.pov_interior"
-
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        mat = context.material
-        ob = context.object
-        return (
-            mat
-            and mat.pov.type == "SURFACE"
-            and (engine in cls.COMPAT_ENGINES)
-            and not (mat.pov.material_use_nodes or mat.use_nodes)
-        )
-
-    def draw_header(self, context):
-        mat = context.material
-
-        self.layout.prop(mat.pov, "interior_fade_color", text="")
-
-    def draw(self, context):
-        layout = self.layout
-        mat = context.material
-        # layout.active = mat.pov.interior_fade_color
-        if mat.pov.interior_fade_color != (0.0, 0.0, 0.0):
-            layout.label(text="Raytrace transparency")
-            layout.label(text="depth max Limit needs")
-            layout.label(text="to be non zero to fade")
-
-        pass
-
-
-class MATERIAL_PT_POV_caustics(MaterialButtonsPanel, Panel):
-    """Use this class to define pov caustics buttons."""
-
-    bl_label = "Caustics"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        mat = context.material
-        ob = context.object
-        return (
-            mat
-            and mat.pov.type == "SURFACE"
-            and (engine in cls.COMPAT_ENGINES)
-            and not (mat.pov.material_use_nodes or mat.use_nodes)
-        )
-
-    def draw_header(self, context):
-        mat = context.material
-        if mat.pov.caustics_enable:
-            self.layout.prop(
-                mat.pov, "caustics_enable", text="", icon="PMARKER_SEL"
-            )
-        else:
-            self.layout.prop(
-                mat.pov, "caustics_enable", text="", icon="PMARKER"
-            )
-
-    def draw(self, context):
-
-        layout = self.layout
-
-        mat = context.material
-        layout.active = mat.pov.caustics_enable
-        col = layout.column()
-        if mat.pov.caustics_enable:
-            col.prop(mat.pov, "refraction_caustics")
-            if mat.pov.refraction_caustics:
-
-                col.prop(mat.pov, "refraction_type", text="")
-
-                if mat.pov.refraction_type == "1":
-                    col.prop(mat.pov, "fake_caustics_power", slider=True)
-                elif mat.pov.refraction_type == "2":
-                    col.prop(mat.pov, "photons_dispersion", slider=True)
-                    col.prop(mat.pov, "photons_dispersion_samples", slider=True)
-            col.prop(mat.pov, "photons_reflection")
-
-            if (
-                not mat.pov.refraction_caustics
-                and not mat.pov.photons_reflection
-            ):
-                col = layout.column()
-                col.alignment = 'CENTER'
-                col.label(text="Caustics override is on, ")
-                col.label(text="but you didn't chose any !")
-
-
-class MATERIAL_PT_strand(MaterialButtonsPanel, Panel):
-    """Use this class to define Blender strand antialiasing buttons."""
-
-    bl_label = "Strand"
-    bl_options = {'DEFAULT_CLOSED'}
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    @classmethod
-    def poll(cls, context):
-        mat = context.material
-        engine = context.scene.render.engine
-        return (
-            mat
-            and (mat.pov.type in {'SURFACE', 'WIRE', 'HALO'})
-            and (engine in cls.COMPAT_ENGINES)
-        )
-
-    def draw(self, context):
-        layout = self.layout
-
-        mat = context.material  # don't use node material
-        tan = mat.strand
-
-        split = layout.split()
-
-        col = split.column()
-        sub = col.column(align=True)
-        sub.label(text="Size:")
-        sub.prop(tan, "root_size", text="Root")
-        sub.prop(tan, "tip_size", text="Tip")
-        sub.prop(tan, "size_min", text="Minimum")
-        sub.prop(tan, "use_blender_units")
-        sub = col.column()
-        sub.active = not mat.pov.use_shadeless
-        sub.prop(tan, "use_tangent_shading")
-        col.prop(tan, "shape")
-
-        col = split.column()
-        col.label(text="Shading:")
-        col.prop(tan, "width_fade")
-        ob = context.object
-        if ob and ob.type == 'MESH':
-            col.prop_search(
-                tan, "uv_layer", ob.data, "tessface_uv_textures", text=""
-            )
-        else:
-            col.prop(tan, "uv_layer", text="")
-        col.separator()
-        sub = col.column()
-        sub.active = not mat.pov.use_shadeless
-        sub.label(text="Surface diffuse:")
-        sub = col.column()
-        sub.prop(tan, "blend_distance", text="Distance")
-
-
-class MATERIAL_PT_POV_replacement_text(MaterialButtonsPanel, Panel):
-    """Use this class to define pov custom code declared name field."""
-
-    bl_label = "Custom POV Code"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    def draw(self, context):
-        layout = self.layout
-
-        mat = context.material
-
-        col = layout.column()
-        col.label(text="Replace properties with:")
-        col.prop(mat.pov, "replacement_text", text="")
-
-
-class TEXTURE_MT_POV_specials(Menu):
-    """Use this class to define pov texture slot operations buttons."""
-
-    bl_label = "Texture Specials"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    def draw(self, context):
-        layout = self.layout
-
-        layout.operator("texture.slot_copy", icon='COPYDOWN')
-        layout.operator("texture.slot_paste", icon='PASTEDOWN')
-
-
-class WORLD_TEXTURE_SLOTS_UL_POV_layerlist(UIList):
-    """Use this class to show pov texture slots list."""  # XXX Not used yet
-
-    index: bpy.props.IntProperty(name='index')
-    def draw_item(
-        self, context, layout, data, item, icon, active_data, active_propname
-    ):
-        world = context.scene.world  # .pov
-        active_data = world.pov
-        # tex = context.texture #may be needed later?
-
-        # We could write some code to decide which icon to use here...
-        custom_icon = 'TEXTURE'
-
-        ob = data
-        slot = item
-        # ma = slot.name
-        # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
-        if self.layout_type in {'DEFAULT', 'COMPACT'}:
-            # You should always start your row layout by a label (icon + text), or a non-embossed text field,
-            # this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
-            # We use icon_value of label, as our given icon is an integer value, not an enum ID.
-            # Note "data" names should never be translated!
-            if slot:
-                layout.prop(
-                    item, "texture", text="", emboss=False, icon='TEXTURE'
-                )
-            else:
-                layout.label(text="New", translate=False, icon_value=icon)
-        # 'GRID' layout type should be as compact as possible (typically a single icon!).
-        elif self.layout_type in {'GRID'}:
-            layout.alignment = 'CENTER'
-            layout.label(text="", icon_value=icon)
-
-
-class MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist(UIList):
-    """Use this class to show pov texture slots list."""
-
-    #    texture_slots:
-    index: bpy.props.IntProperty(name='index')
-    # foo  = random prop
-    def draw_item(
-        self, context, layout, data, item, icon, active_data, active_propname
-    ):
-        ob = data
-        slot = item
-        # ma = slot.name
-        # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
-        if self.layout_type in {'DEFAULT', 'COMPACT'}:
-            # You should always start your row layout by a label (icon + text), or a non-embossed text field,
-            # this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
-            # We use icon_value of label, as our given icon is an integer value, not an enum ID.
-            # Note "data" names should never be translated!
-            if slot:
-                layout.prop(
-                    item, "texture", text="", emboss=False, icon='TEXTURE'
-                )
-            else:
-                layout.label(text="New", translate=False, icon_value=icon)
-        # 'GRID' layout type should be as compact as possible (typically a single icon!).
-        elif self.layout_type in {'GRID'}:
-            layout.alignment = 'CENTER'
-            layout.label(text="", icon_value=icon)
-
-# Rewrite an existing class to modify.
-# register but not unregistered because
-# the modified parts concern only POVRAY_RENDER
-class TEXTURE_PT_context(TextureButtonsPanel, Panel):
-    bl_label = ""
-    bl_context = "texture"
-    bl_options = {'HIDE_HEADER'}
-    COMPAT_ENGINES = {'POVRAY_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
-    @classmethod
-    def poll(cls, context):
-        return (
-            (context.scene.texture_context
-            not in('MATERIAL','WORLD','LIGHT','PARTICLES','LINESTYLE')
-            or context.scene.render.engine != 'POVRAY_RENDER')
-        )
-    def draw(self, context):
-        layout = self.layout
-        tex = context.texture
-        space = context.space_data
-        pin_id = space.pin_id
-        use_pin_id = space.use_pin_id
-        user = context.texture_user
-
-        col = layout.column()
-
-        if not (use_pin_id and isinstance(pin_id, bpy.types.Texture)):
-            pin_id = None
-
-        if not pin_id:
-            col.template_texture_user()
-
-        if user or pin_id:
-            col.separator()
-
-            if pin_id:
-                col.template_ID(space, "pin_id")
-            else:
-                propname = context.texture_user_property.identifier
-                col.template_ID(user, propname, new="texture.new")
-
-            if tex:
-                col.separator()
-
-                split = col.split(factor=0.2)
-                split.label(text="Type")
-                split.prop(tex, "type", text="")
-
-class TEXTURE_PT_POV_context_texture(TextureButtonsPanel, Panel):
-    """Use this class to show pov texture context buttons."""
-
-    bl_label = ""
-    bl_options = {'HIDE_HEADER'}
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        return engine in cls.COMPAT_ENGINES
-        # if not (hasattr(context, "pov_texture_slot") or hasattr(context, "texture_node")):
-        #     return False
-        return (
-            context.material
-            or context.scene.world
-            or context.light
-            or context.texture
-            or context.line_style
-            or context.particle_system
-            or isinstance(context.space_data.pin_id, ParticleSettings)
-            or context.texture_user
-        ) and (engine in cls.COMPAT_ENGINES)
-
-    def draw(self, context):
-        layout = self.layout
-
-        scene = context.scene
-        mat = context.view_layer.objects.active.active_material
-        wld = context.scene.world
-
-        layout.prop(scene, "texture_context", expand=True)
-        if scene.texture_context == 'MATERIAL' and mat is not None:
-
-            row = layout.row()
-            row.template_list(
-                "MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist",
-                "",
-                mat,
-                "pov_texture_slots",
-                mat.pov,
-                "active_texture_index",
-                rows=2,
-                maxrows=16,
-                type="DEFAULT"
-            )
-            col = row.column(align=True)
-            col.operator("pov.textureslotadd", icon='ADD', text='')
-            col.operator("pov.textureslotremove", icon='REMOVE', text='')
-            #todo: recreate for pov_texture_slots?
-            #col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
-            #col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
-            col.separator()
-
-            if mat.pov_texture_slots:
-                index = mat.pov.active_texture_index
-                slot = mat.pov_texture_slots[index]
-                povtex = slot.texture#slot.name
-                tex = bpy.data.textures[povtex]
-                col.prop(tex, 'use_fake_user', text='')
-                #layout.label(text='Linked Texture data browser:')
-                propname = slot.texture_search
-                # if slot.texture was a pointer to texture data rather than just a name string:
-                # layout.template_ID(povtex, "texture", new="texture.new")
-
-                layout.prop_search(
-                    slot, 'texture_search', bpy.data, 'textures', text='', icon='TEXTURE'
-                )
-                try:
-                    bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[slot.texture_search]
-                    bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[slot.texture_search]
-                except KeyError:
-                    # texture not hand-linked by user
-                    pass
-
-                if tex:
-                    layout.separator()
-                    split = layout.split(factor=0.2)
-                    split.label(text="Type")
-                    split.prop(tex, "type", text="")
-
-            # else:
-            # for i in range(18):  # length of material texture slots
-            # mat.pov_texture_slots.add()
-        elif scene.texture_context == 'WORLD' and wld is not None:
-
-            row = layout.row()
-            row.template_list(
-                "WORLD_TEXTURE_SLOTS_UL_POV_layerlist",
-                "",
-                wld,
-                "pov_texture_slots",
-                wld.pov,
-                "active_texture_index",
-                rows=2,
-                maxrows=16,
-                type="DEFAULT"
-            )
-            col = row.column(align=True)
-            col.operator("pov.textureslotadd", icon='ADD', text='')
-            col.operator("pov.textureslotremove", icon='REMOVE', text='')
-
-            #todo: recreate for pov_texture_slots?
-            #col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
-            #col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
-            col.separator()
-
-            if wld.pov_texture_slots:
-                index = wld.pov.active_texture_index
-                slot = wld.pov_texture_slots[index]
-                povtex = slot.texture#slot.name
-                tex = bpy.data.textures[povtex]
-                col.prop(tex, 'use_fake_user', text='')
-                #layout.label(text='Linked Texture data browser:')
-                propname = slot.texture_search
-                # if slot.texture was a pointer to texture data rather than just a name string:
-                # layout.template_ID(povtex, "texture", new="texture.new")
-
-                layout.prop_search(
-                    slot, 'texture_search', bpy.data, 'textures', text='', icon='TEXTURE'
-                )
-                try:
-                    bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[slot.texture_search]
-                    bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[slot.texture_search]
-                except KeyError:
-                    # texture not hand-linked by user
-                    pass
-
-                if tex:
-                    layout.separator()
-                    split = layout.split(factor=0.2)
-                    split.label(text="Type")
-                    split.prop(tex, "type", text="")
-
-# Commented out below is a reminder of what existed in Blender Internal
-# attributes need to be recreated
-'''
-        slot = getattr(context, "texture_slot", None)
-        node = getattr(context, "texture_node", None)
-        space = context.space_data
-
-        #attempt at replacing removed space_data
-        mtl = getattr(context, "material", None)
-        if mtl != None:
-            spacedependant = mtl
-        wld = getattr(context, "world", None)
-        if wld != None:
-            spacedependant = wld
-        lgt = getattr(context, "light", None)
-        if lgt != None:
-            spacedependant = lgt
-
-
-        #idblock = context.particle_system.settings
-
-        tex = getattr(context, "texture", None)
-        if tex != None:
-            spacedependant = tex
-
-
-
-        scene = context.scene
-        idblock = scene.pov#pov_context_tex_datablock(context)
-        pin_id = space.pin_id
-
-        #spacedependant.use_limited_texture_context = True
-
-        if space.use_pin_id and not isinstance(pin_id, Texture):
-            idblock = id_tex_datablock(pin_id)
-            pin_id = None
-
-        if not space.use_pin_id:
-            layout.row().prop(spacedependant, "texture_context", expand=True)
-            pin_id = None
-
-        if spacedependant.texture_context == 'OTHER':
-            if not pin_id:
-                layout.template_texture_user()
-            user = context.texture_user
-            if user or pin_id:
-                layout.separator()
-
-                row = layout.row()
-
-                if pin_id:
-                    row.template_ID(space, "pin_id")
-                else:
-                    propname = context.texture_user_property.identifier
-                    row.template_ID(user, propname, new="texture.new")
-
-                if tex:
-                    split = layout.split(factor=0.2)
-                    if tex.use_nodes:
-                        if slot:
-                            split.label(text="Output:")
-                            split.prop(slot, "output_node", text="")
-                    else:
-                        split.label(text="Type:")
-                        split.prop(tex, "type", text="")
-            return
-
-        tex_collection = (pin_id is None) and (node is None) and (spacedependant.texture_context not in ('LINESTYLE','OTHER'))
-
-        if tex_collection:
-
-            pov = getattr(context, "pov", None)
-            active_texture_index = getattr(spacedependant, "active_texture_index", None)
-            print (pov)
-            print(idblock)
-            print(active_texture_index)
-            row = layout.row()
-
-            row.template_list("TEXTURE_UL_texslots", "", idblock, "texture_slots",
-                              idblock, "active_texture_index", rows=2, maxrows=16, type="DEFAULT")
-
-            # row.template_list("WORLD_TEXTURE_SLOTS_UL_List", "texture_slots", world,
-                              # world.texture_slots, world, "active_texture_index", rows=2)
-
-            col = row.column(align=True)
-            col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
-            col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
-            col.menu("TEXTURE_MT_POV_specials", icon='DOWNARROW_HLT', text="")
-
-        if tex_collection:
-            layout.template_ID(idblock, "active_texture", new="texture.new")
-        elif node:
-            layout.template_ID(node, "texture", new="texture.new")
-        elif idblock:
-            layout.template_ID(idblock, "texture", new="texture.new")
-
-        if pin_id:
-            layout.template_ID(space, "pin_id")
-
-        if tex:
-            split = layout.split(factor=0.2)
-            if tex.use_nodes:
-                if slot:
-                    split.label(text="Output:")
-                    split.prop(slot, "output_node", text="")
-            else:
-                split.label(text="Type:")
-'''
-
-
-class TEXTURE_PT_colors(TextureButtonsPanel, Panel):
-    """Use this class to show pov color ramps."""
-
-    bl_label = "Colors"
-    bl_options = {'DEFAULT_CLOSED'}
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    def draw(self, context):
-        layout = self.layout
-
-        tex = context.texture
-
-        layout.prop(tex, "use_color_ramp", text="Ramp")
-        if tex.use_color_ramp:
-            layout.template_color_ramp(tex, "color_ramp", expand=True)
-
-        split = layout.split()
-
-        col = split.column()
-        col.label(text="RGB Multiply:")
-        sub = col.column(align=True)
-        sub.prop(tex, "factor_red", text="R")
-        sub.prop(tex, "factor_green", text="G")
-        sub.prop(tex, "factor_blue", text="B")
-
-        col = split.column()
-        col.label(text="Adjust:")
-        col.prop(tex, "intensity")
-        col.prop(tex, "contrast")
-        col.prop(tex, "saturation")
-
-        col = layout.column()
-        col.prop(tex, "use_clamp", text="Clamp")
-
-
-# Texture Slot Panels #
-
-
-class TEXTURE_OT_POV_texture_slot_add(Operator):
-    """Use this class for the add texture slot button."""
-
-    bl_idname = "pov.textureslotadd"
-    bl_label = "Add"
-    bl_description = "Add texture_slot"
-    bl_options = {'REGISTER', 'UNDO'}
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    def execute(self, context):
-        idblock = pov_context_tex_datablock(context)
-        tex = bpy.data.textures.new(name='Texture', type='IMAGE')
-        #tex.use_fake_user = True
-        #mat = context.view_layer.objects.active.active_material
-        slot = idblock.pov_texture_slots.add()
-        slot.name = tex.name
-        slot.texture = tex.name
-        slot.texture_search = tex.name
-        # Switch paint brush and paint brush mask
-        # to this texture so settings remain contextual
-        bpy.context.tool_settings.image_paint.brush.texture = tex
-        bpy.context.tool_settings.image_paint.brush.mask_texture = tex
-        idblock.pov.active_texture_index = (len(idblock.pov_texture_slots)-1)
-
-        #for area in bpy.context.screen.areas:
-            #if area.type in ['PROPERTIES']:
-                #area.tag_redraw()
-
-
-        return {'FINISHED'}
-
-
-class TEXTURE_OT_POV_texture_slot_remove(Operator):
-    """Use this class for the remove texture slot button."""
-
-    bl_idname = "pov.textureslotremove"
-    bl_label = "Remove"
-    bl_description = "Remove texture_slot"
-    bl_options = {'REGISTER', 'UNDO'}
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    def execute(self, context):
-        idblock = pov_context_tex_datablock(context)
-        #mat = context.view_layer.objects.active.active_material
-        tex_slot = idblock.pov_texture_slots.remove(idblock.pov.active_texture_index)
-        if idblock.pov.active_texture_index > 0:
-            idblock.pov.active_texture_index -= 1
-        try:
-            tex = idblock.pov_texture_slots[idblock.pov.active_texture_index].texture
-        except IndexError:
-            # No more slots
-            return {'FINISHED'}
-        # Switch paint brush to previous texture so settings remain contextual
-        # if 'tex' in locals(): # Would test is the tex variable is assigned / exists
-        bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[tex]
-        bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[tex]
-
-        return {'FINISHED'}
-
-class TextureSlotPanel(TextureButtonsPanel):
-    """Use this class to show pov texture slots panel."""
-
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    @classmethod
-    def poll(cls, context):
-        if not hasattr(context, "pov_texture_slot"):
-            return False
-
-        engine = context.scene.render.engine
-        return TextureButtonsPanel.poll(cls, context) and (
-            engine in cls.COMPAT_ENGINES
-        )
-
-
-class TEXTURE_PT_POV_type(TextureButtonsPanel, Panel):
-    """Use this class to define pov texture type buttons."""
-
-    bl_label = "POV Textures"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-    bl_options = {'HIDE_HEADER'}
-
-    def draw(self, context):
-        layout = self.layout
-        world = context.world
-        tex = context.texture
-
-        split = layout.split(factor=0.2)
-        split.label(text="Pattern")
-        split.prop(tex.pov, "tex_pattern_type", text="")
-
-        # row = layout.row()
-        # row.template_list("WORLD_TEXTURE_SLOTS_UL_List", "texture_slots", world,
-        # world.texture_slots, world, "active_texture_index")
-
-
-class TEXTURE_PT_POV_preview(TextureButtonsPanel, Panel):
-    """Use this class to define pov texture preview panel."""
-
-    bl_label = "Preview"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-    bl_options = {'HIDE_HEADER'}
-
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        if not hasattr(context, "pov_texture_slot"):
-            return False
-        tex = context.texture
-        mat = bpy.context.active_object.active_material
-        return (
-            tex
-            and (tex.pov.tex_pattern_type != 'emulator')
-            and (engine in cls.COMPAT_ENGINES)
-        )
-
-    def draw(self, context):
-        tex = context.texture
-        slot = getattr(context, "pov_texture_slot", None)
-        idblock = pov_context_tex_datablock(context)
-        layout = self.layout
-        # if idblock:
-        # layout.template_preview(tex, parent=idblock, slot=slot)
-        if tex.pov.tex_pattern_type != 'emulator':
-            layout.operator("tex.preview_update")
-        else:
-            layout.template_preview(tex, slot=slot)
-
-
-class TEXTURE_PT_POV_parameters(TextureButtonsPanel, Panel):
-    """Use this class to define pov texture pattern buttons."""
-
-    bl_label = "POV Pattern Options"
-    bl_options = {'HIDE_HEADER'}
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    def draw(self, context):
-        mat = bpy.context.active_object.active_material
-        layout = self.layout
-        tex = context.texture
-        align = True
-        if tex is not None and tex.pov.tex_pattern_type != 'emulator':
-            if tex.pov.tex_pattern_type == 'agate':
-                layout.prop(
-                    tex.pov, "modifier_turbulence", text="Agate Turbulence"
-                )
-            if tex.pov.tex_pattern_type in {'spiral1', 'spiral2'}:
-                layout.prop(tex.pov, "modifier_numbers", text="Number of arms")
-            if tex.pov.tex_pattern_type == 'tiling':
-                layout.prop(tex.pov, "modifier_numbers", text="Pattern number")
-            if tex.pov.tex_pattern_type == 'magnet':
-                layout.prop(tex.pov, "magnet_style", text="Magnet style")
-            if tex.pov.tex_pattern_type == 'quilted':
-                row = layout.row(align=align)
-                row.prop(tex.pov, "modifier_control0", text="Control0")
-                row.prop(tex.pov, "modifier_control1", text="Control1")
-            if tex.pov.tex_pattern_type == 'brick':
-                col = layout.column(align=align)
-                row = col.row()
-                row.prop(tex.pov, "brick_size_x", text="Brick size X")
-                row.prop(tex.pov, "brick_size_y", text="Brick size Y")
-                row = col.row()
-                row.prop(tex.pov, "brick_size_z", text="Brick size Z")
-                row.prop(tex.pov, "brick_mortar", text="Brick mortar")
-            if tex.pov.tex_pattern_type in {'julia', 'mandel', 'magnet'}:
-                col = layout.column(align=align)
-                if tex.pov.tex_pattern_type == 'julia':
-                    row = col.row()
-                    row.prop(tex.pov, "julia_complex_1", text="Complex 1")
-                    row.prop(tex.pov, "julia_complex_2", text="Complex 2")
-                if (
-                    tex.pov.tex_pattern_type == 'magnet'
-                    and tex.pov.magnet_style == 'julia'
-                ):
-                    row = col.row()
-                    row.prop(tex.pov, "julia_complex_1", text="Complex 1")
-                    row.prop(tex.pov, "julia_complex_2", text="Complex 2")
-                row = col.row()
-                if tex.pov.tex_pattern_type in {'julia', 'mandel'}:
-                    row.prop(tex.pov, "f_exponent", text="Exponent")
-                if tex.pov.tex_pattern_type == 'magnet':
-                    row.prop(tex.pov, "magnet_type", text="Type")
-                row.prop(tex.pov, "f_iter", text="Iterations")
-                row = col.row()
-                row.prop(tex.pov, "f_ior", text="Interior")
-                row.prop(tex.pov, "f_ior_fac", text="Factor I")
-                row = col.row()
-                row.prop(tex.pov, "f_eor", text="Exterior")
-                row.prop(tex.pov, "f_eor_fac", text="Factor E")
-            if tex.pov.tex_pattern_type == 'gradient':
-                layout.label(text="Gradient orientation:")
-                column_flow = layout.column_flow(columns=3, align=True)
-                column_flow.prop(tex.pov, "grad_orient_x", text="X")
-                column_flow.prop(tex.pov, "grad_orient_y", text="Y")
-                column_flow.prop(tex.pov, "grad_orient_z", text="Z")
-            if tex.pov.tex_pattern_type == 'pavement':
-                layout.prop(
-                    tex.pov, "pave_sides", text="Pavement:number of sides"
-                )
-                col = layout.column(align=align)
-                column_flow = col.column_flow(columns=3, align=True)
-                column_flow.prop(tex.pov, "pave_tiles", text="Tiles")
-                if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 6:
-                    column_flow.prop(tex.pov, "pave_pat_35", text="Pattern")
-                if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 5:
-                    column_flow.prop(tex.pov, "pave_pat_22", text="Pattern")
-                if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 5:
-                    column_flow.prop(tex.pov, "pave_pat_12", text="Pattern")
-                if tex.pov.pave_sides == '3' and tex.pov.pave_tiles == 6:
-                    column_flow.prop(tex.pov, "pave_pat_12", text="Pattern")
-                if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 4:
-                    column_flow.prop(tex.pov, "pave_pat_7", text="Pattern")
-                if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 4:
-                    column_flow.prop(tex.pov, "pave_pat_5", text="Pattern")
-                if tex.pov.pave_sides == '3' and tex.pov.pave_tiles == 5:
-                    column_flow.prop(tex.pov, "pave_pat_4", text="Pattern")
-                if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 3:
-                    column_flow.prop(tex.pov, "pave_pat_3", text="Pattern")
-                if tex.pov.pave_sides == '3' and tex.pov.pave_tiles == 4:
-                    column_flow.prop(tex.pov, "pave_pat_3", text="Pattern")
-                if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 3:
-                    column_flow.prop(tex.pov, "pave_pat_2", text="Pattern")
-                if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 6:
-                    column_flow.label(text="!!! 5 tiles!")
-                column_flow.prop(tex.pov, "pave_form", text="Form")
-            if tex.pov.tex_pattern_type == 'function':
-                layout.prop(tex.pov, "func_list", text="Functions")
-            if (
-                tex.pov.tex_pattern_type == 'function'
-                and tex.pov.func_list != "NONE"
-            ):
-                func = None
-                if tex.pov.func_list in {"f_noise3d", "f_ph", "f_r", "f_th"}:
-                    func = 0
-                if tex.pov.func_list in {
-                    "f_comma",
-                    "f_crossed_trough",
-                    "f_cubic_saddle",
-                    "f_cushion",
-                    "f_devils_curve",
-                    "f_enneper",
-                    "f_glob",
-                    "f_heart",
-                    "f_hex_x",
-                    "f_hex_y",
-                    "f_hunt_surface",
-                    "f_klein_bottle",
-                    "f_kummer_surface_v1",
-                    "f_lemniscate_of_gerono",
-                    "f_mitre",
-                    "f_nodal_cubic",
-                    "f_noise_generator",
-                    "f_odd",
-                    "f_paraboloid",
-                    "f_pillow",
-                    "f_piriform",
-                    "f_quantum",
-                    "f_quartic_paraboloid",
-                    "f_quartic_saddle",
-                    "f_sphere",
-                    "f_steiners_roman",
-                    "f_torus_gumdrop",
-                    "f_umbrella",
-                }:
-                    func = 1
-                if tex.pov.func_list in {
-                    "f_bicorn",
-                    "f_bifolia",
-                    "f_boy_surface",
-                    "f_superellipsoid",
-                    "f_torus",
-                }:
-                    func = 2
-                if tex.pov.func_list in {
-                    "f_ellipsoid",
-                    "f_folium_surface",
-                    "f_hyperbolic_torus",
-                    "f_kampyle_of_eudoxus",
-                    "f_parabolic_torus",
-                    "f_quartic_cylinder",
-                    "f_torus2",
-                }:
-                    func = 3
-                if tex.pov.func_list in {
-                    "f_blob2",
-                    "f_cross_ellipsoids",
-                    "f_flange_cover",
-                    "f_isect_ellipsoids",
-                    "f_kummer_surface_v2",
-                    "f_ovals_of_cassini",
-                    "f_rounded_box",
-                    "f_spikes_2d",
-                    "f_strophoid",
-                }:
-                    func = 4
-                if tex.pov.func_list in {
-                    "f_algbr_cyl1",
-                    "f_algbr_cyl2",
-                    "f_algbr_cyl3",
-                    "f_algbr_cyl4",
-                    "f_blob",
-                    "f_mesh1",
-                    "f_poly4",
-                    "f_spikes",
-                }:
-                    func = 5
-                if tex.pov.func_list in {
-                    "f_devils_curve_2d",
-                    "f_dupin_cyclid",
-                    "f_folium_surface_2d",
-                    "f_hetero_mf",
-                    "f_kampyle_of_eudoxus_2d",
-                    "f_lemniscate_of_gerono_2d",
-                    "f_polytubes",
-                    "f_ridge",
-                    "f_ridged_mf",
-                    "f_spiral",
-                    "f_witch_of_agnesi",
-                }:
-                    func = 6
-                if tex.pov.func_list in {
-                    "f_helix1",
-                    "f_helix2",
-                    "f_piriform_2d",
-                    "f_strophoid_2d",
-                }:
-                    func = 7
-                if tex.pov.func_list == "f_helical_torus":
-                    func = 8
-                column_flow = layout.column_flow(columns=3, align=True)
-                column_flow.label(text="X")
-                column_flow.prop(tex.pov, "func_plus_x", text="")
-                column_flow.prop(tex.pov, "func_x", text="Value")
-                column_flow = layout.column_flow(columns=3, align=True)
-                column_flow.label(text="Y")
-                column_flow.prop(tex.pov, "func_plus_y", text="")
-                column_flow.prop(tex.pov, "func_y", text="Value")
-                column_flow = layout.column_flow(columns=3, align=True)
-                column_flow.label(text="Z")
-                column_flow.prop(tex.pov, "func_plus_z", text="")
-                column_flow.prop(tex.pov, "func_z", text="Value")
-                row = layout.row(align=align)
-                if func > 0:
-                    row.prop(tex.pov, "func_P0", text="P0")
-                if func > 1:
-                    row.prop(tex.pov, "func_P1", text="P1")
-                row = layout.row(align=align)
-                if func > 2:
-                    row.prop(tex.pov, "func_P2", text="P2")
-                if func > 3:
-                    row.prop(tex.pov, "func_P3", text="P3")
-                row = layout.row(align=align)
-                if func > 4:
-                    row.prop(tex.pov, "func_P4", text="P4")
-                if func > 5:
-                    row.prop(tex.pov, "func_P5", text="P5")
-                row = layout.row(align=align)
-                if func > 6:
-                    row.prop(tex.pov, "func_P6", text="P6")
-                if func > 7:
-                    row.prop(tex.pov, "func_P7", text="P7")
-                    row = layout.row(align=align)
-                    row.prop(tex.pov, "func_P8", text="P8")
-                    row.prop(tex.pov, "func_P9", text="P9")
-            ###################################################End Patterns############################
-
-            layout.prop(tex.pov, "warp_types", text="Warp types")  # warp
-            if tex.pov.warp_types == "TOROIDAL":
-                layout.prop(
-                    tex.pov, "warp_tor_major_radius", text="Major radius"
-                )
-            if tex.pov.warp_types not in {"CUBIC", "NONE"}:
-                layout.prop(
-                    tex.pov, "warp_orientation", text="Warp orientation"
-                )
-            col = layout.column(align=align)
-            row = col.row()
-            row.prop(tex.pov, "warp_dist_exp", text="Distance exponent")
-            row = col.row()
-            row.prop(tex.pov, "modifier_frequency", text="Frequency")
-            row.prop(tex.pov, "modifier_phase", text="Phase")
-
-            row = layout.row()
-
-            row.label(text="Offset:")
-            row.label(text="Scale:")
-            row.label(text="Rotate:")
-            col = layout.column(align=align)
-            row = col.row()
-            row.prop(tex.pov, "tex_mov_x", text="X")
-            row.prop(tex.pov, "tex_scale_x", text="X")
-            row.prop(tex.pov, "tex_rot_x", text="X")
-            row = col.row()
-            row.prop(tex.pov, "tex_mov_y", text="Y")
-            row.prop(tex.pov, "tex_scale_y", text="Y")
-            row.prop(tex.pov, "tex_rot_y", text="Y")
-            row = col.row()
-            row.prop(tex.pov, "tex_mov_z", text="Z")
-            row.prop(tex.pov, "tex_scale_z", text="Z")
-            row.prop(tex.pov, "tex_rot_z", text="Z")
-            row = layout.row()
-
-            row.label(text="Turbulence:")
-            col = layout.column(align=align)
-            row = col.row()
-            row.prop(tex.pov, "warp_turbulence_x", text="X")
-            row.prop(tex.pov, "modifier_octaves", text="Octaves")
-            row = col.row()
-            row.prop(tex.pov, "warp_turbulence_y", text="Y")
-            row.prop(tex.pov, "modifier_lambda", text="Lambda")
-            row = col.row()
-            row.prop(tex.pov, "warp_turbulence_z", text="Z")
-            row.prop(tex.pov, "modifier_omega", text="Omega")
-
-class TEXTURE_PT_POV_mapping(TextureSlotPanel, Panel):
-    """Use this class to define POV texture mapping buttons"""
-    bl_label = "Mapping"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-    bl_space_type = 'PROPERTIES'
-    bl_region_type = 'WINDOW'
-
-    @classmethod
-    def poll(cls, context):
-        idblock = pov_context_tex_datablock(context)
-        if isinstance(idblock, Brush) and not context.sculpt_object:
-            return False
-
-        if not getattr(context, "texture_slot", None):
-            return False
-
-        engine = context.scene.render.engine
-        return (engine in cls.COMPAT_ENGINES)
-
-    def draw(self, context):
-        layout = self.layout
-
-        idblock = pov_context_tex_datablock(context)
-
-        #tex = context.texture_slot
-        tex = mat.pov_texture_slots[
-            mat.active_texture_index
-        ]
-        if not isinstance(idblock, Brush):
-            split = layout.split(percentage=0.3)
-            col = split.column()
-            col.label(text="Coordinates:")
-            col = split.column()
-            col.prop(tex, "texture_coords", text="")
-
-            if tex.texture_coords == 'ORCO':
-                """
-                ob = context.object
-                if ob and ob.type == 'MESH':
-                    split = layout.split(percentage=0.3)
-                    split.label(text="Mesh:")
-                    split.prop(ob.data, "texco_mesh", text="")
-                """
-            elif tex.texture_coords == 'UV':
-                split = layout.split(percentage=0.3)
-                split.label(text="Map:")
-                ob = context.object
-                if ob and ob.type == 'MESH':
-                    split.prop_search(tex, "uv_layer", ob.data, "uv_textures", text="")
-                else:
-                    split.prop(tex, "uv_layer", text="")
-
-            elif tex.texture_coords == 'OBJECT':
-                split = layout.split(percentage=0.3)
-                split.label(text="Object:")
-                split.prop(tex, "object", text="")
-
-            elif tex.texture_coords == 'ALONG_STROKE':
-                split = layout.split(percentage=0.3)
-                split.label(text="Use Tips:")
-                split.prop(tex, "use_tips", text="")
-
-        if isinstance(idblock, Brush):
-            if context.sculpt_object or context.image_paint_object:
-                brush_texture_settings(layout, idblock, context.sculpt_object)
-        else:
-            if isinstance(idblock, FreestyleLineStyle):
-                split = layout.split(percentage=0.3)
-                split.label(text="Projection:")
-                split.prop(tex, "mapping", text="")
-
-                split = layout.split(percentage=0.3)
-                split.separator()
-                row = split.row()
-                row.prop(tex, "mapping_x", text="")
-                row.prop(tex, "mapping_y", text="")
-                row.prop(tex, "mapping_z", text="")
-
-            elif isinstance(idblock, Material):
-                split = layout.split(percentage=0.3)
-                split.label(text="Projection:")
-                split.prop(tex, "mapping", text="")
-
-                split = layout.split()
-
-                col = split.column()
-                if tex.texture_coords in {'ORCO', 'UV'}:
-                    col.prop(tex, "use_from_dupli")
-                    if (idblock.type == 'VOLUME' and tex.texture_coords == 'ORCO'):
-                        col.prop(tex, "use_map_to_bounds")
-                elif tex.texture_coords == 'OBJECT':
-                    col.prop(tex, "use_from_original")
-                    if (idblock.type == 'VOLUME'):
-                        col.prop(tex, "use_map_to_bounds")
-                else:
-                    col.label()
-
-                col = split.column()
-                row = col.row()
-                row.prop(tex, "mapping_x", text="")
-                row.prop(tex, "mapping_y", text="")
-                row.prop(tex, "mapping_z", text="")
-
-            row = layout.row()
-            row.column().prop(tex, "offset")
-            row.column().prop(tex, "scale")
-
-class TEXTURE_PT_POV_influence(TextureSlotPanel, Panel):
-    """Use this class to define pov texture influence buttons."""
-
-    bl_label = "Influence"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-    bl_space_type = 'PROPERTIES'
-    bl_region_type = 'WINDOW'
-    #bl_context = 'texture'
-    @classmethod
-    def poll(cls, context):
-        idblock = pov_context_tex_datablock(context)
-        if (
-            # isinstance(idblock, Brush) and # Brush used for everything since 2.8
-            context.scene.texture_context == 'OTHER'
-        ):  # XXX replace by isinstance(idblock, bpy.types.Brush) and ...
-            return False
-
-        # Specify below also for pov_world_texture_slots, lights etc.
-        # to display for various types of slots but only when any
-        if not getattr(idblock, "pov_texture_slots", None):
-            return False
-
-        engine = context.scene.render.engine
-        return engine in cls.COMPAT_ENGINES
-
-    def draw(self, context):
-
-        layout = self.layout
-
-        idblock = pov_context_tex_datablock(context)
-        # tex = context.pov_texture_slot
-        #mat = bpy.context.active_object.active_material
-        texslot = idblock.pov_texture_slots[
-            idblock.pov.active_texture_index
-        ]  # bpy.data.textures[mat.active_texture_index]
-        tex = bpy.data.textures[
-            idblock.pov_texture_slots[idblock.pov.active_texture_index].texture
-        ]
-
-        def factor_but(layout, toggle, factor, name):
-            row = layout.row(align=True)
-            row.prop(texslot, toggle, text="")
-            sub = row.row(align=True)
-            sub.active = getattr(texslot, toggle)
-            sub.prop(texslot, factor, text=name, slider=True)
-            return sub  # XXX, temp. use_map_normal needs to override.
-
-        if isinstance(idblock, Material):
-            split = layout.split()
-
-            col = split.column()
-            if idblock.pov.type in {'SURFACE', 'WIRE'}:
-
-                split = layout.split()
-
-                col = split.column()
-                col.label(text="Diffuse:")
-                factor_but(
-                    col, "use_map_diffuse", "diffuse_factor", "Intensity"
-                )
-                factor_but(
-                    col,
-                    "use_map_color_diffuse",
-                    "diffuse_color_factor",
-                    "Color",
-                )
-                factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
-                factor_but(
-                    col,
-                    "use_map_translucency",
-                    "translucency_factor",
-                    "Translucency",
-                )
-
-                col.label(text="Specular:")
-                factor_but(
-                    col, "use_map_specular", "specular_factor", "Intensity"
-                )
-                factor_but(
-                    col, "use_map_color_spec", "specular_color_factor", "Color"
-                )
-                factor_but(
-                    col, "use_map_hardness", "hardness_factor", "Hardness"
-                )
-
-                col = split.column()
-                col.label(text="Shading:")
-                factor_but(col, "use_map_ambient", "ambient_factor", "Ambient")
-                factor_but(col, "use_map_emit", "emit_factor", "Emit")
-                factor_but(col, "use_map_mirror", "mirror_factor", "Mirror")
-                factor_but(col, "use_map_raymir", "raymir_factor", "Ray Mirror")
-
-                col.label(text="Geometry:")
-                # XXX replace 'or' when displacement is fixed to not rely on normal influence value.
-                sub_tmp = factor_but(
-                    col, "use_map_normal", "normal_factor", "Normal"
-                )
-                sub_tmp.active = (
-                    texslot.use_map_normal or texslot.use_map_displacement
-                )
-                # END XXX
-
-                factor_but(col, "use_map_warp", "warp_factor", "Warp")
-                factor_but(
-                    col,
-                    "use_map_displacement",
-                    "displacement_factor",
-                    "Displace",
-                )
-
-                # ~ sub = col.column()
-                # ~ sub.active = texslot.use_map_translucency or texslot.map_emit or texslot.map_alpha or texslot.map_raymir or texslot.map_hardness or texslot.map_ambient or texslot.map_specularity or texslot.map_reflection or texslot.map_mirror
-                # ~ sub.prop(texslot, "default_value", text="Amount", slider=True)
-            elif idblock.pov.type == 'HALO':
-                layout.label(text="Halo:")
-
-                split = layout.split()
-
-                col = split.column()
-                factor_but(
-                    col,
-                    "use_map_color_diffuse",
-                    "diffuse_color_factor",
-                    "Color",
-                )
-                factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
-
-                col = split.column()
-                factor_but(col, "use_map_raymir", "raymir_factor", "Size")
-                factor_but(
-                    col, "use_map_hardness", "hardness_factor", "Hardness"
-                )
-                factor_but(
-                    col, "use_map_translucency", "translucency_factor", "Add"
-                )
-            elif idblock.pov.type == 'VOLUME':
-                layout.label(text="Volume:")
-
-                split = layout.split()
-
-                col = split.column()
-                factor_but(col, "use_map_density", "density_factor", "Density")
-                factor_but(
-                    col, "use_map_emission", "emission_factor", "Emission"
-                )
-                factor_but(
-                    col, "use_map_scatter", "scattering_factor", "Scattering"
-                )
-                factor_but(
-                    col, "use_map_reflect", "reflection_factor", "Reflection"
-                )
-
-                col = split.column()
-                col.label(text=" ")
-                factor_but(
-                    col,
-                    "use_map_color_emission",
-                    "emission_color_factor",
-                    "Emission Color",
-                )
-                factor_but(
-                    col,
-                    "use_map_color_transmission",
-                    "transmission_color_factor",
-                    "Transmission Color",
-                )
-                factor_but(
-                    col,
-                    "use_map_color_reflection",
-                    "reflection_color_factor",
-                    "Reflection Color",
-                )
-
-                layout.label(text="Geometry:")
-
-                split = layout.split()
-
-                col = split.column()
-                factor_but(col, "use_map_warp", "warp_factor", "Warp")
-
-                col = split.column()
-                factor_but(
-                    col,
-                    "use_map_displacement",
-                    "displacement_factor",
-                    "Displace",
-                )
-
-        elif isinstance(idblock, Light):
-            split = layout.split()
-
-            col = split.column()
-            factor_but(col, "use_map_color", "color_factor", "Color")
-
-            col = split.column()
-            factor_but(col, "use_map_shadow", "shadow_factor", "Shadow")
-
-        elif isinstance(idblock, World):
-            split = layout.split()
-
-            col = split.column()
-            factor_but(col, "use_map_blend", "blend_factor", "Blend")
-            factor_but(col, "use_map_horizon", "horizon_factor", "Horizon")
-
-            col = split.column()
-            factor_but(
-                col, "use_map_zenith_up", "zenith_up_factor", "Zenith Up"
-            )
-            factor_but(
-                col, "use_map_zenith_down", "zenith_down_factor", "Zenith Down"
-            )
-        elif isinstance(idblock, ParticleSettings):
-            split = layout.split()
-
-            col = split.column()
-            col.label(text="General:")
-            factor_but(col, "use_map_time", "time_factor", "Time")
-            factor_but(col, "use_map_life", "life_factor", "Lifetime")
-            factor_but(col, "use_map_density", "density_factor", "Density")
-            factor_but(col, "use_map_size", "size_factor", "Size")
-
-            col = split.column()
-            col.label(text="Physics:")
-            factor_but(col, "use_map_velocity", "velocity_factor", "Velocity")
-            factor_but(col, "use_map_damp", "damp_factor", "Damp")
-            factor_but(col, "use_map_gravity", "gravity_factor", "Gravity")
-            factor_but(col, "use_map_field", "field_factor", "Force Fields")
-
-            layout.label(text="Hair:")
-
-            split = layout.split()
-
-            col = split.column()
-            factor_but(col, "use_map_length", "length_factor", "Length")
-            factor_but(col, "use_map_clump", "clump_factor", "Clump")
-            factor_but(col, "use_map_twist", "twist_factor", "Twist")
-
-            col = split.column()
-            factor_but(
-                col, "use_map_kink_amp", "kink_amp_factor", "Kink Amplitude"
-            )
-            factor_but(
-                col, "use_map_kink_freq", "kink_freq_factor", "Kink Frequency"
-            )
-            factor_but(col, "use_map_rough", "rough_factor", "Rough")
-
-        elif isinstance(idblock, FreestyleLineStyle):
-            split = layout.split()
-
-            col = split.column()
-            factor_but(
-                col, "use_map_color_diffuse", "diffuse_color_factor", "Color"
-            )
-            col = split.column()
-            factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
-
-        layout.separator()
-
-        if not isinstance(idblock, ParticleSettings):
-            split = layout.split()
-
-            col = split.column()
-            # col.prop(tex, "blend_type", text="Blend") #deprecated since 2.8
-            # col.prop(tex, "use_rgb_to_intensity") #deprecated since 2.8
-            # color is used on gray-scale textures even when use_rgb_to_intensity is disabled.
-            # col.prop(tex, "color", text="") #deprecated since 2.8
-
-            col = split.column()
-            # col.prop(tex, "invert", text="Negative") #deprecated since 2.8
-            # col.prop(tex, "use_stencil") #deprecated since 2.8
-
-        # if isinstance(idblock, (Material, World)):
-        # col.prop(tex, "default_value", text="DVar", slider=True)
-
-
-class TEXTURE_PT_POV_tex_gamma(TextureButtonsPanel, Panel):
-    """Use this class to define pov texture gamma buttons."""
-
-    bl_label = "Image Gamma"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    def draw_header(self, context):
-        tex = context.texture
-
-        self.layout.prop(
-            tex.pov, "tex_gamma_enable", text="", icon='SEQ_LUMA_WAVEFORM'
-        )
-
-    def draw(self, context):
-        layout = self.layout
-
-        tex = context.texture
-
-        layout.active = tex.pov.tex_gamma_enable
-        layout.prop(tex.pov, "tex_gamma_value", text="Gamma Value")
-
-
-# commented out below UI for texture only custom code inside exported material:
-# class TEXTURE_PT_povray_replacement_text(TextureButtonsPanel, Panel):
-# bl_label = "Custom POV Code"
-# COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-# def draw(self, context):
-# layout = self.layout
-
-# tex = context.texture
-
-# col = layout.column()
-# col.label(text="Replace properties with:")
-# col.prop(tex.pov, "replacement_text", text="")
-
-
-class OBJECT_PT_POV_obj_parameters(ObjectButtonsPanel, Panel):
-    """Use this class to define pov specific object level options buttons."""
-
-    bl_label = "POV"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    @classmethod
-    def poll(cls, context):
-
-        engine = context.scene.render.engine
-        return engine in cls.COMPAT_ENGINES
-
-    def draw(self, context):
-        layout = self.layout
-
-        obj = context.object
-
-        split = layout.split()
-
-        col = split.column(align=True)
-
-        col.label(text="Radiosity:")
-        col.prop(obj.pov, "importance_value", text="Importance")
-        col.label(text="Photons:")
-        col.prop(obj.pov, "collect_photons", text="Receive Photon Caustics")
-        if obj.pov.collect_photons:
-            col.prop(
-                obj.pov, "spacing_multiplier", text="Photons Spacing Multiplier"
-            )
-
-        split = layout.split()
-
-        col = split.column()
-        col.prop(obj.pov, "hollow")
-        col.prop(obj.pov, "double_illuminate")
-
-        if obj.type == 'META' or obj.pov.curveshape == 'lathe':
-            # if obj.pov.curveshape == 'sor'
-            col.prop(obj.pov, "sturm")
-        col.prop(obj.pov, "no_shadow")
-        col.prop(obj.pov, "no_image")
-        col.prop(obj.pov, "no_reflection")
-        col.prop(obj.pov, "no_radiosity")
-        col.prop(obj.pov, "inverse")
-        col.prop(obj.pov, "hierarchy")
-        # col.prop(obj.pov,"boundorclip",text="Bound / Clip")
-        # if obj.pov.boundorclip != "none":
-        # col.prop_search(obj.pov,"boundorclipob",context.blend_data,"objects",text="Object")
-        # text = "Clipped by"
-        # if obj.pov.boundorclip == "clipped_by":
-        # text = "Bounded by"
-        # col.prop(obj.pov,"addboundorclip",text=text)
-
-
-class OBJECT_PT_POV_obj_sphere(PovDataButtonsPanel, Panel):
-    """Use this class to define pov sphere primitive parameters buttons."""
-
-    bl_label = "POV Sphere"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-    # bl_options = {'HIDE_HEADER'}
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        obj = context.object
-        return (
-            obj
-            and obj.pov.object_as == 'SPHERE'
-            and (engine in cls.COMPAT_ENGINES)
-        )
-
-    def draw(self, context):
-        layout = self.layout
-
-        obj = context.object
-
-        col = layout.column()
-
-        if obj.pov.object_as == 'SPHERE':
-            if obj.pov.unlock_parameters == False:
-                col.prop(
-                    obj.pov,
-                    "unlock_parameters",
-                    text="Exported parameters below",
-                    icon='LOCKED',
-                )
-                col.label(text="Sphere radius: " + str(obj.pov.sphere_radius))
-
-            else:
-                col.prop(
-                    obj.pov,
-                    "unlock_parameters",
-                    text="Edit exported parameters",
-                    icon='UNLOCKED',
-                )
-                col.label(text="3D view proxy may get out of synch")
-                col.active = obj.pov.unlock_parameters
-
-                layout.operator(
-                    "pov.sphere_update", text="Update", icon="SHADING_RENDERED"
-                )
-
-                # col.label(text="Parameters:")
-                col.prop(obj.pov, "sphere_radius", text="Radius of Sphere")
-
-
-class OBJECT_PT_POV_obj_cylinder(PovDataButtonsPanel, Panel):
-    """Use this class to define pov cylinder primitive parameters buttons."""
-
-    bl_label = "POV Cylinder"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-    # bl_options = {'HIDE_HEADER'}
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        obj = context.object
-        return (
-            obj
-            and obj.pov.object_as == 'CYLINDER'
-            and (engine in cls.COMPAT_ENGINES)
-        )
-
-    def draw(self, context):
-        layout = self.layout
-
-        obj = context.object
-
-        col = layout.column()
-
-        if obj.pov.object_as == 'CYLINDER':
-            if obj.pov.unlock_parameters == False:
-                col.prop(
-                    obj.pov,
-                    "unlock_parameters",
-                    text="Exported parameters below",
-                    icon='LOCKED',
-                )
-                col.label(
-                    text="Cylinder radius: " + str(obj.pov.cylinder_radius)
-                )
-                col.label(
-                    text="Cylinder cap location: "
-                    + str(obj.pov.cylinder_location_cap)
-                )
-
-            else:
-                col.prop(
-                    obj.pov,
-                    "unlock_parameters",
-                    text="Edit exported parameters",
-                    icon='UNLOCKED',
-                )
-                col.label(text="3D view proxy may get out of synch")
-                col.active = obj.pov.unlock_parameters
-
-                layout.operator(
-                    "pov.cylinder_update", text="Update", icon="MESH_CYLINDER"
-                )
-
-                # col.label(text="Parameters:")
-                col.prop(obj.pov, "cylinder_radius")
-                col.prop(obj.pov, "cylinder_location_cap")
-
-
-class OBJECT_PT_POV_obj_cone(PovDataButtonsPanel, Panel):
-    """Use this class to define pov cone primitive parameters buttons."""
-
-    bl_label = "POV Cone"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-    # bl_options = {'HIDE_HEADER'}
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        obj = context.object
-        return (
-            obj
-            and obj.pov.object_as == 'CONE'
-            and (engine in cls.COMPAT_ENGINES)
-        )
-
-    def draw(self, context):
-        layout = self.layout
-
-        obj = context.object
-
-        col = layout.column()
-
-        if obj.pov.object_as == 'CONE':
-            if obj.pov.unlock_parameters == False:
-                col.prop(
-                    obj.pov,
-                    "unlock_parameters",
-                    text="Exported parameters below",
-                    icon='LOCKED',
-                )
-                col.label(
-                    text="Cone base radius: " + str(obj.pov.cone_base_radius)
-                )
-                col.label(
-                    text="Cone cap radius: " + str(obj.pov.cone_cap_radius)
-                )
-                col.label(
-                    text="Cone proxy segments: " + str(obj.pov.cone_segments)
-                )
-                col.label(text="Cone height: " + str(obj.pov.cone_height))
-            else:
-                col.prop(
-                    obj.pov,
-                    "unlock_parameters",
-                    text="Edit exported parameters",
-                    icon='UNLOCKED',
-                )
-                col.label(text="3D view proxy may get out of synch")
-                col.active = obj.pov.unlock_parameters
-
-                layout.operator(
-                    "pov.cone_update", text="Update", icon="MESH_CONE"
-                )
-
-                # col.label(text="Parameters:")
-                col.prop(
-                    obj.pov, "cone_base_radius", text="Radius of Cone Base"
-                )
-                col.prop(obj.pov, "cone_cap_radius", text="Radius of Cone Cap")
-                col.prop(
-                    obj.pov, "cone_segments", text="Segmentation of Cone proxy"
-                )
-                col.prop(obj.pov, "cone_height", text="Height of the cone")
-
-
-class OBJECT_PT_POV_obj_superellipsoid(PovDataButtonsPanel, Panel):
-    """Use this class to define pov superellipsoid primitive parameters buttons."""
-
-    bl_label = "POV Superquadric ellipsoid"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-    # bl_options = {'HIDE_HEADER'}
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        obj = context.object
-        return (
-            obj
-            and obj.pov.object_as == 'SUPERELLIPSOID'
-            and (engine in cls.COMPAT_ENGINES)
-        )
-
-    def draw(self, context):
-        layout = self.layout
-
-        obj = context.object
-
-        col = layout.column()
-
-        if obj.pov.object_as == 'SUPERELLIPSOID':
-            if obj.pov.unlock_parameters == False:
-                col.prop(
-                    obj.pov,
-                    "unlock_parameters",
-                    text="Exported parameters below",
-                    icon='LOCKED',
-                )
-                col.label(text="Radial segmentation: " + str(obj.pov.se_u))
-                col.label(text="Lateral segmentation: " + str(obj.pov.se_v))
-                col.label(text="Ring shape: " + str(obj.pov.se_n1))
-                col.label(text="Cross-section shape: " + str(obj.pov.se_n2))
-                col.label(text="Fill up and down: " + str(obj.pov.se_edit))
-            else:
-                col.prop(
-                    obj.pov,
-                    "unlock_parameters",
-                    text="Edit exported parameters",
-                    icon='UNLOCKED',
-                )
-                col.label(text="3D view proxy may get out of synch")
-                col.active = obj.pov.unlock_parameters
-
-                layout.operator(
-                    "pov.superellipsoid_update",
-                    text="Update",
-                    icon="MOD_SUBSURF",
-                )
-
-                # col.label(text="Parameters:")
-                col.prop(obj.pov, "se_u")
-                col.prop(obj.pov, "se_v")
-                col.prop(obj.pov, "se_n1")
-                col.prop(obj.pov, "se_n2")
-                col.prop(obj.pov, "se_edit")
-
-
-class OBJECT_PT_POV_obj_torus(PovDataButtonsPanel, Panel):
-    """Use this class to define pov torus primitive parameters buttons."""
-
-    bl_label = "POV Torus"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-    # bl_options = {'HIDE_HEADER'}
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        obj = context.object
-        return (
-            obj
-            and obj.pov.object_as == 'TORUS'
-            and (engine in cls.COMPAT_ENGINES)
-        )
-
-    def draw(self, context):
-        layout = self.layout
-
-        obj = context.object
-
-        col = layout.column()
-
-        if obj.pov.object_as == 'TORUS':
-            if obj.pov.unlock_parameters == False:
-                col.prop(
-                    obj.pov,
-                    "unlock_parameters",
-                    text="Exported parameters below",
-                    icon='LOCKED',
-                )
-                col.label(
-                    text="Torus major radius: "
-                    + str(obj.pov.torus_major_radius)
-                )
-                col.label(
-                    text="Torus minor radius: "
-                    + str(obj.pov.torus_minor_radius)
-                )
-                col.label(
-                    text="Torus major segments: "
-                    + str(obj.pov.torus_major_segments)
-                )
-                col.label(
-                    text="Torus minor segments: "
-                    + str(obj.pov.torus_minor_segments)
-                )
-            else:
-                col.prop(
-                    obj.pov,
-                    "unlock_parameters",
-                    text="Edit exported parameters",
-                    icon='UNLOCKED',
-                )
-                col.label(text="3D view proxy may get out of synch")
-                col.active = obj.pov.unlock_parameters
-
-                layout.operator(
-                    "pov.torus_update", text="Update", icon="MESH_TORUS"
-                )
-
-                # col.label(text="Parameters:")
-                col.prop(obj.pov, "torus_major_radius")
-                col.prop(obj.pov, "torus_minor_radius")
-                col.prop(obj.pov, "torus_major_segments")
-                col.prop(obj.pov, "torus_minor_segments")
-
-
-class OBJECT_PT_POV_obj_supertorus(PovDataButtonsPanel, Panel):
-    """Use this class to define pov supertorus primitive parameters buttons."""
-
-    bl_label = "POV SuperTorus"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-    # bl_options = {'HIDE_HEADER'}
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        obj = context.object
-        return (
-            obj
-            and obj.pov.object_as == 'SUPERTORUS'
-            and (engine in cls.COMPAT_ENGINES)
-        )
-
-    def draw(self, context):
-        layout = self.layout
-
-        obj = context.object
-
-        col = layout.column()
-
-        if obj.pov.object_as == 'SUPERTORUS':
-            if obj.pov.unlock_parameters == False:
-                col.prop(
-                    obj.pov,
-                    "unlock_parameters",
-                    text="Exported parameters below",
-                    icon='LOCKED',
-                )
-                col.label(
-                    text="SuperTorus major radius: "
-                    + str(obj.pov.st_major_radius)
-                )
-                col.label(
-                    text="SuperTorus minor radius: "
-                    + str(obj.pov.st_minor_radius)
-                )
-                col.label(
-                    text="SuperTorus major segments: " + str(obj.pov.st_u)
-                )
-                col.label(
-                    text="SuperTorus minor segments: " + str(obj.pov.st_v)
-                )
-
-                col.label(
-                    text="SuperTorus Ring Manipulator: " + str(obj.pov.st_ring)
-                )
-                col.label(
-                    text="SuperTorus Cross Manipulator: "
-                    + str(obj.pov.st_cross)
-                )
-                col.label(
-                    text="SuperTorus Internal And External radii: "
-                    + str(obj.pov.st_ie)
-                )
-
-                col.label(
-                    text="SuperTorus accuracy: " + str(ob.pov.st_accuracy)
-                )
-                col.label(
-                    text="SuperTorus max gradient: "
-                    + str(ob.pov.st_max_gradient)
-                )
-
-            else:
-                col.prop(
-                    obj.pov,
-                    "unlock_parameters",
-                    text="Edit exported parameters",
-                    icon='UNLOCKED',
-                )
-                col.label(text="3D view proxy may get out of synch")
-                col.active = obj.pov.unlock_parameters
-
-                layout.operator(
-                    "pov.supertorus_update", text="Update", icon="MESH_TORUS"
-                )
-
-                # col.label(text="Parameters:")
-                col.prop(obj.pov, "st_major_radius")
-                col.prop(obj.pov, "st_minor_radius")
-                col.prop(obj.pov, "st_u")
-                col.prop(obj.pov, "st_v")
-                col.prop(obj.pov, "st_ring")
-                col.prop(obj.pov, "st_cross")
-                col.prop(obj.pov, "st_ie")
-                # col.prop(obj.pov, "st_edit") #?
-                col.prop(obj.pov, "st_accuracy")
-                col.prop(obj.pov, "st_max_gradient")
-
-
-class OBJECT_PT_POV_obj_parametric(PovDataButtonsPanel, Panel):
-    """Use this class to define pov parametric surface primitive parameters buttons."""
-
-    bl_label = "POV Parametric surface"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-    # bl_options = {'HIDE_HEADER'}
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        obj = context.object
-        return (
-            obj
-            and obj.pov.object_as == 'PARAMETRIC'
-            and (engine in cls.COMPAT_ENGINES)
-        )
-
-    def draw(self, context):
-        layout = self.layout
-
-        obj = context.object
-
-        col = layout.column()
-
-        if obj.pov.object_as == 'PARAMETRIC':
-            if obj.pov.unlock_parameters == False:
-                col.prop(
-                    obj.pov,
-                    "unlock_parameters",
-                    text="Exported parameters below",
-                    icon='LOCKED',
-                )
-                col.label(text="Minimum U: " + str(obj.pov.u_min))
-                col.label(text="Minimum V: " + str(obj.pov.v_min))
-                col.label(text="Maximum U: " + str(obj.pov.u_max))
-                col.label(text="Minimum V: " + str(obj.pov.v_min))
-                col.label(text="X Function: " + str(obj.pov.x_eq))
-                col.label(text="Y Function: " + str(obj.pov.y_eq))
-                col.label(text="Z Function: " + str(obj.pov.x_eq))
-
-            else:
-                col.prop(
-                    obj.pov,
-                    "unlock_parameters",
-                    text="Edit exported parameters",
-                    icon='UNLOCKED',
-                )
-                col.label(text="3D view proxy may get out of synch")
-                col.active = obj.pov.unlock_parameters
-
-                layout.operator(
-                    "pov.parametric_update", text="Update", icon="SCRIPTPLUGINS"
-                )
-
-                col.prop(obj.pov, "u_min", text="Minimum U")
-                col.prop(obj.pov, "v_min", text="Minimum V")
-                col.prop(obj.pov, "u_max", text="Maximum U")
-                col.prop(obj.pov, "v_max", text="Minimum V")
-                col.prop(obj.pov, "x_eq", text="X Function")
-                col.prop(obj.pov, "y_eq", text="Y Function")
-                col.prop(obj.pov, "z_eq", text="Z Function")
-
-
-class OBJECT_PT_povray_replacement_text(ObjectButtonsPanel, Panel):
-    """Use this class to define pov object replacement field."""
-
-    bl_label = "Custom POV Code"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    def draw(self, context):
-        layout = self.layout
-
-        obj = context.object
-
-        col = layout.column()
-        col.label(text="Replace properties with:")
-        col.prop(obj.pov, "replacement_text", text="")
-
-
-###############################################################################
-# Add Povray Objects
-###############################################################################
-
-
-class VIEW_MT_POV_primitives_add(Menu):
-    """Define the primitives menu with presets"""
-
-    bl_idname = "VIEW_MT_POV_primitives_add"
-    bl_label = "Povray"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    @classmethod
-    def poll(cls, context):
-        engine = context.scene.render.engine
-        return engine == 'POVRAY_RENDER'
-
-    def draw(self, context):
-        layout = self.layout
-        layout.operator_context = 'INVOKE_REGION_WIN'
-        layout.menu(
-            VIEW_MT_POV_Basic_Shapes.bl_idname, text="Primitives", icon="GROUP"
-        )
-        layout.menu(VIEW_MT_POV_import.bl_idname, text="Import", icon="IMPORT")
-
-
-class VIEW_MT_POV_Basic_Shapes(Menu):
-    """Use this class to sort simple primitives menu entries."""
-
-    bl_idname = "POVRAY_MT_basic_shape_tools"
-    bl_label = "Basic_shapes"
-
-    def draw(self, context):
-        layout = self.layout
-        layout.operator_context = 'INVOKE_REGION_WIN'
-        layout.operator(
-            "pov.addplane", text="Infinite Plane", icon='MESH_PLANE'
-        )
-        layout.operator("pov.addbox", text="Box", icon='MESH_CUBE')
-        layout.operator("pov.addsphere", text="Sphere", icon='SHADING_RENDERED')
-        layout.operator(
-            "pov.addcylinder", text="Cylinder", icon="MESH_CYLINDER"
-        )
-        layout.operator("pov.cone_add", text="Cone", icon="MESH_CONE")
-        layout.operator("pov.addtorus", text="Torus", icon='MESH_TORUS')
-        layout.separator()
-        layout.operator("pov.addrainbow", text="Rainbow", icon="COLOR")
-        layout.operator("pov.addlathe", text="Lathe", icon='MOD_SCREW')
-        layout.operator("pov.addprism", text="Prism", icon='MOD_SOLIDIFY')
-        layout.operator(
-            "pov.addsuperellipsoid",
-            text="Superquadric Ellipsoid",
-            icon='MOD_SUBSURF',
-        )
-        layout.operator(
-            "pov.addheightfield", text="Height Field", icon="RNDCURVE"
-        )
-        layout.operator(
-            "pov.addspheresweep", text="Sphere Sweep", icon='FORCE_CURVE'
-        )
-        layout.separator()
-        layout.operator(
-            "pov.addblobsphere", text="Blob Sphere", icon='META_DATA'
-        )
-        layout.separator()
-        layout.label(text="Isosurfaces")
-        layout.operator(
-            "pov.addisosurfacebox", text="Isosurface Box", icon="META_CUBE"
-        )
-        layout.operator(
-            "pov.addisosurfacesphere",
-            text="Isosurface Sphere",
-            icon="META_BALL",
-        )
-        layout.operator(
-            "pov.addsupertorus", text="Supertorus", icon="SURFACE_NTORUS"
-        )
-        layout.separator()
-        layout.label(text="Macro based")
-        layout.operator(
-            "pov.addpolygontocircle",
-            text="Polygon To Circle Blending",
-            icon="MOD_CAST",
-        )
-        layout.operator("pov.addloft", text="Loft", icon="SURFACE_NSURFACE")
-        layout.separator()
-        # Warning if the Add Advanced Objects addon containing
-        # Add mesh extra objects is not enabled
-        if not check_add_mesh_extra_objects():
-            # col = box.column()
-            layout.label(
-                text="Please enable Add Mesh: Extra Objects addon", icon="INFO"
-            )
-            # layout.separator()
-            layout.operator(
-                "preferences.addon_show",
-                text="Go to Add Mesh: Extra Objects addon",
-                icon="PREFERENCES",
-            ).module = "add_mesh_extra_objects"
-
-            # layout.separator()
-            return
-        else:
-            layout.operator(
-                "pov.addparametric", text="Parametric", icon='SCRIPTPLUGINS'
-            )
-
-
-class VIEW_MT_POV_import(Menu):
-    """Use this class for the import menu."""
-
-    bl_idname = "POVRAY_MT_import_tools"
-    bl_label = "Import"
-
-    def draw(self, context):
-        layout = self.layout
-        layout.operator_context = 'INVOKE_REGION_WIN'
-        layout.operator("import_scene.pov", icon="FORCE_LENNARDJONES")
-
-
-def menu_func_add(self, context):
-    engine = context.scene.render.engine
-    if engine == 'POVRAY_RENDER':
-        self.layout.menu("VIEW_MT_POV_primitives_add", icon="PLUGIN")
-
-
-def menu_func_import(self, context):
-    engine = context.scene.render.engine
-    if engine == 'POVRAY_RENDER':
-        self.layout.operator("import_scene.pov", icon="FORCE_LENNARDJONES")
-
-
-##############Nodes
-
-# def find_node_input(node, name):
-# for input in node.inputs:
-# if input.name == name:
-# return input
-
-# def panel_node_draw(layout, id_data, output_type, input_name):
-# if not id_data.use_nodes:
-# #layout.operator("pov.material_use_nodes", icon='SOUND')#'NODETREE')
-# #layout.operator("pov.use_shading_nodes", icon='NODETREE')
-# layout.operator("WM_OT_context_toggle", icon='NODETREE').data_path = \
-# "material.pov.material_use_nodes"
-# return False
-
-# ntree = id_data.node_tree
-
-# node = find_node(id_data, output_type)
-# if not node:
-# layout.label(text="No output node")
-# else:
-# input = find_node_input(node, input_name)
-# layout.template_node_view(ntree, node, input)
-
-# return True
-
-
-class NODE_MT_POV_map_create(Menu):
-    """Create maps"""
-
-    bl_idname = "POVRAY_MT_node_map_create"
-    bl_label = "Create map"
-
-    def draw(self, context):
-        layout = self.layout
-        layout.operator("node.map_create")
-
-
-def menu_func_nodes(self, context):
-    ob = context.object
-    if hasattr(ob, 'active_material'):
-        mat = context.object.active_material
-        if mat and context.space_data.tree_type == 'ObjectNodeTree':
-            self.layout.prop(mat.pov, "material_use_nodes")
-            self.layout.menu(NODE_MT_POV_map_create.bl_idname)
-            self.layout.operator("wm.updatepreviewkey")
-        if (
-            hasattr(mat, 'active_texture')
-            and context.scene.render.engine == 'POVRAY_RENDER'
-        ):
-            tex = mat.active_texture
-            if tex and context.space_data.tree_type == 'TextureNodeTree':
-                self.layout.prop(tex.pov, "texture_use_nodes")
-
-
-###############################################################################
-# Camera Povray Settings
-###############################################################################
-class CAMERA_PT_POV_cam_dof(CameraDataButtonsPanel, Panel):
-    """Use this class for camera depth of field focal blur buttons."""
-
-    bl_label = "POV Aperture"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-    bl_parent_id = "DATA_PT_camera_dof_aperture"
-    bl_options = {'HIDE_HEADER'}
-    # def draw_header(self, context):
-    # cam = context.camera
-
-    # self.layout.prop(cam.pov, "dof_enable", text="")
-
-    def draw(self, context):
-        layout = self.layout
-
-        cam = context.camera
-
-        layout.active = cam.dof.use_dof
-        layout.use_property_split = True  # Active single-column layout
-
-        flow = layout.grid_flow(
-            row_major=True,
-            columns=0,
-            even_columns=True,
-            even_rows=False,
-            align=False,
-        )
-
-        col = flow.column()
-        col.label(text="F-Stop value will export as")
-        col.label(
-            text="POV aperture : "
-            + "%.3f" % (1 / cam.dof.aperture_fstop * 1000)
-        )
-
-        col = flow.column()
-        col.prop(cam.pov, "dof_samples_min")
-        col.prop(cam.pov, "dof_samples_max")
-        col.prop(cam.pov, "dof_variance")
-        col.prop(cam.pov, "dof_confidence")
-
-
-class CAMERA_PT_POV_cam_nor(CameraDataButtonsPanel, Panel):
-    """Use this class for camera normal perturbation buttons."""
-
-    bl_label = "POV Perturbation"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    def draw_header(self, context):
-        cam = context.camera
-
-        self.layout.prop(cam.pov, "normal_enable", text="")
-
-    def draw(self, context):
-        layout = self.layout
-
-        cam = context.camera
-
-        layout.active = cam.pov.normal_enable
-
-        layout.prop(cam.pov, "normal_patterns")
-        layout.prop(cam.pov, "cam_normal")
-        layout.prop(cam.pov, "turbulence")
-        layout.prop(cam.pov, "scale")
-
-
-class CAMERA_PT_POV_replacement_text(CameraDataButtonsPanel, Panel):
-    """Use this class for camera text replacement field."""
-
-    bl_label = "Custom POV Code"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    def draw(self, context):
-        layout = self.layout
-
-        cam = context.camera
-
-        col = layout.column()
-        col.label(text="Replace properties with:")
-        col.prop(cam.pov, "replacement_text", text="")
-
-
-###############################################################################
-# Text Povray Settings
-###############################################################################
-
-
-class TEXT_OT_POV_insert(Operator):
-    """Use this class to create blender text editor operator to insert pov snippets like other pov IDEs"""
-
-    bl_idname = "text.povray_insert"
-    bl_label = "Insert"
-
-    filepath: bpy.props.StringProperty(name="Filepath", subtype='FILE_PATH')
-
-    @classmethod
-    def poll(cls, context):
-        # context.area.type == 'TEXT_EDITOR'
-        return bpy.ops.text.insert.poll()
-
-    def execute(self, context):
-        if self.filepath and isfile(self.filepath):
-            file = open(self.filepath, "r")
-            bpy.ops.text.insert(text=file.read())
-
-            # places the cursor at the end without scrolling -.-
-            # context.space_data.text.write(file.read())
-            file.close()
-        return {'FINISHED'}
-
-
-def validinsert(ext):
-    return ext in {".txt", ".inc", ".pov"}
-
-
-class TEXT_MT_POV_insert(Menu):
-    """Use this class to create a menu launcher in text editor for the TEXT_OT_POV_insert operator ."""
-
-    bl_label = "Insert"
-    bl_idname = "TEXT_MT_POV_insert"
-
-    def draw(self, context):
-        pov_documents = locate_docpath()
-        prop = self.layout.operator(
-            "wm.path_open", text="Open folder", icon='FILE_FOLDER'
-        )
-        prop.filepath = pov_documents
-        self.layout.separator()
-
-        list = []
-        for root, dirs, files in os.walk(pov_documents):
-            list.append(root)
-        print(list)
-        self.path_menu(
-            list,
-            "text.povray_insert",
-            # {"internal": True},
-            filter_ext=validinsert,
-        )
-
-
-class TEXT_PT_POV_custom_code(TextButtonsPanel, Panel):
-    """Use this class to create a panel in text editor for the user to decide if he renders text only or adds to 3d scene."""
-
-    bl_label = "POV"
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    def draw(self, context):
-        layout = self.layout
-
-        text = context.space_data.text
-
-        pov_documents = locate_docpath()
-        if not pov_documents:
-            layout.label(text="Please configure ", icon="INFO")
-            layout.label(text="default pov include path ")
-            layout.label(text="in addon preferences")
-            # layout.separator()
-            layout.operator(
-                "preferences.addon_show",
-                text="Go to Render: Persistence of Vision addon",
-                icon="PREFERENCES",
-            ).module = "render_povray"
-
-            # layout.separator()
-        else:
-            # print(pov_documents)
-            layout.menu(TEXT_MT_POV_insert.bl_idname)
-
-        if text:
-            box = layout.box()
-            box.label(text='Source to render:', icon='RENDER_STILL')
-            row = box.row()
-            row.prop(text.pov, "custom_code", expand=True)
-            if text.pov.custom_code in {'3dview'}:
-                box.operator("render.render", icon='OUTLINER_DATA_ARMATURE')
-            if text.pov.custom_code in {'text'}:
-                rtext = bpy.context.space_data.text
-                box.operator("text.run", icon='ARMATURE_DATA')
-            # layout.prop(text.pov, "custom_code")
-            elif text.pov.custom_code in {'both'}:
-                box.operator("render.render", icon='POSE_HLT')
-                layout.label(text="Please specify declared", icon="INFO")
-                layout.label(text="items in properties ")
-                # layout.label(text="")
-                layout.label(text="replacement fields")
-
-
-###############################################
-# Text editor templates from header menu
-
-
-class TEXT_MT_POV_templates(Menu):
-    """Use this class to create a menu for the same pov templates scenes as other pov IDEs."""
-
-    bl_label = "POV"
-
-    # We list templates on file evaluation, we can assume they are static data,
-    # and better avoid running this on every draw call.
-    import os
-
-    template_paths = [os.path.join(os.path.dirname(__file__), "templates_pov")]
-
-    def draw(self, context):
-        self.path_menu(
-            self.template_paths, "text.open", props_default={"internal": True}
-        )
-
-
-def menu_func_templates(self, context):
-    # Do not depend on POV being active renderer here...
-    self.layout.menu("TEXT_MT_POV_templates")
-
-###############################################################################
-# Freestyle
-###############################################################################
-#import addon_utils
-#addon_utils.paths()[0]
-#addon_utils.modules()
-#mod.bl_info['name'] == 'Freestyle SVG Exporter':
-bpy.utils.script_paths("addons")
-#render_freestyle_svg = os.path.join(bpy.utils.script_paths("addons"), "render_freestyle_svg.py")
-
-render_freestyle_svg = bpy.context.preferences.addons.get('render_freestyle_svg')
-    #mpath=addon_utils.paths()[0].render_freestyle_svg
-    #import mpath
-    #from mpath import render_freestyle_svg #= addon_utils.modules(['Freestyle SVG Exporter'])
-    #from scripts\\addons import render_freestyle_svg
-if check_render_freestyle_svg():
-    '''
-    snippetsWIP
-    import myscript
-    import importlib
-
-    importlib.reload(myscript)
-    myscript.main()
-    '''
-    for member in dir(render_freestyle_svg):
-        subclass = getattr(render_freestyle_svg, member)
-        try:
-            subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-            if subclass.bl_idname == "RENDER_PT_SVGExporterPanel":
-                subclass.bl_parent_id = "RENDER_PT_POV_filter"
-                subclass.bl_options = {'HIDE_HEADER'}
-                #subclass.bl_order = 11
-                print(subclass.bl_info)
-        except:
-            pass
-
-    #del render_freestyle_svg.RENDER_PT_SVGExporterPanel.bl_parent_id
-
-
-class RENDER_PT_POV_filter(RenderButtonsPanel, Panel):
-    """Use this class to invoke stuff like Freestyle UI."""
-
-    bl_label = "Freestyle"
-    bl_options = {'DEFAULT_CLOSED'}
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-    @classmethod
-    def poll(cls, context):
-        with_freestyle = bpy.app.build_options.freestyle
-        engine = context.scene.render.engine
-        return(with_freestyle and engine == 'POVRAY_RENDER')
-    def draw_header(self, context):
-
-        #scene = context.scene
-        rd = context.scene.render
-        layout = self.layout
-
-        if rd.use_freestyle:
-            layout.prop(
-                rd, "use_freestyle", text="", icon='LINE_DATA'
-                    )
-
-        else:
-            layout.prop(
-                rd, "use_freestyle", text="", icon='OUTLINER_OB_IMAGE'
-                    )
-
-    def draw(self, context):
-        rd = context.scene.render
-        layout = self.layout
-        layout.active = rd.use_freestyle
-        layout.use_property_split = True
-        layout.use_property_decorate = False  # No animation.
-        flow = layout.grid_flow(
-            row_major=True,
-            columns=0,
-            even_columns=True,
-            even_rows=False,
-            align=True,
-        )
-
-        flow.prop(rd, "line_thickness_mode", expand=True)
-
-        if rd.line_thickness_mode == 'ABSOLUTE':
-            flow.prop(rd, "line_thickness")
-
-        # Warning if the Freestyle SVG Exporter addon is not enabled
-        if not check_render_freestyle_svg():
-            # col = box.column()
-            layout.label(
-                text="Please enable Freestyle SVG Exporter addon", icon="INFO"
-            )
-            # layout.separator()
-            layout.operator(
-                "preferences.addon_show",
-                text="Go to Render: Freestyle SVG Exporter addon",
-                icon="PREFERENCES",
-            ).module = "render_freestyle_svg"
-
-classes = (
-    WORLD_PT_POV_world,
-    WORLD_MT_POV_presets,
-    WORLD_OT_POV_add_preset,
-    WORLD_TEXTURE_SLOTS_UL_POV_layerlist,
-    #WORLD_TEXTURE_SLOTS_UL_List,
-    WORLD_PT_POV_mist,
-    # RenderButtonsPanel,
-    # ModifierButtonsPanel,
-    # MaterialButtonsPanel,
-    # TextureButtonsPanel,
-    # ObjectButtonsPanel,
-    # CameraDataButtonsPanel,
-    # WorldButtonsPanel,
-    # TextButtonsPanel,
-    # PovDataButtonsPanel,
-    DATA_PT_POV_normals,
-    DATA_PT_POV_texture_space,
-    DATA_PT_POV_vertex_groups,
-    DATA_PT_POV_shape_keys,
-    DATA_PT_POV_uv_texture,
-    DATA_PT_POV_vertex_colors,
-    DATA_PT_POV_customdata,
-    # PovLampButtonsPanel,
-    LIGHT_PT_POV_preview,
-    LIGHT_PT_POV_light,
-    LIGHT_MT_POV_presets,
-    LIGHT_OT_POV_add_preset,
-    OBJECT_PT_POV_rainbow,
-    RENDER_PT_POV_export_settings,
-    RENDER_PT_POV_render_settings,
-    RENDER_PT_POV_photons,
-    RENDER_PT_POV_antialias,
-    RENDER_PT_POV_radiosity,
-    RENDER_PT_POV_filter,
-    POV_RADIOSITY_MT_presets,
-    RENDER_OT_POV_radiosity_add_preset,
-    RENDER_PT_POV_media,
-    MODIFIERS_PT_POV_modifiers,
-    MATERIAL_PT_POV_sss,
-    MATERIAL_MT_POV_sss_presets,
-    MATERIAL_OT_POV_sss_add_preset,
-    MATERIAL_PT_strand,
-    MATERIAL_PT_POV_activate_node,
-    MATERIAL_PT_POV_active_node,
-    MATERIAL_PT_POV_specular,
-    MATERIAL_PT_POV_mirror,
-    MATERIAL_PT_POV_transp,
-    MATERIAL_PT_POV_reflection,
-    # MATERIAL_PT_POV_interior,
-    MATERIAL_PT_POV_fade_color,
-    MATERIAL_PT_POV_caustics,
-    MATERIAL_PT_POV_replacement_text,
-    TEXTURE_MT_POV_specials,
-    TEXTURE_PT_POV_context_texture,
-    TEXTURE_PT_POV_type,
-    TEXTURE_PT_POV_preview,
-    TEXTURE_PT_POV_parameters,
-    TEXTURE_PT_POV_tex_gamma,
-    OBJECT_PT_POV_obj_parameters,
-    OBJECT_PT_POV_obj_sphere,
-    OBJECT_PT_POV_obj_cylinder,
-    OBJECT_PT_POV_obj_cone,
-    OBJECT_PT_POV_obj_superellipsoid,
-    OBJECT_PT_POV_obj_torus,
-    OBJECT_PT_POV_obj_supertorus,
-    OBJECT_PT_POV_obj_parametric,
-    OBJECT_PT_povray_replacement_text,
-    VIEW_MT_POV_primitives_add,
-    VIEW_MT_POV_Basic_Shapes,
-    VIEW_MT_POV_import,
-    NODE_MT_POV_map_create,
-    CAMERA_PT_POV_cam_dof,
-    CAMERA_PT_POV_cam_nor,
-    CAMERA_PT_POV_replacement_text,
-    TEXT_OT_POV_insert,
-    TEXT_MT_POV_insert,
-    TEXT_PT_POV_custom_code,
-    TEXT_MT_POV_templates,
-    #TEXTURE_PT_POV_povray_texture_slots,
-    #TEXTURE_UL_POV_texture_slots,
-    MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist,
-    TEXTURE_OT_POV_texture_slot_add,
-    TEXTURE_OT_POV_texture_slot_remove,
-    TEXTURE_PT_POV_influence,
-    TEXTURE_PT_POV_mapping,
-)
-
-
-def register():
-    # from bpy.utils import register_class
-
-    for cls in classes:
-        register_class(cls)
-
-    bpy.types.VIEW3D_MT_add.prepend(menu_func_add)
-    bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
-    bpy.types.TEXT_MT_templates.append(menu_func_templates)
-    bpy.types.RENDER_PT_POV_radiosity.prepend(rad_panel_func)
-    bpy.types.LIGHT_PT_POV_light.prepend(light_panel_func)
-    # bpy.types.WORLD_PT_POV_world.prepend(world_panel_func)
-    # was used for parametric objects but made the other addon unreachable on
-    # unregister for other tools to use created a user action call instead
-    # addon_utils.enable("add_mesh_extra_objects", default_set=False, persistent=True)
-    # bpy.types.TEXTURE_PT_context_texture.prepend(TEXTURE_PT_POV_type)
-
-    if not povCentricWorkspace in bpy.app.handlers.load_post:
-        # print("Adding POV wentric workspace on load handlers list")
-        bpy.app.handlers.load_post.append(povCentricWorkspace)
-
-def unregister():
-    if povCentricWorkspace in bpy.app.handlers.load_post:
-        # print("Removing POV wentric workspace from load handlers list")
-        bpy.app.handlers.load_post.remove(povCentricWorkspace)
-
-    # from bpy.utils import unregister_class
-
-    # bpy.types.TEXTURE_PT_context_texture.remove(TEXTURE_PT_POV_type)
-    # addon_utils.disable("add_mesh_extra_objects", default_set=False)
-    # bpy.types.WORLD_PT_POV_world.remove(world_panel_func)
-    bpy.types.LIGHT_PT_POV_light.remove(light_panel_func)
-    bpy.types.RENDER_PT_POV_radiosity.remove(rad_panel_func)
-    bpy.types.TEXT_MT_templates.remove(menu_func_templates)
-    bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
-    bpy.types.VIEW3D_MT_add.remove(menu_func_add)
-
-    for cls in reversed(classes):
-        if cls != TEXTURE_PT_context:
-            unregister_class(cls)
diff --git a/render_povray/update_files.py b/render_povray/update_files.py
old mode 100644
new mode 100755
index 416e40d37..985f84684
--- a/render_povray/update_files.py
+++ b/render_povray/update_files.py
@@ -33,8 +33,22 @@ from bpy.props import (
     EnumProperty,
 )
 
+# Todo:
+# *update this file to just cover 2.79 to  3.xx and ui it from a Blender internal to pov menu
+# *as well as update from older pov > switch to QMC when pov 3.8 is out ?
+# *filter if possible  files built in pre 2.79 versions. tell user their file is too old and may
+# be salvaged from older vesion of this operator from within latest stable blender 2.79 version.
+# else if bpy.app.version[0] == 2 and bpy.app.version[1] <= 92 and and bpy.app.version[1] >= 79:
+# warn users to update blender to 3.xx for creating their newer files then try to salvage
+# using this script
+#
+# if bpy.app.version[0] >= 3:  # just test file created a)there or b)before, a) do nothing
+# "your version is relatively futureproof" > doing nothing
+# b)"use this operator to salvage your blends from latest stable 2.79"
+
 
 def update2_0_0_9():
+    """Update properties from older Blender versions. The render API changed a lot up to  2.79."""
     # Temporally register old props, so we can access their values.
     register()
 
@@ -109,26 +123,16 @@ def update2_0_0_9():
         "pov_refraction_type",
         "pov_replacement_text",
     ]:
-        old_mat_props[k] = getattr(bpy.types.Material, k)[1].get(
-            'default', None
-        )
+        old_mat_props[k] = getattr(bpy.types.Material, k)[1].get('default', None)
 
     # Get default values of pov texture props.
     old_tex_props = {}
-    for k in [
-        "pov_tex_gamma_enable",
-        "pov_tex_gamma_value",
-        "pov_replacement_text",
-    ]:
+    for k in ["pov_tex_gamma_enable", "pov_tex_gamma_value", "pov_replacement_text"]:
         old_tex_props[k] = getattr(bpy.types.Texture, k)[1].get('default', None)
 
     # Get default values of pov object props.
     old_obj_props = {}
-    for k in [
-        "pov_importance_value",
-        "pov_collect_photons",
-        "pov_replacement_text",
-    ]:
+    for k in ["pov_importance_value", "pov_collect_photons", "pov_replacement_text"]:
         old_obj_props[k] = getattr(bpy.types.Object, k)[1].get('default', None)
 
     # Get default values of pov camera props.
@@ -189,7 +193,7 @@ def update2_0_0_9():
 
 
 class RenderCopySettings(bpy.types.Operator):
-    """Update old POV properties to new ones"""
+    """Update old POV properties to new ones."""
 
     bl_idname = "scene.pov_update_properties"
     bl_label = "PovRay render: Update to script v0.0.9"
@@ -253,19 +257,13 @@ def register():
 
     # Not a real pov option, just to know if we should write
     Scene.pov_radio_enable = BoolProperty(
-        name="Enable Radiosity",
-        description="Enable POV-Rays radiosity calculation",
-        default=False,
+        name="Enable Radiosity", description="Enable POV-Rays radiosity calculation", default=False
     )
     Scene.pov_radio_display_advanced = BoolProperty(
-        name="Advanced Options",
-        description="Show advanced options",
-        default=False,
+        name="Advanced Options", description="Show advanced options", default=False
     )
     Scene.pov_media_enable = BoolProperty(
-        name="Enable Media",
-        description="Enable POV-Rays atmospheric media",
-        default=False,
+        name="Enable Media", description="Enable POV-Rays atmospheric media", default=False
     )
     Scene.pov_media_samples = IntProperty(
         name="Samples",
@@ -288,9 +286,7 @@ def register():
     )
 
     Scene.pov_baking_enable = BoolProperty(
-        name="Enable Baking",
-        description="Enable POV-Rays texture baking",
-        default=False,
+        name="Enable Baking", description="Enable POV-Rays texture baking", default=False
     )
     Scene.pov_indentation_character = EnumProperty(
         name="Indentation",
@@ -311,9 +307,7 @@ def register():
     )
 
     Scene.pov_comments_enable = BoolProperty(
-        name="Enable Comments",
-        description="Add comments to pov file",
-        default=True,
+        name="Enable Comments", description="Add comments to pov file", default=True
     )
 
     # Real pov options
@@ -339,11 +333,7 @@ def register():
     )
 
     Scene.pov_antialias_depth = IntProperty(
-        name="Antialias Depth",
-        description="Depth of pixel for sampling",
-        min=1,
-        max=9,
-        default=3,
+        name="Antialias Depth", description="Depth of pixel for sampling", min=1, max=9, default=3
     )
 
     Scene.pov_antialias_threshold = FloatProperty(
@@ -504,9 +494,7 @@ def register():
 
     # max_sample - not available yet
     Scene.pov_radio_media = BoolProperty(
-        name="Media",
-        description="Radiosity estimation can be affected by media",
-        default=False,
+        name="Media", description="Radiosity estimation can be affected by media", default=False
     )
 
     Scene.pov_radio_minimum_reuse = FloatProperty(
@@ -529,9 +517,7 @@ def register():
     )
 
     Scene.pov_radio_normal = BoolProperty(
-        name="Normals",
-        description="Radiosity estimation can be affected by normals",
-        default=False,
+        name="Normals", description="Radiosity estimation can be affected by normals", default=False
     )
 
     Scene.pov_radio_recursion_limit = IntProperty(
@@ -638,9 +624,7 @@ def register():
     )
 
     Mat.pov_fake_caustics = BoolProperty(
-        name="Fake Caustics",
-        description="use only (Fast) fake refractive caustics",
-        default=True,
+        name="Fake Caustics", description="use only (Fast) fake refractive caustics", default=True
     )
 
     Mat.pov_fake_caustics_power = FloatProperty(
@@ -654,9 +638,7 @@ def register():
     )
 
     Mat.pov_photons_refraction = BoolProperty(
-        name="Refractive Photon Caustics",
-        description="more physically correct",
-        default=False,
+        name="Refractive Photon Caustics", description="more physically correct", default=False
     )
 
     Mat.pov_photons_dispersion = FloatProperty(
@@ -752,9 +734,7 @@ def register():
 
     # DOF Toggle
     Cam.pov_dof_enable = BoolProperty(
-        name="Depth Of Field",
-        description="Enable POV-Ray Depth Of Field ",
-        default=True,
+        name="Depth Of Field", description="Enable POV-Ray Depth Of Field ", default=True
     )
 
     # Aperture (Intensity of the Blur)
@@ -816,12 +796,12 @@ def unregister():
     Obj = bpy.types.Object
     Cam = bpy.types.Camera
     Text = bpy.types.Text
-    del Scene.pov_tempfiles_enable  # CR
-    del Scene.pov_scene_name  # CR
-    del Scene.pov_deletefiles_enable  # CR
-    del Scene.pov_scene_path  # CR
-    del Scene.pov_renderimage_path  # CR
-    del Scene.pov_list_lf_enable  # CR
+    del Scene.pov_tempfiles_enable
+    del Scene.pov_scene_name
+    del Scene.pov_deletefiles_enable
+    del Scene.pov_scene_path
+    del Scene.pov_renderimage_path
+    del Scene.pov_list_lf_enable
     del Scene.pov_radio_enable
     del Scene.pov_radio_display_advanced
     del Scene.pov_radio_adc_bailout
@@ -836,56 +816,56 @@ def unregister():
     del Scene.pov_radio_nearest_count
     del Scene.pov_radio_normal
     del Scene.pov_radio_recursion_limit
-    del Scene.pov_radio_pretrace_start  # MR
-    del Scene.pov_radio_pretrace_end  # MR
-    del Scene.pov_media_enable  # MR
-    del Scene.pov_media_samples  # MR
-    del Scene.pov_media_color  # MR
-    del Scene.pov_baking_enable  # MR
-    del Scene.pov_max_trace_level  # MR
-    del Scene.pov_photon_spacing  # MR
-    del Scene.pov_photon_max_trace_level  # MR
-    del Scene.pov_photon_adc_bailout  # MR
-    del Scene.pov_photon_gather_min  # MR
-    del Scene.pov_photon_gather_max  # MR
-    del Scene.pov_antialias_enable  # CR
-    del Scene.pov_antialias_method  # CR
-    del Scene.pov_antialias_depth  # CR
-    del Scene.pov_antialias_threshold  # CR
-    del Scene.pov_antialias_gamma  # CR
-    del Scene.pov_jitter_enable  # CR
-    del Scene.pov_jitter_amount  # CR
-    del Scene.pov_command_line_switches  # CR
-    del Scene.pov_indentation_character  # CR
-    del Scene.pov_indentation_spaces  # CR
-    del Scene.pov_comments_enable  # CR
-    del Mat.pov_irid_enable  # MR
-    del Mat.pov_mirror_use_IOR  # MR
-    del Mat.pov_mirror_metallic  # MR
-    del Mat.pov_conserve_energy  # MR
-    del Mat.pov_irid_amount  # MR
-    del Mat.pov_irid_thickness  # MR
-    del Mat.pov_irid_turbulence  # MR
-    del Mat.pov_interior_fade_color  # MR
-    del Mat.pov_caustics_enable  # MR
-    del Mat.pov_fake_caustics  # MR
-    del Mat.pov_fake_caustics_power  # MR
-    del Mat.pov_photons_refraction  # MR
-    del Mat.pov_photons_dispersion  # MR
-    del Mat.pov_photons_reflection  # MR
-    del Mat.pov_refraction_type  # MR
-    del Mat.pov_replacement_text  # MR
-    del Tex.pov_tex_gamma_enable  # MR
-    del Tex.pov_tex_gamma_value  # MR
-    del Tex.pov_replacement_text  # MR
-    del Obj.pov_importance_value  # MR
-    del Obj.pov_collect_photons  # MR
-    del Obj.pov_replacement_text  # MR
-    del Cam.pov_dof_enable  # MR
-    del Cam.pov_dof_aperture  # MR
-    del Cam.pov_dof_samples_min  # MR
-    del Cam.pov_dof_samples_max  # MR
-    del Cam.pov_dof_variance  # MR
-    del Cam.pov_dof_confidence  # MR
-    del Cam.pov_replacement_text  # MR
-    del Text.pov_custom_code  # MR
+    del Scene.pov_radio_pretrace_start
+    del Scene.pov_radio_pretrace_end
+    del Scene.pov_media_enable
+    del Scene.pov_media_samples
+    del Scene.pov_media_color
+    del Scene.pov_baking_enable
+    del Scene.pov_max_trace_level
+    del Scene.pov_photon_spacing
+    del Scene.pov_photon_max_trace_level
+    del Scene.pov_photon_adc_bailout
+    del Scene.pov_photon_gather_min
+    del Scene.pov_photon_gather_max
+    del Scene.pov_antialias_enable
+    del Scene.pov_antialias_method
+    del Scene.pov_antialias_depth
+    del Scene.pov_antialias_threshold
+    del Scene.pov_antialias_gamma
+    del Scene.pov_jitter_enable
+    del Scene.pov_jitter_amount
+    del Scene.pov_command_line_switches
+    del Scene.pov_indentation_character
+    del Scene.pov_indentation_spaces
+    del Scene.pov_comments_enable
+    del Mat.pov_irid_enable
+    del Mat.pov_mirror_use_IOR
+    del Mat.pov_mirror_metallic
+    del Mat.pov_conserve_energy
+    del Mat.pov_irid_amount
+    del Mat.pov_irid_thickness
+    del Mat.pov_irid_turbulence
+    del Mat.pov_interior_fade_color
+    del Mat.pov_caustics_enable
+    del Mat.pov_fake_caustics
+    del Mat.pov_fake_caustics_power
+    del Mat.pov_photons_refraction
+    del Mat.pov_photons_dispersion
+    del Mat.pov_photons_reflection
+    del Mat.pov_refraction_type
+    del Mat.pov_replacement_text
+    del Tex.pov_tex_gamma_enable
+    del Tex.pov_tex_gamma_value
+    del Tex.pov_replacement_text
+    del Obj.pov_importance_value
+    del Obj.pov_collect_photons
+    del Obj.pov_replacement_text
+    del Cam.pov_dof_enable
+    del Cam.pov_dof_aperture
+    del Cam.pov_dof_samples_min
+    del Cam.pov_dof_samples_max
+    del Cam.pov_dof_variance
+    del Cam.pov_dof_confidence
+    del Cam.pov_replacement_text
+    del Text.pov_custom_code
-- 
GitLab