diff options
Diffstat (limited to 'render_povray/texturing_gui.py')
-rwxr-xr-x | render_povray/texturing_gui.py | 1255 |
1 files changed, 1255 insertions, 0 deletions
diff --git a/render_povray/texturing_gui.py b/render_povray/texturing_gui.py new file mode 100755 index 00000000..6d12fb62 --- /dev/null +++ b/render_povray/texturing_gui.py @@ -0,0 +1,1255 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> + +"""User interface for texturing tools.""" + +import bpy +from bpy.utils import register_class, unregister_class +from bpy.types import ( + Operator, + Menu, + UIList, + Panel, + Brush, + Material, + Light, + World, + ParticleSettings, + FreestyleLineStyle, +) + +# from .ui import TextureButtonsPanel + +from .shading_properties import pov_context_tex_datablock +from bl_ui.properties_paint_common import brush_texture_settings + +# Example of wrapping every class 'as is' +from bl_ui import properties_texture + +# unused, replaced by pov_context_tex_datablock (no way to use?): +# from bl_ui.properties_texture import context_tex_datablock +# from bl_ui.properties_texture import texture_filter_common #unused yet? + +for member in dir(properties_texture): + subclass = getattr(properties_texture, member) + try: + subclass.COMPAT_ENGINES.add('POVRAY_RENDER') + except BaseException as e: + print(e.__doc__) + print('An exception occurred: {}'.format(e)) + pass +del properties_texture + + +class TextureButtonsPanel: + """Use this class to define buttons from the texture tab properties.""" + + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "texture" + COMPAT_ENGINES = {'POVRAY_RENDER'} + + @classmethod + def poll(cls, context): + tex = context.texture + rd = context.scene.render + return tex and (rd.engine in cls.COMPAT_ENGINES) + + +class TEXTURE_MT_POV_specials(Menu): + """Use this class to define pov texture slot operations buttons.""" + + bl_label = "Texture Specials" + COMPAT_ENGINES = {'POVRAY_RENDER'} + + def draw(self, context): + layout = self.layout + + layout.operator("texture.slot_copy", icon='COPYDOWN') + layout.operator("texture.slot_paste", icon='PASTEDOWN') + + +class WORLD_TEXTURE_SLOTS_UL_POV_layerlist(UIList): + """Use this class to show pov texture slots list.""" # XXX Not used yet + + index: bpy.props.IntProperty(name='index') + # should active_propname be index or..? + def draw_item(self, context, layout, data, item, icon, active_data, active_propname): + world = context.scene.world # .pov + active_data = world.pov + # tex = context.texture #may be needed later? + + # We could write some code to decide which icon to use here... + # custom_icon = 'TEXTURE' + + # ob = data + slot = item + # ma = slot.name + # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code. + if self.layout_type in {'DEFAULT', 'COMPACT'}: + # You should always start your row layout by a label (icon + text), or a non-embossed text field, + # this will also make the row easily selectable in the list! The later also enables ctrl-click rename. + # We use icon_value of label, as our given icon is an integer value, not an enum ID. + # Note "data" names should never be translated! + if slot: + layout.prop(item, "texture", text="", emboss=False, icon='TEXTURE') + else: + layout.label(text="New", translate=False, icon_value=icon) + # 'GRID' layout type should be as compact as possible (typically a single icon!). + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label(text="", icon_value=icon) + + +class MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist(UIList): + """Use this class to show pov texture slots list.""" + + # texture_slots: + index: bpy.props.IntProperty(name='index') + # foo = random prop + def draw_item(self, context, layout, data, item, icon, active_data, active_propname): + # ob = data + slot = item + # ma = slot.name + # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code. + if self.layout_type in {'DEFAULT', 'COMPACT'}: + # You should always start your row layout by a label (icon + text), or a non-embossed text field, + # this will also make the row easily selectable in the list! The later also enables ctrl-click rename. + # We use icon_value of label, as our given icon is an integer value, not an enum ID. + # Note "data" names should never be translated! + if slot: + layout.prop(item, "texture", text="", emboss=False, icon='TEXTURE') + else: + layout.label(text="New", translate=False, icon_value=icon) + # 'GRID' layout type should be as compact as possible (typically a single icon!). + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label(text="", icon_value=icon) + + +class TEXTURE_PT_context(TextureButtonsPanel, Panel): + """Rewrite of this existing class to modify it.""" + + bl_label = "" + bl_context = "texture" + bl_options = {'HIDE_HEADER'} + COMPAT_ENGINES = {'POVRAY_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + # register but not unregistered because + # the modified parts concern only POVRAY_RENDER + @classmethod + def poll(cls, context): + return ( + context.scene.texture_context + not in ('MATERIAL', 'WORLD', 'LIGHT', 'PARTICLES', 'LINESTYLE') + or context.scene.render.engine != 'POVRAY_RENDER' + ) + + def draw(self, context): + layout = self.layout + tex = context.texture + space = context.space_data + pin_id = space.pin_id + use_pin_id = space.use_pin_id + user = context.texture_user + + col = layout.column() + + if not (use_pin_id and isinstance(pin_id, bpy.types.Texture)): + pin_id = None + + if not pin_id: + col.template_texture_user() + + if user or pin_id: + col.separator() + + if pin_id: + col.template_ID(space, "pin_id") + else: + propname = context.texture_user_property.identifier + col.template_ID(user, propname, new="texture.new") + + if tex: + col.separator() + + split = col.split(factor=0.2) + split.label(text="Type") + split.prop(tex, "type", text="") + + +class TEXTURE_PT_POV_context_texture(TextureButtonsPanel, Panel): + """Use this class to show pov texture context buttons.""" + + bl_label = "" + bl_options = {'HIDE_HEADER'} + COMPAT_ENGINES = {'POVRAY_RENDER'} + + @classmethod + def poll(cls, context): + engine = context.scene.render.engine + return engine in cls.COMPAT_ENGINES + # if not (hasattr(context, "pov_texture_slot") or hasattr(context, "texture_node")): + # return False + return ( + context.material + or context.scene.world + or context.light + or context.texture + or context.line_style + or context.particle_system + or isinstance(context.space_data.pin_id, ParticleSettings) + or context.texture_user + ) and (engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + + scene = context.scene + mat = context.view_layer.objects.active.active_material + wld = context.scene.world + + layout.prop(scene, "texture_context", expand=True) + if scene.texture_context == 'MATERIAL' and mat is not None: + + row = layout.row() + row.template_list( + "MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist", + "", + mat, + "pov_texture_slots", + mat.pov, + "active_texture_index", + rows=2, + maxrows=16, + type="DEFAULT", + ) + col = row.column(align=True) + col.operator("pov.textureslotadd", icon='ADD', text='') + col.operator("pov.textureslotremove", icon='REMOVE', text='') + # XXX todo: recreate for pov_texture_slots? + # col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP' + # col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN' + col.separator() + + if mat.pov_texture_slots: + index = mat.pov.active_texture_index + slot = mat.pov_texture_slots[index] + povtex = slot.texture # slot.name + tex = bpy.data.textures[povtex] + col.prop(tex, 'use_fake_user', text='') + # layout.label(text='Linked Texture data browser:') + # propname = slot.texture_search + # if slot.texture was a pointer to texture data rather than just a name string: + # layout.template_ID(povtex, "texture", new="texture.new") + + layout.prop_search( + slot, 'texture_search', bpy.data, 'textures', text='', icon='TEXTURE' + ) + try: + bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[ + slot.texture_search + ] + bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[ + slot.texture_search + ] + except KeyError: + # texture not hand-linked by user + pass + + if tex: + layout.separator() + split = layout.split(factor=0.2) + split.label(text="Type") + split.prop(tex, "type", text="") + + # else: + # for i in range(18): # length of material texture slots + # mat.pov_texture_slots.add() + elif scene.texture_context == 'WORLD' and wld is not None: + + row = layout.row() + row.template_list( + "WORLD_TEXTURE_SLOTS_UL_POV_layerlist", + "", + wld, + "pov_texture_slots", + wld.pov, + "active_texture_index", + rows=2, + maxrows=16, + type="DEFAULT", + ) + col = row.column(align=True) + col.operator("pov.textureslotadd", icon='ADD', text='') + col.operator("pov.textureslotremove", icon='REMOVE', text='') + + # todo: recreate for pov_texture_slots? + # col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP' + # col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN' + col.separator() + + if wld.pov_texture_slots: + index = wld.pov.active_texture_index + slot = wld.pov_texture_slots[index] + povtex = slot.texture # slot.name + tex = bpy.data.textures[povtex] + col.prop(tex, 'use_fake_user', text='') + # layout.label(text='Linked Texture data browser:') + propname = slot.texture_search + # if slot.texture was a pointer to texture data rather than just a name string: + # layout.template_ID(povtex, "texture", new="texture.new") + + layout.prop_search( + slot, 'texture_search', bpy.data, 'textures', text='', icon='TEXTURE' + ) + try: + bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[ + slot.texture_search + ] + bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[ + slot.texture_search + ] + except KeyError: + # texture not hand-linked by user + pass + + if tex: + layout.separator() + split = layout.split(factor=0.2) + split.label(text="Type") + split.prop(tex, "type", text="") + + +# Commented out below is a reminder of what existed in Blender Internal +# attributes need to be recreated +''' + slot = getattr(context, "texture_slot", None) + node = getattr(context, "texture_node", None) + space = context.space_data + + #attempt at replacing removed space_data + mtl = getattr(context, "material", None) + if mtl != None: + spacedependant = mtl + wld = getattr(context, "world", None) + if wld != None: + spacedependant = wld + lgt = getattr(context, "light", None) + if lgt != None: + spacedependant = lgt + + + #idblock = context.particle_system.settings + + tex = getattr(context, "texture", None) + if tex != None: + spacedependant = tex + + + + scene = context.scene + idblock = scene.pov#pov_context_tex_datablock(context) + pin_id = space.pin_id + + #spacedependant.use_limited_texture_context = True + + if space.use_pin_id and not isinstance(pin_id, Texture): + idblock = id_tex_datablock(pin_id) + pin_id = None + + if not space.use_pin_id: + layout.row().prop(spacedependant, "texture_context", expand=True) + pin_id = None + + if spacedependant.texture_context == 'OTHER': + if not pin_id: + layout.template_texture_user() + user = context.texture_user + if user or pin_id: + layout.separator() + + row = layout.row() + + if pin_id: + row.template_ID(space, "pin_id") + else: + propname = context.texture_user_property.identifier + row.template_ID(user, propname, new="texture.new") + + if tex: + split = layout.split(factor=0.2) + if tex.use_nodes: + if slot: + split.label(text="Output:") + split.prop(slot, "output_node", text="") + else: + split.label(text="Type:") + split.prop(tex, "type", text="") + return + + tex_collection = (pin_id is None) and (node is None) and (spacedependant.texture_context not in ('LINESTYLE','OTHER')) + + if tex_collection: + + pov = getattr(context, "pov", None) + active_texture_index = getattr(spacedependant, "active_texture_index", None) + print (pov) + print(idblock) + print(active_texture_index) + row = layout.row() + + row.template_list("TEXTURE_UL_texslots", "", idblock, "texture_slots", + idblock, "active_texture_index", rows=2, maxrows=16, type="DEFAULT") + + # row.template_list("WORLD_TEXTURE_SLOTS_UL_List", "texture_slots", world, + # world.texture_slots, world, "active_texture_index", rows=2) + + col = row.column(align=True) + col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP' + col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN' + col.menu("TEXTURE_MT_POV_specials", icon='DOWNARROW_HLT', text="") + + if tex_collection: + layout.template_ID(idblock, "active_texture", new="texture.new") + elif node: + layout.template_ID(node, "texture", new="texture.new") + elif idblock: + layout.template_ID(idblock, "texture", new="texture.new") + + if pin_id: + layout.template_ID(space, "pin_id") + + if tex: + split = layout.split(factor=0.2) + if tex.use_nodes: + if slot: + split.label(text="Output:") + split.prop(slot, "output_node", text="") + else: + split.label(text="Type:") +''' + + +class TEXTURE_PT_colors(TextureButtonsPanel, Panel): + """Use this class to show pov color ramps.""" + + bl_label = "Colors" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'POVRAY_RENDER'} + + def draw(self, context): + layout = self.layout + + tex = context.texture + + layout.prop(tex, "use_color_ramp", text="Ramp") + if tex.use_color_ramp: + layout.template_color_ramp(tex, "color_ramp", expand=True) + + split = layout.split() + + col = split.column() + col.label(text="RGB Multiply:") + sub = col.column(align=True) + sub.prop(tex, "factor_red", text="R") + sub.prop(tex, "factor_green", text="G") + sub.prop(tex, "factor_blue", text="B") + + col = split.column() + col.label(text="Adjust:") + col.prop(tex, "intensity") + col.prop(tex, "contrast") + col.prop(tex, "saturation") + + col = layout.column() + col.prop(tex, "use_clamp", text="Clamp") + + +# Texture Slot Panels # + + +class TEXTURE_OT_POV_texture_slot_add(Operator): + """Use this class for the add texture slot button.""" + + bl_idname = "pov.textureslotadd" + bl_label = "Add" + bl_description = "Add texture_slot" + bl_options = {'REGISTER', 'UNDO'} + COMPAT_ENGINES = {'POVRAY_RENDER'} + + def execute(self, context): + idblock = pov_context_tex_datablock(context) + tex = bpy.data.textures.new(name='Texture', type='IMAGE') + # tex.use_fake_user = True + # mat = context.view_layer.objects.active.active_material + slot = idblock.pov_texture_slots.add() + slot.name = tex.name + slot.texture = tex.name + slot.texture_search = tex.name + # Switch paint brush and paint brush mask + # to this texture so settings remain contextual + bpy.context.tool_settings.image_paint.brush.texture = tex + bpy.context.tool_settings.image_paint.brush.mask_texture = tex + idblock.pov.active_texture_index = len(idblock.pov_texture_slots) - 1 + + # for area in bpy.context.screen.areas: + # if area.type in ['PROPERTIES']: + # area.tag_redraw() + + return {'FINISHED'} + + +class TEXTURE_OT_POV_texture_slot_remove(Operator): + """Use this class for the remove texture slot button.""" + + bl_idname = "pov.textureslotremove" + bl_label = "Remove" + bl_description = "Remove texture_slot" + bl_options = {'REGISTER', 'UNDO'} + COMPAT_ENGINES = {'POVRAY_RENDER'} + + def execute(self, context): + idblock = pov_context_tex_datablock(context) + # mat = context.view_layer.objects.active.active_material + # tex_slot = idblock.pov_texture_slots.remove(idblock.pov.active_texture_index) # not used + if idblock.pov.active_texture_index > 0: + idblock.pov.active_texture_index -= 1 + try: + tex = idblock.pov_texture_slots[idblock.pov.active_texture_index].texture + except IndexError: + # No more slots + return {'FINISHED'} + # Switch paint brush to previous texture so settings remain contextual + # if 'tex' in locals(): # Would test is the tex variable is assigned / exists + bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[tex] + bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[tex] + + return {'FINISHED'} + + +class TextureSlotPanel(TextureButtonsPanel): + """Use this class to show pov texture slots panel.""" + + COMPAT_ENGINES = {'POVRAY_RENDER'} + + @classmethod + def poll(cls, context): + if not hasattr(context, "pov_texture_slot"): + return False + + engine = context.scene.render.engine + # return TextureButtonsPanel.poll(cls, context) and (engine in cls.COMPAT_ENGINES) + return TextureButtonsPanel.poll(context) and (engine in cls.COMPAT_ENGINES) + + +class TEXTURE_PT_POV_type(TextureButtonsPanel, Panel): + """Use this class to define pov texture type buttons.""" + + bl_label = "POV Textures" + COMPAT_ENGINES = {'POVRAY_RENDER'} + bl_options = {'HIDE_HEADER'} + + def draw(self, context): + layout = self.layout + # world = context.world # unused + tex = context.texture + + split = layout.split(factor=0.2) + split.label(text="Pattern") + split.prop(tex.pov, "tex_pattern_type", text="") + + # row = layout.row() + # row.template_list("WORLD_TEXTURE_SLOTS_UL_List", "texture_slots", world, + # world.texture_slots, world, "active_texture_index") + + +class TEXTURE_PT_POV_preview(TextureButtonsPanel, Panel): + """Use this class to define pov texture preview panel.""" + + bl_label = "Preview" + COMPAT_ENGINES = {'POVRAY_RENDER'} + bl_options = {'HIDE_HEADER'} + + @classmethod + def poll(cls, context): + engine = context.scene.render.engine + if not hasattr(context, "pov_texture_slot"): + return False + tex = context.texture + # mat = bpy.context.active_object.active_material #unused + return tex and (tex.pov.tex_pattern_type != 'emulator') and (engine in cls.COMPAT_ENGINES) + + def draw(self, context): + tex = context.texture + slot = getattr(context, "pov_texture_slot", None) + # idblock = pov_context_tex_datablock(context) # unused + layout = self.layout + # if idblock: + # layout.template_preview(tex, parent=idblock, slot=slot) + if tex.pov.tex_pattern_type != 'emulator': + layout.operator("tex.preview_update") + else: + layout.template_preview(tex, slot=slot) + + +class TEXTURE_PT_POV_parameters(TextureButtonsPanel, Panel): + """Use this class to define pov texture pattern buttons.""" + + bl_label = "POV Pattern Options" + bl_options = {'HIDE_HEADER'} + COMPAT_ENGINES = {'POVRAY_RENDER'} + + def draw(self, context): + # mat = bpy.context.active_object.active_material # Unused + layout = self.layout + tex = context.texture + align = True + if tex is not None and tex.pov.tex_pattern_type != 'emulator': + if tex.pov.tex_pattern_type == 'agate': + layout.prop(tex.pov, "modifier_turbulence", text="Agate Turbulence") + if tex.pov.tex_pattern_type in {'spiral1', 'spiral2'}: + layout.prop(tex.pov, "modifier_numbers", text="Number of arms") + if tex.pov.tex_pattern_type == 'tiling': + layout.prop(tex.pov, "modifier_numbers", text="Pattern number") + if tex.pov.tex_pattern_type == 'magnet': + layout.prop(tex.pov, "magnet_style", text="Magnet style") + if tex.pov.tex_pattern_type == 'quilted': + row = layout.row(align=align) + row.prop(tex.pov, "modifier_control0", text="Control0") + row.prop(tex.pov, "modifier_control1", text="Control1") + if tex.pov.tex_pattern_type == 'brick': + col = layout.column(align=align) + row = col.row() + row.prop(tex.pov, "brick_size_x", text="Brick size X") + row.prop(tex.pov, "brick_size_y", text="Brick size Y") + row = col.row() + row.prop(tex.pov, "brick_size_z", text="Brick size Z") + row.prop(tex.pov, "brick_mortar", text="Brick mortar") + if tex.pov.tex_pattern_type in {'julia', 'mandel', 'magnet'}: + col = layout.column(align=align) + if tex.pov.tex_pattern_type == 'julia': + row = col.row() + row.prop(tex.pov, "julia_complex_1", text="Complex 1") + row.prop(tex.pov, "julia_complex_2", text="Complex 2") + if tex.pov.tex_pattern_type == 'magnet' and tex.pov.magnet_style == 'julia': + row = col.row() + row.prop(tex.pov, "julia_complex_1", text="Complex 1") + row.prop(tex.pov, "julia_complex_2", text="Complex 2") + row = col.row() + if tex.pov.tex_pattern_type in {'julia', 'mandel'}: + row.prop(tex.pov, "f_exponent", text="Exponent") + if tex.pov.tex_pattern_type == 'magnet': + row.prop(tex.pov, "magnet_type", text="Type") + row.prop(tex.pov, "f_iter", text="Iterations") + row = col.row() + row.prop(tex.pov, "f_ior", text="Interior") + row.prop(tex.pov, "f_ior_fac", text="Factor I") + row = col.row() + row.prop(tex.pov, "f_eor", text="Exterior") + row.prop(tex.pov, "f_eor_fac", text="Factor E") + if tex.pov.tex_pattern_type == 'gradient': + layout.label(text="Gradient orientation:") + column_flow = layout.column_flow(columns=3, align=True) + column_flow.prop(tex.pov, "grad_orient_x", text="X") + column_flow.prop(tex.pov, "grad_orient_y", text="Y") + column_flow.prop(tex.pov, "grad_orient_z", text="Z") + if tex.pov.tex_pattern_type == 'pavement': + layout.prop(tex.pov, "pave_sides", text="Pavement:number of sides") + col = layout.column(align=align) + column_flow = col.column_flow(columns=3, align=True) + column_flow.prop(tex.pov, "pave_tiles", text="Tiles") + if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 6: + column_flow.prop(tex.pov, "pave_pat_35", text="Pattern") + if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 5: + column_flow.prop(tex.pov, "pave_pat_22", text="Pattern") + if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 5: + column_flow.prop(tex.pov, "pave_pat_12", text="Pattern") + if tex.pov.pave_sides == '3' and tex.pov.pave_tiles == 6: + column_flow.prop(tex.pov, "pave_pat_12", text="Pattern") + if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 4: + column_flow.prop(tex.pov, "pave_pat_7", text="Pattern") + if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 4: + column_flow.prop(tex.pov, "pave_pat_5", text="Pattern") + if tex.pov.pave_sides == '3' and tex.pov.pave_tiles == 5: + column_flow.prop(tex.pov, "pave_pat_4", text="Pattern") + if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 3: + column_flow.prop(tex.pov, "pave_pat_3", text="Pattern") + if tex.pov.pave_sides == '3' and tex.pov.pave_tiles == 4: + column_flow.prop(tex.pov, "pave_pat_3", text="Pattern") + if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 3: + column_flow.prop(tex.pov, "pave_pat_2", text="Pattern") + if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 6: + column_flow.label(text="!!! 5 tiles!") + column_flow.prop(tex.pov, "pave_form", text="Form") + if tex.pov.tex_pattern_type == 'function': + layout.prop(tex.pov, "func_list", text="Functions") + if tex.pov.tex_pattern_type == 'function' and tex.pov.func_list != "NONE": + func = None + if tex.pov.func_list in {"f_noise3d", "f_ph", "f_r", "f_th"}: + func = 0 + if tex.pov.func_list in { + "f_comma", + "f_crossed_trough", + "f_cubic_saddle", + "f_cushion", + "f_devils_curve", + "f_enneper", + "f_glob", + "f_heart", + "f_hex_x", + "f_hex_y", + "f_hunt_surface", + "f_klein_bottle", + "f_kummer_surface_v1", + "f_lemniscate_of_gerono", + "f_mitre", + "f_nodal_cubic", + "f_noise_generator", + "f_odd", + "f_paraboloid", + "f_pillow", + "f_piriform", + "f_quantum", + "f_quartic_paraboloid", + "f_quartic_saddle", + "f_sphere", + "f_steiners_roman", + "f_torus_gumdrop", + "f_umbrella", + }: + func = 1 + if tex.pov.func_list in { + "f_bicorn", + "f_bifolia", + "f_boy_surface", + "f_superellipsoid", + "f_torus", + }: + func = 2 + if tex.pov.func_list in { + "f_ellipsoid", + "f_folium_surface", + "f_hyperbolic_torus", + "f_kampyle_of_eudoxus", + "f_parabolic_torus", + "f_quartic_cylinder", + "f_torus2", + }: + func = 3 + if tex.pov.func_list in { + "f_blob2", + "f_cross_ellipsoids", + "f_flange_cover", + "f_isect_ellipsoids", + "f_kummer_surface_v2", + "f_ovals_of_cassini", + "f_rounded_box", + "f_spikes_2d", + "f_strophoid", + }: + func = 4 + if tex.pov.func_list in { + "f_algbr_cyl1", + "f_algbr_cyl2", + "f_algbr_cyl3", + "f_algbr_cyl4", + "f_blob", + "f_mesh1", + "f_poly4", + "f_spikes", + }: + func = 5 + if tex.pov.func_list in { + "f_devils_curve_2d", + "f_dupin_cyclid", + "f_folium_surface_2d", + "f_hetero_mf", + "f_kampyle_of_eudoxus_2d", + "f_lemniscate_of_gerono_2d", + "f_polytubes", + "f_ridge", + "f_ridged_mf", + "f_spiral", + "f_witch_of_agnesi", + }: + func = 6 + if tex.pov.func_list in {"f_helix1", "f_helix2", "f_piriform_2d", "f_strophoid_2d"}: + func = 7 + if tex.pov.func_list == "f_helical_torus": + func = 8 + column_flow = layout.column_flow(columns=3, align=True) + column_flow.label(text="X") + column_flow.prop(tex.pov, "func_plus_x", text="") + column_flow.prop(tex.pov, "func_x", text="Value") + column_flow = layout.column_flow(columns=3, align=True) + column_flow.label(text="Y") + column_flow.prop(tex.pov, "func_plus_y", text="") + column_flow.prop(tex.pov, "func_y", text="Value") + column_flow = layout.column_flow(columns=3, align=True) + column_flow.label(text="Z") + column_flow.prop(tex.pov, "func_plus_z", text="") + column_flow.prop(tex.pov, "func_z", text="Value") + row = layout.row(align=align) + if func > 0: + row.prop(tex.pov, "func_P0", text="P0") + if func > 1: + row.prop(tex.pov, "func_P1", text="P1") + row = layout.row(align=align) + if func > 2: + row.prop(tex.pov, "func_P2", text="P2") + if func > 3: + row.prop(tex.pov, "func_P3", text="P3") + row = layout.row(align=align) + if func > 4: + row.prop(tex.pov, "func_P4", text="P4") + if func > 5: + row.prop(tex.pov, "func_P5", text="P5") + row = layout.row(align=align) + if func > 6: + row.prop(tex.pov, "func_P6", text="P6") + if func > 7: + row.prop(tex.pov, "func_P7", text="P7") + row = layout.row(align=align) + row.prop(tex.pov, "func_P8", text="P8") + row.prop(tex.pov, "func_P9", text="P9") + ###################################################End Patterns############################ + + layout.prop(tex.pov, "warp_types", text="Warp types") # warp + if tex.pov.warp_types == "TOROIDAL": + layout.prop(tex.pov, "warp_tor_major_radius", text="Major radius") + if tex.pov.warp_types not in {"CUBIC", "NONE"}: + layout.prop(tex.pov, "warp_orientation", text="Warp orientation") + col = layout.column(align=align) + row = col.row() + row.prop(tex.pov, "warp_dist_exp", text="Distance exponent") + row = col.row() + row.prop(tex.pov, "modifier_frequency", text="Frequency") + row.prop(tex.pov, "modifier_phase", text="Phase") + + row = layout.row() + + row.label(text="Offset:") + row.label(text="Scale:") + row.label(text="Rotate:") + col = layout.column(align=align) + row = col.row() + row.prop(tex.pov, "tex_mov_x", text="X") + row.prop(tex.pov, "tex_scale_x", text="X") + row.prop(tex.pov, "tex_rot_x", text="X") + row = col.row() + row.prop(tex.pov, "tex_mov_y", text="Y") + row.prop(tex.pov, "tex_scale_y", text="Y") + row.prop(tex.pov, "tex_rot_y", text="Y") + row = col.row() + row.prop(tex.pov, "tex_mov_z", text="Z") + row.prop(tex.pov, "tex_scale_z", text="Z") + row.prop(tex.pov, "tex_rot_z", text="Z") + row = layout.row() + + row.label(text="Turbulence:") + col = layout.column(align=align) + row = col.row() + row.prop(tex.pov, "warp_turbulence_x", text="X") + row.prop(tex.pov, "modifier_octaves", text="Octaves") + row = col.row() + row.prop(tex.pov, "warp_turbulence_y", text="Y") + row.prop(tex.pov, "modifier_lambda", text="Lambda") + row = col.row() + row.prop(tex.pov, "warp_turbulence_z", text="Z") + row.prop(tex.pov, "modifier_omega", text="Omega") + + +class TEXTURE_PT_POV_mapping(TextureSlotPanel, Panel): + """Use this class to define POV texture mapping buttons.""" + + bl_label = "Mapping" + COMPAT_ENGINES = {'POVRAY_RENDER'} + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + + @classmethod + def poll(cls, context): + idblock = pov_context_tex_datablock(context) + if isinstance(idblock, Brush) and not context.sculpt_object: + return False + + if not getattr(context, "texture_slot", None): + return False + + engine = context.scene.render.engine + return engine in cls.COMPAT_ENGINES + + def draw(self, context): + layout = self.layout + + idblock = pov_context_tex_datablock(context) + mat = bpy.context.active_object.active_material + # tex = context.texture_slot + tex = mat.pov_texture_slots[mat.active_texture_index] + if not isinstance(idblock, Brush): + split = layout.split(percentage=0.3) + col = split.column() + col.label(text="Coordinates:") + col = split.column() + col.prop(tex, "texture_coords", text="") + + if tex.texture_coords == 'ORCO': + """ + ob = context.object + if ob and ob.type == 'MESH': + split = layout.split(percentage=0.3) + split.label(text="Mesh:") + split.prop(ob.data, "texco_mesh", text="") + """ + elif tex.texture_coords == 'UV': + split = layout.split(percentage=0.3) + split.label(text="Map:") + ob = context.object + if ob and ob.type == 'MESH': + split.prop_search(tex, "uv_layer", ob.data, "uv_textures", text="") + else: + split.prop(tex, "uv_layer", text="") + + elif tex.texture_coords == 'OBJECT': + split = layout.split(percentage=0.3) + split.label(text="Object:") + split.prop(tex, "object", text="") + + elif tex.texture_coords == 'ALONG_STROKE': + split = layout.split(percentage=0.3) + split.label(text="Use Tips:") + split.prop(tex, "use_tips", text="") + + if isinstance(idblock, Brush): + if context.sculpt_object or context.image_paint_object: + brush_texture_settings(layout, idblock, context.sculpt_object) + else: + if isinstance(idblock, FreestyleLineStyle): + split = layout.split(percentage=0.3) + split.label(text="Projection:") + split.prop(tex, "mapping", text="") + + split = layout.split(percentage=0.3) + split.separator() + row = split.row() + row.prop(tex, "mapping_x", text="") + row.prop(tex, "mapping_y", text="") + row.prop(tex, "mapping_z", text="") + + elif isinstance(idblock, Material): + split = layout.split(percentage=0.3) + split.label(text="Projection:") + split.prop(tex, "mapping", text="") + + split = layout.split() + + col = split.column() + if tex.texture_coords in {'ORCO', 'UV'}: + col.prop(tex, "use_from_dupli") + if idblock.type == 'VOLUME' and tex.texture_coords == 'ORCO': + col.prop(tex, "use_map_to_bounds") + elif tex.texture_coords == 'OBJECT': + col.prop(tex, "use_from_original") + if idblock.type == 'VOLUME': + col.prop(tex, "use_map_to_bounds") + else: + col.label() + + col = split.column() + row = col.row() + row.prop(tex, "mapping_x", text="") + row.prop(tex, "mapping_y", text="") + row.prop(tex, "mapping_z", text="") + + row = layout.row() + row.column().prop(tex, "offset") + row.column().prop(tex, "scale") + + +class TEXTURE_PT_POV_influence(TextureSlotPanel, Panel): + """Use this class to define pov texture influence buttons.""" + + bl_label = "Influence" + COMPAT_ENGINES = {'POVRAY_RENDER'} + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + # bl_context = 'texture' + @classmethod + def poll(cls, context): + idblock = pov_context_tex_datablock(context) + if ( + # isinstance(idblock, Brush) and # Brush used for everything since 2.8 + context.scene.texture_context + == 'OTHER' + ): # XXX replace by isinstance(idblock, bpy.types.Brush) and ... + return False + + # Specify below also for pov_world_texture_slots, lights etc. + # to display for various types of slots but only when any + if not getattr(idblock, "pov_texture_slots", None): + return False + + engine = context.scene.render.engine + return engine in cls.COMPAT_ENGINES + + def draw(self, context): + + layout = self.layout + + idblock = pov_context_tex_datablock(context) + # tex = context.pov_texture_slot + # mat = bpy.context.active_object.active_material + texslot = idblock.pov_texture_slots[ + idblock.pov.active_texture_index + ] # bpy.data.textures[mat.active_texture_index] + # below tex is unused + tex = bpy.data.textures[idblock.pov_texture_slots[idblock.pov.active_texture_index].texture] + + def factor_but(layout, toggle, factor, name): + row = layout.row(align=True) + row.prop(texslot, toggle, text="") + sub = row.row(align=True) + sub.active = getattr(texslot, toggle) + sub.prop(texslot, factor, text=name, slider=True) + return sub # XXX, temp. use_map_normal needs to override. + + if isinstance(idblock, Material): + split = layout.split() + + col = split.column() + if idblock.pov.type in {'SURFACE', 'WIRE'}: + + split = layout.split() + + col = split.column() + col.label(text="Diffuse:") + factor_but(col, "use_map_diffuse", "diffuse_factor", "Intensity") + factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color") + factor_but(col, "use_map_alpha", "alpha_factor", "Alpha") + factor_but(col, "use_map_translucency", "translucency_factor", "Translucency") + + col.label(text="Specular:") + factor_but(col, "use_map_specular", "specular_factor", "Intensity") + factor_but(col, "use_map_color_spec", "specular_color_factor", "Color") + factor_but(col, "use_map_hardness", "hardness_factor", "Hardness") + + col = split.column() + col.label(text="Shading:") + factor_but(col, "use_map_ambient", "ambient_factor", "Ambient") + factor_but(col, "use_map_emit", "emit_factor", "Emit") + factor_but(col, "use_map_mirror", "mirror_factor", "Mirror") + factor_but(col, "use_map_raymir", "raymir_factor", "Ray Mirror") + + col.label(text="Geometry:") + # XXX replace 'or' when displacement is fixed to not rely on normal influence value. + sub_tmp = factor_but(col, "use_map_normal", "normal_factor", "Normal") + sub_tmp.active = texslot.use_map_normal or texslot.use_map_displacement + # END XXX + + factor_but(col, "use_map_warp", "warp_factor", "Warp") + factor_but(col, "use_map_displacement", "displacement_factor", "Displace") + + elif idblock.pov.type == 'HALO': + layout.label(text="Halo:") + + split = layout.split() + + col = split.column() + factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color") + factor_but(col, "use_map_alpha", "alpha_factor", "Alpha") + + col = split.column() + factor_but(col, "use_map_raymir", "raymir_factor", "Size") + factor_but(col, "use_map_hardness", "hardness_factor", "Hardness") + factor_but(col, "use_map_translucency", "translucency_factor", "Add") + elif idblock.pov.type == 'VOLUME': + layout.label(text="Volume:") + + split = layout.split() + + col = split.column() + factor_but(col, "use_map_density", "density_factor", "Density") + factor_but(col, "use_map_emission", "emission_factor", "Emission") + factor_but(col, "use_map_scatter", "scattering_factor", "Scattering") + factor_but(col, "use_map_reflect", "reflection_factor", "Reflection") + + col = split.column() + col.label(text=" ") + factor_but(col, "use_map_color_emission", "emission_color_factor", "Emission Color") + factor_but( + col, + "use_map_color_transmission", + "transmission_color_factor", + "Transmission Color", + ) + factor_but( + col, "use_map_color_reflection", "reflection_color_factor", "Reflection Color" + ) + + layout.label(text="Geometry:") + + split = layout.split() + + col = split.column() + factor_but(col, "use_map_warp", "warp_factor", "Warp") + + col = split.column() + factor_but(col, "use_map_displacement", "displacement_factor", "Displace") + + elif isinstance(idblock, Light): + split = layout.split() + + col = split.column() + factor_but(col, "use_map_color", "color_factor", "Color") + + col = split.column() + factor_but(col, "use_map_shadow", "shadow_factor", "Shadow") + + elif isinstance(idblock, World): + split = layout.split() + + col = split.column() + factor_but(col, "use_map_blend", "blend_factor", "Blend") + factor_but(col, "use_map_horizon", "horizon_factor", "Horizon") + + col = split.column() + factor_but(col, "use_map_zenith_up", "zenith_up_factor", "Zenith Up") + factor_but(col, "use_map_zenith_down", "zenith_down_factor", "Zenith Down") + elif isinstance(idblock, ParticleSettings): + split = layout.split() + + col = split.column() + col.label(text="General:") + factor_but(col, "use_map_time", "time_factor", "Time") + factor_but(col, "use_map_life", "life_factor", "Lifetime") + factor_but(col, "use_map_density", "density_factor", "Density") + factor_but(col, "use_map_size", "size_factor", "Size") + + col = split.column() + col.label(text="Physics:") + factor_but(col, "use_map_velocity", "velocity_factor", "Velocity") + factor_but(col, "use_map_damp", "damp_factor", "Damp") + factor_but(col, "use_map_gravity", "gravity_factor", "Gravity") + factor_but(col, "use_map_field", "field_factor", "Force Fields") + + layout.label(text="Hair:") + + split = layout.split() + + col = split.column() + factor_but(col, "use_map_length", "length_factor", "Length") + factor_but(col, "use_map_clump", "clump_factor", "Clump") + factor_but(col, "use_map_twist", "twist_factor", "Twist") + + col = split.column() + factor_but(col, "use_map_kink_amp", "kink_amp_factor", "Kink Amplitude") + factor_but(col, "use_map_kink_freq", "kink_freq_factor", "Kink Frequency") + factor_but(col, "use_map_rough", "rough_factor", "Rough") + + elif isinstance(idblock, FreestyleLineStyle): + split = layout.split() + + col = split.column() + factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color") + col = split.column() + factor_but(col, "use_map_alpha", "alpha_factor", "Alpha") + + layout.separator() + + if not isinstance(idblock, ParticleSettings): + split = layout.split() + + col = split.column() + # col.prop(tex, "blend_type", text="Blend") #deprecated since 2.8 + # col.prop(tex, "use_rgb_to_intensity") #deprecated since 2.8 + # color is used on gray-scale textures even when use_rgb_to_intensity is disabled. + # col.prop(tex, "color", text="") #deprecated since 2.8 + + col = split.column() + # col.prop(tex, "invert", text="Negative") #deprecated since 2.8 + # col.prop(tex, "use_stencil") #deprecated since 2.8 + + # if isinstance(idblock, (Material, World)): + # col.prop(tex, "default_value", text="DVar", slider=True) + + +class TEXTURE_PT_POV_tex_gamma(TextureButtonsPanel, Panel): + """Use this class to define pov texture gamma buttons.""" + + bl_label = "Image Gamma" + COMPAT_ENGINES = {'POVRAY_RENDER'} + + def draw_header(self, context): + tex = context.texture + + self.layout.prop(tex.pov, "tex_gamma_enable", text="", icon='SEQ_LUMA_WAVEFORM') + + def draw(self, context): + layout = self.layout + + tex = context.texture + + layout.active = tex.pov.tex_gamma_enable + layout.prop(tex.pov, "tex_gamma_value", text="Gamma Value") + + +# commented out below UI for texture only custom code inside exported material: +# class TEXTURE_PT_povray_replacement_text(TextureButtonsPanel, Panel): +# bl_label = "Custom POV Code" +# COMPAT_ENGINES = {'POVRAY_RENDER'} + +# def draw(self, context): +# layout = self.layout + +# tex = context.texture + +# col = layout.column() +# col.label(text="Replace properties with:") +# col.prop(tex.pov, "replacement_text", text="") + + +classes = ( + WORLD_TEXTURE_SLOTS_UL_POV_layerlist, + TEXTURE_MT_POV_specials, + TEXTURE_PT_POV_context_texture, + TEXTURE_PT_colors, + TEXTURE_PT_POV_type, + TEXTURE_PT_POV_preview, + TEXTURE_PT_POV_parameters, + TEXTURE_PT_POV_tex_gamma, + MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist, + TEXTURE_OT_POV_texture_slot_add, + TEXTURE_OT_POV_texture_slot_remove, + TEXTURE_PT_POV_influence, + TEXTURE_PT_POV_mapping, +) + + +def register(): + + for cls in classes: + register_class(cls) + + +def unregister(): + + for cls in reversed(classes): + if cls != TEXTURE_PT_context: + unregister_class(cls) |