diff --git a/render_povray/__init__.py b/render_povray/__init__.py
index 7a6332ee8568d986c10e21df1db72bac1f823317..fded5cffe93ab49bbebfa0c4b1e74f3c4b549001 100644
--- a/render_povray/__init__.py
+++ b/render_povray/__init__.py
@@ -25,16 +25,16 @@ Scene Description Language. The script has been split in as few files
 as possible :
 
 ___init__.py :
-    Initialize variables
+    Initialize properties
 
 update_files.py
-    Update new variables to values from older API. This file needs an update.
+    Update new variables to values from older API. This file needs an update
 
 ui.py :
-    Provide property buttons for the user to set up the variables.
+    Provide property buttons for the user to set up the variables
 
 primitives.py :
-    Display some POV native primitives in 3D view for input and output.
+    Display some POV native primitives in 3D view for input and output
 
 shading.py
     Translate shading properties to declared textures at the top of a pov file
@@ -50,7 +50,7 @@ render.py :
 
 
 Along these essential files also coexist a few additional libraries to help make
-Blender stand up to other POV IDEs such as povwin or QTPOV.
+Blender stand up to other POV IDEs such as povwin or QTPOV
     presets :
         Material (sss)
             apple.py ; chicken.py ; cream.py ; Ketchup.py ; marble.py ;
@@ -64,11 +64,14 @@ Blender stand up to other POV IDEs such as povwin or QTPOV.
             01_Clear_Blue_Sky.py ; 02_Partly_Hazy_Sky.py ; 03_Overcast_Sky.py ;
             04_Cartoony_Sky.py ; 05_Under_Water.py ;
         Light
-            01_(5400K)_Direct_Sun.py ; 02_(5400K)_High_Noon_Sun.py ;
+            01_(4800K)_Direct_Sun.py ;
+            02_(5400K)_High_Noon_Sun.py ;
             03_(6000K)_Daylight_Window.py ;
             04_(6000K)_2500W_HMI_(Halogen_Metal_Iodide).py ;
-            05_(4000K)_100W_Metal_Halide.py ; 06_(3200K)_100W_Quartz_Halogen.py ;
-            07_(2850K)_100w_Tungsten.py ; 08_(2600K)_40w_Tungsten.py ;
+            05_(4000K)_100W_Metal_Halide.py ;
+            06_(3200K)_100W_Quartz_Halogen.py ;
+            07_(2850K)_100w_Tungsten.py ;
+            08_(2600K)_40w_Tungsten.py ;
             09_(5000K)_75W_Full_Spectrum_Fluorescent_T12.py ;
             10_(4300K)_40W_Vintage_Fluorescent_T12.py ;
             11_(5000K)_18W_Standard_Fluorescent_T8 ;
@@ -78,10 +81,13 @@ Blender stand up to other POV IDEs such as povwin or QTPOV.
             15_(3200K)_40W_Induction_Fluorescent.py ;
             16_(2100K)_150W_High_Pressure_Sodium.py ;
             17_(1700K)_135W_Low_Pressure_Sodium.py ;
-            18_(6800K)_175W_Mercury_Vapor.py ; 19_(5200K)_700W_Carbon_Arc.py ;
-            20_(6500K)_15W_LED_Spot.py ; 21_(2700K)_7W_OLED_Panel.py ;
+            18_(6800K)_175W_Mercury_Vapor.py ;
+            19_(5200K)_700W_Carbon_Arc.py ;
+            20_(6500K)_15W_LED_Spot.py ;
+            21_(2700K)_7W_OLED_Panel.py ;
             22_(30000K)_40W_Black_Light_Fluorescent.py ;
-            23_(30000K)_40W_Black_Light_Bulb.py; 24_(1850K)_Candle.py
+            23_(30000K)_40W_Black_Light_Bulb.py;
+            24_(1850K)_Candle.py
     templates:
         abyss.pov ; biscuit.pov ; bsp_Tango.pov ; chess2.pov ;
         cornell.pov ; diffract.pov ; diffuse_back.pov ; float5 ;
@@ -98,20 +104,23 @@ bl_info = {
     "Bastien Montagne, "
     "Constantin Rahn, "
     "Silvio Falcinelli",
-    "version": (0, 1, 0),
+    "version": (0, 1, 1),
     "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)",
 }
 
 if "bpy" in locals():
     import importlib
 
     importlib.reload(ui)
+    importlib.reload(nodes)
     importlib.reload(render)
     importlib.reload(shading)
+    importlib.reload(primitives)
     importlib.reload(update_files)
 
 else:
@@ -121,13 +130,18 @@ else:
     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
+    from bpy.types import (
+        AddonPreferences,
+        PropertyGroup,
+        NodeSocket,
+    )
+
     from bpy.props import (
+        FloatVectorProperty,
         StringProperty,
         BoolProperty,
         IntProperty,
         FloatProperty,
-        FloatVectorProperty,
         EnumProperty,
         PointerProperty,
         CollectionProperty,
@@ -137,39 +151,94 @@ else:
 
 def string_strip_hyphen(name):
 
-    """Remove hyphen characters from a string to avoid POV errors."""
+    """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):
-    mat = context.scene.view_layers["View Layer"].objects.active.active_material
-    index = mat.pov.active_texture_index
-    name = mat.pov_texture_slots[index].name
-    newname = mat.pov_texture_slots[index].texture
-    tex = bpy.data.textures[name]
-    tex.name = newname
-    mat.pov_texture_slots[index].name = newname
+
+    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):
-    mat = context.scene.view_layers["View Layer"].objects.active.active_material
-    index = mat.pov.active_texture_index
-    name = mat.pov_texture_slots[index].texture_search
+    """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]
-        mat.pov_texture_slots[index].name = name
-        mat.pov_texture_slots[index].texture = 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
 
 
+
 ###############################################################################
 # Scene POV properties.
 ###############################################################################
 class RenderPovSettingsScene(PropertyGroup):
 
-    """Declare scene level properties controllable in UI and translated to POV."""
+    """Declare scene level properties controllable in UI and translated to POV"""
 
     # Linux SDL-window enable
     sdl_window_enable: BoolProperty(
@@ -770,7 +839,7 @@ class RenderPovSettingsScene(PropertyGroup):
         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=1.8
+        min=0.0, max=1000.0, soft_min=0.1, soft_max=10.0, default=10.0
     )
 
     radio_gray_threshold: FloatProperty(
@@ -837,14 +906,15 @@ class RenderPovSettingsScene(PropertyGroup):
         name="Pretrace Start",
         description="Fraction of the screen width which sets the size of the "
         "blocks in the mosaic preview first pass",
-        min=0.01, max=1.00, soft_min=0.02, soft_max=1.0, default=0.08
+        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.04, precision=3
+        min=0.000925, max=1.00, soft_min=0.01, soft_max=1.00, default=0.004, precision=3
     )
 
 ###############################################################################
@@ -856,19 +926,28 @@ class MaterialTextureSlot(PropertyGroup):
     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)
-    texture_search : StringProperty(update=active_texture_name_from_search)
+    # 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 = 0.0,
+        default = 1.0,
     )
 
     ambient_factor: FloatProperty(
         name="",
         description="Amount texture affects ambient",
-        default = 0.0,
+        default = 1.0,
     )
 
     bump_method: EnumProperty(
@@ -897,49 +976,49 @@ class MaterialTextureSlot(PropertyGroup):
     density_factor: FloatProperty(
         name="",
         description="Amount texture affects density",
-        default = 0.0,
+        default = 1.0,
     )
 
     diffuse_color_factor: FloatProperty(
         name="",
         description="Amount texture affects diffuse color",
-        default = 0.0,
+        default = 1.0,
     )
 
     diffuse_factor: FloatProperty(
         name="",
         description="Amount texture affects diffuse reflectivity",
-        default = 0.0,
+        default = 1.0,
     )
 
     displacement_factor: FloatProperty(
         name="",
         description="Amount texture displaces the surface",
-        default = 0.0,
+        default = 0.2,
     )
 
     emission_color_factor: FloatProperty(
         name="",
         description="Amount texture affects emission color",
-        default = 0.0,
+        default = 1.0,
     )
 
     emission_factor: FloatProperty(
         name="",
         description="Amount texture affects emission",
-        default = 0.0,
+        default = 1.0,
     )
 
     emit_factor: FloatProperty(
         name="",
         description="Amount texture affects emission",
-        default = 0.0,
+        default = 1.0,
     )
 
     hardness_factor: FloatProperty(
         name="",
         description="Amount texture affects hardness",
-        default = 0.0,
+        default = 1.0,
     )
 
     mapping: EnumProperty(
@@ -985,13 +1064,13 @@ class MaterialTextureSlot(PropertyGroup):
     mirror_factor: FloatProperty(
         name="",
         description="Amount texture affects mirror color",
-        default = 0.0,
+        default = 1.0,
     )
 
     normal_factor: FloatProperty(
         name="",
         description="Amount texture affects normal values",
-        default = 0.0,
+        default = 1.0,
     )
 
     normal_map_space: EnumProperty(
@@ -1013,39 +1092,65 @@ class MaterialTextureSlot(PropertyGroup):
     raymir_factor: FloatProperty(
         name="",
         description="Amount texture affects ray mirror",
-        default = 0.0,
+        default = 1.0,
     )
 
     reflection_color_factor: FloatProperty(
         name="",
         description="Amount texture affects color of out-scattered light",
-        default = 0.0,
+        default = 1.0,
     )
 
     reflection_factor: FloatProperty(
         name="",
         description="Amount texture affects brightness of out-scattered light",
-        default = 0.0,
+        default = 1.0,
     )
 
     scattering_factor: FloatProperty(
         name="",
         description="Amount texture affects scattering",
-        default = 0.0,
+        default = 1.0,
     )
 
     specular_color_factor: FloatProperty(
         name="",
         description="Amount texture affects specular color",
-        default = 0.0,
+        default = 1.0,
     )
 
     specular_factor: FloatProperty(
         name="",
         description="Amount texture affects specular reflectivity",
-        default = 0.0,
+        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="",
@@ -1068,13 +1173,13 @@ class MaterialTextureSlot(PropertyGroup):
     translucency_factor: FloatProperty(
         name="",
         description="Amount texture affects translucency",
-        default = 0.0,
+        default = 1.0,
     )
 
     transmission_color_factor: FloatProperty(
         name="",
         description="Amount texture affects result color after light has been scattered/absorbed",
-        default = 0.0,
+        default = 1.0,
     )
 
     use: BoolProperty(
@@ -1095,6 +1200,12 @@ class MaterialTextureSlot(PropertyGroup):
         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",
@@ -1110,7 +1221,7 @@ class MaterialTextureSlot(PropertyGroup):
     use_map_color_diffuse: BoolProperty(
         name="",
         description="Causes the texture to affect basic color of the material",
-        default = False,
+        default = True,
     )
 
     use_map_color_emission: BoolProperty(
@@ -1234,7 +1345,7 @@ class MaterialTextureSlot(PropertyGroup):
     )
 
 
-#######################################"
+#######################################
 
     blend_factor: FloatProperty(
         name="Blend",
@@ -1328,10 +1439,10 @@ bpy.types.ID.texture_context = EnumProperty(
     default = 'MATERIAL',
 )
 
-bpy.types.ID.active_texture_index = IntProperty(
-    name = "Index for texture_slots",
-    default = 0,
-)
+# 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."""
@@ -1360,6 +1471,7 @@ class RenderPovSettingsMaterial(PropertyGroup):
     active_texture_index: IntProperty(
         name = "Index for texture_slots",
         default = 0,
+        update = brush_texture_update
     )
 
     transparency_method: EnumProperty(
@@ -2123,7 +2235,7 @@ class MaterialRaytraceTransparency(PropertyGroup):
 
     gloss_samples: IntProperty(
         name="Samples",
-        description="Number of cone samples averaged for blurry refractions",
+        description="frequency of the noise sample used for blurry refractions",
         min=0, max=1024, default=18
     )
 
@@ -2205,8 +2317,8 @@ class MaterialRaytraceMirror(PropertyGroup):
     )
 
     gloss_samples: IntProperty(
-        name="Samples",
-        description="Number of cone samples averaged for blurry reflections",
+        name="Noise",
+        description="Frequency of the noise pattern bumps averaged for blurry reflections",
         min=0, max=1024, default=18,
     )
 
@@ -3223,7 +3335,7 @@ class MaterialStrandSettings(PropertyGroup):
 # Povray Nodes
 ###############################################################################
 
-class PovraySocketUniversal(bpy.types.NodeSocket):
+class PovraySocketUniversal(NodeSocket):
     bl_idname = 'PovraySocketUniversal'
     bl_label = 'Povray Socket'
     value_unlimited: bpy.props.FloatProperty(default=0.0)
@@ -3276,7 +3388,7 @@ class PovraySocketUniversal(bpy.types.NodeSocket):
     def draw_color(self, context, node):
         return (1, 0, 0, 1)
 
-class PovraySocketFloat_0_1(bpy.types.NodeSocket):
+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)
@@ -3289,7 +3401,7 @@ class PovraySocketFloat_0_1(bpy.types.NodeSocket):
     def draw_color(self, context, node):
         return (0.5, 0.7, 0.7, 1)
 
-class PovraySocketFloat_0_10(bpy.types.NodeSocket):
+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)
@@ -3304,7 +3416,7 @@ class PovraySocketFloat_0_10(bpy.types.NodeSocket):
     def draw_color(self, context, node):
         return (0.65, 0.65, 0.65, 1)
 
-class PovraySocketFloat_10(bpy.types.NodeSocket):
+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)
@@ -3319,7 +3431,7 @@ class PovraySocketFloat_10(bpy.types.NodeSocket):
     def draw_color(self, context, node):
         return (0.65, 0.65, 0.65, 1)
 
-class PovraySocketFloatPositive(bpy.types.NodeSocket):
+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)
@@ -3331,7 +3443,7 @@ class PovraySocketFloatPositive(bpy.types.NodeSocket):
     def draw_color(self, context, node):
         return (0.045, 0.005, 0.136, 1)
 
-class PovraySocketFloat_000001_10(bpy.types.NodeSocket):
+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)
@@ -3343,7 +3455,7 @@ class PovraySocketFloat_000001_10(bpy.types.NodeSocket):
     def draw_color(self, context, node):
         return (1, 0, 0, 1)
 
-class PovraySocketFloatUnlimited(bpy.types.NodeSocket):
+class PovraySocketFloatUnlimited(NodeSocket):
     bl_idname = 'PovraySocketFloatUnlimited'
     bl_label = 'Povray Socket'
     default_value: bpy.props.FloatProperty(default = 0.0)
@@ -3355,7 +3467,7 @@ class PovraySocketFloatUnlimited(bpy.types.NodeSocket):
     def draw_color(self, context, node):
         return (0.7, 0.7, 1, 1)
 
-class PovraySocketInt_1_9(bpy.types.NodeSocket):
+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)
@@ -3367,7 +3479,7 @@ class PovraySocketInt_1_9(bpy.types.NodeSocket):
     def draw_color(self, context, node):
         return (1, 0.7, 0.7, 1)
 
-class PovraySocketInt_0_256(bpy.types.NodeSocket):
+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)
@@ -3380,7 +3492,7 @@ class PovraySocketInt_0_256(bpy.types.NodeSocket):
         return (0.5, 0.5, 0.5, 1)
 
 
-class PovraySocketPattern(bpy.types.NodeSocket):
+class PovraySocketPattern(NodeSocket):
     bl_idname = 'PovraySocketPattern'
     bl_label = 'Povray Socket'
 
@@ -3417,7 +3529,7 @@ class PovraySocketPattern(bpy.types.NodeSocket):
     def draw_color(self, context, node):
         return (1, 1, 1, 1)
 
-class PovraySocketColor(bpy.types.NodeSocket):
+class PovraySocketColor(NodeSocket):
     bl_idname = 'PovraySocketColor'
     bl_label = 'Povray Socket'
 
@@ -3434,7 +3546,7 @@ class PovraySocketColor(bpy.types.NodeSocket):
     def draw_color(self, context, node):
         return (1, 1, 0, 1)
 
-class PovraySocketColorRGBFT(bpy.types.NodeSocket):
+class PovraySocketColorRGBFT(NodeSocket):
     bl_idname = 'PovraySocketColorRGBFT'
     bl_label = 'Povray Socket'
 
@@ -3452,7 +3564,7 @@ class PovraySocketColorRGBFT(bpy.types.NodeSocket):
     def draw_color(self, context, node):
         return (1, 1, 0, 1)
 
-class PovraySocketTexture(bpy.types.NodeSocket):
+class PovraySocketTexture(NodeSocket):
     bl_idname = 'PovraySocketTexture'
     bl_label = 'Povray Socket'
     default_value: bpy.props.IntProperty()
@@ -3464,7 +3576,7 @@ class PovraySocketTexture(bpy.types.NodeSocket):
 
 
 
-class PovraySocketTransform(bpy.types.NodeSocket):
+class PovraySocketTransform(NodeSocket):
     bl_idname = 'PovraySocketTransform'
     bl_label = 'Povray Socket'
     default_value: bpy.props.IntProperty(min=0,max=255,default=0)
@@ -3474,7 +3586,7 @@ class PovraySocketTransform(bpy.types.NodeSocket):
     def draw_color(self, context, node):
         return (99/255, 99/255, 199/255, 1)
 
-class PovraySocketNormal(bpy.types.NodeSocket):
+class PovraySocketNormal(NodeSocket):
     bl_idname = 'PovraySocketNormal'
     bl_label = 'Povray Socket'
     default_value: bpy.props.IntProperty(min=0,max=255,default=0)
@@ -3484,7 +3596,7 @@ class PovraySocketNormal(bpy.types.NodeSocket):
     def draw_color(self, context, node):
         return (0.65, 0.65, 0.65, 1)
 
-class PovraySocketSlope(bpy.types.NodeSocket):
+class PovraySocketSlope(NodeSocket):
     bl_idname = 'PovraySocketSlope'
     bl_label = 'Povray Socket'
     default_value: bpy.props.FloatProperty(min = 0.0, max = 1.0)
@@ -3500,7 +3612,7 @@ class PovraySocketSlope(bpy.types.NodeSocket):
     def draw_color(self, context, node):
         return (0, 0, 0, 1)
 
-class PovraySocketMap(bpy.types.NodeSocket):
+class PovraySocketMap(NodeSocket):
     bl_idname = 'PovraySocketMap'
     bl_label = 'Povray Socket'
     default_value: bpy.props.StringProperty()
@@ -3774,7 +3886,7 @@ class RenderPovSettingsTexture(PropertyGroup):
             ('checker', "Checker", "", 'PLUGIN', 34),
             ('hexagon', "Hexagon", "", 'PLUGIN', 35),
             ('object', "Mesh", "", 'PLUGIN', 36),
-            ('emulator', "Internal Emulator", "", 'PLUG', 37)
+            ('emulator', "Blender Type Emulator", "", 'SCRIPTPLUGINS', 37)
         ),
         default='emulator',
     )
@@ -5167,7 +5279,7 @@ class RenderPovSettingsWorld(PropertyGroup):
         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"
+            ('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"
@@ -5215,12 +5327,27 @@ class RenderPovSettingsWorld(PropertyGroup):
     )
     active_texture_index: IntProperty(
         name = "Index for texture_slots",
-        default = 0
+        default = 0,
+        update = brush_texture_update
     )
 
-
 class WorldTextureSlot(PropertyGroup):
-    """Declare world texture slot properties controllable in UI and translated to POV."""
+    """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",
@@ -5241,6 +5368,31 @@ class WorldTextureSlot(PropertyGroup):
         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",
@@ -5308,7 +5460,7 @@ for i in range(18):  # length of world texture slots
 
 class MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist(bpy.types.UIList):
     # texture_slots:
-    index: bpy.props.IntProperty(name='index')
+    #index: bpy.props.IntProperty(name='index')
     # foo  = random prop
     def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
         ob = data
@@ -5385,11 +5537,44 @@ class PovrayPreferences(AddonPreferences):
         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 = (
@@ -5451,7 +5636,7 @@ def register():
     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.texture_slots = CollectionProperty(type=WorldTextureSlot)
+    bpy.types.World.pov_texture_slots = CollectionProperty(type=WorldTextureSlot)
     bpy.types.Text.pov = PointerProperty(type=RenderPovSettingsText)
 
 
@@ -5468,6 +5653,7 @@ def unregister():
     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
 
diff --git a/render_povray/nodes.py b/render_povray/nodes.py
index be535db30c0270361b36a9be018bfc2e6852cf23..bbdb97545683d0fc425c258717aada67afd42e62 100644
--- a/render_povray/nodes.py
+++ b/render_povray/nodes.py
@@ -21,7 +21,14 @@
 import bpy
 
 from bpy.utils import register_class
-from bpy.types import Node, ShaderNodeTree, CompositorNodeTree, TextureNodeTree#, NodeSocket
+from bpy.types import (
+        Node,
+        ShaderNodeTree,
+        CompositorNodeTree,
+        TextureNodeTree,
+        #NodeSocket,
+        Operator,
+        )
 from bpy.props import (
         StringProperty,
         BoolProperty,
@@ -1025,7 +1032,7 @@ class TextureOutputNode(Node, TextureNodeTree):
 ##################################################################################
 
 
-class NODE_OT_iso_add(bpy.types.Operator):
+class NODE_OT_iso_add(Operator):
     bl_idname = "pov.nodeisoadd"
     bl_label = "Create iso props"
 
@@ -1042,7 +1049,7 @@ class NODE_OT_iso_add(bpy.types.Operator):
         isonode.label = ob.name
         return {'FINISHED'}
 
-class NODE_OT_map_create(bpy.types.Operator):
+class NODE_OT_map_create(Operator):
     bl_idname = "node.map_create"
     bl_label = "Create map"
 
@@ -1067,7 +1074,7 @@ class NODE_OT_map_create(bpy.types.Operator):
         mat = context.object.active_material
         layout.prop(mat.pov,"inputs_number")
 
-class NODE_OT_povray_node_texture_map_add(bpy.types.Operator):
+class NODE_OT_povray_node_texture_map_add(Operator):
     bl_idname = "pov.nodetexmapadd"
     bl_label = "Texture map"
 
@@ -1091,7 +1098,7 @@ class NODE_OT_povray_node_texture_map_add(bpy.types.Operator):
         return {'FINISHED'}
 
 
-class NODE_OT_povray_node_output_add(bpy.types.Operator):
+class NODE_OT_povray_node_output_add(Operator):
     bl_idname = "pov.nodeoutputadd"
     bl_label = "Output"
 
@@ -1105,7 +1112,7 @@ class NODE_OT_povray_node_output_add(bpy.types.Operator):
         tmap.label="Output"
         return {'FINISHED'}
 
-class NODE_OT_povray_node_layered_add(bpy.types.Operator):
+class NODE_OT_povray_node_layered_add(Operator):
     bl_idname = "pov.nodelayeredadd"
     bl_label = "Layered material"
 
@@ -1116,7 +1123,7 @@ class NODE_OT_povray_node_layered_add(bpy.types.Operator):
         tmap.label="Layered material"
         return {'FINISHED'}
 
-class NODE_OT_povray_input_add(bpy.types.Operator):
+class NODE_OT_povray_input_add(Operator):
     bl_idname = "pov.nodeinputadd"
     bl_label = "Add entry"
 
@@ -1141,7 +1148,7 @@ class NODE_OT_povray_input_add(bpy.types.Operator):
 
         return {'FINISHED'}
 
-class NODE_OT_povray_input_remove(bpy.types.Operator):
+class NODE_OT_povray_input_remove(Operator):
     bl_idname = "pov.nodeinputremove"
     bl_label = "Remove input"
 
@@ -1159,7 +1166,7 @@ class NODE_OT_povray_input_remove(bpy.types.Operator):
                     els.remove(el)
         return {'FINISHED'}
 
-class NODE_OT_povray_image_open(bpy.types.Operator):
+class NODE_OT_povray_image_open(Operator):
     bl_idname = "pov.imageopen"
     bl_label = "Open"
 
@@ -1181,7 +1188,7 @@ class NODE_OT_povray_image_open(bpy.types.Operator):
         return {'FINISHED'}
 
 
-# class TEXTURE_OT_povray_open_image(bpy.types.Operator):
+# class TEXTURE_OT_povray_open_image(Operator):
     # bl_idname = "pov.openimage"
     # bl_label = "Open Image"
 
@@ -1204,7 +1211,7 @@ class NODE_OT_povray_image_open(bpy.types.Operator):
         # view_layer.update()
         # return {'FINISHED'}
 
-class PovrayPatternNode(bpy.types.Operator):
+class PovrayPatternNode(Operator):
     bl_idname = "pov.patternnode"
     bl_label  = "Pattern"
 
@@ -1259,7 +1266,7 @@ class PovrayPatternNode(bpy.types.Operator):
         context.window_manager.modal_handler_add(self)
         return {'RUNNING_MODAL'}
 
-class UpdatePreviewMaterial(bpy.types.Operator):
+class UpdatePreviewMaterial(Operator):
     '''Operator update preview material'''
     bl_idname = "node.updatepreview"
     bl_label = "Update preview"
@@ -1283,7 +1290,7 @@ class UpdatePreviewMaterial(bpy.types.Operator):
         context.window_manager.modal_handler_add(self)
         return {'RUNNING_MODAL'}
 
-class UpdatePreviewKey(bpy.types.Operator):
+class UpdatePreviewKey(Operator):
     '''Operator update preview keymap'''
     bl_idname = "wm.updatepreviewkey"
     bl_label = "Activate RMB"
diff --git a/render_povray/primitives.py b/render_povray/primitives.py
index a9d68d448c30bc94c80ca19f465386ed709eb622..6d864220306446ffa6c31d1d2ca813c7e4c89f2c 100644
--- a/render_povray/primitives.py
+++ b/render_povray/primitives.py
@@ -26,7 +26,7 @@ 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.types import Operator
 
 from bpy.props import (
     StringProperty,
@@ -41,6 +41,7 @@ from bpy.props import (
 
 from mathutils import Vector, Matrix
 
+
 # import collections
 
 
@@ -60,7 +61,7 @@ def pov_define_mesh(mesh, verts, edges, faces, name, hide_geometry=True):
     return mesh
 
 
-class POVRAY_OT_lathe_add(bpy.types.Operator):
+class POVRAY_OT_lathe_add(Operator):
     """Add the representation of POV lathe using a screw modifier."""
 
     bl_idname = "pov.addlathe"
@@ -212,7 +213,7 @@ def pov_superellipsoid_define(context, op, ob):
         bpy.ops.object.mode_set(mode="OBJECT")
 
 
-class POVRAY_OT_superellipsoid_add(bpy.types.Operator):
+class POVRAY_OT_superellipsoid_add(Operator):
     """Add the representation of POV superellipsoid using the pov_superellipsoid_define() function."""
 
     bl_idname = "pov.addsuperellipsoid"
@@ -286,7 +287,7 @@ class POVRAY_OT_superellipsoid_add(bpy.types.Operator):
         return {'FINISHED'}
 
 
-class POVRAY_OT_superellipsoid_update(bpy.types.Operator):
+class POVRAY_OT_superellipsoid_update(Operator):
     """Update the superellipsoid.
 
     Delete its previous proxy geometry and rerun pov_superellipsoid_define() function
@@ -455,7 +456,7 @@ def pov_supertorus_define(context, op, ob):
         ob.pov.st_edit = st_edit
 
 
-class POVRAY_OT_supertorus_add(bpy.types.Operator):
+class POVRAY_OT_supertorus_add(Operator):
     """Add the representation of POV supertorus using the pov_supertorus_define() function."""
 
     bl_idname = "pov.addsupertorus"
@@ -530,7 +531,7 @@ class POVRAY_OT_supertorus_add(bpy.types.Operator):
         return {'FINISHED'}
 
 
-class POVRAY_OT_supertorus_update(bpy.types.Operator):
+class POVRAY_OT_supertorus_update(Operator):
     """Update the supertorus.
 
     Delete its previous proxy geometry and rerun pov_supetorus_define() function
@@ -566,7 +567,7 @@ class POVRAY_OT_supertorus_update(bpy.types.Operator):
 
 
 #########################################################################################################
-class POVRAY_OT_loft_add(bpy.types.Operator):
+class POVRAY_OT_loft_add(Operator):
     """Create the representation of POV loft using Blender curves."""
 
     bl_idname = "pov.addloft"
@@ -695,7 +696,7 @@ class POVRAY_OT_loft_add(bpy.types.Operator):
         return {'FINISHED'}
 
 
-class POVRAY_OT_plane_add(bpy.types.Operator):
+class POVRAY_OT_plane_add(Operator):
     """Add the representation of POV infinite plane using just a very big Blender Plane.
 
     Flag its primitive type with a specific pov.object_as attribute and lock edit mode
@@ -725,7 +726,7 @@ class POVRAY_OT_plane_add(bpy.types.Operator):
         return {'FINISHED'}
 
 
-class POVRAY_OT_box_add(bpy.types.Operator):
+class POVRAY_OT_box_add(Operator):
     """Add the representation of POV box using a simple Blender mesh cube.
 
     Flag its primitive type with a specific pov.object_as attribute and lock edit mode
@@ -796,7 +797,7 @@ def pov_cylinder_define(context, op, ob, radius, loc, loc_cap):
     bpy.ops.object.shade_smooth()
 
 
-class POVRAY_OT_cylinder_add(bpy.types.Operator):
+class POVRAY_OT_cylinder_add(Operator):
     """Add the representation of POV cylinder using pov_cylinder_define() function.
 
     Use imported_cyl_loc when this operator is run by POV importer."""
@@ -846,7 +847,7 @@ class POVRAY_OT_cylinder_add(bpy.types.Operator):
         return {'FINISHED'}
 
 
-class POVRAY_OT_cylinder_update(bpy.types.Operator):
+class POVRAY_OT_cylinder_update(Operator):
     """Update the POV cylinder.
 
     Delete its previous proxy geometry and rerun pov_cylinder_define() function
@@ -932,7 +933,7 @@ def pov_sphere_define(context, op, ob, loc):
         bpy.ops.object.mode_set(mode="OBJECT")
 
 
-class POVRAY_OT_sphere_add(bpy.types.Operator):
+class POVRAY_OT_sphere_add(Operator):
     """Add the representation of POV sphere using pov_sphere_define() function.
 
     Use imported_loc when this operator is run by POV importer."""
@@ -989,7 +990,7 @@ class POVRAY_OT_sphere_add(bpy.types.Operator):
     # return {'FINISHED'}
 
 
-class POVRAY_OT_sphere_update(bpy.types.Operator):
+class POVRAY_OT_sphere_update(Operator):
     """Update the POV sphere.
 
     Delete its previous proxy geometry and rerun pov_sphere_define() function
@@ -1084,7 +1085,7 @@ def pov_cone_define(context, op, ob):
         ob.pov.cone_cap_z = zc
 
 
-class POVRAY_OT_cone_add(bpy.types.Operator):
+class POVRAY_OT_cone_add(Operator):
     """Add the representation of POV cone using pov_cone_define() function."""
 
     bl_idname = "pov.cone_add"
@@ -1139,7 +1140,7 @@ class POVRAY_OT_cone_add(bpy.types.Operator):
         return {'FINISHED'}
 
 
-class POVRAY_OT_cone_update(bpy.types.Operator):
+class POVRAY_OT_cone_update(Operator):
     """Update the POV cone.
 
     Delete its previous proxy geometry and rerun pov_cone_define() function
@@ -1177,7 +1178,7 @@ class POVRAY_OT_cone_update(bpy.types.Operator):
 ########################################ISOSURFACES##################################
 
 
-class POVRAY_OT_isosurface_box_add(bpy.types.Operator):
+class POVRAY_OT_isosurface_box_add(Operator):
     """Add the representation of POV isosurface box using also just a Blender mesh cube.
 
     Flag its primitive type with a specific pov.object_as attribute and lock edit mode
@@ -1207,7 +1208,7 @@ class POVRAY_OT_isosurface_box_add(bpy.types.Operator):
         return {'FINISHED'}
 
 
-class POVRAY_OT_isosurface_sphere_add(bpy.types.Operator):
+class POVRAY_OT_isosurface_sphere_add(Operator):
     """Add the representation of POV isosurface sphere by a Blender mesh icosphere.
 
     Flag its primitive type with a specific pov.object_as attribute and lock edit mode
@@ -1238,7 +1239,7 @@ class POVRAY_OT_isosurface_sphere_add(bpy.types.Operator):
         return {'FINISHED'}
 
 
-class POVRAY_OT_sphere_sweep_add(bpy.types.Operator):
+class POVRAY_OT_sphere_sweep_add(Operator):
     """Add the representation of POV sphere_sweep using a Blender NURBS curve.
 
     Flag its primitive type with a specific ob.pov.curveshape attribute and
@@ -1264,7 +1265,7 @@ class POVRAY_OT_sphere_sweep_add(bpy.types.Operator):
         return {'FINISHED'}
 
 
-class POVRAY_OT_blob_add(bpy.types.Operator):
+class POVRAY_OT_blob_add(Operator):
     """Add the representation of POV blob using a Blender meta ball.
 
     No need to flag its primitive type as meta are exported to blobs
@@ -1284,7 +1285,7 @@ class POVRAY_OT_blob_add(bpy.types.Operator):
         return {'FINISHED'}
 
 
-class POVRAY_OT_rainbow_add(bpy.types.Operator):
+class POVRAY_OT_rainbow_add(Operator):
     """Add the representation of POV rainbow using a Blender spot light.
 
     Rainbows indeed propagate along a visibility cone.
@@ -1334,7 +1335,7 @@ class POVRAY_OT_height_field_add(bpy.types.Operator, ImportHelper):
 
     bl_idname = "pov.addheightfield"
     bl_label = "Height Field"
-    bl_description = "Add Height Field "
+    bl_description = "Add Height Field"
     bl_options = {'REGISTER', 'UNDO'}
 
     # XXX Keep it in sync with __init__'s hf Primitive
@@ -1470,7 +1471,7 @@ def pov_torus_define(context, op, ob):
         bpy.ops.object.mode_set(mode="OBJECT")
 
 
-class POVRAY_OT_torus_add(bpy.types.Operator):
+class POVRAY_OT_torus_add(Operator):
     """Add the representation of POV torus using using pov_torus_define() function."""
 
     bl_idname = "pov.addtorus"
@@ -1503,7 +1504,7 @@ class POVRAY_OT_torus_add(bpy.types.Operator):
         return {'FINISHED'}
 
 
-class POVRAY_OT_torus_update(bpy.types.Operator):
+class POVRAY_OT_torus_update(Operator):
     """Update the POV torus.
 
     Delete its previous proxy geometry and rerun pov_torus_define() function
@@ -1536,7 +1537,7 @@ class POVRAY_OT_torus_update(bpy.types.Operator):
 ###################################################################################
 
 
-class POVRAY_OT_prism_add(bpy.types.Operator):
+class POVRAY_OT_prism_add(Operator):
     """Add the representation of POV prism using using an extruded curve."""
 
     bl_idname = "pov.addprism"
@@ -1662,7 +1663,7 @@ def pov_parametric_define(context, op, ob):
         bpy.ops.object.mode_set(mode="OBJECT")
 
 
-class POVRAY_OT_parametric_add(bpy.types.Operator):
+class POVRAY_OT_parametric_add(Operator):
     """Add the representation of POV parametric surfaces using pov_parametric_define() function."""
 
     bl_idname = "pov.addparametric"
@@ -1698,7 +1699,7 @@ class POVRAY_OT_parametric_add(bpy.types.Operator):
         return {'FINISHED'}
 
 
-class POVRAY_OT_parametric_update(bpy.types.Operator):
+class POVRAY_OT_parametric_update(Operator):
     """Update the representation of POV parametric surfaces.
 
     Delete its previous proxy geometry and rerun pov_parametric_define() function
@@ -1731,7 +1732,7 @@ class POVRAY_OT_parametric_update(bpy.types.Operator):
 #######################################################################
 
 
-class POVRAY_OT_shape_polygon_to_circle_add(bpy.types.Operator):
+class POVRAY_OT_shape_polygon_to_circle_add(Operator):
     """Add the proxy mesh for POV Polygon to circle lofting macro"""
 
     bl_idname = "pov.addpolygontocircle"
diff --git a/render_povray/render.py b/render_povray/render.py
index 6efe7291540584d588ef93c98b4fdfd51f5b3d95..f9de22e48ffbc54b91bb1c6989f651377b67908e 100644
--- a/render_povray/render.py
+++ b/render_povray/render.py
@@ -24,6 +24,10 @@ import os
 import sys
 import time
 from math import atan, pi, degrees, sqrt, cos, sin
+####################
+## Faster mesh export
+import numpy as np
+####################
 import re
 import random
 import platform  #
@@ -69,6 +73,7 @@ def imageFormat(imgF):
 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':
@@ -82,9 +87,9 @@ def imgMap(ts):
     #    image_map = " map_type 3 "
     # elif ts.mapping=="?":
     #    image_map = " map_type 4 "
-    if ts.texture.use_interpolation:
+    if ts.use_interpolation: # Available if image sampling class reactivated?
         image_map += " interpolate 2 "
-    if ts.texture.extension == 'CLIP':
+    if texdata.extension == 'CLIP':
         image_map += " once "
     # image_map += "}"
     # if ts.mapping=='CUBE':
@@ -110,12 +115,12 @@ def imgMapTransforms(ts):
     image_map_transforms = (
         "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 - (0.5 / ts.scale.x) - (ts.offset.x),
-            0.5 - (0.5 / ts.scale.y) - (ts.offset.y),
-            ts.offset.z,
+            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>" % \
@@ -137,6 +142,7 @@ def imgMapTransforms(ts):
 
 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':
@@ -146,9 +152,9 @@ def imgMapBG(wts):
     elif wts.texture_coords == 'TUBE':
         image_mapBG = " map_type 2 "
 
-    if wts.texture.use_interpolation:
+    if tex.use_interpolation:
         image_mapBG += " interpolate 2 "
-    if wts.texture.extension == 'CLIP':
+    if tex.extension == 'CLIP':
         image_mapBG += " once "
     # image_mapBG += "}"
     # if wts.mapping == 'CUBE':
@@ -386,6 +392,7 @@ def write_object_modifiers(scene, ob, File):
 
 def write_pov(filename, scene=None, info_callback=None):
     """Main export process from Blender UI to POV syntax and write to exported file """
+
     import mathutils
 
     # file = filename
@@ -690,7 +697,7 @@ def write_pov(filename, scene=None, info_callback=None):
                 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)
+                    "angle  %f\n" % ( 2 * atan(camera.data.sensor_width / 2 / camera.data.lens) * 180.0 / pi )
                 )
 
             tabWrite(
@@ -737,6 +744,7 @@ def write_pov(filename, scene=None, info_callback=None):
 
     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
@@ -2346,6 +2354,64 @@ def write_pov(filename, scene=None, info_callback=None):
 
     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 ...
@@ -2684,6 +2750,7 @@ def write_pov(filename, scene=None, info_callback=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 (
@@ -3411,6 +3478,8 @@ def write_pov(filename, scene=None, info_callback=None):
                                 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:
@@ -3593,6 +3662,14 @@ def write_pov(filename, scene=None, info_callback=None):
                             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)
@@ -4092,6 +4169,7 @@ def write_pov(filename, scene=None, info_callback=None):
 
                                         else:
                                             shading.writeTextureInfluence(
+                                                using_uberpov,
                                                 mater,
                                                 materialNames,
                                                 LocalMaterialNames,
@@ -4581,89 +4659,91 @@ def write_pov(filename, scene=None, info_callback=None):
             for (
                 t
             ) in (
-                world.texture_slots
+                world.pov_texture_slots
             ):  # risk to write several sky_spheres but maybe ok.
-                if t and t.texture.type is not None:
+                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 t.texture.type == 'IMAGE' and t.use:
-                if t and t.texture.type == 'IMAGE':
-                    image_filename = path_image(t.texture.image)
-                    if t.texture.image.filepath != image_filename:
-                        t.texture.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> "
+                    # 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"
                             % (
-                                (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,
+                                imageFormat(texturesBlend),
+                                texturesBlend,
+                                imgMapBG(t_blend),
                             )
                         )
-
-                        # 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("%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" % (t.texture.intensity)
-                    )
-                    tabWrite("}\n")
-                    # tabWrite("scale 2\n")
-                    # tabWrite("translate -1\n")
+                        tabWrite("}\n")
+                        # tabWrite("scale 2\n")
+                        # tabWrite("translate -1\n")
 
             # For only Background gradient
 
@@ -4910,7 +4990,8 @@ 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")
+    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"
@@ -5066,7 +5147,11 @@ def write_pov(filename, scene=None, info_callback=None):
     if comments:
         file.write("//--Mesh objects--\n")
 
+
+    #tbefore = time.time()
     exportMeshes(scene, sel, csg)
+    #totime = time.time() - tbefore
+    #print("exportMeshes took" + str(totime))
 
     # What follow used to happen here:
     # exportCamera()
@@ -5097,7 +5182,7 @@ def write_pov_ini(
     y = int(render.resolution_y * render.resolution_percentage * 0.01)
 
     file = open(filename_ini, "w")
-    file.write("Version=3.7\n")
+    file.write("Version=3.8\n")
     # write povray text stream to temporary file of same name with _log suffix
     # file.write("All_File='%s'\n" % filename_log)
     # DEBUG.OUT log if none specified:
@@ -5797,15 +5882,106 @@ class PovrayRender(bpy.types.RenderEngine):
 
             # print(filename_log) #bring the pov log to blender console with proper path?
             with open(
-                self._temp_file_log
+                self._temp_file_log,
+                encoding='utf-8'
             ) as f:  # The with keyword automatically closes the file when you are done
-                print(f.read())
+                msg = f.read()
+                #if isinstance(msg, str):
+                    #stdmsg = msg
+                    #decoded = False
+                #else:
+                    #if type(msg) == bytes:
+                #stdmsg = msg.split('\n')
+                #stdmsg = msg.encode('utf-8', "replace")
+                #stdmsg = msg.encode("utf-8", "replace")
+
+                #stdmsg = msg.decode(encoding)
+                    #decoded = True
+                #msg.encode('utf-8').decode('utf-8')
+                print(msg)
+                # Also print to the interactive console used in POV centric workspace
+                # To do: get a grip on new line encoding
+                # and make this a function to be used elsewhere
+                for win in bpy.context.window_manager.windows:
+                    if win.screen != None:
+                        scr = win.screen
+                        for area in scr.areas:
+                            if area.type == 'CONSOLE':
+                                #context override
+                                #ctx = {'window': win, 'screen': scr, 'area':area}#bpy.context.copy()
+                                ctx = {}
+                                ctx['area'] = area
+                                ctx['region'] = area.regions[-1]
+                                ctx['space_data'] = area.spaces.active
+                                ctx['screen'] = scr#C.screen
+                                ctx['window'] = win
+
+                                #bpy.ops.console.banner(ctx, text = "Hello world")
+                                bpy.ops.console.clear_line(ctx)
+                                stdmsg = msg.split('\n') #XXX todo , test and see
+                                for i in stdmsg:
+                                    bpy.ops.console.insert(ctx, text = i)
 
             self.update_stats("", "")
 
             if scene.pov.tempfiles_enable or scene.pov.deletefiles_enable:
                 self._cleanup()
 
+            sound_on = bpy.context.preferences.addons[
+                __package__
+            ].preferences.use_sounds
+
+            if sys.platform[:3] == "win" and sound_on:
+                # Could not find tts Windows command so playing beeps instead :-)
+                # "Korobeiniki"(Коробе́йники)
+                # aka "A-Type" Tetris theme
+                import winsound
+                winsound.Beep(494,250) #B
+                winsound.Beep(370,125) #F
+                winsound.Beep(392,125) #G
+                winsound.Beep(440,250) #A
+                winsound.Beep(392,125) #G
+                winsound.Beep(370,125) #F#
+                winsound.Beep(330,275) #E
+                winsound.Beep(330,125) #E
+                winsound.Beep(392,125) #G
+                winsound.Beep(494,275) #B
+                winsound.Beep(440,125) #A
+                winsound.Beep(392,125) #G
+                winsound.Beep(370,275) #F
+                winsound.Beep(370,125) #F
+                winsound.Beep(392,125) #G
+                winsound.Beep(440,250) #A
+                winsound.Beep(494,250) #B
+                winsound.Beep(392,250) #G
+                winsound.Beep(330,350) #E
+                time.sleep(0.5)
+                winsound.Beep(440,250) #A
+                winsound.Beep(440,150) #A
+                winsound.Beep(523,125) #D8
+                winsound.Beep(659,250) #E8
+                winsound.Beep(587,125) #D8
+                winsound.Beep(523,125) #C8
+                winsound.Beep(494,250) #B
+                winsound.Beep(494,125) #B
+                winsound.Beep(392,125) #G
+                winsound.Beep(494,250) #B
+                winsound.Beep(440,150) #A
+                winsound.Beep(392,125) #G
+                winsound.Beep(370,250) #F#
+                winsound.Beep(370,125) #F#
+                winsound.Beep(392,125) #G
+                winsound.Beep(440,250) #A
+                winsound.Beep(494,250) #B
+                winsound.Beep(392,250) #G
+                winsound.Beep(330,300) #E
+
+            #Does Linux support say command?
+            elif sys.platform[:3] != "win" :
+                finished_render_message = "\'Render completed\'"
+                # We don't want the say command to block Python,
+                # so we add an ampersand after the message
+                os.system("say %s &" % (finished_render_message))
 
 ##################################################################################
 #################################Operators########################################
@@ -5833,7 +6009,7 @@ class RenderPovTexturePreview(Operator):
         outputPrevFile = os.path.join(preview_dir, texPrevName)
         ##################### ini ##########################################
         fileIni = open("%s" % iniPrevFile, "w")
-        fileIni.write('Version=3.7\n')
+        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)
diff --git a/render_povray/shading.py b/render_povray/shading.py
index ac1f923f6703ddf205c493ed3e3c68903163e093..a3f907dceda4311ed73cc408aa20042c815f030e 100644
--- a/render_povray/shading.py
+++ b/render_povray/shading.py
@@ -155,7 +155,7 @@ def writeMaterial(using_uberpov, DEF_MAT_NAME, scene, tabWrite, safety, comments
             elif Level == 1:
                 if (material.pov.specular_shader == 'COOKTORR' or
                     material.pov.specular_shader == 'PHONG'):
-                    tabWrite("phong %.3g\n" % (material.pov.specular_intensity/5))
+                    tabWrite("phong 0\n")#%.3g\n" % (material.pov.specular_intensity/5))
                     tabWrite("phong_size %.3g\n" % (material.pov.specular_hardness /3.14))
 
                 # POV-Ray 'specular' keyword corresponds to a Blinn model, without the ior.
@@ -183,8 +183,10 @@ def writeMaterial(using_uberpov, DEF_MAT_NAME, scene, tabWrite, safety, comments
                     # specular for some values.
                     tabWrite("brilliance %.4g\n" % (1.8 - material.pov.specular_slope * 1.8))
             elif Level == 3:
-                tabWrite("specular %.3g\n" % ((material.pov.specular_intensity*material.pov.specular_color.v)*5))
-                tabWrite("roughness %.3g\n" % (1.1/material.pov.specular_hardness))
+                # Spec must be Max at Level 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)
@@ -265,12 +267,12 @@ def writeMaterial(using_uberpov, DEF_MAT_NAME, scene, tabWrite, safety, comments
 
     if material:
         special_texture_found = False
-        idx = -1
+        tmpidx = -1
         for t in material.pov_texture_slots:
-            idx += 1
+            tmpidx += 1
             # index = material.pov.active_texture_index
-            slot = material.pov_texture_slots[idx] # [index]
-            povtex = 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:
@@ -777,7 +779,7 @@ def exportPattern(texture, string_strip_hyphen):
     return(texStrg)
 
 
-def writeTextureInfluence(mater, materialNames, LocalMaterialNames, path_image, lampCount,
+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."""
@@ -805,14 +807,15 @@ def writeTextureInfluence(mater, materialNames, LocalMaterialNames, path_image,
     texturesNorm = ""
     texturesAlpha = ""
     #proceduralFlag=False
+    tmpidx = -1
     for t in mater.pov_texture_slots:
-        idx = -1
-        for t in mater.pov_texture_slots:
-            idx += 1
-            # index = mater.pov.active_texture_index
-            slot = mater.pov_texture_slots[idx] # [index]
-            povtex = slot.name
-            tex = bpy.data.textures[povtex]
+
+
+        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)
@@ -876,11 +879,13 @@ def writeTextureInfluence(mater, materialNames, LocalMaterialNames, path_image,
                 # 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
-                        if t_dif.texture.pov.tex_gamma_enable:
+                        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
@@ -913,6 +918,7 @@ def writeTextureInfluence(mater, materialNames, LocalMaterialNames, path_image,
     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")
@@ -1056,12 +1062,36 @@ def writeTextureInfluence(mater, materialNames, LocalMaterialNames, path_image,
             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, mappingNor))
+                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 {uv_mapping bump_map " \
-                         "{%s \"%s\" %s  bump_size %.4g }%s}\n" % \
+                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, mappingNor))
+                          ( - 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###############
@@ -1094,6 +1124,35 @@ def writeTextureInfluence(mater, materialNames, LocalMaterialNames, path_image,
             # 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)))
@@ -1166,11 +1225,36 @@ def writeTextureInfluence(mater, materialNames, LocalMaterialNames, path_image,
         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, mappingNor))
+            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 {uv_mapping bump_map {%s \"%s\" %s  bump_size %.4g }%s}\n" % \
+            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, mappingNor))
+                      ( - 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")
 
@@ -1201,12 +1285,12 @@ def writeTextureInfluence(mater, materialNames, LocalMaterialNames, path_image,
     # Write another layered texture using invisible diffuse and metallic trick
     # to emulate colored specular highlights
     special_texture_found = False
-    idx = -1
+    tmpidx = -1
     for t in mater.pov_texture_slots:
-        idx += 1
+        tmpidx += 1
         # index = mater.pov.active_texture_index
-        slot = mater.pov_texture_slots[idx] # [index]
-        povtex = slot.name
+        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)):
@@ -1240,7 +1324,7 @@ def writeTextureInfluence(mater, materialNames, LocalMaterialNames, path_image,
                 if image_filename:
                     if t.use_map_normal:
                         texturesNorm = image_filename
-                        # colvalue = t.normal_factor/10  # UNUSED
+                        # colvalue = t.normal_factor/10  # UNUSED   XXX *-9.5 !
                         #textNormName=tex.image.name + ".normal"
                         #was the above used? --MR
                         t_nor = t
@@ -1248,13 +1332,13 @@ def writeTextureInfluence(mater, materialNames, LocalMaterialNames, path_image,
                             tabWrite("normal{function" \
                                      "{f%s(x,y,z).grey} bump_size %.4g}\n" % \
                                      (texturesNorm,
-                                     t_nor.normal_factor))
+                                     ( - 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,
+                                     ( - t_nor.normal_factor * 9.5),
                                      mappingNor))
 
         tabWrite("}\n") # THEN IT CAN CLOSE LAST LAYER OF TEXTURE
diff --git a/render_povray/ui.py b/render_povray/ui.py
index e15a93741fecd34813391205d5c702554b916e14..9ac79067b04e21d148908e9971e0f1eea21f5dcc 100644
--- a/render_povray/ui.py
+++ b/render_povray/ui.py
@@ -22,11 +22,15 @@
 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,
@@ -43,17 +47,29 @@ from bl_ui import properties_output
 for member in dir(properties_output):
     subclass = getattr(properties_output, member)
     try:
-        subclass.COMPAT_ENGINES.add('POVRAY')
+        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')
+        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
     except:
         pass
 del properties_view_layer
@@ -242,19 +258,139 @@ for member in dir(
         pass
 del properties_particle
 
-# 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
+
+#Use some delay?
+#https://blenderartists.org/t/restrictdata-object-has-no-attribute-scenes-how-to-avoid-it/579885/4
+############# POV-Centric WORSPACE #############
+@persistent
+def povCentricWorkspace(dummy):
+    """Set up a POV centric Workspace if addon was left activate from previous session
+
+    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.
+    """
+
+    #bpy.context.scene.render.engine = 'POVRAY_RENDER'
+    wsp = bpy.data.workspaces.get('Scripting')
+    context = bpy.context
+    if wsp is not None:
+        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')
+                            #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)
+
+
+
 
 
-class WORLD_MT_POV_presets(bpy.types.Menu):
+
+        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"
@@ -262,7 +398,7 @@ class WORLD_MT_POV_presets(bpy.types.Menu):
 
 
 class WORLD_OT_POV_add_preset(AddPresetBase, Operator):
-    '''Add a World Preset'''
+    """Add a World Preset"""
 
     bl_idname = "object.world_preset_add"
     bl_label = "Add World Preset"
@@ -324,6 +460,15 @@ def check_add_mesh_extra_objects():
         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.
@@ -373,31 +518,29 @@ def pov_context_tex_datablock(context):
     """Texture context type recreated as deprecated in blender 2.8"""
 
     idblock = context.brush
-    if idblock and bpy.context.scene.texture_context == 'OTHER':
+    if idblock and context.scene.texture_context == 'OTHER':
         return idblock
 
     # idblock = bpy.context.active_object.active_material
-    idblock = bpy.context.scene.view_layers[
-        "View Layer"
-    ].objects.active.active_material
-    if idblock:
+    idblock = context.view_layer.objects.active.active_material
+    if idblock and context.scene.texture_context == 'MATERIAL':
         return idblock
 
-    idblock = context.world
-    if idblock:
+    idblock = context.scene.world
+    if idblock and context.scene.texture_context == 'WORLD':
         return idblock
 
     idblock = context.light
-    if idblock:
+    if idblock and context.scene.texture_context == 'LIGHT':
         return idblock
 
-    if context.particle_system:
+    if context.particle_system and context.scene.texture_context == 'PARTICLES':
         idblock = context.particle_system.settings
 
     return idblock
 
     idblock = context.line_style
-    if idblock:
+    if idblock and context.scene.texture_context == 'LINESTYLE':
         return idblock
 
 
@@ -688,7 +831,7 @@ class LIGHT_PT_POV_light(PovLampButtonsPanel, Panel):
     draw = properties_data_light.DATA_PT_light.draw
 
 
-class LIGHT_MT_POV_presets(bpy.types.Menu):
+class LIGHT_MT_POV_presets(Menu):
     """Use this class to define preset menu for pov lights."""
 
     bl_label = "Lamp Presets"
@@ -1114,9 +1257,8 @@ class WORLD_PT_POV_mist(WorldButtonsPanel, Panel):
 
 class RENDER_PT_POV_export_settings(RenderButtonsPanel, Panel):
     """Use this class to define pov ini settingss buttons."""
-
-    bl_label = "Start Options"
     bl_options = {'DEFAULT_CLOSED'}
+    bl_label = "Auto Start"
     COMPAT_ENGINES = {'POVRAY_RENDER'}
 
     def draw_header(self, context):
@@ -1131,6 +1273,7 @@ class RENDER_PT_POV_export_settings(RenderButtonsPanel, Panel):
             )
 
     def draw(self, context):
+
         layout = self.layout
 
         scene = context.scene
@@ -1143,25 +1286,25 @@ class RENDER_PT_POV_export_settings(RenderButtonsPanel, Panel):
         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")
+        #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")
+            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")
+            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")
+            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):
@@ -1414,7 +1557,7 @@ class RENDER_PT_POV_radiosity(RenderButtonsPanel, Panel):
             col.prop(scene.pov, "radio_subsurface")
 
 
-class POV_RADIOSITY_MT_presets(bpy.types.Menu):
+class POV_RADIOSITY_MT_presets(Menu):
     """Use this class to define pov radiosity presets menu."""
 
     bl_label = "Radiosity Presets"
@@ -1562,7 +1705,7 @@ class MODIFIERS_PT_POV_modifiers(ModifierButtonsPanel, Panel):
                         col.prop(ob.pov, "inside_vector")
 
 
-class MATERIAL_MT_POV_sss_presets(bpy.types.Menu):
+class MATERIAL_MT_POV_sss_presets(Menu):
     """Use this class to define pov sss preset menu."""
 
     bl_label = "SSS Presets"
@@ -1872,7 +2015,7 @@ class MATERIAL_PT_POV_mirror(MaterialButtonsPanel, Panel):
         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_samples", text="Noise")
         sub.prop(raym, "gloss_anisotropic", text="Anisotropic")
 
 
@@ -2178,7 +2321,7 @@ class MATERIAL_PT_POV_replacement_text(MaterialButtonsPanel, Panel):
         col.prop(mat.pov, "replacement_text", text="")
 
 
-class TEXTURE_MT_POV_specials(bpy.types.Menu):
+class TEXTURE_MT_POV_specials(Menu):
     """Use this class to define pov texture slot operations buttons."""
 
     bl_label = "Texture Specials"
@@ -2191,14 +2334,20 @@ class TEXTURE_MT_POV_specials(bpy.types.Menu):
         layout.operator("texture.slot_paste", icon='PASTEDOWN')
 
 
-class TEXTURE_UL_POV_texture_slots(bpy.types.UIList):
-    """Use this class to show pov texture slots list."""  # used?
-
-    COMPAT_ENGINES = {'POVRAY_RENDER'}
+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
@@ -2220,62 +2369,7 @@ class TEXTURE_UL_POV_texture_slots(bpy.types.UIList):
             layout.label(text="", icon_value=icon)
 
 
-'''
-class MATERIAL_TEXTURE_SLOTS_UL_List(UIList):
-    """Texture Slots UIList."""
-
-
-    def draw_item(self, context, layout, material, item, icon, active_data,
-                  material_texture_list_index, index):
-        material = context.material#.pov
-        active_data = material
-        #tex = context.texture #may be needed later?
-
-
-        # We could write some code to decide which icon to use here...
-        custom_icon = 'TEXTURE'
-
-        # Make sure your code supports all 3 layout types
-        if self.layout_type in {'DEFAULT', 'COMPACT'}:
-            layout.label(item.name, icon = custom_icon)
-
-        elif self.layout_type in {'GRID'}:
-            layout.alignment = 'CENTER'
-            layout.label("", icon = custom_icon)
-'''
-
-
-class WORLD_TEXTURE_SLOTS_UL_List(UIList):
-    """Use this class to show pov texture slots list."""  # XXX Not used yet
-
-    def draw_item(
-        self,
-        context,
-        layout,
-        world,
-        item,
-        icon,
-        active_data,
-        active_texture_index,
-        index,
-    ):
-        world = context.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'
-
-        # Make sure your code supports all 3 layout types
-        if self.layout_type in {'DEFAULT', 'COMPACT'}:
-            layout.label(item.name, icon=custom_icon)
-
-        elif self.layout_type in {'GRID'}:
-            layout.alignment = 'CENTER'
-            layout.label("", icon=custom_icon)
-
-
-class MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist(bpy.types.UIList):
+class MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist(UIList):
     """Use this class to show pov texture slots list."""
 
     #    texture_slots:
@@ -2304,6 +2398,53 @@ class MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist(bpy.types.UIList):
             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."""
@@ -2316,11 +2457,11 @@ class TEXTURE_PT_POV_context_texture(TextureButtonsPanel, Panel):
     def poll(cls, context):
         engine = context.scene.render.engine
         return engine in cls.COMPAT_ENGINES
-        # if not (hasattr(context, "texture_slot") or hasattr(context, "texture_node")):
+        # if not (hasattr(context, "pov_texture_slot") or hasattr(context, "texture_node")):
         #     return False
         return (
             context.material
-            or context.world
+            or context.scene.world
             or context.light
             or context.texture
             or context.line_style
@@ -2333,11 +2474,12 @@ class TEXTURE_PT_POV_context_texture(TextureButtonsPanel, Panel):
         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':
-            mat = context.scene.view_layers[
-                "View Layer"
-            ].objects.active.active_material
+        if scene.texture_context == 'MATERIAL' and mat is not None:
+
             row = layout.row()
             row.template_list(
                 "MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist",
@@ -2353,22 +2495,90 @@ class TEXTURE_PT_POV_context_texture(TextureButtonsPanel, Panel):
             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.name
+                povtex = slot.texture#slot.name
                 tex = bpy.data.textures[povtex]
                 col.prop(tex, 'use_fake_user', text='')
-                layout.label(text='Find texture:')
+                #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=''
+                    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
@@ -2518,7 +2728,7 @@ class TEXTURE_PT_colors(TextureButtonsPanel, Panel):
 # Texture Slot Panels #
 
 
-class MATERIAL_OT_POV_texture_slot_add(Operator):
+class TEXTURE_OT_POV_texture_slot_add(Operator):
     """Use this class for the add texture slot button."""
 
     bl_idname = "pov.textureslotadd"
@@ -2528,18 +2738,29 @@ class MATERIAL_OT_POV_texture_slot_add(Operator):
     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
-        ob = context.scene.view_layers["View Layer"].objects.active
-        slot = ob.active_material.pov_texture_slots.add()
+        #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 MATERIAL_OT_POV_texture_slot_remove(Operator):
+class TEXTURE_OT_POV_texture_slot_remove(Operator):
     """Use this class for the remove texture slot button."""
 
     bl_idname = "pov.textureslotremove"
@@ -2549,14 +2770,23 @@ class MATERIAL_OT_POV_texture_slot_remove(Operator):
     COMPAT_ENGINES = {'POVRAY_RENDER'}
 
     def execute(self, context):
-        pass
-        # tex = bpy.data.textures.new()
-        # tex_slot = context.object.active_material.pov_texture_slots.add()
-        # tex_slot.name = tex.name
+        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."""
 
@@ -2586,7 +2816,7 @@ class TEXTURE_PT_POV_type(TextureButtonsPanel, Panel):
         tex = context.texture
 
         split = layout.split(factor=0.2)
-        split.label(text="POV:")
+        split.label(text="Pattern")
         split.prop(tex.pov, "tex_pattern_type", text="")
 
         # row = layout.row()
@@ -2631,6 +2861,7 @@ 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):
@@ -2911,6 +3142,112 @@ class TEXTURE_PT_POV_parameters(TextureButtonsPanel, Panel):
             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."""
@@ -2919,18 +3256,20 @@ class TEXTURE_PT_POV_influence(TextureSlotPanel, Panel):
     COMPAT_ENGINES = {'POVRAY_RENDER'}
     bl_space_type = 'PROPERTIES'
     bl_region_type = 'WINDOW'
-    # bl_context = 'texture'
+    #bl_context = 'texture'
     @classmethod
     def poll(cls, context):
         idblock = pov_context_tex_datablock(context)
         if (
-            isinstance(idblock, Brush)
-            and bpy.context.scene.texture_context == 'OTHER'
+            # 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
 
-        # if not getattr(context, "pov_texture_slot", None):
-        # 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
@@ -2940,14 +3279,13 @@ class TEXTURE_PT_POV_influence(TextureSlotPanel, Panel):
         layout = self.layout
 
         idblock = pov_context_tex_datablock(context)
-
         # tex = context.pov_texture_slot
-        mat = bpy.context.active_object.active_material
-        texslot = mat.pov_texture_slots[
-            mat.active_texture_index
+        #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[
-            mat.pov_texture_slots[mat.active_texture_index].texture
+            idblock.pov_texture_slots[idblock.pov.active_texture_index].texture
         ]
 
         def factor_but(layout, toggle, factor, name):
@@ -3756,7 +4094,7 @@ class OBJECT_PT_povray_replacement_text(ObjectButtonsPanel, Panel):
 ###############################################################################
 
 
-class VIEW_MT_POV_primitives_add(bpy.types.Menu):
+class VIEW_MT_POV_primitives_add(Menu):
     """Define the primitives menu with presets"""
 
     bl_idname = "VIEW_MT_POV_primitives_add"
@@ -3777,7 +4115,7 @@ class VIEW_MT_POV_primitives_add(bpy.types.Menu):
         layout.menu(VIEW_MT_POV_import.bl_idname, text="Import", icon="IMPORT")
 
 
-class VIEW_MT_POV_Basic_Shapes(bpy.types.Menu):
+class VIEW_MT_POV_Basic_Shapes(Menu):
     """Use this class to sort simple primitives menu entries."""
 
     bl_idname = "POVRAY_MT_basic_shape_tools"
@@ -3859,7 +4197,7 @@ class VIEW_MT_POV_Basic_Shapes(bpy.types.Menu):
             )
 
 
-class VIEW_MT_POV_import(bpy.types.Menu):
+class VIEW_MT_POV_import(Menu):
     """Use this class for the import menu."""
 
     bl_idname = "POVRAY_MT_import_tools"
@@ -3910,7 +4248,7 @@ def menu_func_import(self, context):
 # return True
 
 
-class NODE_MT_POV_map_create(bpy.types.Menu):
+class NODE_MT_POV_map_create(Menu):
     """Create maps"""
 
     bl_idname = "POVRAY_MT_node_map_create"
@@ -4056,7 +4394,7 @@ def validinsert(ext):
     return ext in {".txt", ".inc", ".pov"}
 
 
-class TEXT_MT_POV_insert(bpy.types.Menu):
+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"
@@ -4116,10 +4454,10 @@ class TEXT_PT_POV_custom_code(TextButtonsPanel, Panel):
             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_POSE')
+                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='POSE_DATA')
+                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')
@@ -4133,7 +4471,7 @@ class TEXT_PT_POV_custom_code(TextButtonsPanel, Panel):
 # Text editor templates from header menu
 
 
-class TEXT_MT_POV_templates(bpy.types.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"
@@ -4154,12 +4492,111 @@ 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_List,
+    WORLD_TEXTURE_SLOTS_UL_POV_layerlist,
+    #WORLD_TEXTURE_SLOTS_UL_List,
     WORLD_PT_POV_mist,
     # RenderButtonsPanel,
     # ModifierButtonsPanel,
@@ -4188,6 +4625,7 @@ classes = (
     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,
@@ -4232,13 +4670,14 @@ classes = (
     TEXT_MT_POV_insert,
     TEXT_PT_POV_custom_code,
     TEXT_MT_POV_templates,
-    # TEXTURE_PT_context,
-    # TEXTURE_PT_POV_povray_texture_slots,
-    TEXTURE_UL_POV_texture_slots,
+    TEXTURE_PT_context,
+    #TEXTURE_PT_POV_povray_texture_slots,
+    #TEXTURE_UL_POV_texture_slots,
     MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist,
-    MATERIAL_OT_POV_texture_slot_add,
-    MATERIAL_OT_POV_texture_slot_remove,
+    TEXTURE_OT_POV_texture_slot_add,
+    TEXTURE_OT_POV_texture_slot_remove,
     TEXTURE_PT_POV_influence,
+    TEXTURE_PT_POV_mapping,
 )
 
 
@@ -4257,11 +4696,18 @@ def register():
     # 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)
@@ -4274,4 +4720,5 @@ def unregister():
     bpy.types.VIEW3D_MT_add.remove(menu_func_add)
 
     for cls in reversed(classes):
-        unregister_class(cls)
+        if cls != TEXTURE_PT_context:
+            unregister_class(cls)