diff options
Diffstat (limited to 'source/blender/blenkernel/intern/lib_id_delete.c')
-rw-r--r-- | source/blender/blenkernel/intern/lib_id_delete.c | 72 |
1 files changed, 42 insertions, 30 deletions
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c index f4f5ca7a1d7..c7643c56212 100644 --- a/source/blender/blenkernel/intern/lib_id_delete.c +++ b/source/blender/blenkernel/intern/lib_id_delete.c @@ -16,6 +16,7 @@ #include "BLI_utildefines.h" +#include "BLI_linklist.h" #include "BLI_listbase.h" #include "BKE_anim_data.h" @@ -23,10 +24,10 @@ #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_key.h" +#include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_lib_override.h" #include "BKE_lib_remap.h" -#include "BKE_library.h" #include "BKE_main.h" #include "BKE_main_namemap.h" @@ -202,7 +203,6 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) { const int tag = LIB_TAG_DOIT; ListBase *lbarray[INDEX_ID_MAX]; - Link dummy_link = {0}; int base_count, i; /* Used by batch tagged deletion, when we call BKE_id_free then, id is no more in Main database, @@ -217,6 +217,9 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) BKE_main_lock(bmain); if (do_tagged_deletion) { + struct IDRemapper *id_remapper = BKE_id_remapper_create(); + BKE_layer_collection_resync_forbid(); + /* Main idea of batch deletion is to remove all IDs to be deleted from Main database. * This means that we won't have to loop over all deleted IDs to remove usages * of other deleted IDs. @@ -227,7 +230,6 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) bool keep_looping = true; while (keep_looping) { ID *id, *id_next; - ID *last_remapped_id = tagged_deleted_ids.last; keep_looping = false; /* First tag and remove from Main all datablocks directly from target lib. @@ -243,6 +245,7 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) 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, NULL); /* 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). */ @@ -251,33 +254,38 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) } } } - if (last_remapped_id == NULL) { - dummy_link.next = tagged_deleted_ids.first; - last_remapped_id = (ID *)(&dummy_link); - } - for (id = last_remapped_id->next; id; id = id->next) { - /* Will tag 'never NULL' users of this ID too. - * - * NOTE: #BKE_libblock_unlink() cannot be used here, since it would ignore indirect - * links, this can lead to nasty crashing here in second, actual deleting loop. - * 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_locked(bmain, - id, - NULL, - (ID_REMAP_FLAG_NEVER_NULL_USAGE | - ID_REMAP_FORCE_NEVER_NULL_USAGE | - ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS)); - /* Since we removed ID from Main, - * we also need to unlink its own other IDs usages ourself. */ - BKE_libblock_relink_ex( - bmain, - id, - NULL, - NULL, - (ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS | ID_REMAP_SKIP_USER_CLEAR)); - } + + /* Will tag 'never NULL' users of this ID too. + * + * NOTE: #BKE_libblock_unlink() cannot be used here, since it would ignore indirect + * links, this can lead to nasty crashing here in second, actual deleting loop. + * 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, + ID_REMAP_FLAG_NEVER_NULL_USAGE | + ID_REMAP_FORCE_NEVER_NULL_USAGE | + ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS); + BKE_id_remapper_clear(id_remapper); + } + + /* Since we removed IDs from Main, their own other IDs usages need to be removed 'manually'. */ + LinkNode *cleanup_ids = NULL; + for (ID *id = tagged_deleted_ids.first; id; id = id->next) { + BLI_linklist_prepend(&cleanup_ids, id); } + BKE_libblock_relink_multiple(bmain, + cleanup_ids, + ID_REMAP_TYPE_CLEANUP, + id_remapper, + ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS | + ID_REMAP_SKIP_USER_CLEAR); + + BKE_id_remapper_free(id_remapper); + BLI_linklist_free(cleanup_ids, NULL); + + BKE_layer_collection_resync_allow(); + BKE_main_collection_sync_remap(bmain); /* Now we can safely mark that ID as not being in Main database anymore. */ /* NOTE: This needs to be done in a separate loop than above, otherwise some user-counts of @@ -285,10 +293,14 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) * is never affected). */ for (ID *id = tagged_deleted_ids.first; id; id = id->next) { id->tag |= LIB_TAG_NO_MAIN; + /* User-count needs to be reset artificially, since some usages may not be cleared in batch + * deletion (typically, if one deleted ID uses another deleted ID, this may not be cleared by + * remapping code, depending on order in which these are handled). */ + id->us = ID_FAKE_USERS(id); } } else { - /* First tag all datablocks directly from target lib. + /* First tag all data-blocks directly from target lib. * 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. */ |