diff options
Diffstat (limited to 'render_povray/scenography_gui.py')
-rwxr-xr-x | render_povray/scenography_gui.py | 800 |
1 files changed, 800 insertions, 0 deletions
diff --git a/render_povray/scenography_gui.py b/render_povray/scenography_gui.py new file mode 100755 index 00000000..307d8f41 --- /dev/null +++ b/render_povray/scenography_gui.py @@ -0,0 +1,800 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> + +"""User interface to camera frame, optics distortions, and environment + +with world, sky, atmospheric effects such as rainbows or smoke """ + +import bpy +from bpy.utils import register_class, unregister_class +from bpy.types import Operator, Menu, Panel +from bl_operators.presets import AddPresetBase + +from bl_ui import properties_data_camera + +for member in dir(properties_data_camera): + subclass = getattr(properties_data_camera, member) + try: + subclass.COMPAT_ENGINES.add('POVRAY_RENDER') + except BaseException as e: + print(e.__doc__) + print('An exception occurred: {}'.format(e)) + pass +del properties_data_camera + +# ################################## +# # Use only a subset of the world panels +# from bl_ui import properties_world + +# # TORECREATE##DEPRECATED#properties_world.WORLD_PT_preview.COMPAT_ENGINES.add('POVRAY_RENDER') +# properties_world.WORLD_PT_context_world.COMPAT_ENGINES.add('POVRAY_RENDER') +# # TORECREATE##DEPRECATED#properties_world.WORLD_PT_world.COMPAT_ENGINES.add('POVRAY_RENDER') +# del properties_world + +################################## +# Physics Main wrapping every class 'as is' +from bl_ui import properties_physics_common + +for member in dir(properties_physics_common): + subclass = getattr(properties_physics_common, member) + try: + subclass.COMPAT_ENGINES.add('POVRAY_RENDER') + except BaseException as e: + print(e.__doc__) + print('An exception occurred: {}'.format(e)) + pass +del properties_physics_common + +# Physics Rigid Bodies wrapping every class 'as is' +from bl_ui import properties_physics_rigidbody + +for member in dir(properties_physics_rigidbody): + subclass = getattr(properties_physics_rigidbody, member) + try: + subclass.COMPAT_ENGINES.add('POVRAY_RENDER') + except BaseException as e: + print(e.__doc__) + print('An exception occurred: {}'.format(e)) + pass +del properties_physics_rigidbody + +# Physics Rigid Body Constraint wrapping every class 'as is' +from bl_ui import properties_physics_rigidbody_constraint + +for member in dir(properties_physics_rigidbody_constraint): + subclass = getattr(properties_physics_rigidbody_constraint, member) + try: + subclass.COMPAT_ENGINES.add('POVRAY_RENDER') + except BaseException as e: + print(e.__doc__) + print('An exception occurred: {}'.format(e)) + pass +del properties_physics_rigidbody_constraint + +# Physics Smoke and fluids wrapping every class 'as is' +from bl_ui import properties_physics_fluid + +for member in dir(properties_physics_fluid): + subclass = getattr(properties_physics_fluid, member) + try: + subclass.COMPAT_ENGINES.add('POVRAY_RENDER') + except BaseException as e: + print(e.__doc__) + print('An exception occurred: {}'.format(e)) + pass +del properties_physics_fluid + +# Physics softbody wrapping every class 'as is' +from bl_ui import properties_physics_softbody + +for member in dir(properties_physics_softbody): + subclass = getattr(properties_physics_softbody, member) + try: + subclass.COMPAT_ENGINES.add('POVRAY_RENDER') + except BaseException as e: + print(e.__doc__) + print('An exception occurred: {}'.format(e)) + pass +del properties_physics_softbody + +# Physics Field wrapping every class 'as is' +from bl_ui import properties_physics_field + +for member in dir(properties_physics_field): + subclass = getattr(properties_physics_field, member) + try: + subclass.COMPAT_ENGINES.add('POVRAY_RENDER') + except BaseException as e: + print(e.__doc__) + print('An exception occurred: {}'.format(e)) + pass +del properties_physics_field + +# Physics Cloth wrapping every class 'as is' +from bl_ui import properties_physics_cloth + +for member in dir(properties_physics_cloth): + subclass = getattr(properties_physics_cloth, member) + try: + subclass.COMPAT_ENGINES.add('POVRAY_RENDER') + except BaseException as e: + print(e.__doc__) + print('An exception occurred: {}'.format(e)) + pass +del properties_physics_cloth + +# Physics Dynamic Paint wrapping every class 'as is' +from bl_ui import properties_physics_dynamicpaint + +for member in dir(properties_physics_dynamicpaint): + subclass = getattr(properties_physics_dynamicpaint, member) + try: + subclass.COMPAT_ENGINES.add('POVRAY_RENDER') + except BaseException as e: + print(e.__doc__) + print('An exception occurred: {}'.format(e)) + pass +del properties_physics_dynamicpaint + +from bl_ui import properties_particle + +for member in dir(properties_particle): # add all "particle" panels from blender + subclass = getattr(properties_particle, member) + try: + subclass.COMPAT_ENGINES.add('POVRAY_RENDER') + except BaseException as e: + print(e.__doc__) + print('An exception occurred: {}'.format(e)) + pass +del properties_particle + + +class CameraDataButtonsPanel: + """Use this class to define buttons from the camera data tab of + properties window.""" + + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + COMPAT_ENGINES = {'POVRAY_RENDER'} + + @classmethod + def poll(cls, context): + cam = context.camera + rd = context.scene.render + return cam and (rd.engine in cls.COMPAT_ENGINES) + + +class WorldButtonsPanel: + """Use this class to define buttons from the world tab of + properties window.""" + + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "world" + COMPAT_ENGINES = {'POVRAY_RENDER'} + + @classmethod + def poll(cls, context): + wld = context.world + rd = context.scene.render + return wld and (rd.engine in cls.COMPAT_ENGINES) + + +############################################################################### +# Camera Settings +############################################################################### +class CAMERA_PT_POV_cam_dof(CameraDataButtonsPanel, Panel): + """Use this class for camera depth of field focal blur buttons.""" + + bl_label = "POV Aperture" + COMPAT_ENGINES = {'POVRAY_RENDER'} + bl_parent_id = "DATA_PT_camera_dof_aperture" + bl_options = {'HIDE_HEADER'} + # def draw_header(self, context): + # cam = context.camera + + # self.layout.prop(cam.pov, "dof_enable", text="") + + def draw(self, context): + layout = self.layout + + cam = context.camera + + layout.active = cam.dof.use_dof + layout.use_property_split = True # Active single-column layout + + flow = layout.grid_flow( + row_major=True, columns=0, even_columns=True, even_rows=False, align=False + ) + + col = flow.column() + col.label(text="F-Stop value will export as") + col.label(text="POV aperture : " + "%.3f" % (1 / cam.dof.aperture_fstop * 1000)) + + col = flow.column() + col.prop(cam.pov, "dof_samples_min") + col.prop(cam.pov, "dof_samples_max") + col.prop(cam.pov, "dof_variance") + col.prop(cam.pov, "dof_confidence") + + +class CAMERA_PT_POV_cam_nor(CameraDataButtonsPanel, Panel): + """Use this class for camera normal perturbation buttons.""" + + bl_label = "POV Perturbation" + COMPAT_ENGINES = {'POVRAY_RENDER'} + + def draw_header(self, context): + cam = context.camera + + self.layout.prop(cam.pov, "normal_enable", text="") + + def draw(self, context): + layout = self.layout + + cam = context.camera + + layout.active = cam.pov.normal_enable + + layout.prop(cam.pov, "normal_patterns") + layout.prop(cam.pov, "cam_normal") + layout.prop(cam.pov, "turbulence") + layout.prop(cam.pov, "scale") + + +class CAMERA_PT_POV_replacement_text(CameraDataButtonsPanel, Panel): + """Use this class for camera text replacement field.""" + + bl_label = "Custom POV Code" + COMPAT_ENGINES = {'POVRAY_RENDER'} + + def draw(self, context): + layout = self.layout + + cam = context.camera + + col = layout.column() + col.label(text="Replace properties with:") + col.prop(cam.pov, "replacement_text", text="") + + +############################################################################### +# World background and sky sphere Settings +############################################################################### + + +class WORLD_PT_POV_world(WorldButtonsPanel, Panel): + """Use this class to define pov world buttons""" + + bl_label = "World" + + COMPAT_ENGINES = {'POVRAY_RENDER'} + + def draw(self, context): + layout = self.layout + + world = context.world.pov + + row = layout.row(align=True) + row.menu(WORLD_MT_POV_presets.__name__, text=WORLD_MT_POV_presets.bl_label) + row.operator(WORLD_OT_POV_add_preset.bl_idname, text="", icon='ADD') + row.operator(WORLD_OT_POV_add_preset.bl_idname, text="", icon='REMOVE').remove_active = True + + row = layout.row() + row.prop(world, "use_sky_paper") + row.prop(world, "use_sky_blend") + row.prop(world, "use_sky_real") + + row = layout.row() + row.column().prop(world, "horizon_color") + col = row.column() + col.prop(world, "zenith_color") + col.active = world.use_sky_blend + row.column().prop(world, "ambient_color") + + # row = layout.row() + # row.prop(world, "exposure") #Re-implement later as a light multiplier + # row.prop(world, "color_range") + + +class WORLD_PT_POV_mist(WorldButtonsPanel, Panel): + """Use this class to define pov mist buttons.""" + + bl_label = "Mist" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'POVRAY_RENDER'} + + def draw_header(self, context): + world = context.world + + self.layout.prop(world.mist_settings, "use_mist", text="") + + def draw(self, context): + layout = self.layout + + world = context.world + + layout.active = world.mist_settings.use_mist + + split = layout.split() + + col = split.column() + col.prop(world.mist_settings, "intensity") + col.prop(world.mist_settings, "start") + + col = split.column() + col.prop(world.mist_settings, "depth") + col.prop(world.mist_settings, "height") + + layout.prop(world.mist_settings, "falloff") + + +class WORLD_MT_POV_presets(Menu): + """Apply world preset to all concerned properties""" + + bl_label = "World Presets" + preset_subdir = "pov/world" + preset_operator = "script.execute_preset" + draw = bpy.types.Menu.draw_preset + + +class WORLD_OT_POV_add_preset(AddPresetBase, Operator): + """Add a World Preset recording current values""" + + bl_idname = "object.world_preset_add" + bl_label = "Add World Preset" + preset_menu = "WORLD_MT_POV_presets" + + # variable used for all preset values + preset_defines = ["scene = bpy.context.scene"] + + # properties to store in the preset + preset_values = [ + "scene.world.use_sky_blend", + "scene.world.horizon_color", + "scene.world.zenith_color", + "scene.world.ambient_color", + "scene.world.mist_settings.use_mist", + "scene.world.mist_settings.intensity", + "scene.world.mist_settings.depth", + "scene.world.mist_settings.start", + "scene.pov.media_enable", + "scene.pov.media_scattering_type", + "scene.pov.media_samples", + "scene.pov.media_diffusion_scale", + "scene.pov.media_diffusion_color", + "scene.pov.media_absorption_scale", + "scene.pov.media_absorption_color", + "scene.pov.media_eccentricity", + ] + + # where to store the preset + preset_subdir = "pov/world" + + +class RENDER_PT_POV_media(WorldButtonsPanel, Panel): + """Use this class to define a pov global atmospheric media buttons.""" + + bl_label = "Atmosphere Media" + COMPAT_ENGINES = {'POVRAY_RENDER'} + + def draw_header(self, context): + scene = context.scene + + self.layout.prop(scene.pov, "media_enable", text="") + + def draw(self, context): + layout = self.layout + + scene = context.scene + + layout.active = scene.pov.media_enable + + col = layout.column() + col.prop(scene.pov, "media_scattering_type", text="") + col = layout.column() + col.prop(scene.pov, "media_samples", text="Samples") + split = layout.split() + col = split.column(align=True) + col.label(text="Scattering:") + col.prop(scene.pov, "media_diffusion_scale") + col.prop(scene.pov, "media_diffusion_color", text="") + col = split.column(align=True) + col.label(text="Absorption:") + col.prop(scene.pov, "media_absorption_scale") + col.prop(scene.pov, "media_absorption_color", text="") + if scene.pov.media_scattering_type == '5': + col = layout.column() + col.prop(scene.pov, "media_eccentricity", text="Eccentricity") + + +############################################################################### +# Lights settings +############################################################################### + +################################################################################ +# from bl_ui import properties_data_light +# for member in dir(properties_data_light): +# subclass = getattr(properties_data_light, member) +# try: +# subclass.COMPAT_ENGINES.add('POVRAY_RENDER') +# except BaseException as e: +# print e.__doc__ +# print('An exception occurred: {}'.format(e)) +# pass +# del properties_data_light +#########################LIGHTS################################ + +from bl_ui import properties_data_light + +# # These panels are kept +# properties_data_light.DATA_PT_custom_props_light.COMPAT_ENGINES.add('POVRAY_RENDER') +# properties_data_light.DATA_PT_context_light.COMPAT_ENGINES.add('POVRAY_RENDER') + +## make some native panels contextual to some object variable +## by recreating custom panels inheriting their properties +class PovLightButtonsPanel(properties_data_light.DataButtonsPanel): + """Use this class to define buttons from the light data tab of + properties window.""" + + COMPAT_ENGINES = {'POVRAY_RENDER'} + POV_OBJECT_TYPES = {'RAINBOW'} + + @classmethod + def poll(cls, context): + obj = context.object + # We use our parent class poll func too, avoids to re-define too much things... + return ( + super(PovLightButtonsPanel, cls).poll(context) + and obj + and obj.pov.object_as not in cls.POV_OBJECT_TYPES + ) + + +# We cannot inherit from RNA classes (like e.g. properties_data_mesh.DATA_PT_vertex_groups). +# Complex py/bpy/rna interactions (with metaclass and all) simply do not allow it to work. +# So we simply have to explicitly copy here the interesting bits. ;) +from bl_ui import properties_data_light + +# for member in dir(properties_data_light): +# subclass = getattr(properties_data_light, member) +# try: +# subclass.COMPAT_ENGINES.add('POVRAY_RENDER') +# except BaseException as e: +# print(e.__doc__) +# print('An exception occurred: {}'.format(e)) +# pass + +# Now only These panels are kept +properties_data_light.DATA_PT_custom_props_light.COMPAT_ENGINES.add('POVRAY_RENDER') +properties_data_light.DATA_PT_context_light.COMPAT_ENGINES.add('POVRAY_RENDER') + + +class LIGHT_PT_POV_preview(PovLightButtonsPanel, Panel): + # XXX Needs update and docstring + bl_label = properties_data_light.DATA_PT_preview.bl_label + + draw = properties_data_light.DATA_PT_preview.draw + + +class LIGHT_PT_POV_light(PovLightButtonsPanel, Panel): + """UI panel to main pov light parameters""" + + # bl_label = properties_data_light.DATA_PT_light.bl_label + + # draw = properties_data_light.DATA_PT_light.draw + # class DATA_PT_POV_light(DataButtonsPanel, Panel): + bl_label = "Light" + # COMPAT_ENGINES = {'POVRAY_RENDER'} + + def draw(self, context): + layout = self.layout + + light = context.light + + layout.row().prop(light, "type", expand=True) + + split = layout.split() + + col = split.column() + sub = col.column() + sub.prop(light, "color", text="") + sub.prop(light, "energy") + + if light.type in {'POINT', 'SPOT'}: + sub.label(text="Falloff:") + sub.prop(light, "falloff_type", text="") + sub.prop(light, "distance") + + if light.falloff_type == 'LINEAR_QUADRATIC_WEIGHTED': + col.label(text="Attenuation Factors:") + sub = col.column(align=True) + sub.prop(light, "linear_attenuation", slider=True, text="Linear") + sub.prop(light, "quadratic_attenuation", slider=True, text="Quadratic") + + elif light.falloff_type == 'INVERSE_COEFFICIENTS': + col.label(text="Inverse Coefficients:") + sub = col.column(align=True) + sub.prop(light, "constant_coefficient", text="Constant") + sub.prop(light, "linear_coefficient", text="Linear") + sub.prop(light, "quadratic_coefficient", text="Quadratic") + + if light.type == 'AREA': + col.prop(light, "distance") + + # restore later as interface to POV light groups ? + # col = split.column() + # col.prop(light, "use_own_layer", text="This Layer Only") + + +class LIGHT_MT_POV_presets(Menu): + """Use this class to define preset menu for pov lights.""" + + bl_label = "Lamp Presets" + preset_subdir = "pov/light" + preset_operator = "script.execute_preset" + draw = bpy.types.Menu.draw_preset + + +class LIGHT_OT_POV_add_preset(AddPresetBase, Operator): + """Operator to add a Light Preset""" + + bl_idname = "object.light_preset_add" + bl_label = "Add Light Preset" + preset_menu = "LIGHT_MT_POV_presets" + + # variable used for all preset values + preset_defines = ["lightdata = bpy.context.object.data"] + + # properties to store in the preset + preset_values = ["lightdata.type", "lightdata.color"] + + # where to store the preset + preset_subdir = "pov/light" + + +# Draw into the existing light panel +def light_panel_func(self, context): + """Menu to browse and add light preset""" + layout = self.layout + + row = layout.row(align=True) + row.menu(LIGHT_MT_POV_presets.__name__, text=LIGHT_MT_POV_presets.bl_label) + row.operator(LIGHT_OT_POV_add_preset.bl_idname, text="", icon='ADD') + row.operator(LIGHT_OT_POV_add_preset.bl_idname, text="", icon='REMOVE').remove_active = True + + +'''#TORECREATE##DEPRECATED# +class LIGHT_PT_POV_sunsky(PovLightButtonsPanel, Panel): + bl_label = properties_data_light.DATA_PT_sunsky.bl_label + + @classmethod + def poll(cls, context): + lamp = context.light + engine = context.scene.render.engine + return (lamp and lamp.type == 'SUN') and (engine in cls.COMPAT_ENGINES) + + draw = properties_data_light.DATA_PT_sunsky.draw + +''' + + +class LIGHT_PT_POV_shadow(PovLightButtonsPanel, Panel): + # Todo : update and docstring + bl_label = "Shadow" + + @classmethod + def poll(cls, context): + light = context.light + engine = context.scene.render.engine + return light and (engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + + light = context.light + + layout.row().prop(light.pov, "shadow_method", expand=True) + + split = layout.split() + col = split.column() + + col.prop(light.pov, "use_halo") + sub = col.column(align=True) + sub.active = light.pov.use_halo + sub.prop(light.pov, "halo_intensity", text="Intensity") + + if light.pov.shadow_method == 'NOSHADOW' and light.type == 'AREA': + split = layout.split() + + col = split.column() + col.label(text="Form factor sampling:") + + sub = col.row(align=True) + + if light.shape == 'SQUARE': + sub.prop(light, "shadow_ray_samples_x", text="Samples") + elif light.shape == 'RECTANGLE': + sub.prop(light.pov, "shadow_ray_samples_x", text="Samples X") + sub.prop(light.pov, "shadow_ray_samples_y", text="Samples Y") + + if light.pov.shadow_method != 'NOSHADOW': + split = layout.split() + + col = split.column() + col.prop(light, "shadow_color", text="") + + # col = split.column() + # col.prop(light.pov, "use_shadow_layer", text="This Layer Only") + # col.prop(light.pov, "use_only_shadow") + + if light.pov.shadow_method == 'RAY_SHADOW': + split = layout.split() + + col = split.column() + col.label(text="Sampling:") + + if light.type in {'POINT', 'SUN', 'SPOT'}: + sub = col.row() + + sub.prop(light.pov, "shadow_ray_samples_x", text="Samples") + # any equivalent in pov? + # sub.prop(light, "shadow_soft_size", text="Soft Size") + + elif light.type == 'AREA': + sub = col.row(align=True) + + if light.shape == 'SQUARE': + sub.prop(light.pov, "shadow_ray_samples_x", text="Samples") + elif light.shape == 'RECTANGLE': + sub.prop(light.pov, "shadow_ray_samples_x", text="Samples X") + sub.prop(light.pov, "shadow_ray_samples_y", text="Samples Y") + + +class LIGHT_PT_POV_area(PovLightButtonsPanel, Panel): + """Area light UI panel""" + + bl_label = properties_data_light.DATA_PT_area.bl_label + bl_parent_id = "LIGHT_PT_POV_light" + bl_context = "data" + + @classmethod + def poll(cls, context): + lamp = context.light + engine = context.scene.render.engine + return (lamp and lamp.type == 'AREA') and (engine in cls.COMPAT_ENGINES) + + draw = properties_data_light.DATA_PT_area.draw + + +class LIGHT_PT_POV_spot(PovLightButtonsPanel, Panel): + bl_label = properties_data_light.DATA_PT_spot.bl_label + bl_parent_id = "LIGHT_PT_POV_light" + bl_context = "data" + + @classmethod + def poll(cls, context): + lamp = context.light + engine = context.scene.render.engine + return (lamp and lamp.type == 'SPOT') and (engine in cls.COMPAT_ENGINES) + + draw = properties_data_light.DATA_PT_spot.draw + + +class LIGHT_PT_POV_falloff_curve(PovLightButtonsPanel, Panel): + bl_label = properties_data_light.DATA_PT_falloff_curve.bl_label + bl_options = properties_data_light.DATA_PT_falloff_curve.bl_options + + @classmethod + def poll(cls, context): + lamp = context.light + engine = context.scene.render.engine + + return ( + lamp and lamp.type in {'POINT', 'SPOT'} and lamp.falloff_type == 'CUSTOM_CURVE' + ) and (engine in cls.COMPAT_ENGINES) + + draw = properties_data_light.DATA_PT_falloff_curve.draw + + +class OBJECT_PT_POV_rainbow(PovLightButtonsPanel, Panel): + """Use this class to define buttons from the rainbow panel of + properties window. inheriting lamp buttons panel class""" + + bl_label = "POV-Ray Rainbow" + COMPAT_ENGINES = {'POVRAY_RENDER'} + # bl_options = {'HIDE_HEADER'} + @classmethod + def poll(cls, context): + engine = context.scene.render.engine + obj = context.object + return obj and obj.pov.object_as == 'RAINBOW' and (engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + + obj = context.object + + col = layout.column() + + if obj.pov.object_as == 'RAINBOW': + if not obj.pov.unlock_parameters: + col.prop( + obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED' + ) + col.label(text="Rainbow projection angle: " + str(obj.data.spot_size)) + col.label(text="Rainbow width: " + str(obj.data.spot_blend)) + col.label(text="Rainbow distance: " + str(obj.data.shadow_buffer_clip_start)) + col.label(text="Rainbow arc angle: " + str(obj.pov.arc_angle)) + col.label(text="Rainbow falloff angle: " + str(obj.pov.falloff_angle)) + + else: + col.prop( + obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED' + ) + col.label(text="3D view proxy may get out of synch") + col.active = obj.pov.unlock_parameters + + layout.operator("pov.cone_update", text="Update", icon="MESH_CONE") + + # col.label(text="Parameters:") + col.prop(obj.data, "spot_size", text="Rainbow Projection Angle") + col.prop(obj.data, "spot_blend", text="Rainbow width") + col.prop(obj.data, "shadow_buffer_clip_start", text="Visibility distance") + col.prop(obj.pov, "arc_angle") + col.prop(obj.pov, "falloff_angle") + + +del properties_data_light + + +classes = ( + WORLD_PT_POV_world, + WORLD_MT_POV_presets, + WORLD_OT_POV_add_preset, + WORLD_PT_POV_mist, + RENDER_PT_POV_media, + LIGHT_PT_POV_preview, + LIGHT_PT_POV_light, + LIGHT_PT_POV_shadow, + LIGHT_PT_POV_spot, + LIGHT_PT_POV_area, + LIGHT_MT_POV_presets, + LIGHT_OT_POV_add_preset, + OBJECT_PT_POV_rainbow, + CAMERA_PT_POV_cam_dof, + CAMERA_PT_POV_cam_nor, + CAMERA_PT_POV_replacement_text, +) + + +def register(): + + for cls in classes: + register_class(cls) + bpy.types.LIGHT_PT_POV_light.prepend(light_panel_func) + + +def unregister(): + + for cls in reversed(classes): + unregister_class(cls) + bpy.types.LIGHT_PT_POV_light.remove(light_panel_func) |