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:
authorBastien Montagne <bastien@blender.org>2020-07-20 18:04:16 +0300
committerBastien Montagne <bastien@blender.org>2020-07-20 18:04:16 +0300
commit7484e4529717a61277525bbb6bc9ac7a747e42f1 (patch)
treea5cd70a140ed167b9b26cb84e29163546a61d9e3 /source/blender/blenkernel/intern/collection.c
parentccc2a7996b836cd255fbb7d7f693f5b958442043 (diff)
Fix T78960: 2.83.2 not opening a 2.82a project correctly.
That project cannot be opened correctly ayway, it has recursive collections intanciating themselves... But at least now we have a check at startup to detect and 'fix' those nasty cycles in collections.
Diffstat (limited to 'source/blender/blenkernel/intern/collection.c')
-rw-r--r--source/blender/blenkernel/intern/collection.c83
1 files changed, 75 insertions, 8 deletions
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 4bd0c77af28..6118325c231 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -1147,7 +1147,7 @@ void BKE_collections_after_lib_link(Main *bmain)
/** \name Collection Children
* \{ */
-static bool collection_find_instance_recursive(Collection *collection,
+static bool collection_instance_find_recursive(Collection *collection,
Collection *instance_collection)
{
LISTBASE_FOREACH (CollectionObject *, collection_object, &collection->gobject) {
@@ -1159,7 +1159,7 @@ static bool collection_find_instance_recursive(Collection *collection,
}
LISTBASE_FOREACH (CollectionChild *, collection_child, &collection->children) {
- if (collection_find_instance_recursive(collection_child->collection, instance_collection)) {
+ if (collection_instance_find_recursive(collection_child->collection, instance_collection)) {
return true;
}
}
@@ -1167,21 +1167,88 @@ static bool collection_find_instance_recursive(Collection *collection,
return false;
}
-bool BKE_collection_find_cycle(Collection *new_ancestor, Collection *collection)
+/**
+ * Find potential cycles in collections.
+ *
+ * \param new_ancestor the potential new owner of given \a collection, or the collection to check
+ * if the later is NULL.
+ * \param collection the collection we want to add to \a new_ancestor, may be NULL if we just want
+ * to ensure \a new_ancestor does not already have cycles.
+ * \return true if a cycle is found.
+ */
+bool BKE_collection_cycle_find(Collection *new_ancestor, Collection *collection)
{
if (collection == new_ancestor) {
return true;
}
+ if (collection == NULL) {
+ collection = new_ancestor;
+ }
+
LISTBASE_FOREACH (CollectionParent *, parent, &new_ancestor->parents) {
- if (BKE_collection_find_cycle(parent->collection, collection)) {
+ if (BKE_collection_cycle_find(parent->collection, collection)) {
return true;
}
}
/* Find possible objects in collection or its children, that would instantiate the given ancestor
* collection (that would also make a fully invalid cycle of dependencies) .*/
- return collection_find_instance_recursive(collection, new_ancestor);
+ return collection_instance_find_recursive(collection, new_ancestor);
+}
+
+static bool collection_instance_fix_recursive(Collection *parent_collection,
+ Collection *collection)
+{
+ bool cycles_found = false;
+
+ LISTBASE_FOREACH (CollectionObject *, collection_object, &parent_collection->gobject) {
+ if (collection_object->ob != NULL &&
+ collection_object->ob->instance_collection == collection) {
+ id_us_min(&collection->id);
+ collection_object->ob->instance_collection = NULL;
+ cycles_found = true;
+ }
+ }
+
+ LISTBASE_FOREACH (CollectionChild *, collection_child, &parent_collection->children) {
+ if (collection_instance_fix_recursive(collection_child->collection, collection)) {
+ cycles_found = true;
+ }
+ }
+
+ return cycles_found;
+}
+
+static bool collection_cycle_fix_recursive(Main *bmain,
+ Collection *parent_collection,
+ Collection *collection)
+{
+ bool cycles_found = false;
+
+ LISTBASE_FOREACH_MUTABLE (CollectionParent *, parent, &parent_collection->parents) {
+ if (BKE_collection_cycle_find(parent->collection, collection)) {
+ BKE_collection_child_remove(bmain, parent->collection, parent_collection);
+ cycles_found = true;
+ }
+ else if (collection_cycle_fix_recursive(bmain, parent->collection, collection)) {
+ cycles_found = true;
+ }
+ }
+
+ return cycles_found;
+}
+
+/**
+ * Find and fix potential cycles in collections.
+ *
+ * \param collection the collection to check for existing cycles.
+ * \return true if cycles are found and fixed.
+ */
+bool BKE_collection_cycles_fix(Main *bmain, Collection *collection)
+{
+ return collection_cycle_fix_recursive(bmain, collection, collection) ||
+ collection_instance_fix_recursive(collection, collection);
}
static CollectionChild *collection_find_child(Collection *parent, Collection *collection)
@@ -1223,7 +1290,7 @@ static bool collection_child_add(Collection *parent,
if (child) {
return false;
}
- if (BKE_collection_find_cycle(parent, collection)) {
+ if (BKE_collection_cycle_find(parent, collection)) {
return false;
}
@@ -1301,7 +1368,7 @@ void BKE_collection_parent_relations_rebuild(Collection *collection)
child = child_next) {
child_next = child->next;
- if (child->collection == NULL || BKE_collection_find_cycle(collection, child->collection)) {
+ if (child->collection == NULL || BKE_collection_cycle_find(collection, child->collection)) {
BLI_freelinkN(&collection->children, child);
}
else {
@@ -1464,7 +1531,7 @@ bool BKE_collection_move(Main *bmain,
if (collection->flag & COLLECTION_IS_MASTER) {
return false;
}
- if (BKE_collection_find_cycle(to_parent, collection)) {
+ if (BKE_collection_cycle_find(to_parent, collection)) {
return false;
}