diff --git a/render_ui_animation_render.py b/render_ui_animation_render.py new file mode 100644 index 0000000000000000000000000000000000000000..27d84a4a23ca3a9230aec16bfaa7aa00aafff91b --- /dev/null +++ b/render_ui_animation_render.py @@ -0,0 +1,223 @@ +# ##### 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 ##### + +import bpy + +bl_info = { + "name": "UI Animation Render", + "author": "Luca Rood", + "description": "Render animations of the Blender UI.", + "blender": (2, 80, 0), + "version": (0, 1, 0), + "location": "View3D > Sidebar > View Tab and Ctrl+Shift+F12", + "warning": "", + "category": "Render" +} + +km = None + + +def draw_ui(prefs, layout): + layout.prop(prefs, "delay") + + col = layout.column(align=True) + col.label(text="Animation Highlight:") + + row = col.row() + row.prop(prefs, "anim_highlight", expand=True) + + if prefs.anim_highlight == "replace": + split = col.split(factor=0.2) + split.label(text="Color") + row = split.row(align=True) + row.prop(prefs, "highlight_color", text="") + row.prop(prefs, "highlight_blend", text="Blend") + + +class UIAnimationRenderPreferences(bpy.types.AddonPreferences): + bl_idname = __name__ + + delay: bpy.props.FloatProperty( + name="Capture Delay", + description="How much time to wait (seconds) before capturing each frame, to allow the viewport to clean up", + default=0.5 + ) + + anim_highlight: bpy.props.EnumProperty( + name="Animation Highlight", + description="What to do with the animated field highlight color", + items=[("keep", "Keep", "Keep the animated field highlight", 0), + ("hide", "Hide", "Hide the animated field highlight", 1), + ("replace", "Replace", "Replace the animated field highlight", 2)], + default="keep" + ) + + highlight_color: bpy.props.FloatVectorProperty( + name="Highlight Color", + description="Color to use for animated field highlights", + subtype='COLOR', + default=(1.0, 1.0, 1.0) + ) + + highlight_blend: bpy.props.FloatProperty( + name="Highlight Blend", + description="How much the highlight color influences the field color", + default=0.5 + ) + + def draw(self, context): + draw_ui(self, self.layout) + + +class RenderScreen(bpy.types.Operator): + bl_idname = "render.render_screen" + bl_label = "Render Screen" + bl_description = "Capture the screen for each animation frame and write to the render output path" + + _timer = None + _f_initial = 1 + _theme_blend = 0.0 + _theme_key = (0, 0, 0) + _theme_key_sel = (0, 0, 0) + _theme_anim = (0, 0, 0) + _theme_anim_sel = (0, 0, 0) + _theme_driven = (0, 0, 0) + _theme_driven_sel = (0, 0, 0) + + def modal(self, context, event): + if event.type in {'RIGHTMOUSE', 'ESC'}: + self.stop(context) + return {'CANCELLED'} + + if event.type == 'TIMER': + scene = context.scene + f_curr = scene.frame_current + + bpy.ops.screen.screenshot(filepath=context.scene.render.frame_path(frame=f_curr)) + + if f_curr < scene.frame_end: + scene.frame_set(f_curr + 1) + else: + self.stop(context) + return {'FINISHED'} + + return {'RUNNING_MODAL'} + + def execute(self, context): + # Adjust animation highlight (theme) + prefs = context.preferences + addon_prefs = prefs.addons[__name__].preferences + theme = prefs.themes[0].user_interface.wcol_state + + if addon_prefs.anim_highlight == "hide": + self._theme_blend = theme.blend + theme.blend = 0.0 + elif addon_prefs.anim_highlight == "replace": + self._theme_blend = theme.blend + self._theme_key = theme.inner_key.copy() + self._theme_key_sel = theme.inner_key_sel.copy() + self._theme_anim = theme.inner_anim.copy() + self._theme_anim_sel = theme.inner_anim_sel.copy() + self._theme_driven = theme.inner_driven.copy() + self._theme_driven_sel = theme.inner_driven_sel.copy() + + theme.blend = addon_prefs.highlight_blend + theme.inner_key = addon_prefs.highlight_color + theme.inner_key_sel = addon_prefs.highlight_color + theme.inner_anim = addon_prefs.highlight_color + theme.inner_anim_sel = addon_prefs.highlight_color + theme.inner_driven = addon_prefs.highlight_color + theme.inner_driven_sel = addon_prefs.highlight_color + + # Set frame + scene = context.scene + self._f_initial = scene.frame_current + scene.frame_set(scene.frame_start) + + # Start timer + wm = context.window_manager + self._timer = wm.event_timer_add(addon_prefs.delay, window=context.window) + wm.modal_handler_add(self) + return {'RUNNING_MODAL'} + + def stop(self, context): + # Stop timer + wm = context.window_manager + wm.event_timer_remove(self._timer) + + # Reset frame + context.scene.frame_set(self._f_initial) + + # Reset theme + prefs = context.preferences + addon_prefs = prefs.addons[__name__].preferences + theme = prefs.themes[0].user_interface.wcol_state + + if addon_prefs.anim_highlight == "hide": + theme.blend = self._theme_blend + elif addon_prefs.anim_highlight == "replace": + theme.blend = self._theme_blend + theme.inner_key = self._theme_key + theme.inner_key_sel = self._theme_key_sel + theme.inner_anim = self._theme_anim + theme.inner_anim_sel = self._theme_anim_sel + theme.inner_driven = self._theme_driven + theme.inner_driven_sel = self._theme_driven_sel + + +class VIEW3D_PT_ui_animation_render(bpy.types.Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_category = "View" + bl_label = "UI Animation Render" + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = False + + prefs = context.preferences + addon_prefs = prefs.addons[__name__].preferences + + layout.operator(RenderScreen.bl_idname) + draw_ui(addon_prefs, layout) + + +def register(): + global km + + bpy.utils.register_class(UIAnimationRenderPreferences) + bpy.utils.register_class(RenderScreen) + bpy.utils.register_class(VIEW3D_PT_ui_animation_render) + + wm = bpy.context.window_manager + km = wm.keyconfigs.addon.keymaps.new(name='Screen', space_type='EMPTY') + km.keymap_items.new('render.render_screen', 'F12', 'PRESS', shift=True, ctrl=True) + + +def unregister(): + global km + + bpy.utils.unregister_class(UIAnimationRenderPreferences) + bpy.utils.unregister_class(RenderScreen) + bpy.utils.unregister_class(VIEW3D_PT_ui_animation_render) + + if km is not None: + wm = bpy.context.window_manager + wm.keyconfigs.addon.keymaps.remove(km) + km = None