Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/lib_override.c
| Show First 20 Lines • Show All 410 Lines • ▼ Show 20 Lines | if (success) { | ||||
| } | } | ||||
| else if (id_root_reference->newid != NULL && | else if (id_root_reference->newid != NULL && | ||||
| (id_hierarchy_root == NULL || | (id_hierarchy_root == NULL || | ||||
| id_hierarchy_root->override_library->reference == id_root_reference)) { | id_hierarchy_root->override_library->reference == id_root_reference)) { | ||||
| id_hierarchy_root = id_root_reference->newid; | id_hierarchy_root = id_root_reference->newid; | ||||
| } | } | ||||
| BLI_assert(id_hierarchy_root != NULL); | BLI_assert(id_hierarchy_root != NULL); | ||||
| for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) { | LinkNode *relinked_ids = NULL; | ||||
| reference_id = todo_id_iter->data; | |||||
| ID *local_id = reference_id->newid; | |||||
| if (local_id == NULL) { | |||||
| continue; | |||||
| } | |||||
| local_id->override_library->hierarchy_root = id_hierarchy_root; | |||||
| Key *reference_key, *local_key = NULL; | |||||
| if ((reference_key = BKE_key_from_id(reference_id)) != NULL) { | |||||
| local_key = BKE_key_from_id(reference_id->newid); | |||||
| BLI_assert(local_key != NULL); | |||||
| } | |||||
| /* Still checking the whole Main, that way we can tag other local IDs as needing to be | /* 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. */ | * remapped to use newly created overriding IDs, if needed. */ | ||||
| ID *id; | ID *id; | ||||
| FOREACH_MAIN_ID_BEGIN (bmain, id) { | FOREACH_MAIN_ID_BEGIN (bmain, id) { | ||||
| ID *other_id; | ID *other_id; | ||||
| /* In case we created new overrides as 'no main', they are not accessible directly in this | /* In case we created new overrides as 'no main', they are not accessible directly in this | ||||
| * loop, but we can get to them through their reference's `newid` pointer. */ | * loop, but we can get to them through their reference's `newid` pointer. */ | ||||
| if (do_no_main && id->lib == reference_id->lib && id->newid != NULL) { | if (do_no_main && id->lib == id_root_reference->lib && id->newid != NULL) { | ||||
| other_id = id->newid; | other_id = id->newid; | ||||
| /* Otherwise we cannot properly distinguish between IDs that are actually from the | /* Otherwise we cannot properly distinguish between IDs that are actually from the | ||||
| * linked library (and should not be remapped), and IDs that are overrides re-generated | * linked library (and should not be remapped), and IDs that are overrides re-generated | ||||
| * from the reference from the linked library, and must therefore be remapped. | * from the reference from the linked library, and must therefore be remapped. | ||||
| * | * | ||||
| * This is reset afterwards at the end of this loop. */ | * This is reset afterwards at the end of this loop. */ | ||||
| other_id->lib = NULL; | other_id->lib = NULL; | ||||
| } | } | ||||
| else { | else { | ||||
| other_id = id; | other_id = id; | ||||
| } | } | ||||
| /* If other ID is a linked one, but not from the same library as our reference, then we | /* If other ID is a linked one, but not from the same library as our reference, then we | ||||
| * consider we should also remap it, as part of recursive resync. */ | * consider we should also relink it, as part of recursive resync. */ | ||||
| if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib != reference_id->lib && | if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib != id_root_reference->lib) { | ||||
| other_id != local_id) { | BLI_linklist_prepend(&relinked_ids, other_id); | ||||
| BKE_libblock_relink_ex(bmain, | |||||
| other_id, | |||||
| reference_id, | |||||
| local_id, | |||||
| ID_REMAP_SKIP_OVERRIDE_LIBRARY | ID_REMAP_FORCE_USER_REFCOUNT); | |||||
| if (reference_key != NULL) { | |||||
| BKE_libblock_relink_ex(bmain, | |||||
| other_id, | |||||
| &reference_key->id, | |||||
| &local_key->id, | |||||
| ID_REMAP_SKIP_OVERRIDE_LIBRARY | ID_REMAP_FORCE_USER_REFCOUNT); | |||||
| } | |||||
| } | } | ||||
| if (other_id != id) { | if (other_id != id) { | ||||
| other_id->lib = reference_id->lib; | other_id->lib = id_root_reference->lib; | ||||
| } | } | ||||
| } | } | ||||
| FOREACH_MAIN_ID_END; | FOREACH_MAIN_ID_END; | ||||
| struct IDRemapper *id_remapper = BKE_id_remapper_create(); | |||||
| for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) { | |||||
| reference_id = todo_id_iter->data; | |||||
| ID *local_id = reference_id->newid; | |||||
| if (local_id == NULL) { | |||||
| continue; | |||||
| } | |||||
| local_id->override_library->hierarchy_root = id_hierarchy_root; | |||||
| BKE_id_remapper_add(id_remapper, reference_id, local_id); | |||||
| Key *reference_key, *local_key = NULL; | |||||
| if ((reference_key = BKE_key_from_id(reference_id)) != NULL) { | |||||
| local_key = BKE_key_from_id(reference_id->newid); | |||||
| BLI_assert(local_key != NULL); | |||||
| BKE_id_remapper_add(id_remapper, &reference_key->id, &local_key->id); | |||||
| } | } | ||||
| } | } | ||||
| BKE_libblock_relink_multiple(bmain, | |||||
| relinked_ids, | |||||
| ID_REMAP_TYPE_REMAP, | |||||
| id_remapper, | |||||
| ID_REMAP_SKIP_OVERRIDE_LIBRARY | ID_REMAP_FORCE_USER_REFCOUNT); | |||||
| BKE_id_remapper_free(id_remapper); | |||||
| BLI_linklist_free(relinked_ids, NULL); | |||||
| } | |||||
| else { | else { | ||||
| /* We need to cleanup potentially already created data. */ | /* We need to cleanup potentially already created data. */ | ||||
| for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) { | for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) { | ||||
| reference_id = todo_id_iter->data; | reference_id = todo_id_iter->data; | ||||
| BKE_id_delete(bmain, reference_id->newid); | BKE_id_delete(bmain, reference_id->newid); | ||||
| reference_id->newid = NULL; | reference_id->newid = NULL; | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 860 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| static void lib_override_library_remap(Main *bmain, | static void lib_override_library_remap(Main *bmain, | ||||
| const ID *id_root_reference, | const ID *id_root_reference, | ||||
| GHash *linkedref_to_old_override) | GHash *linkedref_to_old_override) | ||||
| { | { | ||||
| ID *id; | ID *id; | ||||
| struct IDRemapper *remapper = BKE_id_remapper_create(); | struct IDRemapper *remapper = BKE_id_remapper_create(); | ||||
| FOREACH_MAIN_ID_BEGIN (bmain, id) { | LinkNode *nomain_ids = NULL; | ||||
| FOREACH_MAIN_ID_BEGIN (bmain, id) { | |||||
| if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) { | if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) { | ||||
| ID *id_override_new = id->newid; | ID *id_override_new = id->newid; | ||||
| ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id); | ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id); | ||||
| if (id_override_old == NULL) { | if (id_override_old == NULL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BKE_id_remapper_add(remapper, id_override_old, id_override_new); | BKE_id_remapper_add(remapper, id_override_old, id_override_new); | ||||
| } | |||||
| } | |||||
| FOREACH_MAIN_ID_END; | |||||
| /* Remap no-main override IDs we just created too. */ | /* Remap no-main override IDs we just created too. */ | ||||
| GHashIterator linkedref_to_old_override_iter; | GHashIterator linkedref_to_old_override_iter; | ||||
| GHASH_ITER (linkedref_to_old_override_iter, linkedref_to_old_override) { | GHASH_ITER (linkedref_to_old_override_iter, linkedref_to_old_override) { | ||||
| ID *id_override_old_iter = BLI_ghashIterator_getValue(&linkedref_to_old_override_iter); | ID *id_override_old_iter = BLI_ghashIterator_getValue(&linkedref_to_old_override_iter); | ||||
| if ((id_override_old_iter->tag & LIB_TAG_NO_MAIN) == 0) { | if ((id_override_old_iter->tag & LIB_TAG_NO_MAIN) == 0) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BKE_libblock_relink_ex(bmain, | BLI_linklist_prepend(&nomain_ids, id_override_old_iter); | ||||
| id_override_old_iter, | |||||
| id_override_old, | |||||
| id_override_new, | |||||
| ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| FOREACH_MAIN_ID_END; | |||||
| /* Remap all IDs to use the new override. */ | /* Remap all IDs to use the new override. */ | ||||
| BKE_libblock_remap_multiple(bmain, remapper, 0); | BKE_libblock_remap_multiple(bmain, remapper, 0); | ||||
| BKE_libblock_relink_multiple(bmain, | |||||
| nomain_ids, | |||||
| ID_REMAP_TYPE_REMAP, | |||||
| remapper, | |||||
| ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE); | |||||
| BKE_id_remapper_free(remapper); | BKE_id_remapper_free(remapper); | ||||
| } | } | ||||
| static bool lib_override_library_resync(Main *bmain, | static bool lib_override_library_resync(Main *bmain, | ||||
| Scene *scene, | Scene *scene, | ||||
| ViewLayer *view_layer, | ViewLayer *view_layer, | ||||
| ID *id_root, | ID *id_root, | ||||
| LinkNode *id_resync_roots, | LinkNode *id_resync_roots, | ||||
| ▲ Show 20 Lines • Show All 242 Lines • ▼ Show 20 Lines | static bool lib_override_library_resync(Main *bmain, | ||||
| FOREACH_MAIN_LISTBASE_END; | FOREACH_MAIN_LISTBASE_END; | ||||
| /* We remap old to new override usages in a separate loop, after all new overrides have | /* We remap old to new override usages in a separate loop, after all new overrides have | ||||
| * been added to Main. */ | * been added to Main. */ | ||||
| lib_override_library_remap(bmain, id_root_reference, linkedref_to_old_override); | lib_override_library_remap(bmain, id_root_reference, linkedref_to_old_override); | ||||
| BKE_main_collection_sync(bmain); | BKE_main_collection_sync(bmain); | ||||
| LinkNode *id_override_old_list = NULL; | |||||
| /* We need to apply override rules in a separate loop, after all ID pointers have been properly | /* We need to apply override rules in a separate loop, after all ID pointers have been properly | ||||
| * remapped, and all new local override IDs have gotten their proper original names, otherwise | * remapped, and all new local override IDs have gotten their proper original names, otherwise | ||||
| * override operations based on those ID names would fail. */ | * override operations based on those ID names would fail. */ | ||||
| FOREACH_MAIN_ID_BEGIN (bmain, id) { | FOREACH_MAIN_ID_BEGIN (bmain, id) { | ||||
| if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) { | if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) { | ||||
| ID *id_override_new = id->newid; | ID *id_override_new = id->newid; | ||||
| if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_override_new)) { | if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_override_new)) { | ||||
| continue; | continue; | ||||
| Show All 33 Lines | if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) { | ||||
| &rnaptr_src, | &rnaptr_src, | ||||
| NULL, | NULL, | ||||
| id_override_new->override_library, | id_override_new->override_library, | ||||
| do_hierarchy_enforce ? | do_hierarchy_enforce ? | ||||
| RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS : | RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS : | ||||
| RNA_OVERRIDE_APPLY_FLAG_NOP); | RNA_OVERRIDE_APPLY_FLAG_NOP); | ||||
| } | } | ||||
| BLI_linklist_prepend(&id_override_old_list, id_override_old); | |||||
| } | |||||
| } | |||||
| FOREACH_MAIN_ID_END; | |||||
| /* Once overrides have been properly 'transferred' from old to new ID, we can clear ID usages | /* Once overrides have been properly 'transferred' from old to new ID, we can clear ID usages | ||||
| * of the old one. | * of the old one. | ||||
| * This is necessary in case said old ID is not in Main anymore. */ | * This is necessary in case said old ID is not in Main anymore. */ | ||||
| BKE_libblock_relink_ex(bmain, | struct IDRemapper *id_remapper = BKE_id_remapper_create(); | ||||
| id_override_old, | BKE_libblock_relink_multiple(bmain, | ||||
| NULL, | id_override_old_list, | ||||
| NULL, | ID_REMAP_TYPE_CLEANUP, | ||||
| id_remapper, | |||||
| ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE); | ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE); | ||||
| for (LinkNode *ln_iter = id_override_old_list; ln_iter != NULL; ln_iter = ln_iter->next) { | |||||
| ID *id_override_old = ln_iter->link; | |||||
| id_override_old->tag |= LIB_TAG_NO_USER_REFCOUNT; | id_override_old->tag |= LIB_TAG_NO_USER_REFCOUNT; | ||||
| } | } | ||||
| } | BKE_id_remapper_free(id_remapper); | ||||
| FOREACH_MAIN_ID_END; | BLI_linklist_free(id_override_old_list, NULL); | ||||
| /* Delete old override IDs. | /* Delete old override IDs. | ||||
| * Note that we have to use tagged group deletion here, since ID deletion also uses | * Note that we have to use tagged group deletion here, since ID deletion also uses | ||||
| * LIB_TAG_DOIT. This improves performances anyway, so everything is fine. */ | * LIB_TAG_DOIT. This improves performances anyway, so everything is fine. */ | ||||
| int user_edited_overrides_deletion_count = 0; | int user_edited_overrides_deletion_count = 0; | ||||
| FOREACH_MAIN_ID_BEGIN (bmain, id) { | FOREACH_MAIN_ID_BEGIN (bmain, id) { | ||||
| if (id->tag & LIB_TAG_DOIT) { | if (id->tag & LIB_TAG_DOIT) { | ||||
| /* Note that this works because linked IDs are always after local ones (including | /* Note that this works because linked IDs are always after local ones (including | ||||
| ▲ Show 20 Lines • Show All 1,785 Lines • Show Last 20 Lines | |||||