diff options
-rw-r--r-- | source/blender/blenkernel/intern/lib_override.c | 99 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_ID.h | 4 |
2 files changed, 91 insertions, 12 deletions
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 0f753018c46..63709080b5c 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -423,6 +423,8 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat Main *bmain = data->bmain; ID *id_owner = data->id_root; BLI_assert(ID_IS_LINKED(id_owner)); + const uint tag = data->tag; + const uint missing_tag = data->missing_tag; MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id_owner); @@ -430,7 +432,6 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) { /* This ID has already been processed. */ - printf("%s already processed\n", id_owner->name); return; } /* This way we won't process again that ID, should we encounter it again through another @@ -439,9 +440,10 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL; to_id_entry = to_id_entry->next) { - if ((to_id_entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) { - /* Never consider 'loop back' relationships ('from', 'parents', 'owner' etc. pointers) as - * actual dependencies. */ + if ((to_id_entry->usage_flag & + (IDWALK_CB_EMBEDDED | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) != 0) { + /* Never consider 'loop back' relationships ('from', 'parents', 'owner' etc. pointers), nor + * override references or embedded ID pointers, as actual dependencies. */ continue; } @@ -460,10 +462,10 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat * Note: missing IDs (aka placeholders) are never overridden. */ if (ELEM(GS(to_id->name), ID_OB, ID_GR)) { if ((to_id->tag & LIB_TAG_MISSING)) { - to_id->tag |= data->missing_tag; + to_id->tag |= missing_tag; } else { - to_id->tag |= data->tag; + to_id->tag |= tag; } } @@ -570,23 +572,93 @@ static int lib_override_local_group_tag_cb(LibraryIDLinkCallbackData *cb_data) return IDWALK_RET_NOP; } +static void lib_override_local_group_tag_recursive(LibOverrideGroupTagData *data) +{ + Main *bmain = data->bmain; + ID *id_owner = data->id_root; + BLI_assert(ID_IS_OVERRIDE_LIBRARY(id_owner)); + const uint tag = data->tag; + const uint missing_tag = data->missing_tag; + + MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, + id_owner); + BLI_assert(entry != NULL); + + if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) { + /* This ID has already been processed. */ + return; + } + /* This way we won't process again that ID, should we encounter it again through another + * relationship hierarchy. */ + entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED; + + for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL; + to_id_entry = to_id_entry->next) { + if ((to_id_entry->usage_flag & + (IDWALK_CB_EMBEDDED | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) != 0) { + /* Never consider 'loop back' relationships ('from', 'parents', 'owner' etc. pointers), nor + * override references or embedded ID pointers, as actual dependencies. */ + continue; + } + + ID *to_id = *to_id_entry->id_pointer.to; + if (ELEM(to_id, NULL, id_owner)) { + continue; + } + if (!ID_IS_OVERRIDE_LIBRARY(to_id) || ID_IS_LINKED(to_id)) { + continue; + } + + /* Do not tag 'virtual' overrides (shape keys here, as we already rejected embedded case + * above). */ + if (ID_IS_OVERRIDE_LIBRARY_REAL(to_id)) { + ID *reference_lib = NULL; + if (GS(id_owner->name) == ID_KE) { + reference_lib = ((Key *)id_owner)->from->override_library->reference->lib; + } + else { + reference_lib = id_owner->override_library->reference->lib; + } + if (to_id->override_library->reference->lib != reference_lib) { + /* We do not override data-blocks from other libraries, nor do we process them. */ + continue; + } + + if (to_id->override_library->reference->tag & LIB_TAG_MISSING) { + to_id->tag |= missing_tag; + } + else { + to_id->tag |= tag; + } + } + + /* Recursively process the dependencies. */ + LibOverrideGroupTagData sub_data = *data; + sub_data.id_root = to_id; + lib_override_local_group_tag_recursive(&sub_data); + } +} + /* This will tag all override IDs of an override group defined by the given `id_root`. */ static void lib_override_local_group_tag(LibOverrideGroupTagData *data) { - Main *bmain = data->bmain; ID *id_root = data->id_root; + BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root) && !ID_IS_LINKED(id_root)); - id_root->tag |= data->tag; + if ((id_root->override_library->reference->tag & LIB_TAG_MISSING)) { + id_root->tag |= data->missing_tag; + } + else { + id_root->tag |= data->tag; + } /* Tag all local overrides in id_root's group. */ - BKE_library_foreach_ID_link( - bmain, id_root, lib_override_local_group_tag_cb, data, IDWALK_READONLY | IDWALK_RECURSE); + lib_override_local_group_tag_recursive(data); } static bool lib_override_library_create_do(Main *bmain, ID *id_root) { BKE_main_relations_create(bmain, 0); - LibOverrideGroupTagData data = { .bmain = bmain, .id_root = id_root, .tag = LIB_TAG_DOIT, .missing_tag = LIB_TAG_MISSING}; lib_override_linked_group_tag(&data); @@ -790,11 +862,11 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_ ID *id_root_reference = id_root->override_library->reference; BKE_main_relations_create(bmain, 0); - LibOverrideGroupTagData data = { .bmain = bmain, .id_root = id_root, .tag = LIB_TAG_DOIT, .missing_tag = LIB_TAG_MISSING}; lib_override_local_group_tag(&data); + BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false); data.id_root = id_root_reference; lib_override_linked_group_tag(&data); @@ -999,10 +1071,13 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root) BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root)); /* Tag all library overrides in the chains of dependencies from the given root one. */ + BKE_main_relations_create(bmain, 0); LibOverrideGroupTagData data = { .bmain = bmain, .id_root = id_root, .tag = LIB_TAG_DOIT, .missing_tag = LIB_TAG_MISSING}; lib_override_local_group_tag(&data); + BKE_main_relations_free(bmain); + ID *id; FOREACH_MAIN_ID_BEGIN (bmain, id) { if (id->tag & LIB_TAG_DOIT) { diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index d9c821d3ba7..00d0d4e3626 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -427,6 +427,10 @@ typedef struct PreviewImage { (ID_IS_LINKED(_id) && !ID_MISSING(_id) && (((const ID *)(_id))->tag & LIB_TAG_EXTERN) != 0 && \ (BKE_idtype_get_info_from_id((const ID *)(_id))->flags & IDTYPE_FLAGS_NO_LIBLINKING) == 0) +/* NOTE: The three checks below do not take into account whether given ID is linked or not (when + * chaining overrides over several libraries). User must ensure the ID is not linked itself + * currently. */ +/* TODO: add `_EDITABLE` versions of those macros (that would check if ID is linked or not)? */ #define ID_IS_OVERRIDE_LIBRARY_REAL(_id) \ (((const ID *)(_id))->override_library != NULL && \ ((const ID *)(_id))->override_library->reference != NULL) |