Cleanup: Refactor animdata iterators to C++ callbacks

Pull Request: https://projects.blender.org/blender/blender/pulls/125485
This commit is contained in:
Lukas Stockner
2024-08-04 19:55:51 +02:00
committed by Lukas Stockner
parent de9fc05af6
commit 1c7c1829b6
10 changed files with 161 additions and 353 deletions

View File

@@ -8,13 +8,15 @@
* \ingroup bke
*/
#include <functional>
#include <optional>
#include "BLI_sys_types.h" /* for bool */
#include "BLI_function_ref.hh"
struct AnimData;
struct BlendDataReader;
struct BlendWriter;
struct FCurve;
struct ID;
struct Library;
struct LibraryForeachIDData;
@@ -170,3 +172,17 @@ void BKE_animdata_blend_read_data(BlendDataReader *reader, ID *id);
* applied.
*/
void BKE_animdata_liboverride_post_process(ID *id);
/* ************************************* */
/* Batch AnimData API */
/* Loop over all datablocks applying callback */
void BKE_animdata_main_cb(struct Main *bmain, blender::FunctionRef<void(ID *, AnimData *)> func);
/** Apply the given callback function on all F-Curves attached to data in `main` database. */
void BKE_fcurves_main_cb(struct Main *bmain, blender::FunctionRef<void(ID *, FCurve *)> func);
/* Look over all f-curves of a given ID. */
void BKE_fcurves_id_cb(struct ID *id, blender::FunctionRef<void(ID *, FCurve *)> func);
/* ************************************* */
/* TODO: overrides, remapping, and path-finding API's. */

View File

@@ -206,27 +206,6 @@ void BKE_animdata_transfer_by_basepath(struct Main *bmain,
struct ID *dstID,
struct ListBase *basepaths);
/* ************************************* */
/* Batch AnimData API */
/* Define for callback looper used in BKE_animdata_main_cb */
typedef void (*ID_AnimData_Edit_Callback)(struct ID *id, struct AnimData *adt, void *user_data);
/* Define for callback looper used in BKE_fcurves_main_cb */
typedef void (*ID_FCurve_Edit_Callback)(struct ID *id, struct FCurve *fcu, void *user_data);
/* Loop over all datablocks applying callback */
void BKE_animdata_main_cb(struct Main *bmain, ID_AnimData_Edit_Callback func, void *user_data);
/** Apply the given callback function on all F-Curves attached to data in `main` database. */
void BKE_fcurves_main_cb(struct Main *bmain, ID_FCurve_Edit_Callback func, void *user_data);
/* Look over all f-curves of a given ID. */
void BKE_fcurves_id_cb(struct ID *id, ID_FCurve_Edit_Callback func, void *user_data);
/* ************************************* */
/* TODO: overrides, remapping, and path-finding API's. */
/* ------------ NLA Keyframing --------------- */
typedef struct NlaKeyframingContext NlaKeyframingContext;

View File

@@ -57,6 +57,8 @@
static CLG_LogRef LOG = {"bke.anim_sys"};
using blender::FunctionRef;
/* ***************************************** */
/* AnimData API */
@@ -1214,80 +1216,72 @@ bool BKE_animdata_fix_paths_remove(ID *id, const char *prefix)
/* Apply Op to All FCurves in Database --------------------------- */
/* "User-Data" wrapper used by BKE_fcurves_main_cb() */
struct AllFCurvesCbWrapper {
ID_FCurve_Edit_Callback func; /* Operation to apply on F-Curve */
void *user_data; /* Custom data for that operation */
};
/* Helper for adt_apply_all_fcurves_cb() - Apply wrapped operator to list of F-Curves */
static void fcurves_apply_cb(ID *id,
ListBase *fcurves,
ID_FCurve_Edit_Callback func,
void *user_data)
const FunctionRef<void(ID *, FCurve *)> func)
{
LISTBASE_FOREACH (FCurve *, fcu, fcurves) {
func(id, fcu, user_data);
func(id, fcu);
}
}
/* Helper for adt_apply_all_fcurves_cb() - Recursively go through each NLA strip */
static void nlastrips_apply_all_curves_cb(ID *id, ListBase *strips, AllFCurvesCbWrapper *wrapper)
static void nlastrips_apply_all_curves_cb(ID *id,
ListBase *strips,
const FunctionRef<void(ID *, FCurve *)> func)
{
LISTBASE_FOREACH (NlaStrip *, strip, strips) {
/* fix strip's action */
if (strip->act) {
fcurves_apply_cb(id, &strip->act->curves, wrapper->func, wrapper->user_data);
fcurves_apply_cb(id, &strip->act->curves, func);
}
/* Check sub-strips (if meta-strips). */
nlastrips_apply_all_curves_cb(id, &strip->strips, wrapper);
nlastrips_apply_all_curves_cb(id, &strip->strips, func);
}
}
/* Helper for BKE_fcurves_main_cb() - Dispatch wrapped operator to all F-Curves */
static void adt_apply_all_fcurves_cb(ID *id, AnimData *adt, void *wrapper_data)
static void adt_apply_all_fcurves_cb(ID *id,
AnimData *adt,
const FunctionRef<void(ID *, FCurve *)> func)
{
AllFCurvesCbWrapper *wrapper = static_cast<AllFCurvesCbWrapper *>(wrapper_data);
if (adt->action) {
fcurves_apply_cb(id, &adt->action->curves, wrapper->func, wrapper->user_data);
fcurves_apply_cb(id, &adt->action->curves, func);
}
if (adt->tmpact) {
fcurves_apply_cb(id, &adt->tmpact->curves, wrapper->func, wrapper->user_data);
fcurves_apply_cb(id, &adt->tmpact->curves, func);
}
/* free drivers - stored as a list of F-Curves */
fcurves_apply_cb(id, &adt->drivers, wrapper->func, wrapper->user_data);
fcurves_apply_cb(id, &adt->drivers, func);
/* NLA Data - Animation Data for Strips */
LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) {
nlastrips_apply_all_curves_cb(id, &nlt->strips, wrapper);
nlastrips_apply_all_curves_cb(id, &nlt->strips, func);
}
}
void BKE_fcurves_id_cb(ID *id, ID_FCurve_Edit_Callback func, void *user_data)
void BKE_fcurves_id_cb(ID *id, const FunctionRef<void(ID *, FCurve *)> func)
{
AnimData *adt = BKE_animdata_from_id(id);
if (adt != nullptr) {
AllFCurvesCbWrapper wrapper = {func, user_data};
adt_apply_all_fcurves_cb(id, adt, &wrapper);
adt_apply_all_fcurves_cb(id, adt, func);
}
}
void BKE_fcurves_main_cb(Main *bmain, ID_FCurve_Edit_Callback func, void *user_data)
void BKE_fcurves_main_cb(Main *bmain, const FunctionRef<void(ID *, FCurve *)> func)
{
/* Wrap F-Curve operation stuff to pass to the general AnimData-level func */
AllFCurvesCbWrapper wrapper = {func, user_data};
/* Use the AnimData-based function so that we don't have to reimplement all that stuff */
BKE_animdata_main_cb(bmain, adt_apply_all_fcurves_cb, &wrapper);
BKE_animdata_main_cb(bmain,
[&](ID *id, AnimData *adt) { adt_apply_all_fcurves_cb(id, adt, func); });
}
/* Whole Database Ops -------------------------------------------- */
void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *user_data)
void BKE_animdata_main_cb(Main *bmain, const FunctionRef<void(ID *, AnimData *)> func)
{
ID *id;
@@ -1296,7 +1290,7 @@ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *use
for (id = static_cast<ID *>(first); id; id = static_cast<ID *>(id->next)) { \
AnimData *adt = BKE_animdata_from_id(id); \
if (adt) { \
func(id, adt, user_data); \
func(id, adt); \
} \
} \
(void)0
@@ -1309,11 +1303,11 @@ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *use
if (ntp->nodetree) { \
AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
if (adt2) { \
func(id, adt2, user_data); \
func(id, adt2); \
} \
} \
if (adt) { \
func(id, adt, user_data); \
func(id, adt); \
} \
} \
(void)0
@@ -1412,115 +1406,10 @@ void BKE_animdata_fix_paths_rename_all_ex(Main *bmain,
const int newSubscript,
const bool verify_paths)
{
/* TODO: use BKE_animdata_main_cb for looping over all data. */
ID *id;
/* macro for less typing
* - whether animdata exists is checked for by the main renaming callback, though taking
* this outside of the function may make things slightly faster?
*/
#define RENAMEFIX_ANIM_IDS(first) \
for (id = static_cast<ID *>(first); id; id = static_cast<ID *>(id->next)) { \
AnimData *adt = BKE_animdata_from_id(id); \
BKE_animdata_fix_paths_rename( \
id, adt, ref_id, prefix, oldName, newName, oldSubscript, newSubscript, verify_paths); \
} \
(void)0
/* Another version of this macro for node-trees. */
#define RENAMEFIX_ANIM_NODETREE_IDS(first, NtId_Type) \
for (id = static_cast<ID *>(first); id; id = static_cast<ID *>(id->next)) { \
AnimData *adt = BKE_animdata_from_id(id); \
NtId_Type *ntp = (NtId_Type *)id; \
if (ntp->nodetree) { \
AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
BKE_animdata_fix_paths_rename((ID *)ntp->nodetree, \
adt2, \
ref_id, \
prefix, \
oldName, \
newName, \
oldSubscript, \
newSubscript, \
verify_paths); \
} \
BKE_animdata_fix_paths_rename( \
id, adt, ref_id, prefix, oldName, newName, oldSubscript, newSubscript, verify_paths); \
} \
(void)0
/* nodes */
RENAMEFIX_ANIM_IDS(bmain->nodetrees.first);
/* textures */
RENAMEFIX_ANIM_NODETREE_IDS(bmain->textures.first, Tex);
/* lights */
RENAMEFIX_ANIM_NODETREE_IDS(bmain->lights.first, Light);
/* materials */
RENAMEFIX_ANIM_NODETREE_IDS(bmain->materials.first, Material);
/* cameras */
RENAMEFIX_ANIM_IDS(bmain->cameras.first);
/* shapekeys */
RENAMEFIX_ANIM_IDS(bmain->shapekeys.first);
/* metaballs */
RENAMEFIX_ANIM_IDS(bmain->metaballs.first);
/* curves */
RENAMEFIX_ANIM_IDS(bmain->curves.first);
/* armatures */
RENAMEFIX_ANIM_IDS(bmain->armatures.first);
/* lattices */
RENAMEFIX_ANIM_IDS(bmain->lattices.first);
/* meshes */
RENAMEFIX_ANIM_IDS(bmain->meshes.first);
/* particles */
RENAMEFIX_ANIM_IDS(bmain->particles.first);
/* speakers */
RENAMEFIX_ANIM_IDS(bmain->speakers.first);
/* movie clips */
RENAMEFIX_ANIM_IDS(bmain->movieclips.first);
/* objects */
RENAMEFIX_ANIM_IDS(bmain->objects.first);
/* masks */
RENAMEFIX_ANIM_IDS(bmain->masks.first);
/* worlds */
RENAMEFIX_ANIM_NODETREE_IDS(bmain->worlds.first, World);
/* linestyles */
RENAMEFIX_ANIM_IDS(bmain->linestyles.first);
/* grease pencil */
RENAMEFIX_ANIM_IDS(bmain->gpencils.first);
/* cache files */
RENAMEFIX_ANIM_IDS(bmain->cachefiles.first);
/* Hair Curves. */
RENAMEFIX_ANIM_IDS(bmain->hair_curves.first);
/* pointclouds */
RENAMEFIX_ANIM_IDS(bmain->pointclouds.first);
/* volumes */
RENAMEFIX_ANIM_IDS(bmain->volumes.first);
/* scenes */
RENAMEFIX_ANIM_NODETREE_IDS(bmain->scenes.first, Scene);
BKE_animdata_main_cb(bmain, [&](ID *id, AnimData *adt) {
BKE_animdata_fix_paths_rename(
id, adt, ref_id, prefix, oldName, newName, oldSubscript, newSubscript, verify_paths);
});
}
/* .blend file API -------------------------------------------- */

View File

@@ -386,7 +386,7 @@ static char *replace_bbone_easing_rnapath(char *old_path)
return old_path;
}
static void do_version_bbone_easing_fcurve_fix(ID * /*id*/, FCurve *fcu, void * /*user_data*/)
static void do_version_bbone_easing_fcurve_fix(ID * /*id*/, FCurve *fcu)
{
/* F-Curve's path (for bbone_in/out) */
if (fcu->rna_path) {
@@ -1626,6 +1626,6 @@ void do_versions_after_linking_270(Main *bmain)
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 279, 2)) {
/* B-Bones (bbone_in/out -> bbone_easein/out) + Stepped FMod Frame Start/End fix */
BKE_fcurves_main_cb(bmain, do_version_bbone_easing_fcurve_fix, nullptr);
BKE_fcurves_main_cb(bmain, do_version_bbone_easing_fcurve_fix);
}
}

View File

@@ -61,7 +61,7 @@
#undef DNA_GENFILE_VERSIONING_MACROS
#include "BKE_animsys.h"
#include "BKE_anim_data.hh"
#include "BKE_blender.hh"
#include "BKE_collection.hh"
#include "BKE_colortools.hh"
@@ -579,13 +579,6 @@ static void do_version_bbone_scale_fcurve_fix(ListBase *curves, FCurve *fcu)
}
}
static void do_version_bbone_scale_animdata_cb(ID * /*id*/, AnimData *adt, void * /*wrapper_data*/)
{
LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &adt->drivers) {
do_version_bbone_scale_fcurve_fix(&adt->drivers, fcu);
}
}
static void do_version_constraints_maintain_volume_mode_uniform(ListBase *lb)
{
LISTBASE_FOREACH (bConstraint *, con, lb) {
@@ -1001,16 +994,6 @@ static void do_version_curvemapping_walker(Main *bmain, void (*callback)(CurveMa
}
}
static void do_version_fcurve_hide_viewport_fix(ID * /*id*/, FCurve *fcu, void * /*user_data*/)
{
if (fcu->rna_path == nullptr || !STREQ(fcu->rna_path, "hide")) {
return;
}
MEM_freeN(fcu->rna_path);
fcu->rna_path = BLI_strdupn("hide_viewport", 13);
}
static void displacement_node_insert(bNodeTree *ntree)
{
bool need_update = false;
@@ -1688,15 +1671,6 @@ static void update_noise_node_dimensions(bNodeTree *ntree)
}
}
/* This structure is only used to pass data to
* update_mapping_node_fcurve_rna_path_callback.
*/
struct MappingNodeFCurveCallbackData {
char *nodePath;
bNode *minimumNode;
bNode *maximumNode;
};
/* This callback function is used by update_mapping_node_inputs_and_properties.
* It is executed on every fcurve in the nodetree id updating its RNA paths. The
* paths needs to be updated because the node properties became inputs.
@@ -1711,10 +1685,12 @@ struct MappingNodeFCurveCallbackData {
* update if the rna path starts with the rna path of the mapping node and
* doesn't end with "default_value", that is, not the Vector input.
*/
static void update_mapping_node_fcurve_rna_path_callback(ID * /*id*/, FCurve *fcurve, void *_data)
static void update_mapping_node_fcurve_rna_path_callback(FCurve *fcurve,
const char *nodePath,
const bNode *minimumNode,
const bNode *maximumNode)
{
MappingNodeFCurveCallbackData *data = (MappingNodeFCurveCallbackData *)_data;
if (!STRPREFIX(fcurve->rna_path, data->nodePath) ||
if (!STRPREFIX(fcurve->rna_path, nodePath) ||
BLI_str_endswith(fcurve->rna_path, "default_value"))
{
return;
@@ -1722,22 +1698,22 @@ static void update_mapping_node_fcurve_rna_path_callback(ID * /*id*/, FCurve *fc
char *old_fcurve_rna_path = fcurve->rna_path;
if (BLI_str_endswith(old_fcurve_rna_path, "translation")) {
fcurve->rna_path = BLI_sprintfN("%s.%s", data->nodePath, "inputs[1].default_value");
fcurve->rna_path = BLI_sprintfN("%s.%s", nodePath, "inputs[1].default_value");
}
else if (BLI_str_endswith(old_fcurve_rna_path, "rotation")) {
fcurve->rna_path = BLI_sprintfN("%s.%s", data->nodePath, "inputs[2].default_value");
fcurve->rna_path = BLI_sprintfN("%s.%s", nodePath, "inputs[2].default_value");
}
else if (BLI_str_endswith(old_fcurve_rna_path, "scale")) {
fcurve->rna_path = BLI_sprintfN("%s.%s", data->nodePath, "inputs[3].default_value");
fcurve->rna_path = BLI_sprintfN("%s.%s", nodePath, "inputs[3].default_value");
}
else if (data->minimumNode && BLI_str_endswith(old_fcurve_rna_path, "max")) {
char node_name_esc[sizeof(data->minimumNode->name) * 2];
BLI_str_escape(node_name_esc, data->minimumNode->name, sizeof(node_name_esc));
else if (minimumNode && BLI_str_endswith(old_fcurve_rna_path, "max")) {
char node_name_esc[sizeof(minimumNode->name) * 2];
BLI_str_escape(node_name_esc, minimumNode->name, sizeof(node_name_esc));
fcurve->rna_path = BLI_sprintfN("nodes[\"%s\"].%s", node_name_esc, "inputs[1].default_value");
}
else if (data->maximumNode && BLI_str_endswith(old_fcurve_rna_path, "min")) {
char node_name_esc[sizeof(data->maximumNode->name) * 2];
BLI_str_escape(node_name_esc, data->maximumNode->name, sizeof(node_name_esc));
else if (maximumNode && BLI_str_endswith(old_fcurve_rna_path, "min")) {
char node_name_esc[sizeof(maximumNode->name) * 2];
BLI_str_escape(node_name_esc, maximumNode->name, sizeof(node_name_esc));
fcurve->rna_path = BLI_sprintfN("nodes[\"%s\"].%s", node_name_esc, "inputs[1].default_value");
}
@@ -1861,8 +1837,9 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree)
BLI_str_escape(node_name_esc, node->name, sizeof(node_name_esc));
char *nodePath = BLI_sprintfN("nodes[\"%s\"]", node_name_esc);
MappingNodeFCurveCallbackData data = {nodePath, minimumNode, maximumNode};
BKE_fcurves_id_cb(&ntree->id, update_mapping_node_fcurve_rna_path_callback, &data);
BKE_fcurves_id_cb(&ntree->id, [&](ID * /*id*/, FCurve *fcu) {
update_mapping_node_fcurve_rna_path_callback(fcu, nodePath, minimumNode, maximumNode);
});
MEM_freeN(nodePath);
}
}
@@ -2943,7 +2920,14 @@ void do_versions_after_linking_280(FileData *fd, Main *bmain)
/* During development of Blender 2.80 the "Object.hide" property was
* removed, and reintroduced in 5e968a996a53 as "Object.hide_viewport". */
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
BKE_fcurves_id_cb(&ob->id, do_version_fcurve_hide_viewport_fix, nullptr);
BKE_fcurves_id_cb(&ob->id, [&](ID * /*id*/, FCurve *fcu) {
if (fcu->rna_path == nullptr || !STREQ(fcu->rna_path, "hide")) {
return;
}
MEM_freeN(fcu->rna_path);
fcu->rna_path = BLI_strdupn("hide_viewport", 13);
});
}
/* Reset all grease pencil brushes. */
@@ -5221,7 +5205,11 @@ void blo_do_versions_280(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
BKE_animdata_main_cb(bmain, do_version_bbone_scale_animdata_cb, nullptr);
BKE_animdata_main_cb(bmain, [](ID * /*id*/, AnimData *adt) {
LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &adt->drivers) {
do_version_bbone_scale_fcurve_fix(&adt->drivers, fcu);
}
});
}
LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) {

View File

@@ -1459,15 +1459,6 @@ static void do_version_bbone_len_scale_fcurve_fix(FCurve *fcu)
replace_bbone_len_scale_rnapath(&fcu->rna_path, &fcu->array_index);
}
static void do_version_bbone_len_scale_animdata_cb(ID * /*id*/,
AnimData *adt,
void * /*wrapper_data*/)
{
LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &adt->drivers) {
do_version_bbone_len_scale_fcurve_fix(fcu);
}
}
static void do_version_bones_bbone_len_scale(ListBase *lb)
{
LISTBASE_FOREACH (Bone *, bone, lb) {
@@ -2369,7 +2360,7 @@ static void version_liboverride_nla_strip_frame_start_end(IDOverrideLibrary *lib
}
/** Fix the `frame_start` and `frame_end` overrides on NLA strips. See #102662. */
static void version_liboverride_nla_frame_start_end(ID *id, AnimData *adt, void * /*user_data*/)
static void version_liboverride_nla_frame_start_end(ID *id, AnimData *adt)
{
IDOverrideLibrary *liboverride = id->override_library;
if (!liboverride) {
@@ -2511,7 +2502,11 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
BKE_animdata_main_cb(bmain, do_version_bbone_len_scale_animdata_cb, nullptr);
BKE_animdata_main_cb(bmain, [](ID * /*id*/, AnimData *adt) {
LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &adt->drivers) {
do_version_bbone_len_scale_fcurve_fix(fcu);
}
});
}
}
@@ -4516,7 +4511,7 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 306, 11)) {
BKE_animdata_main_cb(bmain, version_liboverride_nla_frame_start_end, nullptr);
BKE_animdata_main_cb(bmain, version_liboverride_nla_frame_start_end);
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {

View File

@@ -14,7 +14,7 @@
#include "BLI_utildefines.h"
#include "BKE_animsys.h"
#include "BKE_anim_data.hh"
#include "RNA_path.hh"
@@ -63,50 +63,33 @@ uint64_t AnimatedPropertyID::hash() const
return uint64_t(((ptr1 >> 4) * 33) ^ (ptr2 >> 4));
}
namespace {
struct AnimatedPropertyCallbackData {
PointerRNA pointer_rna;
AnimatedPropertyStorage *animated_property_storage;
DepsgraphBuilderCache *builder_cache;
};
void animated_property_cb(ID * /*id*/, FCurve *fcurve, void *data_v)
{
if (fcurve->rna_path == nullptr || fcurve->rna_path[0] == '\0') {
return;
}
AnimatedPropertyCallbackData *data = static_cast<AnimatedPropertyCallbackData *>(data_v);
/* Resolve property. */
PointerRNA pointer_rna;
PropertyRNA *property_rna = nullptr;
if (!RNA_path_resolve_property(
&data->pointer_rna, fcurve->rna_path, &pointer_rna, &property_rna))
{
return;
}
/* Get storage for the ID.
* This is needed to deal with cases when nested datablock is animated by its parent. */
AnimatedPropertyStorage *animated_property_storage = data->animated_property_storage;
if (pointer_rna.owner_id != data->pointer_rna.owner_id) {
animated_property_storage = data->builder_cache->ensureAnimatedPropertyStorage(
pointer_rna.owner_id);
}
/* Set the property as animated. */
animated_property_storage->tagPropertyAsAnimated(&pointer_rna, property_rna);
}
} // namespace
AnimatedPropertyStorage::AnimatedPropertyStorage() : is_fully_initialized(false) {}
void AnimatedPropertyStorage::initializeFromID(DepsgraphBuilderCache *builder_cache, const ID *id)
{
AnimatedPropertyCallbackData data;
data.pointer_rna = RNA_id_pointer_create(const_cast<ID *>(id));
data.animated_property_storage = this;
data.builder_cache = builder_cache;
BKE_fcurves_id_cb(const_cast<ID *>(id), animated_property_cb, &data);
PointerRNA own_pointer_rna = RNA_id_pointer_create(const_cast<ID *>(id));
BKE_fcurves_id_cb(const_cast<ID *>(id), [&](ID * /*id*/, FCurve *fcurve) {
if (fcurve->rna_path == nullptr || fcurve->rna_path[0] == '\0') {
return;
}
/* Resolve property. */
PointerRNA pointer_rna;
PropertyRNA *property_rna = nullptr;
if (!RNA_path_resolve_property(
&own_pointer_rna, fcurve->rna_path, &pointer_rna, &property_rna))
{
return;
}
/* Get storage for the ID.
* This is needed to deal with cases when nested datablock is animated by its parent. */
AnimatedPropertyStorage *animated_property_storage = this;
if (pointer_rna.owner_id != own_pointer_rna.owner_id) {
animated_property_storage = builder_cache->ensureAnimatedPropertyStorage(
pointer_rna.owner_id);
}
/* Set the property as animated. */
animated_property_storage->tagPropertyAsAnimated(&pointer_rna, property_rna);
});
}
void AnimatedPropertyStorage::tagPropertyAsAnimated(const AnimatedPropertyID &property_id)

View File

@@ -10,6 +10,7 @@
#include "DNA_anim_types.h"
#include "BKE_anim_data.hh"
#include "BKE_animsys.h"
#include "RNA_access.hh"
@@ -19,48 +20,6 @@
namespace blender::deg {
namespace {
struct AnimatedPropertyStoreCalbackData {
AnimationBackup *backup;
/* ID which needs to be stored.
* Is used to check possibly nested IDs which f-curves are pointing to. */
ID *id;
PointerRNA id_pointer_rna;
};
void animated_property_store_cb(ID *id, FCurve *fcurve, void *data_v)
{
AnimatedPropertyStoreCalbackData *data = reinterpret_cast<AnimatedPropertyStoreCalbackData *>(
data_v);
if (fcurve->rna_path == nullptr || fcurve->rna_path[0] == '\0') {
return;
}
if (id != data->id) {
return;
}
/* Resolve path to the property. */
PathResolvedRNA resolved_rna;
if (!BKE_animsys_rna_path_resolve(
&data->id_pointer_rna, fcurve->rna_path, fcurve->array_index, &resolved_rna))
{
return;
}
/* Read property value. */
float value;
if (!BKE_animsys_read_from_rna_path(&resolved_rna, &value)) {
return;
}
data->backup->values_backup.append({fcurve->rna_path, fcurve->array_index, value});
}
} // namespace
AnimationValueBackup::AnimationValueBackup(const string &rna_path, int array_index, float value)
: rna_path(rna_path), array_index(array_index), value(value)
{
@@ -84,11 +43,31 @@ void AnimationBackup::init_from_id(ID *id)
* the current version of backup. */
return;
AnimatedPropertyStoreCalbackData data;
data.backup = this;
data.id = id;
data.id_pointer_rna = RNA_id_pointer_create(id);
BKE_fcurves_id_cb(id, animated_property_store_cb, &data);
PointerRNA id_pointer_rna = RNA_id_pointer_create(id);
BKE_fcurves_id_cb(id, [&](ID *cb_id, FCurve *fcurve) {
if (fcurve->rna_path == nullptr || fcurve->rna_path[0] == '\0') {
return;
}
if (id != cb_id) {
return;
}
/* Resolve path to the property. */
PathResolvedRNA resolved_rna;
if (!BKE_animsys_rna_path_resolve(
&id_pointer_rna, fcurve->rna_path, fcurve->array_index, &resolved_rna))
{
return;
}
/* Read property value. */
float value;
if (!BKE_animsys_read_from_rna_path(&resolved_rna, &value)) {
return;
}
this->values_backup.append({fcurve->rna_path, fcurve->array_index, value});
});
}
void AnimationBackup::restore_to_id(ID *id)

View File

@@ -114,33 +114,23 @@ static void joined_armature_fix_links_constraints(Main *bmain,
}
}
/** User-data for #joined_armature_fix_animdata_cb(). */
struct tJoinArmature_AdtFixData {
Main *bmain;
Object *srcArm;
Object *tarArm;
GHash *names_map;
};
/* Callback to pass to BKE_animdata_main_cb() for fixing driver ID's to point to the new ID. */
/* FIXME: For now, we only care about drivers here.
* When editing rigs, it's very rare to have animation on the rigs being edited already,
* so it should be safe to skip these.
*/
static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data)
static void joined_armature_fix_animdata_cb(
Main *bmain, ID *id, FCurve *fcu, Object *srcArm, Object *tarArm, GHash *names_map)
{
tJoinArmature_AdtFixData *afd = (tJoinArmature_AdtFixData *)user_data;
ID *src_id = &afd->srcArm->id;
ID *dst_id = &afd->tarArm->id;
ID *src_id = &srcArm->id;
ID *dst_id = &tarArm->id;
GHashIterator gh_iter;
bool changed = false;
/* Fix paths - If this is the target object, it will have some "dirty" paths */
if ((id == src_id) && strstr(fcu->rna_path, "pose.bones[")) {
GHASH_ITER (gh_iter, afd->names_map) {
GHASH_ITER (gh_iter, names_map) {
const char *old_name = static_cast<const char *>(BLI_ghashIterator_getKey(&gh_iter));
const char *new_name = static_cast<const char *>(BLI_ghashIterator_getValue(&gh_iter));
@@ -184,7 +174,7 @@ static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data
* little twists so that we know that it isn't going to clobber the wrong data
*/
if ((dtar->rna_path && strstr(dtar->rna_path, "pose.bones[")) || (dtar->pchan_name[0])) {
GHASH_ITER (gh_iter, afd->names_map) {
GHASH_ITER (gh_iter, names_map) {
const char *old_name = static_cast<const char *>(BLI_ghashIterator_getKey(&gh_iter));
const char *new_name = static_cast<const char *>(
BLI_ghashIterator_getValue(&gh_iter));
@@ -212,7 +202,7 @@ static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data
}
if (changed) {
DEG_id_tag_update_ex(afd->bmain, id, ID_RECALC_SYNC_TO_EVAL);
DEG_id_tag_update_ex(bmain, id, ID_RECALC_SYNC_TO_EVAL);
}
}
@@ -362,17 +352,13 @@ int ED_armature_join_objects_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
if ((ob_iter->type == OB_ARMATURE) && (ob_iter != ob_active)) {
tJoinArmature_AdtFixData afd = {nullptr};
bArmature *curarm = static_cast<bArmature *>(ob_iter->data);
/* we assume that each armature datablock is only used in a single place */
BLI_assert(ob_active->data != ob_iter->data);
/* init callback data for fixing up AnimData links later */
afd.bmain = bmain;
afd.srcArm = ob_iter;
afd.tarArm = ob_active;
afd.names_map = BLI_ghash_str_new("join_armature_adt_fix");
GHash *names_map = BLI_ghash_str_new("join_armature_adt_fix");
/* Make a list of edit-bones in current armature */
ED_armature_to_edit(curarm);
@@ -400,7 +386,7 @@ int ED_armature_join_objects_exec(bContext *C, wmOperator *op)
/* Get new name */
ED_armature_ebone_unique_name(arm->edbo, curbone->name, nullptr);
BLI_ghash_insert(afd.names_map, BLI_strdup(pchan->name), curbone->name);
BLI_ghash_insert(names_map, BLI_strdup(pchan->name), curbone->name);
/* Transform the bone */
{
@@ -462,8 +448,10 @@ int ED_armature_join_objects_exec(bContext *C, wmOperator *op)
DEG_id_tag_update_ex(bmain, &curarm->id, ID_RECALC_GEOMETRY);
/* Fix all the drivers (and animation data) */
BKE_fcurves_main_cb(bmain, joined_armature_fix_animdata_cb, &afd);
BLI_ghash_free(afd.names_map, MEM_freeN, nullptr);
BKE_fcurves_main_cb(bmain, [&](ID *id, FCurve *fcu) {
joined_armature_fix_animdata_cb(bmain, id, fcu, ob_iter, ob_active, names_map);
});
BLI_ghash_free(names_map, MEM_freeN, nullptr);
/* Only copy over animdata now, after all the remapping has been done,
* so that we don't have to worry about ambiguities re which armature

View File

@@ -2502,29 +2502,21 @@ void GPENCIL_OT_vertex_group_normalize_all(wmOperatorType *ot)
/****************************** Join ***********************************/
/** User-data for #gpencil_joined_fix_animdata_cb(). */
struct tJoinGPencil_AdtFixData {
bGPdata *src_gpd;
bGPdata *tar_gpd;
GHash *names_map;
};
/**
* Callback to pass to #BKE_fcurves_main_cb()
* for RNA Paths attached to each F-Curve used in the #AnimData.
*/
static void gpencil_joined_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data)
static void gpencil_joined_fix_animdata_cb(
ID *id, FCurve *fcu, bGPdata *src_gpd, bGPdata *tar_gpd, GHash *names_map)
{
tJoinGPencil_AdtFixData *afd = (tJoinGPencil_AdtFixData *)user_data;
ID *src_id = &afd->src_gpd->id;
ID *dst_id = &afd->tar_gpd->id;
ID *src_id = &src_gpd->id;
ID *dst_id = &tar_gpd->id;
GHashIterator gh_iter;
/* Fix paths - If this is the target datablock, it will have some "dirty" paths */
if ((id == src_id) && fcu->rna_path && strstr(fcu->rna_path, "layers[")) {
GHASH_ITER (gh_iter, afd->names_map) {
GHASH_ITER (gh_iter, names_map) {
const char *old_name = static_cast<const char *>(BLI_ghashIterator_getKey(&gh_iter));
const char *new_name = static_cast<const char *>(BLI_ghashIterator_getValue(&gh_iter));
@@ -2556,7 +2548,7 @@ static void gpencil_joined_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data)
* little twists so that we know that it isn't going to clobber the wrong data
*/
if (dtar->rna_path && strstr(dtar->rna_path, "layers[")) {
GHASH_ITER (gh_iter, afd->names_map) {
GHASH_ITER (gh_iter, names_map) {
const char *old_name = static_cast<const char *>(BLI_ghashIterator_getKey(&gh_iter));
const char *new_name = static_cast<const char *>(
BLI_ghashIterator_getValue(&gh_iter));
@@ -2674,10 +2666,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
}
/* Duplicate #bGPDlayers. */
tJoinGPencil_AdtFixData afd = {nullptr};
afd.src_gpd = gpd_src;
afd.tar_gpd = gpd_dst;
afd.names_map = BLI_ghash_str_new("joined_gp_layers_map");
GHash *names_map = BLI_ghash_str_new("joined_gp_layers_map");
float imat[3][3], bmat[3][3];
float offset_global[3];
@@ -2727,15 +2716,17 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
'.',
offsetof(bGPDlayer, info),
sizeof(gpl_new->info));
BLI_ghash_insert(afd.names_map, BLI_strdup(gpl_src->info), gpl_new->info);
BLI_ghash_insert(names_map, BLI_strdup(gpl_src->info), gpl_new->info);
/* add to destination datablock */
BLI_addtail(&gpd_dst->layers, gpl_new);
}
/* Fix all the animation data */
BKE_fcurves_main_cb(bmain, gpencil_joined_fix_animdata_cb, &afd);
BLI_ghash_free(afd.names_map, MEM_freeN, nullptr);
BKE_fcurves_main_cb(bmain, [&](ID *id, FCurve *fcu) {
gpencil_joined_fix_animdata_cb(id, fcu, gpd_src, gpd_dst, names_map);
});
BLI_ghash_free(names_map, MEM_freeN, nullptr);
/* Only copy over animdata now, after all the remapping has been done,
* so that we don't have to worry about ambiguities re which datablock