Refactor: move keyingsets to animrig

No functional changes intended.

This patch moves the relevant keying set code from editors to animrig.
All functions are in the animrig namespace, and as such have lost their
`ANIM_` prefix.
Other than that, the code has been moved as is into `animrig/intern/keyingsets.cc`

Note that I also had to move `id_frame_has_keyframe` and `fcurve_frame_has_keyframe`.
I moved that into `ANIM_keyframing.hh` and `ANIM_fcurve.hh` since I found that more fitting.

Due to Windows defining `DELETE` as macro I had to rename `ModifyKeyMode::DELETE`
to `ModifyKeyMode::DELETE_KEY`

As a result of this two includes from animrig to editors were removed.

This is part of #121336

Pull Request: https://projects.blender.org/blender/blender/pulls/129980
This commit is contained in:
Christoph Lendenfeld
2024-11-15 10:51:41 +01:00
committed by Christoph Lendenfeld
parent 38363fb2d7
commit b38d8ecb86
28 changed files with 841 additions and 796 deletions

View File

@@ -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

View File

@@ -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.
*/

View File

@@ -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<PointerRNA> *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<PointerRNA> *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<PointerRNA> &sources,
ID *id,
StructRNA *srna,
void *data);
void relative_keyingset_add_source(blender::Vector<PointerRNA> &sources, ID *id);
/** \} */
} // namespace blender::animrig

View File

@@ -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

View File

@@ -35,8 +35,6 @@
#include "RNA_path.hh"
#include "RNA_prototypes.hh"
#include "ED_keyframing.hh"
#include "MEM_guardedalloc.h"
#include "BLT_translation.hh"

View File

@@ -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

View File

@@ -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;

View File

@@ -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<RNAPath> 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<RNAPath> rn
/* Add data-source override for the object. */
blender::Vector<PointerRNA> 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<PointerRNA> 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<PointerRNA> 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<PointerRNA> 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;
}

View File

@@ -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<Scene *>(bmain->scenes.first); scene;
scene = static_cast<Scene *>(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<KeyingSetInfo *>(
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<KeyingSet *>(BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1));
}
return static_cast<KeyingSet *>(
BLI_findlink(&builtin_keyingsets, (-scene->active_keyingset) - 1));
}
void relative_keyingset_add_source(blender::Vector<PointerRNA> &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<PointerRNA> &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<PointerRNA> &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<PointerRNA> *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<blender::StringRefNull> group = groupname ? std::optional(groupname) :
std::nullopt;
const std::optional<int> 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<PointerRNA> *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

View File

@@ -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;
}

View File

@@ -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 ------------------- */

View File

@@ -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
* \{ */

View File

@@ -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<KeyingSetInfo *>(
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<Scene *>(bmain->scenes.first); scene;
scene = static_cast<Scene *>(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<KeyingSet *>(BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1));
}
return static_cast<KeyingSet *>(
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<void(StringPropertySearchVisitParams)> 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<PointerRNA> &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<PointerRNA> &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<PointerRNA> &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<PointerRNA> *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<blender::StringRefNull> group = groupname ? std::optional(groupname) :
std::nullopt;
const std::optional<int> 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<PointerRNA> *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;
}
/* ************************************************** */

View File

@@ -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<PointerRNA> 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 */

View File

@@ -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,

View File

@@ -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 */

View File

@@ -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<PointerRNA> 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

View File

@@ -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<PointerRNA> &sources,
ID *id,
StructRNA *srna,
void *data);
void ANIM_relative_keyingset_add_source(blender::Vector<PointerRNA> &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<PointerRNA> *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<PointerRNA> *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<void(StringPropertySearchVisitParams)> 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"
/** \} */

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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<Object *> 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<Object *> 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);

View File

@@ -679,7 +679,7 @@ bool ED_view3d_camera_autokey(
const float cfra = float(scene->r.cfra);
blender::Vector<PointerRNA> 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;

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();