diff --git a/source/blender/blenkernel/intern/blendfile_link_append.cc b/source/blender/blenkernel/intern/blendfile_link_append.cc index fcc46aea7a1..3b421b2ec9a 100644 --- a/source/blender/blenkernel/intern/blendfile_link_append.cc +++ b/source/blender/blenkernel/intern/blendfile_link_append.cc @@ -1701,12 +1701,12 @@ void BKE_blendfile_override(BlendfileLinkAppendContext *lapp_context, /** \name Library relocating code. * \{ */ -static void blendfile_library_relocate_id_remap_do(Main *bmain, - ID *old_id, - ID *new_id, - ReportList *reports, - const bool do_reload, - const int remap_flags) +static void blendfile_library_relocate_id_remap_prepare( + id::IDRemapper &remapper, + blender::Map &old_owner_id_to_shapekey, + ID *old_id, + ID *new_id, + const bool do_reload) { BLI_assert(old_id); if (do_reload) { @@ -1720,29 +1720,69 @@ static void blendfile_library_relocate_id_remap_do(Main *bmain, old_id->name, old_id->us, new_id->us); - BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags); + remapper.add(old_id, new_id); + } - if (old_id->flag & ID_FLAG_FAKEUSER) { - id_fake_user_clear(old_id); - id_fake_user_set(new_id); - } + /* Usual special code for ShapeKeys snowflakes... + * + * NOTE: Unfortunately, actual reasons for why the old shapekeys needs to be removed from their + * old owner ID was not documented in the initial commit. Suspect it's related to the fact that + * the old ID should not end up using the new shapekeys? */ + Key **old_key_p = BKE_key_from_id_p(old_id); + if (old_key_p == nullptr) { + return; + } + Key *old_key = *old_key_p; + Key *new_key = BKE_key_from_id(new_id); + if (old_key != nullptr) { + old_owner_id_to_shapekey.add(old_id, &old_key->id); + *old_key_p = nullptr; + id_us_min(&old_key->id); + remapper.add(&old_key->id, &new_key->id); + } +} - CLOG_DEBUG(&LOG, - "After remap of %s, old_id users: %d, new_id users: %d", - old_id->name, - old_id->us, - new_id->us); - - /* In some cases, new_id might become direct link, remove parent of library in this case. */ - if (new_id->lib->runtime->parent && (new_id->tag & ID_TAG_INDIRECT) == 0) { - if (do_reload) { - BLI_assert_unreachable(); /* Should not happen in 'pure' reload case... */ - } - new_id->lib->runtime->parent = nullptr; +static void blendfile_library_relocate_id_remap_finalize( + Main *bmain, + blender::Map &old_owner_id_to_shapekey, + ID *old_id, + ID *new_id, + ReportList *reports, + const bool do_reload) +{ + /* Restore old shapekey pointer in old id (see also + * #blendfile_library_relocate_id_remap_prepare above). */ + Key **old_key_p = BKE_key_from_id_p(old_id); + if (old_key_p) { + Key *old_key = reinterpret_cast( + old_owner_id_to_shapekey.lookup_default_as(old_id, nullptr)); + if (old_key) { + BLI_assert(GS(old_key->id.name) == ID_KE); + *old_key_p = old_key; + id_us_plus_no_lib(&old_key->id); } } - if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) { + if (old_id->flag & ID_FLAG_FAKEUSER) { + id_fake_user_clear(old_id); + id_fake_user_set(new_id); + } + + CLOG_DEBUG(&LOG, + "After remap of %s, old_id users: %d, new_id users: %d", + old_id->name, + old_id->us, + new_id->us); + + /* In some cases, new_id might become direct link, remove parent of library in this case. */ + if (new_id->lib->runtime->parent && (new_id->tag & ID_TAG_INDIRECT) == 0) { + if (do_reload) { + BLI_assert_unreachable(); /* Should not happen in 'pure' reload case... */ + } + new_id->lib->runtime->parent = nullptr; + } + + if (old_id->us > 0 && old_id->lib == new_id->lib) { /* Note that this *should* not happen - but better be safe than sorry in this area, * at least until we are 100% sure this cannot ever happen. * Also, we can safely assume names were unique so far, @@ -1785,31 +1825,36 @@ static void blendfile_library_relocate_id_remap_do(Main *bmain, } } -static void blendfile_library_relocate_id_remap(Main *bmain, - ID *old_id, - ID *new_id, +static void blendfile_library_relocate_id_remap(BlendfileLinkAppendContext &lapp_context, ReportList *reports, const bool do_reload, const int remap_flags) { - blendfile_library_relocate_id_remap_do(bmain, old_id, new_id, reports, do_reload, remap_flags); - if (new_id == nullptr) { - return; + Main *bmain = lapp_context.params->bmain; + + id::IDRemapper remapper; + blender::Map old_owner_id_to_shapekey; + + for (BlendfileLinkAppendContextItem &item : lapp_context.items) { + ID *old_id = static_cast(item.userdata); + if (!old_id) { + continue; + } + ID *new_id = item.new_id; + blendfile_library_relocate_id_remap_prepare( + remapper, old_owner_id_to_shapekey, old_id, new_id, do_reload); } - /* Usual special code for ShapeKeys snowflakes... */ - Key **old_key_p = BKE_key_from_id_p(old_id); - if (old_key_p == nullptr) { - return; - } - Key *old_key = *old_key_p; - Key *new_key = BKE_key_from_id(new_id); - if (old_key != nullptr) { - *old_key_p = nullptr; - id_us_min(&old_key->id); - blendfile_library_relocate_id_remap_do( - bmain, &old_key->id, &new_key->id, reports, do_reload, remap_flags); - *old_key_p = old_key; - id_us_plus_no_lib(&old_key->id); + + BKE_libblock_remap_multiple_locked(bmain, remapper, remap_flags); + + for (BlendfileLinkAppendContextItem &item : lapp_context.items) { + ID *old_id = static_cast(item.userdata); + if (!old_id) { + continue; + } + ID *new_id = item.new_id; + blendfile_library_relocate_id_remap_finalize( + bmain, old_owner_id_to_shapekey, old_id, new_id, reports, do_reload); } } @@ -2040,18 +2085,21 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context, * new data. */ blender::Map new_to_old_libraries_map; - BKE_layer_collection_resync_forbid(); - /* Note that in reload case, we also want to replace indirect usages. */ - const int remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | - (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE); for (BlendfileLinkAppendContextItem &item : lapp_context->items) { ID *old_id = static_cast(item.userdata); ID *new_id = item.new_id; if (new_id) { new_to_old_libraries_map.add(new_id->lib, old_id->lib); } - blendfile_library_relocate_id_remap(bmain, old_id, new_id, reports, do_reload, remap_flags); } + + BKE_layer_collection_resync_forbid(); + + /* Note that in reload case, we also want to replace indirect usages. */ + const int remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | + (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE); + blendfile_library_relocate_id_remap(*lapp_context, reports, do_reload, remap_flags); + BKE_layer_collection_resync_allow(); BKE_main_collection_sync_remap(bmain); @@ -2117,7 +2165,7 @@ void BKE_blendfile_id_relocate(BlendfileLinkAppendContext &lapp_context, ReportL /* Do not affect indirect usages. */ const int remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | ID_REMAP_SKIP_INDIRECT_USAGE; - blendfile_library_relocate_id_remap(bmain, old_id, new_id, reports, false, remap_flags); + blendfile_library_relocate_id_remap(lapp_context, reports, false, remap_flags); BKE_layer_collection_resync_allow(); BKE_main_collection_sync_remap(bmain);