From ce3f2c0783b2ed1bbf5c8642139e4b090603adb6 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 30 Dec 2024 14:47:55 -0600 Subject: [PATCH] Unify calls to armature and pose library --- common.py | 80 ++++++++++++------------------------- gui.py | 63 ++++++++++++----------------- operators.py | 109 +++++++++++++++++++++++---------------------------- 3 files changed, 97 insertions(+), 155 deletions(-) diff --git a/common.py b/common.py index 627b842..090f453 100644 --- a/common.py +++ b/common.py @@ -2,60 +2,31 @@ import bpy import mathutils -def getArmatureObject(context): - obj = context.active_object - if obj: - if obj.type == "ARMATURE": - return obj - elif obj.parent is not None and obj.parent.type == "ARMATURE": - return obj.parent - else: - return None - - -def getLegacyPoseLibrary(context): - try: - arm = getArmatureObject(context) - return getattr(arm, "pose_library", None) - except: - pass +def getArmatureData(context): + try: + arm_object = context.active_object + if arm_object and arm_object.type == "ARMATURE": + return arm_object, getattr(arm_object, "pose_library", None) + elif arm_object and arm_object.parent and arm_object.parent.type == "ARMATURE": + return arm_object.parent, getattr(arm_object.parent, "pose_library", None) + else: + return None, None + except: + return None, None def getArmatureAction(context): try: - arm = getArmatureObject(context) - return getattr(arm.animation_data, "action", None) + arm_object, pose_library = getArmatureData(context) + if getattr(arm_object.animation_data.action, "pose_markers", None): + return getattr(arm_object.animation_data, "action", None) except: pass -def getDsplAction(context): - try: - arm = getArmatureObject(context) - return getattr(arm.dspl, "pose_library", None) - except: - pass - - -def getPoseLib(context): - arm = getArmatureObject(context) - pose_library_dspl = getDsplAction(context) - pose_library_action = getArmatureAction(context) - pose_library_legacy = getLegacyPoseLibrary(context) - - if pose_library_dspl: - return pose_library_dspl - elif pose_library_action and not pose_library_dspl: - return pose_library_action - elif pose_library_legacy and not pose_library_dspl: - return pose_library_legacy - else: - return None - - def searchPoseMarker(context, posename, type): try: - pose_library = getPoseLib(context) + arm_object, pose_library = getArmatureData(context) if type == "marker": return pose_library.pose_markers.get(posename, None) if type == "frame": @@ -67,12 +38,11 @@ def searchPoseMarker(context, posename, type): def findFcurve(context, bone_name, transform, index_int): - arm_object = getArmatureObject(context) - action_object = getPoseLib(context) - pose_markers = action_object.pose_markers + arm_object, pose_library = getArmatureData(context) + pose_markers = pose_library.pose_markers active_frame = pose_markers.active.frame - fcurve_object = action_object.fcurves.find( + fcurve_object = pose_library.fcurves.find( 'pose.bones["'+bone_name+'"].'+transform+'', index=index_int) if hasattr(fcurve_object, 'evaluate'): return fcurve_object.evaluate(active_frame) @@ -81,12 +51,11 @@ def findFcurve(context, bone_name, transform, index_int): def createFcurve(context, bone_name, transform, index_int): - arm_object = getArmatureObject(context) - action_object = getPoseLib(context) - pose_markers = action_object.pose_markers + arm_object, pose_library = getArmatureData(context) + pose_markers = pose_library.pose_markers try: - action_object.fcurves.new( + pose_library.fcurves.new( 'pose.bones["'+bone_name+'"].'+transform+'', index=index_int, action_group=bone_name) return except: @@ -94,12 +63,11 @@ def createFcurve(context, bone_name, transform, index_int): def createKeyframe(context, bone_name, transform, index_int, new_marker, loc): - arm_object = getArmatureObject(context) - action_object = getPoseLib(context) - pose_markers = action_object.pose_markers + arm_object, pose_library = getArmatureData(context) + pose_markers = pose_library.pose_markers try: - action_object.fcurves.find( + pose_library.fcurves.find( 'pose.bones["'+bone_name+'"].'+transform+'', index=index_int).keyframe_points.insert(new_marker, loc) return except: diff --git a/gui.py b/gui.py index 3b09879..52467e3 100644 --- a/gui.py +++ b/gui.py @@ -20,7 +20,8 @@ class DATA_PT_DSPLPanel(bpy.types.Panel): # Detect Armature object and parent armature_layout = dspl_panel_layout.column(align=True) active_obj = context.active_object - arm_object = getArmatureObject(context) + arm_object, pose_library = getArmatureData(context) + pose_library_action = getArmatureAction(context) if arm_object: if arm_object == active_obj: @@ -29,44 +30,32 @@ class DATA_PT_DSPLPanel(bpy.types.Panel): armature_layout.label(text=arm_object.name + " (Parent)") # Attach or create pose library - pose_library_dspl = getDsplAction(context) - pose_library_action = getArmatureAction(context) - pose_library_legacy = getLegacyPoseLibrary(context) - - if pose_library_dspl or pose_library_action or pose_library_legacy: - if pose_library_dspl and not pose_library_action: - active_pose_library = pose_library_dspl + if pose_library or pose_library_action: + if pose_library and not pose_library_action: armature_layout.template_ID( arm_object, "pose_library", new="dspl.create_pose_library", unlink="dspl.unlink_pose_library") - elif pose_library_legacy and not pose_library_dspl: - active_pose_library = pose_library_legacy - armature_layout.template_ID( - arm_object, "pose_library", new="dspl.create_pose_library", unlink="dspl.unlink_pose_library") - - elif pose_library_action and not pose_library_dspl: - active_pose_library = pose_library_action + elif pose_library_action and not pose_library: armature_layout.template_ID( arm_object.animation_data, "action", new="dspl.create_pose_library") armature_layout.label( - text="Legacy Pose Library detected.") + text="Pose Library detected as Action") armature_layout.label( - text="You may convert to avoid problems") + text="You should convert to avoid problems") armature_layout.operator( - "dspl.convert_pose_library", icon='PLUGIN', text="Convert to DSPL") + "dspl.convert_pose_library", icon='PLUGIN', text="Convert to Pose Library") - elif pose_library_action and pose_library_dspl: + elif pose_library and pose_library_action: armature_layout.template_ID( arm_object, "pose_library", new="dspl.create_pose_library") - armature_layout.label(text="Double pose configuration!!") - armature_layout.label(text="You should not proceed") + armature_layout.label(text="Pose Library is opened as Action") + armature_layout.label(text="Keyframes will affect pose") armature_layout.operator( - "dspl.convert_pose_library", icon='PLUGIN', text="Convert to DSPL") - active_pose_library = pose_library_dspl + "dspl.convert_pose_library", icon='PLUGIN', text="Unlink from Action") # List poses in pose library - if active_pose_library: + if pose_library: pose_box_layout = dspl_panel_layout.column() # Menu switcher @@ -78,14 +67,14 @@ class DATA_PT_DSPLPanel(bpy.types.Panel): quick_pose_controls_layout = pose_box_layout.column() quick_pose_controls_layout.menu( OBJECT_MT_AddPoseMenu.bl_idname, icon='ADD', text="New Pose") - if active_pose_library.pose_markers.active: + if pose_library.pose_markers.active: quick_apply_layout = quick_pose_controls_layout.split( align=True) quick_apply_layout.operator( "dspl.browse_poses", icon='CON_ARMATURE', text="Browse") if dsplsettings.new_menu == False: quick_apply_layout.operator( - "dspl.apply_pose", icon='ARMATURE_DATA', text="Apply Pose").posename = active_pose_library.pose_markers.active.name + "dspl.apply_pose", icon='ARMATURE_DATA', text="Apply Pose").posename = pose_library.pose_markers.active.name else: quick_apply_layout.prop(dsplsettings, "edit_mode", icon='GREASEPENCIL', text="Edit", toggle=True) @@ -94,11 +83,11 @@ class DATA_PT_DSPLPanel(bpy.types.Panel): if dsplsettings.new_menu == True: pose_button_layout = pose_box_layout.row() pose_button_entries_layout = pose_button_layout.column(align=True) - for pm in active_pose_library.pose_markers: + for pm in pose_library.pose_markers: row = pose_button_entries_layout.row(align=True) # Selected indicator - selected = pm.frame == active_pose_library.pose_markers.active.frame + selected = pm.frame == pose_library.pose_markers.active.frame if dsplsettings.edit_mode == False: row.label(text="", icon='PMARKER_ACT' if selected else 'PMARKER_SEL') @@ -125,19 +114,19 @@ class DATA_PT_DSPLPanel(bpy.types.Panel): # Pose list pose_list_entries_layout = pose_list_layout.row() pose_list_entries_layout.template_list("UI_UL_list","pose_markers", - active_pose_library, "pose_markers", - active_pose_library.pose_markers, "active_index", rows=4) + pose_library, "pose_markers", + pose_library.pose_markers, "active_index", rows=4) # Pose operators pose_ops_layout = pose_list_entries_layout.column(align=True) pose_ops_layout.operator( "wm.call_menu", icon='ADD', text="").name = "OBJECT_MT_AddPoseMenu" - if active_pose_library.pose_markers.active: + if pose_library.pose_markers.active: pose_ops_layout.operator( "dspl.remove_pose", icon='REMOVE', text="") pose_ops_layout.operator( "dspl.apply_pose", icon='ARMATURE_DATA', text="" - ).posename = active_pose_library.pose_markers.active.name + ).posename = pose_library.pose_markers.active.name pose_ops_layout.operator( "dspl.move_pose", icon='TRIA_UP', text="").direction = "UP" pose_ops_layout.operator( @@ -158,13 +147,12 @@ class OBJECT_MT_AddPoseMenu(bpy.types.Menu): bl_label = "Add Pose" def draw(self, context): - arm_object = getArmatureObject(context) - action_object = getPoseLib(context) + arm_object, pose_library = getArmatureData(context) dspl_add_menu_layout = self.layout dspl_add_menu_layout.operator( "dspl.add_pose", icon='ADD', text="Add New Pose") - if len(action_object.pose_markers): + if len(pose_library.pose_markers): dspl_add_menu_layout.menu( "OBJECT_MT_ReplacePoseMenu", text="Replace Existing Pose", icon="DECORATE_OVERRIDE") @@ -174,11 +162,10 @@ class OBJECT_MT_ReplacePoseMenu(bpy.types.Menu): bl_label = "Add Pose" def draw(self, context): - arm_object = getArmatureObject(context) - action_object = getPoseLib(context) + arm_object, pose_library = getArmatureData(context) dspl_replace_menu_layout = self.layout - for pm in action_object.pose_markers: + for pm in pose_library.pose_markers: op = dspl_replace_menu_layout.operator("dspl.add_pose", text=pm.name, icon="PMARKER") op.replace = True op.posename = pm.name diff --git a/operators.py b/operators.py index f7a8a7b..9bbaefe 100644 --- a/operators.py +++ b/operators.py @@ -13,7 +13,7 @@ class DSPL_OT_CreatePoseLibrary(bpy.types.Operator): bl_options = {'REGISTER', 'UNDO'} def execute(self, context): - arm_object = getArmatureObject(context) + arm_object, pose_library = getArmatureData(context) arm_object.pose_library = bpy.data.actions.new( name=arm_object.name + "_PoseLib") arm_object.pose_library.use_fake_user = True @@ -21,7 +21,7 @@ class DSPL_OT_CreatePoseLibrary(bpy.types.Operator): return {'FINISHED'} -# Operator to convert a pose library to dspl property +# Operator to convert an action to pose library class DSPL_OT_ConvertPoseLibrary(bpy.types.Operator): @@ -31,8 +31,9 @@ class DSPL_OT_ConvertPoseLibrary(bpy.types.Operator): bl_options = {'REGISTER', 'UNDO'} def execute(self, context): - arm_object = getArmatureObject(context) - arm_object.pose_library = arm_object.animation_data.action + arm_object, pose_library = getArmatureData(context) + if pose_library is None: + arm_object.pose_library = arm_object.animation_data.action arm_object.animation_data.action = None return {'FINISHED'} @@ -51,11 +52,9 @@ class DSPL_OT_AddPose(bpy.types.Operator): replace: bpy.props.BoolProperty(name="Replace", description="Replace existing pose", default=False, options={'SKIP_SAVE'}) def execute(self, context): - + arm_object, pose_library = getArmatureData(context) if self.replace == False: - arm_object = getArmatureObject(context) - action_object = getPoseLib(context) - pose_markers = action_object.pose_markers + pose_markers = pose_library.pose_markers new_name = self.posename counter = 1 @@ -83,15 +82,13 @@ class DSPL_OT_AddPose(bpy.types.Operator): setKeyframesFromBones(context, arm_object, new_marker) - action_object.pose_markers.active = pose_markers[pose_name] + pose_library.pose_markers.active = pose_markers[pose_name] bpy.context.area.tag_redraw() self.report({'INFO'}, "DSPL: Added " + pose_markers[new_name].name + " to frame " + str(pose_markers[new_name].frame)) else: - arm_object = getArmatureObject(context) - action_object = getPoseLib(context) - pose_markers = action_object.pose_markers + pose_markers = pose_library.pose_markers active_marker = pose_markers.active new_name = self.posename counter = 1 @@ -127,18 +124,17 @@ class DSPL_OT_RemovePose(bpy.types.Operator): posename: bpy.props.StringProperty() def execute(self, context): - arm_object = getArmatureObject(context) - action_object = getPoseLib(context) - pose_markers = action_object.pose_markers + arm_object, pose_library = getArmatureData(context) + pose_markers = pose_library.pose_markers if self.posename: - action_object.pose_markers.active_index = searchPoseMarker(context, posename=self.posename, type="index") - active_index = action_object.pose_markers.active_index + pose_library.pose_markers.active_index = searchPoseMarker(context, posename=self.posename, type="index") + active_index = pose_library.pose_markers.active_index else: active_index = pose_markers.active_index active_marker = pose_markers.active active_frame = active_marker.frame - fcurves = action_object.fcurves + fcurves = pose_library.fcurves for fcu in fcurves: for kf in fcu.keyframe_points.values(): if kf.co.x == active_frame: @@ -156,8 +152,8 @@ class DSPL_OT_RemovePose(bpy.types.Operator): pose_markers.remove(marker=active_marker) - action_object.pose_markers.active = next_marker - action_object.pose_markers.active_index = next_index + pose_library.pose_markers.active = next_marker + pose_library.pose_markers.active_index = next_index self.report({'INFO'}, "DSPL: Removed " + self.posename) @@ -177,10 +173,8 @@ class DSPL_OT_RenamePose(bpy.types.Operator): pose_new_name: bpy.props.StringProperty() def execute(self, context): - - arm_object = getArmatureObject(context) - action_object = getPoseLib(context) - pose_markers = action_object.pose_markers + arm_object, pose_library = getArmatureData(context) + pose_markers = pose_library.pose_markers active_marker = pose_markers.active if self.posename: @@ -217,10 +211,8 @@ class DSPL_OT_MovePose(bpy.types.Operator): posename: bpy.props.StringProperty(name="Pose Name", default="", options={'SKIP_SAVE'}) def execute(self, context): - arm_object = getArmatureObject(context) - action_object = getPoseLib(context) - pose_lib = getPoseLib(context) - pose_markers = action_object.pose_markers + arm_object, pose_library = getArmatureData(context) + pose_markers = pose_library.pose_markers if self.posename: active_index = searchPoseMarker(context, posename=self.posename, type="index") @@ -228,7 +220,6 @@ class DSPL_OT_MovePose(bpy.types.Operator): active_frame = active_marker.frame active_posename = active_marker.name else: - arm_object = getArmatureObject(context) active_marker = pose_markers.active active_index = pose_markers.active_index @@ -240,21 +231,19 @@ class DSPL_OT_MovePose(bpy.types.Operator): swap_index = active_index + move_dir if swap_index < 0: - # swap_index = len(pose_lib.pose_markers) - 1 return {'FINISHED'} - elif swap_index >= len(pose_lib.pose_markers): - # swap_index = 0 + elif swap_index >= len(pose_library.pose_markers): return {'FINISHED'} swap_marker = pose_markers[swap_index] tmp_marker_name = swap_marker.name tmp_marker_frame = swap_marker.frame - action_object.pose_markers[swap_index].name = active_marker.name - action_object.pose_markers[swap_index].frame = active_marker.frame - action_object.pose_markers[active_index].name = tmp_marker_name - action_object.pose_markers[active_index].frame = tmp_marker_frame - action_object.pose_markers.active_index = swap_index + pose_library.pose_markers[swap_index].name = active_marker.name + pose_library.pose_markers[swap_index].frame = active_marker.frame + pose_library.pose_markers[active_index].name = tmp_marker_name + pose_library.pose_markers[active_index].frame = tmp_marker_frame + pose_library.pose_markers.active_index = swap_index return {'FINISHED'} @@ -272,15 +261,15 @@ class DSPL_OT_ApplyPose(bpy.types.Operator): def execute(self, context): - arm_object = getArmatureObject(context) - action_object = getPoseLib(context) - pose_markers = action_object.pose_markers + arm_object, pose_library = getArmatureData(context) + + pose_markers = pose_library.pose_markers if self.posename: active_marker = searchPoseMarker(context, posename=self.posename, type="marker") active_frame = active_marker.frame active_posename = active_marker.name - action_object.pose_markers.active_index = searchPoseMarker(context, posename=self.posename, type="index") + pose_library.pose_markers.active_index = searchPoseMarker(context, posename=self.posename, type="index") else: active_index = pose_markers.active_index active_marker = pose_markers.active @@ -296,8 +285,8 @@ class DSPL_OT_ApplyPose(bpy.types.Operator): def invoke(self, context, event): if event.ctrl: # Select - action_object = getPoseLib(context) - action_object.pose_markers.active_index = searchPoseMarker(context, posename=self.posename, type="index") + arm_object, pose_library = getArmatureData(context) + pose_library.pose_markers.active_index = searchPoseMarker(context, posename=self.posename, type="index") return {'FINISHED'} elif event.alt: # Remove @@ -327,7 +316,7 @@ class DSPL_OT_BrowsePoses(bpy.types.Operator): font_dpi = 72 blf.position(font_id, 15, 30, 0) - mod_var = self.pose_lib.pose_markers.active.name + mod_var = self.pose_library.pose_markers.active.name blf.color(font_id, 1.0, 1.0, 1.0, 1.0) blf.size(font_id, font_size) blf.draw(font_id, "Previewing pose: " + mod_var) @@ -338,16 +327,16 @@ class DSPL_OT_BrowsePoses(bpy.types.Operator): if event.value == 'PRESS': if event.type in {'LEFT_ARROW', 'UP_ARROW'}: - if self.pose_lib.pose_markers.active_index <= 0: - self.pose_lib.pose_markers.active_index = len(self.pose_lib.pose_markers) - 1 + if self.pose_library.pose_markers.active_index <= 0: + self.pose_library.pose_markers.active_index = len(self.pose_library.pose_markers) - 1 else: - self.pose_lib.pose_markers.active_index = self.pose_lib.pose_markers.active_index - 1 + self.pose_library.pose_markers.active_index = self.pose_library.pose_markers.active_index - 1 bpy.ops.dspl.apply_pose() elif event.type in {'RIGHT_ARROW', 'DOWN_ARROW'}: - if self.pose_lib.pose_markers.active_index + 1 >= len(self.pose_lib.pose_markers): - self.pose_lib.pose_markers.active_index = 0 + if self.pose_library.pose_markers.active_index + 1 >= len(self.pose_library.pose_markers): + self.pose_library.pose_markers.active_index = 0 else: - self.pose_lib.pose_markers.active_index = self.pose_lib.pose_markers.active_index + 1 + self.pose_library.pose_markers.active_index = self.pose_library.pose_markers.active_index + 1 bpy.ops.dspl.apply_pose() if event.type in {'LEFTMOUSE', 'RET', 'NUMPAD_ENTER'}: @@ -356,7 +345,7 @@ class DSPL_OT_BrowsePoses(bpy.types.Operator): elif event.type in {'RIGHTMOUSE', 'ESC'}: self.arm_object.pose.backup_restore() - self.pose_lib.pose_markers.active_index = self.backup_index + self.pose_library.pose_markers.active_index = self.backup_index bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') return {'CANCELLED'} @@ -366,15 +355,14 @@ class DSPL_OT_BrowsePoses(bpy.types.Operator): def invoke(self, context, event): bpy.context.area.tag_redraw() - self.arm_object = getArmatureObject(context) - self.pose_lib = getPoseLib(context) - - if self.pose_lib is None: + self.arm_object, self.pose_library = getArmatureData(context) + + if self.pose_library is None: self.report({'WARNING'}, "DSPL: Pose Library not active") return {'CANCELLED'} - self.arm_object.pose.backup_create(self.pose_lib) - self.backup_index = self.pose_lib.pose_markers.active_index + self.arm_object.pose.backup_create(self.pose_library) + self.backup_index = self.pose_library.pose_markers.active_index bpy.ops.dspl.apply_pose() if context.area.type == 'VIEW_3D': @@ -396,16 +384,15 @@ class DSPL_OT_UnlinkPoseLibrary(bpy.types.Operator): bl_options = {'REGISTER', 'UNDO'} def execute(self, context): - arm_object = getArmatureObject(context) - pose_library = getPoseLib(context) + arm_object, pose_library = getArmatureData(context) try: - arm_object.pose_library.use_fake_user = False + arm_object.pose_library = None + # arm_object.pose_library.use_fake_user = False # if not arm_object.pose_library.name.startswith("del_"): # arm_object.pose_library.name = "del_{}".format(arm_object.pose_library.name) except: pass - arm_object.pose_library = None return {'FINISHED'}