Fix #100973: Node Wrangler: previewing node if hierarchy not active
[blender-addons.git] / render_povray / texturing_gui.py
blob8260ffe5d19b7ea9de1ae3ec172b55805270b72d
1 # SPDX-FileCopyrightText: 2021-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 """User interface for texturing tools."""
7 import bpy
8 from bpy.utils import register_class, unregister_class
9 from bpy.types import (
10 Operator,
11 Menu,
12 UIList,
13 Panel,
14 Brush,
15 Material,
16 Light,
17 World,
18 ParticleSettings,
19 FreestyleLineStyle,
22 # from .ui import TextureButtonsPanel
24 from .shading_properties import pov_context_tex_datablock
25 from bl_ui.properties_paint_common import brush_texture_settings
27 # Example of wrapping every class 'as is'
28 from bl_ui import properties_texture
30 # unused, replaced by pov_context_tex_datablock (no way to use?):
31 # from bl_ui.properties_texture import context_tex_datablock
32 # from bl_ui.properties_texture import texture_filter_common #unused yet?
34 for member in dir(properties_texture):
35 subclass = getattr(properties_texture, member)
36 if hasattr(subclass, "COMPAT_ENGINES"):
37 subclass.COMPAT_ENGINES.add("POVRAY_RENDER")
38 del properties_texture
41 class TextureButtonsPanel:
42 """Use this class to define buttons from the texture tab properties."""
44 bl_space_type = "PROPERTIES"
45 bl_region_type = "WINDOW"
46 bl_context = "texture"
47 COMPAT_ENGINES = {"POVRAY_RENDER"}
49 @classmethod
50 def poll(cls, context):
51 tex = context.texture
52 rd = context.scene.render
53 return tex and (rd.engine in cls.COMPAT_ENGINES)
56 class TEXTURE_MT_POV_specials(Menu):
57 """Use this class to define pov texture slot operations buttons."""
59 bl_label = "Texture Specials"
60 COMPAT_ENGINES = {"POVRAY_RENDER"}
62 def draw(self, context):
63 layout = self.layout
65 layout.operator("texture.slot_copy", icon="COPYDOWN")
66 layout.operator("texture.slot_paste", icon="PASTEDOWN")
69 class WORLD_TEXTURE_SLOTS_UL_POV_layerlist(UIList):
70 """Use this class to show pov texture slots list."""
72 index: bpy.props.IntProperty(name="index")
73 # should active_propname be index or..?
75 def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
76 # world = context.scene.world # .pov # NOT USED
77 # active_data = world.pov # NOT USED
78 # tex = context.texture #may be needed later?
80 # We could write some code to decide which icon to use here...
81 # custom_icon = 'TEXTURE'
83 # ob = data
84 slot = item
85 # ma = slot.name
86 # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
87 if self.layout_type in {"DEFAULT", "COMPACT"}:
88 # You should always start your row layout by a label (icon + text), or a non-embossed text field,
89 # this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
90 # We use icon_value of label, as our given icon is an integer value, not an enum ID.
91 # Note "data" names should never be translated!
92 if slot:
93 layout.prop(slot, "texture", text="", emboss=False, icon="TEXTURE")
94 else:
95 layout.label(text="New", translate=False, icon_value=icon)
96 # 'GRID' layout type should be as compact as possible (typically a single icon!).
97 elif self.layout_type in {"GRID"}:
98 layout.alignment = "CENTER"
99 layout.label(text="", icon_value=icon)
102 class MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist(UIList):
103 """Use this class to show pov texture slots list."""
105 # texture_slots:
106 index: bpy.props.IntProperty(name="index")
107 # foo = random prop
109 def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
110 # ob = data
111 slot = item
112 # ma = slot.name
113 # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
114 if self.layout_type in {"DEFAULT", "COMPACT"}:
115 # You should always start your row layout by a label (icon + text), or a non-embossed text field,
116 # this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
117 # We use icon_value of label, as our given icon is an integer value, not an enum ID.
118 # Note "data" names should never be translated!
119 if slot:
120 layout.prop(slot, "texture", text="", emboss=False, icon="TEXTURE")
121 else:
122 layout.label(text="New", translate=False, icon_value=icon)
123 # 'GRID' layout type should be as compact as possible (typically a single icon!).
124 elif self.layout_type in {"GRID"}:
125 layout.alignment = "CENTER"
126 layout.label(text="", icon_value=icon)
129 class TEXTURE_PT_context(TextureButtonsPanel, Panel):
130 """Rewrite of this existing class to modify it."""
132 bl_label = ""
133 bl_context = "texture"
134 bl_options = {"HIDE_HEADER"}
135 COMPAT_ENGINES = {"POVRAY_RENDER", "BLENDER_EEVEE", "BLENDER_WORKBENCH"}
136 # register but not unregistered because
137 # the modified parts concern only POVRAY_RENDER
139 @classmethod
140 def poll(cls, context):
141 return (
142 context.scene.texture_context
143 not in ("MATERIAL", "WORLD", "LIGHT", "PARTICLES", "LINESTYLE")
144 or context.scene.render.engine != "POVRAY_RENDER"
147 def draw(self, context):
148 layout = self.layout
149 tex = context.texture
150 space = context.space_data
151 pin_id = space.pin_id
152 use_pin_id = space.use_pin_id
153 user = context.texture_user
155 col = layout.column()
157 if not (use_pin_id and isinstance(pin_id, bpy.types.Texture)):
158 pin_id = None
160 if not pin_id:
161 col.template_texture_user()
163 if user or pin_id:
164 col.separator()
166 if pin_id:
167 col.template_ID(space, "pin_id")
168 else:
169 propname = context.texture_user_property.identifier
170 col.template_ID(user, propname, new="texture.new")
172 if tex:
173 col.separator()
175 split = col.split(factor=0.2)
176 split.label(text="Type")
177 split.prop(tex, "type", text="")
180 class TEXTURE_PT_POV_context_texture(TextureButtonsPanel, Panel):
181 """Use this class to show pov texture context buttons."""
183 bl_label = ""
184 bl_options = {"HIDE_HEADER"}
185 COMPAT_ENGINES = {"POVRAY_RENDER"}
187 @classmethod
188 def poll(cls, context):
189 engine = context.scene.render.engine
190 # if not (hasattr(context, "pov_texture_slot") or hasattr(context, "texture_node")):
191 # return False
192 return (
193 context.material
194 or context.scene.world
195 or context.light
196 or context.texture
197 or context.line_style
198 or context.particle_system
199 or isinstance(context.space_data.pin_id, ParticleSettings)
200 or context.texture_user
201 ) and (engine in cls.COMPAT_ENGINES)
203 def draw(self, context):
204 layout = self.layout
206 scene = context.scene
207 mat = context.view_layer.objects.active.active_material
208 wld = context.scene.world
210 layout.prop(scene, "texture_context", expand=True)
211 if scene.texture_context == "MATERIAL" and mat is not None:
213 row = layout.row()
214 row.template_list(
215 "MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist",
217 mat,
218 "pov_texture_slots",
219 mat.pov,
220 "active_texture_index",
221 rows=2,
222 maxrows=16,
223 type="DEFAULT",
225 col = row.column(align=True)
226 col.operator("pov.textureslotadd", icon="ADD", text="")
227 col.operator("pov.textureslotremove", icon="REMOVE", text="")
228 # XXX todo: recreate for pov_texture_slots?
229 # col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
230 # col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
231 col.separator()
233 if mat.pov_texture_slots:
234 index = mat.pov.active_texture_index
235 slot = mat.pov_texture_slots[index]
236 try:
237 povtex = slot.texture # slot.name
238 tex = bpy.data.textures[povtex]
239 col.prop(tex, "use_fake_user", text="")
240 # layout.label(text='Linked Texture data browser:')
241 # propname = slot.texture_search
242 # if slot.texture was a pointer to texture data rather than just a name string:
243 # layout.template_ID(povtex, "texture", new="texture.new")
244 except KeyError:
245 tex = None
246 row = layout.row(align=True)
247 row.prop_search(
248 slot, "texture_search", bpy.data, "textures", text="", icon="TEXTURE"
251 row.operator("pov.textureslotupdate", icon="FILE_REFRESH", text="")
252 # try:
253 # bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[
254 # slot.texture_search
256 # bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[
257 # slot.texture_search
259 # except KeyError:
260 # # texture not hand-linked by user
261 # pass
263 if tex:
264 layout.separator()
265 split = layout.split(factor=0.2)
266 split.label(text="Type")
267 split.prop(tex, "type", text="")
269 # else:
270 # for i in range(18): # length of material texture slots
271 # mat.pov_texture_slots.add()
272 elif scene.texture_context == "WORLD" and wld is not None:
274 row = layout.row()
275 row.template_list(
276 "WORLD_TEXTURE_SLOTS_UL_POV_layerlist",
278 wld,
279 "pov_texture_slots",
280 wld.pov,
281 "active_texture_index",
282 rows=2,
283 maxrows=16,
284 type="DEFAULT",
286 col = row.column(align=True)
287 col.operator("pov.textureslotadd", icon="ADD", text="")
288 col.operator("pov.textureslotremove", icon="REMOVE", text="")
290 # todo: recreate for pov_texture_slots?
291 # col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
292 # col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
293 col.separator()
295 if wld.pov_texture_slots:
296 index = wld.pov.active_texture_index
297 slot = wld.pov_texture_slots[index]
298 povtex = slot.texture # slot.name
299 tex = bpy.data.textures[povtex]
300 col.prop(tex, "use_fake_user", text="")
301 # layout.label(text='Linked Texture data browser:')
302 # propname = slot.texture_search # NOT USED
303 # if slot.texture was a pointer to texture data rather than just a name string:
304 # layout.template_ID(povtex, "texture", new="texture.new")
306 layout.prop_search(
307 slot, "texture_search", bpy.data, "textures", text="", icon="TEXTURE"
309 try:
310 bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[
311 slot.texture_search
313 bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[
314 slot.texture_search
316 except KeyError:
317 # texture not hand-linked by user
318 pass
320 if tex:
321 layout.separator()
322 split = layout.split(factor=0.2)
323 split.label(text="Type")
324 split.prop(tex, "type", text="")
327 class TEXTURE_OT_POV_context_texture_update(Operator):
328 """Use this class for the texture slot update button."""
330 bl_idname = "pov.textureslotupdate"
331 bl_label = "Update"
332 bl_description = "Update texture_slot"
333 bl_options = {"REGISTER", "UNDO"}
334 COMPAT_ENGINES = {"POVRAY_RENDER"}
336 @classmethod
337 def poll(cls, context):
338 engine = context.scene.render.engine
339 mate = context.view_layer.objects.active.active_material
340 return mate and engine in cls.COMPAT_ENGINES
342 def execute(self, context):
343 # tex.use_fake_user = True
344 mat = context.view_layer.objects.active.active_material
345 index = mat.pov.active_texture_index
346 slot = mat.pov_texture_slots[index]
347 povtex = slot.texture # slot.name
348 tex = bpy.data.textures[povtex]
350 # Switch paint brush and paint brush mask
351 # to this texture so settings remain contextual
352 bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[slot.texture_search]
353 bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[
354 slot.texture_search
357 return {"FINISHED"}
360 # Commented out below is a reminder of what existed in Blender Internal
361 # attributes need to be recreated
363 slot = getattr(context, "texture_slot", None)
364 node = getattr(context, "texture_node", None)
365 space = context.space_data
367 #attempt at replacing removed space_data
368 mtl = getattr(context, "material", None)
369 if mtl != None:
370 spacedependant = mtl
371 wld = getattr(context, "world", None)
372 if wld != None:
373 spacedependant = wld
374 lgt = getattr(context, "light", None)
375 if lgt != None:
376 spacedependant = lgt
379 #idblock = context.particle_system.settings
381 tex = getattr(context, "texture", None)
382 if tex != None:
383 spacedependant = tex
387 scene = context.scene
388 idblock = scene.pov#pov_context_tex_datablock(context)
389 pin_id = space.pin_id
391 #spacedependant.use_limited_texture_context = True
393 if space.use_pin_id and not isinstance(pin_id, Texture):
394 idblock = id_tex_datablock(pin_id)
395 pin_id = None
397 if not space.use_pin_id:
398 layout.row().prop(spacedependant, "texture_context", expand=True)
399 pin_id = None
401 if spacedependant.texture_context == 'OTHER':
402 if not pin_id:
403 layout.template_texture_user()
404 user = context.texture_user
405 if user or pin_id:
406 layout.separator()
408 row = layout.row()
410 if pin_id:
411 row.template_ID(space, "pin_id")
412 else:
413 propname = context.texture_user_property.identifier
414 row.template_ID(user, propname, new="texture.new")
416 if tex:
417 split = layout.split(factor=0.2)
418 if tex.use_nodes:
419 if slot:
420 split.label(text="Output:")
421 split.prop(slot, "output_node", text="")
422 else:
423 split.label(text="Type:")
424 split.prop(tex, "type", text="")
425 return
427 tex_collection = (pin_id is None) and (node is None) and (spacedependant.texture_context not in ('LINESTYLE','OTHER'))
429 if tex_collection:
431 pov = getattr(context, "pov", None)
432 active_texture_index = getattr(spacedependant, "active_texture_index", None)
433 print (pov)
434 print(idblock)
435 print(active_texture_index)
436 row = layout.row()
438 row.template_list("TEXTURE_UL_texslots", "", idblock, "texture_slots",
439 idblock, "active_texture_index", rows=2, maxrows=16, type="DEFAULT")
441 # row.template_list("WORLD_TEXTURE_SLOTS_UL_List", "texture_slots", world,
442 # world.texture_slots, world, "active_texture_index", rows=2)
444 col = row.column(align=True)
445 col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
446 col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
447 col.menu("TEXTURE_MT_POV_specials", icon='DOWNARROW_HLT', text="")
449 if tex_collection:
450 layout.template_ID(idblock, "active_texture", new="texture.new")
451 elif node:
452 layout.template_ID(node, "texture", new="texture.new")
453 elif idblock:
454 layout.template_ID(idblock, "texture", new="texture.new")
456 if pin_id:
457 layout.template_ID(space, "pin_id")
459 if tex:
460 split = layout.split(factor=0.2)
461 if tex.use_nodes:
462 if slot:
463 split.label(text="Output:")
464 split.prop(slot, "output_node", text="")
465 else:
466 split.label(text="Type:")
470 class TEXTURE_PT_colors(TextureButtonsPanel, Panel):
471 """Use this class to show pov color ramps."""
473 bl_label = "Colors"
474 bl_options = {"DEFAULT_CLOSED"}
475 COMPAT_ENGINES = {"POVRAY_RENDER"}
477 def draw(self, context):
478 layout = self.layout
480 tex = context.texture
482 layout.prop(tex, "use_color_ramp", text="Ramp")
483 if tex.use_color_ramp:
484 layout.template_color_ramp(tex, "color_ramp", expand=True)
486 split = layout.split()
488 col = split.column()
489 col.label(text="RGB Multiply:")
490 sub = col.column(align=True)
491 sub.prop(tex, "factor_red", text="R")
492 sub.prop(tex, "factor_green", text="G")
493 sub.prop(tex, "factor_blue", text="B")
495 col = split.column()
496 col.label(text="Adjust:")
497 col.prop(tex, "intensity")
498 col.prop(tex, "contrast")
499 col.prop(tex, "saturation")
501 col = layout.column()
502 col.prop(tex, "use_clamp", text="Clamp")
505 # Texture Slot Panels #
508 class TEXTURE_OT_POV_texture_slot_add(Operator):
509 """Use this class for the add texture slot button."""
511 bl_idname = "pov.textureslotadd"
512 bl_label = "Add"
513 bl_description = "Add texture_slot"
514 bl_options = {"REGISTER", "UNDO"}
515 COMPAT_ENGINES = {"POVRAY_RENDER"}
517 def execute(self, context):
518 idblock = pov_context_tex_datablock(context)
519 slot_brush = bpy.data.brushes.new("POVtextureSlot")
520 context.tool_settings.image_paint.brush = slot_brush
521 tex = bpy.data.textures.new(name="Texture", type="IMAGE")
522 # tex.use_fake_user = True
523 # mat = context.view_layer.objects.active.active_material
524 slot = idblock.pov_texture_slots.add()
525 slot.name = tex.name
526 slot.texture = tex.name
527 slot.texture_search = tex.name
528 # Switch paint brush and paint brush mask
529 # to this texture so settings remain contextual
530 bpy.context.tool_settings.image_paint.brush.texture = tex
531 bpy.context.tool_settings.image_paint.brush.mask_texture = tex
532 idblock.pov.active_texture_index = len(idblock.pov_texture_slots) - 1
534 # for area in bpy.context.screen.areas:
535 # if area.type in ['PROPERTIES']:
536 # area.tag_redraw()
538 return {"FINISHED"}
541 class TEXTURE_OT_POV_texture_slot_remove(Operator):
542 """Use this class for the remove texture slot button."""
544 bl_idname = "pov.textureslotremove"
545 bl_label = "Remove"
546 bl_description = "Remove texture_slot"
547 bl_options = {"REGISTER", "UNDO"}
548 COMPAT_ENGINES = {"POVRAY_RENDER"}
550 def execute(self, context):
551 idblock = pov_context_tex_datablock(context)
552 # mat = context.view_layer.objects.active.active_material
553 # tex_slot = idblock.pov_texture_slots.remove(idblock.pov.active_texture_index) # not used
554 # tex_to_delete = context.tool_settings.image_paint.brush.texture
555 # bpy.data.textures.remove(tex_to_delete, do_unlink=True, do_id_user=True, do_ui_user=True)
556 idblock.pov_texture_slots.remove(idblock.pov.active_texture_index)
557 if idblock.pov.active_texture_index > 0:
558 idblock.pov.active_texture_index -= 1
559 # try:
560 # tex = idblock.pov_texture_slots[idblock.pov.active_texture_index].texture
561 # except IndexError:
562 # No more slots
563 return {"FINISHED"}
564 # Switch paint brush to previous texture so settings remain contextual
565 # if 'tex' in locals(): # Would test is the tex variable is assigned / exists
566 # bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[tex]
567 # bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[tex]
569 return {"FINISHED"}
572 class TextureSlotPanel(TextureButtonsPanel):
573 """Use this class to show pov texture slots panel."""
575 COMPAT_ENGINES = {"POVRAY_RENDER"}
577 @classmethod
578 def poll(cls, context):
579 if not hasattr(context, "pov_texture_slot"):
580 return False
582 engine = context.scene.render.engine
583 # return TextureButtonsPanel.poll(cls, context) and (engine in cls.COMPAT_ENGINES)
584 return TextureButtonsPanel.poll(context) and (engine in cls.COMPAT_ENGINES)
587 class TEXTURE_PT_POV_type(TextureButtonsPanel, Panel):
588 """Use this class to define pov texture type buttons."""
590 bl_label = "POV Textures"
591 COMPAT_ENGINES = {"POVRAY_RENDER"}
592 bl_options = {"HIDE_HEADER"}
594 def draw(self, context):
595 layout = self.layout
596 # world = context.world # unused
597 tex = context.texture
599 split = layout.split(factor=0.2)
600 split.label(text="Pattern")
601 split.prop(tex.pov, "tex_pattern_type", text="")
603 # row = layout.row()
604 # row.template_list("WORLD_TEXTURE_SLOTS_UL_List", "texture_slots", world,
605 # world.texture_slots, world, "active_texture_index")
608 class TEXTURE_PT_POV_preview(TextureButtonsPanel, Panel):
609 """Use this class to define pov texture preview panel."""
611 bl_label = "Preview"
612 COMPAT_ENGINES = {"POVRAY_RENDER"}
613 bl_options = {"HIDE_HEADER"}
615 @classmethod
616 def poll(cls, context):
617 engine = context.scene.render.engine
618 if not hasattr(context, "pov_texture_slot"):
619 return False
620 tex = context.texture
621 # mat = bpy.context.active_object.active_material #unused
622 return tex and (tex.pov.tex_pattern_type != "emulator") and (engine in cls.COMPAT_ENGINES)
624 def draw(self, context):
625 tex = context.texture
626 slot = getattr(context, "pov_texture_slot", None)
627 # idblock = pov_context_tex_datablock(context) # unused
628 layout = self.layout
629 # if idblock:
630 # layout.template_preview(tex, parent=idblock, slot=slot)
631 if tex.pov.tex_pattern_type != "emulator":
632 layout.operator("tex.preview_update")
633 else:
634 layout.template_preview(tex, slot=slot)
637 class TEXTURE_PT_POV_parameters(TextureButtonsPanel, Panel):
638 """Use this class to define pov texture pattern buttons."""
640 bl_label = "POV Pattern Options"
641 bl_options = {"HIDE_HEADER"}
642 COMPAT_ENGINES = {"POVRAY_RENDER"}
644 def draw(self, context):
645 # mat = bpy.context.active_object.active_material # Unused
646 tex = context.texture
647 if tex is not None and tex.pov.tex_pattern_type != "emulator":
648 layout = self.layout
649 if tex.pov.tex_pattern_type == "agate":
650 layout.prop(tex.pov, "modifier_turbulence", text="Agate Turbulence")
651 if tex.pov.tex_pattern_type in {"spiral1", "spiral2"}:
652 layout.prop(tex.pov, "modifier_numbers", text="Number of arms")
653 if tex.pov.tex_pattern_type == "tiling":
654 layout.prop(tex.pov, "modifier_numbers", text="Pattern number")
655 if tex.pov.tex_pattern_type == "magnet":
656 layout.prop(tex.pov, "magnet_style", text="Magnet style")
657 align = True
658 if tex.pov.tex_pattern_type == "quilted":
659 row = layout.row(align=align)
660 row.prop(tex.pov, "modifier_control0", text="Control0")
661 row.prop(tex.pov, "modifier_control1", text="Control1")
662 if tex.pov.tex_pattern_type == "brick":
663 col = layout.column(align=align)
664 row = col.row()
665 row.prop(tex.pov, "brick_size_x", text="Brick size X")
666 row.prop(tex.pov, "brick_size_y", text="Brick size Y")
667 row = col.row()
668 row.prop(tex.pov, "brick_size_z", text="Brick size Z")
669 row.prop(tex.pov, "brick_mortar", text="Brick mortar")
670 if tex.pov.tex_pattern_type in {"julia", "mandel", "magnet"}:
671 col = layout.column(align=align)
672 if tex.pov.tex_pattern_type == "julia":
673 row = col.row()
674 row.prop(tex.pov, "julia_complex_1", text="Complex 1")
675 row.prop(tex.pov, "julia_complex_2", text="Complex 2")
676 if tex.pov.tex_pattern_type == "magnet" and tex.pov.magnet_style == "julia":
677 row = col.row()
678 row.prop(tex.pov, "julia_complex_1", text="Complex 1")
679 row.prop(tex.pov, "julia_complex_2", text="Complex 2")
680 row = col.row()
681 if tex.pov.tex_pattern_type in {"julia", "mandel"}:
682 row.prop(tex.pov, "f_exponent", text="Exponent")
683 if tex.pov.tex_pattern_type == "magnet":
684 row.prop(tex.pov, "magnet_type", text="Type")
685 row.prop(tex.pov, "f_iter", text="Iterations")
686 row = col.row()
687 row.prop(tex.pov, "f_ior", text="Interior")
688 row.prop(tex.pov, "f_ior_fac", text="Factor I")
689 row = col.row()
690 row.prop(tex.pov, "f_eor", text="Exterior")
691 row.prop(tex.pov, "f_eor_fac", text="Factor E")
692 if tex.pov.tex_pattern_type == "gradient":
693 layout.label(text="Gradient orientation:")
694 column_flow = layout.column_flow(columns=3, align=True)
695 column_flow.prop(tex.pov, "grad_orient_x", text="X")
696 column_flow.prop(tex.pov, "grad_orient_y", text="Y")
697 column_flow.prop(tex.pov, "grad_orient_z", text="Z")
698 if tex.pov.tex_pattern_type == "pavement":
699 layout.prop(tex.pov, "pave_sides", text="Pavement:number of sides")
700 col = layout.column(align=align)
701 column_flow = col.column_flow(columns=3, align=True)
702 column_flow.prop(tex.pov, "pave_tiles", text="Tiles")
703 if tex.pov.pave_sides == "4" and tex.pov.pave_tiles == 6:
704 column_flow.prop(tex.pov, "pave_pat_35", text="Pattern")
705 if tex.pov.pave_sides == "6" and tex.pov.pave_tiles == 5:
706 column_flow.prop(tex.pov, "pave_pat_22", text="Pattern")
707 if tex.pov.pave_sides == "4" and tex.pov.pave_tiles == 5:
708 column_flow.prop(tex.pov, "pave_pat_12", text="Pattern")
709 if tex.pov.pave_sides == "3" and tex.pov.pave_tiles == 6:
710 column_flow.prop(tex.pov, "pave_pat_12", text="Pattern")
711 if tex.pov.pave_sides == "6" and tex.pov.pave_tiles == 4:
712 column_flow.prop(tex.pov, "pave_pat_7", text="Pattern")
713 if tex.pov.pave_sides == "4" and tex.pov.pave_tiles == 4:
714 column_flow.prop(tex.pov, "pave_pat_5", text="Pattern")
715 if tex.pov.pave_sides == "3" and tex.pov.pave_tiles == 5:
716 column_flow.prop(tex.pov, "pave_pat_4", text="Pattern")
717 if tex.pov.pave_sides == "6" and tex.pov.pave_tiles == 3:
718 column_flow.prop(tex.pov, "pave_pat_3", text="Pattern")
719 if tex.pov.pave_sides == "3" and tex.pov.pave_tiles == 4:
720 column_flow.prop(tex.pov, "pave_pat_3", text="Pattern")
721 if tex.pov.pave_sides == "4" and tex.pov.pave_tiles == 3:
722 column_flow.prop(tex.pov, "pave_pat_2", text="Pattern")
723 if tex.pov.pave_sides == "6" and tex.pov.pave_tiles == 6:
724 column_flow.label(text="!!! 5 tiles!")
725 column_flow.prop(tex.pov, "pave_form", text="Form")
726 if tex.pov.tex_pattern_type == "function":
727 layout.prop(tex.pov, "func_list", text="Functions")
728 if tex.pov.tex_pattern_type == "function" and tex.pov.func_list != "NONE":
729 func = None
730 if tex.pov.func_list in {"f_noise3d", "f_ph", "f_r", "f_th"}:
731 func = 0
732 if tex.pov.func_list in {
733 "f_comma",
734 "f_crossed_trough",
735 "f_cubic_saddle",
736 "f_cushion",
737 "f_devils_curve",
738 "f_enneper",
739 "f_glob",
740 "f_heart",
741 "f_hex_x",
742 "f_hex_y",
743 "f_hunt_surface",
744 "f_klein_bottle",
745 "f_kummer_surface_v1",
746 "f_lemniscate_of_gerono",
747 "f_mitre",
748 "f_nodal_cubic",
749 "f_noise_generator",
750 "f_odd",
751 "f_paraboloid",
752 "f_pillow",
753 "f_piriform",
754 "f_quantum",
755 "f_quartic_paraboloid",
756 "f_quartic_saddle",
757 "f_sphere",
758 "f_steiners_roman",
759 "f_torus_gumdrop",
760 "f_umbrella",
762 func = 1
763 if tex.pov.func_list in {
764 "f_bicorn",
765 "f_bifolia",
766 "f_boy_surface",
767 "f_superellipsoid",
768 "f_torus",
770 func = 2
771 if tex.pov.func_list in {
772 "f_ellipsoid",
773 "f_folium_surface",
774 "f_hyperbolic_torus",
775 "f_kampyle_of_eudoxus",
776 "f_parabolic_torus",
777 "f_quartic_cylinder",
778 "f_torus2",
780 func = 3
781 if tex.pov.func_list in {
782 "f_blob2",
783 "f_cross_ellipsoids",
784 "f_flange_cover",
785 "f_isect_ellipsoids",
786 "f_kummer_surface_v2",
787 "f_ovals_of_cassini",
788 "f_rounded_box",
789 "f_spikes_2d",
790 "f_strophoid",
792 func = 4
793 if tex.pov.func_list in {
794 "f_algbr_cyl1",
795 "f_algbr_cyl2",
796 "f_algbr_cyl3",
797 "f_algbr_cyl4",
798 "f_blob",
799 "f_mesh1",
800 "f_poly4",
801 "f_spikes",
803 func = 5
804 if tex.pov.func_list in {
805 "f_devils_curve_2d",
806 "f_dupin_cyclid",
807 "f_folium_surface_2d",
808 "f_hetero_mf",
809 "f_kampyle_of_eudoxus_2d",
810 "f_lemniscate_of_gerono_2d",
811 "f_polytubes",
812 "f_ridge",
813 "f_ridged_mf",
814 "f_spiral",
815 "f_witch_of_agnesi",
817 func = 6
818 if tex.pov.func_list in {"f_helix1", "f_helix2", "f_piriform_2d", "f_strophoid_2d"}:
819 func = 7
820 if tex.pov.func_list == "f_helical_torus":
821 func = 8
822 column_flow = layout.column_flow(columns=3, align=True)
823 column_flow.label(text="X")
824 column_flow.prop(tex.pov, "func_plus_x", text="")
825 column_flow.prop(tex.pov, "func_x", text="Value")
826 column_flow = layout.column_flow(columns=3, align=True)
827 column_flow.label(text="Y")
828 column_flow.prop(tex.pov, "func_plus_y", text="")
829 column_flow.prop(tex.pov, "func_y", text="Value")
830 column_flow = layout.column_flow(columns=3, align=True)
831 column_flow.label(text="Z")
832 column_flow.prop(tex.pov, "func_plus_z", text="")
833 column_flow.prop(tex.pov, "func_z", text="Value")
834 row = layout.row(align=align)
835 if func > 0:
836 row.prop(tex.pov, "func_P0", text="P0")
837 if func > 1:
838 row.prop(tex.pov, "func_P1", text="P1")
839 row = layout.row(align=align)
840 if func > 2:
841 row.prop(tex.pov, "func_P2", text="P2")
842 if func > 3:
843 row.prop(tex.pov, "func_P3", text="P3")
844 row = layout.row(align=align)
845 if func > 4:
846 row.prop(tex.pov, "func_P4", text="P4")
847 if func > 5:
848 row.prop(tex.pov, "func_P5", text="P5")
849 row = layout.row(align=align)
850 if func > 6:
851 row.prop(tex.pov, "func_P6", text="P6")
852 if func > 7:
853 row.prop(tex.pov, "func_P7", text="P7")
854 row = layout.row(align=align)
855 row.prop(tex.pov, "func_P8", text="P8")
856 row.prop(tex.pov, "func_P9", text="P9")
857 # ------------------------- End Patterns ------------------------- #
859 layout.prop(tex.pov, "warp_types", text="Warp types") # warp
860 if tex.pov.warp_types == "TOROIDAL":
861 layout.prop(tex.pov, "warp_tor_major_radius", text="Major radius")
862 if tex.pov.warp_types not in {"CUBIC", "NONE"}:
863 layout.prop(tex.pov, "warp_orientation", text="Warp orientation")
864 col = layout.column(align=align)
865 row = col.row()
866 row.prop(tex.pov, "warp_dist_exp", text="Distance exponent")
867 row = col.row()
868 row.prop(tex.pov, "modifier_frequency", text="Frequency")
869 row.prop(tex.pov, "modifier_phase", text="Phase")
871 row = layout.row()
873 row.label(text="Offset:")
874 row.label(text="Scale:")
875 row.label(text="Rotate:")
876 col = layout.column(align=align)
877 row = col.row()
878 row.prop(tex.pov, "tex_mov_x", text="X")
879 row.prop(tex.pov, "tex_scale_x", text="X")
880 row.prop(tex.pov, "tex_rot_x", text="X")
881 row = col.row()
882 row.prop(tex.pov, "tex_mov_y", text="Y")
883 row.prop(tex.pov, "tex_scale_y", text="Y")
884 row.prop(tex.pov, "tex_rot_y", text="Y")
885 row = col.row()
886 row.prop(tex.pov, "tex_mov_z", text="Z")
887 row.prop(tex.pov, "tex_scale_z", text="Z")
888 row.prop(tex.pov, "tex_rot_z", text="Z")
889 row = layout.row()
891 row.label(text="Turbulence:")
892 col = layout.column(align=align)
893 row = col.row()
894 row.prop(tex.pov, "warp_turbulence_x", text="X")
895 row.prop(tex.pov, "modifier_octaves", text="Octaves")
896 row = col.row()
897 row.prop(tex.pov, "warp_turbulence_y", text="Y")
898 row.prop(tex.pov, "modifier_lambda", text="Lambda")
899 row = col.row()
900 row.prop(tex.pov, "warp_turbulence_z", text="Z")
901 row.prop(tex.pov, "modifier_omega", text="Omega")
904 class TEXTURE_PT_POV_mapping(TextureSlotPanel, Panel):
905 """Use this class to define POV texture mapping buttons."""
907 bl_label = "Mapping"
908 COMPAT_ENGINES = {"POVRAY_RENDER"}
909 bl_space_type = "PROPERTIES"
910 bl_region_type = "WINDOW"
912 @classmethod
913 def poll(cls, context):
914 idblock = pov_context_tex_datablock(context)
915 if isinstance(idblock, Brush) and not context.sculpt_object:
916 return False
918 if not getattr(context, "texture_slot", None):
919 return False
921 engine = context.scene.render.engine
922 return engine in cls.COMPAT_ENGINES
924 def draw(self, context):
925 layout = self.layout
927 idblock = pov_context_tex_datablock(context)
928 mat = bpy.context.active_object.active_material
929 # tex = context.texture_slot
930 tex = mat.pov_texture_slots[mat.active_texture_index]
931 if not isinstance(idblock, Brush):
932 split = layout.split(percentage=0.3)
933 col = split.column()
934 col.label(text="Coordinates:")
935 col = split.column()
936 col.prop(tex, "texture_coords", text="")
938 if tex.texture_coords == "ORCO":
940 ob = context.object
941 if ob and ob.type == 'MESH':
942 split = layout.split(percentage=0.3)
943 split.label(text="Mesh:")
944 split.prop(ob.data, "texco_mesh", text="")
946 elif tex.texture_coords == "UV":
947 split = layout.split(percentage=0.3)
948 split.label(text="Map:")
949 ob = context.object
950 if ob and ob.type == "MESH":
951 split.prop_search(tex, "uv_layer", ob.data, "uv_textures", text="")
952 else:
953 split.prop(tex, "uv_layer", text="")
955 elif tex.texture_coords == "OBJECT":
956 split = layout.split(percentage=0.3)
957 split.label(text="Object:")
958 split.prop(tex, "object", text="")
960 elif tex.texture_coords == "ALONG_STROKE":
961 split = layout.split(percentage=0.3)
962 split.label(text="Use Tips:")
963 split.prop(tex, "use_tips", text="")
965 if isinstance(idblock, Brush):
966 if context.sculpt_object or context.image_paint_object:
967 brush_texture_settings(layout, idblock, context.sculpt_object)
968 else:
969 if isinstance(idblock, FreestyleLineStyle):
970 split = layout.split(percentage=0.3)
971 split.label(text="Projection:")
972 split.prop(tex, "mapping", text="")
974 split = layout.split(percentage=0.3)
975 split.separator()
976 row = split.row()
977 row.prop(tex, "mapping_x", text="")
978 row.prop(tex, "mapping_y", text="")
979 row.prop(tex, "mapping_z", text="")
981 elif isinstance(idblock, Material):
982 split = layout.split(percentage=0.3)
983 split.label(text="Projection:")
984 split.prop(tex, "mapping", text="")
986 split = layout.split()
988 col = split.column()
989 if tex.texture_coords in {"ORCO", "UV"}:
990 col.prop(tex, "use_from_dupli")
991 if idblock.type == "VOLUME" and tex.texture_coords == "ORCO":
992 col.prop(tex, "use_map_to_bounds")
993 elif tex.texture_coords == "OBJECT":
994 col.prop(tex, "use_from_original")
995 if idblock.type == "VOLUME":
996 col.prop(tex, "use_map_to_bounds")
997 else:
998 col.label()
1000 col = split.column()
1001 row = col.row()
1002 row.prop(tex, "mapping_x", text="")
1003 row.prop(tex, "mapping_y", text="")
1004 row.prop(tex, "mapping_z", text="")
1006 row = layout.row()
1007 row.column().prop(tex, "offset")
1008 row.column().prop(tex, "scale")
1011 class TEXTURE_PT_POV_influence(TextureSlotPanel, Panel):
1012 """Use this class to define pov texture influence buttons."""
1014 bl_label = "Influence"
1015 COMPAT_ENGINES = {"POVRAY_RENDER"}
1016 bl_space_type = "PROPERTIES"
1017 bl_region_type = "WINDOW"
1018 # bl_context = 'texture'
1020 @classmethod
1021 def poll(cls, context):
1022 idblock = pov_context_tex_datablock(context)
1023 if (
1024 # isinstance(idblock, Brush) and # Brush used for everything since 2.8
1025 context.scene.texture_context
1026 == "OTHER"
1027 ): # XXX replace by isinstance(idblock, bpy.types.Brush) and ...
1028 return False
1030 # Specify below also for pov_world_texture_slots, lights etc.
1031 # to display for various types of slots but only when any
1032 if not getattr(idblock, "pov_texture_slots", None):
1033 return False
1035 engine = context.scene.render.engine
1036 return engine in cls.COMPAT_ENGINES
1038 def draw(self, context):
1040 layout = self.layout
1042 idblock = pov_context_tex_datablock(context)
1043 # tex = context.pov_texture_slot
1044 # mat = bpy.context.active_object.active_material
1045 texslot = idblock.pov_texture_slots[
1046 idblock.pov.active_texture_index
1047 ] # bpy.data.textures[mat.active_texture_index]
1048 # below tex unused yet ...maybe for particles?
1049 try:
1050 tex = bpy.data.textures[
1051 idblock.pov_texture_slots[idblock.pov.active_texture_index].texture
1052 ] # NOT USED
1053 except KeyError:
1054 tex = None # NOT USED
1056 def factor_but(layout, toggle, factor, name):
1057 row = layout.row(align=True)
1058 row.prop(texslot, toggle, text="")
1059 sub = row.row(align=True)
1060 sub.active = getattr(texslot, toggle)
1061 sub.prop(texslot, factor, text=name, slider=True)
1062 return sub # XXX, temp. use_map_normal needs to override.
1064 if isinstance(idblock, Material):
1065 split = layout.split()
1067 col = split.column()
1068 if idblock.pov.type in {"SURFACE", "WIRE"}:
1070 split = layout.split()
1072 col = split.column()
1073 col.label(text="Diffuse:")
1074 factor_but(col, "use_map_diffuse", "diffuse_factor", "Intensity")
1075 factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
1076 factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
1077 factor_but(col, "use_map_translucency", "translucency_factor", "Translucency")
1079 col.label(text="Specular:")
1080 factor_but(col, "use_map_specular", "specular_factor", "Intensity")
1081 factor_but(col, "use_map_color_spec", "specular_color_factor", "Color")
1082 factor_but(col, "use_map_hardness", "hardness_factor", "Hardness")
1084 col = split.column()
1085 col.label(text="Shading:")
1086 factor_but(col, "use_map_ambient", "ambient_factor", "Ambient")
1087 factor_but(col, "use_map_emit", "emit_factor", "Emit")
1088 factor_but(col, "use_map_mirror", "mirror_factor", "Mirror")
1089 factor_but(col, "use_map_raymir", "raymir_factor", "Ray Mirror")
1091 col.label(text="Geometry:")
1092 # XXX replace 'or' when displacement is fixed to not rely on normal influence value.
1093 sub_tmp = factor_but(col, "use_map_normal", "normal_factor", "Normal")
1094 sub_tmp.active = texslot.use_map_normal or texslot.use_map_displacement
1095 # END XXX
1097 factor_but(col, "use_map_warp", "warp_factor", "Warp")
1098 factor_but(col, "use_map_displacement", "displacement_factor", "Displace")
1100 elif idblock.pov.type == "HALO":
1101 layout.label(text="Halo:")
1103 split = layout.split()
1105 col = split.column()
1106 factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
1107 factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
1109 col = split.column()
1110 factor_but(col, "use_map_raymir", "raymir_factor", "Size")
1111 factor_but(col, "use_map_hardness", "hardness_factor", "Hardness")
1112 factor_but(col, "use_map_translucency", "translucency_factor", "Add")
1113 elif idblock.pov.type == "VOLUME":
1114 layout.label(text="Volume:")
1116 split = layout.split()
1118 col = split.column()
1119 factor_but(col, "use_map_density", "density_factor", "Density")
1120 factor_but(col, "use_map_emission", "emission_factor", "Emission")
1121 factor_but(col, "use_map_scatter", "scattering_factor", "Scattering")
1122 factor_but(col, "use_map_reflect", "reflection_factor", "Reflection")
1124 col = split.column()
1125 col.label(text=" ")
1126 factor_but(col, "use_map_color_emission", "emission_color_factor", "Emission Color")
1127 factor_but(
1128 col,
1129 "use_map_color_transmission",
1130 "transmission_color_factor",
1131 "Transmission Color",
1133 factor_but(
1134 col, "use_map_color_reflection", "reflection_color_factor", "Reflection Color"
1137 layout.label(text="Geometry:")
1139 split = layout.split()
1141 col = split.column()
1142 factor_but(col, "use_map_warp", "warp_factor", "Warp")
1144 col = split.column()
1145 factor_but(col, "use_map_displacement", "displacement_factor", "Displace")
1147 elif isinstance(idblock, Light):
1148 split = layout.split()
1150 col = split.column()
1151 factor_but(col, "use_map_color", "color_factor", "Color")
1153 col = split.column()
1154 factor_but(col, "use_map_shadow", "shadow_factor", "Shadow")
1156 elif isinstance(idblock, World):
1157 split = layout.split()
1159 col = split.column()
1160 factor_but(col, "use_map_blend", "blend_factor", "Blend")
1161 factor_but(col, "use_map_horizon", "horizon_factor", "Horizon")
1163 col = split.column()
1164 factor_but(col, "use_map_zenith_up", "zenith_up_factor", "Zenith Up")
1165 factor_but(col, "use_map_zenith_down", "zenith_down_factor", "Zenith Down")
1166 elif isinstance(idblock, ParticleSettings):
1167 split = layout.split()
1169 col = split.column()
1170 col.label(text="General:")
1171 factor_but(col, "use_map_time", "time_factor", "Time")
1172 factor_but(col, "use_map_life", "life_factor", "Lifetime")
1173 factor_but(col, "use_map_density", "density_factor", "Density")
1174 factor_but(col, "use_map_size", "size_factor", "Size")
1176 col = split.column()
1177 col.label(text="Physics:")
1178 factor_but(col, "use_map_velocity", "velocity_factor", "Velocity")
1179 factor_but(col, "use_map_damp", "damp_factor", "Damp")
1180 factor_but(col, "use_map_gravity", "gravity_factor", "Gravity")
1181 factor_but(col, "use_map_field", "field_factor", "Force Fields")
1183 layout.label(text="Hair:")
1185 split = layout.split()
1187 col = split.column()
1188 factor_but(col, "use_map_length", "length_factor", "Length")
1189 factor_but(col, "use_map_clump", "clump_factor", "Clump")
1190 factor_but(col, "use_map_twist", "twist_factor", "Twist")
1192 col = split.column()
1193 factor_but(col, "use_map_kink_amp", "kink_amp_factor", "Kink Amplitude")
1194 factor_but(col, "use_map_kink_freq", "kink_freq_factor", "Kink Frequency")
1195 factor_but(col, "use_map_rough", "rough_factor", "Rough")
1197 elif isinstance(idblock, FreestyleLineStyle):
1198 split = layout.split()
1200 col = split.column()
1201 factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
1202 col = split.column()
1203 factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
1205 layout.separator()
1207 if not isinstance(idblock, ParticleSettings):
1208 split = layout.split()
1210 col = split.column()
1211 # col.prop(tex, "blend_type", text="Blend") #deprecated since 2.8
1212 # col.prop(tex, "use_rgb_to_intensity") #deprecated since 2.8
1213 # color is used on gray-scale textures even when use_rgb_to_intensity is disabled.
1214 # col.prop(tex, "color", text="") #deprecated since 2.8
1216 col = split.column()
1217 # col.prop(tex, "invert", text="Negative") #deprecated since 2.8
1218 # col.prop(tex, "use_stencil") #deprecated since 2.8
1220 # if isinstance(idblock, (Material, World)):
1221 # col.prop(tex, "default_value", text="DVar", slider=True)
1224 class TEXTURE_PT_POV_tex_gamma(TextureButtonsPanel, Panel):
1225 """Use this class to define pov texture gamma buttons."""
1227 bl_label = "Image Gamma"
1228 COMPAT_ENGINES = {"POVRAY_RENDER"}
1230 def draw_header(self, context):
1231 tex = context.texture
1233 self.layout.prop(tex.pov, "tex_gamma_enable", text="", icon="SEQ_LUMA_WAVEFORM")
1235 def draw(self, context):
1236 layout = self.layout
1238 tex = context.texture
1240 layout.active = tex.pov.tex_gamma_enable
1241 layout.prop(tex.pov, "tex_gamma_value", text="Gamma Value")
1244 # commented out below UI for texture only custom code inside exported material:
1245 # class TEXTURE_PT_povray_replacement_text(TextureButtonsPanel, Panel):
1246 # bl_label = "Custom POV Code"
1247 # COMPAT_ENGINES = {'POVRAY_RENDER'}
1249 # def draw(self, context):
1250 # layout = self.layout
1252 # tex = context.texture
1254 # col = layout.column()
1255 # col.label(text="Replace properties with:")
1256 # col.prop(tex.pov, "replacement_text", text="")
1259 classes = (
1260 WORLD_TEXTURE_SLOTS_UL_POV_layerlist,
1261 TEXTURE_MT_POV_specials,
1262 # TEXTURE_PT_context # todo: solve UI design for painting
1263 TEXTURE_PT_POV_context_texture,
1264 TEXTURE_PT_colors,
1265 TEXTURE_PT_POV_type,
1266 TEXTURE_PT_POV_preview,
1267 TEXTURE_PT_POV_parameters,
1268 TEXTURE_PT_POV_tex_gamma,
1269 MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist,
1270 TEXTURE_OT_POV_texture_slot_add,
1271 TEXTURE_OT_POV_texture_slot_remove,
1272 TEXTURE_OT_POV_context_texture_update,
1273 TEXTURE_PT_POV_influence,
1274 TEXTURE_PT_POV_mapping,
1278 def register():
1279 for cls in classes:
1280 register_class(cls)
1283 def unregister():
1284 for cls in reversed(classes):
1285 # if cls != TEXTURE_PT_context:
1286 unregister_class(cls)