diff options
author | Bastien Montagne <bastien@blender.org> | 2020-07-23 12:30:48 +0300 |
---|---|---|
committer | Bastien Montagne <bastien@blender.org> | 2020-07-23 12:33:24 +0300 |
commit | 60b80ce142eb181342fc691610b3f42fedc0c00b (patch) | |
tree | ed554706657a48762c810fc65c23d1d45a83db4b /source/blender/blenkernel | |
parent | 79440c37acff6c6fbcdd3d4bb7a703820c722929 (diff) |
LibOverride: Add core functions to reset a library override.
This means that we delete all override properties except for those over
ID pointers *if* the assigned pointer matches the linked data hierarchy.
Then we reload affected datablocks.
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r-- | source/blender/blenkernel/BKE_lib_override.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/lib_override.c | 131 |
2 files changed, 134 insertions, 0 deletions
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h index ba8f2eb3399..6a05f0c22b6 100644 --- a/source/blender/blenkernel/BKE_lib_override.h +++ b/source/blender/blenkernel/BKE_lib_override.h @@ -119,6 +119,9 @@ bool BKE_lib_override_library_status_check_reference(struct Main *bmain, struct bool BKE_lib_override_library_operations_create(struct Main *bmain, struct ID *local); void BKE_lib_override_library_main_operations_create(struct Main *bmain, const bool force_auto); +void BKE_lib_override_library_id_reset(struct Main *bmain, struct ID *id_root); +void BKE_lib_override_library_id_hierarchy_reset(struct Main *bmain, struct ID *id_root); + void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *override_property, const short tag, const bool do_set); diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 7577e803adc..421a53b8e8d 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -1165,6 +1165,137 @@ void BKE_lib_override_library_main_operations_create(Main *bmain, const bool for #endif } +static bool lib_override_library_id_reset_do(Main *bmain, ID *id_root) +{ + bool was_property_deleted = false; + + LISTBASE_FOREACH_MUTABLE ( + IDOverrideLibraryProperty *, op, &id_root->override_library->properties) { + bool do_op_delete = true; + const bool is_collection = op->rna_prop_type == PROP_COLLECTION; + if (is_collection || op->rna_prop_type == PROP_POINTER) { + PointerRNA ptr_root, ptr_root_lib, ptr, ptr_lib; + PropertyRNA *prop, *prop_lib; + + RNA_pointer_create(id_root, &RNA_ID, id_root, &ptr_root); + RNA_pointer_create(id_root->override_library->reference, + &RNA_ID, + id_root->override_library->reference, + &ptr_root_lib); + + bool prop_exists = RNA_path_resolve_property(&ptr_root, op->rna_path, &ptr, &prop); + BLI_assert(prop_exists); + prop_exists = RNA_path_resolve_property(&ptr_root_lib, op->rna_path, &ptr_lib, &prop_lib); + + if (prop_exists) { + BLI_assert(ELEM(RNA_property_type(prop), PROP_POINTER, PROP_COLLECTION)); + BLI_assert(RNA_property_type(prop) == RNA_property_type(prop_lib)); + if (is_collection) { + ptr.type = RNA_property_pointer_type(&ptr, prop); + ptr_lib.type = RNA_property_pointer_type(&ptr_lib, prop_lib); + } + else { + ptr = RNA_property_pointer_get(&ptr, prop); + ptr_lib = RNA_property_pointer_get(&ptr_lib, prop_lib); + } + if (ptr.owner_id != NULL && ptr_lib.owner_id != NULL) { + BLI_assert(ptr.type == ptr_lib.type); + do_op_delete = !(RNA_struct_is_ID(ptr.type) && ptr.owner_id->override_library != NULL && + ptr.owner_id->override_library->reference == ptr_lib.owner_id); + } + } + } + + if (do_op_delete) { + BKE_lib_override_library_property_delete(id_root->override_library, op); + was_property_deleted = true; + } + } + + if (was_property_deleted) { + DEG_id_tag_update_ex(bmain, id_root, ID_RECALC_COPY_ON_WRITE); + IDOverrideLibraryRuntime *override_runtime = override_library_rna_path_runtime_ensure( + id_root->override_library); + override_runtime->tag |= IDOVERRIDE_LIBRARY_RUNTIME_TAG_NEEDS_RELOAD; + } + + return was_property_deleted; +} + +/** Reset all overrides in given \a id_root, while preserving ID relations. */ +void BKE_lib_override_library_id_reset(Main *bmain, ID *id_root) +{ + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { + return; + } + + if (lib_override_library_id_reset_do(bmain, id_root)) { + if (id_root->override_library->runtime != NULL && + (id_root->override_library->runtime->tag & IDOVERRIDE_LIBRARY_RUNTIME_TAG_NEEDS_RELOAD) != + 0) { + BKE_lib_override_library_update(bmain, id_root); + id_root->override_library->runtime->tag &= ~IDOVERRIDE_LIBRARY_RUNTIME_TAG_NEEDS_RELOAD; + } + } +} + +static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain, ID *id_root) +{ + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { + return; + } + + void **entry_pp = BLI_ghash_lookup(bmain->relations->id_user_to_used, id_root); + if (entry_pp == NULL) { + /* Already processed. */ + return; + } + + lib_override_library_id_reset_do(bmain, id_root); + + /* This way we won't process again that ID should we encounter it again through another + * relationship hierarchy. + * Note that this does not free any memory from relations, so we can still use the entries. + */ + BKE_main_relations_ID_remove(bmain, id_root); + + for (MainIDRelationsEntry *entry = *entry_pp; entry != NULL; entry = entry->next) { + if ((entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) { + /* Never consider 'loop back' relationships ('from', 'parents', 'owner' etc. pointers) as + * actual dependencies. */ + continue; + } + /* We only consider IDs from the same library. */ + if (entry->id_pointer != NULL) { + ID *id_entry = *entry->id_pointer; + if (id_entry->override_library != NULL) { + lib_override_library_id_hierarchy_recursive_reset(bmain, id_entry); + } + } + } +} + +/** Reset all overrides in given \a id_root and its dependencies, while preserving ID relations. */ +void BKE_lib_override_library_id_hierarchy_reset(Main *bmain, ID *id_root) +{ + BKE_main_relations_create(bmain, 0); + + lib_override_library_id_hierarchy_recursive_reset(bmain, id_root); + + BKE_main_relations_free(bmain); + + ID *id; + FOREACH_MAIN_ID_BEGIN (bmain, id) { + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id) || id->override_library->runtime == NULL || + (id->override_library->runtime->tag & IDOVERRIDE_LIBRARY_RUNTIME_TAG_NEEDS_RELOAD) == 0) { + continue; + } + BKE_lib_override_library_update(bmain, id); + id->override_library->runtime->tag &= ~IDOVERRIDE_LIBRARY_RUNTIME_TAG_NEEDS_RELOAD; + } + FOREACH_MAIN_ID_END; +} + /** Set or clear given tag in all operations as unused in that override property data. */ void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *override_property, const short tag, |