Merge branch 'blender-v3.6-release'
[blender-addons.git] / render_povray / render_gui.py
blobe00e37054c06c5033d0cedb0abdbf44bf8148e0a
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 """User interface for rendering parameters"""
6 import bpy
7 from sys import platform # really import here, as in render.py?
9 # Or todo: handle this more crossplatform using QTpovray for Linux for instance
10 # from os.path import isfile
11 from bl_operators.presets import AddPresetBase
12 from bpy.utils import register_class, unregister_class
13 from bpy.types import Operator, Menu, Panel
16 # Example of wrapping every class 'as is'
17 from bl_ui import properties_output
19 for member in dir(properties_output):
20 subclass = getattr(properties_output, member)
21 if hasattr(subclass, "COMPAT_ENGINES"):
22 subclass.COMPAT_ENGINES.add("POVRAY_RENDER")
23 del properties_output
25 from bl_ui import properties_freestyle
27 for member in dir(properties_freestyle):
28 subclass = getattr(properties_freestyle, member)
29 if hasattr(subclass, "COMPAT_ENGINES") and (
30 subclass.bl_space_type != "PROPERTIES" or subclass.bl_context != "render"
32 subclass.COMPAT_ENGINES.add("POVRAY_RENDER")
33 # subclass.bl_parent_id = "RENDER_PT_POV_filter"
34 del properties_freestyle
36 from bl_ui import properties_view_layer
38 for member in dir(properties_view_layer):
39 subclass = getattr(properties_view_layer, member)
40 if hasattr(subclass, "COMPAT_ENGINES"):
41 subclass.COMPAT_ENGINES.add("POVRAY_RENDER")
42 del properties_view_layer
44 # Use some of the existing buttons.
45 # from bl_ui import properties_render
47 # DEPRECATED#properties_render.RENDER_PT_render.COMPAT_ENGINES.add('POVRAY_RENDER')
48 # DEPRECATED#properties_render.RENDER_PT_format.COMPAT_ENGINES.add('POVRAY_RENDER')
49 # properties_render.RENDER_PT_antialiasing.COMPAT_ENGINES.add('POVRAY_RENDER')
50 # TORECREATE##DEPRECATED#properties_render.RENDER_PT_shading.COMPAT_ENGINES.add('POVRAY_RENDER')
51 # DEPRECATED#properties_render.RENDER_PT_output.COMPAT_ENGINES.add('POVRAY_RENDER')
52 # del properties_render
55 def check_render_freestyle_svg():
56 """Test if Freestyle SVG Exporter addon is activated
58 This addon is currently used to generate the SVG lines file
59 when Freestyle is enabled alongside POV
60 """
61 return "render_freestyle_svg" in bpy.context.preferences.addons.keys()
64 class RenderButtonsPanel:
65 """Use this class to define buttons from the render tab of
66 properties window."""
68 bl_space_type = "PROPERTIES"
69 bl_region_type = "WINDOW"
70 bl_context = "render"
71 COMPAT_ENGINES = {"POVRAY_RENDER"}
73 @classmethod
74 def poll(cls, context):
75 rd = context.scene.render
76 return rd.engine in cls.COMPAT_ENGINES
79 class RENDER_PT_POV_export_settings(RenderButtonsPanel, Panel):
80 """Use this class to define pov ini settings buttons."""
82 bl_options = {"DEFAULT_CLOSED"}
83 bl_label = "Auto Start"
84 COMPAT_ENGINES = {"POVRAY_RENDER"}
86 def draw_header(self, context):
87 scene = context.scene
88 if scene.pov.tempfiles_enable:
89 self.layout.prop(scene.pov, "tempfiles_enable", text="", icon="AUTO")
90 else:
91 self.layout.prop(scene.pov, "tempfiles_enable", text="", icon="CONSOLE")
93 def draw(self, context):
95 layout = self.layout
97 scene = context.scene
99 layout.active = scene.pov.max_trace_level != 0
100 split = layout.split()
102 col = split.column()
103 col.label(text="Command line options:")
104 col.prop(scene.pov, "command_line_switches", text="", icon="RIGHTARROW")
105 split = layout.split()
107 # layout.active = not scene.pov.tempfiles_enable
108 if not scene.pov.tempfiles_enable:
109 split.prop(scene.pov, "deletefiles_enable", text="Delete")
110 if not platform.startswith("win"):
111 split.prop(scene.pov, "sdl_window_enable", text="Show")
112 split.prop(scene.pov, "pov_editor", text="Edit")
114 col = layout.column()
115 col.prop(scene.pov, "scene_name", text="Name")
116 col.prop(scene.pov, "scene_path", text="Path to files")
117 # col.prop(scene.pov, "scene_path", text="Path to POV-file")
118 # col.prop(scene.pov, "renderimage_path", text="Path to image")
120 split = layout.split()
121 split.prop(scene.pov, "indentation_character", text="Indent")
122 if scene.pov.indentation_character == "SPACE":
123 split.prop(scene.pov, "indentation_spaces", text="Spaces")
125 row = layout.row()
126 row.prop(scene.pov, "comments_enable", text="Comments")
127 row.prop(scene.pov, "list_lf_enable", text="Line breaks in lists")
130 class RENDER_PT_POV_render_settings(RenderButtonsPanel, Panel):
131 """Use this class to host pov render settings buttons from other sub panels."""
133 bl_label = "Global Settings"
134 bl_icon = "SETTINGS"
135 bl_options = {"DEFAULT_CLOSED"}
136 COMPAT_ENGINES = {"POVRAY_RENDER"}
138 def draw_header(self, context):
139 scene = context.scene
140 if scene.pov.global_settings_advanced:
141 self.layout.prop(scene.pov, "global_settings_advanced", text="", icon="PREFERENCES")
142 else:
143 self.layout.prop(scene.pov, "global_settings_advanced", text="", icon="SETTINGS")
145 def draw(self, context):
146 layout = self.layout
148 scene = context.scene
150 layout.active = scene.pov.global_settings_advanced
153 class RENDER_PT_POV_light_paths(RenderButtonsPanel, Panel):
154 """Use this class to define pov's main light ray relative settings buttons."""
156 bl_label = "Light Paths Tracing"
157 bl_parent_id = "RENDER_PT_POV_render_settings"
158 bl_options = {"DEFAULT_CLOSED"}
159 COMPAT_ENGINES = {"POVRAY_RENDER"}
161 def draw(self, context):
162 layout = self.layout
164 scene = context.scene
165 # rd = context.scene.render
166 # layout.active = (scene.pov.max_trace_level != 0)
167 layout.active = scene.pov.global_settings_advanced
168 if scene.pov.use_shadows:
169 layout.prop(scene.pov, "use_shadows", icon="COMMUNITY")
170 else:
171 layout.prop(scene.pov, "use_shadows", icon="USER")
172 col = layout.column()
173 col.prop(scene.pov, "max_trace_level", text="Ray Depth")
174 row = layout.row(align=True)
175 row.prop(scene.pov, "adc_bailout")
178 class RENDER_PT_POV_film(RenderButtonsPanel, Panel):
179 """Use this class to define pov film settings buttons."""
181 bl_label = "Film"
182 bl_parent_id = "RENDER_PT_POV_render_settings"
183 bl_options = {"DEFAULT_CLOSED"}
184 COMPAT_ENGINES = {"POVRAY_RENDER"}
186 def draw(self, context):
187 layout = self.layout
189 povprops = context.scene.pov
190 agnosticprops = context.scene.render
192 layout.active = povprops.global_settings_advanced
193 col = layout.column()
194 col.label(text="Background")
195 row = layout.row(align=True)
196 if agnosticprops.film_transparent:
197 row.prop(
198 agnosticprops,
199 "film_transparent",
200 text="Blender alpha",
201 icon="NODE_COMPOSITING",
202 invert_checkbox=True,
204 else:
205 row.prop(
206 agnosticprops,
207 "film_transparent",
208 text="POV alpha",
209 icon="IMAGE_ALPHA",
210 invert_checkbox=True,
212 row.prop(povprops, "alpha_mode", text="")
213 if povprops.alpha_mode == "SKY":
214 row.label(text=" (color only)")
215 elif povprops.alpha_mode == "TRANSPARENT":
216 row.prop(povprops, "alpha_filter", text="(premultiplied)", slider=True)
217 else:
218 # povprops.alpha_mode == 'STRAIGHT'
219 row.label(text=" (unassociated)")
222 class RENDER_PT_POV_hues(RenderButtonsPanel, Panel):
223 """Use this class to define pov RGB tweaking buttons."""
225 bl_label = "Hues"
226 bl_parent_id = "RENDER_PT_POV_render_settings"
227 bl_options = {"DEFAULT_CLOSED"}
228 COMPAT_ENGINES = {"POVRAY_RENDER"}
230 def draw(self, context):
231 layout = self.layout
233 scene = context.scene
235 layout.active = scene.pov.global_settings_advanced
237 row = layout.row(align=True)
238 row.prop(scene.pov, "ambient_light")
239 row = layout.row(align=True)
240 row.prop(scene.pov, "irid_wavelength")
241 row = layout.row(align=True)
244 class RENDER_PT_POV_pattern_rules(RenderButtonsPanel, Panel):
245 """Use this class to change pov sets of texture generating algorithms."""
247 bl_label = "Pattern Rules"
248 bl_parent_id = "RENDER_PT_POV_render_settings"
249 bl_options = {"DEFAULT_CLOSED"}
250 COMPAT_ENGINES = {"POVRAY_RENDER"}
252 def draw(self, context):
253 layout = self.layout
255 scene = context.scene
257 layout.active = scene.pov.global_settings_advanced
259 row = layout.row(align=True)
260 row.prop(scene.pov, "number_of_waves")
261 row = layout.row(align=True)
262 row.prop(scene.pov, "noise_generator")
265 class RENDER_PT_POV_photons(RenderButtonsPanel, Panel):
266 """Use this class to define pov photons buttons."""
268 bl_label = "Photons"
269 bl_options = {"DEFAULT_CLOSED"}
270 COMPAT_ENGINES = {"POVRAY_RENDER"}
272 # def draw_header(self, context):
273 # self.layout.label(icon='SETTINGS')
275 def draw_header(self, context):
276 scene = context.scene
277 if scene.pov.photon_enable:
278 self.layout.prop(scene.pov, "photon_enable", text="", icon="PARTICLES")
279 else:
280 self.layout.prop(scene.pov, "photon_enable", text="", icon="MOD_PARTICLES")
282 def draw(self, context):
283 scene = context.scene
284 layout = self.layout
285 layout.active = scene.pov.photon_enable
286 col = layout.column()
287 # col.label(text="Global Photons:")
288 col.prop(scene.pov, "photon_max_trace_level", text="Photon Depth")
290 split = layout.split()
292 col = split.column()
293 col.prop(scene.pov, "photon_spacing", text="Spacing")
294 col.prop(scene.pov, "photon_gather_min")
296 col = split.column()
297 col.prop(scene.pov, "photon_adc_bailout", text="Photon ADC")
298 col.prop(scene.pov, "photon_gather_max")
300 box = layout.box()
301 box.label(text="Photon Map File:")
302 row = box.row()
303 row.prop(scene.pov, "photon_map_file_save_load", expand=True)
304 if scene.pov.photon_map_file_save_load in {"save"}:
305 box.prop(scene.pov, "photon_map_dir")
306 box.prop(scene.pov, "photon_map_filename")
307 if scene.pov.photon_map_file_save_load in {"load"}:
308 box.prop(scene.pov, "photon_map_file")
309 # end main photons
312 def uberpov_only_qmc_til_pov38release(layout):
313 col = layout.column()
314 col.alignment = "CENTER"
315 col.label(text="Stochastic Anti Aliasing is")
316 col.label(text="Only Available with UberPOV")
317 col.label(text="Feature Set in User Preferences.")
318 col.label(text="Using Type 2 (recursive) instead")
321 def no_qmc_fallbacks(row, scene, layout):
322 row.prop(scene.pov, "jitter_enable", text="Jitter")
324 split = layout.split()
325 col = split.column()
326 col.prop(scene.pov, "antialias_depth", text="AA Depth")
327 sub = split.column()
328 sub.prop(scene.pov, "jitter_amount", text="Jitter Amount")
329 sub.enabled = bool(scene.pov.jitter_enable)
330 row = layout.row()
331 row.prop(scene.pov, "antialias_threshold", text="AA Threshold")
332 row.prop(scene.pov, "antialias_gamma", text="AA Gamma")
335 class RENDER_PT_POV_antialias(RenderButtonsPanel, Panel):
336 """Use this class to define pov antialiasing buttons."""
338 bl_label = "Anti-Aliasing"
339 bl_options = {"DEFAULT_CLOSED"}
340 COMPAT_ENGINES = {"POVRAY_RENDER"}
342 def draw_header(self, context):
343 prefs = bpy.context.preferences.addons[__package__].preferences
344 scene = context.scene
345 if prefs.branch_feature_set_povray != "uberpov" and scene.pov.antialias_method == "2":
346 self.layout.prop(scene.pov, "antialias_enable", text="", icon="ERROR")
347 elif scene.pov.antialias_enable:
348 self.layout.prop(scene.pov, "antialias_enable", text="", icon="ANTIALIASED")
349 else:
350 self.layout.prop(scene.pov, "antialias_enable", text="", icon="ALIASED")
352 def draw(self, context):
353 prefs = bpy.context.preferences.addons[__package__].preferences
354 layout = self.layout
355 scene = context.scene
357 layout.active = scene.pov.antialias_enable
359 row = layout.row()
360 row.prop(scene.pov, "antialias_method", text="")
362 if prefs.branch_feature_set_povray != "uberpov" and scene.pov.antialias_method == "2":
363 uberpov_only_qmc_til_pov38release(layout)
364 else:
365 no_qmc_fallbacks(row, scene, layout)
366 if prefs.branch_feature_set_povray == "uberpov":
367 row = layout.row()
368 row.prop(scene.pov, "antialias_confidence", text="AA Confidence")
369 row.enabled = scene.pov.antialias_method == "2"
372 class RENDER_PT_POV_radiosity(RenderButtonsPanel, Panel):
373 """Use this class to define pov radiosity buttons."""
375 bl_label = "Diffuse Radiosity"
376 bl_options = {"DEFAULT_CLOSED"}
377 COMPAT_ENGINES = {"POVRAY_RENDER"}
379 def draw_header(self, context):
380 scene = context.scene
381 if scene.pov.radio_enable:
382 self.layout.prop(scene.pov, "radio_enable", text="", icon="OUTLINER_OB_LIGHTPROBE")
383 else:
384 self.layout.prop(scene.pov, "radio_enable", text="", icon="LIGHTPROBE_CUBEMAP")
386 def draw(self, context):
387 layout = self.layout
389 scene = context.scene
391 layout.active = scene.pov.radio_enable
393 split = layout.split()
395 col = split.column()
396 col.prop(scene.pov, "radio_count", text="Rays")
397 col.prop(scene.pov, "radio_recursion_limit", text="Recursions")
399 split.prop(scene.pov, "radio_error_bound", text="Error Bound")
401 layout.prop(scene.pov, "radio_display_advanced")
403 if scene.pov.radio_display_advanced:
404 split = layout.split()
406 col = split.column()
407 col.prop(scene.pov, "radio_adc_bailout", slider=True)
408 col.prop(scene.pov, "radio_minimum_reuse", text="Min Reuse")
409 col.prop(scene.pov, "radio_gray_threshold", slider=True)
410 col.prop(scene.pov, "radio_pretrace_start", slider=True)
411 col.prop(scene.pov, "radio_low_error_factor", slider=True)
413 col = split.column()
414 col.prop(scene.pov, "radio_brightness")
415 col.prop(scene.pov, "radio_maximum_reuse", text="Max Reuse")
416 col.prop(scene.pov, "radio_nearest_count")
417 col.prop(scene.pov, "radio_pretrace_end", slider=True)
419 col = layout.column()
420 col.label(text="Estimation Influence:")
421 col.prop(scene.pov, "radio_always_sample")
422 col.prop(scene.pov, "radio_normal")
423 col.prop(scene.pov, "radio_media")
424 col.prop(scene.pov, "radio_subsurface")
427 class RADIOSITY_MT_POV_presets(Menu):
428 """Use this class to define pov radiosity presets menu."""
430 bl_label = "Radiosity Presets"
431 preset_subdir = "pov/radiosity"
432 preset_operator = "script.execute_preset"
433 draw = bpy.types.Menu.draw_preset
436 class RENDER_OT_POV_radiosity_add_preset(AddPresetBase, Operator):
437 """Use this class to define pov radiosity add presets button"""
439 """Add a Radiosity Preset"""
440 bl_idname = "scene.radiosity_preset_add"
441 bl_label = "Add Radiosity Preset"
442 preset_menu = "RADIOSITY_MT_POV_presets"
444 # variable used for all preset values
445 preset_defines = ["scene = bpy.context.scene"]
447 # properties to store in the preset
448 preset_values = [
449 "scene.pov.radio_display_advanced",
450 "scene.pov.radio_adc_bailout",
451 "scene.pov.radio_always_sample",
452 "scene.pov.radio_brightness",
453 "scene.pov.radio_count",
454 "scene.pov.radio_error_bound",
455 "scene.pov.radio_gray_threshold",
456 "scene.pov.radio_low_error_factor",
457 "scene.pov.radio_media",
458 "scene.pov.radio_subsurface",
459 "scene.pov.radio_minimum_reuse",
460 "scene.pov.radio_maximum_reuse",
461 "scene.pov.radio_nearest_count",
462 "scene.pov.radio_normal",
463 "scene.pov.radio_recursion_limit",
464 "scene.pov.radio_pretrace_start",
465 "scene.pov.radio_pretrace_end",
468 # where to store the preset
469 preset_subdir = "pov/radiosity"
472 # Draw into an existing panel
473 def rad_panel_func(self, context):
474 """Display radiosity presets rolldown menu"""
475 layout = self.layout
477 row = layout.row(align=True)
478 row.menu(RADIOSITY_MT_POV_presets.__name__, text=RADIOSITY_MT_POV_presets.bl_label)
479 row.operator(RENDER_OT_POV_radiosity_add_preset.bl_idname, text="", icon="ADD")
480 row.operator(
481 RENDER_OT_POV_radiosity_add_preset.bl_idname, text="", icon="REMOVE"
482 ).remove_active = True
485 # ---------------------------------------------------------------- #
486 # Freestyle
487 # ---------------------------------------------------------------- #
488 # import addon_utils
489 # addon_utils.paths()[0]
490 # addon_utils.modules()
491 # mod.bl_info['name'] == 'Freestyle SVG Exporter':
492 bpy.utils.script_paths(subdir="addons")
493 # render_freestyle_svg = os.path.join(bpy.utils.script_paths(subdir="addons"), "render_freestyle_svg.py")
495 render_freestyle_svg = bpy.context.preferences.addons.get("render_freestyle_svg")
496 # mpath=addon_utils.paths()[0].render_freestyle_svg
497 # import mpath
498 # from mpath import render_freestyle_svg #= addon_utils.modules(module_cache=['Freestyle SVG Exporter'])
499 # from scripts\\addons import render_freestyle_svg
500 if check_render_freestyle_svg():
502 snippetsWIP
503 import myscript
504 import importlib
506 importlib.reload(myscript)
507 myscript.main()
509 for member in dir(render_freestyle_svg):
510 subclass = getattr(render_freestyle_svg, member)
511 if hasattr(subclass, "COMPAT_ENGINES"):
512 subclass.COMPAT_ENGINES.add("POVRAY_RENDER")
513 if subclass.bl_idname == "RENDER_PT_SVGExporterPanel":
514 subclass.bl_parent_id = "RENDER_PT_POV_filter"
515 subclass.bl_options = {"HIDE_HEADER"}
516 # subclass.bl_order = 11
517 print(subclass.bl_info)
519 # del render_freestyle_svg.RENDER_PT_SVGExporterPanel.bl_parent_id
522 class RENDER_PT_POV_filter(RenderButtonsPanel, Panel):
523 """Use this class to invoke stuff like Freestyle UI."""
525 bl_label = "Freestyle"
526 bl_options = {"DEFAULT_CLOSED"}
527 COMPAT_ENGINES = {"POVRAY_RENDER"}
529 @classmethod
530 def poll(cls, context):
531 with_freestyle = bpy.app.build_options.freestyle
532 engine = context.scene.render.engine
533 return with_freestyle and engine == "POVRAY_RENDER"
535 def draw_header(self, context):
537 # scene = context.scene
538 rd = context.scene.render
539 layout = self.layout
541 if rd.use_freestyle:
542 layout.prop(rd, "use_freestyle", text="", icon="LINE_DATA")
544 else:
545 layout.prop(rd, "use_freestyle", text="", icon="MOD_LINEART")
547 def draw(self, context):
548 rd = context.scene.render
549 layout = self.layout
550 layout.active = rd.use_freestyle
551 layout.use_property_split = True
552 layout.use_property_decorate = False # No animation.
553 flow = layout.grid_flow(
554 row_major=True, columns=0, even_columns=True, even_rows=False, align=True
557 flow.prop(rd, "line_thickness_mode", expand=True)
559 if rd.line_thickness_mode == "ABSOLUTE":
560 flow.prop(rd, "line_thickness")
562 # Warning if the Freestyle SVG Exporter addon is not enabled
563 if not check_render_freestyle_svg():
564 # col = box.column()
565 layout.label(text="Please enable Freestyle SVG Exporter addon", icon="INFO")
566 # layout.separator()
567 layout.operator(
568 "preferences.addon_show",
569 text="Go to Render: Freestyle SVG Exporter addon",
570 icon="PREFERENCES",
571 ).module = "render_freestyle_svg"
574 ##class RENDER_PT_povray_baking(RenderButtonsPanel, Panel):
575 ## bl_label = "Baking"
576 ## COMPAT_ENGINES = {'POVRAY_RENDER'}
578 ## def draw_header(self, context):
579 ## scene = context.scene
581 ## self.layout.prop(scene.pov, "baking_enable", text="")
583 ## def draw(self, context):
584 ## layout = self.layout
586 ## scene = context.scene
587 ## rd = scene.render
589 ## layout.active = scene.pov.baking_enable
592 classes = (
593 RENDER_PT_POV_export_settings,
594 RENDER_PT_POV_render_settings,
595 RENDER_PT_POV_light_paths,
596 RENDER_PT_POV_film,
597 RENDER_PT_POV_hues,
598 RENDER_PT_POV_pattern_rules,
599 RENDER_PT_POV_photons,
600 RENDER_PT_POV_antialias,
601 RENDER_PT_POV_radiosity,
602 RENDER_PT_POV_filter,
603 # RENDER_PT_povray_baking,
604 RADIOSITY_MT_POV_presets,
605 RENDER_OT_POV_radiosity_add_preset,
609 def register():
610 for cls in classes:
611 register_class(cls)
612 RENDER_PT_POV_radiosity.prepend(rad_panel_func)
615 def unregister():
616 RENDER_PT_POV_radiosity.remove(rad_panel_func)
617 for cls in reversed(classes):
618 unregister_class(cls)