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
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h29
-rw-r--r--source/blender/blenkernel/intern/lib_override.c85
-rw-r--r--source/blender/blenkernel/intern/lib_override_proxy_conversion.c4
-rw-r--r--source/blender/editors/object/object_relations.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.cc99
-rw-r--r--source/blender/makesrna/intern/rna_ID.c6
6 files changed, 172 insertions, 53 deletions
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index 858bc2f5625..98301ca7a70 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -92,7 +92,13 @@ struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
*
* \param id_hierarchy_root: the override ID that is the root of the hierarchy. May be NULL, in
* which case it is assumed that the given `id_root_reference` is tagged for override, and its
- * newly created override will be used as hierarchy root.
+ * newly created override will be used as hierarchy root. Must be NULL if
+ * `id_hierarchy_root_reference` is not NULL.
+ *
+ * \param id_hierarchy_root_reference: the linked ID that is the root of the hierarchy. Must be
+ * tagged for override. May be NULL, in which case it is assumed that the given `id_root_reference`
+ * is tagged for override, and its newly created override will be used as hierarchy root. Must be
+ * NULL if `id_hierarchy_root` is not NULL.
*
* \param do_no_main: Create the new override data outside of Main database.
* Used for resyncing of linked overrides.
@@ -103,6 +109,7 @@ bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
struct Library *owner_library,
const struct ID *id_root_reference,
struct ID *id_hierarchy_root,
+ const struct ID *id_hierarchy_root_reference,
bool do_no_main);
/**
* Advanced 'smart' function to create fully functional overrides.
@@ -119,11 +126,18 @@ bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
* \param owner_library: the library in which the overrides should be created. Besides versioning
* and resync code path, this should always be NULL (i.e. the local .blend file).
*
- * \param id_root: The root ID to create an override from.
+ * \param id_root_reference: The linked root ID to create an override from. May be a sub-root of
+ * the overall hierarchy, in which case calling code is expected to have already tagged required
+ * 'path' of IDs leading from the given `id_hierarchy_root` to the given `id_root`.
+ *
+ * \param id_hierarchy_root_reference: The ID to be used a hierarchy root of the overrides to be
+ * created. Can be either the linked root ID of the whole override hierarchy, (typically the same
+ * as `id_root`, unless a sub-part only of the hierarchy is overridden), or the already existing
+ * override hierarchy root if part of the hierarchy is already overridden.
*
- * \param id_reference: Some reference ID used to do some post-processing after overrides have been
- * created, may be NULL. Typically, the Empty object instantiating the linked collection we
- * override, currently.
+ * \param id_instance_hint: Some ID used as hint/reference to do some post-processing after
+ * overrides have been created, may be NULL. Typically, the Empty object instantiating the linked
+ * collection we override, currently.
*
* \param r_id_root_override: if not NULL, the override generated for the given \a id_root.
*
@@ -133,8 +147,9 @@ bool BKE_lib_override_library_create(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct Library *owner_library,
- struct ID *id_root,
- struct ID *id_reference,
+ struct ID *id_root_reference,
+ struct ID *id_hierarchy_root_reference,
+ struct ID *id_instance_hint,
struct ID **r_id_root_override);
/**
* Create a library override template.
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index d9418d7ec03..922c1beda38 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -321,17 +321,36 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
return local_id;
}
+/* TODO: Make this static local function instead? API is becoming complex, and it's not used
+ * outside of this file anyway. */
bool BKE_lib_override_library_create_from_tag(Main *bmain,
Library *owner_library,
const ID *id_root_reference,
ID *id_hierarchy_root,
+ const ID *id_hierarchy_root_reference,
const bool do_no_main)
{
- BLI_assert(id_root_reference != NULL);
- BLI_assert(id_hierarchy_root != NULL || (id_root_reference->tag & LIB_TAG_DOIT) != 0);
- BLI_assert(id_hierarchy_root == NULL ||
- (ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root) &&
- id_hierarchy_root->override_library->reference == id_root_reference));
+ BLI_assert(id_root_reference != NULL && ID_IS_LINKED(id_root_reference));
+ /* If we do not have any hierarchy root given, then the root reference must be tagged for
+ * override. */
+ BLI_assert(id_hierarchy_root != NULL || id_hierarchy_root_reference != NULL ||
+ (id_root_reference->tag & LIB_TAG_DOIT) != 0);
+ /* At least one of the hierarchy root pointers must be NULL, passing both is useless and can
+ * create confusion. */
+ BLI_assert(ELEM(NULL, id_hierarchy_root, id_hierarchy_root_reference));
+
+ if (id_hierarchy_root != NULL) {
+ /* If the hierarchy root is given, it must be a valid existing override (used during partial
+ * resync process mainly). */
+ BLI_assert((ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root) &&
+ id_hierarchy_root->override_library->reference->lib == id_root_reference->lib));
+ }
+ if (!ELEM(id_hierarchy_root_reference, NULL, id_root_reference)) {
+ /* If the reference hierarchy root is given, it must be from the same library as the reference
+ * root, and also tagged for override. */
+ BLI_assert((id_hierarchy_root_reference->lib == id_root_reference->lib &&
+ (id_hierarchy_root_reference->tag & LIB_TAG_DOIT) != 0));
+ }
const Library *reference_library = id_root_reference->lib;
@@ -387,7 +406,12 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
/* Only remap new local ID's pointers, we don't want to force our new overrides onto our whole
* existing linked IDs usages. */
if (success) {
- if (id_root_reference->newid != NULL) {
+ if (id_hierarchy_root_reference != NULL) {
+ id_hierarchy_root = id_hierarchy_root_reference->newid;
+ }
+ else if (id_root_reference->newid != NULL &&
+ (id_hierarchy_root == NULL ||
+ id_hierarchy_root->override_library->reference == id_root_reference)) {
id_hierarchy_root = id_root_reference->newid;
}
BLI_assert(id_hierarchy_root != NULL);
@@ -887,12 +911,13 @@ static void lib_override_overrides_group_tag(LibOverrideGroupTagData *data)
static bool lib_override_library_create_do(Main *bmain,
Scene *scene,
Library *owner_library,
- ID *id_root)
+ ID *id_root_reference,
+ ID *id_hierarchy_root_reference)
{
BKE_main_relations_create(bmain, 0);
LibOverrideGroupTagData data = {.bmain = bmain,
.scene = scene,
- .id_root = id_root,
+ .id_root = id_root_reference,
.tag = LIB_TAG_DOIT,
.missing_tag = LIB_TAG_MISSING,
.is_override = false,
@@ -906,8 +931,18 @@ static bool lib_override_library_create_do(Main *bmain,
BKE_main_relations_free(bmain);
lib_override_group_tag_data_clear(&data);
- const bool success = BKE_lib_override_library_create_from_tag(
- bmain, owner_library, id_root, NULL, false);
+ bool success = false;
+ if (id_hierarchy_root_reference->lib != id_root_reference->lib) {
+ BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference));
+ BLI_assert(id_hierarchy_root_reference->override_library->reference->lib ==
+ id_root_reference->lib);
+ success = BKE_lib_override_library_create_from_tag(
+ bmain, owner_library, id_root_reference, id_hierarchy_root_reference, NULL, false);
+ }
+ else {
+ success = BKE_lib_override_library_create_from_tag(
+ bmain, owner_library, id_root_reference, NULL, id_hierarchy_root_reference, false);
+ }
return success;
}
@@ -917,7 +952,7 @@ static void lib_override_library_create_post_process(Main *bmain,
ViewLayer *view_layer,
const Library *owner_library,
ID *id_root,
- ID *id_reference,
+ ID *id_instance_hint,
Collection *residual_storage,
const bool is_resync)
{
@@ -941,8 +976,8 @@ static void lib_override_library_create_post_process(Main *bmain,
(!ID_IS_LINKED(id_root->newid) || id_root->newid->lib == owner_library)) {
switch (GS(id_root->name)) {
case ID_GR: {
- Object *ob_reference = id_reference != NULL && GS(id_reference->name) == ID_OB ?
- (Object *)id_reference :
+ Object *ob_reference = id_instance_hint != NULL && GS(id_instance_hint->name) == ID_OB ?
+ (Object *)id_instance_hint :
NULL;
Collection *collection_new = ((Collection *)id_root->newid);
if (is_resync && BKE_collection_is_in_scene(collection_new)) {
@@ -951,10 +986,10 @@ static void lib_override_library_create_post_process(Main *bmain,
if (ob_reference != NULL) {
BKE_collection_add_from_object(bmain, scene, ob_reference, collection_new);
}
- else if (id_reference != NULL) {
- BLI_assert(GS(id_reference->name) == ID_GR);
+ else if (id_instance_hint != NULL) {
+ BLI_assert(GS(id_instance_hint->name) == ID_GR);
BKE_collection_add_from_collection(
- bmain, scene, ((Collection *)id_reference), collection_new);
+ bmain, scene, ((Collection *)id_instance_hint), collection_new);
}
else {
BKE_collection_add_from_collection(
@@ -1047,26 +1082,32 @@ bool BKE_lib_override_library_create(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
Library *owner_library,
- ID *id_root,
- ID *id_reference,
+ ID *id_root_reference,
+ ID *id_hierarchy_root_reference,
+ ID *id_instance_hint,
ID **r_id_root_override)
{
if (r_id_root_override != NULL) {
*r_id_root_override = NULL;
}
- const bool success = lib_override_library_create_do(bmain, scene, owner_library, id_root);
+ if (id_hierarchy_root_reference == NULL) {
+ id_hierarchy_root_reference = id_root_reference;
+ }
+
+ const bool success = lib_override_library_create_do(
+ bmain, scene, owner_library, id_root_reference, id_hierarchy_root_reference);
if (!success) {
return success;
}
if (r_id_root_override != NULL) {
- *r_id_root_override = id_root->newid;
+ *r_id_root_override = id_root_reference->newid;
}
lib_override_library_create_post_process(
- bmain, scene, view_layer, owner_library, id_root, id_reference, NULL, false);
+ bmain, scene, view_layer, owner_library, id_root_reference, id_instance_hint, NULL, false);
/* Cleanup. */
BKE_main_id_newptr_and_tag_clear(bmain);
@@ -1527,7 +1568,7 @@ static bool lib_override_library_resync(Main *bmain,
* override IDs (including within the old overrides themselves, since those are tagged too
* above). */
const bool success = BKE_lib_override_library_create_from_tag(
- bmain, NULL, id_root_reference, id_root->override_library->hierarchy_root, true);
+ bmain, NULL, id_root_reference, id_root->override_library->hierarchy_root, NULL, true);
if (!success) {
BLI_ghash_free(linkedref_to_old_override, NULL, NULL);
diff --git a/source/blender/blenkernel/intern/lib_override_proxy_conversion.c b/source/blender/blenkernel/intern/lib_override_proxy_conversion.c
index 809235ad24c..dc164313788 100644
--- a/source/blender/blenkernel/intern/lib_override_proxy_conversion.c
+++ b/source/blender/blenkernel/intern/lib_override_proxy_conversion.c
@@ -42,7 +42,7 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain,
const bool is_override_instancing_object = ob_proxy_group != NULL;
ID *id_root = is_override_instancing_object ? &ob_proxy_group->instance_collection->id :
&ob_proxy->proxy->id;
- ID *id_reference = is_override_instancing_object ? &ob_proxy_group->id : &ob_proxy->id;
+ ID *id_instance_hint = is_override_instancing_object ? &ob_proxy_group->id : &ob_proxy->id;
/* In some cases the instance collection of a proxy object may be local (see e.g. T83875). Not
* sure this is a valid state, but for now just abort the overriding process. */
@@ -81,7 +81,7 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain,
FOREACH_MAIN_ID_END;
return BKE_lib_override_library_create(
- bmain, scene, view_layer, ob_proxy->id.lib, id_root, id_reference, NULL);
+ bmain, scene, view_layer, ob_proxy->id.lib, id_root, id_root, id_instance_hint, NULL);
}
static void lib_override_library_proxy_convert_do(Main *bmain,
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 1204a57d59f..3ecf86d14ed 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -2318,7 +2318,7 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
const bool success = BKE_lib_override_library_create(
- bmain, scene, view_layer, NULL, id_root, &obact->id, NULL);
+ bmain, scene, view_layer, NULL, id_root, id_root, &obact->id, NULL);
/* Remove the instance empty from this scene, the items now have an overridden collection
* instead. */
diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc
index 53a81cf161e..8de7322f1f1 100644
--- a/source/blender/editors/space_outliner/outliner_tools.cc
+++ b/source/blender/editors/space_outliner/outliner_tools.cc
@@ -766,29 +766,30 @@ static void id_override_library_create_fn(bContext *C,
void *user_data)
{
BLI_assert(TSE_IS_REAL_ID(tselem));
- ID *id_root = tselem->id;
+ ID *id_root_reference = tselem->id;
OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data);
const bool do_hierarchy = data->do_hierarchy;
bool success = false;
- ID *id_reference = nullptr;
+ ID *id_instance_hint = nullptr;
bool is_override_instancing_object = false;
if (tsep != nullptr && tsep->type == TSE_SOME_ID && tsep->id != nullptr &&
GS(tsep->id->name) == ID_OB && !ID_IS_OVERRIDE_LIBRARY(tsep->id)) {
Object *ob = (Object *)tsep->id;
- if (ob->type == OB_EMPTY && &ob->instance_collection->id == id_root) {
- BLI_assert(GS(id_root->name) == ID_GR);
+ if (ob->type == OB_EMPTY && &ob->instance_collection->id == id_root_reference) {
+ BLI_assert(GS(id_root_reference->name) == ID_GR);
/* Empty instantiating the collection we override, we need to pass it to BKE overriding code
* for proper handling. */
- id_reference = tsep->id;
+ id_instance_hint = tsep->id;
is_override_instancing_object = true;
}
}
- if (ID_IS_OVERRIDABLE_LIBRARY(id_root) || (ID_IS_LINKED(id_root) && do_hierarchy)) {
+ if (ID_IS_OVERRIDABLE_LIBRARY(id_root_reference) ||
+ (ID_IS_LINKED(id_root_reference) && do_hierarchy)) {
Main *bmain = CTX_data_main(C);
- id_root->tag |= LIB_TAG_DOIT;
+ id_root_reference->tag |= LIB_TAG_DOIT;
/* For now, remap all local usages of linked ID to local override one here. */
ID *id_iter;
@@ -804,38 +805,100 @@ static void id_override_library_create_fn(bContext *C,
if (do_hierarchy) {
/* Tag all linked parents in tree hierarchy to be also overridden. */
+ ID *id_hierarchy_root_reference = id_root_reference;
while ((te = te->parent) != nullptr) {
if (!TSE_IS_REAL_ID(te->store_elem)) {
continue;
}
- if (!ID_IS_LINKED(te->store_elem->id)) {
+
+ /* Tentative hierarchy root. */
+ ID *id_current_hierarchy_root = te->store_elem->id;
+
+ /* If the parent ID is from a different library than the reference root one, we are done
+ * with upwards tree processing in any case. */
+ if (id_current_hierarchy_root->lib != id_root_reference->lib) {
+ if (ID_IS_OVERRIDE_LIBRARY_VIRTUAL(id_current_hierarchy_root)) {
+ /* Virtual overrides (i.e. embedded IDs), we can simply keep processing their parent to
+ * get an actual real override. */
+ continue;
+ }
+
+ /* If the parent ID is already an override, and is valid (i.e. local override), we can
+ * access its hierarchy root directly. */
+ if (!ID_IS_LINKED(id_current_hierarchy_root) &&
+ ID_IS_OVERRIDE_LIBRARY_REAL(id_current_hierarchy_root) &&
+ id_current_hierarchy_root->override_library->reference->lib ==
+ id_root_reference->lib) {
+ id_hierarchy_root_reference =
+ id_current_hierarchy_root->override_library->hierarchy_root;
+ BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference));
+ break;
+ }
+
+ if (ID_IS_LINKED(id_current_hierarchy_root)) {
+ /* No local 'anchor' was found for the hierarchy to override, do not proceed, as this
+ * would most likely generate invisible/confusing/hard to use and manage overrides. */
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Invalid anchor ('%s') found, needed to create library override from "
+ "data-block '%s'",
+ id_current_hierarchy_root->name,
+ id_root_reference->name);
+ return;
+ }
+
+ /* In all other cases, `id_current_hierarchy_root` cannot be a valid hierarchy root, so
+ * current `id_hierarchy_root_reference` is our best candidate. */
+
break;
}
+
/* If some element in the tree needs to be overridden, but its ID is not overridable,
* abort. */
- if (!ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(te->store_elem->id)) {
+ if (!ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(id_current_hierarchy_root)) {
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
BKE_reportf(reports,
RPT_WARNING,
"Could not create library override from data-block '%s', one of its parents "
"is not overridable ('%s')",
- id_root->name,
- te->store_elem->id->name);
+ id_root_reference->name,
+ id_current_hierarchy_root->name);
return;
}
- te->store_elem->id->tag |= LIB_TAG_DOIT;
+ id_current_hierarchy_root->tag |= LIB_TAG_DOIT;
+ id_hierarchy_root_reference = id_current_hierarchy_root;
+ }
+
+ /* That case can happen when linked data is a complex mix involving several libraries and/or
+ * linked overrides. E.g. a mix of overrides from one library, and indirectly linked data
+ * from another library. Do not try to support such cases for now. */
+ if (!((id_hierarchy_root_reference->lib == id_root_reference->lib) ||
+ (!ID_IS_LINKED(id_hierarchy_root_reference) &&
+ ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference) &&
+ id_hierarchy_root_reference->override_library->reference->lib ==
+ id_root_reference->lib))) {
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Invalid hierarchy root ('%s') found, needed to create library override from "
+ "data-block '%s'",
+ id_hierarchy_root_reference->name,
+ id_root_reference->name);
+ return;
}
success = BKE_lib_override_library_create(bmain,
CTX_data_scene(C),
CTX_data_view_layer(C),
nullptr,
- id_root,
- id_reference,
+ id_root_reference,
+ id_hierarchy_root_reference,
+ id_instance_hint,
nullptr);
}
- else if (ID_IS_OVERRIDABLE_LIBRARY(id_root)) {
- success = BKE_lib_override_library_create_from_id(bmain, id_root, true) != nullptr;
+ else if (ID_IS_OVERRIDABLE_LIBRARY(id_root_reference)) {
+ success = BKE_lib_override_library_create_from_id(bmain, id_root_reference, true) != nullptr;
/* Cleanup. */
BKE_main_id_newptr_and_tag_clear(bmain);
@@ -845,14 +908,14 @@ static void id_override_library_create_fn(bContext *C,
/* Remove the instance empty from this scene, the items now have an overridden collection
* instead. */
if (success && is_override_instancing_object) {
- ED_object_base_free_and_unlink(bmain, scene, (Object *)id_reference);
+ ED_object_base_free_and_unlink(bmain, scene, (Object *)id_instance_hint);
}
}
if (!success) {
BKE_reportf(reports,
RPT_WARNING,
"Could not create library override from data-block '%s'",
- id_root->name);
+ id_root_reference->name);
}
}
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 78960803182..94ffa330064 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -696,7 +696,7 @@ static ID *rna_ID_override_create(ID *id, Main *bmain, bool remap_local_usages)
}
static ID *rna_ID_override_hierarchy_create(
- ID *id, Main *bmain, Scene *scene, ViewLayer *view_layer, ID *id_reference)
+ ID *id, Main *bmain, Scene *scene, ViewLayer *view_layer, ID *id_instance_hint)
{
if (!ID_IS_OVERRIDABLE_LIBRARY(id)) {
return NULL;
@@ -706,7 +706,7 @@ static ID *rna_ID_override_hierarchy_create(
ID *id_root_override = NULL;
BKE_lib_override_library_create(
- bmain, scene, view_layer, NULL, id, id_reference, &id_root_override);
+ bmain, scene, view_layer, NULL, id, id, id_instance_hint, &id_root_override);
WM_main_add_notifier(NC_ID | NA_ADDED, NULL);
WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL);
@@ -2057,7 +2057,7 @@ static void rna_def_ID(BlenderRNA *brna)
"reference",
"ID",
"",
- "Another ID (usually an Object or Collection) used to decide where to "
+ "Another ID (usually an Object or Collection) used as a hint to decide where to "
"instantiate the new overrides");
func = RNA_def_function(srna, "override_template_create", "rna_ID_override_template_create");