Anim: Remove legacy pose library conversion

Remove the operators to convert a legacy pose library (from Blender 2.93
and older) to the current system (introduced in Blender 3.0).

The removal is mostly because the pose markers do not play well with
slotted Actions. The conversion code was never updated for those, and by
now it's easier to remove them than to update the code to the current
data model.

Technically it was still possible to create a legacy pose library (an
Action with pose markers) in current versions of Blender, and then use
this operator to convert that to a modern pose library. I don't know of
anybody doing that, though.

This is part of #146586

Pull Request: https://projects.blender.org/blender/blender/pulls/147061
This commit is contained in:
Sybren A. Stüvel
2025-09-30 16:13:04 +02:00
parent 2468b3c7dd
commit 44913ffb60
5 changed files with 2 additions and 135 deletions

View File

@@ -23,7 +23,7 @@ bl_info = {
from typing import List, Tuple
_need_reload = "operators" in locals()
from . import gui, keymaps, operators, conversion
from . import gui, keymaps, operators
if _need_reload:
import importlib
@@ -31,7 +31,6 @@ if _need_reload:
gui = importlib.reload(gui)
keymaps = importlib.reload(keymaps)
operators = importlib.reload(operators)
conversion = importlib.reload(conversion)
import bpy

View File

@@ -1,62 +0,0 @@
# SPDX-FileCopyrightText: 2021-2023 Blender Foundation
#
# SPDX-License-Identifier: GPL-2.0-or-later
"""
Pose Library - Conversion of old pose libraries.
"""
from typing import Optional
from collections.abc import Collection
if "pose_creation" not in locals():
from . import pose_creation
else:
import importlib
pose_creation = importlib.reload(pose_creation)
import bpy
from bpy.types import (
Action,
TimelineMarker,
)
def convert_old_poselib(old_poselib: Action) -> Collection[Action]:
"""Convert an old-style pose library to a set of pose Actions.
Old pose libraries were one Action with multiple pose markers. Each pose
marker will be converted to an Action by itself and marked as asset.
"""
pose_assets = [action for marker in old_poselib.pose_markers if (action := convert_old_pose(old_poselib, marker))]
# Mark all Actions as assets in one go. Ideally this would be done on an
# appropriate frame in the scene (to set up things like the background
# colour), but the old-style poselib doesn't contain such information. All
# we can do is just render on the current frame.
context_override = {'selected_ids': pose_assets}
with bpy.context.temp_override(**context_override):
bpy.ops.asset.mark()
return pose_assets
def convert_old_pose(old_poselib: Action, marker: TimelineMarker) -> Optional[Action]:
"""Convert an old-style pose library pose to a pose action."""
frame: int = marker.frame
action: Optional[Action] = None
for fcurve in old_poselib.fcurves:
key = pose_creation.find_keyframe(fcurve, frame)
if not key:
continue
if action is None:
action = bpy.data.actions.new(marker.name)
pose_creation.create_single_key_fcurve(action, fcurve, key)
return action

View File

@@ -28,6 +28,7 @@ class VIEW3D_MT_pose_modify(Menu):
layout.operator("poselib.asset_modify", text="Add Selected Bones").mode = "ADD"
layout.operator("poselib.asset_modify", text="Remove Selected Bones").mode = "REMOVE"
class PoseLibraryPanel:
@classmethod
def pose_library_panel_poll(cls, context: Context) -> bool:
@@ -132,8 +133,6 @@ class DOPESHEET_PT_asset_panel(PoseLibraryPanel, Panel):
row.operator("poselib.restore_previous_action", text="", icon='LOOP_BACK')
col.operator("poselib.copy_as_asset", icon="COPYDOWN")
layout.operator("poselib.convert_old_poselib")
def pose_library_list_item_asset_menu(self: UIList, context: Context) -> None:
layout = self.layout

View File

@@ -288,75 +288,8 @@ class POSELIB_OT_pose_asset_select_bones(PoseAssetUser, Operator):
return tip_("Deselect those bones that are used in this pose")
class POSELIB_OT_convert_old_poselib(Operator):
bl_idname = "poselib.convert_old_poselib"
bl_label = "Convert Legacy Pose Library"
bl_description = "Create a pose asset for each pose marker in the current action"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context: Context) -> bool:
action = context.object and context.object.animation_data and context.object.animation_data.action
if not action:
cls.poll_message_set("Active object has no Action")
return False
if not action.pose_markers:
cls.poll_message_set(tip_("Action %r is not a legacy pose library") % action.name)
return False
return True
def execute(self, context: Context) -> Set[str]:
from . import conversion
old_poselib = context.object.animation_data.action
new_actions = conversion.convert_old_poselib(old_poselib)
if not new_actions:
self.report({'ERROR'}, "Unable to convert to pose assets")
return {'CANCELLED'}
self.report({'INFO'}, tip_("Converted %d poses to pose assets") % len(new_actions))
return {'FINISHED'}
class POSELIB_OT_convert_old_object_poselib(Operator):
bl_idname = "poselib.convert_old_object_poselib"
bl_label = "Convert Legacy Pose Library"
bl_description = "Create a pose asset for each pose marker in this legacy pose library data-block"
# Mark this one as "internal", as it converts `context.object.pose_library`
# instead of its current animation Action.
bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
@classmethod
def poll(cls, context: Context) -> bool:
action = context.object and context.object.pose_library
if not action:
cls.poll_message_set("Active object has no pose library Action")
return False
if not action.pose_markers:
cls.poll_message_set(tip_("Action %r is not a legacy pose library") % action.name)
return False
return True
def execute(self, context: Context) -> Set[str]:
from . import conversion
old_poselib = context.object.pose_library
new_actions = conversion.convert_old_poselib(old_poselib)
if not new_actions:
self.report({'ERROR'}, "Unable to convert to pose assets")
return {'CANCELLED'}
self.report({'INFO'}, tip_("Converted %d poses to pose assets") % len(new_actions))
return {'FINISHED'}
classes = (
ASSET_OT_assign_action,
POSELIB_OT_convert_old_poselib,
POSELIB_OT_convert_old_object_poselib,
POSELIB_OT_copy_as_asset,
POSELIB_OT_paste_asset,
POSELIB_OT_pose_asset_select_bones,

View File

@@ -91,8 +91,6 @@ class PoseActionCreator:
def _create_new_action(self) -> Action:
dst_action = bpy.data.actions.new(self.params.new_asset_name)
if self.params.src_action:
dst_action.id_root = self.params.src_action.id_root
dst_action.user_clear() # actions.new() sets users=1, but marking as asset also increments user count.
return dst_action