Fix add-ons with Python 3.12 by replacing "imp" with "importlib"
[blender-addons.git] / render_povray / render_gui.py
blobe99199aeb676721994fab742fdbd9cb5001d57ef
1 # SPDX-FileCopyrightText: 2021-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 """User interface for rendering parameters"""
8 import bpy
9 from sys import platform # really import here, as in render.py?
11 # Or todo: handle this more crossplatform using QTpovray for Linux for instance
12 # from os.path import isfile
13 from bl_operators.presets import AddPresetBase
14 from bpy.utils import register_class, unregister_class
15 from bpy.types import Operator, Menu, Panel
18 # Example of wrapping every class 'as is'
19 from bl_ui import properties_output
21 for member in dir(properties_output):
22 subclass = getattr(properties_output, member)
23 if hasattr(subclass, "COMPAT_ENGINES"):
24 subclass.COMPAT_ENGINES.add("POVRAY_RENDER")
25 del properties_output
27 from bl_ui import properties_freestyle
29 for member in dir(properties_freestyle):
30 subclass = getattr(properties_freestyle, member)
31 if hasattr(subclass, "COMPAT_ENGINES") and (
32 subclass.bl_space_type != "PROPERTIES" or subclass.bl_context != "render"
34 subclass.COMPAT_ENGINES.add("POVRAY_RENDER")
35 # subclass.bl_parent_id = "RENDER_PT_POV_filter"
36 del properties_freestyle
38 from bl_ui import properties_view_layer
40 for member in dir(properties_view_layer):
41 subclass = getattr(properties_view_layer, member)
42 if hasattr(subclass, "COMPAT_ENGINES"):
43 subclass.COMPAT_ENGINES.add("POVRAY_RENDER")
44 del properties_view_layer
46 # Use some of the existing buttons.
47 # from bl_ui import properties_render
49 # DEPRECATED#properties_render.RENDER_PT_render.COMPAT_ENGINES.add('POVRAY_RENDER')
50 # DEPRECATED#properties_render.RENDER_PT_format.COMPAT_ENGINES.add('POVRAY_RENDER')
51 # properties_render.RENDER_PT_antialiasing.COMPAT_ENGINES.add('POVRAY_RENDER')
52 # TORECREATE##DEPRECATED#properties_render.RENDER_PT_shading.COMPAT_ENGINES.add('POVRAY_RENDER')
53 # DEPRECATED#properties_render.RENDER_PT_output.COMPAT_ENGINES.add('POVRAY_RENDER')
54 # del properties_render
57 def check_render_freestyle_svg():
58 """Test if Freestyle SVG Exporter addon is activated
60 This addon is currently used to generate the SVG lines file
61 when Freestyle is enabled alongside POV
62 """
63 return "render_freestyle_svg" in bpy.context.preferences.addons.keys()
66 class RenderButtonsPanel:
67 """Use this class to define buttons from the render tab of
68 properties window."""
70 bl_space_type = "PROPERTIES"
71 bl_region_type = "WINDOW"
72 bl_context = "render"
73 COMPAT_ENGINES = {"POVRAY_RENDER"}
75 @classmethod
76 def poll(cls, context):
77 rd = context.scene.render
78 return rd.engine in cls.COMPAT_ENGINES
81 class RENDER_PT_POV_export_settings(RenderButtonsPanel, Panel):
82 """Use this class to define pov ini settings buttons."""
84 bl_options = {"DEFAULT_CLOSED"}
85 bl_label = "Auto Start"
86 COMPAT_ENGINES = {"POVRAY_RENDER"}
88 def draw_header(self, context):
89 scene = context.scene
90 if scene.pov.tempfiles_enable:
91 self.layout.prop(scene.pov, "tempfiles_enable", text="", icon="AUTO")
92 else:
93 self.layout.prop(scene.pov, "tempfiles_enable", text="", icon="CONSOLE")
95 def draw(self, context):
97 layout = self.layout
99 scene = context.scene
101 layout.active = scene.pov.max_trace_level != 0
102 split = layout.split()
104 col = split.column()
105 col.label(text="Command line options:")
106 col.prop(scene.pov, "command_line_switches", text="", icon="RIGHTARROW")
107 split = layout.split()
109 # layout.active = not scene.pov.tempfiles_enable
110 if not scene.pov.tempfiles_enable:
111 split.prop(scene.pov, "deletefiles_enable", text="Delete")
112 if not platform.startswith("win"):
113 split.prop(scene.pov, "sdl_window_enable", text="Show")
114 split.prop(scene.pov, "pov_editor", text="Edit")
116 col = layout.column()
117 col.prop(scene.pov, "scene_name", text="Name")
118 col.prop(scene.pov, "scene_path", text="Path to files")
119 # col.prop(scene.pov, "scene_path", text="Path to POV-file")
120 # col.prop(scene.pov, "renderimage_path", text="Path to image")
122 split = layout.split()
123 split.prop(scene.pov, "indentation_character", text="Indent")
124 if scene.pov.indentation_character == "SPACE":
125 split.prop(scene.pov, "indentation_spaces", text="Spaces")
127 row = layout.row()
128 row.prop(scene.pov, "comments_enable", text="Comments")
129 row.prop(scene.pov, "list_lf_enable", text="Line breaks in lists")
132 class RENDER_PT_POV_render_settings(RenderButtonsPanel, Panel):
133 """Use this class to host pov render settings buttons from other sub panels."""
135 bl_label = "Global Settings"
136 bl_icon = "SETTINGS"
137 bl_options = {"DEFAULT_CLOSED"}
138 COMPAT_ENGINES = {"POVRAY_RENDER"}
140 def draw_header(self, context):
141 scene = context.scene
142 if scene.pov.global_settings_advanced:
143 self.layout.prop(scene.pov, "global_settings_advanced", text="", icon="PREFERENCES")
144 else:
145 self.layout.prop(scene.pov, "global_settings_advanced", text="", icon="SETTINGS")
147 def draw(self, context):
148 layout = self.layout
150 scene = context.scene
152 layout.active = scene.pov.global_settings_advanced
155 class RENDER_PT_POV_light_paths(RenderButtonsPanel, Panel):
156 """Use this class to define pov's main light ray relative settings buttons."""
158 bl_label = "Light Paths Tracing"
159 bl_parent_id = "RENDER_PT_POV_render_settings"
160 bl_options = {"DEFAULT_CLOSED"}
161 COMPAT_ENGINES = {"POVRAY_RENDER"}
163 def draw(self, context):
164 layout = self.layout
166 scene = context.scene
167 # rd = context.scene.render
168 # layout.active = (scene.pov.max_trace_level != 0)
169 layout.active = scene.pov.global_settings_advanced
170 if scene.pov.use_shadows:
171 layout.prop(scene.pov, "use_shadows", icon="COMMUNITY")
172 else:
173 layout.prop(scene.pov, "use_shadows", icon="USER")
174 col = layout.column()
175 col.prop(scene.pov, "max_trace_level", text="Ray Depth")
176 row = layout.row(align=True)
177 row.prop(scene.pov, "adc_bailout")
180 class RENDER_PT_POV_film(RenderButtonsPanel, Panel):
181 """Use this class to define pov film settings buttons."""
183 bl_label = "Film"
184 bl_parent_id = "RENDER_PT_POV_render_settings"
185 bl_options = {"DEFAULT_CLOSED"}
186 COMPAT_ENGINES = {"POVRAY_RENDER"}
188 def draw(self, context):
189 layout = self.layout
191 povprops = context.scene.pov
192 agnosticprops = context.scene.render
194 layout.active = povprops.global_settings_advanced
195 col = layout.column()
196 col.label(text="Background")
197 row = layout.row(align=True)
198 if agnosticprops.film_transparent:
199 row.prop(
200 agnosticprops,
201 "film_transparent",
202 text="Blender alpha",
203 icon="NODE_COMPOSITING",
204 invert_checkbox=True,
206 else:
207 row.prop(
208 agnosticprops,
209 "film_transparent",
210 text="POV alpha",
211 icon="IMAGE_ALPHA",
212 invert_checkbox=True,
214 row.prop(povprops, "alpha_mode", text="")
215 if povprops.alpha_mode == "SKY":
216 row.label(text=" (color only)")
217 elif povprops.alpha_mode == "TRANSPARENT":
218 row.prop(povprops, "alpha_filter", text="(premultiplied)", slider=True)
219 else:
220 # povprops.alpha_mode == 'STRAIGHT'
221 row.label(text=" (unassociated)")
224 class RENDER_PT_POV_hues(RenderButtonsPanel, Panel):
225 """Use this class to define pov RGB tweaking buttons."""
227 bl_label = "Hues"
228 bl_parent_id = "RENDER_PT_POV_render_settings"
229 bl_options = {"DEFAULT_CLOSED"}
230 COMPAT_ENGINES = {"POVRAY_RENDER"}
232 def draw(self, context):
233 layout = self.layout
235 scene = context.scene
237 layout.active = scene.pov.global_settings_advanced
239 row = layout.row(align=True)
240 row.prop(scene.pov, "ambient_light")
241 row = layout.row(align=True)
242 row.prop(scene.pov, "irid_wavelength")
243 row = layout.row(align=True)
246 class RENDER_PT_POV_pattern_rules(RenderButtonsPanel, Panel):
247 """Use this class to change pov sets of texture generating algorithms."""
249 bl_label = "Pattern Rules"
250 bl_parent_id = "RENDER_PT_POV_render_settings"
251 bl_options = {"DEFAULT_CLOSED"}
252 COMPAT_ENGINES = {"POVRAY_RENDER"}
254 def draw(self, context):
255 layout = self.layout
257 scene = context.scene
259 layout.active = scene.pov.global_settings_advanced
261 row = layout.row(align=True)
262 row.prop(scene.pov, "number_of_waves")
263 row = layout.row(align=True)
264 row.prop(scene.pov, "noise_generator")
267 class RENDER_PT_POV_photons(RenderButtonsPanel, Panel):
268 """Use this class to define pov photons buttons."""
270 bl_label = "Photons"
271 bl_options = {"DEFAULT_CLOSED"}
272 COMPAT_ENGINES = {"POVRAY_RENDER"}
274 # def draw_header(self, context):
275 # self.layout.label(icon='SETTINGS')
277 def draw_header(self, context):
278 scene = context.scene
279 if scene.pov.photon_enable:
280 self.layout.prop(scene.pov, "photon_enable", text="", icon="PARTICLES")
281 else:
282 self.layout.prop(scene.pov, "photon_enable", text="", icon="MOD_PARTICLES")
284 def draw(self, context):
285 scene = context.scene
286 layout = self.layout
287 layout.active = scene.pov.photon_enable
288 col = layout.column()
289 # col.label(text="Global Photons:")
290 col.prop(scene.pov, "photon_max_trace_level", text="Photon Depth")
292 split = layout.split()
294 col = split.column()
295 col.prop(scene.pov, "photon_spacing", text="Spacing")
296 col.prop(scene.pov, "photon_gather_min")
298 col = split.column()
299 col.prop(scene.pov, "photon_adc_bailout", text="Photon ADC")
300 col.prop(scene.pov, "photon_gather_max")
302 box = layout.box()
303 box.label(text="Photon Map File:")
304 row = box.row()
305 row.prop(scene.pov, "photon_map_file_save_load", expand=True)
306 if scene.pov.photon_map_file_save_load in {"save"}:
307 box.prop(scene.pov, "photon_map_dir")
308 box.prop(scene.pov, "photon_map_filename")
309 if scene.pov.photon_map_file_save_load in {"load"}:
310 box.prop(scene.pov, "photon_map_file")
311 # end main photons
314 def uberpov_only_qmc_til_pov38release(layout):
315 col = layout.column()
316 col.alignment = "CENTER"
317 col.label(text="Stochastic Anti Aliasing is")
318 col.label(text="Only Available with UberPOV")
319 col.label(text="Feature Set in User Preferences.")
320 col.label(text="Using Type 2 (recursive) instead")
323 def no_qmc_fallbacks(row, scene, layout):
324 row.prop(scene.pov, "jitter_enable", text="Jitter")
326 split = layout.split()
327 col = split.column()
328 col.prop(scene.pov, "antialias_depth", text="AA Depth")
329 sub = split.column()
330 sub.prop(scene.pov, "jitter_amount", text="Jitter Amount")
331 sub.enabled = bool(scene.pov.jitter_enable)
332 row = layout.row()
333 row.prop(scene.pov, "antialias_threshold", text="AA Threshold")
334 row.prop(scene.pov, "antialias_gamma", text="AA Gamma")
337 class RENDER_PT_POV_antialias(RenderButtonsPanel, Panel):
338 """Use this class to define pov antialiasing buttons."""
340 bl_label = "Anti-Aliasing"
341 bl_options = {"DEFAULT_CLOSED"}
342 COMPAT_ENGINES = {"POVRAY_RENDER"}
344 def draw_header(self, context):
345 prefs = bpy.context.preferences.addons[__package__].preferences
346 scene = context.scene
347 if prefs.branch_feature_set_povray != "uberpov" and scene.pov.antialias_method == "2":
348 self.layout.prop(scene.pov, "antialias_enable", text="", icon="ERROR")
349 elif scene.pov.antialias_enable:
350 self.layout.prop(scene.pov, "antialias_enable", text="", icon="ANTIALIASED")
351 else:
352 self.layout.prop(scene.pov, "antialias_enable", text="", icon="ALIASED")
354 def draw(self, context):
355 prefs = bpy.context.preferences.addons[__package__].preferences
356 layout = self.layout
357 scene = context.scene
359 layout.active = scene.pov.antialias_enable
361 row = layout.row()
362 row.prop(scene.pov, "antialias_method", text="")
364 if prefs.branch_feature_set_povray != "uberpov" and scene.pov.antialias_method == "2":
365 uberpov_only_qmc_til_pov38release(layout)
366 else:
367 no_qmc_fallbacks(row, scene, layout)
368 if prefs.branch_feature_set_povray == "uberpov":
369 row = layout.row()
370 row.prop(scene.pov, "antialias_confidence", text="AA Confidence")
371 row.enabled = scene.pov.antialias_method == "2"
374 class RENDER_PT_POV_radiosity(RenderButtonsPanel, Panel):
375 """Use this class to define pov radiosity buttons."""
377 bl_label = "Diffuse Radiosity"
378 bl_options = {"DEFAULT_CLOSED"}
379 COMPAT_ENGINES = {"POVRAY_RENDER"}
381 def draw_header(self, context):
382 scene = context.scene
383 if scene.pov.radio_enable:
384 self.layout.prop(scene.pov, "radio_enable", text="", icon="OUTLINER_OB_LIGHTPROBE")
385 else:
386 self.layout.prop(scene.pov, "radio_enable", text="", icon="LIGHTPROBE_CUBEMAP")
388 def draw(self, context):
389 layout = self.layout
391 scene = context.scene
393 layout.active = scene.pov.radio_enable
395 split = layout.split()
397 col = split.column()
398 col.prop(scene.pov, "radio_count", text="Rays")
399 col.prop(scene.pov, "radio_recursion_limit", text="Recursions")
401 split.prop(scene.pov, "radio_error_bound", text="Error Bound")
403 layout.prop(scene.pov, "radio_display_advanced")
405 if scene.pov.radio_display_advanced:
406 split = layout.split()
408 col = split.column()
409 col.prop(scene.pov, "radio_adc_bailout", slider=True)
410 col.prop(scene.pov, "radio_minimum_reuse", text="Min Reuse")
411 col.prop(scene.pov, "radio_gray_threshold", slider=True)
412 col.prop(scene.pov, "radio_pretrace_start", slider=True)
413 col.prop(scene.pov, "radio_low_error_factor", slider=True)
415 col = split.column()
416 col.prop(scene.pov, "radio_brightness")
417 col.prop(scene.pov, "radio_maximum_reuse", text="Max Reuse")
418 col.prop(scene.pov, "radio_nearest_count")
419 col.prop(scene.pov, "radio_pretrace_end", slider=True)
421 col = layout.column()
422 col.label(text="Estimation Influence:")
423 col.prop(scene.pov, "radio_always_sample")
424 col.prop(scene.pov, "radio_normal")
425 col.prop(scene.pov, "radio_media")
426 col.prop(scene.pov, "radio_subsurface")
429 class RADIOSITY_MT_POV_presets(Menu):
430 """Use this class to define pov radiosity presets menu."""
432 bl_label = "Radiosity Presets"
433 preset_subdir = "pov/radiosity"
434 preset_operator = "script.execute_preset"
435 draw = bpy.types.Menu.draw_preset
438 class RENDER_OT_POV_radiosity_add_preset(AddPresetBase, Operator):
439 """Use this class to define pov radiosity add presets button"""
441 """Add a Radiosity Preset"""
442 bl_idname = "scene.radiosity_preset_add"
443 bl_label = "Add Radiosity Preset"
444 preset_menu = "RADIOSITY_MT_POV_presets"
446 # variable used for all preset values
447 preset_defines = ["scene = bpy.context.scene"]
449 # properties to store in the preset
450 preset_values = [
451 "scene.pov.radio_display_advanced",
452 "scene.pov.radio_adc_bailout",
453 "scene.pov.radio_always_sample",
454 "scene.pov.radio_brightness",
455 "scene.pov.radio_count",
456 "scene.pov.radio_error_bound",
457 "scene.pov.radio_gray_threshold",
458 "scene.pov.radio_low_error_factor",
459 "scene.pov.radio_media",
460 "scene.pov.radio_subsurface",
461 "scene.pov.radio_minimum_reuse",
462 "scene.pov.radio_maximum_reuse",
463 "scene.pov.radio_nearest_count",
464 "scene.pov.radio_normal",
465 "scene.pov.radio_recursion_limit",
466 "scene.pov.radio_pretrace_start",
467 "scene.pov.radio_pretrace_end",
470 # where to store the preset
471 preset_subdir = "pov/radiosity"
474 # Draw into an existing panel
475 def rad_panel_func(self, context):
476 """Display radiosity presets rolldown menu"""
477 layout = self.layout
479 row = layout.row(align=True)
480 row.menu(RADIOSITY_MT_POV_presets.__name__, text=RADIOSITY_MT_POV_presets.bl_label)
481 row.operator(RENDER_OT_POV_radiosity_add_preset.bl_idname, text="", icon="ADD")
482 row.operator(
483 RENDER_OT_POV_radiosity_add_preset.bl_idname, text="", icon="REMOVE"
484 ).remove_active = True
487 # ---------------------------------------------------------------- #
488 # Freestyle
489 # ---------------------------------------------------------------- #
490 # import addon_utils
491 # addon_utils.paths()[0]
492 # addon_utils.modules()
493 # mod.bl_info['name'] == 'Freestyle SVG Exporter':
494 bpy.utils.script_paths(subdir="addons")
495 # render_freestyle_svg = os.path.join(bpy.utils.script_paths(subdir="addons"), "render_freestyle_svg.py")
497 render_freestyle_svg = bpy.context.preferences.addons.get("render_freestyle_svg")
498 # mpath=addon_utils.paths()[0].render_freestyle_svg
499 # import mpath
500 # from mpath import render_freestyle_svg #= addon_utils.modules(module_cache=['Freestyle SVG Exporter'])
501 # from scripts\\addons import render_freestyle_svg
502 if check_render_freestyle_svg():
504 snippetsWIP
505 import myscript
506 import importlib
508 importlib.reload(myscript)
509 myscript.main()
511 for member in dir(render_freestyle_svg):
512 subclass = getattr(render_freestyle_svg, member)
513 if hasattr(subclass, "COMPAT_ENGINES"):
514 subclass.COMPAT_ENGINES.add("POVRAY_RENDER")
515 if subclass.bl_idname == "RENDER_PT_SVGExporterPanel":
516 subclass.bl_parent_id = "RENDER_PT_POV_filter"
517 subclass.bl_options = {"HIDE_HEADER"}
518 # subclass.bl_order = 11
519 print(subclass.bl_info)
521 # del render_freestyle_svg.RENDER_PT_SVGExporterPanel.bl_parent_id
524 class RENDER_PT_POV_filter(RenderButtonsPanel, Panel):
525 """Use this class to invoke stuff like Freestyle UI."""
527 bl_label = "Freestyle"
528 bl_options = {"DEFAULT_CLOSED"}
529 COMPAT_ENGINES = {"POVRAY_RENDER"}
531 @classmethod
532 def poll(cls, context):
533 with_freestyle = bpy.app.build_options.freestyle
534 engine = context.scene.render.engine
535 return with_freestyle and engine == "POVRAY_RENDER"
537 def draw_header(self, context):
539 # scene = context.scene
540 rd = context.scene.render
541 layout = self.layout
543 if rd.use_freestyle:
544 layout.prop(rd, "use_freestyle", text="", icon="LINE_DATA")
546 else:
547 layout.prop(rd, "use_freestyle", text="", icon="MOD_LINEART")
549 def draw(self, context):
550 rd = context.scene.render
551 layout = self.layout
552 layout.active = rd.use_freestyle
553 layout.use_property_split = True
554 layout.use_property_decorate = False # No animation.
555 flow = layout.grid_flow(
556 row_major=True, columns=0, even_columns=True, even_rows=False, align=True
559 flow.prop(rd, "line_thickness_mode", expand=True)
561 if rd.line_thickness_mode == "ABSOLUTE":
562 flow.prop(rd, "line_thickness")
564 # Warning if the Freestyle SVG Exporter addon is not enabled
565 if not check_render_freestyle_svg():
566 # col = box.column()
567 layout.label(text="Please enable Freestyle SVG Exporter addon", icon="INFO")
568 # layout.separator()
569 layout.operator(
570 "preferences.addon_show",
571 text="Go to Render: Freestyle SVG Exporter addon",
572 icon="PREFERENCES",
573 ).module = "render_freestyle_svg"
576 ##class RENDER_PT_povray_baking(RenderButtonsPanel, Panel):
577 ## bl_label = "Baking"
578 ## COMPAT_ENGINES = {'POVRAY_RENDER'}
580 ## def draw_header(self, context):
581 ## scene = context.scene
583 ## self.layout.prop(scene.pov, "baking_enable", text="")
585 ## def draw(self, context):
586 ## layout = self.layout
588 ## scene = context.scene
589 ## rd = scene.render
591 ## layout.active = scene.pov.baking_enable
594 classes = (
595 RENDER_PT_POV_export_settings,
596 RENDER_PT_POV_render_settings,
597 RENDER_PT_POV_light_paths,
598 RENDER_PT_POV_film,
599 RENDER_PT_POV_hues,
600 RENDER_PT_POV_pattern_rules,
601 RENDER_PT_POV_photons,
602 RENDER_PT_POV_antialias,
603 RENDER_PT_POV_radiosity,
604 RENDER_PT_POV_filter,
605 # RENDER_PT_povray_baking,
606 RADIOSITY_MT_POV_presets,
607 RENDER_OT_POV_radiosity_add_preset,
611 def register():
612 for cls in classes:
613 register_class(cls)
614 RENDER_PT_POV_radiosity.prepend(rad_panel_func)
617 def unregister():
618 RENDER_PT_POV_radiosity.remove(rad_panel_func)
619 for cls in reversed(classes):
620 unregister_class(cls)