Animall: move to own dir, to add translations later
[blender-addons.git] / render_povray / texturing_gui.py
blob574fa3484aff754d4899b314033091f345c7482f
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 """User interface for texturing tools."""
5 import bpy
6 from bpy.utils import register_class, unregister_class
7 from bpy.types import (
8 Operator,
9 Menu,
10 UIList,
11 Panel,
12 Brush,
13 Material,
14 Light,
15 World,
16 ParticleSettings,
17 FreestyleLineStyle,
20 # from .ui import TextureButtonsPanel
22 from .shading_properties import pov_context_tex_datablock
23 from bl_ui.properties_paint_common import brush_texture_settings
25 # Example of wrapping every class 'as is'
26 from bl_ui import properties_texture
28 # unused, replaced by pov_context_tex_datablock (no way to use?):
29 # from bl_ui.properties_texture import context_tex_datablock
30 # from bl_ui.properties_texture import texture_filter_common #unused yet?
32 for member in dir(properties_texture):
33 subclass = getattr(properties_texture, member)
34 if hasattr(subclass, "COMPAT_ENGINES"):
35 subclass.COMPAT_ENGINES.add("POVRAY_RENDER")
36 del properties_texture
39 class TextureButtonsPanel:
40 """Use this class to define buttons from the texture tab properties."""
42 bl_space_type = "PROPERTIES"
43 bl_region_type = "WINDOW"
44 bl_context = "texture"
45 COMPAT_ENGINES = {"POVRAY_RENDER"}
47 @classmethod
48 def poll(cls, context):
49 tex = context.texture
50 rd = context.scene.render
51 return tex and (rd.engine in cls.COMPAT_ENGINES)
54 class TEXTURE_MT_POV_specials(Menu):
55 """Use this class to define pov texture slot operations buttons."""
57 bl_label = "Texture Specials"
58 COMPAT_ENGINES = {"POVRAY_RENDER"}
60 def draw(self, context):
61 layout = self.layout
63 layout.operator("texture.slot_copy", icon="COPYDOWN")
64 layout.operator("texture.slot_paste", icon="PASTEDOWN")
67 class WORLD_TEXTURE_SLOTS_UL_POV_layerlist(UIList):
68 """Use this class to show pov texture slots list."""
70 index: bpy.props.IntProperty(name="index")
71 # should active_propname be index or..?
73 def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
74 # world = context.scene.world # .pov # NOT USED
75 # active_data = world.pov # NOT USED
76 # tex = context.texture #may be needed later?
78 # We could write some code to decide which icon to use here...
79 # custom_icon = 'TEXTURE'
81 # ob = data
82 slot = item
83 # ma = slot.name
84 # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
85 if self.layout_type in {"DEFAULT", "COMPACT"}:
86 # You should always start your row layout by a label (icon + text), or a non-embossed text field,
87 # this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
88 # We use icon_value of label, as our given icon is an integer value, not an enum ID.
89 # Note "data" names should never be translated!
90 if slot:
91 layout.prop(slot, "texture", text="", emboss=False, icon="TEXTURE")
92 else:
93 layout.label(text="New", translate=False, icon_value=icon)
94 # 'GRID' layout type should be as compact as possible (typically a single icon!).
95 elif self.layout_type in {"GRID"}:
96 layout.alignment = "CENTER"
97 layout.label(text="", icon_value=icon)
100 class MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist(UIList):
101 """Use this class to show pov texture slots list."""
103 # texture_slots:
104 index: bpy.props.IntProperty(name="index")
105 # foo = random prop
107 def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
108 # ob = data
109 slot = item
110 # ma = slot.name
111 # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
112 if self.layout_type in {"DEFAULT", "COMPACT"}:
113 # You should always start your row layout by a label (icon + text), or a non-embossed text field,
114 # this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
115 # We use icon_value of label, as our given icon is an integer value, not an enum ID.
116 # Note "data" names should never be translated!
117 if slot:
118 layout.prop(slot, "texture", text="", emboss=False, icon="TEXTURE")
119 else:
120 layout.label(text="New", translate=False, icon_value=icon)
121 # 'GRID' layout type should be as compact as possible (typically a single icon!).
122 elif self.layout_type in {"GRID"}:
123 layout.alignment = "CENTER"
124 layout.label(text="", icon_value=icon)
127 class TEXTURE_PT_context(TextureButtonsPanel, Panel):
128 """Rewrite of this existing class to modify it."""
130 bl_label = ""
131 bl_context = "texture"
132 bl_options = {"HIDE_HEADER"}
133 COMPAT_ENGINES = {"POVRAY_RENDER", "BLENDER_EEVEE", "BLENDER_WORKBENCH"}
134 # register but not unregistered because
135 # the modified parts concern only POVRAY_RENDER
137 @classmethod
138 def poll(cls, context):
139 return (
140 context.scene.texture_context
141 not in ("MATERIAL", "WORLD", "LIGHT", "PARTICLES", "LINESTYLE")
142 or context.scene.render.engine != "POVRAY_RENDER"
145 def draw(self, context):
146 layout = self.layout
147 tex = context.texture
148 space = context.space_data
149 pin_id = space.pin_id
150 use_pin_id = space.use_pin_id
151 user = context.texture_user
153 col = layout.column()
155 if not (use_pin_id and isinstance(pin_id, bpy.types.Texture)):
156 pin_id = None
158 if not pin_id:
159 col.template_texture_user()
161 if user or pin_id:
162 col.separator()
164 if pin_id:
165 col.template_ID(space, "pin_id")
166 else:
167 propname = context.texture_user_property.identifier
168 col.template_ID(user, propname, new="texture.new")
170 if tex:
171 col.separator()
173 split = col.split(factor=0.2)
174 split.label(text="Type")
175 split.prop(tex, "type", text="")
178 class TEXTURE_PT_POV_context_texture(TextureButtonsPanel, Panel):
179 """Use this class to show pov texture context buttons."""
181 bl_label = ""
182 bl_options = {"HIDE_HEADER"}
183 COMPAT_ENGINES = {"POVRAY_RENDER"}
185 @classmethod
186 def poll(cls, context):
187 engine = context.scene.render.engine
188 # if not (hasattr(context, "pov_texture_slot") or hasattr(context, "texture_node")):
189 # return False
190 return (
191 context.material
192 or context.scene.world
193 or context.light
194 or context.texture
195 or context.line_style
196 or context.particle_system
197 or isinstance(context.space_data.pin_id, ParticleSettings)
198 or context.texture_user
199 ) and (engine in cls.COMPAT_ENGINES)
201 def draw(self, context):
202 layout = self.layout
204 scene = context.scene
205 mat = context.view_layer.objects.active.active_material
206 wld = context.scene.world
208 layout.prop(scene, "texture_context", expand=True)
209 if scene.texture_context == "MATERIAL" and mat is not None:
211 row = layout.row()
212 row.template_list(
213 "MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist",
215 mat,
216 "pov_texture_slots",
217 mat.pov,
218 "active_texture_index",
219 rows=2,
220 maxrows=16,
221 type="DEFAULT",
223 col = row.column(align=True)
224 col.operator("pov.textureslotadd", icon="ADD", text="")
225 col.operator("pov.textureslotremove", icon="REMOVE", text="")
226 # XXX todo: recreate for pov_texture_slots?
227 # col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
228 # col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
229 col.separator()
231 if mat.pov_texture_slots:
232 index = mat.pov.active_texture_index
233 slot = mat.pov_texture_slots[index]
234 try:
235 povtex = slot.texture # slot.name
236 tex = bpy.data.textures[povtex]
237 col.prop(tex, "use_fake_user", text="")
238 # layout.label(text='Linked Texture data browser:')
239 # propname = slot.texture_search
240 # if slot.texture was a pointer to texture data rather than just a name string:
241 # layout.template_ID(povtex, "texture", new="texture.new")
242 except KeyError:
243 tex = None
244 row = layout.row(align=True)
245 row.prop_search(
246 slot, "texture_search", bpy.data, "textures", text="", icon="TEXTURE"
249 row.operator("pov.textureslotupdate", icon="FILE_REFRESH", text="")
250 # try:
251 # bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[
252 # slot.texture_search
254 # bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[
255 # slot.texture_search
257 # except KeyError:
258 # # texture not hand-linked by user
259 # pass
261 if tex:
262 layout.separator()
263 split = layout.split(factor=0.2)
264 split.label(text="Type")
265 split.prop(tex, "type", text="")
267 # else:
268 # for i in range(18): # length of material texture slots
269 # mat.pov_texture_slots.add()
270 elif scene.texture_context == "WORLD" and wld is not None:
272 row = layout.row()
273 row.template_list(
274 "WORLD_TEXTURE_SLOTS_UL_POV_layerlist",
276 wld,
277 "pov_texture_slots",
278 wld.pov,
279 "active_texture_index",
280 rows=2,
281 maxrows=16,
282 type="DEFAULT",
284 col = row.column(align=True)
285 col.operator("pov.textureslotadd", icon="ADD", text="")
286 col.operator("pov.textureslotremove", icon="REMOVE", text="")
288 # todo: recreate for pov_texture_slots?
289 # col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
290 # col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
291 col.separator()
293 if wld.pov_texture_slots:
294 index = wld.pov.active_texture_index
295 slot = wld.pov_texture_slots[index]
296 povtex = slot.texture # slot.name
297 tex = bpy.data.textures[povtex]
298 col.prop(tex, "use_fake_user", text="")
299 # layout.label(text='Linked Texture data browser:')
300 # propname = slot.texture_search # NOT USED
301 # if slot.texture was a pointer to texture data rather than just a name string:
302 # layout.template_ID(povtex, "texture", new="texture.new")
304 layout.prop_search(
305 slot, "texture_search", bpy.data, "textures", text="", icon="TEXTURE"
307 try:
308 bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[
309 slot.texture_search
311 bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[
312 slot.texture_search
314 except KeyError:
315 # texture not hand-linked by user
316 pass
318 if tex:
319 layout.separator()
320 split = layout.split(factor=0.2)
321 split.label(text="Type")
322 split.prop(tex, "type", text="")
325 class TEXTURE_OT_POV_context_texture_update(Operator):
326 """Use this class for the texture slot update button."""
328 bl_idname = "pov.textureslotupdate"
329 bl_label = "Update"
330 bl_description = "Update texture_slot"
331 bl_options = {"REGISTER", "UNDO"}
332 COMPAT_ENGINES = {"POVRAY_RENDER"}
334 @classmethod
335 def poll(cls, context):
336 engine = context.scene.render.engine
337 mate = context.view_layer.objects.active.active_material
338 return mate and engine in cls.COMPAT_ENGINES
340 def execute(self, context):
341 # tex.use_fake_user = True
342 mat = context.view_layer.objects.active.active_material
343 index = mat.pov.active_texture_index
344 slot = mat.pov_texture_slots[index]
345 povtex = slot.texture # slot.name
346 tex = bpy.data.textures[povtex]
348 # Switch paint brush and paint brush mask
349 # to this texture so settings remain contextual
350 bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[slot.texture_search]
351 bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[
352 slot.texture_search
355 return {"FINISHED"}
358 # Commented out below is a reminder of what existed in Blender Internal
359 # attributes need to be recreated
361 slot = getattr(context, "texture_slot", None)
362 node = getattr(context, "texture_node", None)
363 space = context.space_data
365 #attempt at replacing removed space_data
366 mtl = getattr(context, "material", None)
367 if mtl != None:
368 spacedependant = mtl
369 wld = getattr(context, "world", None)
370 if wld != None:
371 spacedependant = wld
372 lgt = getattr(context, "light", None)
373 if lgt != None:
374 spacedependant = lgt
377 #idblock = context.particle_system.settings
379 tex = getattr(context, "texture", None)
380 if tex != None:
381 spacedependant = tex
385 scene = context.scene
386 idblock = scene.pov#pov_context_tex_datablock(context)
387 pin_id = space.pin_id
389 #spacedependant.use_limited_texture_context = True
391 if space.use_pin_id and not isinstance(pin_id, Texture):
392 idblock = id_tex_datablock(pin_id)
393 pin_id = None
395 if not space.use_pin_id:
396 layout.row().prop(spacedependant, "texture_context", expand=True)
397 pin_id = None
399 if spacedependant.texture_context == 'OTHER':
400 if not pin_id:
401 layout.template_texture_user()
402 user = context.texture_user
403 if user or pin_id:
404 layout.separator()
406 row = layout.row()
408 if pin_id:
409 row.template_ID(space, "pin_id")
410 else:
411 propname = context.texture_user_property.identifier
412 row.template_ID(user, propname, new="texture.new")
414 if tex:
415 split = layout.split(factor=0.2)
416 if tex.use_nodes:
417 if slot:
418 split.label(text="Output:")
419 split.prop(slot, "output_node", text="")
420 else:
421 split.label(text="Type:")
422 split.prop(tex, "type", text="")
423 return
425 tex_collection = (pin_id is None) and (node is None) and (spacedependant.texture_context not in ('LINESTYLE','OTHER'))
427 if tex_collection:
429 pov = getattr(context, "pov", None)
430 active_texture_index = getattr(spacedependant, "active_texture_index", None)
431 print (pov)
432 print(idblock)
433 print(active_texture_index)
434 row = layout.row()
436 row.template_list("TEXTURE_UL_texslots", "", idblock, "texture_slots",
437 idblock, "active_texture_index", rows=2, maxrows=16, type="DEFAULT")
439 # row.template_list("WORLD_TEXTURE_SLOTS_UL_List", "texture_slots", world,
440 # world.texture_slots, world, "active_texture_index", rows=2)
442 col = row.column(align=True)
443 col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
444 col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
445 col.menu("TEXTURE_MT_POV_specials", icon='DOWNARROW_HLT', text="")
447 if tex_collection:
448 layout.template_ID(idblock, "active_texture", new="texture.new")
449 elif node:
450 layout.template_ID(node, "texture", new="texture.new")
451 elif idblock:
452 layout.template_ID(idblock, "texture", new="texture.new")
454 if pin_id:
455 layout.template_ID(space, "pin_id")
457 if tex:
458 split = layout.split(factor=0.2)
459 if tex.use_nodes:
460 if slot:
461 split.label(text="Output:")
462 split.prop(slot, "output_node", text="")
463 else:
464 split.label(text="Type:")
468 class TEXTURE_PT_colors(TextureButtonsPanel, Panel):
469 """Use this class to show pov color ramps."""
471 bl_label = "Colors"
472 bl_options = {"DEFAULT_CLOSED"}
473 COMPAT_ENGINES = {"POVRAY_RENDER"}
475 def draw(self, context):
476 layout = self.layout
478 tex = context.texture
480 layout.prop(tex, "use_color_ramp", text="Ramp")
481 if tex.use_color_ramp:
482 layout.template_color_ramp(tex, "color_ramp", expand=True)
484 split = layout.split()
486 col = split.column()
487 col.label(text="RGB Multiply:")
488 sub = col.column(align=True)
489 sub.prop(tex, "factor_red", text="R")
490 sub.prop(tex, "factor_green", text="G")
491 sub.prop(tex, "factor_blue", text="B")
493 col = split.column()
494 col.label(text="Adjust:")
495 col.prop(tex, "intensity")
496 col.prop(tex, "contrast")
497 col.prop(tex, "saturation")
499 col = layout.column()
500 col.prop(tex, "use_clamp", text="Clamp")
503 # Texture Slot Panels #
506 class TEXTURE_OT_POV_texture_slot_add(Operator):
507 """Use this class for the add texture slot button."""
509 bl_idname = "pov.textureslotadd"
510 bl_label = "Add"
511 bl_description = "Add texture_slot"
512 bl_options = {"REGISTER", "UNDO"}
513 COMPAT_ENGINES = {"POVRAY_RENDER"}
515 def execute(self, context):
516 idblock = pov_context_tex_datablock(context)
517 slot_brush = bpy.data.brushes.new("POVtextureSlot")
518 context.tool_settings.image_paint.brush = slot_brush
519 tex = bpy.data.textures.new(name="Texture", type="IMAGE")
520 # tex.use_fake_user = True
521 # mat = context.view_layer.objects.active.active_material
522 slot = idblock.pov_texture_slots.add()
523 slot.name = tex.name
524 slot.texture = tex.name
525 slot.texture_search = tex.name
526 # Switch paint brush and paint brush mask
527 # to this texture so settings remain contextual
528 bpy.context.tool_settings.image_paint.brush.texture = tex
529 bpy.context.tool_settings.image_paint.brush.mask_texture = tex
530 idblock.pov.active_texture_index = len(idblock.pov_texture_slots) - 1
532 # for area in bpy.context.screen.areas:
533 # if area.type in ['PROPERTIES']:
534 # area.tag_redraw()
536 return {"FINISHED"}
539 class TEXTURE_OT_POV_texture_slot_remove(Operator):
540 """Use this class for the remove texture slot button."""
542 bl_idname = "pov.textureslotremove"
543 bl_label = "Remove"
544 bl_description = "Remove texture_slot"
545 bl_options = {"REGISTER", "UNDO"}
546 COMPAT_ENGINES = {"POVRAY_RENDER"}
548 def execute(self, context):
549 idblock = pov_context_tex_datablock(context)
550 # mat = context.view_layer.objects.active.active_material
551 # tex_slot = idblock.pov_texture_slots.remove(idblock.pov.active_texture_index) # not used
552 # tex_to_delete = context.tool_settings.image_paint.brush.texture
553 # bpy.data.textures.remove(tex_to_delete, do_unlink=True, do_id_user=True, do_ui_user=True)
554 idblock.pov_texture_slots.remove(idblock.pov.active_texture_index)
555 if idblock.pov.active_texture_index > 0:
556 idblock.pov.active_texture_index -= 1
557 # try:
558 # tex = idblock.pov_texture_slots[idblock.pov.active_texture_index].texture
559 # except IndexError:
560 # No more slots
561 return {"FINISHED"}
562 # Switch paint brush to previous texture so settings remain contextual
563 # if 'tex' in locals(): # Would test is the tex variable is assigned / exists
564 # bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[tex]
565 # bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[tex]
567 return {"FINISHED"}
570 class TextureSlotPanel(TextureButtonsPanel):
571 """Use this class to show pov texture slots panel."""
573 COMPAT_ENGINES = {"POVRAY_RENDER"}
575 @classmethod
576 def poll(cls, context):
577 if not hasattr(context, "pov_texture_slot"):
578 return False
580 engine = context.scene.render.engine
581 # return TextureButtonsPanel.poll(cls, context) and (engine in cls.COMPAT_ENGINES)
582 return TextureButtonsPanel.poll(context) and (engine in cls.COMPAT_ENGINES)
585 class TEXTURE_PT_POV_type(TextureButtonsPanel, Panel):
586 """Use this class to define pov texture type buttons."""
588 bl_label = "POV Textures"
589 COMPAT_ENGINES = {"POVRAY_RENDER"}
590 bl_options = {"HIDE_HEADER"}
592 def draw(self, context):
593 layout = self.layout
594 # world = context.world # unused
595 tex = context.texture
597 split = layout.split(factor=0.2)
598 split.label(text="Pattern")
599 split.prop(tex.pov, "tex_pattern_type", text="")
601 # row = layout.row()
602 # row.template_list("WORLD_TEXTURE_SLOTS_UL_List", "texture_slots", world,
603 # world.texture_slots, world, "active_texture_index")
606 class TEXTURE_PT_POV_preview(TextureButtonsPanel, Panel):
607 """Use this class to define pov texture preview panel."""
609 bl_label = "Preview"
610 COMPAT_ENGINES = {"POVRAY_RENDER"}
611 bl_options = {"HIDE_HEADER"}
613 @classmethod
614 def poll(cls, context):
615 engine = context.scene.render.engine
616 if not hasattr(context, "pov_texture_slot"):
617 return False
618 tex = context.texture
619 # mat = bpy.context.active_object.active_material #unused
620 return tex and (tex.pov.tex_pattern_type != "emulator") and (engine in cls.COMPAT_ENGINES)
622 def draw(self, context):
623 tex = context.texture
624 slot = getattr(context, "pov_texture_slot", None)
625 # idblock = pov_context_tex_datablock(context) # unused
626 layout = self.layout
627 # if idblock:
628 # layout.template_preview(tex, parent=idblock, slot=slot)
629 if tex.pov.tex_pattern_type != "emulator":
630 layout.operator("tex.preview_update")
631 else:
632 layout.template_preview(tex, slot=slot)
635 class TEXTURE_PT_POV_parameters(TextureButtonsPanel, Panel):
636 """Use this class to define pov texture pattern buttons."""
638 bl_label = "POV Pattern Options"
639 bl_options = {"HIDE_HEADER"}
640 COMPAT_ENGINES = {"POVRAY_RENDER"}
642 def draw(self, context):
643 # mat = bpy.context.active_object.active_material # Unused
644 tex = context.texture
645 if tex is not None and tex.pov.tex_pattern_type != "emulator":
646 layout = self.layout
647 if tex.pov.tex_pattern_type == "agate":
648 layout.prop(tex.pov, "modifier_turbulence", text="Agate Turbulence")
649 if tex.pov.tex_pattern_type in {"spiral1", "spiral2"}:
650 layout.prop(tex.pov, "modifier_numbers", text="Number of arms")
651 if tex.pov.tex_pattern_type == "tiling":
652 layout.prop(tex.pov, "modifier_numbers", text="Pattern number")
653 if tex.pov.tex_pattern_type == "magnet":
654 layout.prop(tex.pov, "magnet_style", text="Magnet style")
655 align = True
656 if tex.pov.tex_pattern_type == "quilted":
657 row = layout.row(align=align)
658 row.prop(tex.pov, "modifier_control0", text="Control0")
659 row.prop(tex.pov, "modifier_control1", text="Control1")
660 if tex.pov.tex_pattern_type == "brick":
661 col = layout.column(align=align)
662 row = col.row()
663 row.prop(tex.pov, "brick_size_x", text="Brick size X")
664 row.prop(tex.pov, "brick_size_y", text="Brick size Y")
665 row = col.row()
666 row.prop(tex.pov, "brick_size_z", text="Brick size Z")
667 row.prop(tex.pov, "brick_mortar", text="Brick mortar")
668 if tex.pov.tex_pattern_type in {"julia", "mandel", "magnet"}:
669 col = layout.column(align=align)
670 if tex.pov.tex_pattern_type == "julia":
671 row = col.row()
672 row.prop(tex.pov, "julia_complex_1", text="Complex 1")
673 row.prop(tex.pov, "julia_complex_2", text="Complex 2")
674 if tex.pov.tex_pattern_type == "magnet" and tex.pov.magnet_style == "julia":
675 row = col.row()
676 row.prop(tex.pov, "julia_complex_1", text="Complex 1")
677 row.prop(tex.pov, "julia_complex_2", text="Complex 2")
678 row = col.row()
679 if tex.pov.tex_pattern_type in {"julia", "mandel"}:
680 row.prop(tex.pov, "f_exponent", text="Exponent")
681 if tex.pov.tex_pattern_type == "magnet":
682 row.prop(tex.pov, "magnet_type", text="Type")
683 row.prop(tex.pov, "f_iter", text="Iterations")
684 row = col.row()
685 row.prop(tex.pov, "f_ior", text="Interior")
686 row.prop(tex.pov, "f_ior_fac", text="Factor I")
687 row = col.row()
688 row.prop(tex.pov, "f_eor", text="Exterior")
689 row.prop(tex.pov, "f_eor_fac", text="Factor E")
690 if tex.pov.tex_pattern_type == "gradient":
691 layout.label(text="Gradient orientation:")
692 column_flow = layout.column_flow(columns=3, align=True)
693 column_flow.prop(tex.pov, "grad_orient_x", text="X")
694 column_flow.prop(tex.pov, "grad_orient_y", text="Y")
695 column_flow.prop(tex.pov, "grad_orient_z", text="Z")
696 if tex.pov.tex_pattern_type == "pavement":
697 layout.prop(tex.pov, "pave_sides", text="Pavement:number of sides")
698 col = layout.column(align=align)
699 column_flow = col.column_flow(columns=3, align=True)
700 column_flow.prop(tex.pov, "pave_tiles", text="Tiles")
701 if tex.pov.pave_sides == "4" and tex.pov.pave_tiles == 6:
702 column_flow.prop(tex.pov, "pave_pat_35", text="Pattern")
703 if tex.pov.pave_sides == "6" and tex.pov.pave_tiles == 5:
704 column_flow.prop(tex.pov, "pave_pat_22", text="Pattern")
705 if tex.pov.pave_sides == "4" and tex.pov.pave_tiles == 5:
706 column_flow.prop(tex.pov, "pave_pat_12", text="Pattern")
707 if tex.pov.pave_sides == "3" and tex.pov.pave_tiles == 6:
708 column_flow.prop(tex.pov, "pave_pat_12", text="Pattern")
709 if tex.pov.pave_sides == "6" and tex.pov.pave_tiles == 4:
710 column_flow.prop(tex.pov, "pave_pat_7", text="Pattern")
711 if tex.pov.pave_sides == "4" and tex.pov.pave_tiles == 4:
712 column_flow.prop(tex.pov, "pave_pat_5", text="Pattern")
713 if tex.pov.pave_sides == "3" and tex.pov.pave_tiles == 5:
714 column_flow.prop(tex.pov, "pave_pat_4", text="Pattern")
715 if tex.pov.pave_sides == "6" and tex.pov.pave_tiles == 3:
716 column_flow.prop(tex.pov, "pave_pat_3", text="Pattern")
717 if tex.pov.pave_sides == "3" and tex.pov.pave_tiles == 4:
718 column_flow.prop(tex.pov, "pave_pat_3", text="Pattern")
719 if tex.pov.pave_sides == "4" and tex.pov.pave_tiles == 3:
720 column_flow.prop(tex.pov, "pave_pat_2", text="Pattern")
721 if tex.pov.pave_sides == "6" and tex.pov.pave_tiles == 6:
722 column_flow.label(text="!!! 5 tiles!")
723 column_flow.prop(tex.pov, "pave_form", text="Form")
724 if tex.pov.tex_pattern_type == "function":
725 layout.prop(tex.pov, "func_list", text="Functions")
726 if tex.pov.tex_pattern_type == "function" and tex.pov.func_list != "NONE":
727 func = None
728 if tex.pov.func_list in {"f_noise3d", "f_ph", "f_r", "f_th"}:
729 func = 0
730 if tex.pov.func_list in {
731 "f_comma",
732 "f_crossed_trough",
733 "f_cubic_saddle",
734 "f_cushion",
735 "f_devils_curve",
736 "f_enneper",
737 "f_glob",
738 "f_heart",
739 "f_hex_x",
740 "f_hex_y",
741 "f_hunt_surface",
742 "f_klein_bottle",
743 "f_kummer_surface_v1",
744 "f_lemniscate_of_gerono",
745 "f_mitre",
746 "f_nodal_cubic",
747 "f_noise_generator",
748 "f_odd",
749 "f_paraboloid",
750 "f_pillow",
751 "f_piriform",
752 "f_quantum",
753 "f_quartic_paraboloid",
754 "f_quartic_saddle",
755 "f_sphere",
756 "f_steiners_roman",
757 "f_torus_gumdrop",
758 "f_umbrella",
760 func = 1
761 if tex.pov.func_list in {
762 "f_bicorn",
763 "f_bifolia",
764 "f_boy_surface",
765 "f_superellipsoid",
766 "f_torus",
768 func = 2
769 if tex.pov.func_list in {
770 "f_ellipsoid",
771 "f_folium_surface",
772 "f_hyperbolic_torus",
773 "f_kampyle_of_eudoxus",
774 "f_parabolic_torus",
775 "f_quartic_cylinder",
776 "f_torus2",
778 func = 3
779 if tex.pov.func_list in {
780 "f_blob2",
781 "f_cross_ellipsoids",
782 "f_flange_cover",
783 "f_isect_ellipsoids",
784 "f_kummer_surface_v2",
785 "f_ovals_of_cassini",
786 "f_rounded_box",
787 "f_spikes_2d",
788 "f_strophoid",
790 func = 4
791 if tex.pov.func_list in {
792 "f_algbr_cyl1",
793 "f_algbr_cyl2",
794 "f_algbr_cyl3",
795 "f_algbr_cyl4",
796 "f_blob",
797 "f_mesh1",
798 "f_poly4",
799 "f_spikes",
801 func = 5
802 if tex.pov.func_list in {
803 "f_devils_curve_2d",
804 "f_dupin_cyclid",
805 "f_folium_surface_2d",
806 "f_hetero_mf",
807 "f_kampyle_of_eudoxus_2d",
808 "f_lemniscate_of_gerono_2d",
809 "f_polytubes",
810 "f_ridge",
811 "f_ridged_mf",
812 "f_spiral",
813 "f_witch_of_agnesi",
815 func = 6
816 if tex.pov.func_list in {"f_helix1", "f_helix2", "f_piriform_2d", "f_strophoid_2d"}:
817 func = 7
818 if tex.pov.func_list == "f_helical_torus":
819 func = 8
820 column_flow = layout.column_flow(columns=3, align=True)
821 column_flow.label(text="X")
822 column_flow.prop(tex.pov, "func_plus_x", text="")
823 column_flow.prop(tex.pov, "func_x", text="Value")
824 column_flow = layout.column_flow(columns=3, align=True)
825 column_flow.label(text="Y")
826 column_flow.prop(tex.pov, "func_plus_y", text="")
827 column_flow.prop(tex.pov, "func_y", text="Value")
828 column_flow = layout.column_flow(columns=3, align=True)
829 column_flow.label(text="Z")
830 column_flow.prop(tex.pov, "func_plus_z", text="")
831 column_flow.prop(tex.pov, "func_z", text="Value")
832 row = layout.row(align=align)
833 if func > 0:
834 row.prop(tex.pov, "func_P0", text="P0")
835 if func > 1:
836 row.prop(tex.pov, "func_P1", text="P1")
837 row = layout.row(align=align)
838 if func > 2:
839 row.prop(tex.pov, "func_P2", text="P2")
840 if func > 3:
841 row.prop(tex.pov, "func_P3", text="P3")
842 row = layout.row(align=align)
843 if func > 4:
844 row.prop(tex.pov, "func_P4", text="P4")
845 if func > 5:
846 row.prop(tex.pov, "func_P5", text="P5")
847 row = layout.row(align=align)
848 if func > 6:
849 row.prop(tex.pov, "func_P6", text="P6")
850 if func > 7:
851 row.prop(tex.pov, "func_P7", text="P7")
852 row = layout.row(align=align)
853 row.prop(tex.pov, "func_P8", text="P8")
854 row.prop(tex.pov, "func_P9", text="P9")
855 # ------------------------- End Patterns ------------------------- #
857 layout.prop(tex.pov, "warp_types", text="Warp types") # warp
858 if tex.pov.warp_types == "TOROIDAL":
859 layout.prop(tex.pov, "warp_tor_major_radius", text="Major radius")
860 if tex.pov.warp_types not in {"CUBIC", "NONE"}:
861 layout.prop(tex.pov, "warp_orientation", text="Warp orientation")
862 col = layout.column(align=align)
863 row = col.row()
864 row.prop(tex.pov, "warp_dist_exp", text="Distance exponent")
865 row = col.row()
866 row.prop(tex.pov, "modifier_frequency", text="Frequency")
867 row.prop(tex.pov, "modifier_phase", text="Phase")
869 row = layout.row()
871 row.label(text="Offset:")
872 row.label(text="Scale:")
873 row.label(text="Rotate:")
874 col = layout.column(align=align)
875 row = col.row()
876 row.prop(tex.pov, "tex_mov_x", text="X")
877 row.prop(tex.pov, "tex_scale_x", text="X")
878 row.prop(tex.pov, "tex_rot_x", text="X")
879 row = col.row()
880 row.prop(tex.pov, "tex_mov_y", text="Y")
881 row.prop(tex.pov, "tex_scale_y", text="Y")
882 row.prop(tex.pov, "tex_rot_y", text="Y")
883 row = col.row()
884 row.prop(tex.pov, "tex_mov_z", text="Z")
885 row.prop(tex.pov, "tex_scale_z", text="Z")
886 row.prop(tex.pov, "tex_rot_z", text="Z")
887 row = layout.row()
889 row.label(text="Turbulence:")
890 col = layout.column(align=align)
891 row = col.row()
892 row.prop(tex.pov, "warp_turbulence_x", text="X")
893 row.prop(tex.pov, "modifier_octaves", text="Octaves")
894 row = col.row()
895 row.prop(tex.pov, "warp_turbulence_y", text="Y")
896 row.prop(tex.pov, "modifier_lambda", text="Lambda")
897 row = col.row()
898 row.prop(tex.pov, "warp_turbulence_z", text="Z")
899 row.prop(tex.pov, "modifier_omega", text="Omega")
902 class TEXTURE_PT_POV_mapping(TextureSlotPanel, Panel):
903 """Use this class to define POV texture mapping buttons."""
905 bl_label = "Mapping"
906 COMPAT_ENGINES = {"POVRAY_RENDER"}
907 bl_space_type = "PROPERTIES"
908 bl_region_type = "WINDOW"
910 @classmethod
911 def poll(cls, context):
912 idblock = pov_context_tex_datablock(context)
913 if isinstance(idblock, Brush) and not context.sculpt_object:
914 return False
916 if not getattr(context, "texture_slot", None):
917 return False
919 engine = context.scene.render.engine
920 return engine in cls.COMPAT_ENGINES
922 def draw(self, context):
923 layout = self.layout
925 idblock = pov_context_tex_datablock(context)
926 mat = bpy.context.active_object.active_material
927 # tex = context.texture_slot
928 tex = mat.pov_texture_slots[mat.active_texture_index]
929 if not isinstance(idblock, Brush):
930 split = layout.split(percentage=0.3)
931 col = split.column()
932 col.label(text="Coordinates:")
933 col = split.column()
934 col.prop(tex, "texture_coords", text="")
936 if tex.texture_coords == "ORCO":
938 ob = context.object
939 if ob and ob.type == 'MESH':
940 split = layout.split(percentage=0.3)
941 split.label(text="Mesh:")
942 split.prop(ob.data, "texco_mesh", text="")
944 elif tex.texture_coords == "UV":
945 split = layout.split(percentage=0.3)
946 split.label(text="Map:")
947 ob = context.object
948 if ob and ob.type == "MESH":
949 split.prop_search(tex, "uv_layer", ob.data, "uv_textures", text="")
950 else:
951 split.prop(tex, "uv_layer", text="")
953 elif tex.texture_coords == "OBJECT":
954 split = layout.split(percentage=0.3)
955 split.label(text="Object:")
956 split.prop(tex, "object", text="")
958 elif tex.texture_coords == "ALONG_STROKE":
959 split = layout.split(percentage=0.3)
960 split.label(text="Use Tips:")
961 split.prop(tex, "use_tips", text="")
963 if isinstance(idblock, Brush):
964 if context.sculpt_object or context.image_paint_object:
965 brush_texture_settings(layout, idblock, context.sculpt_object)
966 else:
967 if isinstance(idblock, FreestyleLineStyle):
968 split = layout.split(percentage=0.3)
969 split.label(text="Projection:")
970 split.prop(tex, "mapping", text="")
972 split = layout.split(percentage=0.3)
973 split.separator()
974 row = split.row()
975 row.prop(tex, "mapping_x", text="")
976 row.prop(tex, "mapping_y", text="")
977 row.prop(tex, "mapping_z", text="")
979 elif isinstance(idblock, Material):
980 split = layout.split(percentage=0.3)
981 split.label(text="Projection:")
982 split.prop(tex, "mapping", text="")
984 split = layout.split()
986 col = split.column()
987 if tex.texture_coords in {"ORCO", "UV"}:
988 col.prop(tex, "use_from_dupli")
989 if idblock.type == "VOLUME" and tex.texture_coords == "ORCO":
990 col.prop(tex, "use_map_to_bounds")
991 elif tex.texture_coords == "OBJECT":
992 col.prop(tex, "use_from_original")
993 if idblock.type == "VOLUME":
994 col.prop(tex, "use_map_to_bounds")
995 else:
996 col.label()
998 col = split.column()
999 row = col.row()
1000 row.prop(tex, "mapping_x", text="")
1001 row.prop(tex, "mapping_y", text="")
1002 row.prop(tex, "mapping_z", text="")
1004 row = layout.row()
1005 row.column().prop(tex, "offset")
1006 row.column().prop(tex, "scale")
1009 class TEXTURE_PT_POV_influence(TextureSlotPanel, Panel):
1010 """Use this class to define pov texture influence buttons."""
1012 bl_label = "Influence"
1013 COMPAT_ENGINES = {"POVRAY_RENDER"}
1014 bl_space_type = "PROPERTIES"
1015 bl_region_type = "WINDOW"
1016 # bl_context = 'texture'
1018 @classmethod
1019 def poll(cls, context):
1020 idblock = pov_context_tex_datablock(context)
1021 if (
1022 # isinstance(idblock, Brush) and # Brush used for everything since 2.8
1023 context.scene.texture_context
1024 == "OTHER"
1025 ): # XXX replace by isinstance(idblock, bpy.types.Brush) and ...
1026 return False
1028 # Specify below also for pov_world_texture_slots, lights etc.
1029 # to display for various types of slots but only when any
1030 if not getattr(idblock, "pov_texture_slots", None):
1031 return False
1033 engine = context.scene.render.engine
1034 return engine in cls.COMPAT_ENGINES
1036 def draw(self, context):
1038 layout = self.layout
1040 idblock = pov_context_tex_datablock(context)
1041 # tex = context.pov_texture_slot
1042 # mat = bpy.context.active_object.active_material
1043 texslot = idblock.pov_texture_slots[
1044 idblock.pov.active_texture_index
1045 ] # bpy.data.textures[mat.active_texture_index]
1046 # below tex unused yet ...maybe for particles?
1047 try:
1048 tex = bpy.data.textures[
1049 idblock.pov_texture_slots[idblock.pov.active_texture_index].texture
1050 ] # NOT USED
1051 except KeyError:
1052 tex = None # NOT USED
1054 def factor_but(layout, toggle, factor, name):
1055 row = layout.row(align=True)
1056 row.prop(texslot, toggle, text="")
1057 sub = row.row(align=True)
1058 sub.active = getattr(texslot, toggle)
1059 sub.prop(texslot, factor, text=name, slider=True)
1060 return sub # XXX, temp. use_map_normal needs to override.
1062 if isinstance(idblock, Material):
1063 split = layout.split()
1065 col = split.column()
1066 if idblock.pov.type in {"SURFACE", "WIRE"}:
1068 split = layout.split()
1070 col = split.column()
1071 col.label(text="Diffuse:")
1072 factor_but(col, "use_map_diffuse", "diffuse_factor", "Intensity")
1073 factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
1074 factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
1075 factor_but(col, "use_map_translucency", "translucency_factor", "Translucency")
1077 col.label(text="Specular:")
1078 factor_but(col, "use_map_specular", "specular_factor", "Intensity")
1079 factor_but(col, "use_map_color_spec", "specular_color_factor", "Color")
1080 factor_but(col, "use_map_hardness", "hardness_factor", "Hardness")
1082 col = split.column()
1083 col.label(text="Shading:")
1084 factor_but(col, "use_map_ambient", "ambient_factor", "Ambient")
1085 factor_but(col, "use_map_emit", "emit_factor", "Emit")
1086 factor_but(col, "use_map_mirror", "mirror_factor", "Mirror")
1087 factor_but(col, "use_map_raymir", "raymir_factor", "Ray Mirror")
1089 col.label(text="Geometry:")
1090 # XXX replace 'or' when displacement is fixed to not rely on normal influence value.
1091 sub_tmp = factor_but(col, "use_map_normal", "normal_factor", "Normal")
1092 sub_tmp.active = texslot.use_map_normal or texslot.use_map_displacement
1093 # END XXX
1095 factor_but(col, "use_map_warp", "warp_factor", "Warp")
1096 factor_but(col, "use_map_displacement", "displacement_factor", "Displace")
1098 elif idblock.pov.type == "HALO":
1099 layout.label(text="Halo:")
1101 split = layout.split()
1103 col = split.column()
1104 factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
1105 factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
1107 col = split.column()
1108 factor_but(col, "use_map_raymir", "raymir_factor", "Size")
1109 factor_but(col, "use_map_hardness", "hardness_factor", "Hardness")
1110 factor_but(col, "use_map_translucency", "translucency_factor", "Add")
1111 elif idblock.pov.type == "VOLUME":
1112 layout.label(text="Volume:")
1114 split = layout.split()
1116 col = split.column()
1117 factor_but(col, "use_map_density", "density_factor", "Density")
1118 factor_but(col, "use_map_emission", "emission_factor", "Emission")
1119 factor_but(col, "use_map_scatter", "scattering_factor", "Scattering")
1120 factor_but(col, "use_map_reflect", "reflection_factor", "Reflection")
1122 col = split.column()
1123 col.label(text=" ")
1124 factor_but(col, "use_map_color_emission", "emission_color_factor", "Emission Color")
1125 factor_but(
1126 col,
1127 "use_map_color_transmission",
1128 "transmission_color_factor",
1129 "Transmission Color",
1131 factor_but(
1132 col, "use_map_color_reflection", "reflection_color_factor", "Reflection Color"
1135 layout.label(text="Geometry:")
1137 split = layout.split()
1139 col = split.column()
1140 factor_but(col, "use_map_warp", "warp_factor", "Warp")
1142 col = split.column()
1143 factor_but(col, "use_map_displacement", "displacement_factor", "Displace")
1145 elif isinstance(idblock, Light):
1146 split = layout.split()
1148 col = split.column()
1149 factor_but(col, "use_map_color", "color_factor", "Color")
1151 col = split.column()
1152 factor_but(col, "use_map_shadow", "shadow_factor", "Shadow")
1154 elif isinstance(idblock, World):
1155 split = layout.split()
1157 col = split.column()
1158 factor_but(col, "use_map_blend", "blend_factor", "Blend")
1159 factor_but(col, "use_map_horizon", "horizon_factor", "Horizon")
1161 col = split.column()
1162 factor_but(col, "use_map_zenith_up", "zenith_up_factor", "Zenith Up")
1163 factor_but(col, "use_map_zenith_down", "zenith_down_factor", "Zenith Down")
1164 elif isinstance(idblock, ParticleSettings):
1165 split = layout.split()
1167 col = split.column()
1168 col.label(text="General:")
1169 factor_but(col, "use_map_time", "time_factor", "Time")
1170 factor_but(col, "use_map_life", "life_factor", "Lifetime")
1171 factor_but(col, "use_map_density", "density_factor", "Density")
1172 factor_but(col, "use_map_size", "size_factor", "Size")
1174 col = split.column()
1175 col.label(text="Physics:")
1176 factor_but(col, "use_map_velocity", "velocity_factor", "Velocity")
1177 factor_but(col, "use_map_damp", "damp_factor", "Damp")
1178 factor_but(col, "use_map_gravity", "gravity_factor", "Gravity")
1179 factor_but(col, "use_map_field", "field_factor", "Force Fields")
1181 layout.label(text="Hair:")
1183 split = layout.split()
1185 col = split.column()
1186 factor_but(col, "use_map_length", "length_factor", "Length")
1187 factor_but(col, "use_map_clump", "clump_factor", "Clump")
1188 factor_but(col, "use_map_twist", "twist_factor", "Twist")
1190 col = split.column()
1191 factor_but(col, "use_map_kink_amp", "kink_amp_factor", "Kink Amplitude")
1192 factor_but(col, "use_map_kink_freq", "kink_freq_factor", "Kink Frequency")
1193 factor_but(col, "use_map_rough", "rough_factor", "Rough")
1195 elif isinstance(idblock, FreestyleLineStyle):
1196 split = layout.split()
1198 col = split.column()
1199 factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
1200 col = split.column()
1201 factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
1203 layout.separator()
1205 if not isinstance(idblock, ParticleSettings):
1206 split = layout.split()
1208 col = split.column()
1209 # col.prop(tex, "blend_type", text="Blend") #deprecated since 2.8
1210 # col.prop(tex, "use_rgb_to_intensity") #deprecated since 2.8
1211 # color is used on gray-scale textures even when use_rgb_to_intensity is disabled.
1212 # col.prop(tex, "color", text="") #deprecated since 2.8
1214 col = split.column()
1215 # col.prop(tex, "invert", text="Negative") #deprecated since 2.8
1216 # col.prop(tex, "use_stencil") #deprecated since 2.8
1218 # if isinstance(idblock, (Material, World)):
1219 # col.prop(tex, "default_value", text="DVar", slider=True)
1222 class TEXTURE_PT_POV_tex_gamma(TextureButtonsPanel, Panel):
1223 """Use this class to define pov texture gamma buttons."""
1225 bl_label = "Image Gamma"
1226 COMPAT_ENGINES = {"POVRAY_RENDER"}
1228 def draw_header(self, context):
1229 tex = context.texture
1231 self.layout.prop(tex.pov, "tex_gamma_enable", text="", icon="SEQ_LUMA_WAVEFORM")
1233 def draw(self, context):
1234 layout = self.layout
1236 tex = context.texture
1238 layout.active = tex.pov.tex_gamma_enable
1239 layout.prop(tex.pov, "tex_gamma_value", text="Gamma Value")
1242 # commented out below UI for texture only custom code inside exported material:
1243 # class TEXTURE_PT_povray_replacement_text(TextureButtonsPanel, Panel):
1244 # bl_label = "Custom POV Code"
1245 # COMPAT_ENGINES = {'POVRAY_RENDER'}
1247 # def draw(self, context):
1248 # layout = self.layout
1250 # tex = context.texture
1252 # col = layout.column()
1253 # col.label(text="Replace properties with:")
1254 # col.prop(tex.pov, "replacement_text", text="")
1257 classes = (
1258 WORLD_TEXTURE_SLOTS_UL_POV_layerlist,
1259 TEXTURE_MT_POV_specials,
1260 # TEXTURE_PT_context # todo: solve UI design for painting
1261 TEXTURE_PT_POV_context_texture,
1262 TEXTURE_PT_colors,
1263 TEXTURE_PT_POV_type,
1264 TEXTURE_PT_POV_preview,
1265 TEXTURE_PT_POV_parameters,
1266 TEXTURE_PT_POV_tex_gamma,
1267 MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist,
1268 TEXTURE_OT_POV_texture_slot_add,
1269 TEXTURE_OT_POV_texture_slot_remove,
1270 TEXTURE_OT_POV_context_texture_update,
1271 TEXTURE_PT_POV_influence,
1272 TEXTURE_PT_POV_mapping,
1276 def register():
1277 for cls in classes:
1278 register_class(cls)
1281 def unregister():
1282 for cls in reversed(classes):
1283 # if cls != TEXTURE_PT_context:
1284 unregister_class(cls)