BKE ID remap: Refactor: Remove C API around CPP IDRemapper.

The ID remapper code was already largely defined in a CPP struct
(IDRemapper). Make this an actual class, and remove the C API wrapper
around.

This makes the code cleaner, easier to follow, and easier to extend or
modify in the future.

Pull Request: https://projects.blender.org/blender/blender/pulls/118146
This commit is contained in:
Bastien Montagne
2024-02-13 15:36:38 +01:00
committed by Bastien Montagne
parent d284941e89
commit 5baef63a20
34 changed files with 414 additions and 487 deletions
@@ -21,9 +21,12 @@
#include "BKE_callbacks.hh"
struct IDRemapper;
struct Main;
namespace blender::bke::id {
class IDRemapper;
}
namespace blender::asset_system {
class AssetIdentifier;
@@ -140,7 +143,7 @@ class AssetLibrary {
* mapped to null (typically when an ID gets removed), the asset is removed, because we don't
* support such empty/null assets.
*/
void remap_ids_and_remove_invalid(const IDRemapper &mappings);
void remap_ids_and_remove_invalid(const blender::bke::id::IDRemapper &mappings);
/**
* Update `catalog_simple_name` by looking up the asset's catalog by its ID.
@@ -264,7 +267,7 @@ bool AS_asset_library_has_any_unsaved_catalogs(void);
* An asset library can include local IDs (IDs in the current file). Their pointers need to be
* remapped on change (or assets removed as IDs gets removed).
*/
void AS_asset_library_remap_ids(const IDRemapper *mappings);
void AS_asset_library_remap_ids(const blender::bke::id::IDRemapper &mappings);
/**
* Attempt to resolve a full path to an asset based on the currently available (not necessary
@@ -13,6 +13,7 @@
#include "AS_asset_library.hh"
#include "AS_asset_representation.hh"
#include "BKE_lib_remap.hh"
#include "BKE_main.hh"
#include "BKE_preferences.h"
@@ -117,12 +118,11 @@ void AS_asset_library_refresh_catalog_simplename(AssetLibrary *asset_library,
asset_library->refresh_catalog_simplename(asset_data);
}
void AS_asset_library_remap_ids(const IDRemapper *mappings)
void AS_asset_library_remap_ids(const bke::id::IDRemapper &mappings)
{
AssetLibraryService *service = AssetLibraryService::get();
service->foreach_loaded_asset_library(
[mappings](AssetLibrary &library) { library.remap_ids_and_remove_invalid(*mappings); },
true);
[mappings](AssetLibrary &library) { library.remap_ids_and_remove_invalid(mappings); }, true);
}
void AS_asset_full_path_explode_from_weak_ref(const AssetWeakReference *asset_reference,
@@ -239,7 +239,7 @@ bool AssetLibrary::remove_asset(AssetRepresentation &asset)
return asset_storage_->remove_asset(asset);
}
void AssetLibrary::remap_ids_and_remove_invalid(const IDRemapper &mappings)
void AssetLibrary::remap_ids_and_remove_invalid(const bke::id::IDRemapper &mappings)
{
asset_storage_->remap_ids_and_remove_invalid(mappings);
}
@@ -43,7 +43,7 @@ bool AssetStorage::remove_asset(AssetRepresentation &asset)
return external_assets_.remove_as(&asset);
}
void AssetStorage::remap_ids_and_remove_invalid(const IDRemapper &mappings)
void AssetStorage::remap_ids_and_remove_invalid(const blender::bke::id::IDRemapper &mappings)
{
Set<AssetRepresentation *> removed_assets{};
@@ -51,8 +51,8 @@ void AssetStorage::remap_ids_and_remove_invalid(const IDRemapper &mappings)
AssetRepresentation &asset = *asset_ptr;
BLI_assert(asset.is_local_id());
const IDRemapperApplyResult result = BKE_id_remapper_apply(
&mappings, &asset.local_asset_id_, ID_REMAP_APPLY_DEFAULT);
const IDRemapperApplyResult result = mappings.apply(&asset.local_asset_id_,
ID_REMAP_APPLY_DEFAULT);
/* Entirely remove assets whose ID is unset. We don't want assets with a null ID pointer. */
if (result == ID_REMAP_RESULT_SOURCE_UNASSIGNED) {
@@ -17,7 +17,10 @@
struct AssetMetaData;
struct ID;
struct IDRemapper;
namespace blender::bke::id {
class IDRemapper;
}
namespace blender::asset_system {
@@ -49,7 +52,7 @@ class AssetStorage {
bool remove_asset(AssetRepresentation &asset);
/** See #AssetLibrary::remap_ids_and_remove_nulled(). */
void remap_ids_and_remove_invalid(const IDRemapper &mappings);
void remap_ids_and_remove_invalid(const blender::bke::id::IDRemapper &mappings);
};
} // namespace blender::asset_system
+78 -59
View File
@@ -21,13 +21,17 @@
*/
#include "BLI_compiler_attrs.h"
#include "BLI_map.hh"
#include "BLI_span.hh"
#include "BLI_utildefines.h"
struct ID;
struct IDRemapper;
struct Main;
namespace blender::bke::id {
class IDRemapper;
}
/* BKE_libblock_free, delete are declared in BKE_lib_id.hh for convenience. */
/* Also IDRemap->flag. */
@@ -124,9 +128,13 @@ enum eIDRemapType {
*
* \note Is preferred over BKE_libblock_remap_locked due to performance.
*/
void BKE_libblock_remap_multiple_locked(Main *bmain, IDRemapper *mappings, const int remap_flags);
void BKE_libblock_remap_multiple_locked(Main *bmain,
blender::bke::id::IDRemapper &mappings,
const int remap_flags);
void BKE_libblock_remap_multiple(Main *bmain, IDRemapper *mappings, const int remap_flags);
void BKE_libblock_remap_multiple(Main *bmain,
blender::bke::id::IDRemapper &mappings,
const int remap_flags);
/**
* Bare raw remapping of IDs, with no other processing than actually updating the ID pointers.
@@ -137,7 +145,9 @@ void BKE_libblock_remap_multiple(Main *bmain, IDRemapper *mappings, const int re
* case e.g. in read-file process.
*
* WARNING: This call will likely leave the given BMain in invalid state in many aspects. */
void BKE_libblock_remap_multiple_raw(Main *bmain, IDRemapper *mappings, const int remap_flags);
void BKE_libblock_remap_multiple_raw(Main *bmain,
blender::bke::id::IDRemapper &mappings,
const int remap_flags);
/**
* Replace all references in given Main to \a old_id by \a new_id
* (if \a new_id is NULL, it unlinks \a old_id).
@@ -178,7 +188,7 @@ void BKE_libblock_relink_ex(Main *bmain, void *idv, void *old_idv, void *new_idv
void BKE_libblock_relink_multiple(Main *bmain,
const blender::Span<ID *> ids,
eIDRemapType remap_type,
IDRemapper *id_remapper,
blender::bke::id::IDRemapper &id_remapper,
int remap_flags);
/**
@@ -193,7 +203,8 @@ void BKE_libblock_relink_multiple(Main *bmain,
void BKE_libblock_relink_to_newid(Main *bmain, ID *id, int remap_flag) ATTR_NONNULL();
using BKE_library_free_notifier_reference_cb = void (*)(const void *);
using BKE_library_remap_editor_id_reference_cb = void (*)(const IDRemapper *mappings);
using BKE_library_remap_editor_id_reference_cb =
void (*)(const blender::bke::id::IDRemapper &mappings);
void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func);
void BKE_library_callback_remap_editor_id_reference_set(
@@ -220,7 +231,7 @@ enum IDRemapperApplyOptions {
*
* NOTE: Currently unused by main remapping code, since user-count is handled by
* `foreach_libblock_remap_callback_apply` there, depending on whether the remapped pointer does
* use it or not. Need for rare cases in UI handling though (see e.g. `image_id_remap` in
* use it or not. Needed for rare cases in UI handling though (see e.g. `image_id_remap` in
* `space_image.cc`).
*/
ID_REMAP_APPLY_UPDATE_REFCOUNT = (1 << 0),
@@ -233,9 +244,9 @@ enum IDRemapperApplyOptions {
ID_REMAP_APPLY_ENSURE_REAL = (1 << 1),
/**
* Unassign in stead of remap when the new ID data-block would become id_self.
* Unassign instead of remap when the new ID pointer would point to itself.
*
* To use this option 'BKE_id_remapper_apply_ex' must be used with a not-null id_self parameter.
* To use this option #IDRemapper::apply must be used with a non-null id_self parameter.
*/
ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF = (1 << 2),
@@ -244,58 +255,66 @@ enum IDRemapperApplyOptions {
ENUM_OPERATORS(IDRemapperApplyOptions, ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF)
using IDRemapperIterFunction = void (*)(ID *old_id, ID *new_id, void *user_data);
using IDTypeFilter = uint64_t;
/**
* Create a new ID Remapper.
*
* An ID remapper stores multiple remapping rules.
*/
IDRemapper *BKE_id_remapper_create();
namespace blender::bke::id {
void BKE_id_remapper_clear(IDRemapper *id_remapper);
bool BKE_id_remapper_is_empty(const IDRemapper *id_remapper);
/** Free the given ID Remapper. */
void BKE_id_remapper_free(IDRemapper *id_remapper);
/** Add a new remapping. Does not replace an existing mapping for `old_id`, if any. */
void BKE_id_remapper_add(IDRemapper *id_remapper, ID *old_id, ID *new_id);
/** Add a new remapping, replacing a potential already existing mapping of `old_id`. */
void BKE_id_remapper_add_overwrite(IDRemapper *id_remapper, ID *old_id, ID *new_id);
class IDRemapper {
blender::Map<ID *, ID *> mappings_;
IDTypeFilter source_types_ = 0;
/**
* Apply a remapping.
*
* Update the id pointer stored in the given r_id_ptr if a remapping rule exists.
*/
IDRemapperApplyResult BKE_id_remapper_apply(const IDRemapper *id_remapper,
ID **r_id_ptr,
IDRemapperApplyOptions options);
/**
* Apply a remapping.
*
* Use this function when `ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF`. In this case
* the #id_self parameter is required. Otherwise the #BKE_id_remapper_apply can be used.
*
* \param id_self: required for ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF.
* When remapping to id_self it will then be remapped to NULL.
*/
IDRemapperApplyResult BKE_id_remapper_apply_ex(const IDRemapper *id_remapper,
ID **r_id_ptr,
IDRemapperApplyOptions options,
ID *id_self);
bool BKE_id_remapper_has_mapping_for(const IDRemapper *id_remapper, uint64_t type_filter);
public:
void clear(void)
{
mappings_.clear();
source_types_ = 0;
}
/**
* Determine the mapping result, without applying the mapping.
*/
IDRemapperApplyResult BKE_id_remapper_get_mapping_result(const IDRemapper *id_remapper,
ID *id,
IDRemapperApplyOptions options,
const ID *id_self);
void BKE_id_remapper_iter(const IDRemapper *id_remapper,
IDRemapperIterFunction func,
void *user_data);
bool is_empty(void) const
{
return mappings_.is_empty();
}
/** Returns a readable string for the given result. Can be used for debugging purposes. */
const char *BKE_id_remapper_result_string(const IDRemapperApplyResult result);
/** Prints out the rules inside the given id_remapper. Can be used for debugging purposes. */
void BKE_id_remapper_print(const IDRemapper *id_remapper);
bool contains_mappings_for_any(IDTypeFilter filter) const
{
return (source_types_ & filter) != 0;
}
/** Add a new remapping. Does not replace an existing mapping for `old_id`, if any. */
void add(ID *old_id, ID *new_id);
/** Add a new remapping, replacing a potential already existing mapping of `old_id`. */
void add_overwrite(ID *old_id, ID *new_id);
/** Determine the mapping result, without applying the mapping. */
IDRemapperApplyResult get_mapping_result(ID *id,
IDRemapperApplyOptions options,
const ID *id_self) const;
/**
* Apply a remapping.
*
* Update the id pointer stored in the given r_id_ptr if a remapping rule exists.
*
* \param id_self: Only for ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF.
* When remapping to `id_self` it will then be remapped to `nullptr` instead.
*/
IDRemapperApplyResult apply(ID **r_id_ptr,
IDRemapperApplyOptions options,
ID *id_self = nullptr) const;
/** Iterate over all remapping pairs in the remapper, and call the callback function on them. */
void iter(IDRemapperIterFunction func, void *user_data) const
{
for (auto item : mappings_.items()) {
func(item.key, item.value, user_data);
}
}
/** Return a readable string for the given result. Can be used for debugging purposes. */
static const blender::StringRefNull result_to_string(const IDRemapperApplyResult result);
/** Print out the rules inside the given id_remapper. Can be used for debugging purposes. */
void print(void) const;
};
} // namespace blender::bke::id
+5 -2
View File
@@ -17,6 +17,10 @@
#include "BKE_context.hh"
namespace blender::bke::id {
class IDRemapper;
}
namespace blender::asset_system {
class AssetRepresentation;
}
@@ -28,7 +32,6 @@ struct BlendLibReader;
struct BlendWriter;
struct Header;
struct ID;
struct IDRemapper;
struct LayoutPanelState;
struct LibraryForeachIDData;
struct ListBase;
@@ -109,7 +112,7 @@ struct SpaceType {
bContextDataCallback context;
/* Used when we want to replace an ID by another (or NULL). */
void (*id_remap)(ScrArea *area, SpaceLink *sl, const IDRemapper *mappings);
void (*id_remap)(ScrArea *area, SpaceLink *sl, const blender::bke::id::IDRemapper &mappings);
/**
* foreach_id callback to process all ID pointers of the editor. Used indirectly by lib_query's
+6 -2
View File
@@ -29,7 +29,10 @@ struct BlendDataReader;
struct BlendLibReader;
struct LibraryForeachIDData;
struct Library;
struct IDRemapper;
namespace blender::bke::id {
class IDRemapper;
}
enum ViewerPathEqualFlag {
VIEWER_PATH_EQUAL_FLAG_IGNORE_REPEAT_ITERATION = (1 << 0),
@@ -44,7 +47,8 @@ bool BKE_viewer_path_equal(const ViewerPath *a,
void BKE_viewer_path_blend_write(BlendWriter *writer, const ViewerPath *viewer_path);
void BKE_viewer_path_blend_read_data(BlendDataReader *reader, ViewerPath *viewer_path);
void BKE_viewer_path_foreach_id(LibraryForeachIDData *data, ViewerPath *viewer_path);
void BKE_viewer_path_id_remap(ViewerPath *viewer_path, const IDRemapper *mappings);
void BKE_viewer_path_id_remap(ViewerPath *viewer_path,
const blender::bke::id::IDRemapper &mappings);
ViewerPathElem *BKE_viewer_path_elem_new(ViewerPathElemType type);
IDViewerPathElem *BKE_viewer_path_elem_new_id();
+23 -22
View File
@@ -64,6 +64,8 @@
# include "BPY_extern.h"
#endif
using namespace blender::bke;
/* -------------------------------------------------------------------- */
/** \name Blend/Library Paths
* \{ */
@@ -228,7 +230,7 @@ struct ReuseOldBMainData {
/** Storage for all remapping rules (old_id -> new_id) required by the preservation of old IDs
* into the new Main. */
IDRemapper *remapper;
id::IDRemapper *remapper;
bool is_libraries_remapped;
/** Used to find matching IDs by name/lib in new main, to remap ID usages of data ported over
@@ -246,25 +248,25 @@ struct ReuseOldBMainData {
* double of a linked data as a local one, without any known relationships between them. In
* practice, this latter case is not expected to commonly happen.
*/
static IDRemapper *reuse_bmain_data_remapper_ensure(ReuseOldBMainData *reuse_data)
static id::IDRemapper &reuse_bmain_data_remapper_ensure(ReuseOldBMainData *reuse_data)
{
if (reuse_data->is_libraries_remapped) {
return reuse_data->remapper;
return *reuse_data->remapper;
}
if (reuse_data->remapper == nullptr) {
reuse_data->remapper = BKE_id_remapper_create();
reuse_data->remapper = MEM_new<id::IDRemapper>(__func__);
}
Main *new_bmain = reuse_data->new_bmain;
Main *old_bmain = reuse_data->old_bmain;
IDRemapper *remapper = reuse_data->remapper;
id::IDRemapper &remapper = *reuse_data->remapper;
LISTBASE_FOREACH (Library *, old_lib_iter, &old_bmain->libraries) {
/* In case newly opened `new_bmain` is a library of the `old_bmain`, remap it to null, since a
* file should never ever have linked data from itself. */
if (STREQ(old_lib_iter->filepath_abs, new_bmain->filepath)) {
BKE_id_remapper_add(remapper, &old_lib_iter->id, nullptr);
remapper.add(&old_lib_iter->id, nullptr);
continue;
}
@@ -277,19 +279,18 @@ static IDRemapper *reuse_bmain_data_remapper_ensure(ReuseOldBMainData *reuse_dat
continue;
}
BKE_id_remapper_add(remapper, &old_lib_iter->id, &new_lib_iter->id);
remapper.add(&old_lib_iter->id, &new_lib_iter->id);
break;
}
}
reuse_data->is_libraries_remapped = true;
return reuse_data->remapper;
return *reuse_data->remapper;
}
static bool reuse_bmain_data_remapper_is_id_remapped(IDRemapper *remapper, ID *id)
static bool reuse_bmain_data_remapper_is_id_remapped(id::IDRemapper &remapper, ID *id)
{
IDRemapperApplyResult result = BKE_id_remapper_get_mapping_result(
remapper, id, ID_REMAP_APPLY_DEFAULT, nullptr);
IDRemapperApplyResult result = remapper.get_mapping_result(id, ID_REMAP_APPLY_DEFAULT, nullptr);
if (ELEM(result, ID_REMAP_RESULT_SOURCE_REMAPPED, ID_REMAP_RESULT_SOURCE_UNASSIGNED)) {
/* ID is already remapped to its matching ID in the new main, or explicitly remapped to null,
* nothing else to do here. */
@@ -319,7 +320,7 @@ static void swap_old_bmain_data_for_blendfile(ReuseOldBMainData *reuse_data, con
ListBase *new_lb = which_libbase(new_bmain, id_code);
ListBase *old_lb = which_libbase(old_bmain, id_code);
IDRemapper *remapper = reuse_bmain_data_remapper_ensure(reuse_data);
id::IDRemapper &remapper = reuse_bmain_data_remapper_ensure(reuse_data);
/* NOTE: Full swapping is only supported for ID types that are assumed to be only local
* data-blocks (like UI-like ones). Otherwise, the swapping could fail in many funny ways. */
@@ -346,14 +347,14 @@ static void swap_old_bmain_data_for_blendfile(ReuseOldBMainData *reuse_data, con
const int strcmp_result = strcmp(discarded_id_iter->name + 2, reused_id_iter->name + 2);
if (strcmp_result == 0) {
/* Matching IDs, we can remap the discarded 'new' one to the re-used 'old' one. */
BKE_id_remapper_add(remapper, discarded_id_iter, reused_id_iter);
remapper.add(discarded_id_iter, reused_id_iter);
discarded_id_iter = static_cast<ID *>(discarded_id_iter->next);
reused_id_iter = static_cast<ID *>(reused_id_iter->next);
}
else if (strcmp_result < 0) {
/* No matching reused 'old' ID for this discarded 'new' one. */
BKE_id_remapper_add(remapper, discarded_id_iter, nullptr);
remapper.add(discarded_id_iter, nullptr);
discarded_id_iter = static_cast<ID *>(discarded_id_iter->next);
}
@@ -365,7 +366,7 @@ static void swap_old_bmain_data_for_blendfile(ReuseOldBMainData *reuse_data, con
for (; discarded_id_iter != nullptr;
discarded_id_iter = static_cast<ID *>(discarded_id_iter->next))
{
BKE_id_remapper_add(remapper, discarded_id_iter, nullptr);
remapper.add(discarded_id_iter, nullptr);
}
FOREACH_MAIN_LISTBASE_ID_BEGIN (new_lb, reused_id_iter) {
@@ -374,7 +375,7 @@ static void swap_old_bmain_data_for_blendfile(ReuseOldBMainData *reuse_data, con
/* Ensure that the reused ID is remapped to itself, since it is known to be in the `new_bmain`.
*/
BKE_id_remapper_add_overwrite(remapper, reused_id_iter, reused_id_iter);
remapper.add_overwrite(reused_id_iter, reused_id_iter);
}
FOREACH_MAIN_LISTBASE_ID_END;
}
@@ -428,8 +429,8 @@ static void swap_wm_data_for_blendfile(ReuseOldBMainData *reuse_data, const bool
* new WM, and is responsible to free it properly. */
reuse_data->wm_setup_data->old_wm = old_wm;
IDRemapper *remapper = reuse_bmain_data_remapper_ensure(reuse_data);
BKE_id_remapper_add(remapper, &old_wm->id, &new_wm->id);
id::IDRemapper &remapper = reuse_bmain_data_remapper_ensure(reuse_data);
remapper.add(&old_wm->id, &new_wm->id);
}
/* Current (old) WM, but no (new) one in file (should only happen when reading pre 2.5 files, no
* WM back then), or not loading UI: Keep current WM. */
@@ -452,7 +453,7 @@ static int swap_old_bmain_data_for_blendfile_dependencies_process_cb(
ReuseOldBMainData *reuse_data = static_cast<ReuseOldBMainData *>(cb_data->user_data);
/* First check if it has already been remapped. */
IDRemapper *remapper = reuse_bmain_data_remapper_ensure(reuse_data);
id::IDRemapper &remapper = reuse_bmain_data_remapper_ensure(reuse_data);
if (reuse_bmain_data_remapper_is_id_remapped(remapper, id)) {
return IDWALK_RET_NOP;
}
@@ -461,7 +462,7 @@ static int swap_old_bmain_data_for_blendfile_dependencies_process_cb(
BLI_assert(id_map != nullptr);
ID *id_new = BKE_main_idmap_lookup_id(id_map, id);
BKE_id_remapper_add(remapper, id, id_new);
remapper.add(id, id_new);
return IDWALK_RET_NOP;
}
@@ -784,7 +785,7 @@ static void setup_app_data(bContext *C,
/* Handle all pending remapping from swapping old and new IDs around. */
BKE_libblock_remap_multiple_raw(bfd->main,
reuse_data.remapper,
*reuse_data.remapper,
(ID_REMAP_FORCE_UI_POINTERS | ID_REMAP_SKIP_USER_REFCOUNT |
ID_REMAP_SKIP_UPDATE_TAGGING | ID_REMAP_SKIP_USER_CLEAR));
@@ -793,7 +794,7 @@ static void setup_app_data(bContext *C,
* library of the previous opened blendfile'. */
reuse_bmain_data_invalid_local_usages_fix(&reuse_data);
BKE_id_remapper_free(reuse_data.remapper);
MEM_delete(reuse_data.remapper);
reuse_data.remapper = nullptr;
wm_data_consistency_ensure(CTX_wm_manager(C), curscene, cur_view_layer);
+12 -10
View File
@@ -77,6 +77,8 @@
# include "BLI_time_utildefines.h"
#endif
using namespace blender::bke::id;
static CLG_LogRef LOG = {"bke.lib_id"};
IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
@@ -803,10 +805,10 @@ static void id_swap(Main *bmain,
IDRemapper *remapper_id_b = input_remapper_id_b;
if (do_self_remap) {
if (remapper_id_a == nullptr) {
remapper_id_a = BKE_id_remapper_create();
remapper_id_a = MEM_new<IDRemapper>(__func__);
}
if (remapper_id_b == nullptr) {
remapper_id_b = BKE_id_remapper_create();
remapper_id_b = MEM_new<IDRemapper>(__func__);
}
}
@@ -852,25 +854,25 @@ static void id_swap(Main *bmain,
}
if (remapper_id_a != nullptr) {
BKE_id_remapper_add(remapper_id_a, id_b, id_a);
remapper_id_a->add(id_b, id_a);
}
if (remapper_id_b != nullptr) {
BKE_id_remapper_add(remapper_id_b, id_a, id_b);
remapper_id_b->add(id_a, id_b);
}
/* Finalize remapping of internal references to self broken by swapping, if requested. */
if (do_self_remap) {
BKE_libblock_relink_multiple(
bmain, {id_a}, ID_REMAP_TYPE_REMAP, remapper_id_a, self_remap_flags);
bmain, {id_a}, ID_REMAP_TYPE_REMAP, *remapper_id_a, self_remap_flags);
BKE_libblock_relink_multiple(
bmain, {id_b}, ID_REMAP_TYPE_REMAP, remapper_id_b, self_remap_flags);
bmain, {id_b}, ID_REMAP_TYPE_REMAP, *remapper_id_b, self_remap_flags);
}
if (input_remapper_id_a == nullptr && remapper_id_a != nullptr) {
BKE_id_remapper_free(remapper_id_a);
MEM_delete(remapper_id_a);
}
if (input_remapper_id_b == nullptr && remapper_id_b != nullptr) {
BKE_id_remapper_free(remapper_id_b);
MEM_delete(remapper_id_b);
}
}
@@ -908,10 +910,10 @@ static void id_embedded_swap(ID **embedded_id_a,
/* Restore internal pointers to the swapped embedded IDs in their owners' data. This also
* includes the potential self-references inside the embedded IDs themselves. */
if (remapper_id_a != nullptr) {
BKE_id_remapper_add(remapper_id_a, *embedded_id_b, *embedded_id_a);
remapper_id_a->add(*embedded_id_b, *embedded_id_a);
}
if (remapper_id_b != nullptr) {
BKE_id_remapper_add(remapper_id_b, *embedded_id_a, *embedded_id_b);
remapper_id_b->add(*embedded_id_a, *embedded_id_b);
}
}
}
@@ -42,6 +42,8 @@
# include "BPY_extern.h"
#endif
using namespace blender::bke::id;
static CLG_LogRef LOG = {"bke.lib_id_delete"};
void BKE_libblock_free_data(ID *id, const bool do_id_user)
@@ -146,10 +148,9 @@ static int id_free(Main *bmain, void *idv, int flag, const bool use_flag_from_id
}
if (remap_editor_id_reference_cb) {
IDRemapper *remapper = BKE_id_remapper_create();
BKE_id_remapper_add(remapper, id, nullptr);
IDRemapper remapper;
remapper.add(id, nullptr);
remap_editor_id_reference_cb(remapper);
BKE_id_remapper_free(remapper);
}
}
@@ -241,7 +242,7 @@ static size_t id_delete(Main *bmain,
BKE_main_lock(bmain);
if (do_tagged_deletion) {
IDRemapper *id_remapper = BKE_id_remapper_create();
IDRemapper id_remapper;
BKE_layer_collection_resync_forbid();
/* Main idea of batch deletion is to remove all IDs to be deleted from Main database.
@@ -269,7 +270,7 @@ static size_t id_delete(Main *bmain,
BLI_remlink(lb, id);
BKE_main_namemap_remove_name(bmain, id, id->name + 2);
BLI_addtail(&tagged_deleted_ids, id);
BKE_id_remapper_add(id_remapper, id, nullptr);
id_remapper.add(id, nullptr);
/* Do not tag as no_main now, we want to unlink it first (lower-level ID management
* code has some specific handling of 'no main' IDs that would be a problem in that
* case). */
@@ -283,7 +284,7 @@ static size_t id_delete(Main *bmain,
BLI_remlink(&bmain->shapekeys, &shape_key->id);
BKE_main_namemap_remove_name(bmain, &shape_key->id, shape_key->id.name + 2);
BLI_addtail(&tagged_deleted_ids, &shape_key->id);
BKE_id_remapper_add(id_remapper, &shape_key->id, nullptr);
id_remapper.add(&shape_key->id, nullptr);
shape_key->id.tag |= tag;
}
@@ -299,7 +300,7 @@ static size_t id_delete(Main *bmain,
* Also, this will also flag users of deleted data that cannot be unlinked
* (object using deleted obdata, etc.), so that they also get deleted. */
BKE_libblock_remap_multiple_locked(bmain, id_remapper, remapping_flags);
BKE_id_remapper_clear(id_remapper);
id_remapper.clear();
}
/* Since we removed IDs from Main, their own other IDs usages need to be removed 'manually'. */
@@ -316,7 +317,6 @@ static size_t id_delete(Main *bmain,
ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS |
ID_REMAP_SKIP_USER_CLEAR);
cleanup_ids.clear();
BKE_id_remapper_free(id_remapper);
BKE_layer_collection_resync_allow();
BKE_main_collection_sync_remap(bmain);
@@ -340,22 +340,22 @@ static size_t id_delete(Main *bmain,
* Note that we go forward here, since we want to check dependencies before users
* (e.g. meshes before objects).
* Avoids to have to loop twice. */
IDRemapper *remapper = BKE_id_remapper_create();
IDRemapper remapper;
for (i = 0; i < base_count; i++) {
ListBase *lb = lbarray[i];
ID *id, *id_next;
BKE_id_remapper_clear(remapper);
remapper.clear();
for (id = static_cast<ID *>(lb->first); id; id = id_next) {
id_next = static_cast<ID *>(id->next);
/* NOTE: in case we delete a library, we also delete all its datablocks! */
if ((id->tag & tag) || (ID_IS_LINKED(id) && (id->lib->id.tag & tag))) {
id->tag |= tag;
BKE_id_remapper_add(remapper, id, nullptr);
remapper.add(id, nullptr);
}
}
if (BKE_id_remapper_is_empty(remapper)) {
if (remapper.is_empty()) {
continue;
}
@@ -367,7 +367,6 @@ static size_t id_delete(Main *bmain,
* (object using deleted obdata, etc.), so that they also get deleted. */
BKE_libblock_remap_multiple_locked(bmain, remapper, remapping_flags);
}
BKE_id_remapper_free(remapper);
}
BKE_main_unlock(bmain);
@@ -10,215 +10,87 @@
#include "MEM_guardedalloc.h"
#include "BLI_map.hh"
namespace blender::bke::id {
using IDTypeFilter = uint64_t;
void IDRemapper::add(ID *old_id, ID *new_id)
{
BLI_assert(old_id != nullptr);
BLI_assert(new_id == nullptr || (GS(old_id->name) == GS(new_id->name)));
BLI_assert(BKE_idtype_idcode_to_idfilter(GS(old_id->name)) != 0);
namespace blender::bke::id::remapper {
struct IDRemapper {
private:
Map<ID *, ID *> mappings;
IDTypeFilter source_types = 0;
mappings_.add(old_id, new_id);
source_types_ |= BKE_idtype_idcode_to_idfilter(GS(old_id->name));
}
public:
void clear()
{
mappings.clear();
source_types = 0;
void IDRemapper::add_overwrite(ID *old_id, ID *new_id)
{
BLI_assert(old_id != nullptr);
BLI_assert(new_id == nullptr || (GS(old_id->name) == GS(new_id->name)));
BLI_assert(BKE_idtype_idcode_to_idfilter(GS(old_id->name)) != 0);
mappings_.add_overwrite(old_id, new_id);
source_types_ |= BKE_idtype_idcode_to_idfilter(GS(old_id->name));
}
IDRemapperApplyResult IDRemapper::get_mapping_result(ID *id,
IDRemapperApplyOptions options,
const ID *id_self) const
{
if (!mappings_.contains(id)) {
return ID_REMAP_RESULT_SOURCE_UNAVAILABLE;
}
const ID *new_id = mappings_.lookup(id);
if ((options & ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF) != 0 && id_self == new_id) {
new_id = nullptr;
}
if (new_id == nullptr) {
return ID_REMAP_RESULT_SOURCE_UNASSIGNED;
}
bool is_empty() const
{
return mappings.is_empty();
return ID_REMAP_RESULT_SOURCE_REMAPPED;
}
IDRemapperApplyResult IDRemapper::apply(ID **r_id_ptr,
IDRemapperApplyOptions options,
ID *id_self) const
{
BLI_assert(r_id_ptr != nullptr);
BLI_assert_msg(
((options & ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF) == 0 || id_self != nullptr),
"ID_REMAP_APPLY_WHEN_REMAPPING_TO_SELF requires a non-null `id_self` parameter.");
if (*r_id_ptr == nullptr) {
return ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE;
}
void add(ID *old_id, ID *new_id)
{
BLI_assert(old_id != nullptr);
BLI_assert(new_id == nullptr || (GS(old_id->name) == GS(new_id->name)));
mappings.add(old_id, new_id);
BLI_assert(BKE_idtype_idcode_to_idfilter(GS(old_id->name)) != 0);
source_types |= BKE_idtype_idcode_to_idfilter(GS(old_id->name));
if (!mappings_.contains(*r_id_ptr)) {
return ID_REMAP_RESULT_SOURCE_UNAVAILABLE;
}
void add_overwrite(ID *old_id, ID *new_id)
{
BLI_assert(old_id != nullptr);
BLI_assert(new_id == nullptr || (GS(old_id->name) == GS(new_id->name)));
mappings.add_overwrite(old_id, new_id);
BLI_assert(BKE_idtype_idcode_to_idfilter(GS(old_id->name)) != 0);
source_types |= BKE_idtype_idcode_to_idfilter(GS(old_id->name));
if (options & ID_REMAP_APPLY_UPDATE_REFCOUNT) {
id_us_min(*r_id_ptr);
}
bool contains_mappings_for_any(IDTypeFilter filter) const
{
return (source_types & filter) != 0;
*r_id_ptr = mappings_.lookup(*r_id_ptr);
if (options & ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF && *r_id_ptr == id_self) {
*r_id_ptr = nullptr;
}
if (*r_id_ptr == nullptr) {
return ID_REMAP_RESULT_SOURCE_UNASSIGNED;
}
IDRemapperApplyResult get_mapping_result(ID *id,
IDRemapperApplyOptions options,
const ID *id_self) const
{
if (!mappings.contains(id)) {
return ID_REMAP_RESULT_SOURCE_UNAVAILABLE;
}
const ID *new_id = mappings.lookup(id);
if ((options & ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF) != 0 && id_self == new_id) {
new_id = nullptr;
}
if (new_id == nullptr) {
return ID_REMAP_RESULT_SOURCE_UNASSIGNED;
}
return ID_REMAP_RESULT_SOURCE_REMAPPED;
if (options & ID_REMAP_APPLY_UPDATE_REFCOUNT) {
/* Do not handle LIB_TAG_INDIRECT/LIB_TAG_EXTERN here. */
id_us_plus_no_lib(*r_id_ptr);
}
IDRemapperApplyResult apply(ID **r_id_ptr, IDRemapperApplyOptions options, ID *id_self) const
{
BLI_assert(r_id_ptr != nullptr);
if (*r_id_ptr == nullptr) {
return ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE;
}
if (!mappings.contains(*r_id_ptr)) {
return ID_REMAP_RESULT_SOURCE_UNAVAILABLE;
}
if (options & ID_REMAP_APPLY_UPDATE_REFCOUNT) {
id_us_min(*r_id_ptr);
}
*r_id_ptr = mappings.lookup(*r_id_ptr);
if (options & ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF && *r_id_ptr == id_self) {
*r_id_ptr = nullptr;
}
if (*r_id_ptr == nullptr) {
return ID_REMAP_RESULT_SOURCE_UNASSIGNED;
}
if (options & ID_REMAP_APPLY_UPDATE_REFCOUNT) {
/* Do not handle LIB_TAG_INDIRECT/LIB_TAG_EXTERN here. */
id_us_plus_no_lib(*r_id_ptr);
}
if (options & ID_REMAP_APPLY_ENSURE_REAL) {
id_us_ensure_real(*r_id_ptr);
}
return ID_REMAP_RESULT_SOURCE_REMAPPED;
if (options & ID_REMAP_APPLY_ENSURE_REAL) {
id_us_ensure_real(*r_id_ptr);
}
void iter(IDRemapperIterFunction func, void *user_data) const
{
for (auto item : mappings.items()) {
func(item.key, item.value, user_data);
}
}
};
} // namespace blender::bke::id::remapper
/** \brief wrap CPP IDRemapper to a C handle. */
static IDRemapper *wrap(blender::bke::id::remapper::IDRemapper *remapper)
{
return static_cast<IDRemapper *>(static_cast<void *>(remapper));
return ID_REMAP_RESULT_SOURCE_REMAPPED;
}
/** \brief wrap C handle to a CPP IDRemapper. */
static blender::bke::id::remapper::IDRemapper *unwrap(IDRemapper *remapper)
{
return static_cast<blender::bke::id::remapper::IDRemapper *>(static_cast<void *>(remapper));
}
/** \brief wrap C handle to a CPP IDRemapper. */
static const blender::bke::id::remapper::IDRemapper *unwrap(const IDRemapper *remapper)
{
return static_cast<const blender::bke::id::remapper::IDRemapper *>(
static_cast<const void *>(remapper));
}
IDRemapper *BKE_id_remapper_create()
{
blender::bke::id::remapper::IDRemapper *remapper =
MEM_new<blender::bke::id::remapper::IDRemapper>(__func__);
return wrap(remapper);
}
void BKE_id_remapper_free(IDRemapper *id_remapper)
{
blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
MEM_delete<blender::bke::id::remapper::IDRemapper>(remapper);
}
void BKE_id_remapper_clear(IDRemapper *id_remapper)
{
blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
remapper->clear();
}
bool BKE_id_remapper_is_empty(const IDRemapper *id_remapper)
{
const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
return remapper->is_empty();
}
void BKE_id_remapper_add(IDRemapper *id_remapper, ID *old_id, ID *new_id)
{
blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
remapper->add(old_id, new_id);
}
void BKE_id_remapper_add_overwrite(IDRemapper *id_remapper, ID *old_id, ID *new_id)
{
blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
remapper->add_overwrite(old_id, new_id);
}
bool BKE_id_remapper_has_mapping_for(const IDRemapper *id_remapper, uint64_t type_filter)
{
const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
return remapper->contains_mappings_for_any(type_filter);
}
IDRemapperApplyResult BKE_id_remapper_get_mapping_result(const IDRemapper *id_remapper,
ID *id,
IDRemapperApplyOptions options,
const ID *id_self)
{
const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
return remapper->get_mapping_result(id, options, id_self);
}
IDRemapperApplyResult BKE_id_remapper_apply_ex(const IDRemapper *id_remapper,
ID **r_id_ptr,
const IDRemapperApplyOptions options,
ID *id_self)
{
BLI_assert_msg((options & ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF) == 0 ||
id_self != nullptr,
"ID_REMAP_APPLY_WHEN_REMAPPING_TO_SELF requires id_self parameter.");
const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
return remapper->apply(r_id_ptr, options, id_self);
}
IDRemapperApplyResult BKE_id_remapper_apply(const IDRemapper *id_remapper,
ID **r_id_ptr,
const IDRemapperApplyOptions options)
{
BLI_assert_msg((options & ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF) == 0,
"ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF requires id_self parameter. Use "
"`BKE_id_remapper_apply_ex`.");
return BKE_id_remapper_apply_ex(id_remapper, r_id_ptr, options, nullptr);
}
void BKE_id_remapper_iter(const IDRemapper *id_remapper,
IDRemapperIterFunction func,
void *user_data)
{
const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
remapper->iter(func, user_data);
}
const char *BKE_id_remapper_result_string(const IDRemapperApplyResult result)
const blender::StringRefNull IDRemapper::result_to_string(const IDRemapperApplyResult result)
{
switch (result) {
case ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE:
@@ -229,23 +101,22 @@ const char *BKE_id_remapper_result_string(const IDRemapperApplyResult result)
return "unassigned";
case ID_REMAP_RESULT_SOURCE_REMAPPED:
return "remapped";
default:
BLI_assert_unreachable();
}
BLI_assert_unreachable();
return "";
}
static void id_remapper_print_item_cb(ID *old_id, ID *new_id, void * /*user_data*/)
void IDRemapper::print(void) const
{
if (old_id != nullptr && new_id != nullptr) {
printf("Remap %s(%p) to %s(%p)\n", old_id->name, old_id, new_id->name, new_id);
}
if (old_id != nullptr && new_id == nullptr) {
printf("Unassign %s(%p)\n", old_id->name, old_id);
}
auto print_cb = [](ID *old_id, ID *new_id, void * /*user_data*/) {
if (old_id != nullptr && new_id != nullptr) {
printf("Remap %s(%p) to %s(%p)\n", old_id->name, old_id, new_id->name, new_id);
}
if (old_id != nullptr && new_id == nullptr) {
printf("Unassign %s(%p)\n", old_id->name, old_id);
}
};
this->iter(print_cb, nullptr);
}
void BKE_id_remapper_print(const IDRemapper *id_remapper)
{
BKE_id_remapper_iter(id_remapper, id_remapper_print_item_cb, nullptr);
}
} // namespace blender::bke::id
@@ -10,29 +10,27 @@
#include "DNA_ID.h"
namespace blender::bke::id::remapper::tests {
using namespace blender::bke::id;
namespace blender::bke::id::tests {
TEST(lib_id_remapper, unavailable)
{
ID id1;
ID *idp = &id1;
IDRemapper *remapper = BKE_id_remapper_create();
IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
IDRemapper remapper;
IDRemapperApplyResult result = remapper.apply(&idp, ID_REMAP_APPLY_DEFAULT);
EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_UNAVAILABLE);
BKE_id_remapper_free(remapper);
}
TEST(lib_id_remapper, not_mappable)
{
ID *idp = nullptr;
IDRemapper *remapper = BKE_id_remapper_create();
IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
IDRemapper remapper;
IDRemapperApplyResult result = remapper.apply(&idp, ID_REMAP_APPLY_DEFAULT);
EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE);
BKE_id_remapper_free(remapper);
}
TEST(lib_id_remapper, mapped)
@@ -43,13 +41,11 @@ TEST(lib_id_remapper, mapped)
STRNCPY(id1.name, "OB1");
STRNCPY(id2.name, "OB2");
IDRemapper *remapper = BKE_id_remapper_create();
BKE_id_remapper_add(remapper, &id1, &id2);
IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
IDRemapper remapper;
remapper.add(&id1, &id2);
IDRemapperApplyResult result = remapper.apply(&idp, ID_REMAP_APPLY_DEFAULT);
EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_REMAPPED);
EXPECT_EQ(idp, &id2);
BKE_id_remapper_free(remapper);
}
TEST(lib_id_remapper, unassigned)
@@ -58,13 +54,11 @@ TEST(lib_id_remapper, unassigned)
ID *idp = &id1;
STRNCPY(id1.name, "OB2");
IDRemapper *remapper = BKE_id_remapper_create();
BKE_id_remapper_add(remapper, &id1, nullptr);
IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
IDRemapper remapper;
remapper.add(&id1, nullptr);
IDRemapperApplyResult result = remapper.apply(&idp, ID_REMAP_APPLY_DEFAULT);
EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_UNASSIGNED);
EXPECT_EQ(idp, nullptr);
BKE_id_remapper_free(remapper);
}
TEST(lib_id_remapper, unassign_when_mapped_to_self)
@@ -80,31 +74,28 @@ TEST(lib_id_remapper, unassign_when_mapped_to_self)
/* Default mapping behavior. Should just remap to id2. */
idp = &id1;
IDRemapper *remapper = BKE_id_remapper_create();
BKE_id_remapper_add(remapper, &id1, &id2);
IDRemapperApplyResult result = BKE_id_remapper_apply_ex(
remapper, &idp, ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF, &id_self);
IDRemapper remapper;
remapper.add(&id1, &id2);
IDRemapperApplyResult result = remapper.apply(
&idp, ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF, &id_self);
EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_REMAPPED);
EXPECT_EQ(idp, &id2);
/* Default mapping behavior. Should unassign. */
idp = &id1;
BKE_id_remapper_clear(remapper);
BKE_id_remapper_add(remapper, &id1, nullptr);
result = BKE_id_remapper_apply_ex(
remapper, &idp, ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF, &id_self);
remapper.clear();
remapper.add(&id1, nullptr);
result = remapper.apply(&idp, ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF, &id_self);
EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_UNASSIGNED);
EXPECT_EQ(idp, nullptr);
/* Unmap when remapping to self behavior. Should unassign. */
idp = &id1;
BKE_id_remapper_clear(remapper);
BKE_id_remapper_add(remapper, &id1, &id_self);
result = BKE_id_remapper_apply_ex(
remapper, &idp, ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF, &id_self);
remapper.clear();
remapper.add(&id1, &id_self);
result = remapper.apply(&idp, ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF, &id_self);
EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_UNASSIGNED);
EXPECT_EQ(idp, nullptr);
BKE_id_remapper_free(remapper);
}
} // namespace blender::bke::id::remapper::tests
} // namespace blender::bke::id::tests
@@ -72,6 +72,8 @@
# include "BLI_time_utildefines.h"
#endif
using namespace blender::bke;
static CLG_LogRef LOG = {"bke.liboverride"};
static CLG_LogRef LOG_RESYNC = {"bke.liboverride_resync"};
@@ -487,11 +489,11 @@ static void lib_override_prefill_newid_from_existing_overrides(Main *bmain, ID *
FOREACH_MAIN_ID_END;
}
static void lib_override_remapper_overrides_add(IDRemapper *id_remapper,
static void lib_override_remapper_overrides_add(id::IDRemapper &id_remapper,
ID *reference_id,
ID *local_id)
{
BKE_id_remapper_add(id_remapper, reference_id, local_id);
id_remapper.add(reference_id, local_id);
Key *reference_key, *local_key = nullptr;
if ((reference_key = BKE_key_from_id(reference_id)) != nullptr) {
@@ -500,7 +502,7 @@ static void lib_override_remapper_overrides_add(IDRemapper *id_remapper,
BLI_assert(local_key != nullptr);
}
BKE_id_remapper_add(id_remapper, &reference_key->id, &local_key->id);
id_remapper.add(&reference_key->id, &local_key->id);
}
}
@@ -620,7 +622,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
BLI_assert(id_hierarchy_root != nullptr);
blender::Vector<ID *> relinked_ids;
IDRemapper *id_remapper = BKE_id_remapper_create();
id::IDRemapper id_remapper;
/* Still checking the whole Main, that way we can tag other local IDs as needing to be
* remapped to use newly created overriding IDs, if needed. */
ID *id;
@@ -693,7 +695,6 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
id_remapper,
ID_REMAP_SKIP_OVERRIDE_LIBRARY | ID_REMAP_FORCE_USER_REFCOUNT);
BKE_id_remapper_free(id_remapper);
relinked_ids.clear();
}
else {
@@ -1934,7 +1935,7 @@ static void lib_override_library_remap(Main *bmain,
GHash *linkedref_to_old_override)
{
ID *id;
IDRemapper *remapper = BKE_id_remapper_create();
id::IDRemapper remapper;
blender::Vector<ID *> nomain_ids;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
@@ -1944,7 +1945,7 @@ static void lib_override_library_remap(Main *bmain,
if (id_override_old == nullptr) {
continue;
}
BKE_id_remapper_add(remapper, id_override_old, id_override_new);
remapper.add(id_override_old, id_override_new);
}
}
FOREACH_MAIN_ID_END;
@@ -1968,7 +1969,6 @@ static void lib_override_library_remap(Main *bmain,
ID_REMAP_TYPE_REMAP,
remapper,
ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
BKE_id_remapper_free(remapper);
}
/**
@@ -2515,7 +2515,7 @@ static bool lib_override_library_resync(Main *bmain,
/* Once overrides have been properly 'transferred' from old to new ID, we can clear ID usages
* of the old one.
* This is necessary in case said old ID is not in Main anymore. */
IDRemapper *id_remapper = BKE_id_remapper_create();
id::IDRemapper id_remapper;
BKE_libblock_relink_multiple(bmain,
id_override_old_vector,
ID_REMAP_TYPE_CLEANUP,
@@ -2525,7 +2525,6 @@ static bool lib_override_library_resync(Main *bmain,
id_override_old->tag |= LIB_TAG_NO_USER_REFCOUNT;
}
id_override_old_vector.clear();
BKE_id_remapper_free(id_remapper);
/* Delete old override IDs.
* Note that we have to use tagged group deletion here, since ID deletion also uses
+44 -47
View File
@@ -38,6 +38,8 @@
#include "lib_intern.hh" /* own include */
using namespace blender::bke::id;
static CLG_LogRef LOG = {"bke.lib_remap"};
BKE_library_free_notifier_reference_cb free_notifier_reference_cb = nullptr;
@@ -59,7 +61,7 @@ struct IDRemap {
eIDRemapType type;
Main *bmain; /* Only used to trigger depsgraph updates in the right bmain. */
IDRemapper *id_remapper;
IDRemapper &id_remapper;
/** The ID in which we are replacing old_id by new_id usages. */
ID *id_owner;
@@ -103,7 +105,7 @@ static void foreach_libblock_remap_callback_apply(ID *id_owner,
ID *id_self,
ID **id_ptr,
IDRemap *id_remap_data,
const IDRemapper *mappings,
const IDRemapper &mappings,
const IDRemapperApplyOptions id_remapper_options,
const int cb_flag,
const bool is_indirect,
@@ -116,7 +118,7 @@ static void foreach_libblock_remap_callback_apply(ID *id_owner,
ID *old_id = *id_ptr;
if (!violates_never_null) {
BKE_id_remapper_apply_ex(mappings, id_ptr, id_remapper_options, id_self);
mappings.apply(id_ptr, id_remapper_options, id_self);
if (!skip_update_tagging) {
if (id_remap_data->bmain != nullptr) {
DEG_id_tag_update_ex(id_remap_data->bmain,
@@ -195,15 +197,15 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_NOP;
}
IDRemapper *id_remapper = id_remap_data->id_remapper;
IDRemapper &id_remapper = id_remap_data->id_remapper;
IDRemapperApplyOptions id_remapper_options = ID_REMAP_APPLY_DEFAULT;
/* Used to cleanup all IDs used by a specific one. */
if (id_remap_data->type == ID_REMAP_TYPE_CLEANUP) {
/* Clearing existing instance to reduce potential lookup times for IDs referencing many other
* IDs. This makes sure that there will only be a single rule in the id_remapper. */
BKE_id_remapper_clear(id_remapper);
BKE_id_remapper_add(id_remapper, *id_p, nullptr);
id_remapper.clear();
id_remapper.add(*id_p, nullptr);
}
/* Better remap to nullptr than not remapping at all,
@@ -212,8 +214,8 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
id_remapper_options |= ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF;
}
const IDRemapperApplyResult expected_mapping_result = BKE_id_remapper_get_mapping_result(
id_remapper, *id_p, id_remapper_options, id_self);
const IDRemapperApplyResult expected_mapping_result = id_remapper.get_mapping_result(
*id_p, id_remapper_options, id_self);
/* Exit, when no modifications will be done; ensuring id->runtime counters won't changed. */
if (ELEM(expected_mapping_result,
ID_REMAP_RESULT_SOURCE_UNAVAILABLE,
@@ -247,7 +249,7 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
id_owner->lib,
(*id_p)->name,
*id_p,
BKE_id_remapper_result_string(expected_mapping_result),
id_remapper.result_to_string(expected_mapping_result).c_str(),
is_indirect,
skip_indirect,
is_reference,
@@ -292,7 +294,7 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
static void libblock_remap_data_preprocess_ob(Object *ob,
eIDRemapType remap_type,
const IDRemapper *id_remapper)
const IDRemapper &id_remapper)
{
if (ob->type != OB_ARMATURE) {
return;
@@ -303,7 +305,7 @@ static void libblock_remap_data_preprocess_ob(Object *ob,
const bool is_cleanup_type = remap_type == ID_REMAP_TYPE_CLEANUP;
/* Early exit when mapping, but no armature mappings present. */
if (!is_cleanup_type && !BKE_id_remapper_has_mapping_for(id_remapper, FILTER_ID_AR)) {
if (!is_cleanup_type && !id_remapper.contains_mappings_for_any(FILTER_ID_AR)) {
return;
}
@@ -313,8 +315,8 @@ static void libblock_remap_data_preprocess_ob(Object *ob,
* Fortunately, this is just a tag, so we can accept to 'over-tag' a bit for pose recalc,
* and avoid another complex and risky condition nightmare like the one we have in
* foreach_libblock_remap_callback(). */
const IDRemapperApplyResult expected_mapping_result = BKE_id_remapper_get_mapping_result(
id_remapper, static_cast<ID *>(ob->data), ID_REMAP_APPLY_DEFAULT, nullptr);
const IDRemapperApplyResult expected_mapping_result = id_remapper.get_mapping_result(
static_cast<ID *>(ob->data), ID_REMAP_APPLY_DEFAULT, nullptr);
if (is_cleanup_type || expected_mapping_result == ID_REMAP_RESULT_SOURCE_REMAPPED) {
ob->pose->flag |= POSE_RECALC;
/* We need to clear pose bone pointers immediately, some code may access those before
@@ -325,7 +327,7 @@ static void libblock_remap_data_preprocess_ob(Object *ob,
static void libblock_remap_data_preprocess(ID *id_owner,
eIDRemapType remap_type,
const IDRemapper *id_remapper)
const IDRemapper &id_remapper)
{
switch (GS(id_owner->name)) {
case ID_OB: {
@@ -483,9 +485,16 @@ static void libblock_remap_reset_remapping_status_callback(ID *old_id,
* (useful to retrieve info about remapping process).
*/
static void libblock_remap_data(
Main *bmain, ID *id, eIDRemapType remap_type, IDRemapper *id_remapper, const int remap_flags)
Main *bmain, ID *id, eIDRemapType remap_type, IDRemapper &id_remapper, const int remap_flags)
{
IDRemap id_remap_data = {eIDRemapType(0)};
IDRemap id_remap_data = {
/*.type=*/remap_type,
/*.bmain=*/bmain,
/*.id_remapper=*/id_remapper,
/*.id_owner=*/nullptr,
/*.flag=*/remap_flags,
};
const bool include_ui = (remap_flags & ID_REMAP_FORCE_UI_POINTERS) != 0;
const int foreach_id_flags = (((remap_flags & ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS) != 0 ?
IDWALK_DO_INTERNAL_RUNTIME_POINTERS :
@@ -499,13 +508,7 @@ static void libblock_remap_data(
IDWALK_DO_LIBRARY_POINTER :
IDWALK_NOP));
id_remap_data.id_remapper = id_remapper;
id_remap_data.type = remap_type;
id_remap_data.bmain = bmain;
id_remap_data.id_owner = nullptr;
id_remap_data.flag = remap_flags;
BKE_id_remapper_iter(id_remapper, libblock_remap_reset_remapping_status_callback, nullptr);
id_remapper.iter(libblock_remap_reset_remapping_status_callback, nullptr);
if (id) {
#ifdef DEBUG_PRINT
@@ -524,7 +527,7 @@ static void libblock_remap_data(
FOREACH_MAIN_ID_BEGIN (bmain, id_curr) {
const uint64_t can_use_filter_id = BKE_library_id_can_use_filter_id(id_curr, include_ui);
const bool has_mapping = BKE_id_remapper_has_mapping_for(id_remapper, can_use_filter_id);
const bool has_mapping = id_remapper.contains_mappings_for_any(can_use_filter_id);
/* Continue when id_remapper doesn't have any mappings that can be used by id_curr. */
if (!has_mapping) {
@@ -544,7 +547,7 @@ static void libblock_remap_data(
FOREACH_MAIN_ID_END;
}
BKE_id_remapper_iter(id_remapper, libblock_remap_data_update_tags, &id_remap_data);
id_remapper.iter(libblock_remap_data_update_tags, &id_remap_data);
}
struct LibBlockRemapMultipleUserData {
@@ -645,9 +648,9 @@ static void libblock_remap_foreach_idpair_cb(ID *old_id, ID *new_id, void *user_
BKE_libblock_runtime_reset_remapping_status(old_id);
}
void BKE_libblock_remap_multiple_locked(Main *bmain, IDRemapper *mappings, const int remap_flags)
void BKE_libblock_remap_multiple_locked(Main *bmain, IDRemapper &mappings, const int remap_flags)
{
if (BKE_id_remapper_is_empty(mappings)) {
if (mappings.is_empty()) {
/* Early exit nothing to do. */
return;
}
@@ -658,7 +661,7 @@ void BKE_libblock_remap_multiple_locked(Main *bmain, IDRemapper *mappings, const
user_data.bmain = bmain;
user_data.remap_flags = remap_flags;
BKE_id_remapper_iter(mappings, libblock_remap_foreach_idpair_cb, &user_data);
mappings.iter(libblock_remap_foreach_idpair_cb, &user_data);
/* We assume editors do not hold references to their IDs... This is false in some cases
* (Image is especially tricky here),
@@ -671,9 +674,9 @@ void BKE_libblock_remap_multiple_locked(Main *bmain, IDRemapper *mappings, const
DEG_relations_tag_update(bmain);
}
void BKE_libblock_remap_multiple_raw(Main *bmain, IDRemapper *mappings, const int remap_flags)
void BKE_libblock_remap_multiple_raw(Main *bmain, IDRemapper &mappings, const int remap_flags)
{
if (BKE_id_remapper_is_empty(mappings)) {
if (mappings.is_empty()) {
/* Early exit nothing to do. */
return;
}
@@ -687,12 +690,11 @@ void BKE_libblock_remap_multiple_raw(Main *bmain, IDRemapper *mappings, const in
void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const int remap_flags)
{
IDRemapper *remapper = BKE_id_remapper_create();
IDRemapper remapper;
ID *old_id = static_cast<ID *>(old_idv);
ID *new_id = static_cast<ID *>(new_idv);
BKE_id_remapper_add(remapper, old_id, new_id);
remapper.add(old_id, new_id);
BKE_libblock_remap_multiple_locked(bmain, remapper, remap_flags);
BKE_id_remapper_free(remapper);
}
void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const int remap_flags)
@@ -704,7 +706,7 @@ void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const int rem
BKE_main_unlock(bmain);
}
void BKE_libblock_remap_multiple(Main *bmain, IDRemapper *mappings, const int remap_flags)
void BKE_libblock_remap_multiple(Main *bmain, IDRemapper &mappings, const int remap_flags)
{
BKE_main_lock(bmain);
@@ -798,10 +800,10 @@ static void libblock_relink_foreach_idpair_cb(ID *old_id, ID *new_id, void *user
void BKE_libblock_relink_multiple(Main *bmain,
const blender::Span<ID *> ids,
const eIDRemapType remap_type,
IDRemapper *id_remapper,
IDRemapper &id_remapper,
const int remap_flags)
{
BLI_assert(remap_type == ID_REMAP_TYPE_REMAP || BKE_id_remapper_is_empty(id_remapper));
BLI_assert(remap_type == ID_REMAP_TYPE_REMAP || id_remapper.is_empty());
for (ID *id_iter : ids) {
libblock_remap_data(bmain, id_iter, remap_type, id_remapper, remap_flags);
@@ -815,7 +817,7 @@ void BKE_libblock_relink_multiple(Main *bmain,
case ID_REMAP_TYPE_REMAP: {
LibBlockRelinkMultipleUserData user_data = {bmain, ids};
BKE_id_remapper_iter(id_remapper, libblock_relink_foreach_idpair_cb, &user_data);
id_remapper.iter(libblock_relink_foreach_idpair_cb, &user_data);
break;
}
case ID_REMAP_TYPE_CLEANUP: {
@@ -869,7 +871,7 @@ void BKE_libblock_relink_ex(
blender::Array<ID *> ids = {id};
/* No need to lock here, we are only affecting given ID, not bmain database. */
IDRemapper *id_remapper = BKE_id_remapper_create();
IDRemapper id_remapper;
eIDRemapType remap_type = ID_REMAP_TYPE_REMAP;
BLI_assert(id != nullptr);
@@ -877,7 +879,7 @@ void BKE_libblock_relink_ex(
if (old_id != nullptr) {
BLI_assert((new_id == nullptr) || GS(old_id->name) == GS(new_id->name));
BLI_assert(old_id != new_id);
BKE_id_remapper_add(id_remapper, old_id, new_id);
id_remapper.add(old_id, new_id);
}
else {
BLI_assert(new_id == nullptr);
@@ -885,13 +887,11 @@ void BKE_libblock_relink_ex(
}
BKE_libblock_relink_multiple(bmain, ids, remap_type, id_remapper, remap_flags);
BKE_id_remapper_free(id_remapper);
}
struct RelinkToNewIDData {
blender::Vector<ID *> ids;
IDRemapper *id_remapper;
IDRemapper id_remapper;
};
static void libblock_relink_to_newid_prepare_data(Main *bmain,
@@ -908,12 +908,12 @@ static int id_relink_to_newid_looper(LibraryIDLinkCallbackData *cb_data)
Main *bmain = cb_data->bmain;
ID **id_pointer = cb_data->id_pointer;
ID *id = *id_pointer;
RelinkToNewIDData *relink_data = (RelinkToNewIDData *)cb_data->user_data;
RelinkToNewIDData *relink_data = static_cast<RelinkToNewIDData *>(cb_data->user_data);
if (id) {
/* See: NEW_ID macro */
if (id->newid != nullptr) {
BKE_id_remapper_add(relink_data->id_remapper, id, id->newid);
relink_data->id_remapper.add(id, id->newid);
id = id->newid;
}
if (id->tag & LIB_TAG_NEW) {
@@ -945,7 +945,6 @@ void BKE_libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag)
BLI_assert(bmain->relations == nullptr);
RelinkToNewIDData relink_data{};
relink_data.id_remapper = BKE_id_remapper_create();
libblock_relink_to_newid_prepare_data(bmain, id, &relink_data);
@@ -953,6 +952,4 @@ void BKE_libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag)
ID_REMAP_SKIP_OVERRIDE_LIBRARY;
BKE_libblock_relink_multiple(
bmain, relink_data.ids, ID_REMAP_TYPE_REMAP, relink_data.id_remapper, remap_flag_final);
BKE_id_remapper_free(relink_data.id_remapper);
}
+8 -8
View File
@@ -38,6 +38,8 @@
#include "IMB_imbuf.hh"
#include "IMB_imbuf_types.hh"
using namespace blender::bke;
static CLG_LogRef LOG = {"bke.main"};
Main *BKE_main_new()
@@ -258,7 +260,7 @@ static bool are_ids_from_different_mains_matching(Main *bmain_1, ID *id_1, Main
static void main_merge_add_id_to_move(Main *bmain_dst,
blender::Map<std::string, blender::Vector<ID *>> &id_map_dst,
ID *id_src,
IDRemapper *id_remapper,
id::IDRemapper &id_remapper,
blender::Vector<ID *> &ids_to_move,
const bool is_library,
MainMergeReport &reports)
@@ -287,7 +289,7 @@ static void main_merge_add_id_to_move(Main *bmain_dst,
"found in given destination Main",
id_src->name,
bmain_dst->filepath);
BKE_id_remapper_add(id_remapper, id_src, nullptr);
id_remapper.add(id_src, nullptr);
reports.num_unknown_ids++;
}
else {
@@ -321,8 +323,8 @@ void BKE_main_merge(Main *bmain_dst, Main **r_bmain_src, MainMergeReport &report
/* A dedicated remapper for libraries is needed because these need to be remapped _before_ IDs
* are moved from `bmain_src` to `bmain_dst`, to avoid having to fix naming and ordering of IDs
* afterwards (especially in case some source linked IDs become local in `bmain_dst`). */
IDRemapper *id_remapper = BKE_id_remapper_create();
IDRemapper *id_remapper_libraries = BKE_id_remapper_create();
id::IDRemapper id_remapper;
id::IDRemapper id_remapper_libraries;
blender::Vector<ID *> ids_to_move;
FOREACH_MAIN_ID_BEGIN (bmain_src, id_iter_src) {
@@ -347,11 +349,11 @@ void BKE_main_merge(Main *bmain_dst, Main **r_bmain_src, MainMergeReport &report
BLI_assert(!src_has_match_in_dst);
if (!src_has_match_in_dst) {
if (is_library) {
BKE_id_remapper_add(id_remapper_libraries, id_iter_src, id_iter_dst);
id_remapper_libraries.add(id_iter_src, id_iter_dst);
reports.num_remapped_libraries++;
}
else {
BKE_id_remapper_add(id_remapper, id_iter_src, id_iter_dst);
id_remapper.add(id_iter_src, id_iter_dst);
reports.num_remapped_ids++;
}
src_has_match_in_dst = true;
@@ -426,8 +428,6 @@ void BKE_main_merge(Main *bmain_dst, Main **r_bmain_src, MainMergeReport &report
BLI_assert(BKE_main_namemap_validate(bmain_dst));
BKE_id_remapper_free(id_remapper);
BKE_id_remapper_free(id_remapper_libraries);
BKE_main_free(bmain_src);
*r_bmain_src = nullptr;
}
@@ -142,13 +142,14 @@ void BKE_viewer_path_foreach_id(LibraryForeachIDData *data, ViewerPath *viewer_p
}
}
void BKE_viewer_path_id_remap(ViewerPath *viewer_path, const IDRemapper *mappings)
void BKE_viewer_path_id_remap(ViewerPath *viewer_path,
const blender::bke::id::IDRemapper &mappings)
{
LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) {
switch (ViewerPathElemType(elem->type)) {
case VIEWER_PATH_ELEM_TYPE_ID: {
auto *typed_elem = reinterpret_cast<IDViewerPathElem *>(elem);
BKE_id_remapper_apply(mappings, &typed_elem->id, ID_REMAP_APPLY_DEFAULT);
mappings.apply(&typed_elem->id, ID_REMAP_APPLY_DEFAULT);
break;
}
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
+7 -2
View File
@@ -11,10 +11,13 @@
#include "BLI_compiler_attrs.h"
#include "WM_types.hh"
struct IDRemapper;
struct Main;
struct bContext;
namespace blender::bke::id {
class IDRemapper;
}
/* ed_util.cc */
void ED_editors_init_for_undo(Main *bmain);
@@ -42,7 +45,9 @@ bool ED_editors_flush_edits(Main *bmain);
* \param new_id: may be NULL to unlink \a old_id.
*/
void ED_spacedata_id_remap_single(ScrArea *area, SpaceLink *sl, ID *old_id, ID *new_id);
void ED_spacedata_id_remap(ScrArea *area, SpaceLink *sl, const IDRemapper *mappings);
void ED_spacedata_id_remap(ScrArea *area,
SpaceLink *sl,
const blender::bke::id::IDRemapper &mappings);
void ED_operatortypes_edutils();
@@ -783,13 +783,15 @@ static void action_refresh(const bContext *C, ScrArea *area)
/* XXX re-sizing y-extents of tot should go here? */
}
static void action_id_remap(ScrArea * /*area*/, SpaceLink *slink, const IDRemapper *mappings)
static void action_id_remap(ScrArea * /*area*/,
SpaceLink *slink,
const blender::bke::id::IDRemapper &mappings)
{
SpaceAction *sact = (SpaceAction *)slink;
BKE_id_remapper_apply(mappings, (ID **)&sact->action, ID_REMAP_APPLY_DEFAULT);
BKE_id_remapper_apply(mappings, (ID **)&sact->ads.filter_grp, ID_REMAP_APPLY_DEFAULT);
BKE_id_remapper_apply(mappings, &sact->ads.source, ID_REMAP_APPLY_DEFAULT);
mappings.apply((ID **)&sact->action, ID_REMAP_APPLY_DEFAULT);
mappings.apply((ID **)&sact->ads.filter_grp, ID_REMAP_APPLY_DEFAULT);
mappings.apply(&sact->ads.source, ID_REMAP_APPLY_DEFAULT);
}
static void action_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
@@ -854,20 +854,20 @@ static void buttons_area_listener(const wmSpaceTypeListenerParams *params)
}
}
static void buttons_id_remap(ScrArea * /*area*/, SpaceLink *slink, const IDRemapper *mappings)
static void buttons_id_remap(ScrArea * /*area*/,
SpaceLink *slink,
const blender::bke::id::IDRemapper &mappings)
{
SpaceProperties *sbuts = (SpaceProperties *)slink;
if (BKE_id_remapper_apply(mappings, &sbuts->pinid, ID_REMAP_APPLY_DEFAULT) ==
ID_REMAP_RESULT_SOURCE_UNASSIGNED)
{
if (mappings.apply(&sbuts->pinid, ID_REMAP_APPLY_DEFAULT) == ID_REMAP_RESULT_SOURCE_UNASSIGNED) {
sbuts->flag &= ~SB_PIN_CONTEXT;
}
if (sbuts->path) {
ButsContextPath *path = static_cast<ButsContextPath *>(sbuts->path);
for (int i = 0; i < path->len; i++) {
switch (BKE_id_remapper_apply(mappings, &path->ptr[i].owner_id, ID_REMAP_APPLY_DEFAULT)) {
switch (mappings.apply(&path->ptr[i].owner_id, ID_REMAP_APPLY_DEFAULT)) {
case ID_REMAP_RESULT_SOURCE_UNASSIGNED: {
path->len = i;
if (i != 0) {
@@ -901,7 +901,7 @@ static void buttons_id_remap(ScrArea * /*area*/, SpaceLink *slink, const IDRemap
if (sbuts->texuser) {
ButsContextTexture *ct = static_cast<ButsContextTexture *>(sbuts->texuser);
BKE_id_remapper_apply(mappings, (ID **)&ct->texture, ID_REMAP_APPLY_DEFAULT);
mappings.apply((ID **)&ct->texture, ID_REMAP_APPLY_DEFAULT);
BLI_freelistN(&ct->users);
ct->user = nullptr;
}
@@ -1151,16 +1151,18 @@ static void clip_properties_region_listener(const wmRegionListenerParams *params
/** \name IO Callbacks
* \{ */
static void clip_id_remap(ScrArea * /*area*/, SpaceLink *slink, const IDRemapper *mappings)
static void clip_id_remap(ScrArea * /*area*/,
SpaceLink *slink,
const blender::bke::id::IDRemapper &mappings)
{
SpaceClip *sclip = (SpaceClip *)slink;
if (!BKE_id_remapper_has_mapping_for(mappings, FILTER_ID_MC | FILTER_ID_MSK)) {
if (!mappings.contains_mappings_for_any(FILTER_ID_MC | FILTER_ID_MSK)) {
return;
}
BKE_id_remapper_apply(mappings, (ID **)&sclip->clip, ID_REMAP_APPLY_ENSURE_REAL);
BKE_id_remapper_apply(mappings, (ID **)&sclip->mask_info.mask, ID_REMAP_APPLY_ENSURE_REAL);
mappings.apply((ID **)&sclip->clip, ID_REMAP_APPLY_ENSURE_REAL);
mappings.apply((ID **)&sclip->mask_info.mask, ID_REMAP_APPLY_ENSURE_REAL);
}
static void clip_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
@@ -827,7 +827,9 @@ static void file_space_subtype_item_extend(bContext * /*C*/, EnumPropertyItem **
RNA_enum_items_add(item, totitem, rna_enum_space_file_browse_mode_items);
}
static void file_id_remap(ScrArea *area, SpaceLink *sl, const IDRemapper * /*mappings*/)
static void file_id_remap(ScrArea *area,
SpaceLink *sl,
const blender::bke::id::IDRemapper & /*mappings*/)
{
SpaceFile *sfile = (SpaceFile *)sl;
@@ -796,15 +796,17 @@ static void graph_refresh(const bContext *C, ScrArea *area)
graph_refresh_fcurve_colors(C);
}
static void graph_id_remap(ScrArea * /*area*/, SpaceLink *slink, const IDRemapper *mappings)
static void graph_id_remap(ScrArea * /*area*/,
SpaceLink *slink,
const blender::bke::id::IDRemapper &mappings)
{
SpaceGraph *sgraph = (SpaceGraph *)slink;
if (!sgraph->ads) {
return;
}
BKE_id_remapper_apply(mappings, (ID **)&sgraph->ads->filter_grp, ID_REMAP_APPLY_DEFAULT);
BKE_id_remapper_apply(mappings, (ID **)&sgraph->ads->source, ID_REMAP_APPLY_DEFAULT);
mappings.apply((ID **)&sgraph->ads->filter_grp, ID_REMAP_APPLY_DEFAULT);
mappings.apply((ID **)&sgraph->ads->source, ID_REMAP_APPLY_DEFAULT);
}
static void graph_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
@@ -1006,19 +1006,19 @@ static void image_header_region_listener(const wmRegionListenerParams *params)
}
}
static void image_id_remap(ScrArea * /*area*/, SpaceLink *slink, const IDRemapper *mappings)
static void image_id_remap(ScrArea * /*area*/,
SpaceLink *slink,
const blender::bke::id::IDRemapper &mappings)
{
SpaceImage *simg = (SpaceImage *)slink;
if (!BKE_id_remapper_has_mapping_for(mappings,
FILTER_ID_IM | FILTER_ID_GD_LEGACY | FILTER_ID_MSK))
{
if (!mappings.contains_mappings_for_any(FILTER_ID_IM | FILTER_ID_GD_LEGACY | FILTER_ID_MSK)) {
return;
}
BKE_id_remapper_apply(mappings, (ID **)&simg->image, ID_REMAP_APPLY_ENSURE_REAL);
BKE_id_remapper_apply(mappings, (ID **)&simg->gpd, ID_REMAP_APPLY_UPDATE_REFCOUNT);
BKE_id_remapper_apply(mappings, (ID **)&simg->mask_info.mask, ID_REMAP_APPLY_ENSURE_REAL);
mappings.apply((ID **)&simg->image, ID_REMAP_APPLY_ENSURE_REAL);
mappings.apply((ID **)&simg->gpd, ID_REMAP_APPLY_UPDATE_REFCOUNT);
mappings.apply((ID **)&simg->mask_info.mask, ID_REMAP_APPLY_ENSURE_REAL);
}
static void image_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
@@ -554,17 +554,18 @@ static void nla_listener(const wmSpaceTypeListenerParams *params)
}
}
static void nla_id_remap(ScrArea * /*area*/, SpaceLink *slink, const IDRemapper *mappings)
static void nla_id_remap(ScrArea * /*area*/,
SpaceLink *slink,
const blender::bke::id::IDRemapper &mappings)
{
SpaceNla *snla = reinterpret_cast<SpaceNla *>(slink);
if (snla->ads == nullptr) {
return;
}
BKE_id_remapper_apply(
mappings, reinterpret_cast<ID **>(&snla->ads->filter_grp), ID_REMAP_APPLY_DEFAULT);
BKE_id_remapper_apply(
mappings, reinterpret_cast<ID **>(&snla->ads->source), ID_REMAP_APPLY_DEFAULT);
mappings.apply(reinterpret_cast<ID **>(&snla->ads->filter_grp), ID_REMAP_APPLY_DEFAULT);
mappings.apply(reinterpret_cast<ID **>(&snla->ads->source), ID_REMAP_APPLY_DEFAULT);
}
static void nla_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
@@ -1223,7 +1223,9 @@ static void node_id_remap_cb(ID *old_id, ID *new_id, void *user_data)
}
}
static void node_id_remap(ScrArea * /*area*/, SpaceLink *slink, const IDRemapper *mappings)
static void node_id_remap(ScrArea * /*area*/,
SpaceLink *slink,
const blender::bke::id::IDRemapper &mappings)
{
/* Although we should be able to perform all the mappings in a single go this lead to issues when
* running the python test cases. Somehow the nodetree/edittree weren't updated to the new
@@ -1236,7 +1238,7 @@ static void node_id_remap(ScrArea * /*area*/, SpaceLink *slink, const IDRemapper
* We could also move a remap address at a time to use the IDRemapper as that should get closer
* to cleaner code. See {D13615} for more information about this topic.
*/
BKE_id_remapper_iter(mappings, node_id_remap_cb, slink);
mappings.iter(node_id_remap_cb, slink);
}
static void node_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
@@ -410,7 +410,9 @@ static SpaceLink *outliner_duplicate(SpaceLink *sl)
return (SpaceLink *)space_outliner_new;
}
static void outliner_id_remap(ScrArea *area, SpaceLink *slink, const IDRemapper *mappings)
static void outliner_id_remap(ScrArea *area,
SpaceLink *slink,
const blender::bke::id::IDRemapper &mappings)
{
SpaceOutliner *space_outliner = (SpaceOutliner *)slink;
@@ -425,7 +427,7 @@ static void outliner_id_remap(ScrArea *area, SpaceLink *slink, const IDRemapper
BLI_mempool_iternew(space_outliner->treestore, &iter);
while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
switch (BKE_id_remapper_apply(mappings, &tselem->id, ID_REMAP_APPLY_DEFAULT)) {
switch (mappings.apply(&tselem->id, ID_REMAP_APPLY_DEFAULT)) {
case ID_REMAP_RESULT_SOURCE_REMAPPED:
changed = true;
break;
@@ -66,7 +66,8 @@
static int gather_strip_data_ids_to_null(LibraryIDLinkCallbackData *cb_data)
{
IDRemapper *id_remapper = static_cast<IDRemapper *>(cb_data->user_data);
blender::bke::id::IDRemapper &id_remapper = *static_cast<blender::bke::id::IDRemapper *>(
cb_data->user_data);
ID *id = *cb_data->id_pointer;
/* We don't care about embedded, loop-back, or internal IDs. */
@@ -82,7 +83,7 @@ static int gather_strip_data_ids_to_null(LibraryIDLinkCallbackData *cb_data)
/* Nullify everything that is not:
* #bSound, #MovieClip, #Image, #Text, #VFont, #bAction, or #Collection IDs. */
if (!ELEM(id_type, ID_SO, ID_MC, ID_IM, ID_TXT, ID_VF, ID_AC)) {
BKE_id_remapper_add(id_remapper, id, nullptr);
id_remapper.add(id, nullptr);
return IDWALK_RET_STOP_RECURSION;
}
}
@@ -183,12 +184,11 @@ static bool sequencer_write_copy_paste_file(Main *bmain_src,
* to copy whole scenes. We have to come up with a proper idea of how to copy and
* paste scene strips.
*/
IDRemapper *id_remapper = BKE_id_remapper_create();
blender::bke::id::IDRemapper id_remapper;
BKE_library_foreach_ID_link(
bmain_src, &scene_dst->id, gather_strip_data_ids_to_null, id_remapper, IDWALK_RECURSE);
bmain_src, &scene_dst->id, gather_strip_data_ids_to_null, &id_remapper, IDWALK_RECURSE);
BKE_libblock_remap_multiple(bmain_src, id_remapper, 0);
BKE_id_remapper_free(id_remapper);
/* Ensure that there are no old copy tags around */
BKE_blendfile_write_partial_begin(bmain_src);
@@ -906,10 +906,12 @@ static void sequencer_buttons_region_listener(const wmRegionListenerParams *para
}
}
static void sequencer_id_remap(ScrArea * /*area*/, SpaceLink *slink, const IDRemapper *mappings)
static void sequencer_id_remap(ScrArea * /*area*/,
SpaceLink *slink,
const blender::bke::id::IDRemapper &mappings)
{
SpaceSeq *sseq = (SpaceSeq *)slink;
BKE_id_remapper_apply(mappings, (ID **)&sseq->gpd, ID_REMAP_APPLY_DEFAULT);
mappings.apply((ID **)&sseq->gpd, ID_REMAP_APPLY_DEFAULT);
}
static void sequencer_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
@@ -152,7 +152,9 @@ static void spreadsheet_keymap(wmKeyConfig *keyconf)
WM_keymap_ensure(keyconf, "Spreadsheet Generic", SPACE_SPREADSHEET, RGN_TYPE_WINDOW);
}
static void spreadsheet_id_remap(ScrArea * /*area*/, SpaceLink *slink, const IDRemapper *mappings)
static void spreadsheet_id_remap(ScrArea * /*area*/,
SpaceLink *slink,
const blender::bke::id::IDRemapper &mappings)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)slink;
BKE_viewer_path_id_remap(&sspreadsheet->viewer_path, mappings);
@@ -376,10 +376,12 @@ static void text_properties_region_draw(const bContext *C, ARegion *region)
ED_region_panels(C, region);
}
static void text_id_remap(ScrArea * /*area*/, SpaceLink *slink, const IDRemapper *mappings)
static void text_id_remap(ScrArea * /*area*/,
SpaceLink *slink,
const blender::bke::id::IDRemapper &mappings)
{
SpaceText *stext = (SpaceText *)slink;
BKE_id_remapper_apply(mappings, (ID **)&stext->text, ID_REMAP_APPLY_ENSURE_REAL);
mappings.apply((ID **)&stext->text, ID_REMAP_APPLY_ENSURE_REAL);
}
static void text_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
@@ -1991,9 +1991,10 @@ static void space_view3d_refresh(const bContext *C, ScrArea *area)
MEM_SAFE_FREE(v3d->runtime.local_stats);
}
static void view3d_id_remap_v3d_ob_centers(View3D *v3d, const IDRemapper *mappings)
static void view3d_id_remap_v3d_ob_centers(View3D *v3d,
const blender::bke::id::IDRemapper &mappings)
{
if (BKE_id_remapper_apply(mappings, (ID **)&v3d->ob_center, ID_REMAP_APPLY_DEFAULT) ==
if (mappings.apply((ID **)&v3d->ob_center, ID_REMAP_APPLY_DEFAULT) ==
ID_REMAP_RESULT_SOURCE_UNASSIGNED)
{
/* Otherwise, bone-name may remain valid...
@@ -2002,10 +2003,13 @@ static void view3d_id_remap_v3d_ob_centers(View3D *v3d, const IDRemapper *mappin
}
}
static void view3d_id_remap_v3d(
ScrArea *area, SpaceLink *slink, View3D *v3d, const IDRemapper *mappings, const bool is_local)
static void view3d_id_remap_v3d(ScrArea *area,
SpaceLink *slink,
View3D *v3d,
const blender::bke::id::IDRemapper &mappings,
const bool is_local)
{
if (BKE_id_remapper_apply(mappings, (ID **)&v3d->camera, ID_REMAP_APPLY_DEFAULT) ==
if (mappings.apply((ID **)&v3d->camera, ID_REMAP_APPLY_DEFAULT) ==
ID_REMAP_RESULT_SOURCE_UNASSIGNED)
{
/* 3D view might be inactive, in that case needs to use slink->regionbase */
@@ -2023,11 +2027,13 @@ static void view3d_id_remap_v3d(
}
}
static void view3d_id_remap(ScrArea *area, SpaceLink *slink, const IDRemapper *mappings)
static void view3d_id_remap(ScrArea *area,
SpaceLink *slink,
const blender::bke::id::IDRemapper &mappings)
{
if (!BKE_id_remapper_has_mapping_for(mappings,
FILTER_ID_OB | FILTER_ID_MA | FILTER_ID_IM | FILTER_ID_MC))
if (!mappings.contains_mappings_for_any(FILTER_ID_OB | FILTER_ID_MA | FILTER_ID_IM |
FILTER_ID_MC))
{
return;
}
+5 -4
View File
@@ -464,7 +464,9 @@ void unpack_menu(bContext *C,
UI_popup_menu_end(C, pup);
}
void ED_spacedata_id_remap(ScrArea *area, SpaceLink *sl, const IDRemapper *mappings)
void ED_spacedata_id_remap(ScrArea *area,
SpaceLink *sl,
const blender::bke::id::IDRemapper &mappings)
{
SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
if (st && st->id_remap) {
@@ -477,9 +479,8 @@ void ED_spacedata_id_remap_single(ScrArea *area, SpaceLink *sl, ID *old_id, ID *
SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
if (st && st->id_remap) {
IDRemapper *mappings = BKE_id_remapper_create();
BKE_id_remapper_add(mappings, old_id, new_id);
blender::bke::id::IDRemapper mappings;
mappings.add(old_id, new_id);
st->id_remap(area, sl, mappings);
BKE_id_remapper_free(mappings);
}
}
+5 -2
View File
@@ -28,7 +28,6 @@ struct GHashIterator;
struct GPUViewport;
struct ID;
struct IDProperty;
struct IDRemapper;
struct ImBuf;
struct ImageFormatData;
struct Main;
@@ -71,6 +70,10 @@ struct wmXrRuntimeData;
struct wmXrSessionState;
#endif
namespace blender::bke::id {
class IDRemapper;
}
namespace blender::asset_system {
class AssetRepresentation;
}
@@ -585,7 +588,7 @@ void WM_main_add_notifier(unsigned int type, void *reference);
* Clear notifiers by reference, Used so listeners don't act on freed data.
*/
void WM_main_remove_notifier_reference(const void *reference);
void WM_main_remap_editor_id_reference(const IDRemapper *mappings);
void WM_main_remap_editor_id_reference(const blender::bke::id::IDRemapper &mappings);
/* reports */
/**
@@ -412,7 +412,7 @@ static void wm_main_remap_msgbus_notify(ID *old_id, ID *new_id, void *user_data)
}
}
void WM_main_remap_editor_id_reference(const IDRemapper *mappings)
void WM_main_remap_editor_id_reference(const blender::bke::id::IDRemapper &mappings)
{
Main *bmain = G_MAIN;
@@ -424,11 +424,11 @@ void WM_main_remap_editor_id_reference(const IDRemapper *mappings)
}
}
BKE_id_remapper_iter(mappings, wm_main_remap_assetlist, nullptr);
mappings.iter(wm_main_remap_assetlist, nullptr);
wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
if (wm && wm->message_bus) {
BKE_id_remapper_iter(mappings, wm_main_remap_msgbus_notify, wm->message_bus);
mappings.iter(wm_main_remap_msgbus_notify, wm->message_bus);
}
AS_asset_library_remap_ids(mappings);