diff --git a/source/blender/animrig/ANIM_fcurve.hh b/source/blender/animrig/ANIM_fcurve.hh index 21840cf330a..4bdee146c91 100644 --- a/source/blender/animrig/ANIM_fcurve.hh +++ b/source/blender/animrig/ANIM_fcurve.hh @@ -157,4 +157,12 @@ void bake_fcurve(FCurve *fcu, blender::int2 range, float step, BakeCurveRemove r */ void bake_fcurve_segments(FCurve *fcu); +/** + * \brief Lesser Keyframe Checking API call. + * + * Checks if some F-Curve has a keyframe for a given frame. + * \note Used for the buttons to check for keyframes. + */ +bool fcurve_frame_has_keyframe(const FCurve *fcu, float frame); + } // namespace blender::animrig diff --git a/source/blender/animrig/ANIM_keyframing.hh b/source/blender/animrig/ANIM_keyframing.hh index 6b029fdbff0..16ee2db1c5f 100644 --- a/source/blender/animrig/ANIM_keyframing.hh +++ b/source/blender/animrig/ANIM_keyframing.hh @@ -206,6 +206,16 @@ int clear_keyframe(Main *bmain, ReportList *reports, ID *id, const RNAPath &rna_ /** Check if a flag is set for keyframing (per scene takes precedence). */ bool is_keying_flag(const Scene *scene, eKeying_Flag flag); +/** + * \brief Main Keyframe Checking API call. + * + * Checks whether a keyframe exists for the given ID-block one the given frame. + * It is recommended to call this method over the other keyframe-checkers directly, + * in case some detail of the implementation changes... + * \param frame: The value of this is quite often result of #BKE_scene_ctime_get() + */ +bool id_frame_has_keyframe(ID *id, float frame); + /** * Get the settings for key-framing from the given scene. */ diff --git a/source/blender/animrig/ANIM_keyingsets.hh b/source/blender/animrig/ANIM_keyingsets.hh index 6349d1db3a7..0e36cf0a06e 100644 --- a/source/blender/animrig/ANIM_keyingsets.hh +++ b/source/blender/animrig/ANIM_keyingsets.hh @@ -8,12 +8,78 @@ * \brief Functionality to interact with keying sets. */ +#pragma once + +struct KeyingSet; +struct ExtensionRNA; +/* Forward declaration for this struct which is declared a bit later. */ +struct KeyingSetInfo; +struct bContext; +struct ID; +struct Scene; +struct PointerRNA; + +/* Names for builtin keying sets so we don't confuse these with labels/text, + * defined in python script: `keyingsets_builtins.py`. */ + +static constexpr const char *ANIM_KS_LOCATION_ID = "Location"; +static constexpr const char *ANIM_KS_ROTATION_ID = "Rotation"; +static constexpr const char *ANIM_KS_SCALING_ID = "Scaling"; +static constexpr const char *ANIM_KS_LOC_ROT_SCALE_ID = "LocRotScale"; +static constexpr const char *ANIM_KS_LOC_ROT_SCALE_CPROP_ID = "LocRotScaleCProp"; +static constexpr const char *ANIM_KS_AVAILABLE_ID = "Available"; +static constexpr const char *ANIM_KS_WHOLE_CHARACTER_ID = "WholeCharacter"; +static constexpr const char *ANIM_KS_WHOLE_CHARACTER_SELECTED_ID = "WholeCharacterSelected"; + +/** Polling Callback for KeyingSets. */ +using cbKeyingSet_Poll = bool (*)(KeyingSetInfo *ksi, bContext *C); +/** Context Iterator Callback for KeyingSets. */ +using cbKeyingSet_Iterator = void (*)(KeyingSetInfo *ksi, bContext *C, KeyingSet *ks); +/** Property Specifier Callback for KeyingSets (called from iterators) */ +using cbKeyingSet_Generate = void (*)(KeyingSetInfo *ksi, + bContext *C, + KeyingSet *ks, + PointerRNA *ptr); + +/** Callback info for 'Procedural' KeyingSets to use. */ +struct KeyingSetInfo { + KeyingSetInfo *next, *prev; + + /* info */ + /** Identifier used for class name, which KeyingSet instances reference as "Type-info Name". */ + char idname[64]; + /** identifier so that user can hook this up to a KeyingSet (used as label). */ + char name[64]; + /** Short help/description. */ + char description[1024]; /* #RNA_DYN_DESCR_MAX */ + /** Keying settings. */ + short keyingflag; + + /* polling callbacks */ + /** callback for polling the context for whether the right data is available. */ + cbKeyingSet_Poll poll; + + /* generate callbacks */ + /** + * Iterator to use to go through collections of data in context + * - this callback is separate from the 'adding' stage, allowing + * BuiltIn KeyingSets to be manually specified to use. + */ + cbKeyingSet_Iterator iter; + /** Generator to use to add properties based on the data found by iterator. */ + cbKeyingSet_Generate generate; + + /** RNA integration. */ + ExtensionRNA rna_ext; +}; + namespace blender::animrig { /** Mode for modify_keyframes. */ enum class ModifyKeyMode { INSERT = 0, - DELETE, + /* Not calling it just `DELETE` because that interferes with a macro on windows. */ + DELETE_KEY, }; /** Return codes for errors (with Relative KeyingSets). */ @@ -25,4 +91,101 @@ enum class ModifyKeyReturn { MISSING_TYPEINFO = -2, }; +/* -------------------------------------------------------------------- */ +/** \name Keyingset Usage + * \{ */ + +/** + * Given a #KeyingSet and context info, validate Keying Set's paths. + * This is only really necessary with relative/built-in KeyingSets + * where their list of paths is dynamically generated based on the + * current context info. + * + * \note Passing sources as pointer because it can be a nullptr. + * + * \return 0 if succeeded, otherwise an error code: #eModifyKey_Returns. + */ +ModifyKeyReturn validate_keyingset(bContext *C, + blender::Vector *sources, + KeyingSet *keyingset); + +/** + * Use the specified #KeyingSet and context info (if required) + * to add/remove various Keyframes on the specified frame. + * + * Modify keyframes for the channels specified by the KeyingSet. + * This takes into account many of the different combinations of using KeyingSets. + * + * \returns the number of channels that key-frames were added or + * an #eModifyKey_Returns value (always a negative number). + */ +int apply_keyingset(bContext *C, + blender::Vector *sources, + KeyingSet *keyingset, + ModifyKeyMode mode, + float cfra); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Queries + * \{ */ + +/** + * Find builtin #KeyingSet by name. + * + * \return The first builtin #KeyingSet with the given name + */ +KeyingSet *builtin_keyingset_get_named(const char name[]); + +/** + * Find KeyingSet type info given a name. + */ +KeyingSetInfo *keyingset_info_find_name(const char name[]); + +/** + * Check if the ID appears in the paths specified by the #KeyingSet. + */ +bool keyingset_find_id(KeyingSet *keyingset, ID *id); + +/** + * Get Keying Set to use for Auto-Key-Framing some transforms. + */ +KeyingSet *get_keyingset_for_autokeying(const Scene *scene, const char *transformKSName); + +/** + * Get the active Keying Set for the given scene. + */ +KeyingSet *scene_get_active_keyingset(const Scene *scene); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Creation, Destruction + * \{ */ + +/** + * Add the given KeyingSetInfo to the list of type infos, + * and create an appropriate builtin set too. + */ +void keyingset_info_register(KeyingSetInfo *keyingset_info); +/** + * Remove the given #KeyingSetInfo from the list of type infos, + * and also remove the builtin set if appropriate. + */ +void keyingset_info_unregister(Main *bmain, KeyingSetInfo *keyingset_info); + +void keyingset_infos_exit(); + +/** + * Add another data source for Relative Keying Sets to be evaluated with. + */ +void relative_keyingset_add_source(blender::Vector &sources, + ID *id, + StructRNA *srna, + void *data); +void relative_keyingset_add_source(blender::Vector &sources, ID *id); + +/** \} */ + } // namespace blender::animrig diff --git a/source/blender/animrig/CMakeLists.txt b/source/blender/animrig/CMakeLists.txt index e7abaf27604..0ef91c3c7a9 100644 --- a/source/blender/animrig/CMakeLists.txt +++ b/source/blender/animrig/CMakeLists.txt @@ -34,6 +34,7 @@ set(SRC intern/fcurve.cc intern/keyframing.cc intern/keyframing_auto.cc + intern/keyingsets.cc intern/nla.cc intern/pose.cc intern/visualkey.cc diff --git a/source/blender/animrig/intern/action.cc b/source/blender/animrig/intern/action.cc index e5f347ed08c..789c7a3cfac 100644 --- a/source/blender/animrig/intern/action.cc +++ b/source/blender/animrig/intern/action.cc @@ -35,8 +35,6 @@ #include "RNA_path.hh" #include "RNA_prototypes.hh" -#include "ED_keyframing.hh" - #include "MEM_guardedalloc.h" #include "BLT_translation.hh" diff --git a/source/blender/animrig/intern/fcurve.cc b/source/blender/animrig/intern/fcurve.cc index 8b372c1ce22..c236d6c43a8 100644 --- a/source/blender/animrig/intern/fcurve.cc +++ b/source/blender/animrig/intern/fcurve.cc @@ -673,4 +673,29 @@ void bake_fcurve_segments(FCurve *fcu) BKE_fcurve_handles_recalc(fcu); } +bool fcurve_frame_has_keyframe(const FCurve *fcu, float frame) +{ + /* quick sanity check */ + if (ELEM(nullptr, fcu, fcu->bezt)) { + return false; + } + + if ((fcu->flag & FCURVE_MUTED) == 0) { + bool replace; + int i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, frame, fcu->totvert, &replace); + + /* BKE_fcurve_bezt_binarysearch_index will set replace to be 0 or 1 + * - obviously, 1 represents a match + */ + if (replace) { + /* sanity check: 'i' may in rare cases exceed arraylen */ + if ((i >= 0) && (i < fcu->totvert)) { + return true; + } + } + } + + return false; +} + } // namespace blender::animrig diff --git a/source/blender/animrig/intern/keyframing.cc b/source/blender/animrig/intern/keyframing.cc index 7827fc325d4..ea3464d3e4a 100644 --- a/source/blender/animrig/intern/keyframing.cc +++ b/source/blender/animrig/intern/keyframing.cc @@ -261,6 +261,97 @@ eInsertKeyFlags get_keyframing_flags(Scene *scene) return flag; } +/** + * Checks whether the Action assigned to `adt` (if any) has any keyframes at the + * given frame. Since we're only concerned whether a keyframe exists, we can + * simply loop until a match is found. + * + * For layered actions, this only checks for keyframes in the assigned slot. + */ +static bool assigned_action_has_keyframe_at(AnimData &adt, float frame) +{ + /* can only find if there is data */ + if (adt.action == nullptr) { + return false; + } + + if (adt.action->flag & ACT_MUTED) { + return false; + } + + /* loop over F-Curves, using binary-search to try to find matches + * - this assumes that keyframes are only beztriples + */ + for (FCurve *fcu : blender::animrig::legacy::fcurves_for_assigned_action(&adt)) { + /* only check if there are keyframes (currently only of type BezTriple) */ + if (fcu->bezt && fcu->totvert) { + if (fcurve_frame_has_keyframe(fcu, frame)) { + return true; + } + } + } + + /* nothing found */ + return false; +} + +/* Checks whether an Object has a keyframe for a given frame */ +static bool object_frame_has_keyframe(Object *ob, float frame) +{ + /* error checking */ + if (ob == nullptr) { + return false; + } + + /* check its own animation data - specifically, the action it contains */ + if ((ob->adt) && (ob->adt->action)) { + /* #41525 - When the active action is a NLA strip being edited, + * we need to correct the frame number to "look inside" the + * remapped action + */ + float ob_frame = BKE_nla_tweakedit_remap(ob->adt, frame, NLATIME_CONVERT_UNMAP); + + if (assigned_action_has_keyframe_at(*ob->adt, ob_frame)) { + return true; + } + } + + /* nothing found */ + return false; +} + +bool id_frame_has_keyframe(ID *id, float frame) +{ + /* sanity checks */ + if (id == nullptr) { + return false; + } + + /* perform special checks for 'macro' types */ + switch (GS(id->name)) { + case ID_OB: /* object */ + return object_frame_has_keyframe((Object *)id, frame); +#if 0 + /* XXX TODO... for now, just use 'normal' behavior */ + case ID_SCE: /* scene */ + break; +#endif + default: /* 'normal type' */ + { + AnimData *adt = BKE_animdata_from_id(id); + + /* only check keyframes in active action */ + if (adt) { + return assigned_action_has_keyframe_at(*adt, frame); + } + break; + } + } + + /* no keyframe found */ + return false; +} + bool key_insertion_may_create_fcurve(const eInsertKeyFlags insert_key_flags) { return (insert_key_flags & (INSERTKEY_REPLACE | INSERTKEY_AVAILABLE)) == 0; diff --git a/source/blender/animrig/intern/keyframing_auto.cc b/source/blender/animrig/intern/keyframing_auto.cc index 310a56266be..c01bb085603 100644 --- a/source/blender/animrig/intern/keyframing_auto.cc +++ b/source/blender/animrig/intern/keyframing_auto.cc @@ -20,8 +20,6 @@ #include "RNA_path.hh" #include "RNA_prototypes.hh" -#include "ED_keyframing.hh" - #include "ANIM_keyframing.hh" #include "ANIM_keyingsets.hh" @@ -116,7 +114,7 @@ void autokeyframe_object(bContext *C, Scene *scene, Object *ob, Span rn } ReportList *reports = CTX_wm_reports(C); - KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene); + KeyingSet *active_ks = scene_get_active_keyingset(scene); Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct( depsgraph, BKE_scene_frame_get(scene)); @@ -126,15 +124,14 @@ void autokeyframe_object(bContext *C, Scene *scene, Object *ob, Span rn /* Add data-source override for the object. */ blender::Vector sources; - ANIM_relative_keyingset_add_source(sources, id); + relative_keyingset_add_source(sources, id); if (is_keying_flag(scene, AUTOKEY_FLAG_ONLYKEYINGSET) && (active_ks)) { /* Only insert into active keyingset * NOTE: we assume here that the active Keying Set * does not need to have its iterator overridden. */ - ANIM_apply_keyingset( - C, &sources, active_ks, ModifyKeyMode::INSERT, anim_eval_context.eval_time); + apply_keyingset(C, &sources, active_ks, ModifyKeyMode::INSERT, anim_eval_context.eval_time); return; } @@ -172,8 +169,8 @@ bool autokeyframe_object(bContext *C, Scene *scene, Object *ob, KeyingSet *ks) * 3) Free the extra info. */ blender::Vector sources; - ANIM_relative_keyingset_add_source(sources, &ob->id); - ANIM_apply_keyingset(C, &sources, ks, ModifyKeyMode::INSERT, BKE_scene_frame_get(scene)); + relative_keyingset_add_source(sources, &ob->id); + apply_keyingset(C, &sources, ks, ModifyKeyMode::INSERT, BKE_scene_frame_get(scene)); return true; } @@ -190,8 +187,8 @@ bool autokeyframe_pchan(bContext *C, Scene *scene, Object *ob, bPoseChannel *pch * 3) Free the extra info. */ blender::Vector sources; - ANIM_relative_keyingset_add_source(sources, &ob->id, &RNA_PoseBone, pchan); - ANIM_apply_keyingset(C, &sources, ks, ModifyKeyMode::INSERT, BKE_scene_frame_get(scene)); + relative_keyingset_add_source(sources, &ob->id, &RNA_PoseBone, pchan); + apply_keyingset(C, &sources, ks, ModifyKeyMode::INSERT, BKE_scene_frame_get(scene)); return true; } @@ -216,7 +213,7 @@ void autokeyframe_pose_channel(bContext *C, } ReportList *reports = CTX_wm_reports(C); - KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene); + KeyingSet *active_ks = scene_get_active_keyingset(scene); Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); const float scene_frame = BKE_scene_frame_get(scene); const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph, @@ -235,13 +232,12 @@ void autokeyframe_pose_channel(bContext *C, Vector sources; /* Add data-source override for the camera object. */ - ANIM_relative_keyingset_add_source(sources, id, &RNA_PoseBone, pose_channel); + relative_keyingset_add_source(sources, id, &RNA_PoseBone, pose_channel); /* only insert into active keyingset? */ if (is_keying_flag(scene, AUTOKEY_FLAG_ONLYKEYINGSET) && (active_ks)) { /* Run the active Keying Set on the current data-source. */ - ANIM_apply_keyingset( - C, &sources, active_ks, ModifyKeyMode::INSERT, anim_eval_context.eval_time); + apply_keyingset(C, &sources, active_ks, ModifyKeyMode::INSERT, anim_eval_context.eval_time); return; } diff --git a/source/blender/animrig/intern/keyingsets.cc b/source/blender/animrig/intern/keyingsets.cc new file mode 100644 index 00000000000..37a349448cc --- /dev/null +++ b/source/blender/animrig/intern/keyingsets.cc @@ -0,0 +1,466 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup animrig + */ + +#include "ANIM_keyframing.hh" +#include "ANIM_keyingsets.hh" + +#include "BKE_animsys.h" +#include "BKE_context.hh" +#include "BKE_main.hh" +#include "BKE_report.hh" + +#include "BLI_listbase.h" +#include "BLI_string.h" + +#include "DEG_depsgraph.hh" + +#include "DNA_anim_types.h" +#include "DNA_scene_types.h" + +#include "RNA_access.hh" + +#include "WM_api.hh" + +/* Keying Set Type Info declarations. */ +static ListBase keyingset_type_infos = {nullptr, nullptr}; +ListBase builtin_keyingsets = {nullptr, nullptr}; + +namespace blender::animrig { + +void keyingset_info_register(KeyingSetInfo *keyingset_info) +{ + /* Create a new KeyingSet + * - inherit name and keyframing settings from the typeinfo + */ + KeyingSet *keyingset = BKE_keyingset_add(&builtin_keyingsets, + keyingset_info->idname, + keyingset_info->name, + 1, + keyingset_info->keyingflag); + + /* Link this KeyingSet with its typeinfo. */ + memcpy(&keyingset->typeinfo, keyingset_info->idname, sizeof(keyingset->typeinfo)); + + /* Copy description. */ + STRNCPY(keyingset->description, keyingset_info->description); + + /* Add type-info to the list. */ + BLI_addtail(&keyingset_type_infos, keyingset_info); +} + +void keyingset_info_unregister(Main *bmain, KeyingSetInfo *keyingset_info) +{ + /* Find relevant builtin KeyingSets which use this, and remove them. */ + /* TODO: this isn't done now, since unregister is really only used at the moment when we + * reload the scripts, which kind of defeats the purpose of "builtin"? */ + LISTBASE_FOREACH_MUTABLE (KeyingSet *, keyingset, &builtin_keyingsets) { + /* Remove if matching typeinfo name. */ + if (!STREQ(keyingset->typeinfo, keyingset_info->idname)) { + continue; + } + Scene *scene; + BKE_keyingset_free_paths(keyingset); + BLI_remlink(&builtin_keyingsets, keyingset); + + for (scene = static_cast(bmain->scenes.first); scene; + scene = static_cast(scene->id.next)) + { + BLI_remlink_safe(&scene->keyingsets, keyingset); + } + + MEM_freeN(keyingset); + } + + BLI_freelinkN(&keyingset_type_infos, keyingset_info); +} + +void keyingset_infos_exit() +{ + /* Free type infos. */ + LISTBASE_FOREACH_MUTABLE (KeyingSetInfo *, keyingset_info, &keyingset_type_infos) { + /* Free extra RNA data, and remove from list. */ + if (keyingset_info->rna_ext.free) { + keyingset_info->rna_ext.free(keyingset_info->rna_ext.data); + } + BLI_freelinkN(&keyingset_type_infos, keyingset_info); + } + + BKE_keyingsets_free(&builtin_keyingsets); +} + +bool keyingset_find_id(KeyingSet *keyingset, ID *id) +{ + if (ELEM(nullptr, keyingset, id)) { + return false; + } + + return BLI_findptr(&keyingset->paths, id, offsetof(KS_Path, id)) != nullptr; +} + +KeyingSetInfo *keyingset_info_find_name(const char name[]) +{ + if ((name == nullptr) || (name[0] == 0)) { + return nullptr; + } + + /* Search by comparing names. */ + return static_cast( + BLI_findstring(&keyingset_type_infos, name, offsetof(KeyingSetInfo, idname))); +} + +KeyingSet *builtin_keyingset_get_named(const char name[]) +{ + if (name[0] == 0) { + return nullptr; + } + + /* Loop over KeyingSets checking names. */ + LISTBASE_FOREACH (KeyingSet *, keyingset, &builtin_keyingsets) { + if (STREQ(name, keyingset->idname)) { + return keyingset; + } + } + +/* Complain about missing keying sets on debug builds. */ +#ifndef NDEBUG + printf("%s: '%s' not found\n", __func__, name); +#endif + + /* no matches found */ + return nullptr; +} + +KeyingSet *get_keyingset_for_autokeying(const Scene *scene, const char *transformKSName) +{ + /* Get KeyingSet to use + * - use the active KeyingSet if defined (and user wants to use it for all autokeying), + * or otherwise key transforms only + */ + if (is_keying_flag(scene, AUTOKEY_FLAG_ONLYKEYINGSET) && (scene->active_keyingset)) { + return scene_get_active_keyingset(scene); + } + + if (is_keying_flag(scene, AUTOKEY_FLAG_INSERTAVAILABLE)) { + return builtin_keyingset_get_named(ANIM_KS_AVAILABLE_ID); + } + + return builtin_keyingset_get_named(transformKSName); +} + +KeyingSet *scene_get_active_keyingset(const Scene *scene) +{ + /* If no scene, we've got no hope of finding the Keying Set. */ + if (scene == nullptr) { + return nullptr; + } + + /* Currently, there are several possibilities here: + * - 0: no active keying set + * - > 0: one of the user-defined Keying Sets, but indices start from 0 (hence the -1) + * - < 0: a builtin keying set + */ + if (scene->active_keyingset > 0) { + return static_cast(BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1)); + } + return static_cast( + BLI_findlink(&builtin_keyingsets, (-scene->active_keyingset) - 1)); +} + +void relative_keyingset_add_source(blender::Vector &sources, + ID *id, + StructRNA *srna, + void *data) +{ + if (ELEM(nullptr, srna, data, id)) { + return; + } + sources.append(RNA_pointer_create(id, srna, data)); +} + +void relative_keyingset_add_source(blender::Vector &sources, ID *id) +{ + if (id == nullptr) { + return; + } + sources.append(RNA_id_pointer_create(id)); +} + +/* Special 'Overrides' Iterator for Relative KeyingSets ------ */ + +/* Iterator used for overriding the behavior of iterators defined for + * relative Keying Sets, with the main usage of this being operators + * requiring Auto Keyframing. Internal Use Only! + */ +static void RKS_ITER_overrides_list(KeyingSetInfo *keyingset_info, + bContext *C, + KeyingSet *keyingset, + blender::Vector &sources) +{ + for (PointerRNA ptr : sources) { + /* Run generate callback on this data. */ + keyingset_info->generate(keyingset_info, C, keyingset, &ptr); + } +} + +ModifyKeyReturn validate_keyingset(bContext *C, + blender::Vector *sources, + KeyingSet *keyingset) +{ + if (keyingset == nullptr) { + return ModifyKeyReturn::SUCCESS; + } + + /* If relative Keying Sets, poll and build up the paths. */ + if (keyingset->flag & KEYINGSET_ABSOLUTE) { + return ModifyKeyReturn::SUCCESS; + } + + KeyingSetInfo *keyingset_info = keyingset_info_find_name(keyingset->typeinfo); + + /* Clear all existing paths + * NOTE: BKE_keyingset_free_paths() frees all of the paths for the KeyingSet, but not the set + * itself. + */ + BKE_keyingset_free_paths(keyingset); + + /* Get the associated 'type info' for this KeyingSet. */ + if (keyingset_info == nullptr) { + return ModifyKeyReturn::MISSING_TYPEINFO; + } + /* TODO: check for missing callbacks! */ + + /* Check if it can be used in the current context. */ + if (!keyingset_info->poll(keyingset_info, C)) { + /* Poll callback tells us that KeyingSet is useless in current context. */ + /* FIXME: the poll callback needs to give us more info why. */ + return ModifyKeyReturn::INVALID_CONTEXT; + } + + /* If a list of data sources are provided, run a special iterator over them, + * otherwise, just continue per normal. + */ + if (sources != nullptr) { + RKS_ITER_overrides_list(keyingset_info, C, keyingset, *sources); + } + else { + keyingset_info->iter(keyingset_info, C, keyingset); + } + + /* If we don't have any paths now, then this still qualifies as invalid context. */ + /* FIXME: we need some error conditions (to be retrieved from the iterator why this failed!) + */ + if (BLI_listbase_is_empty(&keyingset->paths)) { + return ModifyKeyReturn::INVALID_CONTEXT; + } + + return ModifyKeyReturn::SUCCESS; +} + +/* Determine which keying flags apply based on the override flags. */ +static eInsertKeyFlags keyingset_apply_keying_flags(const eInsertKeyFlags base_flags, + const eInsertKeyFlags overrides, + const eInsertKeyFlags own_flags) +{ + /* Pass through all flags by default (i.e. even not explicitly listed ones). */ + eInsertKeyFlags result = base_flags; + +/* The logic for whether a keying flag applies is as follows: + * - If the flag in question is set in "overrides", that means that the + * status of that flag in "own_flags" is used + * - If however the flag isn't set, then its value in "base_flags" is used + * instead (i.e. no override) + */ +#define APPLY_KEYINGFLAG_OVERRIDE(kflag) \ + if (overrides & kflag) { \ + result &= ~kflag; \ + result |= (own_flags & kflag); \ + } + + /* Apply the flags one by one... + * (See rna_def_common_keying_flags() for the supported flags) + */ + APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_NEEDED) + APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_MATRIX) + +#undef APPLY_KEYINGFLAG_OVERRIDE + + return result; +} + +static int insert_key_to_keying_set_path(bContext *C, + KS_Path *keyingset_path, + KeyingSet *keyingset, + const eInsertKeyFlags insert_key_flags, + const ModifyKeyMode mode, + const float frame) +{ + /* Since keying settings can be defined on the paths too, + * apply the settings for this path first. */ + const eInsertKeyFlags path_insert_key_flags = keyingset_apply_keying_flags( + insert_key_flags, + eInsertKeyFlags(keyingset_path->keyingoverride), + eInsertKeyFlags(keyingset_path->keyingflag)); + + const char *groupname = nullptr; + /* Get pointer to name of group to add channels to. */ + if (keyingset_path->groupmode == KSP_GROUP_NONE) { + groupname = nullptr; + } + else if (keyingset_path->groupmode == KSP_GROUP_KSNAME) { + groupname = keyingset->name; + } + else { + groupname = keyingset_path->group; + } + + /* Init - array_length should be greater than array_index so that + * normal non-array entries get keyframed correctly. + */ + int array_index = keyingset_path->array_index; + int array_length = array_index; + + /* Get length of array if whole array option is enabled. */ + if (keyingset_path->flag & KSP_FLAG_WHOLE_ARRAY) { + PointerRNA ptr; + PropertyRNA *prop; + + PointerRNA id_ptr = RNA_id_pointer_create(keyingset_path->id); + if (RNA_path_resolve_property(&id_ptr, keyingset_path->rna_path, &ptr, &prop)) { + array_length = RNA_property_array_length(&ptr, prop); + /* Start from start of array, instead of the previously specified index - #48020 */ + array_index = 0; + } + } + + /* We should do at least one step. */ + if (array_length == array_index) { + array_length++; + } + + Main *bmain = CTX_data_main(C); + ReportList *reports = CTX_wm_reports(C); + Scene *scene = CTX_data_scene(C); + const eBezTriple_KeyframeType keytype = eBezTriple_KeyframeType( + scene->toolsettings->keyframe_type); + /* For each possible index, perform operation + * - Assume that array-length is greater than index. */ + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph, + frame); + int keyed_channels = 0; + + CombinedKeyingResult combined_result; + for (; array_index < array_length; array_index++) { + if (mode == ModifyKeyMode::INSERT) { + const std::optional group = groupname ? std::optional(groupname) : + std::nullopt; + const std::optional index = array_index >= 0 ? std::optional(array_index) : + std::nullopt; + PointerRNA id_rna_pointer = RNA_id_pointer_create(keyingset_path->id); + CombinedKeyingResult result = insert_keyframes(bmain, + &id_rna_pointer, + group, + {{keyingset_path->rna_path, {}, index}}, + std::nullopt, + anim_eval_context, + keytype, + path_insert_key_flags); + keyed_channels += result.get_count(SingleKeyingResult::SUCCESS); + combined_result.merge(result); + } + else if (mode == ModifyKeyMode::DELETE_KEY) { + RNAPath rna_path = {keyingset_path->rna_path, std::nullopt, array_index}; + if (array_index < 0) { + rna_path.index = std::nullopt; + } + keyed_channels += delete_keyframe(bmain, reports, keyingset_path->id, rna_path, frame); + } + } + + if (combined_result.get_count(SingleKeyingResult::SUCCESS) == 0) { + combined_result.generate_reports(reports); + } + + switch (GS(keyingset_path->id->name)) { + case ID_OB: /* Object (or Object-Related) Keyframes */ + { + Object *ob = (Object *)keyingset_path->id; + + /* XXX: only object transforms? */ + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + break; + } + default: + DEG_id_tag_update(keyingset_path->id, ID_RECALC_ANIMATION_NO_FLUSH); + break; + } + + /* Send notifiers for updates (this doesn't require context to work!). */ + WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_ADDED, nullptr); + + return keyed_channels; +} + +int apply_keyingset(bContext *C, + blender::Vector *sources, + KeyingSet *keyingset, + const ModifyKeyMode mode, + const float cfra) +{ + if (keyingset == nullptr) { + return 0; + } + + Scene *scene = CTX_data_scene(C); + const eInsertKeyFlags base_kflags = get_keyframing_flags(scene); + eInsertKeyFlags kflag = INSERTKEY_NOFLAGS; + if (mode == ModifyKeyMode::INSERT) { + /* use context settings as base */ + kflag = keyingset_apply_keying_flags(base_kflags, + eInsertKeyFlags(keyingset->keyingoverride), + eInsertKeyFlags(keyingset->keyingflag)); + } + else if (mode == ModifyKeyMode::DELETE_KEY) { + kflag = INSERTKEY_NOFLAGS; + } + + /* If relative Keying Sets, poll and build up the paths. */ + { + const ModifyKeyReturn error = validate_keyingset(C, sources, keyingset); + if (error != ModifyKeyReturn::SUCCESS) { + BLI_assert(int(error) < 0); + return int(error); + } + } + + ReportList *reports = CTX_wm_reports(C); + int keyed_channels = 0; + + /* Apply the paths as specified in the KeyingSet now. */ + LISTBASE_FOREACH (KS_Path *, keyingset_path, &keyingset->paths) { + /* Skip path if no ID pointer is specified. */ + if (keyingset_path->id == nullptr) { + BKE_reportf(reports, + RPT_WARNING, + "Skipping path in keying set, as it has no ID (KS = '%s', path = '%s[%d]')", + keyingset->name, + keyingset_path->rna_path, + keyingset_path->array_index); + continue; + } + + keyed_channels += insert_key_to_keying_set_path( + C, keyingset_path, keyingset, kflag, mode, cfra); + } + + /* Return the number of channels successfully affected. */ + BLI_assert(keyed_channels >= 0); + return keyed_channels; +} + +} // namespace blender::animrig diff --git a/source/blender/editors/animation/anim_channels_defines.cc b/source/blender/editors/animation/anim_channels_defines.cc index 8de3c0b5d0d..c55ab78aabd 100644 --- a/source/blender/editors/animation/anim_channels_defines.cc +++ b/source/blender/editors/animation/anim_channels_defines.cc @@ -71,7 +71,8 @@ #include "UI_view2d.hh" #include "ED_anim_api.hh" -#include "ED_keyframing.hh" + +#include "ANIM_fcurve.hh" #include "WM_api.hh" #include "WM_types.hh" @@ -5373,7 +5374,7 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi /* try to resolve the path stored in the F-Curve */ if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) { /* set the special 'replace' flag if on a keyframe */ - if (fcurve_frame_has_keyframe(fcu, cfra)) { + if (blender::animrig::fcurve_frame_has_keyframe(fcu, cfra)) { flag |= INSERTKEY_REPLACE; } @@ -5463,7 +5464,7 @@ static void achannel_setting_slider_nla_curve_cb(bContext *C, void * /*id_poin*/ if (fcu && prop) { /* set the special 'replace' flag if on a keyframe */ - if (fcurve_frame_has_keyframe(fcu, cfra)) { + if (blender::animrig::fcurve_frame_has_keyframe(fcu, cfra)) { flag |= INSERTKEY_REPLACE; } diff --git a/source/blender/editors/animation/anim_intern.hh b/source/blender/editors/animation/anim_intern.hh index d15432467fa..99f559b322d 100644 --- a/source/blender/editors/animation/anim_intern.hh +++ b/source/blender/editors/animation/anim_intern.hh @@ -15,7 +15,7 @@ struct ListBase; /* KeyingSets/Keyframing Interface ------------- */ -/** List of builtin KeyingSets (defined in `keyingsets.cc`). */ +/** List of builtin KeyingSets (defined in `blender/animrig/keyingsets.cc`). */ extern ListBase builtin_keyingsets; /* Operator Define Prototypes ------------------- */ diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index f2a7ca7c04c..044547efa89 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -180,13 +180,13 @@ static int insert_key_with_keyingset(bContext *C, wmOperator *op, KeyingSet *ks) /* 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 */ - if (obedit && ANIM_keyingset_find_id(ks, (ID *)obedit->data)) { + if (obedit && blender::animrig::keyingset_find_id(ks, (ID *)obedit->data)) { blender::ed::object::mode_set(C, OB_MODE_OBJECT); ob_edit_mode = true; } /* try to insert keyframes for the channels specified by KeyingSet */ - const int num_channels = ANIM_apply_keyingset( + const int num_channels = blender::animrig::apply_keyingset( C, nullptr, ks, blender::animrig::ModifyKeyMode::INSERT, cfra); if (G.debug & G_DEBUG) { BKE_reportf(op->reports, @@ -635,8 +635,8 @@ static int delete_key_using_keying_set(bContext *C, wmOperator *op, KeyingSet *k const bool confirm = op->flag & OP_IS_INVOKE; /* try to delete keyframes for the channels specified by KeyingSet */ - num_channels = ANIM_apply_keyingset( - C, nullptr, ks, blender::animrig::ModifyKeyMode::DELETE, cfra); + num_channels = blender::animrig::apply_keyingset( + C, nullptr, ks, blender::animrig::ModifyKeyMode::DELETE_KEY, cfra); if (G.debug & G_DEBUG) { printf("KeyingSet '%s' - Successfully removed %d Keyframes\n", ks->name, num_channels); } @@ -989,7 +989,7 @@ static int delete_key_v3d_without_keying_set(bContext *C, wmOperator *op) static int delete_key_v3d_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - KeyingSet *ks = ANIM_scene_get_active_keyingset(scene); + KeyingSet *ks = blender::animrig::scene_get_active_keyingset(scene); if (ks == nullptr) { return delete_key_v3d_without_keying_set(C, op); @@ -1364,31 +1364,6 @@ void ANIM_OT_keyframe_clear_button(wmOperatorType *ot) /* --------------- API/Per-Datablock Handling ------------------- */ -bool fcurve_frame_has_keyframe(const FCurve *fcu, float frame) -{ - /* quick sanity check */ - if (ELEM(nullptr, fcu, fcu->bezt)) { - return false; - } - - if ((fcu->flag & FCURVE_MUTED) == 0) { - bool replace; - int i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, frame, fcu->totvert, &replace); - - /* BKE_fcurve_bezt_binarysearch_index will set replace to be 0 or 1 - * - obviously, 1 represents a match - */ - if (replace) { - /* sanity check: 'i' may in rare cases exceed arraylen */ - if ((i >= 0) && (i < fcu->totvert)) { - return true; - } - } - } - - return false; -} - bool fcurve_is_changed(PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, @@ -1408,99 +1383,6 @@ bool fcurve_is_changed(PointerRNA ptr, return !compare_ff_relative(fcurve_val, cur_val, FLT_EPSILON, 64); } -/** - * Checks whether the Action assigned to `adt` (if any) has any keyframes at the - * given frame. Since we're only concerned whether a keyframe exists, we can - * simply loop until a match is found. - * - * For layered actions, this only checks for keyframes in the assigned slot. - */ -static bool assigned_action_has_keyframe_at(AnimData &adt, float frame) -{ - /* can only find if there is data */ - if (adt.action == nullptr) { - return false; - } - - if (adt.action->flag & ACT_MUTED) { - return false; - } - - /* loop over F-Curves, using binary-search to try to find matches - * - this assumes that keyframes are only beztriples - */ - for (FCurve *fcu : blender::animrig::legacy::fcurves_for_assigned_action(&adt)) { - /* only check if there are keyframes (currently only of type BezTriple) */ - if (fcu->bezt && fcu->totvert) { - if (fcurve_frame_has_keyframe(fcu, frame)) { - return true; - } - } - } - - /* nothing found */ - return false; -} - -/* Checks whether an Object has a keyframe for a given frame */ -static bool object_frame_has_keyframe(Object *ob, float frame) -{ - /* error checking */ - if (ob == nullptr) { - return false; - } - - /* check its own animation data - specifically, the action it contains */ - if ((ob->adt) && (ob->adt->action)) { - /* #41525 - When the active action is a NLA strip being edited, - * we need to correct the frame number to "look inside" the - * remapped action - */ - float ob_frame = BKE_nla_tweakedit_remap(ob->adt, frame, NLATIME_CONVERT_UNMAP); - - if (assigned_action_has_keyframe_at(*ob->adt, ob_frame)) { - return true; - } - } - - /* nothing found */ - return false; -} - -/* --------------- API ------------------- */ - -bool id_frame_has_keyframe(ID *id, float frame) -{ - /* sanity checks */ - if (id == nullptr) { - return false; - } - - /* perform special checks for 'macro' types */ - switch (GS(id->name)) { - case ID_OB: /* object */ - return object_frame_has_keyframe((Object *)id, frame); -#if 0 - /* XXX TODO... for now, just use 'normal' behavior */ - case ID_SCE: /* scene */ - break; -#endif - default: /* 'normal type' */ - { - AnimData *adt = BKE_animdata_from_id(id); - - /* only check keyframes in active action */ - if (adt) { - return assigned_action_has_keyframe_at(*adt, frame); - } - break; - } - } - - /* no keyframe found */ - return false; -} - /* -------------------------------------------------------------------- */ /** \name Internal Utilities * \{ */ diff --git a/source/blender/editors/animation/keyingsets.cc b/source/blender/editors/animation/keyingsets.cc index bda6db93af0..613b2858313 100644 --- a/source/blender/editors/animation/keyingsets.cc +++ b/source/blender/editors/animation/keyingsets.cc @@ -557,145 +557,11 @@ void ANIM_OT_keying_set_active_set(wmOperatorType *ot) RNA_def_enum_funcs(prop, keyingset_set_active_enum_itemf); } -/* ******************************************* */ -/* REGISTERED KEYING SETS */ - -/* Keying Set Type Info declarations. */ -static ListBase keyingset_type_infos = {nullptr, nullptr}; - -ListBase builtin_keyingsets = {nullptr, nullptr}; - -/* --------------- */ - -KeyingSetInfo *ANIM_keyingset_info_find_name(const char name[]) -{ - if ((name == nullptr) || (name[0] == 0)) { - return nullptr; - } - - /* Search by comparing names. */ - return static_cast( - BLI_findstring(&keyingset_type_infos, name, offsetof(KeyingSetInfo, idname))); -} - -KeyingSet *ANIM_builtin_keyingset_get_named(const char name[]) -{ - if (name[0] == 0) { - return nullptr; - } - - /* Loop over KeyingSets checking names. */ - LISTBASE_FOREACH (KeyingSet *, keyingset, &builtin_keyingsets) { - if (STREQ(name, keyingset->idname)) { - return keyingset; - } - } - -/* Complain about missing keying sets on debug builds. */ -#ifndef NDEBUG - printf("%s: '%s' not found\n", __func__, name); -#endif - - /* no matches found */ - return nullptr; -} - -/* --------------- */ - -void ANIM_keyingset_info_register(KeyingSetInfo *keyingset_info) -{ - /* Create a new KeyingSet - * - inherit name and keyframing settings from the typeinfo - */ - KeyingSet *keyingset = BKE_keyingset_add(&builtin_keyingsets, - keyingset_info->idname, - keyingset_info->name, - 1, - keyingset_info->keyingflag); - - /* Link this KeyingSet with its typeinfo. */ - memcpy(&keyingset->typeinfo, keyingset_info->idname, sizeof(keyingset->typeinfo)); - - /* Copy description. */ - STRNCPY(keyingset->description, keyingset_info->description); - - /* Add type-info to the list. */ - BLI_addtail(&keyingset_type_infos, keyingset_info); -} - -void ANIM_keyingset_info_unregister(Main *bmain, KeyingSetInfo *keyingset_info) -{ - /* Find relevant builtin KeyingSets which use this, and remove them. */ - /* TODO: this isn't done now, since unregister is really only used at the moment when we - * reload the scripts, which kind of defeats the purpose of "builtin"? */ - LISTBASE_FOREACH_MUTABLE (KeyingSet *, keyingset, &builtin_keyingsets) { - /* Remove if matching typeinfo name. */ - if (!STREQ(keyingset->typeinfo, keyingset_info->idname)) { - continue; - } - Scene *scene; - BKE_keyingset_free_paths(keyingset); - BLI_remlink(&builtin_keyingsets, keyingset); - - for (scene = static_cast(bmain->scenes.first); scene; - scene = static_cast(scene->id.next)) - { - BLI_remlink_safe(&scene->keyingsets, keyingset); - } - - MEM_freeN(keyingset); - } - - BLI_freelinkN(&keyingset_type_infos, keyingset_info); -} - -void ANIM_keyingset_infos_exit() -{ - /* Free type infos. */ - LISTBASE_FOREACH_MUTABLE (KeyingSetInfo *, keyingset_info, &keyingset_type_infos) { - /* Free extra RNA data, and remove from list. */ - if (keyingset_info->rna_ext.free) { - keyingset_info->rna_ext.free(keyingset_info->rna_ext.data); - } - BLI_freelinkN(&keyingset_type_infos, keyingset_info); - } - - BKE_keyingsets_free(&builtin_keyingsets); -} - -bool ANIM_keyingset_find_id(KeyingSet *keyingset, ID *id) -{ - if (ELEM(nullptr, keyingset, id)) { - return false; - } - - return BLI_findptr(&keyingset->paths, id, offsetof(KS_Path, id)) != nullptr; -} - /* ******************************************* */ /* KEYING SETS API (for UI) */ /* Getters for Active/Indices ----------------------------- */ -KeyingSet *ANIM_scene_get_active_keyingset(const Scene *scene) -{ - /* If no scene, we've got no hope of finding the Keying Set. */ - if (scene == nullptr) { - return nullptr; - } - - /* Currently, there are several possibilities here: - * - 0: no active keying set - * - > 0: one of the user-defined Keying Sets, but indices start from 0 (hence the -1) - * - < 0: a builtin keying set - */ - if (scene->active_keyingset > 0) { - return static_cast(BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1)); - } - return static_cast( - BLI_findlink(&builtin_keyingsets, (-scene->active_keyingset) - 1)); -} - int ANIM_scene_get_keyingset_index(Scene *scene, KeyingSet *keyingset) { int index; @@ -727,25 +593,6 @@ int ANIM_scene_get_keyingset_index(Scene *scene, KeyingSet *keyingset) return 0; } -KeyingSet *ANIM_get_keyingset_for_autokeying(const Scene *scene, const char *transformKSName) -{ - /* Get KeyingSet to use - * - use the active KeyingSet if defined (and user wants to use it for all autokeying), - * or otherwise key transforms only - */ - if (blender::animrig::is_keying_flag(scene, AUTOKEY_FLAG_ONLYKEYINGSET) && - (scene->active_keyingset)) - { - return ANIM_scene_get_active_keyingset(scene); - } - - if (blender::animrig::is_keying_flag(scene, AUTOKEY_FLAG_INSERTAVAILABLE)) { - return ANIM_builtin_keyingset_get_named(ANIM_KS_AVAILABLE_ID); - } - - return ANIM_builtin_keyingset_get_named(transformKSName); -} - static void anim_keyingset_visit_for_search_impl( const bContext *C, blender::FunctionRef visit_fn, @@ -880,7 +727,7 @@ bool ANIM_keyingset_context_ok_poll(bContext *C, KeyingSet *keyingset) return true; } - KeyingSetInfo *keyingset_info = ANIM_keyingset_info_find_name(keyingset->typeinfo); + KeyingSetInfo *keyingset_info = blender::animrig::keyingset_info_find_name(keyingset->typeinfo); /* Get the associated 'type info' for this KeyingSet. */ if (keyingset_info == nullptr) { @@ -891,302 +738,3 @@ bool ANIM_keyingset_context_ok_poll(bContext *C, KeyingSet *keyingset) /* Check if it can be used in the current context. */ return keyingset_info->poll(keyingset_info, C); } - -/* Special 'Overrides' Iterator for Relative KeyingSets ------ */ - -/* Iterator used for overriding the behavior of iterators defined for - * relative Keying Sets, with the main usage of this being operators - * requiring Auto Keyframing. Internal Use Only! - */ -static void RKS_ITER_overrides_list(KeyingSetInfo *keyingset_info, - bContext *C, - KeyingSet *keyingset, - blender::Vector &sources) -{ - for (PointerRNA ptr : sources) { - /* Run generate callback on this data. */ - keyingset_info->generate(keyingset_info, C, keyingset, &ptr); - } -} - -void ANIM_relative_keyingset_add_source(blender::Vector &sources, - ID *id, - StructRNA *srna, - void *data) -{ - if (ELEM(nullptr, srna, data, id)) { - return; - } - sources.append(RNA_pointer_create(id, srna, data)); -} - -void ANIM_relative_keyingset_add_source(blender::Vector &sources, ID *id) -{ - if (id == nullptr) { - return; - } - sources.append(RNA_id_pointer_create(id)); -} - -/* KeyingSet Operations (Insert/Delete Keyframes) ------------ */ - -blender::animrig::ModifyKeyReturn ANIM_validate_keyingset(bContext *C, - blender::Vector *sources, - KeyingSet *keyingset) -{ - using namespace blender::animrig; - if (keyingset == nullptr) { - return ModifyKeyReturn::SUCCESS; - } - - /* If relative Keying Sets, poll and build up the paths. */ - if (keyingset->flag & KEYINGSET_ABSOLUTE) { - return ModifyKeyReturn::SUCCESS; - } - - KeyingSetInfo *keyingset_info = ANIM_keyingset_info_find_name(keyingset->typeinfo); - - /* Clear all existing paths - * NOTE: BKE_keyingset_free_paths() frees all of the paths for the KeyingSet, but not the set - * itself. - */ - BKE_keyingset_free_paths(keyingset); - - /* Get the associated 'type info' for this KeyingSet. */ - if (keyingset_info == nullptr) { - return ModifyKeyReturn::MISSING_TYPEINFO; - } - /* TODO: check for missing callbacks! */ - - /* Check if it can be used in the current context. */ - if (!keyingset_info->poll(keyingset_info, C)) { - /* Poll callback tells us that KeyingSet is useless in current context. */ - /* FIXME: the poll callback needs to give us more info why. */ - return ModifyKeyReturn::INVALID_CONTEXT; - } - - /* If a list of data sources are provided, run a special iterator over them, - * otherwise, just continue per normal. - */ - if (sources != nullptr) { - RKS_ITER_overrides_list(keyingset_info, C, keyingset, *sources); - } - else { - keyingset_info->iter(keyingset_info, C, keyingset); - } - - /* If we don't have any paths now, then this still qualifies as invalid context. */ - /* FIXME: we need some error conditions (to be retrieved from the iterator why this failed!) - */ - if (BLI_listbase_is_empty(&keyingset->paths)) { - return ModifyKeyReturn::INVALID_CONTEXT; - } - - return ModifyKeyReturn::SUCCESS; -} - -/* Determine which keying flags apply based on the override flags. */ -static eInsertKeyFlags keyingset_apply_keying_flags(const eInsertKeyFlags base_flags, - const eInsertKeyFlags overrides, - const eInsertKeyFlags own_flags) -{ - /* Pass through all flags by default (i.e. even not explicitly listed ones). */ - eInsertKeyFlags result = base_flags; - -/* The logic for whether a keying flag applies is as follows: - * - If the flag in question is set in "overrides", that means that the - * status of that flag in "own_flags" is used - * - If however the flag isn't set, then its value in "base_flags" is used - * instead (i.e. no override) - */ -#define APPLY_KEYINGFLAG_OVERRIDE(kflag) \ - if (overrides & kflag) { \ - result &= ~kflag; \ - result |= (own_flags & kflag); \ - } - - /* Apply the flags one by one... - * (See rna_def_common_keying_flags() for the supported flags) - */ - APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_NEEDED) - APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_MATRIX) - -#undef APPLY_KEYINGFLAG_OVERRIDE - - return result; -} - -static int insert_key_to_keying_set_path(bContext *C, - KS_Path *keyingset_path, - KeyingSet *keyingset, - const eInsertKeyFlags insert_key_flags, - const blender::animrig::ModifyKeyMode mode, - const float frame) -{ - using namespace blender::animrig; - /* Since keying settings can be defined on the paths too, - * apply the settings for this path first. */ - const eInsertKeyFlags path_insert_key_flags = keyingset_apply_keying_flags( - insert_key_flags, - eInsertKeyFlags(keyingset_path->keyingoverride), - eInsertKeyFlags(keyingset_path->keyingflag)); - - const char *groupname = nullptr; - /* Get pointer to name of group to add channels to. */ - if (keyingset_path->groupmode == KSP_GROUP_NONE) { - groupname = nullptr; - } - else if (keyingset_path->groupmode == KSP_GROUP_KSNAME) { - groupname = keyingset->name; - } - else { - groupname = keyingset_path->group; - } - - /* Init - array_length should be greater than array_index so that - * normal non-array entries get keyframed correctly. - */ - int array_index = keyingset_path->array_index; - int array_length = array_index; - - /* Get length of array if whole array option is enabled. */ - if (keyingset_path->flag & KSP_FLAG_WHOLE_ARRAY) { - PointerRNA ptr; - PropertyRNA *prop; - - PointerRNA id_ptr = RNA_id_pointer_create(keyingset_path->id); - if (RNA_path_resolve_property(&id_ptr, keyingset_path->rna_path, &ptr, &prop)) { - array_length = RNA_property_array_length(&ptr, prop); - /* Start from start of array, instead of the previously specified index - #48020 */ - array_index = 0; - } - } - - /* We should do at least one step. */ - if (array_length == array_index) { - array_length++; - } - - Main *bmain = CTX_data_main(C); - ReportList *reports = CTX_wm_reports(C); - Scene *scene = CTX_data_scene(C); - const eBezTriple_KeyframeType keytype = eBezTriple_KeyframeType( - scene->toolsettings->keyframe_type); - /* For each possible index, perform operation - * - Assume that array-length is greater than index. */ - Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); - const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph, - frame); - int keyed_channels = 0; - - CombinedKeyingResult combined_result; - for (; array_index < array_length; array_index++) { - if (mode == ModifyKeyMode::INSERT) { - const std::optional group = groupname ? std::optional(groupname) : - std::nullopt; - const std::optional index = array_index >= 0 ? std::optional(array_index) : - std::nullopt; - PointerRNA id_rna_pointer = RNA_id_pointer_create(keyingset_path->id); - CombinedKeyingResult result = insert_keyframes(bmain, - &id_rna_pointer, - group, - {{keyingset_path->rna_path, {}, index}}, - std::nullopt, - anim_eval_context, - keytype, - path_insert_key_flags); - keyed_channels += result.get_count(SingleKeyingResult::SUCCESS); - combined_result.merge(result); - } - else if (mode == ModifyKeyMode::DELETE) { - RNAPath rna_path = {keyingset_path->rna_path, std::nullopt, array_index}; - if (array_index < 0) { - rna_path.index = std::nullopt; - } - keyed_channels += delete_keyframe(bmain, reports, keyingset_path->id, rna_path, frame); - } - } - - if (combined_result.get_count(SingleKeyingResult::SUCCESS) == 0) { - combined_result.generate_reports(reports); - } - - switch (GS(keyingset_path->id->name)) { - case ID_OB: /* Object (or Object-Related) Keyframes */ - { - Object *ob = (Object *)keyingset_path->id; - - /* XXX: only object transforms? */ - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - break; - } - default: - DEG_id_tag_update(keyingset_path->id, ID_RECALC_ANIMATION_NO_FLUSH); - break; - } - - /* Send notifiers for updates (this doesn't require context to work!). */ - WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_ADDED, nullptr); - - return keyed_channels; -} - -int ANIM_apply_keyingset(bContext *C, - blender::Vector *sources, - KeyingSet *keyingset, - const blender::animrig::ModifyKeyMode mode, - const float cfra) -{ - using namespace blender::animrig; - if (keyingset == nullptr) { - return 0; - } - - Scene *scene = CTX_data_scene(C); - const eInsertKeyFlags base_kflags = get_keyframing_flags(scene); - eInsertKeyFlags kflag = INSERTKEY_NOFLAGS; - if (mode == ModifyKeyMode::INSERT) { - /* use context settings as base */ - kflag = keyingset_apply_keying_flags(base_kflags, - eInsertKeyFlags(keyingset->keyingoverride), - eInsertKeyFlags(keyingset->keyingflag)); - } - else if (mode == ModifyKeyMode::DELETE) { - kflag = INSERTKEY_NOFLAGS; - } - - /* If relative Keying Sets, poll and build up the paths. */ - { - const ModifyKeyReturn error = ANIM_validate_keyingset(C, sources, keyingset); - if (error != ModifyKeyReturn::SUCCESS) { - BLI_assert(int(error) < 0); - return int(error); - } - } - - ReportList *reports = CTX_wm_reports(C); - int keyed_channels = 0; - - /* Apply the paths as specified in the KeyingSet now. */ - LISTBASE_FOREACH (KS_Path *, keyingset_path, &keyingset->paths) { - /* Skip path if no ID pointer is specified. */ - if (keyingset_path->id == nullptr) { - BKE_reportf(reports, - RPT_WARNING, - "Skipping path in keying set, as it has no ID (KS = '%s', path = '%s[%d]')", - keyingset->name, - keyingset_path->rna_path, - keyingset_path->array_index); - continue; - } - - keyed_channels += insert_key_to_keying_set_path( - C, keyingset_path, keyingset, kflag, mode, cfra); - } - - /* Return the number of channels successfully affected. */ - BLI_assert(keyed_channels >= 0); - return keyed_channels; -} - -/* ************************************************** */ diff --git a/source/blender/editors/armature/pose_lib_2.cc b/source/blender/editors/armature/pose_lib_2.cc index a46a0f5c2e2..1965b520844 100644 --- a/source/blender/editors/armature/pose_lib_2.cc +++ b/source/blender/editors/armature/pose_lib_2.cc @@ -136,7 +136,8 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, PoseBlendData *pbd) bPose *pose = pbd->ob->pose; bAction *act = poselib_action_to_blend(pbd); - KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID); + KeyingSet *ks = blender::animrig::get_keyingset_for_autokeying(scene, + ANIM_KS_WHOLE_CHARACTER_ID); blender::Vector sources; /* start tagging/keying */ @@ -155,7 +156,7 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, PoseBlendData *pbd) } /* Add data-source override for the PoseChannel, to be used later. */ - ANIM_relative_keyingset_add_source(sources, &pbd->ob->id, &RNA_PoseBone, pchan); + blender::animrig::relative_keyingset_add_source(sources, &pbd->ob->id, &RNA_PoseBone, pchan); } if (adt->action) { @@ -163,7 +164,7 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, PoseBlendData *pbd) } /* Perform actual auto-keying. */ - ANIM_apply_keyingset( + blender::animrig::apply_keyingset( C, &sources, ks, blender::animrig::ModifyKeyMode::INSERT, float(scene->r.cfra)); /* send notifiers for this */ diff --git a/source/blender/editors/armature/pose_select.cc b/source/blender/editors/armature/pose_select.cc index e3b0e480867..130c897600b 100644 --- a/source/blender/editors/armature/pose_select.cc +++ b/source/blender/editors/armature/pose_select.cc @@ -944,17 +944,18 @@ static bool pose_select_same_collection(bContext *C, const bool extend) static bool pose_select_same_keyingset(bContext *C, ReportList *reports, bool extend) { + using namespace blender::animrig; Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); bool changed_multi = false; - KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C)); + KeyingSet *ks = scene_get_active_keyingset(CTX_data_scene(C)); /* sanity checks: validate Keying Set and object */ if (ks == nullptr) { BKE_report(reports, RPT_ERROR, "No active Keying Set to use"); return false; } - if (ANIM_validate_keyingset(C, nullptr, ks) != blender::animrig::ModifyKeyReturn::SUCCESS) { + if (validate_keyingset(C, nullptr, ks) != ModifyKeyReturn::SUCCESS) { if (ks->paths.first == nullptr) { if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) { BKE_report(reports, diff --git a/source/blender/editors/armature/pose_transform.cc b/source/blender/editors/armature/pose_transform.cc index 6e7d3fbd547..23cbf1d0d30 100644 --- a/source/blender/editors/armature/pose_transform.cc +++ b/source/blender/editors/armature/pose_transform.cc @@ -844,7 +844,8 @@ static int pose_paste_exec(bContext *C, wmOperator *op) bool selOnly = RNA_boolean_get(op->ptr, "selected_mask"); /* Get KeyingSet to use. */ - KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID); + KeyingSet *ks = blender::animrig::get_keyingset_for_autokeying(scene, + ANIM_KS_WHOLE_CHARACTER_ID); /* Sanity checks. */ if (ELEM(nullptr, ob, ob->pose)) { @@ -1197,7 +1198,8 @@ static int pose_clear_transform_generic_exec(bContext *C, /* do auto-keyframing as appropriate */ if (blender::animrig::autokeyframe_cfra_can_key(scene, &ob_iter->id)) { /* tag for autokeying later */ - ANIM_relative_keyingset_add_source(sources, &ob_iter->id, &RNA_PoseBone, pchan); + blender::animrig::relative_keyingset_add_source( + sources, &ob_iter->id, &RNA_PoseBone, pchan); #if 1 /* XXX: Ugly Hack - Run clearing function on evaluated copy of pchan */ bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name); @@ -1213,10 +1215,10 @@ static int pose_clear_transform_generic_exec(bContext *C, /* perform autokeying on the bones if needed */ if (!sources.is_empty()) { /* get KeyingSet to use */ - KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName); + KeyingSet *ks = blender::animrig::get_keyingset_for_autokeying(scene, default_ksName); /* insert keyframes */ - ANIM_apply_keyingset( + blender::animrig::apply_keyingset( C, &sources, ks, blender::animrig::ModifyKeyMode::INSERT, float(scene->r.cfra)); /* now recalculate paths */ diff --git a/source/blender/editors/armature/pose_utils.cc b/source/blender/editors/armature/pose_utils.cc index 6a0aace87bc..7ffd32c7ad4 100644 --- a/source/blender/editors/armature/pose_utils.cc +++ b/source/blender/editors/armature/pose_utils.cc @@ -392,7 +392,8 @@ void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks, } /* Insert keyframes as necessary if auto-key-framing. */ - KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID); + KeyingSet *ks = blender::animrig::get_keyingset_for_autokeying(scene, + ANIM_KS_WHOLE_CHARACTER_ID); blender::Vector sources; /* iterate over each pose-channel affected, tagging bones to be keyed */ @@ -407,11 +408,12 @@ void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks, } /* Add data-source override for the PoseChannel, to be used later. */ - ANIM_relative_keyingset_add_source(sources, &pfl->ob->id, &RNA_PoseBone, pchan); + blender::animrig::relative_keyingset_add_source(sources, &pfl->ob->id, &RNA_PoseBone, pchan); } /* insert keyframes for all relevant bones in one go */ - ANIM_apply_keyingset(C, &sources, ks, blender::animrig::ModifyKeyMode::INSERT, cframe); + blender::animrig::apply_keyingset( + C, &sources, ks, blender::animrig::ModifyKeyMode::INSERT, cframe); /* do the bone paths * - only do this if keyframes should have been added diff --git a/source/blender/editors/include/ED_keyframing.hh b/source/blender/editors/include/ED_keyframing.hh index f708d67559a..941286baa18 100644 --- a/source/blender/editors/include/ED_keyframing.hh +++ b/source/blender/editors/include/ED_keyframing.hh @@ -64,145 +64,11 @@ void ED_keyframes_add(FCurve *fcu, int num_keys_to_add); /** \name Keying Sets * \{ */ -/* Forward declaration. For this struct which is declared a bit later. */ -struct ExtensionRNA; -struct KeyingSetInfo; - -/** Polling Callback for KeyingSets. */ -using cbKeyingSet_Poll = bool (*)(KeyingSetInfo *ksi, bContext *C); -/** Context Iterator Callback for KeyingSets. */ -using cbKeyingSet_Iterator = void (*)(KeyingSetInfo *ksi, bContext *C, KeyingSet *ks); -/** Property Specifier Callback for KeyingSets (called from iterators) */ -using cbKeyingSet_Generate = void (*)(KeyingSetInfo *ksi, - bContext *C, - KeyingSet *ks, - PointerRNA *ptr); - -/** Callback info for 'Procedural' KeyingSets to use. */ -struct KeyingSetInfo { - KeyingSetInfo *next, *prev; - - /* info */ - /** Identifier used for class name, which KeyingSet instances reference as "Type-info Name". */ - char idname[64]; - /** identifier so that user can hook this up to a KeyingSet (used as label). */ - char name[64]; - /** Short help/description. */ - char description[1024]; /* #RNA_DYN_DESCR_MAX */ - /** Keying settings. */ - short keyingflag; - - /* polling callbacks */ - /** callback for polling the context for whether the right data is available. */ - cbKeyingSet_Poll poll; - - /* generate callbacks */ - /** - * Iterator to use to go through collections of data in context - * - this callback is separate from the 'adding' stage, allowing - * BuiltIn KeyingSets to be manually specified to use. - */ - cbKeyingSet_Iterator iter; - /** Generator to use to add properties based on the data found by iterator. */ - cbKeyingSet_Generate generate; - - /** RNA integration. */ - ExtensionRNA rna_ext; -}; - -/* -------- */ - -/** - * Add another data source for Relative Keying Sets to be evaluated with. - */ -void ANIM_relative_keyingset_add_source(blender::Vector &sources, - ID *id, - StructRNA *srna, - void *data); -void ANIM_relative_keyingset_add_source(blender::Vector &sources, ID *id); - -/** - * Given a #KeyingSet and context info, validate Keying Set's paths. - * This is only really necessary with relative/built-in KeyingSets - * where their list of paths is dynamically generated based on the - * current context info. - * - * \note Passing sources as pointer because it can be a nullptr. - * - * \return 0 if succeeded, otherwise an error code: #eModifyKey_Returns. - */ -blender::animrig::ModifyKeyReturn ANIM_validate_keyingset(bContext *C, - blender::Vector *sources, - KeyingSet *keyingset); - -/** - * Use the specified #KeyingSet and context info (if required) - * to add/remove various Keyframes on the specified frame. - * - * Modify keyframes for the channels specified by the KeyingSet. - * This takes into account many of the different combinations of using KeyingSets. - * - * \returns the number of channels that key-frames were added or - * an #eModifyKey_Returns value (always a negative number). - */ -int ANIM_apply_keyingset(bContext *C, - blender::Vector *sources, - KeyingSet *keyingset, - blender::animrig::ModifyKeyMode mode, - float cfra); - -/* -------- */ - -/** - * Find builtin #KeyingSet by name. - * - * \return The first builtin #KeyingSet with the given name - */ -KeyingSet *ANIM_builtin_keyingset_get_named(const char name[]); - -/** - * Find KeyingSet type info given a name. - */ -KeyingSetInfo *ANIM_keyingset_info_find_name(const char name[]); - -/** - * Check if the ID appears in the paths specified by the #KeyingSet. - */ -bool ANIM_keyingset_find_id(KeyingSet *keyingset, ID *id); - -/** - * Add the given KeyingSetInfo to the list of type infos, - * and create an appropriate builtin set too. - */ -void ANIM_keyingset_info_register(KeyingSetInfo *keyingset_info); -/** - * Remove the given #KeyingSetInfo from the list of type infos, - * and also remove the builtin set if appropriate. - */ -void ANIM_keyingset_info_unregister(Main *bmain, KeyingSetInfo *keyingset_info); - -/* cleanup on exit */ -/* --------------- */ - -void ANIM_keyingset_infos_exit(); - -/* -------- */ - -/** - * Get the active Keying Set for the given scene. - */ -KeyingSet *ANIM_scene_get_active_keyingset(const Scene *scene); - /** * Get the index of the Keying Set provided, for the given Scene. */ int ANIM_scene_get_keyingset_index(Scene *scene, KeyingSet *keyingset); -/** - * Get Keying Set to use for Auto-Key-Framing some transforms. - */ -KeyingSet *ANIM_get_keyingset_for_autokeying(const Scene *scene, const char *transformKSName); - void ANIM_keyingset_visit_for_search( const bContext *C, PointerRNA *ptr, @@ -216,6 +82,7 @@ void ANIM_keyingset_visit_for_search_no_poll( PropertyRNA *prop, const char *edit_text, blender::FunctionRef visit_fn); + /** * Dynamically populate an enum of Keying Sets. */ @@ -421,14 +288,6 @@ void ANIM_copy_as_driver(ID *target_id, const char *target_path, const char *var /** \name Keyframe Checking * \{ */ -/** - * \brief Lesser Keyframe Checking API call. - * - * Checks if some F-Curve has a keyframe for a given frame. - * \note Used for the buttons to check for keyframes. - */ -bool fcurve_frame_has_keyframe(const FCurve *fcu, float frame); - /** * \brief Lesser Keyframe Checking API call. * @@ -440,26 +299,4 @@ bool fcurve_is_changed(PointerRNA ptr, FCurve *fcu, const AnimationEvalContext *anim_eval_context); -/** - * \brief Main Keyframe Checking API call. - * - * Checks whether a keyframe exists for the given ID-block one the given frame. - * It is recommended to call this method over the other keyframe-checkers directly, - * in case some detail of the implementation changes... - * \param frame: The value of this is quite often result of #BKE_scene_ctime_get() - */ -bool id_frame_has_keyframe(ID *id, float frame); - -/* Names for builtin keying sets so we don't confuse these with labels/text, - * defined in python script: `keyingsets_builtins.py`. */ - -#define ANIM_KS_LOCATION_ID "Location" -#define ANIM_KS_ROTATION_ID "Rotation" -#define ANIM_KS_SCALING_ID "Scaling" -#define ANIM_KS_LOC_ROT_SCALE_ID "LocRotScale" -#define ANIM_KS_LOC_ROT_SCALE_CPROP_ID "LocRotScaleCProp" -#define ANIM_KS_AVAILABLE_ID "Available" -#define ANIM_KS_WHOLE_CHARACTER_ID "WholeCharacter" -#define ANIM_KS_WHOLE_CHARACTER_SELECTED_ID "WholeCharacterSelected" - /** \} */ diff --git a/source/blender/editors/interface/interface_anim.cc b/source/blender/editors/interface/interface_anim.cc index d7652148851..3e9ab33f75a 100644 --- a/source/blender/editors/interface/interface_anim.cc +++ b/source/blender/editors/interface/interface_anim.cc @@ -100,7 +100,7 @@ void ui_but_anim_flag(uiBut *but, const AnimationEvalContext *anim_eval_context) cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); } - if (fcurve_frame_has_keyframe(fcu, cfra)) { + if (blender::animrig::fcurve_frame_has_keyframe(fcu, cfra)) { but->flag |= UI_BUT_ANIMATED_KEY; } diff --git a/source/blender/editors/object/object_select.cc b/source/blender/editors/object/object_select.cc index b9cf773230c..7cc62793332 100644 --- a/source/blender/editors/object/object_select.cc +++ b/source/blender/editors/object/object_select.cc @@ -954,7 +954,7 @@ static bool select_grouped_color(bContext *C, Object *ob) static bool select_grouped_keyingset(bContext *C, Object * /*ob*/, ReportList *reports) { - KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C)); + KeyingSet *ks = blender::animrig::scene_get_active_keyingset(CTX_data_scene(C)); bool changed = false; /* firstly, validate KeyingSet */ @@ -962,7 +962,9 @@ static bool select_grouped_keyingset(bContext *C, Object * /*ob*/, ReportList *r BKE_report(reports, RPT_ERROR, "No active Keying Set to use"); return false; } - if (ANIM_validate_keyingset(C, nullptr, ks) != blender::animrig::ModifyKeyReturn::SUCCESS) { + if (blender::animrig::validate_keyingset(C, nullptr, ks) != + blender::animrig::ModifyKeyReturn::SUCCESS) + { if (ks->paths.first == nullptr) { if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) { BKE_report(reports, diff --git a/source/blender/editors/object/object_transform.cc b/source/blender/editors/object/object_transform.cc index 19de7e0c49c..bcbaddc5714 100644 --- a/source/blender/editors/object/object_transform.cc +++ b/source/blender/editors/object/object_transform.cc @@ -71,6 +71,7 @@ #include "ANIM_action.hh" #include "ANIM_keyframing.hh" +#include "ANIM_keyingsets.hh" #include "ED_anim_api.hh" #include "ED_armature.hh" @@ -343,7 +344,7 @@ static int object_clear_transform_generic_exec(bContext *C, } /* get KeyingSet to use */ - ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName); + ks = blender::animrig::get_keyingset_for_autokeying(scene, default_ksName); if (blender::animrig::is_autokey_on(scene)) { ANIM_deselect_keys_in_animation_editors(C); diff --git a/source/blender/editors/space_view3d/view3d_draw.cc b/source/blender/editors/space_view3d/view3d_draw.cc index 9d35c7a7152..6fce228b578 100644 --- a/source/blender/editors/space_view3d/view3d_draw.cc +++ b/source/blender/editors/space_view3d/view3d_draw.cc @@ -48,7 +48,6 @@ #include "ED_gpencil_legacy.hh" #include "ED_info.hh" -#include "ED_keyframing.hh" #include "ED_scene.hh" #include "ED_screen.hh" #include "ED_view3d_offscreen.hh" @@ -80,6 +79,8 @@ #include "IMB_imbuf.hh" #include "IMB_imbuf_types.hh" +#include "ANIM_keyframing.hh" + #include "view3d_intern.hh" /* own include */ using blender::float4; @@ -1393,7 +1394,9 @@ static void draw_selected_name( } /* color depends on whether there is a keyframe */ - if (id_frame_has_keyframe((ID *)ob, /* BKE_scene_ctime_get(scene) */ float(cfra))) { + if (blender::animrig::id_frame_has_keyframe((ID *)ob, + /* BKE_scene_ctime_get(scene) */ float(cfra))) + { UI_FontThemeColor(font_id, TH_TIME_KEYFRAME); } } diff --git a/source/blender/editors/space_view3d/view3d_snap.cc b/source/blender/editors/space_view3d/view3d_snap.cc index 4885dd2c17d..454c78dffd0 100644 --- a/source/blender/editors/space_view3d/view3d_snap.cc +++ b/source/blender/editors/space_view3d/view3d_snap.cc @@ -52,6 +52,7 @@ #include "ANIM_action.hh" #include "ANIM_bone_collections.hh" #include "ANIM_keyframing.hh" +#include "ANIM_keyingsets.hh" #include "view3d_intern.hh" @@ -125,7 +126,7 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *op) } } else if (OBPOSE_FROM_OBACT(obact)) { - KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); + KeyingSet *ks = blender::animrig::get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); Vector objects_eval = BKE_object_pose_array_get(scene, view_layer_eval, v3d); for (Object *ob_eval : objects_eval) { Object *ob = DEG_get_original_object(ob_eval); @@ -182,7 +183,7 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *op) /* Object mode. */ Main *bmain = CTX_data_main(C); - KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); + KeyingSet *ks = blender::animrig::get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); const bool use_transform_skip_children = (scene->toolsettings->transform_flag & SCE_XFORM_SKIP_CHILDREN); @@ -387,7 +388,7 @@ static bool snap_selected_to_location(bContext *C, } } else if (OBPOSE_FROM_OBACT(obact)) { - KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); + KeyingSet *ks = blender::animrig::get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); ViewLayer *view_layer = CTX_data_view_layer(C); Vector objects = BKE_object_pose_array_get(scene, view_layer, v3d); @@ -463,7 +464,7 @@ static bool snap_selected_to_location(bContext *C, } } else { - KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); + KeyingSet *ks = blender::animrig::get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); Main *bmain = CTX_data_main(C); Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); diff --git a/source/blender/editors/space_view3d/view3d_utils.cc b/source/blender/editors/space_view3d/view3d_utils.cc index 3c2e9ca1d7b..059e8c9efc8 100644 --- a/source/blender/editors/space_view3d/view3d_utils.cc +++ b/source/blender/editors/space_view3d/view3d_utils.cc @@ -679,7 +679,7 @@ bool ED_view3d_camera_autokey( const float cfra = float(scene->r.cfra); blender::Vector sources; /* add data-source override for the camera object */ - ANIM_relative_keyingset_add_source(sources, id_key); + blender::animrig::relative_keyingset_add_source(sources, id_key); /* insert keyframes * 1) on the first frame @@ -687,12 +687,12 @@ bool ED_view3d_camera_autokey( * TODO: need to check in future that frame changed before doing this */ if (do_rotate) { - KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_ROTATION_ID); - ANIM_apply_keyingset(C, &sources, ks, ModifyKeyMode::INSERT, cfra); + KeyingSet *ks = blender::animrig::get_keyingset_for_autokeying(scene, ANIM_KS_ROTATION_ID); + blender::animrig::apply_keyingset(C, &sources, ks, ModifyKeyMode::INSERT, cfra); } if (do_translate) { - KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); - ANIM_apply_keyingset(C, &sources, ks, ModifyKeyMode::INSERT, cfra); + KeyingSet *ks = blender::animrig::get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); + blender::animrig::apply_keyingset(C, &sources, ks, ModifyKeyMode::INSERT, cfra); } return true; diff --git a/source/blender/makesrna/intern/rna_animation.cc b/source/blender/makesrna/intern/rna_animation.cc index d9d6822413d..0047e2428e6 100644 --- a/source/blender/makesrna/intern/rna_animation.cc +++ b/source/blender/makesrna/intern/rna_animation.cc @@ -33,6 +33,7 @@ #include "ED_keyframing.hh" #include "ANIM_action.hh" +#include "ANIM_keyingsets.hh" using namespace blender; @@ -507,7 +508,7 @@ static bool rna_KeyingSetInfo_unregister(Main *bmain, StructRNA *type) WM_main_add_notifier(NC_WINDOW, nullptr); /* unlink Blender-side data */ - ANIM_keyingset_info_unregister(bmain, ksi); + blender::animrig::keyingset_info_unregister(bmain, ksi); return true; } @@ -545,7 +546,7 @@ static StructRNA *rna_KeyingSetInfo_register(Main *bmain, } /* check if we have registered this info before, and remove it */ - ksi = ANIM_keyingset_info_find_name(dummy_ksi.idname); + ksi = blender::animrig::keyingset_info_find_name(dummy_ksi.idname); if (ksi) { BKE_reportf(reports, RPT_INFO, @@ -585,7 +586,7 @@ static StructRNA *rna_KeyingSetInfo_register(Main *bmain, ksi->generate = (have_function[2]) ? RKS_GEN_rna_internal : nullptr; /* add and register with other info as needed */ - ANIM_keyingset_info_register(ksi); + blender::animrig::keyingset_info_register(ksi); WM_main_add_notifier(NC_WINDOW, nullptr); @@ -744,7 +745,7 @@ static PointerRNA rna_KeyingSet_typeinfo_get(PointerRNA *ptr) /* keying set info is only for builtin Keying Sets */ if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) { - ksi = ANIM_keyingset_info_find_name(ks->typeinfo); + ksi = blender::animrig::keyingset_info_find_name(ks->typeinfo); } return rna_pointer_inherit_refine(ptr, &RNA_KeyingSetInfo, ksi); } diff --git a/source/blender/makesrna/intern/rna_animation_api.cc b/source/blender/makesrna/intern/rna_animation_api.cc index c21b5bf941d..fd34bedf137 100644 --- a/source/blender/makesrna/intern/rna_animation_api.cc +++ b/source/blender/makesrna/intern/rna_animation_api.cc @@ -32,7 +32,7 @@ static void rna_KeyingSet_context_refresh(KeyingSet *ks, bContext *C, ReportList { using namespace blender::animrig; /* TODO: enable access to providing a list of overrides (dsources)? */ - const ModifyKeyReturn error = ANIM_validate_keyingset(C, nullptr, ks); + const ModifyKeyReturn error = validate_keyingset(C, nullptr, ks); if (error == ModifyKeyReturn::SUCCESS) { return; diff --git a/source/blender/makesrna/intern/rna_scene.cc b/source/blender/makesrna/intern/rna_scene.cc index 18bdfc92538..0183e4ec5e5 100644 --- a/source/blender/makesrna/intern/rna_scene.cc +++ b/source/blender/makesrna/intern/rna_scene.cc @@ -68,6 +68,8 @@ #include "BLI_threads.h" +#include "ANIM_keyingsets.hh" + #include "DEG_depsgraph.hh" #ifdef WITH_OPENEXR @@ -1111,7 +1113,8 @@ static void rna_Scene_frame_update(Main * /*bmain*/, Scene * /*current_scene*/, static PointerRNA rna_Scene_active_keying_set_get(PointerRNA *ptr) { Scene *scene = (Scene *)ptr->data; - return rna_pointer_inherit_refine(ptr, &RNA_KeyingSet, ANIM_scene_get_active_keyingset(scene)); + return rna_pointer_inherit_refine( + ptr, &RNA_KeyingSet, blender::animrig::scene_get_active_keyingset(scene)); } static void rna_Scene_active_keying_set_set(PointerRNA *ptr, @@ -1143,7 +1146,7 @@ static void rna_Scene_active_keying_set_index_set(PointerRNA *ptr, int value) scene->active_keyingset = value + 1; } -/* XXX: evil... builtin_keyingsets is defined in `keyingsets.cc`! */ +/* XXX: evil... builtin_keyingsets is defined in `blender::animrig::keyingsets.cc`! */ /* TODO: make API function to retrieve this... */ extern ListBase builtin_keyingsets; diff --git a/source/blender/windowmanager/intern/wm_init_exit.cc b/source/blender/windowmanager/intern/wm_init_exit.cc index b6a527dd563..c13a5640437 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.cc +++ b/source/blender/windowmanager/intern/wm_init_exit.cc @@ -112,6 +112,8 @@ #include "DEG_depsgraph.hh" #include "DEG_depsgraph_query.hh" +#include "ANIM_keyingsets.hh" + #include "DRW_engine.hh" CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_OPERATORS, "wm.operator"); @@ -629,7 +631,7 @@ void WM_exit_ex(bContext *C, const bool do_python_exit, const bool do_user_exit_ BLT_lang_free(); - ANIM_keyingset_infos_exit(); + blender::animrig::keyingset_infos_exit(); // free_txt_data();