Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/lib_override.c')
-rw-r--r--source/blender/blenkernel/intern/lib_override.c334
1 files changed, 201 insertions, 133 deletions
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index e4094c48368..9e8e515e1a3 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -368,118 +368,154 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain)
return success;
}
-static bool lib_override_hierarchy_recursive_tag(Main *bmain,
- ID *id,
- const uint tag,
- const uint missing_tag,
- Library *override_group_lib_reference)
+/* Tag all IDs in dependency relationships within an override hierarchy/group.
+ *
+ * Note: this is typically called to complete `lib_override_linked_group_tag()`.
+ * Note: BMain's relations mapping won't be valid anymore after that call.
+ */
+static bool lib_override_hierarchy_dependencies_recursive_tag(Main *bmain,
+ ID *id,
+ const uint tag,
+ const uint missing_tag)
{
- void **entry_vp = BLI_ghash_lookup_p(bmain->relations->id_user_to_used, id);
- if (entry_vp == NULL) {
- /* Already processed. */
- return (id->tag & tag) != 0;
- }
+ MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
+ BLI_assert(entry != NULL);
- /* Note: in case some reference ID is missing from linked data (and therefore its override uses
- * a placeholder as reference), use `missing_tag` instead of `tag` for this override. */
- if (override_group_lib_reference != NULL && ID_IS_OVERRIDE_LIBRARY_REAL(id) &&
- id->override_library->reference->lib == override_group_lib_reference) {
- if (id->override_library->reference->tag & LIB_TAG_MISSING) {
- id->tag |= missing_tag;
- }
- else {
- id->tag |= tag;
- }
+ if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
+ /* This ID has already been processed. */
+ return (*(uint *)&id->tag & tag) != 0;
}
-
/* 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);
+ * relationship hierarchy. */
+ entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
- for (MainIDRelationsEntry *entry = *entry_vp; entry != NULL; entry = entry->next) {
- if ((entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) {
+ 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. */
continue;
}
/* We only consider IDs from the same library. */
- if (entry->id_pointer != NULL && (*entry->id_pointer)->lib == id->lib) {
- if (lib_override_hierarchy_recursive_tag(
- bmain, *entry->id_pointer, tag, missing_tag, override_group_lib_reference) &&
- override_group_lib_reference == NULL) {
+ ID *to_id = *to_id_entry->id_pointer.to;
+ if (to_id != NULL && to_id->lib == id->lib) {
+ if (lib_override_hierarchy_dependencies_recursive_tag(bmain, to_id, tag, missing_tag)) {
id->tag |= tag;
}
}
}
- return (id->tag & tag) != 0;
+ return (*(uint *)&id->tag & tag) != 0;
}
-/**
- * Tag all IDs in given \a bmain that are being used by given \a id_root ID or its dependencies,
- * recursively.
- * It detects and tag only chains of dependencies marked at both ends by given tag.
- *
- * This will include all local IDs, and all IDs from the same library as the \a id_root.
- *
- * \param id_root: The root of the hierarchy of dependencies to be tagged.
- * \param do_create_main_relashionships: Whether main relations needs to be created or already
- * exist (in any case, they will be freed by this function).
- */
-void BKE_lib_override_library_dependencies_tag(Main *bmain,
- ID *id_root,
- const uint tag,
- const bool do_create_main_relashionships)
+typedef struct LibOverrideGroupTagData {
+ ID *id_root;
+ uint tag;
+ uint missing_tag;
+} LibOverrideGroupTagData;
+
+static int lib_override_linked_group_tag_cb(LibraryIDLinkCallbackData *cb_data)
{
- if (do_create_main_relashionships) {
- BKE_main_relations_create(bmain, 0);
+ if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_LOOPBACK)) {
+ return IDWALK_RET_STOP_RECURSION;
}
- /* We tag all intermediary data-blocks in-between two overridden ones (e.g. if a shape-key
- * has a driver using an armature object's bone, we need to override the shape-key/obdata,
- * the objects using them, etc.) */
- lib_override_hierarchy_recursive_tag(bmain, id_root, tag, 0, NULL);
+ LibOverrideGroupTagData *data = cb_data->user_data;
+ const uint tag = data->tag;
+ const uint missing_tag = data->missing_tag;
- BKE_main_relations_free(bmain);
+ ID *id_root = data->id_root;
+ Library *library_root = id_root->lib;
+ ID *id = *cb_data->id_pointer;
+ ID *id_owner = cb_data->id_owner;
+
+ BLI_assert(id_owner == cb_data->id_self);
+
+ if (ELEM(id, NULL, id_owner)) {
+ return IDWALK_RET_NOP;
+ }
+
+ BLI_assert(id_owner->lib == library_root);
+
+ if (*(uint *)&id->tag & (tag | missing_tag)) {
+ /* Already processed and tagged, nothing else to do here. */
+ return IDWALK_RET_STOP_RECURSION;
+ }
+
+ if (id->lib != library_root) {
+ /* We do not override data-blocks from other libraries, nor do we process them. */
+ return IDWALK_RET_STOP_RECURSION;
+ }
+
+ /* We tag all collections and objects for override. And we also tag all other data-blocks which
+ * would use one of those.
+ * Note: missing IDs (aka placeholders) are never overridden. */
+ if (ELEM(GS(id->name), ID_OB, ID_GR)) {
+ if ((id->tag & LIB_TAG_MISSING)) {
+ id->tag |= missing_tag;
+ }
+ else {
+ id->tag |= tag;
+ }
+ }
+
+ return IDWALK_RET_NOP;
}
-/**
- * Tag all IDs in given \a bmain that are part of the same \a id_root liboverride ID group.
- * That is, all other liboverride IDs (in)directly used by \a is_root one, and sharing the same
- * library for their reference IDs.
+/* This will tag at least all 'boundary' linked IDs for a potential override group.
*
- * \param id_root: The root of the hierarchy of liboverride dependencies to be tagged.
- * \param do_create_main_relashionships: Whether main relations needs to be created or already
- * exist (in any case, they will be freed by this function).
+ * Note that you will then need to call #lib_override_hierarchy_dependencies_recursive_tag to
+ * complete tagging of all dependencies within the override group.
+ *
+ * We currently only consider Collections and Objects (that are not used as bone shapes) as valid
+ * boundary IDs to define an override group.
*/
-void BKE_lib_override_library_override_group_tag(Main *bmain,
- ID *id_root,
- const uint tag,
- const uint missing_tag,
- const bool do_create_main_relashionships)
+static void lib_override_linked_group_tag(
+ Main *bmain, ID *id, const uint tag, const uint missing_tag, const bool create_bmain_relations)
{
- if (do_create_main_relashionships) {
+ if (create_bmain_relations) {
BKE_main_relations_create(bmain, 0);
}
- /* We tag all liboverride data-blocks from the same library as reference one,
- * being used by the root ID. */
- lib_override_hierarchy_recursive_tag(
- bmain, id_root, tag, missing_tag, id_root->override_library->reference->lib);
+ if (ELEM(GS(id->name), ID_OB, ID_GR)) {
+ LibOverrideGroupTagData data = {.id_root = id, .tag = tag, .missing_tag = missing_tag};
+ /* Tag all collections and objects. */
+ BKE_library_foreach_ID_link(
+ bmain, id, lib_override_linked_group_tag_cb, &data, IDWALK_READONLY | IDWALK_RECURSE);
- BKE_main_relations_free(bmain);
+ /* Then, we remove (untag) bone shape objects, you shall never want to directly/explicitly
+ * override those. */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & tag)) {
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
+ if (pchan->custom != NULL) {
+ pchan->custom->id.tag &= ~(tag | missing_tag);
+ }
+ }
+ }
+ }
+ }
+
+ lib_override_hierarchy_dependencies_recursive_tag(bmain, id, tag, missing_tag);
+
+ if (create_bmain_relations) {
+ BKE_main_relations_free(bmain);
+ }
}
-static int lib_override_library_make_tag_ids_cb(LibraryIDLinkCallbackData *cb_data)
+static int lib_override_local_group_tag_cb(LibraryIDLinkCallbackData *cb_data)
{
- if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_LOOPBACK)) {
+ if (cb_data->cb_flag &
+ (IDWALK_CB_EMBEDDED | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) {
return IDWALK_RET_STOP_RECURSION;
}
- ID *id_root = cb_data->user_data;
- Library *library_root = id_root->lib;
+ LibOverrideGroupTagData *data = cb_data->user_data;
+ const uint tag = data->tag;
+ const uint missing_tag = data->missing_tag;
+
+ ID *id_root = data->id_root;
+ Library *library_reference_root = id_root->override_library->reference->lib;
ID *id = *cb_data->id_pointer;
ID *id_owner = cb_data->id_owner;
@@ -489,62 +525,69 @@ static int lib_override_library_make_tag_ids_cb(LibraryIDLinkCallbackData *cb_da
return IDWALK_RET_NOP;
}
- BLI_assert(id->lib != NULL);
- BLI_assert(id_owner->lib == library_root);
-
- if (id->tag & LIB_TAG_DOIT) {
+ if (*(uint *)&id->tag & (tag | missing_tag)) {
/* Already processed and tagged, nothing else to do here. */
return IDWALK_RET_STOP_RECURSION;
}
- if (id->lib != library_root) {
+ if (!ID_IS_OVERRIDE_LIBRARY(id) || ID_IS_LINKED(id)) {
+ /* Fully local, or linked ID, those are never part of a local override group. */
+ return IDWALK_RET_STOP_RECURSION;
+ }
+
+ /* NOTE: Since we rejected embedded data too at the beginning of this function, id should only be
+ * a real override now.
+ *
+ * However, our usual trouble maker, Key, is not considered as an embedded ID currently, yet it
+ * is never a real override either. Enjoy. */
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
+ return IDWALK_RET_NOP;
+ }
+
+ if (id->override_library->reference->lib != library_reference_root) {
/* We do not override data-blocks from other libraries, nor do we process them. */
return IDWALK_RET_STOP_RECURSION;
}
- /* We tag all collections and objects for override. And we also tag all other data-blocks which
- * would use one of those.
- * Note: missing IDs (aka placeholders) are never overridden. */
- if (ELEM(GS(id->name), ID_OB, ID_GR) && !(id->tag & LIB_TAG_MISSING)) {
- id->tag |= LIB_TAG_DOIT;
+ if (id->override_library->reference->tag & LIB_TAG_MISSING) {
+ id->tag |= missing_tag;
+ }
+ else {
+ id->tag |= tag;
}
return IDWALK_RET_NOP;
}
+/* This will tag at least all 'boundary' linked IDs for a potential override group.
+ *
+ * Note that you will then need to call #lib_override_hierarchy_dependencies_recursive_tag to
+ * complete tagging of all dependencies within the override group.
+ *
+ * We currently only consider Collections and Objects (that are not used as bone shapes) as valid
+ * boundary IDs to define an override group.
+ */
+static void lib_override_local_group_tag(Main *bmain,
+ ID *id,
+ const uint tag,
+ const uint missing_tag)
+{
+ LibOverrideGroupTagData data = {.id_root = id, .tag = tag, .missing_tag = missing_tag};
+ /* Tag all local overrides in id_root's group. */
+ BKE_library_foreach_ID_link(
+ bmain, id, lib_override_local_group_tag_cb, &data, IDWALK_READONLY | IDWALK_RECURSE);
+}
+
static bool lib_override_library_create_do(Main *bmain, ID *id_root)
{
id_root->tag |= LIB_TAG_DOIT;
BKE_main_relations_create(bmain, 0);
- if (ELEM(GS(id_root->name), ID_OB, ID_GR)) {
- /* Tag all collections and objects. */
- BKE_library_foreach_ID_link(bmain,
- id_root,
- lib_override_library_make_tag_ids_cb,
- id_root,
- IDWALK_READONLY | IDWALK_RECURSE);
-
- /* Then, we remove (untag) bone shape objects, you shall never want to override those
- * (hopefully). */
- LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
- if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & LIB_TAG_DOIT)) {
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
- if (pchan->custom != NULL) {
- pchan->custom->id.tag &= ~LIB_TAG_DOIT;
- }
- }
- }
- }
- }
+ lib_override_linked_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_MISSING, false);
+ lib_override_hierarchy_dependencies_recursive_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_MISSING);
- /* Now tag all non-object/collection IDs 'in-between' two tagged ones, as those are part of an
- * override chain and therefore also need to be overridden.
- * One very common cases are e.g. drivers on geometry or materials of an overridden object, that
- * are using another overridden object as parameter. */
- /* Note that this call will also free the main relations data we created above. */
- BKE_lib_override_library_dependencies_tag(bmain, id_root, LIB_TAG_DOIT, false);
+ BKE_main_relations_free(bmain);
return BKE_lib_override_library_create_from_tag(bmain);
}
@@ -737,14 +780,14 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root));
- /* Tag all collections and objects, as well as other IDs using them. */
id_root->tag |= LIB_TAG_DOIT;
ID *id_root_reference = id_root->override_library->reference;
- /* Make a mapping 'linked reference IDs' -> 'Local override IDs' of existing overrides, and tag
- * linked reference ones to be overridden again. */
- BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_MISSING, true);
+ lib_override_local_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_MISSING);
+
+ lib_override_linked_group_tag(bmain, id_root_reference, LIB_TAG_DOIT, LIB_TAG_MISSING, true);
+ /* Make a mapping 'linked reference IDs' -> 'Local override IDs' of existing overrides. */
GHash *linkedref_to_old_override = BLI_ghash_new(
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
ID *id;
@@ -755,7 +798,7 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
* same linked ID in a same hierarchy. */
if (!BLI_ghash_haskey(linkedref_to_old_override, id->override_library->reference)) {
BLI_ghash_insert(linkedref_to_old_override, id->override_library->reference, id);
- id->override_library->reference->tag |= LIB_TAG_DOIT;
+ BLI_assert(id->override_library->reference->tag & LIB_TAG_DOIT);
}
}
}
@@ -765,7 +808,7 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
/* Note that this call also remaps all pointers of tagged IDs from old override IDs to new
* override IDs (including within the old overrides themselves, since those are tagged too
* above). */
- const bool success = lib_override_library_create_do(bmain, id_root_reference);
+ const bool success = BKE_lib_override_library_create_from_tag(bmain);
if (!success) {
return success;
@@ -828,6 +871,23 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
RNA_id_pointer_create(id_override_old, &rnaptr_src);
RNA_id_pointer_create(id_override_new, &rnaptr_dst);
+ /* We remove any operation tagged with `IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE`,
+ * that way the potentially new pointer will be properly kept, when old one is still valid
+ * too (typical case: assigning new ID to some usage, while old one remains used elsewhere
+ * in the override hierarchy). */
+ LISTBASE_FOREACH_MUTABLE (
+ IDOverrideLibraryProperty *, op, &id_override_new->override_library->properties) {
+ LISTBASE_FOREACH_MUTABLE (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
+ if (opop->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) {
+ lib_override_library_property_operation_clear(opop);
+ BLI_freelinkN(&op->operations, opop);
+ }
+ }
+ if (BLI_listbase_is_empty(&op->operations)) {
+ BKE_lib_override_library_property_delete(id_override_new->override_library, op);
+ }
+ }
+
RNA_struct_override_apply(
bmain, &rnaptr_dst, &rnaptr_src, NULL, id_override_new->override_library);
}
@@ -900,7 +960,7 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
id_root->tag |= LIB_TAG_DOIT;
/* Tag all library overrides in the chains of dependencies from the given root one. */
- BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_DOIT, true);
+ lib_override_local_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_DOIT);
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
@@ -1619,31 +1679,37 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain, ID *i
return;
}
- void **entry_pp = BLI_ghash_lookup(bmain->relations->id_user_to_used, id_root);
- if (entry_pp == NULL) {
- /* Already processed. */
+ void **entry_vp = BLI_ghash_lookup_p(bmain->relations->relations_from_pointers, id_root);
+ if (entry_vp == NULL) {
+ /* This ID is not used by nor using any other ID. */
+ lib_override_library_id_reset_do(bmain, id_root);
+ return;
+ }
+
+ MainIDRelationsEntry *entry = *entry_vp;
+ if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
+ /* This ID has already been 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);
+ * relationship hierarchy. */
+ entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
- for (MainIDRelationsEntry *entry = *entry_pp; entry != NULL; entry = entry->next) {
- if ((entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) {
+ 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. */
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);
+ if (*to_id_entry->id_pointer.to != NULL) {
+ ID *to_id = *to_id_entry->id_pointer.to;
+ if (to_id->override_library != NULL) {
+ lib_override_library_id_hierarchy_recursive_reset(bmain, to_id);
}
}
}
@@ -1922,7 +1988,9 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
ID *local)
{
if (ID_IS_OVERRIDE_LIBRARY_TEMPLATE(local) || ID_IS_OVERRIDE_LIBRARY_VIRTUAL(local)) {
- /* This is actually purely local data with an override template, nothing to do here! */
+ /* This is actually purely local data with an override template, or one of those embedded IDs
+ * (root node trees, master collections or shapekeys) that cannot have their own override.
+ * Nothing to do here! */
return NULL;
}