From bbebd0f4cbd520e5ee3302a2ded33062afe22770 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Tue, 10 Oct 2023 13:44:07 +0200 Subject: [PATCH 01/41] add userpref enum --- release/datafiles/userdef/userdef_default.c | 1 + scripts/startup/bl_ui/space_userpref.py | 2 ++ .../blenloader/intern/versioning_userdef.cc | 3 +++ source/blender/makesdna/DNA_userdef_types.h | 12 ++++++++++++ source/blender/makesrna/intern/rna_userdef.cc | 18 ++++++++++++++++++ 5 files changed, 36 insertions(+) diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c index 3d35b6b75c1..774f3ff5efa 100644 --- a/release/datafiles/userdef/userdef_default.c +++ b/release/datafiles/userdef/userdef_default.c @@ -165,6 +165,7 @@ const UserDef U_default = { .glalphaclip = 0.004, .autokey_mode = (AUTOKEY_MODE_NORMAL & ~AUTOKEY_ON), .autokey_flag = AUTOKEY_FLAG_XYZ2RGB, + .key_insert_channels = USER_ANIM_KEY_CHANNEL_TRANSLATE, .animation_flag = USER_ANIM_HIGH_QUALITY_DRAWING, .text_render = 0, .navigation_mode = VIEW_NAVIGATION_WALK, diff --git a/scripts/startup/bl_ui/space_userpref.py b/scripts/startup/bl_ui/space_userpref.py index c8d68bf9779..96786018faa 100644 --- a/scripts/startup/bl_ui/space_userpref.py +++ b/scripts/startup/bl_ui/space_userpref.py @@ -576,6 +576,8 @@ class USERPREF_PT_animation_keyframes(AnimationPanel, CenterAlignMixIn, Panel): prefs = context.preferences edit = prefs.edit + layout.prop(edit, "key_insert_channels", expand=True) + col = layout.column() col.prop(edit, "use_visual_keying") col.prop(edit, "use_keyframe_insert_needed", text="Only Insert Needed") diff --git a/source/blender/blenloader/intern/versioning_userdef.cc b/source/blender/blenloader/intern/versioning_userdef.cc index 7e785184212..c7101f25eef 100644 --- a/source/blender/blenloader/intern/versioning_userdef.cc +++ b/source/blender/blenloader/intern/versioning_userdef.cc @@ -896,6 +896,9 @@ void blo_do_versions_userdef(UserDef *userdef) */ { /* Keep this block, even when empty. */ + userdef->key_insert_channels = (USER_ANIM_KEY_CHANNEL_TRANSLATE | + USER_ANIM_KEY_CHANNEL_ROTATE | USER_ANIM_KEY_CHANNEL_SCALE | + USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES); } LISTBASE_FOREACH (bTheme *, btheme, &userdef->themes) { diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 416e6168132..dc1ce32238d 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -955,6 +955,9 @@ typedef struct UserDef { short autokey_mode; /** Flags for autokeying. */ short autokey_flag; + /** Flags for which channels to insert keys at. */ + short key_insert_channels; + char _pad15[6]; /** Flags for animation. */ short animation_flag; @@ -1296,6 +1299,15 @@ typedef enum eAutokey_Flag { ANIMRECORD_FLAG_WITHNLA = (1 << 10), } eAutokey_Flag; +typedef enum eKeyInsertChannels { + USER_ANIM_KEY_CHANNEL_TRANSLATE = (1 << 0), + USER_ANIM_KEY_CHANNEL_ROTATE = (1 << 1), + USER_ANIM_KEY_CHANNEL_SCALE = (1 << 2), + USER_ANIM_KEY_CHANNEL_ROTATION_MODE = (1 << 3), + USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES = (1 << 4), + USER_ANIM_KEY_CHANNEL_BBONE_SHAPE = (1 << 5), +} eKeyInsertChannels; + /** * Animation flags * #UserDef.animation_flag, used for animation flags that aren't covered by more specific flags diff --git a/source/blender/makesrna/intern/rna_userdef.cc b/source/blender/makesrna/intern/rna_userdef.cc index 3202f8e09e1..5d143f07c04 100644 --- a/source/blender/makesrna/intern/rna_userdef.cc +++ b/source/blender/makesrna/intern/rna_userdef.cc @@ -149,6 +149,16 @@ static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = { {0, nullptr, 0, nullptr, nullptr}, }; +static const EnumPropertyItem rna_enum_key_insert_channels[] = { + {USER_ANIM_KEY_CHANNEL_TRANSLATE, "TRANSLATE", 0, "Translate", ""}, + {USER_ANIM_KEY_CHANNEL_ROTATE, "ROTATE", 0, "Rotate", ""}, + {USER_ANIM_KEY_CHANNEL_SCALE, "SCALE", 0, "Scale", ""}, + {USER_ANIM_KEY_CHANNEL_ROTATION_MODE, "ROTATE_MODE", 0, "Rotation Mode", ""}, + {USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES, "CUSTOM_PROPS", 0, "Custom Properties", ""}, + {USER_ANIM_KEY_CHANNEL_BBONE_SHAPE, "BBONE_SHAPE", 0, "BBone Shape", ""}, + {0, nullptr, 0, nullptr, nullptr}, +}; + static const EnumPropertyItem rna_enum_preference_gpu_backend_items[] = { {GPU_BACKEND_OPENGL, "OPENGL", 0, "OpenGL", "Use OpenGL backend"}, {GPU_BACKEND_METAL, "METAL", 0, "Metal", "Use Metal backend"}, @@ -5405,6 +5415,14 @@ static void rna_def_userdef_edit(BlenderRNA *brna) "Show warning indicators when transforming objects and bones if auto keying is enabled"); /* keyframing settings */ + prop = RNA_def_property(srna, "key_insert_channels", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, nullptr, "key_insert_channels"); + RNA_def_property_enum_items(prop, rna_enum_key_insert_channels); + RNA_def_property_flag(prop, PROP_ENUM_FLAG); + RNA_def_property_ui_text(prop, + "Default Key Channels", + "Which channels to insert keys at when no keying set is active"); + prop = RNA_def_property(srna, "use_keyframe_insert_needed", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, nullptr, "autokey_flag", AUTOKEY_FLAG_INSERTNEEDED); RNA_def_property_ui_text( -- 2.30.2 From 8ca7671352573661353975d99cb150fd1b06c8e7 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Tue, 10 Oct 2023 14:12:39 +0200 Subject: [PATCH 02/41] constness --- source/blender/editors/animation/keyframing.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index f362e03162e..ab9103d35ce 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -1979,7 +1979,6 @@ static int insert_key_exec(bContext *C, wmOperator *op) bool ob_edit_mode = false; const float cfra = BKE_scene_frame_get(scene); - int num_channels; const bool confirm = op->flag & OP_IS_INVOKE; KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene); @@ -1996,7 +1995,9 @@ static int insert_key_exec(bContext *C, wmOperator *op) } /* try to insert keyframes for the channels specified by KeyingSet */ - num_channels = ANIM_apply_keyingset(C, nullptr, nullptr, ks, MODIFYKEY_MODE_INSERT, cfra); + const int num_channels = ANIM_apply_keyingset( + C, nullptr, nullptr, ks, MODIFYKEY_MODE_INSERT, cfra); + if (G.debug & G_DEBUG) { BKE_reportf(op->reports, RPT_INFO, -- 2.30.2 From 53722d3b6da864799f6fc6ad2aa26920d64acd9b Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Tue, 10 Oct 2023 14:50:04 +0200 Subject: [PATCH 03/41] remove builtin keyingsets --- scripts/modules/keyingsets_utils.py | 283 ---------- scripts/startup/keyingsets_builtins.py | 686 ------------------------- 2 files changed, 969 deletions(-) delete mode 100644 scripts/modules/keyingsets_utils.py delete mode 100644 scripts/startup/keyingsets_builtins.py diff --git a/scripts/modules/keyingsets_utils.py b/scripts/modules/keyingsets_utils.py deleted file mode 100644 index e13d61fb133..00000000000 --- a/scripts/modules/keyingsets_utils.py +++ /dev/null @@ -1,283 +0,0 @@ -# SPDX-FileCopyrightText: 2010-2023 Blender Authors -# -# SPDX-License-Identifier: GPL-2.0-or-later - -# This file defines a set of methods that are useful for various -# Relative Keying Set (RKS) related operations, such as: callbacks -# for polling, iterator callbacks, and also generate callbacks. -# All of these can be used in conjunction with the others. - -__all__ = ( - "path_add_property", - "RKS_POLL_selected_objects", - "RKS_POLL_selected_bones", - "RKS_POLL_selected_items", - "RKS_ITER_selected_objects", - "RKS_ITER_selected_bones", - "RKS_ITER_selected_item", - "RKS_GEN_available", - "RKS_GEN_location", - "RKS_GEN_rotation", - "RKS_GEN_scaling", - "RKS_GEN_bendy_bones", -) - -import bpy - -########################### -# General Utilities - - -# Append the specified property name on the the existing path -def path_add_property(path, prop): - if path: - return path + "." + prop - else: - return prop - -########################### -# Poll Callbacks - - -# selected objects (active object must be in object mode) -def RKS_POLL_selected_objects(_ksi, context): - ob = context.active_object - if ob: - return ob.mode == 'OBJECT' - else: - return bool(context.selected_objects) - - -# selected bones -def RKS_POLL_selected_bones(_ksi, context): - # we must be in Pose Mode, and there must be some bones selected - ob = context.active_object - if ob and ob.mode == 'POSE': - if context.active_pose_bone or context.selected_pose_bones: - return True - - # nothing selected - return False - - -# selected bones or objects -def RKS_POLL_selected_items(ksi, context): - return (RKS_POLL_selected_bones(ksi, context) or - RKS_POLL_selected_objects(ksi, context)) - -########################### -# Iterator Callbacks - - -# All selected objects or pose bones, depending on which we've got. -def RKS_ITER_selected_item(ksi, context, ks): - ob = context.active_object - if ob and ob.mode == 'POSE': - for bone in context.selected_pose_bones: - ksi.generate(context, ks, bone) - else: - for ob in context.selected_objects: - ksi.generate(context, ks, ob) - - -# All selected objects only. -def RKS_ITER_selected_objects(ksi, context, ks): - for ob in context.selected_objects: - ksi.generate(context, ks, ob) - - -# All selected bones only. -def RKS_ITER_selected_bones(ksi, context, ks): - for bone in context.selected_pose_bones: - ksi.generate(context, ks, bone) - -########################### -# Generate Callbacks - - -# "Available" F-Curves. -def RKS_GEN_available(_ksi, _context, ks, data): - # try to get the animation data associated with the closest - # ID-block to the data (neither of which may exist/be easy to find) - id_block = data.id_data - adt = getattr(id_block, "animation_data", None) - - # there must also be an active action... - if adt is None or adt.action is None: - return - - # if we haven't got an ID-block as 'data', try to restrict - # paths added to only those which branch off from here - # i.e. for bones - if id_block != data: - basePath = data.path_from_id() - else: - basePath = None # this is not needed... - - # for each F-Curve, include a path to key it - # NOTE: we don't need to set the group settings here - for fcu in adt.action.fcurves: - if basePath: - if basePath in fcu.data_path: - ks.paths.add(id_block, fcu.data_path, index=fcu.array_index) - else: - ks.paths.add(id_block, fcu.data_path, index=fcu.array_index) - -# ------ - - -# get ID block and based ID path for transform generators -# private function -def get_transform_generators_base_info(data): - # ID-block for the data - id_block = data.id_data - - # get base path and grouping method/name - if isinstance(data, bpy.types.ID): - # no path in this case - path = "" - - # transform data on ID-blocks directly should get grouped under a - # hardcoded label ("Object Transforms") so that they get grouped - # consistently when keyframed directly - grouping = "Object Transforms" - else: - # get the path to the ID-block - path = data.path_from_id() - - # try to use the name of the data element to group the F-Curve - # else fallback on the KeyingSet name - grouping = getattr(data, "name", None) - - # return the ID-block and the path - return id_block, path, grouping - - -# Location -def RKS_GEN_location(_ksi, _context, ks, data): - # get id-block and path info - id_block, base_path, grouping = get_transform_generators_base_info(data) - - # add the property name to the base path - path = path_add_property(base_path, "location") - - # add Keying Set entry for this... - if grouping: - ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping) - else: - ks.paths.add(id_block, path) - - -# Rotation -def RKS_GEN_rotation(_ksi, _context, ks, data): - # get id-block and path info - id_block, base_path, grouping = get_transform_generators_base_info(data) - - # add the property name to the base path - # rotation mode affects the property used - if data.rotation_mode == 'QUATERNION': - path = path_add_property(base_path, "rotation_quaternion") - elif data.rotation_mode == 'AXIS_ANGLE': - path = path_add_property(base_path, "rotation_axis_angle") - else: - path = path_add_property(base_path, "rotation_euler") - - # add Keying Set entry for this... - if grouping: - ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping) - else: - ks.paths.add(id_block, path) - - -# Scaling -def RKS_GEN_scaling(_ksi, _context, ks, data): - # get id-block and path info - id_block, base_path, grouping = get_transform_generators_base_info(data) - - # add the property name to the base path - path = path_add_property(base_path, "scale") - - # add Keying Set entry for this... - if grouping: - ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping) - else: - ks.paths.add(id_block, path) - - -# Custom Properties -def RKS_GEN_custom_props(_ksi, _context, ks, data): - # get id-block and path info - id_block, base_path, grouping = get_transform_generators_base_info(data) - - # Only some RNA types can be animated. - prop_type_compat = {bpy.types.BoolProperty, - bpy.types.IntProperty, - bpy.types.FloatProperty} - - # When working with a pose, 'id_block' is the armature object (which should - # get the animation data), whereas 'data' is the bone being keyed. - for cprop_name in data.keys(): - # ignore special "_RNA_UI" used for UI editing - if cprop_name == "_RNA_UI": - continue - - prop_path = '["%s"]' % bpy.utils.escape_identifier(cprop_name) - - try: - rna_property = data.path_resolve(prop_path, False) - except ValueError: - # Can technically happen, but there is no known case. - continue - if rna_property is None: - # In this case the property cannot be converted to an - # FCurve-compatible value, so we can't keyframe it anyways. - continue - if rna_property.rna_type not in prop_type_compat: - continue - - path = "%s%s" % (base_path, prop_path) - if grouping: - ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping) - else: - ks.paths.add(id_block, path) - -# ------ - - -# Property identifiers for Bendy Bones -bbone_property_ids = ( - "bbone_curveinx", - "bbone_curveiny", - "bbone_curveoutx", - "bbone_curveouty", - - "bbone_rollin", - "bbone_rollout", - - "bbone_scalein", - "bbone_scaleout", - - # NOTE: These are in the nested bone struct - # Do it this way to force them to be included - # in whatever actions are being keyed here - "bone.bbone_in", - "bone.bbone_out", -) - - -# Add Keying Set entries for bendy bones -def RKS_GEN_bendy_bones(_ksi, _context, ks, data): - # get id-block and path info - # NOTE: This assumes that we're dealing with a bone here... - id_block, base_path, grouping = get_transform_generators_base_info(data) - - # for each of the bendy bone properties, add a Keying Set entry for it... - for propname in bbone_property_ids: - # add the property name to the base path - path = path_add_property(base_path, propname) - - # add Keying Set entry for this... - if grouping: - ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping) - else: - ks.paths.add(id_block, path) diff --git a/scripts/startup/keyingsets_builtins.py b/scripts/startup/keyingsets_builtins.py deleted file mode 100644 index 79e4eda1aed..00000000000 --- a/scripts/startup/keyingsets_builtins.py +++ /dev/null @@ -1,686 +0,0 @@ -# SPDX-FileCopyrightText: 2010-2023 Blender Authors -# -# SPDX-License-Identifier: GPL-2.0-or-later - -""" -Built-In Keying Sets -None of these Keying Sets should be removed, as these are needed by various parts of Blender in order for them -to work correctly. - -Beware also about changing the order that these are defined here, since this can result in old files referring to the -wrong Keying Set as the active one, potentially resulting in lost (i.e. unkeyed) animation. - -Note that these classes cannot be subclassed further; only direct subclasses of KeyingSetInfo -are supported. -""" - -import bpy -import keyingsets_utils -from bpy.types import KeyingSetInfo - -############################### -# Built-In KeyingSets - - -# "Defines" -# Keep these in sync with those in ED_keyframing.hh! -ANIM_KS_LOCATION_ID = "Location" -ANIM_KS_ROTATION_ID = "Rotation" -ANIM_KS_SCALING_ID = "Scaling" -ANIM_KS_LOC_ROT_SCALE_ID = "LocRotScale" -ANIM_KS_LOC_ROT_SCALE_CPROP_ID = "LocRotScaleCProp" -ANIM_KS_AVAILABLE_ID = "Available" -ANIM_KS_WHOLE_CHARACTER_ID = "WholeCharacter" -ANIM_KS_WHOLE_CHARACTER_SELECTED_ID = "WholeCharacterSelected" - - -# Location -class BUILTIN_KSI_Location(KeyingSetInfo): - """Insert a keyframe on each of the location channels""" - bl_idname = ANIM_KS_LOCATION_ID - bl_label = "Location" - - # poll - use predefined callback for selected bones/objects - poll = keyingsets_utils.RKS_POLL_selected_items - - # iterator - use callback for selected bones/objects - iterator = keyingsets_utils.RKS_ITER_selected_item - - # generator - use callback for location - generate = keyingsets_utils.RKS_GEN_location - - -# Rotation -class BUILTIN_KSI_Rotation(KeyingSetInfo): - """Insert a keyframe on each of the rotation channels""" - bl_idname = ANIM_KS_ROTATION_ID - bl_label = "Rotation" - - # poll - use predefined callback for selected bones/objects - poll = keyingsets_utils.RKS_POLL_selected_items - - # iterator - use callback for selected bones/objects - iterator = keyingsets_utils.RKS_ITER_selected_item - - # generator - use callback for rotation - generate = keyingsets_utils.RKS_GEN_rotation - - -# Scale -class BUILTIN_KSI_Scaling(KeyingSetInfo): - """Insert a keyframe on each of the scale channels""" - bl_idname = ANIM_KS_SCALING_ID - bl_label = "Scale" - - # poll - use predefined callback for selected bones/objects - poll = keyingsets_utils.RKS_POLL_selected_items - - # iterator - use callback for selected bones/objects - iterator = keyingsets_utils.RKS_ITER_selected_item - - # generator - use callback for scaling - generate = keyingsets_utils.RKS_GEN_scaling - -# ------------ - - -# LocRot -class BUILTIN_KSI_LocRot(KeyingSetInfo): - """Insert a keyframe on each of the location and rotation channels""" - bl_label = "Location & Rotation" - - # poll - use predefined callback for selected bones/objects - poll = keyingsets_utils.RKS_POLL_selected_items - - # iterator - use callback for selected bones/objects - iterator = keyingsets_utils.RKS_ITER_selected_item - - # generator - def generate(self, context, ks, data): - # location - keyingsets_utils.RKS_GEN_location(self, context, ks, data) - # rotation - keyingsets_utils.RKS_GEN_rotation(self, context, ks, data) - - -# LocScale -class BUILTIN_KSI_LocScale(KeyingSetInfo): - """Insert a keyframe on each of the location and scale channels""" - bl_label = "Location & Scale" - - # poll - use predefined callback for selected bones/objects - poll = keyingsets_utils.RKS_POLL_selected_items - - # iterator - use callback for selected bones/objects - iterator = keyingsets_utils.RKS_ITER_selected_item - - # generator - def generate(self, context, ks, data): - # location - keyingsets_utils.RKS_GEN_location(self, context, ks, data) - # scale - keyingsets_utils.RKS_GEN_scaling(self, context, ks, data) - - -# LocRotScale -class BUILTIN_KSI_LocRotScale(KeyingSetInfo): - """Insert a keyframe on each of the location, rotation, and scale channels""" - bl_idname = ANIM_KS_LOC_ROT_SCALE_ID - bl_label = "Location, Rotation & Scale" - - # poll - use predefined callback for selected bones/objects - poll = keyingsets_utils.RKS_POLL_selected_items - - # iterator - use callback for selected bones/objects - iterator = keyingsets_utils.RKS_ITER_selected_item - - # generator - def generate(self, context, ks, data): - # location - keyingsets_utils.RKS_GEN_location(self, context, ks, data) - # rotation - keyingsets_utils.RKS_GEN_rotation(self, context, ks, data) - # scale - keyingsets_utils.RKS_GEN_scaling(self, context, ks, data) - - -# LocRotScaleCProp -class BUILTIN_KSI_LocRotScaleCProp(KeyingSetInfo): - """Key location/rotation/scale as well as custom properties""" - bl_idname = ANIM_KS_LOC_ROT_SCALE_CPROP_ID - bl_label = "Location, Rotation, Scale & Custom Properties" - - poll = keyingsets_utils.RKS_POLL_selected_items - iterator = keyingsets_utils.RKS_ITER_selected_item - - def generate(self, context, ks, data): - keyingsets_utils.RKS_GEN_location(self, context, ks, data) - keyingsets_utils.RKS_GEN_rotation(self, context, ks, data) - keyingsets_utils.RKS_GEN_scaling(self, context, ks, data) - keyingsets_utils.RKS_GEN_custom_props(self, context, ks, data) - - -# RotScale -class BUILTIN_KSI_RotScale(KeyingSetInfo): - """Insert a keyframe on each of the rotation and scale channels""" - bl_label = "Rotation & Scale" - - # poll - use predefined callback for selected bones/objects - poll = keyingsets_utils.RKS_POLL_selected_items - - # iterator - use callback for selected bones/objects - iterator = keyingsets_utils.RKS_ITER_selected_item - - # generator - def generate(self, context, ks, data): - # rotation - keyingsets_utils.RKS_GEN_rotation(self, context, ks, data) - # scaling - keyingsets_utils.RKS_GEN_scaling(self, context, ks, data) - -# ------------ - - -# Bendy Bones -class BUILTIN_KSI_BendyBones(KeyingSetInfo): - """Insert a keyframe for each of the BBone shape properties""" - bl_label = "BBone Shape" - - # poll - use callback for selected bones - poll = keyingsets_utils.RKS_POLL_selected_bones - - # iterator - use callback for selected bones - iterator = keyingsets_utils.RKS_ITER_selected_bones - - # generator - use generator for bendy bone properties - generate = keyingsets_utils.RKS_GEN_bendy_bones - -# ------------ - - -# VisualLocation -class BUILTIN_KSI_VisualLoc(KeyingSetInfo): - """Insert a keyframe on each of the location channels, """ \ - """taking into account effects of constraints and relationships""" - bl_label = "Visual Location" - - bl_options = {'INSERTKEY_VISUAL'} - - # poll - use predefined callback for selected bones/objects - poll = keyingsets_utils.RKS_POLL_selected_items - - # iterator - use callback for selected bones/objects - iterator = keyingsets_utils.RKS_ITER_selected_item - - # generator - use callback for location - generate = keyingsets_utils.RKS_GEN_location - - -# VisualRotation -class BUILTIN_KSI_VisualRot(KeyingSetInfo): - """Insert a keyframe on each of the rotation channels, """ \ - """taking into account effects of constraints and relationships""" - bl_label = "Visual Rotation" - - bl_options = {'INSERTKEY_VISUAL'} - - # poll - use predefined callback for selected bones/objects - poll = keyingsets_utils.RKS_POLL_selected_items - - # iterator - use callback for selected bones/objects - iterator = keyingsets_utils.RKS_ITER_selected_item - - # generator - use callback for rotation - generate = keyingsets_utils.RKS_GEN_rotation - - -# VisualScaling -class BUILTIN_KSI_VisualScaling(KeyingSetInfo): - """Insert a keyframe on each of the scale channels, """ \ - """taking into account effects of constraints and relationships""" - bl_label = "Visual Scale" - - bl_options = {'INSERTKEY_VISUAL'} - - # poll - use predefined callback for selected bones/objects - poll = keyingsets_utils.RKS_POLL_selected_items - - # iterator - use callback for selected bones/objects - iterator = keyingsets_utils.RKS_ITER_selected_item - - # generator - use callback for location - generate = keyingsets_utils.RKS_GEN_scaling - - -# VisualLocRot -class BUILTIN_KSI_VisualLocRot(KeyingSetInfo): - """Insert a keyframe on each of the location and rotation channels, """ \ - """taking into account effects of constraints and relationships""" - bl_label = "Visual Location & Rotation" - - bl_options = {'INSERTKEY_VISUAL'} - - # poll - use predefined callback for selected bones/objects - poll = keyingsets_utils.RKS_POLL_selected_items - - # iterator - use callback for selected bones/objects - iterator = keyingsets_utils.RKS_ITER_selected_item - - # generator - def generate(self, context, ks, data): - # location - keyingsets_utils.RKS_GEN_location(self, context, ks, data) - # rotation - keyingsets_utils.RKS_GEN_rotation(self, context, ks, data) - - -# VisualLocScale -class BUILTIN_KSI_VisualLocScale(KeyingSetInfo): - """Insert a keyframe on each of the location and scale channels, """ \ - """taking into account effects of constraints and relationships""" - bl_label = "Visual Location & Scale" - - bl_options = {'INSERTKEY_VISUAL'} - - # poll - use predefined callback for selected bones/objects - poll = keyingsets_utils.RKS_POLL_selected_items - - # iterator - use callback for selected bones/objects - iterator = keyingsets_utils.RKS_ITER_selected_item - - # generator - def generate(self, context, ks, data): - # location - keyingsets_utils.RKS_GEN_location(self, context, ks, data) - # scaling - keyingsets_utils.RKS_GEN_scaling(self, context, ks, data) - - -# VisualLocRotScale -class BUILTIN_KSI_VisualLocRotScale(KeyingSetInfo): - """Insert a keyframe on each of the location, """ \ - """rotation and scale channels, taking into account effects of constraints and relationships""" - bl_label = "Visual Location, Rotation & Scale" - - bl_options = {'INSERTKEY_VISUAL'} - - # poll - use predefined callback for selected bones/objects - poll = keyingsets_utils.RKS_POLL_selected_items - - # iterator - use callback for selected bones/objects - iterator = keyingsets_utils.RKS_ITER_selected_item - - # generator - def generate(self, context, ks, data): - # location - keyingsets_utils.RKS_GEN_location(self, context, ks, data) - # rotation - keyingsets_utils.RKS_GEN_rotation(self, context, ks, data) - # scaling - keyingsets_utils.RKS_GEN_scaling(self, context, ks, data) - - -# VisualRotScale -class BUILTIN_KSI_VisualRotScale(KeyingSetInfo): - """Insert a keyframe on each of the rotation and scale channels, """ \ - """taking into account effects of constraints and relationships""" - bl_label = "Visual Rotation & Scale" - - bl_options = {'INSERTKEY_VISUAL'} - - # poll - use predefined callback for selected bones/objects - poll = keyingsets_utils.RKS_POLL_selected_items - - # iterator - use callback for selected bones/objects - iterator = keyingsets_utils.RKS_ITER_selected_item - - # generator - def generate(self, context, ks, data): - # rotation - keyingsets_utils.RKS_GEN_rotation(self, context, ks, data) - # scaling - keyingsets_utils.RKS_GEN_scaling(self, context, ks, data) - -# ------------ - - -# Available -class BUILTIN_KSI_Available(KeyingSetInfo): - """Insert a keyframe on each of the already existing F-Curves""" - bl_idname = ANIM_KS_AVAILABLE_ID - bl_label = "Available" - - # poll - selected objects or selected object with animation data - def poll(self, context): - ob = context.active_object - if ob: - # TODO: this fails if one animation-less object is active, but many others are selected - return ob.animation_data and ob.animation_data.action - else: - return bool(context.selected_objects) - - # iterator - use callback for selected bones/objects - iterator = keyingsets_utils.RKS_ITER_selected_item - - # generator - use callback for doing this - generate = keyingsets_utils.RKS_GEN_available - -############################### - - -class WholeCharacterMixin: - # these prefixes should be avoided, as they are not really bones - # that animators should be touching (or need to touch) - badBonePrefixes = ( - 'DEF', - 'GEO', - 'MCH', - 'ORG', - 'COR', - 'VIS', - # ... more can be added here as you need in your own rigs ... - ) - - # poll - pose-mode on active object only - def poll(self, context): - return ((context.active_object) and (context.active_object.pose) and - (context.active_object.mode == 'POSE')) - - # iterator - all bones regardless of selection - def iterator(self, context, ks): - for bone in context.active_object.pose.bones: - if not bone.name.startswith(self.badBonePrefixes): - self.generate(context, ks, bone) - - # generator - all unlocked bone transforms + custom properties - def generate(self, context, ks, bone): - # loc, rot, scale - only include unlocked ones - if not bone.bone.use_connect: - self.doLoc(ks, bone) - - if bone.rotation_mode in {'QUATERNION', 'AXIS_ANGLE'}: - self.doRot4d(ks, bone) - else: - self.doRot3d(ks, bone) - self.doScale(ks, bone) - - # bbone properties? - self.doBBone(context, ks, bone) - - # custom props? - self.doCustomProps(ks, bone) - # ---------------- - - # helper to add some bone's property to the Keying Set - def addProp(self, ks, bone, prop, index=-1, use_groups=True): - # add the property name to the base path - id_path = bone.path_from_id() - id_block = bone.id_data - - if prop.startswith('['): - # custom properties - path = id_path + prop - else: - # standard transforms/properties - path = keyingsets_utils.path_add_property(id_path, prop) - - # add Keying Set entry for this... - if use_groups: - ks.paths.add(id_block, path, index=index, group_method='NAMED', group_name=bone.name) - else: - ks.paths.add(id_block, path, index=index) - - # ---------------- - - # location properties - def doLoc(self, ks, bone): - if bone.lock_location == (False, False, False): - self.addProp(ks, bone, "location") - else: - for i in range(3): - if not bone.lock_location[i]: - self.addProp(ks, bone, "location", i) - - # rotation properties - def doRot4d(self, ks, bone): - # rotation mode affects the property used - if bone.rotation_mode == 'QUATERNION': - prop = "rotation_quaternion" - elif bone.rotation_mode == 'AXIS_ANGLE': - prop = "rotation_axis_angle" - - # add rotation properties if they will - if bone.lock_rotations_4d: - # can check individually - if (bone.lock_rotation == (False, False, False)) and (bone.lock_rotation_w is False): - self.addProp(ks, bone, prop) - else: - if bone.lock_rotation_w is False: - self.addProp(ks, bone, prop, 0) # w = 0 - - for i in range(3): - if not bone.lock_rotation[i]: - self.addProp(ks, bone, prop, i + 1) # i + 1, since here x/y/z = 1,2,3, and w=0 - elif True not in bone.lock_rotation: - # if axis-angle rotations get locked as eulers, then it's too messy to allow anything - # other than all open unless we keyframe the whole lot - self.addProp(ks, bone, prop) - - def doRot3d(self, ks, bone): - if bone.lock_rotation == (False, False, False): - self.addProp(ks, bone, "rotation_euler") - else: - for i in range(3): - if not bone.lock_rotation[i]: - self.addProp(ks, bone, "rotation_euler", i) - - # scale properties - def doScale(self, ks, bone): - if bone.lock_scale == (0, 0, 0): - self.addProp(ks, bone, "scale") - else: - for i in range(3): - if not bone.lock_scale[i]: - self.addProp(ks, bone, "scale", i) - - # ---------------- - - # bendy bone properties - def doBBone(self, context, ks, pchan): - bone = pchan.bone - - # This check is crude, but is the best we can do for now - # It simply adds all of these if the bbone has segments - # (and the bone is a control bone). This may lead to some - # false positives... - if bone.bbone_segments > 1: - keyingsets_utils.RKS_GEN_bendy_bones(self, context, ks, pchan) - - # ---------------- - - # custom properties - def doCustomProps(self, ks, bone): - - prop_type_compat = { - bpy.types.BoolProperty, - bpy.types.IntProperty, - bpy.types.FloatProperty, - } - - # go over all custom properties for bone - for prop in bone.keys(): - # for now, just add all of 'em - prop_rna = type(bone).bl_rna.properties.get(prop, None) - if prop_rna is None: - prop_path = '["%s"]' % bpy.utils.escape_identifier(prop) - try: - rna_property = bone.path_resolve(prop_path, False) - except ValueError: - # This happens when a custom property is set to None. In that case it cannot - # be converted to an FCurve-compatible value, so we can't keyframe it anyway. - continue - if rna_property.rna_type in prop_type_compat: - self.addProp(ks, bone, prop_path) - elif prop_rna.is_animatable: - self.addProp(ks, bone, prop) - - -class BUILTIN_KSI_WholeCharacter(WholeCharacterMixin, KeyingSetInfo): - """Insert a keyframe for all properties that are likely to get animated in a character rig """ \ - """(useful when blocking out a shot)""" - bl_idname = ANIM_KS_WHOLE_CHARACTER_ID - bl_label = "Whole Character" - - -class BUILTIN_KSI_WholeCharacterSelected(WholeCharacterMixin, KeyingSetInfo): - """Insert a keyframe for all properties that are likely to get animated in a character rig """ \ - """(only selected bones)""" - bl_idname = ANIM_KS_WHOLE_CHARACTER_SELECTED_ID - bl_label = "Whole Character (Selected Bones Only)" - - # iterator - all bones regardless of selection - def iterator(self, context, ks): - # Use either the selected bones, or all of them if none are selected. - bones = context.selected_pose_bones_from_active_object or context.active_object.pose.bones - - for bone in bones: - if bone.name.startswith(self.badBonePrefixes): - continue - self.generate(context, ks, bone) - - -############################### - -# Delta Location - - -class BUILTIN_KSI_DeltaLocation(KeyingSetInfo): - """Insert keyframes for additional location offset""" - bl_label = "Delta Location" - - # poll - selected objects only (and only if active object in object mode) - poll = keyingsets_utils.RKS_POLL_selected_objects - - # iterator - selected objects only - iterator = keyingsets_utils.RKS_ITER_selected_objects - - # generator - delta location channels only - def generate(self, _context, ks, data): - # get id-block and path info - id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data) - - # add the property name to the base path - path = keyingsets_utils.path_add_property(base_path, "delta_location") - - # add Keying Set entry for this... - if grouping: - ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping) - else: - ks.paths.add(id_block, path) - - -# Delta Rotation -class BUILTIN_KSI_DeltaRotation(KeyingSetInfo): - """Insert keyframes for additional rotation offset""" - bl_label = "Delta Rotation" - - # poll - selected objects only (and only if active object in object mode) - poll = keyingsets_utils.RKS_POLL_selected_objects - - # iterator - selected objects only - iterator = keyingsets_utils.RKS_ITER_selected_objects - - # generator - delta location channels only - def generate(self, _context, ks, data): - # get id-block and path info - id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data) - - # add the property name to the base path - # rotation mode affects the property used - if data.rotation_mode == 'QUATERNION': - path = keyingsets_utils.path_add_property(base_path, "delta_rotation_quaternion") - elif data.rotation_mode == 'AXIS_ANGLE': - # XXX: for now, this is not available yet - # path = path_add_property(base_path, "delta_rotation_axis_angle") - return - else: - path = keyingsets_utils.path_add_property(base_path, "delta_rotation_euler") - - # add Keying Set entry for this... - if grouping: - ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping) - else: - ks.paths.add(id_block, path) - - -# Delta Scale -class BUILTIN_KSI_DeltaScale(KeyingSetInfo): - """Insert keyframes for additional scale factor""" - bl_label = "Delta Scale" - - # poll - selected objects only (and only if active object in object mode) - poll = keyingsets_utils.RKS_POLL_selected_objects - - # iterator - selected objects only - iterator = keyingsets_utils.RKS_ITER_selected_objects - - # generator - delta location channels only - def generate(self, _context, ks, data): - # get id-block and path info - id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data) - - # add the property name to the base path - path = keyingsets_utils.path_add_property(base_path, "delta_scale") - - # add Keying Set entry for this... - if grouping: - ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping) - else: - ks.paths.add(id_block, path) - -############################### - - -# Note that this controls order of options in `insert keyframe` menu. -# Better try to keep some logical order here beyond mere alphabetical one, also because of menu entries shortcut. -# See also #51867. -classes = ( - BUILTIN_KSI_Available, - BUILTIN_KSI_Location, - BUILTIN_KSI_Rotation, - BUILTIN_KSI_Scaling, - BUILTIN_KSI_LocRot, - BUILTIN_KSI_LocRotScale, - BUILTIN_KSI_LocRotScaleCProp, - BUILTIN_KSI_LocScale, - BUILTIN_KSI_RotScale, - BUILTIN_KSI_DeltaLocation, - BUILTIN_KSI_DeltaRotation, - BUILTIN_KSI_DeltaScale, - BUILTIN_KSI_VisualLoc, - BUILTIN_KSI_VisualRot, - BUILTIN_KSI_VisualScaling, - BUILTIN_KSI_VisualLocRot, - BUILTIN_KSI_VisualLocRotScale, - BUILTIN_KSI_VisualLocScale, - BUILTIN_KSI_VisualRotScale, - BUILTIN_KSI_BendyBones, - BUILTIN_KSI_WholeCharacter, - BUILTIN_KSI_WholeCharacterSelected, -) - - -def register(): - from bpy.utils import register_class - for cls in classes: - register_class(cls) - - -def unregister(): - from bpy.utils import unregister_class - for cls in classes: - unregister_class(cls) - - -if __name__ == "__main__": - register() -- 2.30.2 From 6739d4e4268a8f331bff54c55b5ef051156d6fb1 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 13 Oct 2023 16:17:21 +0200 Subject: [PATCH 04/41] Revert "remove builtin keyingsets" This reverts commit 53722d3b6da864799f6fc6ad2aa26920d64acd9b. --- scripts/modules/keyingsets_utils.py | 283 ++++++++++ scripts/startup/keyingsets_builtins.py | 686 +++++++++++++++++++++++++ 2 files changed, 969 insertions(+) create mode 100644 scripts/modules/keyingsets_utils.py create mode 100644 scripts/startup/keyingsets_builtins.py diff --git a/scripts/modules/keyingsets_utils.py b/scripts/modules/keyingsets_utils.py new file mode 100644 index 00000000000..e13d61fb133 --- /dev/null +++ b/scripts/modules/keyingsets_utils.py @@ -0,0 +1,283 @@ +# SPDX-FileCopyrightText: 2010-2023 Blender Authors +# +# SPDX-License-Identifier: GPL-2.0-or-later + +# This file defines a set of methods that are useful for various +# Relative Keying Set (RKS) related operations, such as: callbacks +# for polling, iterator callbacks, and also generate callbacks. +# All of these can be used in conjunction with the others. + +__all__ = ( + "path_add_property", + "RKS_POLL_selected_objects", + "RKS_POLL_selected_bones", + "RKS_POLL_selected_items", + "RKS_ITER_selected_objects", + "RKS_ITER_selected_bones", + "RKS_ITER_selected_item", + "RKS_GEN_available", + "RKS_GEN_location", + "RKS_GEN_rotation", + "RKS_GEN_scaling", + "RKS_GEN_bendy_bones", +) + +import bpy + +########################### +# General Utilities + + +# Append the specified property name on the the existing path +def path_add_property(path, prop): + if path: + return path + "." + prop + else: + return prop + +########################### +# Poll Callbacks + + +# selected objects (active object must be in object mode) +def RKS_POLL_selected_objects(_ksi, context): + ob = context.active_object + if ob: + return ob.mode == 'OBJECT' + else: + return bool(context.selected_objects) + + +# selected bones +def RKS_POLL_selected_bones(_ksi, context): + # we must be in Pose Mode, and there must be some bones selected + ob = context.active_object + if ob and ob.mode == 'POSE': + if context.active_pose_bone or context.selected_pose_bones: + return True + + # nothing selected + return False + + +# selected bones or objects +def RKS_POLL_selected_items(ksi, context): + return (RKS_POLL_selected_bones(ksi, context) or + RKS_POLL_selected_objects(ksi, context)) + +########################### +# Iterator Callbacks + + +# All selected objects or pose bones, depending on which we've got. +def RKS_ITER_selected_item(ksi, context, ks): + ob = context.active_object + if ob and ob.mode == 'POSE': + for bone in context.selected_pose_bones: + ksi.generate(context, ks, bone) + else: + for ob in context.selected_objects: + ksi.generate(context, ks, ob) + + +# All selected objects only. +def RKS_ITER_selected_objects(ksi, context, ks): + for ob in context.selected_objects: + ksi.generate(context, ks, ob) + + +# All selected bones only. +def RKS_ITER_selected_bones(ksi, context, ks): + for bone in context.selected_pose_bones: + ksi.generate(context, ks, bone) + +########################### +# Generate Callbacks + + +# "Available" F-Curves. +def RKS_GEN_available(_ksi, _context, ks, data): + # try to get the animation data associated with the closest + # ID-block to the data (neither of which may exist/be easy to find) + id_block = data.id_data + adt = getattr(id_block, "animation_data", None) + + # there must also be an active action... + if adt is None or adt.action is None: + return + + # if we haven't got an ID-block as 'data', try to restrict + # paths added to only those which branch off from here + # i.e. for bones + if id_block != data: + basePath = data.path_from_id() + else: + basePath = None # this is not needed... + + # for each F-Curve, include a path to key it + # NOTE: we don't need to set the group settings here + for fcu in adt.action.fcurves: + if basePath: + if basePath in fcu.data_path: + ks.paths.add(id_block, fcu.data_path, index=fcu.array_index) + else: + ks.paths.add(id_block, fcu.data_path, index=fcu.array_index) + +# ------ + + +# get ID block and based ID path for transform generators +# private function +def get_transform_generators_base_info(data): + # ID-block for the data + id_block = data.id_data + + # get base path and grouping method/name + if isinstance(data, bpy.types.ID): + # no path in this case + path = "" + + # transform data on ID-blocks directly should get grouped under a + # hardcoded label ("Object Transforms") so that they get grouped + # consistently when keyframed directly + grouping = "Object Transforms" + else: + # get the path to the ID-block + path = data.path_from_id() + + # try to use the name of the data element to group the F-Curve + # else fallback on the KeyingSet name + grouping = getattr(data, "name", None) + + # return the ID-block and the path + return id_block, path, grouping + + +# Location +def RKS_GEN_location(_ksi, _context, ks, data): + # get id-block and path info + id_block, base_path, grouping = get_transform_generators_base_info(data) + + # add the property name to the base path + path = path_add_property(base_path, "location") + + # add Keying Set entry for this... + if grouping: + ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping) + else: + ks.paths.add(id_block, path) + + +# Rotation +def RKS_GEN_rotation(_ksi, _context, ks, data): + # get id-block and path info + id_block, base_path, grouping = get_transform_generators_base_info(data) + + # add the property name to the base path + # rotation mode affects the property used + if data.rotation_mode == 'QUATERNION': + path = path_add_property(base_path, "rotation_quaternion") + elif data.rotation_mode == 'AXIS_ANGLE': + path = path_add_property(base_path, "rotation_axis_angle") + else: + path = path_add_property(base_path, "rotation_euler") + + # add Keying Set entry for this... + if grouping: + ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping) + else: + ks.paths.add(id_block, path) + + +# Scaling +def RKS_GEN_scaling(_ksi, _context, ks, data): + # get id-block and path info + id_block, base_path, grouping = get_transform_generators_base_info(data) + + # add the property name to the base path + path = path_add_property(base_path, "scale") + + # add Keying Set entry for this... + if grouping: + ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping) + else: + ks.paths.add(id_block, path) + + +# Custom Properties +def RKS_GEN_custom_props(_ksi, _context, ks, data): + # get id-block and path info + id_block, base_path, grouping = get_transform_generators_base_info(data) + + # Only some RNA types can be animated. + prop_type_compat = {bpy.types.BoolProperty, + bpy.types.IntProperty, + bpy.types.FloatProperty} + + # When working with a pose, 'id_block' is the armature object (which should + # get the animation data), whereas 'data' is the bone being keyed. + for cprop_name in data.keys(): + # ignore special "_RNA_UI" used for UI editing + if cprop_name == "_RNA_UI": + continue + + prop_path = '["%s"]' % bpy.utils.escape_identifier(cprop_name) + + try: + rna_property = data.path_resolve(prop_path, False) + except ValueError: + # Can technically happen, but there is no known case. + continue + if rna_property is None: + # In this case the property cannot be converted to an + # FCurve-compatible value, so we can't keyframe it anyways. + continue + if rna_property.rna_type not in prop_type_compat: + continue + + path = "%s%s" % (base_path, prop_path) + if grouping: + ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping) + else: + ks.paths.add(id_block, path) + +# ------ + + +# Property identifiers for Bendy Bones +bbone_property_ids = ( + "bbone_curveinx", + "bbone_curveiny", + "bbone_curveoutx", + "bbone_curveouty", + + "bbone_rollin", + "bbone_rollout", + + "bbone_scalein", + "bbone_scaleout", + + # NOTE: These are in the nested bone struct + # Do it this way to force them to be included + # in whatever actions are being keyed here + "bone.bbone_in", + "bone.bbone_out", +) + + +# Add Keying Set entries for bendy bones +def RKS_GEN_bendy_bones(_ksi, _context, ks, data): + # get id-block and path info + # NOTE: This assumes that we're dealing with a bone here... + id_block, base_path, grouping = get_transform_generators_base_info(data) + + # for each of the bendy bone properties, add a Keying Set entry for it... + for propname in bbone_property_ids: + # add the property name to the base path + path = path_add_property(base_path, propname) + + # add Keying Set entry for this... + if grouping: + ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping) + else: + ks.paths.add(id_block, path) diff --git a/scripts/startup/keyingsets_builtins.py b/scripts/startup/keyingsets_builtins.py new file mode 100644 index 00000000000..79e4eda1aed --- /dev/null +++ b/scripts/startup/keyingsets_builtins.py @@ -0,0 +1,686 @@ +# SPDX-FileCopyrightText: 2010-2023 Blender Authors +# +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Built-In Keying Sets +None of these Keying Sets should be removed, as these are needed by various parts of Blender in order for them +to work correctly. + +Beware also about changing the order that these are defined here, since this can result in old files referring to the +wrong Keying Set as the active one, potentially resulting in lost (i.e. unkeyed) animation. + +Note that these classes cannot be subclassed further; only direct subclasses of KeyingSetInfo +are supported. +""" + +import bpy +import keyingsets_utils +from bpy.types import KeyingSetInfo + +############################### +# Built-In KeyingSets + + +# "Defines" +# Keep these in sync with those in ED_keyframing.hh! +ANIM_KS_LOCATION_ID = "Location" +ANIM_KS_ROTATION_ID = "Rotation" +ANIM_KS_SCALING_ID = "Scaling" +ANIM_KS_LOC_ROT_SCALE_ID = "LocRotScale" +ANIM_KS_LOC_ROT_SCALE_CPROP_ID = "LocRotScaleCProp" +ANIM_KS_AVAILABLE_ID = "Available" +ANIM_KS_WHOLE_CHARACTER_ID = "WholeCharacter" +ANIM_KS_WHOLE_CHARACTER_SELECTED_ID = "WholeCharacterSelected" + + +# Location +class BUILTIN_KSI_Location(KeyingSetInfo): + """Insert a keyframe on each of the location channels""" + bl_idname = ANIM_KS_LOCATION_ID + bl_label = "Location" + + # poll - use predefined callback for selected bones/objects + poll = keyingsets_utils.RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator - use callback for location + generate = keyingsets_utils.RKS_GEN_location + + +# Rotation +class BUILTIN_KSI_Rotation(KeyingSetInfo): + """Insert a keyframe on each of the rotation channels""" + bl_idname = ANIM_KS_ROTATION_ID + bl_label = "Rotation" + + # poll - use predefined callback for selected bones/objects + poll = keyingsets_utils.RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator - use callback for rotation + generate = keyingsets_utils.RKS_GEN_rotation + + +# Scale +class BUILTIN_KSI_Scaling(KeyingSetInfo): + """Insert a keyframe on each of the scale channels""" + bl_idname = ANIM_KS_SCALING_ID + bl_label = "Scale" + + # poll - use predefined callback for selected bones/objects + poll = keyingsets_utils.RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator - use callback for scaling + generate = keyingsets_utils.RKS_GEN_scaling + +# ------------ + + +# LocRot +class BUILTIN_KSI_LocRot(KeyingSetInfo): + """Insert a keyframe on each of the location and rotation channels""" + bl_label = "Location & Rotation" + + # poll - use predefined callback for selected bones/objects + poll = keyingsets_utils.RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator + def generate(self, context, ks, data): + # location + keyingsets_utils.RKS_GEN_location(self, context, ks, data) + # rotation + keyingsets_utils.RKS_GEN_rotation(self, context, ks, data) + + +# LocScale +class BUILTIN_KSI_LocScale(KeyingSetInfo): + """Insert a keyframe on each of the location and scale channels""" + bl_label = "Location & Scale" + + # poll - use predefined callback for selected bones/objects + poll = keyingsets_utils.RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator + def generate(self, context, ks, data): + # location + keyingsets_utils.RKS_GEN_location(self, context, ks, data) + # scale + keyingsets_utils.RKS_GEN_scaling(self, context, ks, data) + + +# LocRotScale +class BUILTIN_KSI_LocRotScale(KeyingSetInfo): + """Insert a keyframe on each of the location, rotation, and scale channels""" + bl_idname = ANIM_KS_LOC_ROT_SCALE_ID + bl_label = "Location, Rotation & Scale" + + # poll - use predefined callback for selected bones/objects + poll = keyingsets_utils.RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator + def generate(self, context, ks, data): + # location + keyingsets_utils.RKS_GEN_location(self, context, ks, data) + # rotation + keyingsets_utils.RKS_GEN_rotation(self, context, ks, data) + # scale + keyingsets_utils.RKS_GEN_scaling(self, context, ks, data) + + +# LocRotScaleCProp +class BUILTIN_KSI_LocRotScaleCProp(KeyingSetInfo): + """Key location/rotation/scale as well as custom properties""" + bl_idname = ANIM_KS_LOC_ROT_SCALE_CPROP_ID + bl_label = "Location, Rotation, Scale & Custom Properties" + + poll = keyingsets_utils.RKS_POLL_selected_items + iterator = keyingsets_utils.RKS_ITER_selected_item + + def generate(self, context, ks, data): + keyingsets_utils.RKS_GEN_location(self, context, ks, data) + keyingsets_utils.RKS_GEN_rotation(self, context, ks, data) + keyingsets_utils.RKS_GEN_scaling(self, context, ks, data) + keyingsets_utils.RKS_GEN_custom_props(self, context, ks, data) + + +# RotScale +class BUILTIN_KSI_RotScale(KeyingSetInfo): + """Insert a keyframe on each of the rotation and scale channels""" + bl_label = "Rotation & Scale" + + # poll - use predefined callback for selected bones/objects + poll = keyingsets_utils.RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator + def generate(self, context, ks, data): + # rotation + keyingsets_utils.RKS_GEN_rotation(self, context, ks, data) + # scaling + keyingsets_utils.RKS_GEN_scaling(self, context, ks, data) + +# ------------ + + +# Bendy Bones +class BUILTIN_KSI_BendyBones(KeyingSetInfo): + """Insert a keyframe for each of the BBone shape properties""" + bl_label = "BBone Shape" + + # poll - use callback for selected bones + poll = keyingsets_utils.RKS_POLL_selected_bones + + # iterator - use callback for selected bones + iterator = keyingsets_utils.RKS_ITER_selected_bones + + # generator - use generator for bendy bone properties + generate = keyingsets_utils.RKS_GEN_bendy_bones + +# ------------ + + +# VisualLocation +class BUILTIN_KSI_VisualLoc(KeyingSetInfo): + """Insert a keyframe on each of the location channels, """ \ + """taking into account effects of constraints and relationships""" + bl_label = "Visual Location" + + bl_options = {'INSERTKEY_VISUAL'} + + # poll - use predefined callback for selected bones/objects + poll = keyingsets_utils.RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator - use callback for location + generate = keyingsets_utils.RKS_GEN_location + + +# VisualRotation +class BUILTIN_KSI_VisualRot(KeyingSetInfo): + """Insert a keyframe on each of the rotation channels, """ \ + """taking into account effects of constraints and relationships""" + bl_label = "Visual Rotation" + + bl_options = {'INSERTKEY_VISUAL'} + + # poll - use predefined callback for selected bones/objects + poll = keyingsets_utils.RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator - use callback for rotation + generate = keyingsets_utils.RKS_GEN_rotation + + +# VisualScaling +class BUILTIN_KSI_VisualScaling(KeyingSetInfo): + """Insert a keyframe on each of the scale channels, """ \ + """taking into account effects of constraints and relationships""" + bl_label = "Visual Scale" + + bl_options = {'INSERTKEY_VISUAL'} + + # poll - use predefined callback for selected bones/objects + poll = keyingsets_utils.RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator - use callback for location + generate = keyingsets_utils.RKS_GEN_scaling + + +# VisualLocRot +class BUILTIN_KSI_VisualLocRot(KeyingSetInfo): + """Insert a keyframe on each of the location and rotation channels, """ \ + """taking into account effects of constraints and relationships""" + bl_label = "Visual Location & Rotation" + + bl_options = {'INSERTKEY_VISUAL'} + + # poll - use predefined callback for selected bones/objects + poll = keyingsets_utils.RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator + def generate(self, context, ks, data): + # location + keyingsets_utils.RKS_GEN_location(self, context, ks, data) + # rotation + keyingsets_utils.RKS_GEN_rotation(self, context, ks, data) + + +# VisualLocScale +class BUILTIN_KSI_VisualLocScale(KeyingSetInfo): + """Insert a keyframe on each of the location and scale channels, """ \ + """taking into account effects of constraints and relationships""" + bl_label = "Visual Location & Scale" + + bl_options = {'INSERTKEY_VISUAL'} + + # poll - use predefined callback for selected bones/objects + poll = keyingsets_utils.RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator + def generate(self, context, ks, data): + # location + keyingsets_utils.RKS_GEN_location(self, context, ks, data) + # scaling + keyingsets_utils.RKS_GEN_scaling(self, context, ks, data) + + +# VisualLocRotScale +class BUILTIN_KSI_VisualLocRotScale(KeyingSetInfo): + """Insert a keyframe on each of the location, """ \ + """rotation and scale channels, taking into account effects of constraints and relationships""" + bl_label = "Visual Location, Rotation & Scale" + + bl_options = {'INSERTKEY_VISUAL'} + + # poll - use predefined callback for selected bones/objects + poll = keyingsets_utils.RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator + def generate(self, context, ks, data): + # location + keyingsets_utils.RKS_GEN_location(self, context, ks, data) + # rotation + keyingsets_utils.RKS_GEN_rotation(self, context, ks, data) + # scaling + keyingsets_utils.RKS_GEN_scaling(self, context, ks, data) + + +# VisualRotScale +class BUILTIN_KSI_VisualRotScale(KeyingSetInfo): + """Insert a keyframe on each of the rotation and scale channels, """ \ + """taking into account effects of constraints and relationships""" + bl_label = "Visual Rotation & Scale" + + bl_options = {'INSERTKEY_VISUAL'} + + # poll - use predefined callback for selected bones/objects + poll = keyingsets_utils.RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator + def generate(self, context, ks, data): + # rotation + keyingsets_utils.RKS_GEN_rotation(self, context, ks, data) + # scaling + keyingsets_utils.RKS_GEN_scaling(self, context, ks, data) + +# ------------ + + +# Available +class BUILTIN_KSI_Available(KeyingSetInfo): + """Insert a keyframe on each of the already existing F-Curves""" + bl_idname = ANIM_KS_AVAILABLE_ID + bl_label = "Available" + + # poll - selected objects or selected object with animation data + def poll(self, context): + ob = context.active_object + if ob: + # TODO: this fails if one animation-less object is active, but many others are selected + return ob.animation_data and ob.animation_data.action + else: + return bool(context.selected_objects) + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator - use callback for doing this + generate = keyingsets_utils.RKS_GEN_available + +############################### + + +class WholeCharacterMixin: + # these prefixes should be avoided, as they are not really bones + # that animators should be touching (or need to touch) + badBonePrefixes = ( + 'DEF', + 'GEO', + 'MCH', + 'ORG', + 'COR', + 'VIS', + # ... more can be added here as you need in your own rigs ... + ) + + # poll - pose-mode on active object only + def poll(self, context): + return ((context.active_object) and (context.active_object.pose) and + (context.active_object.mode == 'POSE')) + + # iterator - all bones regardless of selection + def iterator(self, context, ks): + for bone in context.active_object.pose.bones: + if not bone.name.startswith(self.badBonePrefixes): + self.generate(context, ks, bone) + + # generator - all unlocked bone transforms + custom properties + def generate(self, context, ks, bone): + # loc, rot, scale - only include unlocked ones + if not bone.bone.use_connect: + self.doLoc(ks, bone) + + if bone.rotation_mode in {'QUATERNION', 'AXIS_ANGLE'}: + self.doRot4d(ks, bone) + else: + self.doRot3d(ks, bone) + self.doScale(ks, bone) + + # bbone properties? + self.doBBone(context, ks, bone) + + # custom props? + self.doCustomProps(ks, bone) + # ---------------- + + # helper to add some bone's property to the Keying Set + def addProp(self, ks, bone, prop, index=-1, use_groups=True): + # add the property name to the base path + id_path = bone.path_from_id() + id_block = bone.id_data + + if prop.startswith('['): + # custom properties + path = id_path + prop + else: + # standard transforms/properties + path = keyingsets_utils.path_add_property(id_path, prop) + + # add Keying Set entry for this... + if use_groups: + ks.paths.add(id_block, path, index=index, group_method='NAMED', group_name=bone.name) + else: + ks.paths.add(id_block, path, index=index) + + # ---------------- + + # location properties + def doLoc(self, ks, bone): + if bone.lock_location == (False, False, False): + self.addProp(ks, bone, "location") + else: + for i in range(3): + if not bone.lock_location[i]: + self.addProp(ks, bone, "location", i) + + # rotation properties + def doRot4d(self, ks, bone): + # rotation mode affects the property used + if bone.rotation_mode == 'QUATERNION': + prop = "rotation_quaternion" + elif bone.rotation_mode == 'AXIS_ANGLE': + prop = "rotation_axis_angle" + + # add rotation properties if they will + if bone.lock_rotations_4d: + # can check individually + if (bone.lock_rotation == (False, False, False)) and (bone.lock_rotation_w is False): + self.addProp(ks, bone, prop) + else: + if bone.lock_rotation_w is False: + self.addProp(ks, bone, prop, 0) # w = 0 + + for i in range(3): + if not bone.lock_rotation[i]: + self.addProp(ks, bone, prop, i + 1) # i + 1, since here x/y/z = 1,2,3, and w=0 + elif True not in bone.lock_rotation: + # if axis-angle rotations get locked as eulers, then it's too messy to allow anything + # other than all open unless we keyframe the whole lot + self.addProp(ks, bone, prop) + + def doRot3d(self, ks, bone): + if bone.lock_rotation == (False, False, False): + self.addProp(ks, bone, "rotation_euler") + else: + for i in range(3): + if not bone.lock_rotation[i]: + self.addProp(ks, bone, "rotation_euler", i) + + # scale properties + def doScale(self, ks, bone): + if bone.lock_scale == (0, 0, 0): + self.addProp(ks, bone, "scale") + else: + for i in range(3): + if not bone.lock_scale[i]: + self.addProp(ks, bone, "scale", i) + + # ---------------- + + # bendy bone properties + def doBBone(self, context, ks, pchan): + bone = pchan.bone + + # This check is crude, but is the best we can do for now + # It simply adds all of these if the bbone has segments + # (and the bone is a control bone). This may lead to some + # false positives... + if bone.bbone_segments > 1: + keyingsets_utils.RKS_GEN_bendy_bones(self, context, ks, pchan) + + # ---------------- + + # custom properties + def doCustomProps(self, ks, bone): + + prop_type_compat = { + bpy.types.BoolProperty, + bpy.types.IntProperty, + bpy.types.FloatProperty, + } + + # go over all custom properties for bone + for prop in bone.keys(): + # for now, just add all of 'em + prop_rna = type(bone).bl_rna.properties.get(prop, None) + if prop_rna is None: + prop_path = '["%s"]' % bpy.utils.escape_identifier(prop) + try: + rna_property = bone.path_resolve(prop_path, False) + except ValueError: + # This happens when a custom property is set to None. In that case it cannot + # be converted to an FCurve-compatible value, so we can't keyframe it anyway. + continue + if rna_property.rna_type in prop_type_compat: + self.addProp(ks, bone, prop_path) + elif prop_rna.is_animatable: + self.addProp(ks, bone, prop) + + +class BUILTIN_KSI_WholeCharacter(WholeCharacterMixin, KeyingSetInfo): + """Insert a keyframe for all properties that are likely to get animated in a character rig """ \ + """(useful when blocking out a shot)""" + bl_idname = ANIM_KS_WHOLE_CHARACTER_ID + bl_label = "Whole Character" + + +class BUILTIN_KSI_WholeCharacterSelected(WholeCharacterMixin, KeyingSetInfo): + """Insert a keyframe for all properties that are likely to get animated in a character rig """ \ + """(only selected bones)""" + bl_idname = ANIM_KS_WHOLE_CHARACTER_SELECTED_ID + bl_label = "Whole Character (Selected Bones Only)" + + # iterator - all bones regardless of selection + def iterator(self, context, ks): + # Use either the selected bones, or all of them if none are selected. + bones = context.selected_pose_bones_from_active_object or context.active_object.pose.bones + + for bone in bones: + if bone.name.startswith(self.badBonePrefixes): + continue + self.generate(context, ks, bone) + + +############################### + +# Delta Location + + +class BUILTIN_KSI_DeltaLocation(KeyingSetInfo): + """Insert keyframes for additional location offset""" + bl_label = "Delta Location" + + # poll - selected objects only (and only if active object in object mode) + poll = keyingsets_utils.RKS_POLL_selected_objects + + # iterator - selected objects only + iterator = keyingsets_utils.RKS_ITER_selected_objects + + # generator - delta location channels only + def generate(self, _context, ks, data): + # get id-block and path info + id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data) + + # add the property name to the base path + path = keyingsets_utils.path_add_property(base_path, "delta_location") + + # add Keying Set entry for this... + if grouping: + ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping) + else: + ks.paths.add(id_block, path) + + +# Delta Rotation +class BUILTIN_KSI_DeltaRotation(KeyingSetInfo): + """Insert keyframes for additional rotation offset""" + bl_label = "Delta Rotation" + + # poll - selected objects only (and only if active object in object mode) + poll = keyingsets_utils.RKS_POLL_selected_objects + + # iterator - selected objects only + iterator = keyingsets_utils.RKS_ITER_selected_objects + + # generator - delta location channels only + def generate(self, _context, ks, data): + # get id-block and path info + id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data) + + # add the property name to the base path + # rotation mode affects the property used + if data.rotation_mode == 'QUATERNION': + path = keyingsets_utils.path_add_property(base_path, "delta_rotation_quaternion") + elif data.rotation_mode == 'AXIS_ANGLE': + # XXX: for now, this is not available yet + # path = path_add_property(base_path, "delta_rotation_axis_angle") + return + else: + path = keyingsets_utils.path_add_property(base_path, "delta_rotation_euler") + + # add Keying Set entry for this... + if grouping: + ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping) + else: + ks.paths.add(id_block, path) + + +# Delta Scale +class BUILTIN_KSI_DeltaScale(KeyingSetInfo): + """Insert keyframes for additional scale factor""" + bl_label = "Delta Scale" + + # poll - selected objects only (and only if active object in object mode) + poll = keyingsets_utils.RKS_POLL_selected_objects + + # iterator - selected objects only + iterator = keyingsets_utils.RKS_ITER_selected_objects + + # generator - delta location channels only + def generate(self, _context, ks, data): + # get id-block and path info + id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data) + + # add the property name to the base path + path = keyingsets_utils.path_add_property(base_path, "delta_scale") + + # add Keying Set entry for this... + if grouping: + ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping) + else: + ks.paths.add(id_block, path) + +############################### + + +# Note that this controls order of options in `insert keyframe` menu. +# Better try to keep some logical order here beyond mere alphabetical one, also because of menu entries shortcut. +# See also #51867. +classes = ( + BUILTIN_KSI_Available, + BUILTIN_KSI_Location, + BUILTIN_KSI_Rotation, + BUILTIN_KSI_Scaling, + BUILTIN_KSI_LocRot, + BUILTIN_KSI_LocRotScale, + BUILTIN_KSI_LocRotScaleCProp, + BUILTIN_KSI_LocScale, + BUILTIN_KSI_RotScale, + BUILTIN_KSI_DeltaLocation, + BUILTIN_KSI_DeltaRotation, + BUILTIN_KSI_DeltaScale, + BUILTIN_KSI_VisualLoc, + BUILTIN_KSI_VisualRot, + BUILTIN_KSI_VisualScaling, + BUILTIN_KSI_VisualLocRot, + BUILTIN_KSI_VisualLocRotScale, + BUILTIN_KSI_VisualLocScale, + BUILTIN_KSI_VisualRotScale, + BUILTIN_KSI_BendyBones, + BUILTIN_KSI_WholeCharacter, + BUILTIN_KSI_WholeCharacterSelected, +) + + +def register(): + from bpy.utils import register_class + for cls in classes: + register_class(cls) + + +def unregister(): + from bpy.utils import unregister_class + for cls in classes: + unregister_class(cls) + + +if __name__ == "__main__": + register() -- 2.30.2 From 0399369cce30124ce0ce87b614c9290e9ce70d5e Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Tue, 17 Oct 2023 10:52:42 +0200 Subject: [PATCH 05/41] insert_key_wip --- .../blender/editors/animation/keyframing.cc | 50 ++++++++++++++++--- .../blender/editors/animation/keyingsets.cc | 4 +- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index 67db6b92fe0..b8162733101 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -677,7 +677,7 @@ static bool modify_key_op_poll(bContext *C) /* Insert Key Operator ------------------------ */ -static int insert_key_exec(bContext *C, wmOperator *op) +static int insert_key_with_keyingset(bContext *C, wmOperator *op, KeyingSet *ks) { Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); @@ -685,12 +685,6 @@ static int insert_key_exec(bContext *C, wmOperator *op) const float cfra = BKE_scene_frame_get(scene); const bool confirm = op->flag & OP_IS_INVOKE; - - KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene); - if (ks == nullptr) { - return OPERATOR_CANCELLED; - } - /* exit the edit mode to make sure that those object data properties that have been * updated since the last switching to the edit mode will be keyframed correctly */ @@ -742,6 +736,48 @@ static int insert_key_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static int insert_key_foo(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + + // for selected RNA -> call + ID *id; + const char *rna_path = ""; + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Scene *scene = CTX_data_scene(C); + const float cfra = BKE_scene_frame_get(scene); + const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph, + cfra); + ListBase nla_cache = {nullptr, nullptr}; + bAction *action = nullptr; + eInsertKeyFlags insert_key_flags = INSERTKEY_NOFLAGS; + const char *groupname = nullptr; + const int array_index = -1; + blender::animrig::insert_keyframe(bmain, + op->reports, + id, + action, + groupname, + rna_path, + array_index, + &anim_eval_context, + BEZT_KEYTYPE_KEYFRAME, + &nla_cache, + insert_key_flags); + + return OPERATOR_FINISHED; +} + +static int insert_key_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene); + if (ks != nullptr) { + return insert_key_with_keyingset(C, op, ks); + } + return insert_key_foo(C, op); +} + void ANIM_OT_keyframe_insert(wmOperatorType *ot) { PropertyRNA *prop; diff --git a/source/blender/editors/animation/keyingsets.cc b/source/blender/editors/animation/keyingsets.cc index 6bd6c6fb94d..b03aabd1353 100644 --- a/source/blender/editors/animation/keyingsets.cc +++ b/source/blender/editors/animation/keyingsets.cc @@ -862,10 +862,10 @@ KeyingSet *ANIM_keyingset_get_from_idname(Scene *scene, const char *idname) { KeyingSet *ks = static_cast( BLI_findstring(&scene->keyingsets, idname, offsetof(KeyingSet, idname))); - if (ks == nullptr) { + /* if (ks == nullptr) { ks = static_cast( BLI_findstring(&builtin_keyingsets, idname, offsetof(KeyingSet, idname))); - } + } */ return ks; } -- 2.30.2 From aec593ba47c22d5883f11ab0c3ab3be383934f09 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Tue, 17 Oct 2023 13:42:22 +0200 Subject: [PATCH 06/41] changes after refactor --- source/blender/editors/animation/keyframing.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index bc555b77b80..69ef9119f4b 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -748,7 +748,6 @@ static int insert_key_foo(bContext *C, wmOperator *op) const float cfra = BKE_scene_frame_get(scene); const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph, cfra); - ListBase nla_cache = {nullptr, nullptr}; bAction *action = nullptr; eInsertKeyFlags insert_key_flags = INSERTKEY_NOFLAGS; const char *groupname = nullptr; @@ -762,7 +761,6 @@ static int insert_key_foo(bContext *C, wmOperator *op) array_index, &anim_eval_context, BEZT_KEYTYPE_KEYFRAME, - &nla_cache, insert_key_flags); return OPERATOR_FINISHED; -- 2.30.2 From 5e33c8c2282d4e55e52982e83d7bf15ccdb96557 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Tue, 17 Oct 2023 17:42:00 +0200 Subject: [PATCH 07/41] first somewhat working version --- source/blender/animrig/ANIM_keyframing.hh | 8 + source/blender/animrig/intern/keyframing.cc | 94 +++++++++++ .../blender/editors/animation/keyframing.cc | 153 +++++++++++++++--- source/blender/makesdna/DNA_userdef_types.h | 2 +- 4 files changed, 233 insertions(+), 24 deletions(-) diff --git a/source/blender/animrig/ANIM_keyframing.hh b/source/blender/animrig/ANIM_keyframing.hh index ea184054ddb..229e3a20590 100644 --- a/source/blender/animrig/ANIM_keyframing.hh +++ b/source/blender/animrig/ANIM_keyframing.hh @@ -10,6 +10,9 @@ #pragma once +#include + +#include "BLI_vector.hh" #include "DNA_anim_types.h" #include "ED_transform.hh" #include "RNA_types.hh" @@ -147,4 +150,9 @@ bool autokeyframe_property(bContext *C, /** \} */ +int action_insert_key(bAction *action, + std::string rna_path, + float frame, + const blender::Vector &values); + } // namespace blender::animrig diff --git a/source/blender/animrig/intern/keyframing.cc b/source/blender/animrig/intern/keyframing.cc index 63b901064d2..f98d7b80e68 100644 --- a/source/blender/animrig/intern/keyframing.cc +++ b/source/blender/animrig/intern/keyframing.cc @@ -8,6 +8,7 @@ #include #include +#include #include "ANIM_fcurve.hh" #include "ANIM_keyframing.hh" @@ -36,6 +37,7 @@ #include "RNA_access.hh" #include "RNA_define.hh" #include "RNA_path.hh" +#include "RNA_prototypes.h" #include "RNA_types.hh" #include "WM_api.hh" @@ -1027,4 +1029,96 @@ int clear_keyframe(Main *bmain, return key_count; } +static FCurve *action_fcurve_ensure( + bAction *act, const char group[], PointerRNA *ptr, std::string rna_path, const int array_index) +{ + bActionGroup *agrp; + FCurve *fcu; + + /* try to find f-curve matching for this setting + * - add if not found and allowed to add one + * TODO: add auto-grouping support? how this works will need to be resolved + */ + fcu = BKE_fcurve_find(&act->curves, rna_path.c_str(), array_index); + if (fcu) { + return fcu; + } + + /* use default settings to make a F-Curve */ + fcu = BKE_fcurve_create(); + + fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); + fcu->auto_smoothing = U.auto_smoothing_new; + if (BLI_listbase_is_empty(&act->curves)) { + fcu->flag |= FCURVE_ACTIVE; /* first one added active */ + } + + /* store path - make copy, and store that */ + char fcu_rna_path[rna_path.length() + 1]; + std::strcpy(fcu_rna_path, rna_path.c_str()); + fcu->rna_path = fcu_rna_path; + fcu->array_index = array_index; + + /* if a group name has been provided, try to add or find a group, then add F-Curve to it */ + if (group) { + /* try to find group */ + agrp = BKE_action_group_find_name(act, group); + + /* no matching groups, so add one */ + if (agrp == nullptr) { + agrp = action_groups_add_new(act, group); + + /* sync bone group colors if applicable */ + if (ptr && (ptr->type == &RNA_PoseBone)) { + bPoseChannel *pchan = static_cast(ptr->data); + action_group_colors_set_from_posebone(agrp, pchan); + } + } + + /* add F-Curve to group */ + action_groups_add_channel(act, agrp, fcu); + } + else { + /* just add F-Curve to end of Action's list */ + BLI_addtail(&act->curves, fcu); + } + + /* return the F-Curve */ + return fcu; +} + +static bool insert_key_fcu_foo(FCurve *fcu, const float frame, const float value) +{ + if (!BKE_fcurve_is_keyframable(fcu)) { + return false; + } + const int inserted_index = insert_vert_fcurve( + fcu, frame, value, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NOFLAGS); + return inserted_index >= 0; +} + +int action_insert_key(bAction *action, + std::string rna_path, + const float frame, + const blender::Vector &values) +{ + BLI_assert(action != nullptr); + + int property_array_index = 0; + int inserted_keys = 0; + const char *group = ""; + for (const float value : values) { + FCurve *fcu = action_fcurve_ensure(action, group, nullptr, rna_path, property_array_index); + if (!fcu) { + continue; + } + const bool inserted_key = insert_key_fcu_foo(fcu, frame, value); + if (inserted_key) { + inserted_keys++; + } + property_array_index++; + } + return inserted_keys; +} + } // namespace blender::animrig diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index 69ef9119f4b..df9670c623c 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -32,6 +32,7 @@ #include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_idtype.h" +#include "BKE_lib_id.h" #include "BKE_nla.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -621,6 +622,64 @@ float *ANIM_setting_get_rna_values( return values; } +/* Values are casted to float since that is what the animation system deals with. */ +static void get_rna_values(PointerRNA *ptr, PropertyRNA *prop, blender::Vector &values) +{ + if (RNA_property_array_check(prop)) { + const int length = RNA_property_array_length(ptr, prop); + + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: { + bool *tmp_bool = static_cast(MEM_malloc_arrayN(length, sizeof(bool), __func__)); + RNA_property_boolean_get_array(ptr, prop, tmp_bool); + for (int i = 0; i < length; i++) { + values.append(float(tmp_bool[i])); + } + MEM_freeN(tmp_bool); + break; + } + case PROP_INT: { + int *tmp_int = static_cast(MEM_malloc_arrayN(length, sizeof(int), __func__)); + RNA_property_int_get_array(ptr, prop, tmp_int); + for (int i = 0; i < length; i++) { + values.append(float(tmp_int[i])); + } + MEM_freeN(tmp_int); + break; + } + case PROP_FLOAT: { + float *tmp_float = static_cast( + MEM_malloc_arrayN(length, sizeof(float), __func__)); + RNA_property_float_get_array(ptr, prop, tmp_float); + for (int i = 0; i < length; i++) { + values.append(tmp_float[i]); + } + break; + } + default: + break; + } + } + else { + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: + values.append(float(RNA_property_boolean_get(ptr, prop))); + break; + case PROP_INT: + values.append(float(RNA_property_int_get(ptr, prop))); + break; + case PROP_FLOAT: + values.append(RNA_property_float_get(ptr, prop)); + break; + case PROP_ENUM: + values.append(float(RNA_property_enum_get(ptr, prop))); + break; + default: + break; + } + } +} + /* ------------------------- Insert Key API ------------------------- */ void ED_keyframes_add(FCurve *fcu, int num_keys_to_add) @@ -736,32 +795,80 @@ static int insert_key_with_keyingset(bContext *C, wmOperator *op, KeyingSet *ks) return OPERATOR_FINISHED; } +static void construct_rna_paths(blender::Vector &r_paths, ID *id) +{ + eKeyInsertChannels insert_channel_flags = eKeyInsertChannels(U.key_insert_channels); + if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_TRANSLATE) { + r_paths.append("location"); + } + if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_ROTATE) { + r_paths.append("rotation_euler"); + } + if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_SCALE) { + r_paths.append("scale"); + } + if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES) { + /* Magic needed? */ + } +} + static int insert_key_foo(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); + using namespace blender; - // for selected RNA -> call - ID *id; - const char *rna_path = ""; - Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - const float cfra = BKE_scene_frame_get(scene); - const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph, - cfra); - bAction *action = nullptr; - eInsertKeyFlags insert_key_flags = INSERTKEY_NOFLAGS; - const char *groupname = nullptr; - const int array_index = -1; - blender::animrig::insert_keyframe(bmain, - op->reports, - id, - action, - groupname, - rna_path, - array_index, - &anim_eval_context, - BEZT_KEYTYPE_KEYFRAME, - insert_key_flags); + + const float scene_frame = BKE_scene_frame_get(scene); + + ListBase selected_objects = {nullptr, nullptr}; + CTX_data_selected_objects(C, &selected_objects); + bool depsgraph_needs_update = false; + LISTBASE_FOREACH (CollectionPointerLink *, object_ptr_link, &selected_objects) { + ID *selected_id = object_ptr_link->ptr.owner_id; + if (!BKE_id_is_editable(bmain, selected_id)) { + BKE_reportf(op->reports, RPT_ERROR, "'%s' is not editable", selected_id->name + 2); + return 0; + } + bAction *action = ED_id_action_ensure(bmain, selected_id); + if (action == nullptr) { + BKE_reportf(op->reports, + RPT_ERROR, + "Could not insert keyframe, as this type does not support animation data (ID = " + "%s)", + selected_id->name); + continue; + } + PointerRNA id_ptr = RNA_id_pointer_create(selected_id); + Vector rna_paths; + construct_rna_paths(rna_paths, selected_id); + for (const std::string &rna_path : rna_paths) { + PointerRNA ptr; + PropertyRNA *prop = nullptr; + const bool path_resolved = RNA_path_resolve_property(&id_ptr, rna_path.c_str(), &ptr, &prop); + if (!path_resolved) { + BKE_reportf( + op->reports, + RPT_ERROR, + "Could not insert keyframe, as this type does not support animation data (ID = " + "%s, path = %s)", + selected_id->name, + rna_path.c_str()); + continue; + } + Vector rna_values; + get_rna_values(&ptr, prop, rna_values); + int result = animrig::action_insert_key(action, rna_path, scene_frame, rna_values); + if (result > 0) { + depsgraph_needs_update = true; + } + } + } + if (depsgraph_needs_update) { + DEG_relations_tag_update(bmain); + } + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, nullptr); + BLI_freelistN(&selected_objects); return OPERATOR_FINISHED; } @@ -770,7 +877,7 @@ static int insert_key_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene); - if (ks != nullptr) { + if (false) { return insert_key_with_keyingset(C, op, ks); } return insert_key_foo(C, op); diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index a21a0cc0a8e..60d3f65d6ce 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -955,7 +955,7 @@ typedef struct UserDef { /** Flags for autokeying. */ short autokey_flag; /** Flags for which channels to insert keys at. */ - short key_insert_channels; + short key_insert_channels; // eKeyInsertChannels char _pad15[6]; /** Flags for animation. */ short animation_flag; -- 2.30.2 From 6f90fc0b5304e362f28d1b0a6521b4a430bf29ea Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 19 Oct 2023 15:51:35 +0200 Subject: [PATCH 08/41] remove unneeded namespace --- source/blender/animrig/ANIM_keyframing.hh | 2 +- source/blender/animrig/intern/keyframing.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/animrig/ANIM_keyframing.hh b/source/blender/animrig/ANIM_keyframing.hh index 229e3a20590..2e52cac5de2 100644 --- a/source/blender/animrig/ANIM_keyframing.hh +++ b/source/blender/animrig/ANIM_keyframing.hh @@ -153,6 +153,6 @@ bool autokeyframe_property(bContext *C, int action_insert_key(bAction *action, std::string rna_path, float frame, - const blender::Vector &values); + const Vector &values); } // namespace blender::animrig diff --git a/source/blender/animrig/intern/keyframing.cc b/source/blender/animrig/intern/keyframing.cc index f98d7b80e68..f99652197a1 100644 --- a/source/blender/animrig/intern/keyframing.cc +++ b/source/blender/animrig/intern/keyframing.cc @@ -1100,7 +1100,7 @@ static bool insert_key_fcu_foo(FCurve *fcu, const float frame, const float value int action_insert_key(bAction *action, std::string rna_path, const float frame, - const blender::Vector &values) + const Vector &values) { BLI_assert(action != nullptr); -- 2.30.2 From fbd4f788c1da53254dd6f5f41372c2f3d0a943dd Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 19 Oct 2023 16:11:18 +0200 Subject: [PATCH 09/41] construct quaternion rna paths --- .../blender/editors/animation/keyframing.cc | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index df9670c623c..ce4b8ec7578 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -795,20 +795,38 @@ static int insert_key_with_keyingset(bContext *C, wmOperator *op, KeyingSet *ks) return OPERATOR_FINISHED; } -static void construct_rna_paths(blender::Vector &r_paths, ID *id) +static blender::Vector construct_rna_paths(Object *ob) { + blender::Vector r_paths; eKeyInsertChannels insert_channel_flags = eKeyInsertChannels(U.key_insert_channels); if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_TRANSLATE) { r_paths.append("location"); } if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_ROTATE) { - r_paths.append("rotation_euler"); + switch (ob->rotmode) { + case ROT_MODE_QUAT: + r_paths.append("rotation_quaternion"); + break; + case ROT_MODE_AXISANGLE: + r_paths.append("rotation_axis_angle"); + break; + case ROT_MODE_XYZ: + case ROT_MODE_XZY: + case ROT_MODE_YXZ: + case ROT_MODE_YZX: + case ROT_MODE_ZXY: + case ROT_MODE_ZYX: + r_paths.append("rotation_euler"); + default: + break; + } } if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_SCALE) { r_paths.append("scale"); } if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES) { /* Magic needed? */ + // id->properties } } @@ -840,8 +858,8 @@ static int insert_key_foo(bContext *C, wmOperator *op) continue; } PointerRNA id_ptr = RNA_id_pointer_create(selected_id); - Vector rna_paths; - construct_rna_paths(rna_paths, selected_id); + Object *ob = static_cast(object_ptr_link->ptr.data); + Vector rna_paths = construct_rna_paths(ob); for (const std::string &rna_path : rna_paths) { PointerRNA ptr; PropertyRNA *prop = nullptr; -- 2.30.2 From bce441fe6eac73bd19ded3c955f6f9afece6b7a4 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 19 Oct 2023 16:43:26 +0200 Subject: [PATCH 10/41] fix issue with the rna path on new fcurves --- source/blender/animrig/intern/keyframing.cc | 4 ++-- source/blender/editors/animation/keyframing.cc | 13 +++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/source/blender/animrig/intern/keyframing.cc b/source/blender/animrig/intern/keyframing.cc index f99652197a1..953f63a367b 100644 --- a/source/blender/animrig/intern/keyframing.cc +++ b/source/blender/animrig/intern/keyframing.cc @@ -1054,7 +1054,7 @@ static FCurve *action_fcurve_ensure( } /* store path - make copy, and store that */ - char fcu_rna_path[rna_path.length() + 1]; + char *fcu_rna_path = static_cast(MEM_mallocN(rna_path.length() + 1, "fcu_rna_path")); std::strcpy(fcu_rna_path, rna_path.c_str()); fcu->rna_path = fcu_rna_path; fcu->array_index = array_index; @@ -1106,7 +1106,7 @@ int action_insert_key(bAction *action, int property_array_index = 0; int inserted_keys = 0; - const char *group = ""; + const char *group = "Object Transforms"; for (const float value : values) { FCurve *fcu = action_fcurve_ensure(action, group, nullptr, rna_path, property_array_index); if (!fcu) { diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index ce4b8ec7578..ad72d6e20fc 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -797,18 +797,18 @@ static int insert_key_with_keyingset(bContext *C, wmOperator *op, KeyingSet *ks) static blender::Vector construct_rna_paths(Object *ob) { - blender::Vector r_paths; + blender::Vector paths; eKeyInsertChannels insert_channel_flags = eKeyInsertChannels(U.key_insert_channels); if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_TRANSLATE) { - r_paths.append("location"); + paths.append("location"); } if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_ROTATE) { switch (ob->rotmode) { case ROT_MODE_QUAT: - r_paths.append("rotation_quaternion"); + paths.append("rotation_quaternion"); break; case ROT_MODE_AXISANGLE: - r_paths.append("rotation_axis_angle"); + paths.append("rotation_axis_angle"); break; case ROT_MODE_XYZ: case ROT_MODE_XZY: @@ -816,18 +816,19 @@ static blender::Vector construct_rna_paths(Object *ob) case ROT_MODE_YZX: case ROT_MODE_ZXY: case ROT_MODE_ZYX: - r_paths.append("rotation_euler"); + paths.append("rotation_euler"); default: break; } } if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_SCALE) { - r_paths.append("scale"); + paths.append("scale"); } if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES) { /* Magic needed? */ // id->properties } + return paths; } static int insert_key_foo(bContext *C, wmOperator *op) -- 2.30.2 From 2eda9367aae8a99db03f374ab87f3f46895d553a Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 19 Oct 2023 16:43:50 +0200 Subject: [PATCH 11/41] rename function --- source/blender/animrig/ANIM_keyframing.hh | 2 +- source/blender/animrig/intern/keyframing.cc | 2 +- source/blender/editors/animation/keyframing.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/animrig/ANIM_keyframing.hh b/source/blender/animrig/ANIM_keyframing.hh index 2e52cac5de2..6841bfe91df 100644 --- a/source/blender/animrig/ANIM_keyframing.hh +++ b/source/blender/animrig/ANIM_keyframing.hh @@ -150,7 +150,7 @@ bool autokeyframe_property(bContext *C, /** \} */ -int action_insert_key(bAction *action, +int insert_key_action(bAction *action, std::string rna_path, float frame, const Vector &values); diff --git a/source/blender/animrig/intern/keyframing.cc b/source/blender/animrig/intern/keyframing.cc index 953f63a367b..1ac7fcfa104 100644 --- a/source/blender/animrig/intern/keyframing.cc +++ b/source/blender/animrig/intern/keyframing.cc @@ -1097,7 +1097,7 @@ static bool insert_key_fcu_foo(FCurve *fcu, const float frame, const float value return inserted_index >= 0; } -int action_insert_key(bAction *action, +int insert_key_action(bAction *action, std::string rna_path, const float frame, const Vector &values) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index ad72d6e20fc..13ebf3eea5b 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -877,7 +877,7 @@ static int insert_key_foo(bContext *C, wmOperator *op) } Vector rna_values; get_rna_values(&ptr, prop, rna_values); - int result = animrig::action_insert_key(action, rna_path, scene_frame, rna_values); + int result = animrig::insert_key_action(action, rna_path, scene_frame, rna_values); if (result > 0) { depsgraph_needs_update = true; } -- 2.30.2 From 2e79abd174e1e53d7d4eda9959f8fadcba512df4 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 19 Oct 2023 17:41:22 +0200 Subject: [PATCH 12/41] got custom properties to work --- source/blender/editors/animation/keyframing.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index 13ebf3eea5b..a0fe2b500a9 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -15,6 +15,7 @@ #include "BLT_translation.h" +#include "DNA_ID.h" #include "DNA_action_types.h" #include "DNA_anim_types.h" #include "DNA_armature_types.h" @@ -825,8 +826,13 @@ static blender::Vector construct_rna_paths(Object *ob) paths.append("scale"); } if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES) { - /* Magic needed? */ - // id->properties + if (ob->id.properties) { + LISTBASE_FOREACH (IDProperty *, prop, &ob->id.properties->data.group) { + std::string name = prop->name; + std::string rna_path = "[\"" + name + "\"]"; + paths.append(rna_path); + } + } } return paths; } -- 2.30.2 From 2dfe7cd3a34061e1b59d401d3d36bc7bf4112f05 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 19 Oct 2023 17:49:49 +0200 Subject: [PATCH 13/41] pass keyframe values as a span --- source/blender/animrig/ANIM_keyframing.hh | 2 +- source/blender/animrig/intern/keyframing.cc | 2 +- source/blender/editors/animation/keyframing.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/animrig/ANIM_keyframing.hh b/source/blender/animrig/ANIM_keyframing.hh index 6841bfe91df..2b837e6ad5d 100644 --- a/source/blender/animrig/ANIM_keyframing.hh +++ b/source/blender/animrig/ANIM_keyframing.hh @@ -153,6 +153,6 @@ bool autokeyframe_property(bContext *C, int insert_key_action(bAction *action, std::string rna_path, float frame, - const Vector &values); + const Span values); } // namespace blender::animrig diff --git a/source/blender/animrig/intern/keyframing.cc b/source/blender/animrig/intern/keyframing.cc index 1ac7fcfa104..fe0e1f4850e 100644 --- a/source/blender/animrig/intern/keyframing.cc +++ b/source/blender/animrig/intern/keyframing.cc @@ -1100,7 +1100,7 @@ static bool insert_key_fcu_foo(FCurve *fcu, const float frame, const float value int insert_key_action(bAction *action, std::string rna_path, const float frame, - const Vector &values) + const Span values) { BLI_assert(action != nullptr); diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index a0fe2b500a9..c8d27f268aa 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -883,7 +883,7 @@ static int insert_key_foo(bContext *C, wmOperator *op) } Vector rna_values; get_rna_values(&ptr, prop, rna_values); - int result = animrig::insert_key_action(action, rna_path, scene_frame, rna_values); + int result = animrig::insert_key_action(action, rna_path, scene_frame, rna_values.as_span()); if (result > 0) { depsgraph_needs_update = true; } -- 2.30.2 From a8838cfd778c42f7998d4631087f2bdf4bdffa17 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 20 Oct 2023 14:02:15 +0200 Subject: [PATCH 14/41] pose bones wip --- .../blender/editors/animation/keyframing.cc | 54 ++++++++++++++++--- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index c8d27f268aa..955f65fddfc 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -837,23 +837,22 @@ static blender::Vector construct_rna_paths(Object *ob) return paths; } -static int insert_key_foo(bContext *C, wmOperator *op) +static void insert_key_object_mode(bContext *C, wmOperator *op) { using namespace blender; - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); + bool depsgraph_needs_update = false; + Scene *scene = CTX_data_scene(C); const float scene_frame = BKE_scene_frame_get(scene); ListBase selected_objects = {nullptr, nullptr}; CTX_data_selected_objects(C, &selected_objects); - bool depsgraph_needs_update = false; LISTBASE_FOREACH (CollectionPointerLink *, object_ptr_link, &selected_objects) { ID *selected_id = object_ptr_link->ptr.owner_id; if (!BKE_id_is_editable(bmain, selected_id)) { BKE_reportf(op->reports, RPT_ERROR, "'%s' is not editable", selected_id->name + 2); - return 0; + return; } bAction *action = ED_id_action_ensure(bmain, selected_id); if (action == nullptr) { @@ -864,7 +863,7 @@ static int insert_key_foo(bContext *C, wmOperator *op) selected_id->name); continue; } - PointerRNA id_ptr = RNA_id_pointer_create(selected_id); + PointerRNA id_ptr = object_ptr_link->ptr; Object *ob = static_cast(object_ptr_link->ptr.data); Vector rna_paths = construct_rna_paths(ob); for (const std::string &rna_path : rna_paths) { @@ -889,11 +888,52 @@ static int insert_key_foo(bContext *C, wmOperator *op) } } } + BLI_freelistN(&selected_objects); +} + +static void insert_key_pose_mode(bContext *C, wmOperator *op) +{ + using namespace blender; + Main *bmain = CTX_data_main(C); + bool depsgraph_needs_update = false; + + Scene *scene = CTX_data_scene(C); + const float scene_frame = BKE_scene_frame_get(scene); + + ListBase selected_pose_bones = {nullptr, nullptr}; + CTX_data_selected_pose_bones(C, &selected_pose_bones); + LISTBASE_FOREACH (CollectionPointerLink *, object_ptr_link, &selected_pose_bones) { + } + BLI_freelistN(&selected_pose_bones); +} + +static int insert_key_foo(bContext *C, wmOperator *op) +{ + using namespace blender; + + bool depsgraph_needs_update = false; + + eContextObjectMode context_mode = CTX_data_mode_enum(C); + switch (context_mode) { + + case CTX_MODE_OBJECT: + insert_key_object_mode(C, op); + break; + + case CTX_MODE_POSE: + insert_key_pose_mode(C, op); + break; + + default: + BKE_reportf(op->reports, RPT_ERROR, "Unsupported context mode"); + break; + } + + Main *bmain = CTX_data_main(C); if (depsgraph_needs_update) { DEG_relations_tag_update(bmain); } WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, nullptr); - BLI_freelistN(&selected_objects); return OPERATOR_FINISHED; } -- 2.30.2 From 87c8142dc8e02a367e3bde50162d3f6150deab4d Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 20 Oct 2023 14:58:55 +0200 Subject: [PATCH 15/41] working for pose bones --- .../blender/editors/animation/keyframing.cc | 98 +++++++++++++++++-- 1 file changed, 91 insertions(+), 7 deletions(-) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index 955f65fddfc..fa7b699050a 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -837,6 +837,47 @@ static blender::Vector construct_rna_paths(Object *ob) return paths; } +static blender::Vector construct_rna_paths(bPoseChannel *pose_channel) +{ + blender::Vector paths; + eKeyInsertChannels insert_channel_flags = eKeyInsertChannels(U.key_insert_channels); + if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_TRANSLATE) { + paths.append("location"); + } + if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_ROTATE) { + switch (pose_channel->rotmode) { + case ROT_MODE_QUAT: + paths.append("rotation_quaternion"); + break; + case ROT_MODE_AXISANGLE: + paths.append("rotation_axis_angle"); + break; + case ROT_MODE_XYZ: + case ROT_MODE_XZY: + case ROT_MODE_YXZ: + case ROT_MODE_YZX: + case ROT_MODE_ZXY: + case ROT_MODE_ZYX: + paths.append("rotation_euler"); + default: + break; + } + } + if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_SCALE) { + paths.append("scale"); + } + if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES) { + if (pose_channel->prop) { + LISTBASE_FOREACH (IDProperty *, prop, &pose_channel->prop->data.group) { + std::string name = prop->name; + std::string rna_path = "[\"" + name + "\"]"; + paths.append(rna_path); + } + } + } + return paths; +} + static void insert_key_object_mode(bContext *C, wmOperator *op) { using namespace blender; @@ -848,8 +889,8 @@ static void insert_key_object_mode(bContext *C, wmOperator *op) ListBase selected_objects = {nullptr, nullptr}; CTX_data_selected_objects(C, &selected_objects); - LISTBASE_FOREACH (CollectionPointerLink *, object_ptr_link, &selected_objects) { - ID *selected_id = object_ptr_link->ptr.owner_id; + LISTBASE_FOREACH (CollectionPointerLink *, collection_ptr_link, &selected_objects) { + ID *selected_id = collection_ptr_link->ptr.owner_id; if (!BKE_id_is_editable(bmain, selected_id)) { BKE_reportf(op->reports, RPT_ERROR, "'%s' is not editable", selected_id->name + 2); return; @@ -863,13 +904,14 @@ static void insert_key_object_mode(bContext *C, wmOperator *op) selected_id->name); continue; } - PointerRNA id_ptr = object_ptr_link->ptr; - Object *ob = static_cast(object_ptr_link->ptr.data); + PointerRNA id_ptr = collection_ptr_link->ptr; + Object *ob = static_cast(collection_ptr_link->ptr.data); Vector rna_paths = construct_rna_paths(ob); for (const std::string &rna_path : rna_paths) { PointerRNA ptr; PropertyRNA *prop = nullptr; const bool path_resolved = RNA_path_resolve_property(&id_ptr, rna_path.c_str(), &ptr, &prop); + std::string id_to_prop = RNA_path_from_ID_to_property(&ptr, prop); if (!path_resolved) { BKE_reportf( op->reports, @@ -877,12 +919,13 @@ static void insert_key_object_mode(bContext *C, wmOperator *op) "Could not insert keyframe, as this type does not support animation data (ID = " "%s, path = %s)", selected_id->name, - rna_path.c_str()); + id_to_prop.c_str()); continue; } Vector rna_values; get_rna_values(&ptr, prop, rna_values); - int result = animrig::insert_key_action(action, rna_path, scene_frame, rna_values.as_span()); + int result = animrig::insert_key_action( + action, id_to_prop, scene_frame, rna_values.as_span()); if (result > 0) { depsgraph_needs_update = true; } @@ -902,8 +945,49 @@ static void insert_key_pose_mode(bContext *C, wmOperator *op) ListBase selected_pose_bones = {nullptr, nullptr}; CTX_data_selected_pose_bones(C, &selected_pose_bones); - LISTBASE_FOREACH (CollectionPointerLink *, object_ptr_link, &selected_pose_bones) { + LISTBASE_FOREACH (CollectionPointerLink *, collection_ptr_link, &selected_pose_bones) { + ID *selected_id = collection_ptr_link->ptr.owner_id; + if (!BKE_id_is_editable(bmain, selected_id)) { + BKE_reportf(op->reports, RPT_ERROR, "'%s' is not editable", selected_id->name + 2); + return; } + bAction *action = ED_id_action_ensure(bmain, selected_id); + if (action == nullptr) { + BKE_reportf(op->reports, + RPT_ERROR, + "Could not insert keyframe, as this type does not support animation data (ID = " + "%s)", + selected_id->name); + continue; + } + PointerRNA id_ptr = collection_ptr_link->ptr; + bPoseChannel *pchan = static_cast(collection_ptr_link->ptr.data); + Vector rna_paths = construct_rna_paths(pchan); + + for (const std::string &rna_path : rna_paths) { + PointerRNA ptr; + PropertyRNA *prop = nullptr; + const bool path_resolved = RNA_path_resolve_property(&id_ptr, rna_path.c_str(), &ptr, &prop); + std::string id_to_prop = RNA_path_from_ID_to_property(&ptr, prop); + if (!path_resolved) { + BKE_reportf( + op->reports, + RPT_ERROR, + "Could not insert keyframe, as this type does not support animation data (ID = " + "%s, path = %s)", + selected_id->name, + id_to_prop.c_str()); + continue; + } + Vector rna_values; + get_rna_values(&ptr, prop, rna_values); + int result = animrig::insert_key_action( + action, id_to_prop, scene_frame, rna_values.as_span()); + if (result > 0) { + depsgraph_needs_update = true; + } + } + } BLI_freelistN(&selected_pose_bones); } -- 2.30.2 From 823600eb37660f4f4da89c2d46dd235c024b6842 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 20 Oct 2023 15:07:14 +0200 Subject: [PATCH 16/41] deduplicate function --- .../blender/editors/animation/keyframing.cc | 56 +++---------------- 1 file changed, 9 insertions(+), 47 deletions(-) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index fa7b699050a..d403e1c44eb 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -796,7 +796,8 @@ static int insert_key_with_keyingset(bContext *C, wmOperator *op, KeyingSet *ks) return OPERATOR_FINISHED; } -static blender::Vector construct_rna_paths(Object *ob) +static blender::Vector construct_rna_paths(const eRotationModes rotation_mode, + IDProperty *properties) { blender::Vector paths; eKeyInsertChannels insert_channel_flags = eKeyInsertChannels(U.key_insert_channels); @@ -804,7 +805,7 @@ static blender::Vector construct_rna_paths(Object *ob) paths.append("location"); } if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_ROTATE) { - switch (ob->rotmode) { + switch (rotation_mode) { case ROT_MODE_QUAT: paths.append("rotation_quaternion"); break; @@ -826,49 +827,8 @@ static blender::Vector construct_rna_paths(Object *ob) paths.append("scale"); } if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES) { - if (ob->id.properties) { - LISTBASE_FOREACH (IDProperty *, prop, &ob->id.properties->data.group) { - std::string name = prop->name; - std::string rna_path = "[\"" + name + "\"]"; - paths.append(rna_path); - } - } - } - return paths; -} - -static blender::Vector construct_rna_paths(bPoseChannel *pose_channel) -{ - blender::Vector paths; - eKeyInsertChannels insert_channel_flags = eKeyInsertChannels(U.key_insert_channels); - if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_TRANSLATE) { - paths.append("location"); - } - if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_ROTATE) { - switch (pose_channel->rotmode) { - case ROT_MODE_QUAT: - paths.append("rotation_quaternion"); - break; - case ROT_MODE_AXISANGLE: - paths.append("rotation_axis_angle"); - break; - case ROT_MODE_XYZ: - case ROT_MODE_XZY: - case ROT_MODE_YXZ: - case ROT_MODE_YZX: - case ROT_MODE_ZXY: - case ROT_MODE_ZYX: - paths.append("rotation_euler"); - default: - break; - } - } - if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_SCALE) { - paths.append("scale"); - } - if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES) { - if (pose_channel->prop) { - LISTBASE_FOREACH (IDProperty *, prop, &pose_channel->prop->data.group) { + if (properties) { + LISTBASE_FOREACH (IDProperty *, prop, &properties->data.group) { std::string name = prop->name; std::string rna_path = "[\"" + name + "\"]"; paths.append(rna_path); @@ -906,7 +866,8 @@ static void insert_key_object_mode(bContext *C, wmOperator *op) } PointerRNA id_ptr = collection_ptr_link->ptr; Object *ob = static_cast(collection_ptr_link->ptr.data); - Vector rna_paths = construct_rna_paths(ob); + Vector rna_paths = construct_rna_paths(eRotationModes(ob->rotmode), + ob->id.properties); for (const std::string &rna_path : rna_paths) { PointerRNA ptr; PropertyRNA *prop = nullptr; @@ -962,7 +923,8 @@ static void insert_key_pose_mode(bContext *C, wmOperator *op) } PointerRNA id_ptr = collection_ptr_link->ptr; bPoseChannel *pchan = static_cast(collection_ptr_link->ptr.data); - Vector rna_paths = construct_rna_paths(pchan); + Vector rna_paths = construct_rna_paths(eRotationModes(pchan->rotmode), + pchan->prop); for (const std::string &rna_path : rna_paths) { PointerRNA ptr; -- 2.30.2 From 5a1960e3f1f523ae9c65a2dc816fc062b8ac1773 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 20 Oct 2023 15:29:25 +0200 Subject: [PATCH 17/41] extract functionality --- .../blender/editors/animation/keyframing.cc | 106 +++++++----------- 1 file changed, 42 insertions(+), 64 deletions(-) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index d403e1c44eb..2642104f786 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -838,6 +838,46 @@ static blender::Vector construct_rna_paths(const eRotationModes rot return paths; } +static void insert_key_id(PointerRNA *id_ptr, + const blender::Span rna_paths, + const float scene_frame, + Main *bmain, + ReportList *reports) +{ + using namespace blender; + + ID *id = id_ptr->owner_id; + bAction *action = ED_id_action_ensure(bmain, id); + if (action == nullptr) { + BKE_reportf(reports, + RPT_ERROR, + "Could not insert keyframe, as this type does not support animation data (ID = " + "%s)", + id->name); + return; + } + + for (const std::string &rna_path : rna_paths) { + PointerRNA ptr; + PropertyRNA *prop = nullptr; + const bool path_resolved = RNA_path_resolve_property(id_ptr, rna_path.c_str(), &ptr, &prop); + std::string id_to_prop = RNA_path_from_ID_to_property(&ptr, prop); + if (!path_resolved) { + BKE_reportf(reports, + RPT_ERROR, + "Could not insert keyframe, as this type does not support animation data (ID = " + "%s, path = %s)", + id->name, + id_to_prop.c_str()); + continue; + } + Vector rna_values; + get_rna_values(&ptr, prop, rna_values); + const int inserted_keys = animrig::insert_key_action( + action, id_to_prop, scene_frame, rna_values.as_span()); + } +} + static void insert_key_object_mode(bContext *C, wmOperator *op) { using namespace blender; @@ -855,42 +895,11 @@ static void insert_key_object_mode(bContext *C, wmOperator *op) BKE_reportf(op->reports, RPT_ERROR, "'%s' is not editable", selected_id->name + 2); return; } - bAction *action = ED_id_action_ensure(bmain, selected_id); - if (action == nullptr) { - BKE_reportf(op->reports, - RPT_ERROR, - "Could not insert keyframe, as this type does not support animation data (ID = " - "%s)", - selected_id->name); - continue; - } PointerRNA id_ptr = collection_ptr_link->ptr; Object *ob = static_cast(collection_ptr_link->ptr.data); Vector rna_paths = construct_rna_paths(eRotationModes(ob->rotmode), ob->id.properties); - for (const std::string &rna_path : rna_paths) { - PointerRNA ptr; - PropertyRNA *prop = nullptr; - const bool path_resolved = RNA_path_resolve_property(&id_ptr, rna_path.c_str(), &ptr, &prop); - std::string id_to_prop = RNA_path_from_ID_to_property(&ptr, prop); - if (!path_resolved) { - BKE_reportf( - op->reports, - RPT_ERROR, - "Could not insert keyframe, as this type does not support animation data (ID = " - "%s, path = %s)", - selected_id->name, - id_to_prop.c_str()); - continue; - } - Vector rna_values; - get_rna_values(&ptr, prop, rna_values); - int result = animrig::insert_key_action( - action, id_to_prop, scene_frame, rna_values.as_span()); - if (result > 0) { - depsgraph_needs_update = true; - } - } + insert_key_id(&id_ptr, rna_paths.as_span(), scene_frame, bmain, op->reports); } BLI_freelistN(&selected_objects); } @@ -912,43 +921,12 @@ static void insert_key_pose_mode(bContext *C, wmOperator *op) BKE_reportf(op->reports, RPT_ERROR, "'%s' is not editable", selected_id->name + 2); return; } - bAction *action = ED_id_action_ensure(bmain, selected_id); - if (action == nullptr) { - BKE_reportf(op->reports, - RPT_ERROR, - "Could not insert keyframe, as this type does not support animation data (ID = " - "%s)", - selected_id->name); - continue; - } PointerRNA id_ptr = collection_ptr_link->ptr; bPoseChannel *pchan = static_cast(collection_ptr_link->ptr.data); Vector rna_paths = construct_rna_paths(eRotationModes(pchan->rotmode), pchan->prop); - for (const std::string &rna_path : rna_paths) { - PointerRNA ptr; - PropertyRNA *prop = nullptr; - const bool path_resolved = RNA_path_resolve_property(&id_ptr, rna_path.c_str(), &ptr, &prop); - std::string id_to_prop = RNA_path_from_ID_to_property(&ptr, prop); - if (!path_resolved) { - BKE_reportf( - op->reports, - RPT_ERROR, - "Could not insert keyframe, as this type does not support animation data (ID = " - "%s, path = %s)", - selected_id->name, - id_to_prop.c_str()); - continue; - } - Vector rna_values; - get_rna_values(&ptr, prop, rna_values); - int result = animrig::insert_key_action( - action, id_to_prop, scene_frame, rna_values.as_span()); - if (result > 0) { - depsgraph_needs_update = true; - } - } + insert_key_id(&id_ptr, rna_paths.as_span(), scene_frame, bmain, op->reports); } BLI_freelistN(&selected_pose_bones); } -- 2.30.2 From 11f43efb74b46fd126d8142f42109aca9ee252e8 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 20 Oct 2023 16:30:02 +0200 Subject: [PATCH 18/41] action group and bone color working --- source/blender/animrig/ANIM_keyframing.hh | 3 +- source/blender/animrig/intern/keyframing.cc | 38 +++++++++++-------- .../blender/editors/animation/keyframing.cc | 21 ++++++---- 3 files changed, 37 insertions(+), 25 deletions(-) diff --git a/source/blender/animrig/ANIM_keyframing.hh b/source/blender/animrig/ANIM_keyframing.hh index 2b837e6ad5d..5dcd552ee99 100644 --- a/source/blender/animrig/ANIM_keyframing.hh +++ b/source/blender/animrig/ANIM_keyframing.hh @@ -151,7 +151,8 @@ bool autokeyframe_property(bContext *C, /** \} */ int insert_key_action(bAction *action, - std::string rna_path, + PointerRNA *ptr, + const std::string &rna_path, float frame, const Span values); diff --git a/source/blender/animrig/intern/keyframing.cc b/source/blender/animrig/intern/keyframing.cc index fe0e1f4850e..5b398d87d54 100644 --- a/source/blender/animrig/intern/keyframing.cc +++ b/source/blender/animrig/intern/keyframing.cc @@ -1029,17 +1029,17 @@ int clear_keyframe(Main *bmain, return key_count; } -static FCurve *action_fcurve_ensure( - bAction *act, const char group[], PointerRNA *ptr, std::string rna_path, const int array_index) +static FCurve *action_fcurve_ensure(bAction *action, + const char group[], + PointerRNA *ptr, + const std::string &rna_path, + const int array_index) { - bActionGroup *agrp; - FCurve *fcu; - /* try to find f-curve matching for this setting * - add if not found and allowed to add one * TODO: add auto-grouping support? how this works will need to be resolved */ - fcu = BKE_fcurve_find(&act->curves, rna_path.c_str(), array_index); + FCurve *fcu = BKE_fcurve_find(&action->curves, rna_path.c_str(), array_index); if (fcu) { return fcu; } @@ -1049,7 +1049,7 @@ static FCurve *action_fcurve_ensure( fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); fcu->auto_smoothing = U.auto_smoothing_new; - if (BLI_listbase_is_empty(&act->curves)) { + if (BLI_listbase_is_empty(&action->curves)) { fcu->flag |= FCURVE_ACTIVE; /* first one added active */ } @@ -1062,25 +1062,25 @@ static FCurve *action_fcurve_ensure( /* if a group name has been provided, try to add or find a group, then add F-Curve to it */ if (group) { /* try to find group */ - agrp = BKE_action_group_find_name(act, group); + bActionGroup *action_group = BKE_action_group_find_name(action, group); /* no matching groups, so add one */ - if (agrp == nullptr) { - agrp = action_groups_add_new(act, group); + if (action_group == nullptr) { + action_group = action_groups_add_new(action, group); /* sync bone group colors if applicable */ if (ptr && (ptr->type == &RNA_PoseBone)) { bPoseChannel *pchan = static_cast(ptr->data); - action_group_colors_set_from_posebone(agrp, pchan); + action_group_colors_set_from_posebone(action_group, pchan); } } /* add F-Curve to group */ - action_groups_add_channel(act, agrp, fcu); + action_groups_add_channel(action, action_group, fcu); } else { /* just add F-Curve to end of Action's list */ - BLI_addtail(&act->curves, fcu); + BLI_addtail(&action->curves, fcu); } /* return the F-Curve */ @@ -1098,17 +1098,23 @@ static bool insert_key_fcu_foo(FCurve *fcu, const float frame, const float value } int insert_key_action(bAction *action, - std::string rna_path, + PointerRNA *ptr, + const std::string &rna_path, const float frame, const Span values) { BLI_assert(action != nullptr); + std::string group = "Object Transforms"; + if (ptr->type == &RNA_PoseBone) { + bPoseChannel *pose_channel = static_cast(ptr->data); + group = pose_channel->name; + } + int property_array_index = 0; int inserted_keys = 0; - const char *group = "Object Transforms"; for (const float value : values) { - FCurve *fcu = action_fcurve_ensure(action, group, nullptr, rna_path, property_array_index); + FCurve *fcu = action_fcurve_ensure(action, group.c_str(), ptr, rna_path, property_array_index); if (!fcu) { continue; } diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index 2642104f786..248dfee9e5c 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -797,7 +797,7 @@ static int insert_key_with_keyingset(bContext *C, wmOperator *op, KeyingSet *ks) } static blender::Vector construct_rna_paths(const eRotationModes rotation_mode, - IDProperty *properties) + IDProperty *properties = nullptr) { blender::Vector paths; eKeyInsertChannels insert_channel_flags = eKeyInsertChannels(U.key_insert_channels); @@ -826,6 +826,9 @@ static blender::Vector construct_rna_paths(const eRotationModes rot if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_SCALE) { paths.append("scale"); } + if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_ROTATION_MODE) { + paths.append("rotation_mode"); + } if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES) { if (properties) { LISTBASE_FOREACH (IDProperty *, prop, &properties->data.group) { @@ -838,7 +841,7 @@ static blender::Vector construct_rna_paths(const eRotationModes rot return paths; } -static void insert_key_id(PointerRNA *id_ptr, +static void insert_key_id(PointerRNA *rna_pointer, const blender::Span rna_paths, const float scene_frame, Main *bmain, @@ -846,7 +849,7 @@ static void insert_key_id(PointerRNA *id_ptr, { using namespace blender; - ID *id = id_ptr->owner_id; + ID *id = rna_pointer->owner_id; bAction *action = ED_id_action_ensure(bmain, id); if (action == nullptr) { BKE_reportf(reports, @@ -860,21 +863,23 @@ static void insert_key_id(PointerRNA *id_ptr, for (const std::string &rna_path : rna_paths) { PointerRNA ptr; PropertyRNA *prop = nullptr; - const bool path_resolved = RNA_path_resolve_property(id_ptr, rna_path.c_str(), &ptr, &prop); - std::string id_to_prop = RNA_path_from_ID_to_property(&ptr, prop); + const bool path_resolved = RNA_path_resolve_property( + rna_pointer, rna_path.c_str(), &ptr, &prop); if (!path_resolved) { BKE_reportf(reports, RPT_ERROR, - "Could not insert keyframe, as this type does not support animation data (ID = " + "Could not insert keyframe, as this property does not exist (ID = " "%s, path = %s)", id->name, - id_to_prop.c_str()); + rna_path.c_str()); continue; } + std::string rna_path_id_to_prop = RNA_path_from_ID_to_property(&ptr, prop); Vector rna_values; get_rna_values(&ptr, prop, rna_values); + const int inserted_keys = animrig::insert_key_action( - action, id_to_prop, scene_frame, rna_values.as_span()); + action, rna_pointer, rna_path_id_to_prop, scene_frame, rna_values.as_span()); } } -- 2.30.2 From f86e31ca42de4be34d7c7de16105fc34641cd060 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 20 Oct 2023 17:01:56 +0200 Subject: [PATCH 19/41] skip popup menu --- scripts/presets/keyconfig/keymap_data/blender_default.py | 4 ++-- source/blender/editors/animation/keyframing.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/presets/keyconfig/keymap_data/blender_default.py b/scripts/presets/keyconfig/keymap_data/blender_default.py index f6e2005344b..00a3fcd3a3b 100644 --- a/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -4674,7 +4674,7 @@ def km_object_mode(params): ("object.join", {"type": 'J', "value": 'PRESS', "ctrl": True}, None), ("wm.context_toggle", {"type": 'PERIOD', "value": 'PRESS', "ctrl": True}, {"properties": [("data_path", 'tool_settings.use_transform_data_origin')]}), - ("anim.keyframe_insert_menu", {"type": 'I', "value": 'PRESS'}, None), + ("anim.keyframe_insert", {"type": 'I', "value": 'PRESS'}, None), ("anim.keyframe_delete_v3d", {"type": 'I', "value": 'PRESS', "alt": True}, None), ("anim.keying_set_active_set", {"type": 'I', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None), ("collection.create", {"type": 'G', "value": 'PRESS', "ctrl": True}, None), @@ -4813,7 +4813,7 @@ def km_pose(params): op_menu("VIEW3D_MT_bone_collections", {"type": 'M', "value": 'PRESS', "shift": True}), ("armature.move_to_collection", {"type": 'M', "value": 'PRESS'}, None), ("transform.bbone_resize", {"type": 'S', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None), - ("anim.keyframe_insert_menu", {"type": 'I', "value": 'PRESS'}, None), + ("anim.keyframe_insert", {"type": 'I', "value": 'PRESS'}, None), ("anim.keyframe_delete_v3d", {"type": 'I', "value": 'PRESS', "alt": True}, None), ("anim.keying_set_active_set", {"type": 'I', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None), ("pose.push", {"type": 'E', "value": 'PRESS', "ctrl": True}, None), diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index 248dfee9e5c..2ff7f90de84 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -970,8 +970,8 @@ static int insert_key_foo(bContext *C, wmOperator *op) static int insert_key_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene); - if (false) { + KeyingSet *ks = ANIM_keyingset_get_from_enum_type(scene, scene->active_keyingset); + if (ks) { return insert_key_with_keyingset(C, op, ks); } return insert_key_foo(C, op); -- 2.30.2 From 26a0272cb95a5c38e61421d3746832802737e90f Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Tue, 24 Oct 2023 09:05:52 +0200 Subject: [PATCH 20/41] use refactored ANIM_setting_get_rna_values --- .../blender/editors/animation/keyframing.cc | 61 +------------------ 1 file changed, 1 insertion(+), 60 deletions(-) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index d546fd71bfb..664179e0467 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -616,64 +616,6 @@ blender::Vector ANIM_setting_get_rna_values(PointerRNA *ptr, PropertyRNA return values; } -/* Values are casted to float since that is what the animation system deals with. */ -static void get_rna_values(PointerRNA *ptr, PropertyRNA *prop, blender::Vector &values) -{ - if (RNA_property_array_check(prop)) { - const int length = RNA_property_array_length(ptr, prop); - - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: { - bool *tmp_bool = static_cast(MEM_malloc_arrayN(length, sizeof(bool), __func__)); - RNA_property_boolean_get_array(ptr, prop, tmp_bool); - for (int i = 0; i < length; i++) { - values.append(float(tmp_bool[i])); - } - MEM_freeN(tmp_bool); - break; - } - case PROP_INT: { - int *tmp_int = static_cast(MEM_malloc_arrayN(length, sizeof(int), __func__)); - RNA_property_int_get_array(ptr, prop, tmp_int); - for (int i = 0; i < length; i++) { - values.append(float(tmp_int[i])); - } - MEM_freeN(tmp_int); - break; - } - case PROP_FLOAT: { - float *tmp_float = static_cast( - MEM_malloc_arrayN(length, sizeof(float), __func__)); - RNA_property_float_get_array(ptr, prop, tmp_float); - for (int i = 0; i < length; i++) { - values.append(tmp_float[i]); - } - break; - } - default: - break; - } - } - else { - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - values.append(float(RNA_property_boolean_get(ptr, prop))); - break; - case PROP_INT: - values.append(float(RNA_property_int_get(ptr, prop))); - break; - case PROP_FLOAT: - values.append(RNA_property_float_get(ptr, prop)); - break; - case PROP_ENUM: - values.append(float(RNA_property_enum_get(ptr, prop))); - break; - default: - break; - } - } -} - /* ------------------------- Insert Key API ------------------------- */ void ED_keyframes_add(FCurve *fcu, int num_keys_to_add) @@ -868,8 +810,7 @@ static void insert_key_id(PointerRNA *rna_pointer, continue; } std::string rna_path_id_to_prop = RNA_path_from_ID_to_property(&ptr, prop); - Vector rna_values; - get_rna_values(&ptr, prop, rna_values); + Vector rna_values = ANIM_setting_get_rna_values(&ptr, prop); const int inserted_keys = animrig::insert_key_action( action, rna_pointer, rna_path_id_to_prop, scene_frame, rna_values.as_span()); -- 2.30.2 From 610ac02b5bd72bd0b88aac34c2943eaed9eed817 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 2 Nov 2023 15:37:35 +0100 Subject: [PATCH 21/41] correct mapping to NLA time --- source/blender/animrig/ANIM_keyframing.hh | 4 ++++ source/blender/editors/animation/keyframing.cc | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/source/blender/animrig/ANIM_keyframing.hh b/source/blender/animrig/ANIM_keyframing.hh index 5dcd552ee99..cf770723d54 100644 --- a/source/blender/animrig/ANIM_keyframing.hh +++ b/source/blender/animrig/ANIM_keyframing.hh @@ -150,6 +150,10 @@ bool autokeyframe_property(bContext *C, /** \} */ +/** + * Insert a key in the given action. + * \param frame is expected to be in NLA space. + */ int insert_key_action(bAction *action, PointerRNA *ptr, const std::string &rna_path, diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index 664179e0467..d44c6287fb8 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -795,6 +795,9 @@ static void insert_key_id(PointerRNA *rna_pointer, return; } + AnimData *adt = BKE_animdata_from_id(id); + const float nla_frame = BKE_nla_tweakedit_remap(adt, scene_frame, NLATIME_CONVERT_UNMAP); + for (const std::string &rna_path : rna_paths) { PointerRNA ptr; PropertyRNA *prop = nullptr; @@ -813,7 +816,7 @@ static void insert_key_id(PointerRNA *rna_pointer, Vector rna_values = ANIM_setting_get_rna_values(&ptr, prop); const int inserted_keys = animrig::insert_key_action( - action, rna_pointer, rna_path_id_to_prop, scene_frame, rna_values.as_span()); + action, rna_pointer, rna_path_id_to_prop, nla_frame, rna_values.as_span()); } } -- 2.30.2 From 3ce7c5589573c3a2e66dcedd6933f8da25eccdf2 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 2 Nov 2023 16:48:22 +0100 Subject: [PATCH 22/41] expose keyframe_insert operator in menus keyframe_insert_menu has gotten a new label --- .../keyconfig/keymap_data/industry_compatible_data.py | 4 ++-- scripts/startup/bl_ui/space_view3d.py | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py index a400d44ed08..02b91cd4c2e 100644 --- a/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py +++ b/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py @@ -3225,7 +3225,7 @@ def km_pose(params): ("pose.select_hierarchy", {"type": 'DOWN_ARROW', "value": 'PRESS', "shift": True, "repeat": True}, {"properties": [("direction", 'CHILD'), ("extend", True)]}), ("pose.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None), - ("anim.keyframe_insert_menu", {"type": 'S', "value": 'PRESS', "shift": True}, None), + ("anim.keyframe_insert", {"type": 'S', "value": 'PRESS', "shift": True}, None), ("anim.keyframe_insert_by_name", {"type": 'S', "value": 'PRESS'}, {"properties": [("type", 'LocRotScale')]}), ("anim.keyframe_insert_by_name", {"type": 'W', "value": 'PRESS', "shift": True}, @@ -3297,7 +3297,7 @@ def km_object_mode(params): {"properties": [("use_global", True), ("confirm", False)]}), ("object.duplicate_move", {"type": 'D', "value": 'PRESS', "ctrl": True}, None), # Keyframing - ("anim.keyframe_insert_menu", {"type": 'S', "value": 'PRESS', "shift": True}, None), + ("anim.keyframe_insert", {"type": 'S', "value": 'PRESS', "shift": True}, None), ("anim.keyframe_insert_by_name", {"type": 'S', "value": 'PRESS'}, {"properties": [("type", 'LocRotScale')]}), ("anim.keyframe_insert_by_name", {"type": 'W', "value": 'PRESS', "shift": True}, diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index 7c1dc07aabf..f0e5c2e798c 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -2759,7 +2759,8 @@ class VIEW3D_MT_object_animation(Menu): def draw(self, _context): layout = self.layout - layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe...") + layout.operator("anim.keyframe_insert", text="Insert Keyframe") + layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe by Type...") layout.operator("anim.keyframe_delete_v3d", text="Delete Keyframes...") layout.operator("anim.keyframe_clear_v3d", text="Clear Keyframes...") layout.operator("anim.keying_set_active_set", text="Change Keying Set...") @@ -3023,7 +3024,8 @@ class VIEW3D_MT_object_context_menu(Menu): layout.separator() - layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe...") + layout.operator("anim.keyframe_insert", text="Insert Keyframe") + layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe by Type...") layout.separator() @@ -4174,7 +4176,8 @@ class VIEW3D_MT_pose_context_menu(Menu): layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe...") + layout.operator("anim.keyframe_insert", text="Insert Keyframe") + layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe by Type") layout.separator() -- 2.30.2 From 901532cc0b3823d26ae38f5d72de3fc17f08054e Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 2 Nov 2023 16:49:39 +0100 Subject: [PATCH 23/41] rename label to Insert Keyframe with Keying Set --- scripts/startup/bl_ui/space_view3d.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index f0e5c2e798c..44e9e7e8d55 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -2760,7 +2760,7 @@ class VIEW3D_MT_object_animation(Menu): layout = self.layout layout.operator("anim.keyframe_insert", text="Insert Keyframe") - layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe by Type...") + layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe with Keying Set") layout.operator("anim.keyframe_delete_v3d", text="Delete Keyframes...") layout.operator("anim.keyframe_clear_v3d", text="Clear Keyframes...") layout.operator("anim.keying_set_active_set", text="Change Keying Set...") @@ -3025,7 +3025,7 @@ class VIEW3D_MT_object_context_menu(Menu): layout.separator() layout.operator("anim.keyframe_insert", text="Insert Keyframe") - layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe by Type...") + layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe with Keying Set") layout.separator() @@ -4177,7 +4177,7 @@ class VIEW3D_MT_pose_context_menu(Menu): layout.operator_context = 'INVOKE_REGION_WIN' layout.operator("anim.keyframe_insert", text="Insert Keyframe") - layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe by Type") + layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe with Keying Set") layout.separator() -- 2.30.2 From f9579ac0068a3e3ce3c1378269089e9680d12069 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 2 Nov 2023 17:17:39 +0100 Subject: [PATCH 24/41] remove useless comments --- source/blender/animrig/intern/keyframing.cc | 11 +---------- source/blender/editors/animation/keyframing.cc | 4 ++-- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/source/blender/animrig/intern/keyframing.cc b/source/blender/animrig/intern/keyframing.cc index f48d1703b7f..89041b49734 100644 --- a/source/blender/animrig/intern/keyframing.cc +++ b/source/blender/animrig/intern/keyframing.cc @@ -1020,46 +1020,37 @@ static FCurve *action_fcurve_ensure(bAction *action, return fcu; } - /* use default settings to make a F-Curve */ fcu = BKE_fcurve_create(); fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); fcu->auto_smoothing = U.auto_smoothing_new; if (BLI_listbase_is_empty(&action->curves)) { - fcu->flag |= FCURVE_ACTIVE; /* first one added active */ + fcu->flag |= FCURVE_ACTIVE; } - /* store path - make copy, and store that */ char *fcu_rna_path = static_cast(MEM_mallocN(rna_path.length() + 1, "fcu_rna_path")); std::strcpy(fcu_rna_path, rna_path.c_str()); fcu->rna_path = fcu_rna_path; fcu->array_index = array_index; - /* if a group name has been provided, try to add or find a group, then add F-Curve to it */ if (group) { - /* try to find group */ bActionGroup *action_group = BKE_action_group_find_name(action, group); - /* no matching groups, so add one */ if (action_group == nullptr) { action_group = action_groups_add_new(action, group); - /* sync bone group colors if applicable */ if (ptr && (ptr->type == &RNA_PoseBone)) { bPoseChannel *pchan = static_cast(ptr->data); action_group_colors_set_from_posebone(action_group, pchan); } } - /* add F-Curve to group */ action_groups_add_channel(action, action_group, fcu); } else { - /* just add F-Curve to end of Action's list */ BLI_addtail(&action->curves, fcu); } - /* return the F-Curve */ return fcu; } diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index d44c6287fb8..da82ad492bc 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -873,7 +873,7 @@ static void insert_key_pose_mode(bContext *C, wmOperator *op) BLI_freelistN(&selected_pose_bones); } -static int insert_key_foo(bContext *C, wmOperator *op) +static int insert_key(bContext *C, wmOperator *op) { using namespace blender; @@ -911,7 +911,7 @@ static int insert_key_exec(bContext *C, wmOperator *op) if (ks) { return insert_key_with_keyingset(C, op, ks); } - return insert_key_foo(C, op); + return insert_key(C, op); } void ANIM_OT_keyframe_insert(wmOperatorType *ot) -- 2.30.2 From 7ab9465822e5f534371e7ad447aa36b4645d797b Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 2 Nov 2023 17:38:01 +0100 Subject: [PATCH 25/41] refactoring and renamign --- source/blender/animrig/intern/keyframing.cc | 51 ++++++++++----------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/source/blender/animrig/intern/keyframing.cc b/source/blender/animrig/intern/keyframing.cc index 89041b49734..355283a2c18 100644 --- a/source/blender/animrig/intern/keyframing.cc +++ b/source/blender/animrig/intern/keyframing.cc @@ -1005,33 +1005,31 @@ int clear_keyframe(Main *bmain, return key_count; } +/** Try to find an FCurve in the given bAction that matches the given rna_path. Create one if not + * found.*/ static FCurve *action_fcurve_ensure(bAction *action, - const char group[], - PointerRNA *ptr, const std::string &rna_path, - const int array_index) + const int array_index, + const char *group = nullptr, + PointerRNA *ptr = nullptr) { - /* try to find f-curve matching for this setting - * - add if not found and allowed to add one - * TODO: add auto-grouping support? how this works will need to be resolved - */ - FCurve *fcu = BKE_fcurve_find(&action->curves, rna_path.c_str(), array_index); - if (fcu) { - return fcu; + FCurve *fcurve = BKE_fcurve_find(&action->curves, rna_path.c_str(), array_index); + if (fcurve) { + return fcurve; } - fcu = BKE_fcurve_create(); + fcurve = BKE_fcurve_create(); - fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); - fcu->auto_smoothing = U.auto_smoothing_new; + fcurve->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); + fcurve->auto_smoothing = U.auto_smoothing_new; if (BLI_listbase_is_empty(&action->curves)) { - fcu->flag |= FCURVE_ACTIVE; + fcurve->flag |= FCURVE_ACTIVE; } char *fcu_rna_path = static_cast(MEM_mallocN(rna_path.length() + 1, "fcu_rna_path")); std::strcpy(fcu_rna_path, rna_path.c_str()); - fcu->rna_path = fcu_rna_path; - fcu->array_index = array_index; + fcurve->rna_path = fcu_rna_path; + fcurve->array_index = array_index; if (group) { bActionGroup *action_group = BKE_action_group_find_name(action, group); @@ -1045,16 +1043,16 @@ static FCurve *action_fcurve_ensure(bAction *action, } } - action_groups_add_channel(action, action_group, fcu); + action_groups_add_channel(action, action_group, fcurve); } else { - BLI_addtail(&action->curves, fcu); + BLI_addtail(&action->curves, fcurve); } - return fcu; + return fcurve; } -static bool insert_key_fcu_foo(FCurve *fcu, const float frame, const float value) +static bool insert_key_fcurve(FCurve *fcu, const float frame, const float value) { if (!BKE_fcurve_is_keyframable(fcu)) { return false; @@ -1072,20 +1070,21 @@ int insert_key_action(bAction *action, { BLI_assert(action != nullptr); - std::string group = "Object Transforms"; + std::string group; if (ptr->type == &RNA_PoseBone) { bPoseChannel *pose_channel = static_cast(ptr->data); group = pose_channel->name; } + else { + group = "Object Transforms"; + } int property_array_index = 0; int inserted_keys = 0; for (const float value : values) { - FCurve *fcu = action_fcurve_ensure(action, group.c_str(), ptr, rna_path, property_array_index); - if (!fcu) { - continue; - } - const bool inserted_key = insert_key_fcu_foo(fcu, frame, value); + FCurve *fcurve = action_fcurve_ensure( + action, rna_path, property_array_index, group.c_str(), ptr); + const bool inserted_key = insert_key_fcurve(fcurve, frame, value); if (inserted_key) { inserted_keys++; } -- 2.30.2 From 6982acb221a311cfc942cd16b14c77ebdd8a6f76 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 9 Nov 2023 17:44:49 +0100 Subject: [PATCH 26/41] resolve merge issues --- source/blender/editors/animation/keyframing.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index 7b2220e1e9b..0c85c6ce523 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -411,7 +411,7 @@ static void insert_key_id(PointerRNA *rna_pointer, continue; } std::string rna_path_id_to_prop = RNA_path_from_ID_to_property(&ptr, prop); - Vector rna_values = ANIM_setting_get_rna_values(&ptr, prop); + Vector rna_values = animrig::get_rna_values(&ptr, prop); const int inserted_keys = animrig::insert_key_action( action, rna_pointer, rna_path_id_to_prop, nla_frame, rna_values.as_span()); -- 2.30.2 From dec0c5f278c7aaaf7c880a6512f192d52f167c42 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 10 Nov 2023 09:30:28 +0100 Subject: [PATCH 27/41] pass Main to action insertion function --- source/blender/animrig/ANIM_keyframing.hh | 3 +- source/blender/animrig/intern/keyframing.cc | 52 ++----------------- .../blender/editors/animation/keyframing.cc | 2 +- 3 files changed, 6 insertions(+), 51 deletions(-) diff --git a/source/blender/animrig/ANIM_keyframing.hh b/source/blender/animrig/ANIM_keyframing.hh index bceaf449556..5e437115b0b 100644 --- a/source/blender/animrig/ANIM_keyframing.hh +++ b/source/blender/animrig/ANIM_keyframing.hh @@ -172,7 +172,8 @@ bool autokeyframe_property(bContext *C, * Insert a key in the given action. * \param frame is expected to be in NLA space. */ -int insert_key_action(bAction *action, +int insert_key_action(Main *bmain, + bAction *action, PointerRNA *ptr, const std::string &rna_path, float frame, diff --git a/source/blender/animrig/intern/keyframing.cc b/source/blender/animrig/intern/keyframing.cc index f022e5a1765..1e21c24c5f3 100644 --- a/source/blender/animrig/intern/keyframing.cc +++ b/source/blender/animrig/intern/keyframing.cc @@ -950,53 +950,6 @@ int clear_keyframe(Main *bmain, return key_count; } -/** Try to find an FCurve in the given bAction that matches the given rna_path. Create one if not - * found.*/ -static FCurve *action_fcurve_ensure(bAction *action, - const std::string &rna_path, - const int array_index, - const char *group = nullptr, - PointerRNA *ptr = nullptr) -{ - FCurve *fcurve = BKE_fcurve_find(&action->curves, rna_path.c_str(), array_index); - if (fcurve) { - return fcurve; - } - - fcurve = BKE_fcurve_create(); - - fcurve->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); - fcurve->auto_smoothing = U.auto_smoothing_new; - if (BLI_listbase_is_empty(&action->curves)) { - fcurve->flag |= FCURVE_ACTIVE; - } - - char *fcu_rna_path = static_cast(MEM_mallocN(rna_path.length() + 1, "fcu_rna_path")); - std::strcpy(fcu_rna_path, rna_path.c_str()); - fcurve->rna_path = fcu_rna_path; - fcurve->array_index = array_index; - - if (group) { - bActionGroup *action_group = BKE_action_group_find_name(action, group); - - if (action_group == nullptr) { - action_group = action_groups_add_new(action, group); - - if (ptr && (ptr->type == &RNA_PoseBone)) { - bPoseChannel *pchan = static_cast(ptr->data); - action_group_colors_set_from_posebone(action_group, pchan); - } - } - - action_groups_add_channel(action, action_group, fcurve); - } - else { - BLI_addtail(&action->curves, fcurve); - } - - return fcurve; -} - static bool insert_key_fcurve(FCurve *fcu, const float frame, const float value) { if (!BKE_fcurve_is_keyframable(fcu)) { @@ -1007,7 +960,8 @@ static bool insert_key_fcurve(FCurve *fcu, const float frame, const float value) return inserted_index >= 0; } -int insert_key_action(bAction *action, +int insert_key_action(Main *bmain, + bAction *action, PointerRNA *ptr, const std::string &rna_path, const float frame, @@ -1028,7 +982,7 @@ int insert_key_action(bAction *action, int inserted_keys = 0; for (const float value : values) { FCurve *fcurve = action_fcurve_ensure( - action, rna_path, property_array_index, group.c_str(), ptr); + bmain, action, group.c_str(), ptr, rna_path.c_str(), property_array_index); const bool inserted_key = insert_key_fcurve(fcurve, frame, value); if (inserted_key) { inserted_keys++; diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index 0c85c6ce523..0c1f9e3b19d 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -414,7 +414,7 @@ static void insert_key_id(PointerRNA *rna_pointer, Vector rna_values = animrig::get_rna_values(&ptr, prop); const int inserted_keys = animrig::insert_key_action( - action, rna_pointer, rna_path_id_to_prop, nla_frame, rna_values.as_span()); + bmain, action, rna_pointer, rna_path_id_to_prop, nla_frame, rna_values.as_span()); } } -- 2.30.2 From c79a3423a2b3378dc63557397ee3f38d5d42abd2 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 10 Nov 2023 10:53:14 +0100 Subject: [PATCH 28/41] comment and assertion --- source/blender/animrig/ANIM_keyframing.hh | 3 ++- source/blender/animrig/intern/keyframing.cc | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/animrig/ANIM_keyframing.hh b/source/blender/animrig/ANIM_keyframing.hh index 5e437115b0b..1ba495b1c6a 100644 --- a/source/blender/animrig/ANIM_keyframing.hh +++ b/source/blender/animrig/ANIM_keyframing.hh @@ -169,7 +169,8 @@ bool autokeyframe_property(bContext *C, /** \} */ /** - * Insert a key in the given action. + * Insert keys for the given rna_path in the given action. The length of the values Span is + * expected to be the size of the property array. * \param frame is expected to be in NLA space. */ int insert_key_action(Main *bmain, diff --git a/source/blender/animrig/intern/keyframing.cc b/source/blender/animrig/intern/keyframing.cc index 1e21c24c5f3..23287ae9426 100644 --- a/source/blender/animrig/intern/keyframing.cc +++ b/source/blender/animrig/intern/keyframing.cc @@ -967,6 +967,7 @@ int insert_key_action(Main *bmain, const float frame, const Span values) { + BLI_assert(bmain != nullptr); BLI_assert(action != nullptr); std::string group; -- 2.30.2 From 8760e51f81bba05716bd6d479aa0562c890269d6 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 10 Nov 2023 11:36:37 +0100 Subject: [PATCH 29/41] refactor code --- .../blender/editors/animation/keyframing.cc | 105 ++++++++---------- 1 file changed, 45 insertions(+), 60 deletions(-) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index 0c1f9e3b19d..f9b2984301a 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -377,6 +377,8 @@ static blender::Vector construct_rna_paths(const eRotationModes rot static void insert_key_id(PointerRNA *rna_pointer, const blender::Span rna_paths, const float scene_frame, + const eInsertKeyFlags insert_key_flags, + const eBezTriple_KeyframeType, Main *bmain, ReportList *reports) { @@ -396,6 +398,7 @@ static void insert_key_id(PointerRNA *rna_pointer, AnimData *adt = BKE_animdata_from_id(id); const float nla_frame = BKE_nla_tweakedit_remap(adt, scene_frame, NLATIME_CONVERT_UNMAP); + int insert_key_count = 0; for (const std::string &rna_path : rna_paths) { PointerRNA ptr; PropertyRNA *prop = nullptr; @@ -413,49 +416,57 @@ static void insert_key_id(PointerRNA *rna_pointer, std::string rna_path_id_to_prop = RNA_path_from_ID_to_property(&ptr, prop); Vector rna_values = animrig::get_rna_values(&ptr, prop); - const int inserted_keys = animrig::insert_key_action( + insert_key_count += animrig::insert_key_action( bmain, action, rna_pointer, rna_path_id_to_prop, nla_frame, rna_values.as_span()); } -} -static void insert_key_object_mode(bContext *C, wmOperator *op) -{ - using namespace blender; - Main *bmain = CTX_data_main(C); - bool depsgraph_needs_update = false; - - Scene *scene = CTX_data_scene(C); - const float scene_frame = BKE_scene_frame_get(scene); - - ListBase selected_objects = {nullptr, nullptr}; - CTX_data_selected_objects(C, &selected_objects); - LISTBASE_FOREACH (CollectionPointerLink *, collection_ptr_link, &selected_objects) { - ID *selected_id = collection_ptr_link->ptr.owner_id; - if (!BKE_id_is_editable(bmain, selected_id)) { - BKE_reportf(op->reports, RPT_ERROR, "'%s' is not editable", selected_id->name + 2); - return; - } - PointerRNA id_ptr = collection_ptr_link->ptr; - Object *ob = static_cast(collection_ptr_link->ptr.data); - Vector rna_paths = construct_rna_paths(eRotationModes(ob->rotmode), - ob->id.properties); - insert_key_id(&id_ptr, rna_paths.as_span(), scene_frame, bmain, op->reports); + if (insert_key_count == 0) { + BKE_reportf(reports, RPT_ERROR, "Failed to insert any keys"); } - BLI_freelistN(&selected_objects); } -static void insert_key_pose_mode(bContext *C, wmOperator *op) +/* Fill the list with CollectionPointerLink depending on the mode of the context. */ +static bool get_selection(bContext *C, ListBase *r_selection) +{ + const eContextObjectMode context_mode = CTX_data_mode_enum(C); + switch (context_mode) { + + case CTX_MODE_OBJECT: { + CTX_data_selected_objects(C, r_selection); + break; + } + + case CTX_MODE_POSE: { + CTX_data_selected_pose_bones(C, r_selection); + break; + } + + default: + return false; + } + + return true; +} + +static int insert_key(bContext *C, wmOperator *op) { using namespace blender; - Main *bmain = CTX_data_main(C); - bool depsgraph_needs_update = false; + ListBase selection = {nullptr, nullptr}; + const bool found_selection = get_selection(C, &selection); + if (!found_selection) { + BKE_reportf(op->reports, RPT_ERROR, "Unsupported context mode"); + } + + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); const float scene_frame = BKE_scene_frame_get(scene); - ListBase selected_pose_bones = {nullptr, nullptr}; - CTX_data_selected_pose_bones(C, &selected_pose_bones); - LISTBASE_FOREACH (CollectionPointerLink *, collection_ptr_link, &selected_pose_bones) { + const eInsertKeyFlags insert_key_flags = ANIM_get_keyframing_flags(scene, false); + const eBezTriple_KeyframeType key_type = eBezTriple_KeyframeType( + scene->toolsettings->keyframe_type); + + LISTBASE_FOREACH (CollectionPointerLink *, collection_ptr_link, &selection) { ID *selected_id = collection_ptr_link->ptr.owner_id; if (!BKE_id_is_editable(bmain, selected_id)) { BKE_reportf(op->reports, RPT_ERROR, "'%s' is not editable", selected_id->name + 2); @@ -466,38 +477,12 @@ static void insert_key_pose_mode(bContext *C, wmOperator *op) Vector rna_paths = construct_rna_paths(eRotationModes(pchan->rotmode), pchan->prop); - insert_key_id(&id_ptr, rna_paths.as_span(), scene_frame, bmain, op->reports); - } - BLI_freelistN(&selected_pose_bones); -} - -static int insert_key(bContext *C, wmOperator *op) -{ - using namespace blender; - - bool depsgraph_needs_update = false; - - eContextObjectMode context_mode = CTX_data_mode_enum(C); - switch (context_mode) { - - case CTX_MODE_OBJECT: - insert_key_object_mode(C, op); - break; - - case CTX_MODE_POSE: - insert_key_pose_mode(C, op); - break; - - default: - BKE_reportf(op->reports, RPT_ERROR, "Unsupported context mode"); - break; + insert_key_id( + &id_ptr, rna_paths.as_span(), scene_frame, insert_key_flags, key_type, bmain, op->reports); } - Main *bmain = CTX_data_main(C); - if (depsgraph_needs_update) { - DEG_relations_tag_update(bmain); - } WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, nullptr); + BLI_freelistN(&selection); return OPERATOR_FINISHED; } -- 2.30.2 From 33d5adf2b8d7f98f84ff4dd25d166e9d55530471 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 10 Nov 2023 12:25:55 +0100 Subject: [PATCH 30/41] use common function for inserting keys --- source/blender/animrig/intern/keyframing.cc | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/source/blender/animrig/intern/keyframing.cc b/source/blender/animrig/intern/keyframing.cc index 4c67a5f6a43..c66c3128ec3 100644 --- a/source/blender/animrig/intern/keyframing.cc +++ b/source/blender/animrig/intern/keyframing.cc @@ -967,22 +967,14 @@ int clear_keyframe(Main *bmain, return key_count; } -static bool insert_key_fcurve(FCurve *fcu, const float frame, const float value) -{ - if (!BKE_fcurve_is_keyframable(fcu)) { - return false; - } - const int inserted_index = insert_vert_fcurve( - fcu, frame, value, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NOFLAGS); - return inserted_index >= 0; -} - int insert_key_action(Main *bmain, bAction *action, PointerRNA *ptr, const std::string &rna_path, const float frame, - const Span values) + const Span values, + eInsertKeyFlags insert_key_flag, + eBezTriple_KeyframeType key_type) { BLI_assert(bmain != nullptr); BLI_assert(action != nullptr); @@ -998,10 +990,11 @@ int insert_key_action(Main *bmain, int property_array_index = 0; int inserted_keys = 0; - for (const float value : values) { + for (float value : values) { FCurve *fcurve = action_fcurve_ensure( bmain, action, group.c_str(), ptr, rna_path.c_str(), property_array_index); - const bool inserted_key = insert_key_fcurve(fcurve, frame, value); + const bool inserted_key = insert_keyframe_value( + fcurve, frame, value, key_type, insert_key_flag); if (inserted_key) { inserted_keys++; } -- 2.30.2 From 30a3649bdabc7f64aed4f2de86f21ed444294f18 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 10 Nov 2023 12:29:37 +0100 Subject: [PATCH 31/41] pass keyframing flags --- source/blender/animrig/ANIM_keyframing.hh | 4 +++- source/blender/editors/animation/keyframing.cc | 18 +++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/source/blender/animrig/ANIM_keyframing.hh b/source/blender/animrig/ANIM_keyframing.hh index 1ba495b1c6a..fb3736dd2e6 100644 --- a/source/blender/animrig/ANIM_keyframing.hh +++ b/source/blender/animrig/ANIM_keyframing.hh @@ -178,6 +178,8 @@ int insert_key_action(Main *bmain, PointerRNA *ptr, const std::string &rna_path, float frame, - const Span values); + const Span values, + eInsertKeyFlags insert_key_flag, + eBezTriple_KeyframeType key_type); } // namespace blender::animrig diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index f9b2984301a..c5f41245e18 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -378,7 +378,7 @@ static void insert_key_id(PointerRNA *rna_pointer, const blender::Span rna_paths, const float scene_frame, const eInsertKeyFlags insert_key_flags, - const eBezTriple_KeyframeType, + const eBezTriple_KeyframeType key_type, Main *bmain, ReportList *reports) { @@ -416,8 +416,14 @@ static void insert_key_id(PointerRNA *rna_pointer, std::string rna_path_id_to_prop = RNA_path_from_ID_to_property(&ptr, prop); Vector rna_values = animrig::get_rna_values(&ptr, prop); - insert_key_count += animrig::insert_key_action( - bmain, action, rna_pointer, rna_path_id_to_prop, nla_frame, rna_values.as_span()); + insert_key_count += animrig::insert_key_action(bmain, + action, + rna_pointer, + rna_path_id_to_prop, + nla_frame, + rna_values.as_span(), + insert_key_flags, + key_type); } if (insert_key_count == 0) { @@ -429,18 +435,16 @@ static void insert_key_id(PointerRNA *rna_pointer, static bool get_selection(bContext *C, ListBase *r_selection) { const eContextObjectMode context_mode = CTX_data_mode_enum(C); - switch (context_mode) { + switch (context_mode) { case CTX_MODE_OBJECT: { CTX_data_selected_objects(C, r_selection); break; } - case CTX_MODE_POSE: { CTX_data_selected_pose_bones(C, r_selection); break; } - default: return false; } @@ -470,7 +474,7 @@ static int insert_key(bContext *C, wmOperator *op) ID *selected_id = collection_ptr_link->ptr.owner_id; if (!BKE_id_is_editable(bmain, selected_id)) { BKE_reportf(op->reports, RPT_ERROR, "'%s' is not editable", selected_id->name + 2); - return; + continue; } PointerRNA id_ptr = collection_ptr_link->ptr; bPoseChannel *pchan = static_cast(collection_ptr_link->ptr.data); -- 2.30.2 From 0ab0cb27dca55a2f6d0a45d7fce95cffd2d375d4 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 10 Nov 2023 14:40:13 +0100 Subject: [PATCH 32/41] add unit tests --- release/datafiles/userdef/userdef_default.c | 2 +- .../blenloader/intern/versioning_userdef.cc | 4 +- .../blender/editors/animation/keyframing.cc | 4 +- source/blender/makesdna/DNA_userdef_types.h | 4 +- source/blender/makesrna/intern/rna_userdef.cc | 4 +- tests/python/bl_animation_keyframing.py | 45 ++++++++++++++++++- 6 files changed, 52 insertions(+), 11 deletions(-) diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c index 774f3ff5efa..1cc3e7c59cb 100644 --- a/release/datafiles/userdef/userdef_default.c +++ b/release/datafiles/userdef/userdef_default.c @@ -165,7 +165,7 @@ const UserDef U_default = { .glalphaclip = 0.004, .autokey_mode = (AUTOKEY_MODE_NORMAL & ~AUTOKEY_ON), .autokey_flag = AUTOKEY_FLAG_XYZ2RGB, - .key_insert_channels = USER_ANIM_KEY_CHANNEL_TRANSLATE, + .key_insert_channels = USER_ANIM_KEY_CHANNEL_LOCATION, .animation_flag = USER_ANIM_HIGH_QUALITY_DRAWING, .text_render = 0, .navigation_mode = VIEW_NAVIGATION_WALK, diff --git a/source/blender/blenloader/intern/versioning_userdef.cc b/source/blender/blenloader/intern/versioning_userdef.cc index 79f6f233581..287e0cebd7d 100644 --- a/source/blender/blenloader/intern/versioning_userdef.cc +++ b/source/blender/blenloader/intern/versioning_userdef.cc @@ -916,8 +916,8 @@ void blo_do_versions_userdef(UserDef *userdef) */ { /* Keep this block, even when empty. */ - userdef->key_insert_channels = (USER_ANIM_KEY_CHANNEL_TRANSLATE | - USER_ANIM_KEY_CHANNEL_ROTATE | USER_ANIM_KEY_CHANNEL_SCALE | + userdef->key_insert_channels = (USER_ANIM_KEY_CHANNEL_LOCATION | + USER_ANIM_KEY_CHANNEL_ROTATION | USER_ANIM_KEY_CHANNEL_SCALE | USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES); } diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index c5f41245e18..ae32e6e82c0 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -334,10 +334,10 @@ static blender::Vector construct_rna_paths(const eRotationModes rot { blender::Vector paths; eKeyInsertChannels insert_channel_flags = eKeyInsertChannels(U.key_insert_channels); - if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_TRANSLATE) { + if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_LOCATION) { paths.append("location"); } - if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_ROTATE) { + if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_ROTATION) { switch (rotation_mode) { case ROT_MODE_QUAT: paths.append("rotation_quaternion"); diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index f633dec6608..810c8853a49 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -1299,8 +1299,8 @@ typedef enum eAutokey_Flag { } eAutokey_Flag; typedef enum eKeyInsertChannels { - USER_ANIM_KEY_CHANNEL_TRANSLATE = (1 << 0), - USER_ANIM_KEY_CHANNEL_ROTATE = (1 << 1), + USER_ANIM_KEY_CHANNEL_LOCATION = (1 << 0), + USER_ANIM_KEY_CHANNEL_ROTATION = (1 << 1), USER_ANIM_KEY_CHANNEL_SCALE = (1 << 2), USER_ANIM_KEY_CHANNEL_ROTATION_MODE = (1 << 3), USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES = (1 << 4), diff --git a/source/blender/makesrna/intern/rna_userdef.cc b/source/blender/makesrna/intern/rna_userdef.cc index bc47e3f89b7..a24474670b6 100644 --- a/source/blender/makesrna/intern/rna_userdef.cc +++ b/source/blender/makesrna/intern/rna_userdef.cc @@ -150,8 +150,8 @@ static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = { }; static const EnumPropertyItem rna_enum_key_insert_channels[] = { - {USER_ANIM_KEY_CHANNEL_TRANSLATE, "TRANSLATE", 0, "Translate", ""}, - {USER_ANIM_KEY_CHANNEL_ROTATE, "ROTATE", 0, "Rotate", ""}, + {USER_ANIM_KEY_CHANNEL_LOCATION, "LOCATION", 0, "Location", ""}, + {USER_ANIM_KEY_CHANNEL_ROTATION, "ROTATION", 0, "Rotation", ""}, {USER_ANIM_KEY_CHANNEL_SCALE, "SCALE", 0, "Scale", ""}, {USER_ANIM_KEY_CHANNEL_ROTATION_MODE, "ROTATE_MODE", 0, "Rotation Mode", ""}, {USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES, "CUSTOM_PROPS", 0, "Custom Properties", ""}, diff --git a/tests/python/bl_animation_keyframing.py b/tests/python/bl_animation_keyframing.py index 26acba3689d..a8472aa316e 100644 --- a/tests/python/bl_animation_keyframing.py +++ b/tests/python/bl_animation_keyframing.py @@ -15,6 +15,7 @@ blender -b -noaudio --factory-startup --python tests/python/bl_animation_keyfram def _fcurve_paths_match(fcurves: list, expected_paths: list) -> bool: data_paths = list(set([fcurve.data_path for fcurve in fcurves])) + print(sorted(data_paths), sorted(expected_paths)) return sorted(data_paths) == sorted(expected_paths) @@ -51,6 +52,16 @@ def _insert_by_name_test(insert_key: str, expected_paths: list): return match +def _insert_from_user_preference_test(enabled_user_pref_fields: set, expected_paths: list): + keyed_object = _create_animation_object() + bpy.context.preferences.edit.key_insert_channels = enabled_user_pref_fields + with bpy.context.temp_override(**_get_view3d_context()): + bpy.ops.anim.keyframe_insert() + match = _fcurve_paths_match(keyed_object.animation_data.action.fcurves, expected_paths) + bpy.data.objects.remove(keyed_object, do_unlink=True) + return match + + def _get_keying_set(scene, name: str): return scene.keying_sets_all[scene.keying_sets_all.find(name)] @@ -90,6 +101,13 @@ class InsertKeyTest(AbstractKeyframingTest, unittest.TestCase): _insert_with_keying_set_test("Location, Rotation & Scale", ["location", "rotation_euler", "scale"]) ) + def test_insert_from_user_preferences(self): + self.assertTrue(_insert_from_user_preference_test({"LOCATION"}, ["location"])) + self.assertTrue(_insert_from_user_preference_test({"ROTATION"}, ["rotation_euler"])) + self.assertTrue(_insert_from_user_preference_test({"SCALE"}, ["scale"])) + self.assertTrue(_insert_from_user_preference_test( + {"LOCATION", "ROTATION", "SCALE"}, ["location", "rotation", "scale"])) + class VisualKeyingTest(AbstractKeyframingTest, unittest.TestCase): """ Check if visual keying produces the correct keyframe values. """ @@ -130,7 +148,7 @@ class VisualKeyingTest(AbstractKeyframingTest, unittest.TestCase): bpy.data.objects.remove(target, do_unlink=True) bpy.data.objects.remove(constrained, do_unlink=True) - def test_visual_location_user_pref(self): + def test_visual_location_user_pref_override(self): # When enabling the user preference setting, # the normal keying sets behave like their visual keying set counterpart. bpy.context.preferences.edit.use_visual_keying = True @@ -151,6 +169,27 @@ class VisualKeyingTest(AbstractKeyframingTest, unittest.TestCase): bpy.data.objects.remove(constrained, do_unlink=True) bpy.context.preferences.edit.use_visual_keying = False + def test_visual_location_user_pref(self): + target = _create_animation_object() + t_value = 1 + target.location = (t_value, t_value, t_value) + constrained = _create_animation_object() + constraint = constrained.constraints.new("COPY_LOCATION") + constraint.target = target + + bpy.context.preferences.edit.use_visual_keying = True + bpy.context.preferences.edit.key_insert_channels = {"LOCATION"} + + with bpy.context.temp_override(**_get_view3d_context()): + bpy.ops.anim.keyframe_insert() + + for fcurve in constrained.animation_data.action.fcurves: + self.assertEqual(fcurve.keyframe_points[0].co.y, t_value) + + bpy.data.objects.remove(target, do_unlink=True) + bpy.data.objects.remove(constrained, do_unlink=True) + bpy.context.preferences.edit.use_visual_keying = False + class CycleAwareKeyingTest(AbstractKeyframingTest, unittest.TestCase): """ Check if cycle aware keying remaps the keyframes correctly and adds fcurve modifiers. """ @@ -175,8 +214,10 @@ class CycleAwareKeyingTest(AbstractKeyframingTest, unittest.TestCase): bpy.ops.anim.keyframe_insert_by_name(type="Location") # Will be mapped to frame 3. + # This will insert the key based on the user preference settings. + bpy.context.preferences.edit.key_insert_channels = {"LOCATION"} bpy.context.scene.frame_set(22) - bpy.ops.anim.keyframe_insert_by_name(type="Location") + bpy.ops.anim.keyframe_insert() # Will be mapped to frame 9. bpy.context.scene.frame_set(-10) -- 2.30.2 From e7a5e556b50a983e9519e5f4668be09e07a0e987 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 10 Nov 2023 15:07:43 +0100 Subject: [PATCH 33/41] uncomment code --- source/blender/editors/animation/keyingsets.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/animation/keyingsets.cc b/source/blender/editors/animation/keyingsets.cc index 68a9b72e311..f90a435a69b 100644 --- a/source/blender/editors/animation/keyingsets.cc +++ b/source/blender/editors/animation/keyingsets.cc @@ -862,10 +862,10 @@ KeyingSet *ANIM_keyingset_get_from_idname(Scene *scene, const char *idname) { KeyingSet *ks = static_cast( BLI_findstring(&scene->keyingsets, idname, offsetof(KeyingSet, idname))); - /* if (ks == nullptr) { + if (ks == nullptr) { ks = static_cast( BLI_findstring(&builtin_keyingsets, idname, offsetof(KeyingSet, idname))); - } */ + } return ks; } -- 2.30.2 From 929f53234f12c0328c1d1e80a7e9b7402b212c32 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 10 Nov 2023 15:48:59 +0100 Subject: [PATCH 34/41] split operators --- .../blender/editors/animation/keyframing.cc | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index ae32e6e82c0..36b9e8a3f7a 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -503,13 +503,12 @@ static int insert_key_exec(bContext *C, wmOperator *op) void ANIM_OT_keyframe_insert(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ ot->name = "Insert Keyframe"; ot->idname = "ANIM_OT_keyframe_insert"; ot->description = - "Insert keyframes on the current frame for all properties in the specified Keying Set"; + "Insert keyframes on the current frame using the either the active keying set, or the user " + "preferences if no keying set is active"; /* callbacks */ ot->exec = insert_key_exec; @@ -517,13 +516,16 @@ void ANIM_OT_keyframe_insert(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} - /* keyingset to use (dynamic enum) */ - prop = RNA_def_enum( - ot->srna, "type", rna_enum_dummy_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); - RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf); - RNA_def_property_flag(prop, PROP_HIDDEN); - ot->prop = prop; +static int keyframe_insert_with_keyingset_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene); + if (ks == nullptr) { + return OPERATOR_CANCELLED; + } + return insert_key_with_keyingset(C, op, ks); } void ANIM_OT_keyframe_insert_by_name(wmOperatorType *ot) @@ -536,7 +538,7 @@ void ANIM_OT_keyframe_insert_by_name(wmOperatorType *ot) ot->description = "Alternate access to 'Insert Keyframe' for keymaps to use"; /* callbacks */ - ot->exec = insert_key_exec; + ot->exec = keyframe_insert_with_keyingset_exec; ot->poll = modify_key_op_poll; /* flags */ @@ -626,7 +628,7 @@ void ANIM_OT_keyframe_insert_menu(wmOperatorType *ot) /* callbacks */ ot->invoke = insert_key_menu_invoke; - ot->exec = insert_key_exec; + ot->exec = keyframe_insert_with_keyingset_exec; ot->poll = ED_operator_areaactive; /* flags */ -- 2.30.2 From 411327f4c8db8a68f276788e071a2dbc2030c25a Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 10 Nov 2023 16:12:35 +0100 Subject: [PATCH 35/41] fix regression test issues --- .../blender/editors/animation/keyframing.cc | 26 +++++++++++++++---- tests/python/bl_animation_keyframing.py | 3 ++- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index 36b9e8a3f7a..cf401c8c491 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -329,10 +329,27 @@ static int insert_key_with_keyingset(bContext *C, wmOperator *op, KeyingSet *ks) return OPERATOR_FINISHED; } -static blender::Vector construct_rna_paths(const eRotationModes rotation_mode, - IDProperty *properties = nullptr) +static blender::Vector construct_rna_paths(PointerRNA *ptr) { + eRotationModes rotation_mode; + IDProperty *properties; blender::Vector paths; + + if (ptr->type == &RNA_PoseBone) { + bPoseChannel *pchan = static_cast(ptr->data); + rotation_mode = eRotationModes(pchan->rotmode); + properties = pchan->prop; + } + else if (ptr->type == &RNA_Object) { + Object *ob = static_cast(ptr->data); + rotation_mode = eRotationModes(ob->rotmode); + properties = ob->id.properties; + } + else { + /* Pointer type not supported. */ + return paths; + } + eKeyInsertChannels insert_channel_flags = eKeyInsertChannels(U.key_insert_channels); if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_LOCATION) { paths.append("location"); @@ -477,9 +494,7 @@ static int insert_key(bContext *C, wmOperator *op) continue; } PointerRNA id_ptr = collection_ptr_link->ptr; - bPoseChannel *pchan = static_cast(collection_ptr_link->ptr.data); - Vector rna_paths = construct_rna_paths(eRotationModes(pchan->rotmode), - pchan->prop); + Vector rna_paths = construct_rna_paths(&collection_ptr_link->ptr); insert_key_id( &id_ptr, rna_paths.as_span(), scene_frame, insert_key_flags, key_type, bmain, op->reports); @@ -494,6 +509,7 @@ static int insert_key(bContext *C, wmOperator *op) static int insert_key_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); + /* Use the active keying set if there is one. */ KeyingSet *ks = ANIM_keyingset_get_from_enum_type(scene, scene->active_keyingset); if (ks) { return insert_key_with_keyingset(C, op, ks); diff --git a/tests/python/bl_animation_keyframing.py b/tests/python/bl_animation_keyframing.py index a8472aa316e..df93adde328 100644 --- a/tests/python/bl_animation_keyframing.py +++ b/tests/python/bl_animation_keyframing.py @@ -106,7 +106,7 @@ class InsertKeyTest(AbstractKeyframingTest, unittest.TestCase): self.assertTrue(_insert_from_user_preference_test({"ROTATION"}, ["rotation_euler"])) self.assertTrue(_insert_from_user_preference_test({"SCALE"}, ["scale"])) self.assertTrue(_insert_from_user_preference_test( - {"LOCATION", "ROTATION", "SCALE"}, ["location", "rotation", "scale"])) + {"LOCATION", "ROTATION", "SCALE"}, ["location", "rotation_euler", "scale"])) class VisualKeyingTest(AbstractKeyframingTest, unittest.TestCase): @@ -232,6 +232,7 @@ class CycleAwareKeyingTest(AbstractKeyframingTest, unittest.TestCase): self.assertEqual(len(fcurve.keyframe_points), len(expected_keys)) key_index = 0 for key in fcurve.keyframe_points: + print(key.co.x) self.assertEqual(key.co.x, expected_keys[key_index]) key_index += 1 -- 2.30.2 From 6dc61fb5b0a52507a2a929580421d115649404e6 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 10 Nov 2023 16:16:40 +0100 Subject: [PATCH 36/41] fix cycle aware keying --- source/blender/editors/animation/keyframing.cc | 4 +++- tests/python/bl_animation_keyframing.py | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index cf401c8c491..aeb8366b784 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -483,7 +483,9 @@ static int insert_key(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); const float scene_frame = BKE_scene_frame_get(scene); - const eInsertKeyFlags insert_key_flags = ANIM_get_keyframing_flags(scene, false); + /* Passing autokey mode as true because that is needed to get the cycle aware keying flag. */ + const bool use_autokey_mode = true; + const eInsertKeyFlags insert_key_flags = ANIM_get_keyframing_flags(scene, use_autokey_mode); const eBezTriple_KeyframeType key_type = eBezTriple_KeyframeType( scene->toolsettings->keyframe_type); diff --git a/tests/python/bl_animation_keyframing.py b/tests/python/bl_animation_keyframing.py index df93adde328..af26c39e425 100644 --- a/tests/python/bl_animation_keyframing.py +++ b/tests/python/bl_animation_keyframing.py @@ -15,7 +15,6 @@ blender -b -noaudio --factory-startup --python tests/python/bl_animation_keyfram def _fcurve_paths_match(fcurves: list, expected_paths: list) -> bool: data_paths = list(set([fcurve.data_path for fcurve in fcurves])) - print(sorted(data_paths), sorted(expected_paths)) return sorted(data_paths) == sorted(expected_paths) @@ -232,7 +231,6 @@ class CycleAwareKeyingTest(AbstractKeyframingTest, unittest.TestCase): self.assertEqual(len(fcurve.keyframe_points), len(expected_keys)) key_index = 0 for key in fcurve.keyframe_points: - print(key.co.x) self.assertEqual(key.co.x, expected_keys[key_index]) key_index += 1 -- 2.30.2 From 1b37659cc0cc2fecbfbac75a77ff5e78b54ccfba Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 10 Nov 2023 16:28:51 +0100 Subject: [PATCH 37/41] make sure visual keying works --- .../blender/editors/animation/keyframing.cc | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index aeb8366b784..f3e5394c400 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -50,6 +50,7 @@ #include "ANIM_fcurve.hh" #include "ANIM_keyframing.hh" #include "ANIM_rna.hh" +#include "ANIM_visualkey.hh" #include "UI_interface.hh" #include "UI_resources.hh" @@ -391,6 +392,26 @@ static blender::Vector construct_rna_paths(PointerRNA *ptr) return paths; } +static blender::Vector get_keyframe_values(PointerRNA *ptr, + PropertyRNA *prop, + const bool visual_key) +{ + using namespace blender; + Vector values; + + if (visual_key && animrig::visualkey_can_use(ptr, prop)) { + /* Visual-keying is only available for object and pchan datablocks, as + * it works by keyframing using a value extracted from the final matrix + * instead of using the kt system to extract a value. + */ + values = animrig::visualkey_get_values(ptr, prop); + } + else { + values = animrig::get_rna_values(ptr, prop); + } + return values; +} + static void insert_key_id(PointerRNA *rna_pointer, const blender::Span rna_paths, const float scene_frame, @@ -414,6 +435,7 @@ static void insert_key_id(PointerRNA *rna_pointer, AnimData *adt = BKE_animdata_from_id(id); const float nla_frame = BKE_nla_tweakedit_remap(adt, scene_frame, NLATIME_CONVERT_UNMAP); + const bool visual_keyframing = insert_key_flags & INSERTKEY_MATRIX; int insert_key_count = 0; for (const std::string &rna_path : rna_paths) { @@ -431,7 +453,7 @@ static void insert_key_id(PointerRNA *rna_pointer, continue; } std::string rna_path_id_to_prop = RNA_path_from_ID_to_property(&ptr, prop); - Vector rna_values = animrig::get_rna_values(&ptr, prop); + Vector rna_values = get_keyframe_values(&ptr, prop, visual_keyframing); insert_key_count += animrig::insert_key_action(bmain, action, -- 2.30.2 From 5c7e5b081ace75779066563ad1f295fc87493924 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 10 Nov 2023 16:49:07 +0100 Subject: [PATCH 38/41] remove bbone shape keying option --- source/blender/makesdna/DNA_userdef_types.h | 1 - source/blender/makesrna/intern/rna_userdef.cc | 1 - 2 files changed, 2 deletions(-) diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 810c8853a49..b53dcd8cc03 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -1304,7 +1304,6 @@ typedef enum eKeyInsertChannels { USER_ANIM_KEY_CHANNEL_SCALE = (1 << 2), USER_ANIM_KEY_CHANNEL_ROTATION_MODE = (1 << 3), USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES = (1 << 4), - USER_ANIM_KEY_CHANNEL_BBONE_SHAPE = (1 << 5), } eKeyInsertChannels; /** diff --git a/source/blender/makesrna/intern/rna_userdef.cc b/source/blender/makesrna/intern/rna_userdef.cc index a24474670b6..c41f7fc0c22 100644 --- a/source/blender/makesrna/intern/rna_userdef.cc +++ b/source/blender/makesrna/intern/rna_userdef.cc @@ -155,7 +155,6 @@ static const EnumPropertyItem rna_enum_key_insert_channels[] = { {USER_ANIM_KEY_CHANNEL_SCALE, "SCALE", 0, "Scale", ""}, {USER_ANIM_KEY_CHANNEL_ROTATION_MODE, "ROTATE_MODE", 0, "Rotation Mode", ""}, {USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES, "CUSTOM_PROPS", 0, "Custom Properties", ""}, - {USER_ANIM_KEY_CHANNEL_BBONE_SHAPE, "BBONE_SHAPE", 0, "BBone Shape", ""}, {0, nullptr, 0, nullptr, nullptr}, }; -- 2.30.2 From c03af6a1796a632da8c6c64eb4c335af6c40fa50 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 10 Nov 2023 16:50:20 +0100 Subject: [PATCH 39/41] rename function --- source/blender/editors/animation/keyframing.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index f3e5394c400..6bccdddcc69 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -412,13 +412,13 @@ static blender::Vector get_keyframe_values(PointerRNA *ptr, return values; } -static void insert_key_id(PointerRNA *rna_pointer, - const blender::Span rna_paths, - const float scene_frame, - const eInsertKeyFlags insert_key_flags, - const eBezTriple_KeyframeType key_type, - Main *bmain, - ReportList *reports) +static void insert_key_rna(PointerRNA *rna_pointer, + const blender::Span rna_paths, + const float scene_frame, + const eInsertKeyFlags insert_key_flags, + const eBezTriple_KeyframeType key_type, + Main *bmain, + ReportList *reports) { using namespace blender; @@ -520,7 +520,7 @@ static int insert_key(bContext *C, wmOperator *op) PointerRNA id_ptr = collection_ptr_link->ptr; Vector rna_paths = construct_rna_paths(&collection_ptr_link->ptr); - insert_key_id( + insert_key_rna( &id_ptr, rna_paths.as_span(), scene_frame, insert_key_flags, key_type, bmain, op->reports); } -- 2.30.2 From ad24a194cb2a4b96c96b871b42ad4977e463c1d8 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Tue, 21 Nov 2023 11:35:34 +0100 Subject: [PATCH 40/41] implement review comments --- source/blender/animrig/ANIM_keyframing.hh | 4 +++- source/blender/editors/animation/keyframing.cc | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/source/blender/animrig/ANIM_keyframing.hh b/source/blender/animrig/ANIM_keyframing.hh index dec5affbb1c..77cc98aaeda 100644 --- a/source/blender/animrig/ANIM_keyframing.hh +++ b/source/blender/animrig/ANIM_keyframing.hh @@ -181,7 +181,9 @@ bool autokeyframe_property(bContext *C, /** * Insert keys for the given rna_path in the given action. The length of the values Span is * expected to be the size of the property array. - * \param frame is expected to be in NLA space. + * \param frame is expected to be in the local time of the action, meaning it has to be NLA mapped + * already. + * \returns The number of keys inserted. */ int insert_key_action(Main *bmain, bAction *action, diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index c6843c0359f..4cad01e8046 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -547,7 +547,7 @@ void ANIM_OT_keyframe_insert(wmOperatorType *ot) ot->name = "Insert Keyframe"; ot->idname = "ANIM_OT_keyframe_insert"; ot->description = - "Insert keyframes on the current frame using the either the active keying set, or the user " + "Insert keyframes on the current frame using either the active keying set, or the user " "preferences if no keying set is active"; /* callbacks */ -- 2.30.2 From c447ffac86220f949e157aa57043fa2be49d2b12 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Tue, 21 Nov 2023 13:47:54 +0100 Subject: [PATCH 41/41] add todo --- source/blender/editors/animation/keyframing.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index 4cad01e8046..5e9aa0575e8 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -99,6 +99,9 @@ eInsertKeyFlags ANIM_get_keyframing_flags(Scene *scene, const bool use_autokey_m } /* only if including settings from the autokeying mode... */ + /* TODO: The fact that this flag needs to be passed as true is confusing because it is not clear + * why those two flags would be exclusive to autokeying. Refactor flags so they are separate + * between normal keying and autokeying. */ if (use_autokey_mode) { /* keyframing mode - only replace existing keyframes */ if (is_autokey_mode(scene, AUTOKEY_MODE_EDITKEYS)) { -- 2.30.2