Refactor: convert "Bake Action" operator to current Action API

Remove the use of `action.fcurves` in the Bake Action operator, replacing
it with the current API (introduced for slotted Actions in Blender 4.4).

No functional changes.

This is part of #146586

Pull Request: https://projects.blender.org/blender/blender/pulls/147060
This commit is contained in:
Sybren A. Stüvel
2025-09-23 16:29:11 +02:00
parent c77ac91ee4
commit 5c2069e284

View File

@@ -390,13 +390,6 @@ def bake_action_iter(
if bake_options.do_object:
obj_info.append((frame, *obj_frame_info(obj)))
# -------------------------------------------------------------------------
# Clean (store initial data)
if bake_options.do_clean and action is not None:
clean_orig_data = {fcu: {p.co[1] for p in fcu.keyframe_points} for fcu in action.fcurves}
else:
clean_orig_data = {}
# -------------------------------------------------------------------------
# Create action
@@ -423,16 +416,24 @@ def bake_action_iter(
if not atd.use_tweak_mode:
atd.action_blend_type = 'REPLACE'
# If any data is going to be baked, there will be a channelbag created, so
# might just as well create it now and have a clear, unambiguous reference
# to it. If it is created here, it will have no F-Curves, and so certain
# loops below will just be no-ops.
channelbag: ActionChannelbag = action_ensure_channelbag_for_slot(atd.action, atd.action_slot)
# -------------------------------------------------------------------------
# Clean (store initial data)
if bake_options.do_clean:
clean_orig_data = {fcu: {p.co[1] for p in fcu.keyframe_points} for fcu in channelbag.fcurves}
else:
clean_orig_data = {}
# -------------------------------------------------------------------------
# Apply transformations to action
# pose
lookup_fcurves = {}
assert action.is_action_layered
channelbag = action_get_channelbag_for_slot(action, atd.action_slot)
if channelbag:
# channelbag can be None if no layers or strips exist in the action.
lookup_fcurves = {(fcurve.data_path, fcurve.array_index): fcurve for fcurve in channelbag.fcurves}
lookup_fcurves = {(fcurve.data_path, fcurve.array_index): fcurve for fcurve in channelbag.fcurves}
if bake_options.do_pose:
for f, armature_custom_properties in armature_info:
@@ -524,10 +525,10 @@ def bake_action_iter(
bake_custom_properties(pbone, custom_props=custom_props[name], frame=f, group_name=name)
if is_new_action:
keyframes.insert_keyframes_into_new_action(total_new_keys, action, name)
keyframes.insert_keyframes_into_new_action(total_new_keys, channelbag, name)
else:
keyframes.insert_keyframes_into_existing_action(
lookup_fcurves, total_new_keys, action, atd.action_slot)
lookup_fcurves, total_new_keys, channelbag)
# object. TODO. multiple objects
if bake_options.do_object:
@@ -591,10 +592,9 @@ def bake_action_iter(
bake_custom_properties(obj, custom_props=custom_props, frame=f, group_name=name)
if is_new_action:
keyframes.insert_keyframes_into_new_action(total_new_keys, action, name)
keyframes.insert_keyframes_into_new_action(total_new_keys, channelbag, name)
else:
keyframes.insert_keyframes_into_existing_action(
lookup_fcurves, total_new_keys, action, atd.action_slot)
keyframes.insert_keyframes_into_existing_action(lookup_fcurves, total_new_keys, channelbag)
if bake_options.do_parents_clear:
obj.parent = None
@@ -603,7 +603,7 @@ def bake_action_iter(
# Clean
if bake_options.do_clean:
for fcu in action.fcurves:
for fcu in channelbag.fcurves:
fcu_orig_data = clean_orig_data.get(fcu, set())
keyframe_points = fcu.keyframe_points
@@ -675,15 +675,14 @@ class KeyframesCo:
def insert_keyframes_into_new_action(
self,
total_new_keys: int,
action: Action,
action_group_name: str,
channelbag: ActionChannelbag,
group_name: str,
) -> None:
"""
Assumes the action is new, that it has no F-curves. Otherwise, the only difference between versions is
performance and implementation simplicity.
:arg action_group_name: Name of Action Group that F-curves are added to.
:type action_group_name: str
:arg group_name: Name of the Group that F-curves are added to.
"""
linear_enum_values = [
bpy.types.Keyframe.bl_rna.properties["interpolation"].enum_items["LINEAR"].value
@@ -694,8 +693,8 @@ class KeyframesCo:
continue
data_path, array_index = fc_key
keyframe_points = action.fcurves.new(
data_path, index=array_index, action_group=action_group_name
keyframe_points = channelbag.fcurves.new(
data_path, index=array_index, group_name=group_name
).keyframe_points
keyframe_points.add(total_new_keys)
@@ -709,18 +708,14 @@ class KeyframesCo:
self,
lookup_fcurves: Mapping[FCurveKey, bpy.types.FCurve],
total_new_keys: int,
action: Action,
action_slot: ActionSlot,
channelbag: ActionChannelbag,
) -> None:
"""
Assumes the action already exists, that it might already have F-curves. Otherwise, the
only difference between versions is performance and implementation simplicity.
:arg lookup_fcurves: : This is only used for efficiency.
It's a substitute for ``action.fcurves.find()`` which is a potentially expensive linear search.
:type lookup_fcurves: ``Mapping[FCurveKey, bpy.types.FCurve]``
:arg action_group_name: Name of Action Group that F-curves are added to.
:type action_group_name: str
It's a substitute for ``channelbag.fcurves.find()`` which is a potentially expensive linear search.
"""
linear_enum_values = [
bpy.types.Keyframe.bl_rna.properties["interpolation"].enum_items["LINEAR"].value
@@ -733,8 +728,6 @@ class KeyframesCo:
fcurve = lookup_fcurves.get(fc_key, None)
if fcurve is None:
data_path, array_index = fc_key
assert action.is_action_layered
channelbag = action_ensure_channelbag_for_slot(action, action_slot)
fcurve = channelbag.fcurves.new(data_path, index=array_index)
keyframe_points = fcurve.keyframe_points