diff options
author | CansecoGPC <machaquiro@yahoo.es> | 2019-12-09 16:42:04 +0300 |
---|---|---|
committer | CansecoGPC <machaquiro@yahoo.es> | 2019-12-09 16:42:04 +0300 |
commit | 75af6e5dcf84cc2d2693374a01ecbad0f874701b (patch) | |
tree | 86d5ad098857a591e9f997881d762e839b33e98a /amaranth/animation | |
parent | 395ca8a4be7a66c72a5556c51f958644601a846b (diff) |
Amaranth: Add back from addons contrib
Diffstat (limited to 'amaranth/animation')
-rw-r--r-- | amaranth/animation/__init__.py | 0 | ||||
-rw-r--r-- | amaranth/animation/frame_current.py | 45 | ||||
-rw-r--r-- | amaranth/animation/jump_frames.py | 209 | ||||
-rw-r--r-- | amaranth/animation/motion_paths.py | 144 | ||||
-rw-r--r-- | amaranth/animation/timeline_extra_info.py | 67 |
5 files changed, 465 insertions, 0 deletions
diff --git a/amaranth/animation/__init__.py b/amaranth/animation/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/amaranth/animation/__init__.py diff --git a/amaranth/animation/frame_current.py b/amaranth/animation/frame_current.py new file mode 100644 index 00000000..6bea2009 --- /dev/null +++ b/amaranth/animation/frame_current.py @@ -0,0 +1,45 @@ +# 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. +""" +Current Frame Slider + +Currently the only way to change the current frame is to have a Timeline +editor open, but sometimes you don't have one, or you're fullscreen. +This option adds the Current Frame slider to the Specials menu. Find it +hitting the W menu in Object mode, you can slide or click in the middle +of the button to set the frame manually. +""" + +import bpy + + +def button_frame_current(self, context): + get_addon = "amaranth" in context.preferences.addons.keys() + if not get_addon: + return + + scene = context.scene + if context.preferences.addons["amaranth"].preferences.use_frame_current: + self.layout.separator() + self.layout.prop(scene, "frame_current", text="Set Current Frame") + + +def register(): + bpy.types.VIEW3D_MT_object_context_menu.append(button_frame_current) + bpy.types.VIEW3D_MT_pose_context_menu.append(button_frame_current) + + +def unregister(): + bpy.types.VIEW3D_MT_object_context_menu.remove(button_frame_current) + bpy.types.VIEW3D_MT_pose_context_menu.remove(button_frame_current) diff --git a/amaranth/animation/jump_frames.py b/amaranth/animation/jump_frames.py new file mode 100644 index 00000000..fb12cb35 --- /dev/null +++ b/amaranth/animation/jump_frames.py @@ -0,0 +1,209 @@ +# 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. +""" +Jump X Frames on Shift Up/Down + +When you hit Shift Up/Down, you'll jump 10 frames forward/backwards. +Sometimes is nice to tweak that value. + +In the User Preferences, Editing tab, you'll find a "Frames to Jump" +slider where you can adjust how many frames you'd like to move +forwards/backwards. + +Make sure you save your user settings if you want to use this value from +now on. + +Find it on the User Preferences, Editing. +""" + +import bpy +from bpy.types import Operator +from bpy.props import BoolProperty + +KEYMAPS = list() + + +# FUNCTION: Check if object has keyframes for a specific frame +def is_keyframe(ob, frame): + if ob is not None and ob.animation_data is not None and ob.animation_data.action is not None: + for fcu in ob.animation_data.action.fcurves: + if frame in (p.co.x for p in fcu.keyframe_points): + return True + return False + + +# monkey path is_keyframe function +bpy.types.Object.is_keyframe = is_keyframe + + +# FEATURE: Jump to frame in-between next and previous keyframe +class AMTH_SCREEN_OT_keyframe_jump_inbetween(Operator): + """Jump to half in-between keyframes""" + bl_idname = "screen.amth_keyframe_jump_inbetween" + bl_label = "Jump to Keyframe In-between" + + backwards: BoolProperty() + + def execute(self, context): + back = self.backwards + + scene = context.scene + ob = bpy.context.object + frame_start = scene.frame_start + frame_end = scene.frame_end + + if not context.scene.get("amth_keyframes_jump"): + context.scene["amth_keyframes_jump"] = list() + + keyframes_list = context.scene["amth_keyframes_jump"] + + for f in range(frame_start, frame_end): + if ob.is_keyframe(f): + keyframes_list = list(keyframes_list) + keyframes_list.append(f) + + if keyframes_list: + keyframes_list_half = [] + + for i, item in enumerate(keyframes_list): + try: + next_item = keyframes_list[i + 1] + keyframes_list_half.append(int((item + next_item) / 2)) + except: + pass + + if len(keyframes_list_half) > 1: + if back: + v = (scene.frame_current == keyframes_list_half[::-1][-1], + scene.frame_current < keyframes_list_half[::-1][-1]) + if any(v): + self.report({"INFO"}, "No keyframes behind") + else: + for i in keyframes_list_half[::-1]: + if scene.frame_current > i: + scene.frame_current = i + break + else: + v = (scene.frame_current == keyframes_list_half[-1], + scene.frame_current > keyframes_list_half[-1]) + if any(v): + self.report({"INFO"}, "No keyframes ahead") + else: + for i in keyframes_list_half: + if scene.frame_current < i: + scene.frame_current = i + break + else: + self.report({"INFO"}, "Object has only 1 keyframe") + else: + self.report({"INFO"}, "Object has no keyframes") + + return {"FINISHED"} + + +# FEATURE: Jump forward/backward every N frames +class AMTH_SCREEN_OT_frame_jump(Operator): + """Jump a number of frames forward/backwards""" + bl_idname = "screen.amaranth_frame_jump" + bl_label = "Jump Frames" + + forward: BoolProperty(default=True) + + def execute(self, context): + scene = context.scene + + get_addon = "amaranth" in context.preferences.addons.keys() + if not get_addon: + return {"CANCELLED"} + + preferences = context.preferences.addons["amaranth"].preferences + + if preferences.use_framerate: + framedelta = scene.render.fps + else: + framedelta = preferences.frames_jump + if self.forward: + scene.frame_current = scene.frame_current + framedelta + else: + scene.frame_current = scene.frame_current - framedelta + + return {"FINISHED"} + + +def ui_userpreferences_edit(self, context): + get_addon = "amaranth" in context.preferences.addons.keys() + if not get_addon: + return + + preferences = context.preferences.addons["amaranth"].preferences + + col = self.layout.column() + split = col.split(factor=0.21) + split.prop(preferences, "frames_jump", + text="Frames to Jump") + + +def label(self, context): + get_addon = "amaranth" in context.preferences.addons.keys() + if not get_addon: + return + + layout = self.layout + + if context.preferences.addons["amaranth"].preferences.use_timeline_extra_info: + row = layout.row(align=True) + + row.operator(AMTH_SCREEN_OT_keyframe_jump_inbetween.bl_idname, + icon="PREV_KEYFRAME", text="").backwards = True + row.operator(AMTH_SCREEN_OT_keyframe_jump_inbetween.bl_idname, + icon="NEXT_KEYFRAME", text="").backwards = False + + +def register(): + bpy.utils.register_class(AMTH_SCREEN_OT_frame_jump) + bpy.utils.register_class(AMTH_SCREEN_OT_keyframe_jump_inbetween) + bpy.types.USERPREF_PT_animation_timeline.append(ui_userpreferences_edit) + bpy.types.USERPREF_PT_animation_timeline.append(label) + + # register keyboard shortcuts + wm = bpy.context.window_manager + kc = wm.keyconfigs.addon + + km = kc.keymaps.new(name="Frames") + kmi = km.keymap_items.new('screen.amth_keyframe_jump_inbetween', 'UP_ARROW', 'PRESS', shift=True, ctrl=True) + kmi.properties.backwards = False + KEYMAPS.append((km, kmi)) + + kmi = km.keymap_items.new('screen.amth_keyframe_jump_inbetween', 'DOWN_ARROW', 'PRESS', shift=True, ctrl=True) + kmi.properties.backwards = True + KEYMAPS.append((km, kmi)) + + kmi = km.keymap_items.new( + "screen.amaranth_frame_jump", "UP_ARROW", "PRESS", shift=True) + kmi.properties.forward = True + KEYMAPS.append((km, kmi)) + + kmi = km.keymap_items.new( + "screen.amaranth_frame_jump", "DOWN_ARROW", "PRESS", shift=True) + kmi.properties.forward = False + KEYMAPS.append((km, kmi)) + + +def unregister(): + bpy.utils.unregister_class(AMTH_SCREEN_OT_frame_jump) + bpy.utils.unregister_class(AMTH_SCREEN_OT_keyframe_jump_inbetween) + bpy.types.USERPREF_PT_animation_timeline.remove(ui_userpreferences_edit) + for km, kmi in KEYMAPS: + km.keymap_items.remove(kmi) + KEYMAPS.clear() diff --git a/amaranth/animation/motion_paths.py b/amaranth/animation/motion_paths.py new file mode 100644 index 00000000..7988b452 --- /dev/null +++ b/amaranth/animation/motion_paths.py @@ -0,0 +1,144 @@ +# 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. +""" +Bone Motion Paths: + +Match Frame Range + Clear All Paths + +* Clear All Paths: +Silly operator to loop through all bones and clear their paths, useful +when having hidden bones (othrewise you have to go through each one of +them and clear manually) + +*Match Current Frame Range: +Set the current frame range as motion path range. + +Both requests by Hjalti from Project Pampa +Thanks to Bassam Kurdali for helping finding out the weirdness behind +Motion Paths bpy. + +Developed during Caminandes Open Movie Project +""" + +import bpy + + +class AMTH_POSE_OT_paths_clear_all(bpy.types.Operator): + + """Clear motion paths from all bones""" + bl_idname = "pose.paths_clear_all" + bl_label = "Clear All Motion Paths" + bl_options = {"UNDO"} + + @classmethod + def poll(cls, context): + return context.mode == "POSE" + + def execute(self, context): + # silly but works + for b in context.object.data.bones: + b.select = True + bpy.ops.pose.paths_clear() + b.select = False + return {"FINISHED"} + + +class AMTH_POSE_OT_paths_frame_match(bpy.types.Operator): + + """Match Start/End frame of scene to motion path range""" + bl_idname = "pose.paths_frame_match" + bl_label = "Match Frame Range" + bl_options = {"UNDO"} + + def execute(self, context): + avs = context.object.pose.animation_visualization + scene = context.scene + + if avs.motion_path.type == "RANGE": + if scene.use_preview_range: + avs.motion_path.frame_start = scene.frame_preview_start + avs.motion_path.frame_end = scene.frame_preview_end + else: + avs.motion_path.frame_start = scene.frame_start + avs.motion_path.frame_end = scene.frame_end + + else: + if scene.use_preview_range: + avs.motion_path.frame_before = scene.frame_preview_start + avs.motion_path.frame_after = scene.frame_preview_end + else: + avs.motion_path.frame_before = scene.frame_start + avs.motion_path.frame_after = scene.frame_end + + return {"FINISHED"} + + +def pose_motion_paths_ui(self, context): + + layout = self.layout + scene = context.scene + avs = context.object.pose.animation_visualization + if context.active_pose_bone: + mpath = context.active_pose_bone.motion_path + layout.separator() + layout.label(text="Motion Paths Extras:") + + split = layout.split() + + col = split.column(align=True) + + if context.selected_pose_bones: + if mpath: + sub = col.row(align=True) + sub.operator( + "pose.paths_update", text="Update Path", icon="BONE_DATA") + sub.operator("pose.paths_clear", text="", icon="X") + else: + col.operator( + "pose.paths_calculate", + text="Calculate Path", + icon="BONE_DATA") + else: + col.label(text="Select Bones First", icon="ERROR") + + col = split.column(align=True) + col.operator( + AMTH_POSE_OT_paths_frame_match.bl_idname, + text="Set Preview Frame Range" if scene.use_preview_range else "Set Frame Range", + icon="PREVIEW_RANGE" if scene.use_preview_range else "TIME") + + col = layout.column() + row = col.row(align=True) + + if avs.motion_path.type == "RANGE": + row.prop(avs.motion_path, "frame_start", text="Start") + row.prop(avs.motion_path, "frame_end", text="End") + else: + row.prop(avs.motion_path, "frame_before", text="Before") + row.prop(avs.motion_path, "frame_after", text="After") + + layout.separator() + layout.operator(AMTH_POSE_OT_paths_clear_all.bl_idname, icon="X") + + +def register(): + bpy.utils.register_class(AMTH_POSE_OT_paths_clear_all) + bpy.utils.register_class(AMTH_POSE_OT_paths_frame_match) + bpy.types.DATA_PT_display.append(pose_motion_paths_ui) + + +def unregister(): + bpy.utils.unregister_class(AMTH_POSE_OT_paths_clear_all) + bpy.utils.unregister_class(AMTH_POSE_OT_paths_frame_match) + bpy.types.DATA_PT_display.remove(pose_motion_paths_ui) diff --git a/amaranth/animation/timeline_extra_info.py b/amaranth/animation/timeline_extra_info.py new file mode 100644 index 00000000..0e875b43 --- /dev/null +++ b/amaranth/animation/timeline_extra_info.py @@ -0,0 +1,67 @@ +# 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. +""" +Timeline Extra Info + +Display amount of frames left until Frame End, very handy especially when +rendering an animation or OpenGL preview. +Display current/end time on SMPTE. Find it on the Timeline header. +""" + +import bpy + + +def label_timeline_extra_info(self, context): + get_addon = "amaranth" in context.preferences.addons.keys() + if not get_addon: + return + + layout = self.layout + scene = context.scene + + if context.preferences.addons["amaranth"].preferences.use_timeline_extra_info: + row = layout.row(align=True) + + # Check for preview range + frame_start = scene.frame_preview_start if scene.use_preview_range else scene.frame_start + frame_end = scene.frame_preview_end if scene.use_preview_range else scene.frame_end + + row.label( + text="%s / %s" % + (bpy.utils.smpte_from_frame( + scene.frame_current - + frame_start), + bpy.utils.smpte_from_frame( + frame_end - + frame_start))) + + if (scene.frame_current > frame_end): + row.label(text="%s Frames Ahead" % + ((frame_end - scene.frame_current) * -1)) + elif (scene.frame_current == frame_start): + row.label(text="Start Frame (%s left)" % + (frame_end - scene.frame_current)) + elif (scene.frame_current == frame_end): + row.label(text="%s End Frame" % scene.frame_current) + else: + row.label(text="%s Frames Left" % + (frame_end - scene.frame_current)) + + +def register(): + bpy.types.STATUSBAR_HT_header.append(label_timeline_extra_info) + + +def unregister(): + bpy.types.STATUSBAR_HT_header.remove(label_timeline_extra_info) |