diff options
Diffstat (limited to 'source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc')
-rw-r--r-- | source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc | 89 |
1 files changed, 59 insertions, 30 deletions
diff --git a/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc b/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc index f8705c3f0ad..2150d2b211a 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc @@ -15,6 +15,7 @@ #include "BLT_translation.h" +#include "BKE_lib_override.h" #include "BKE_lib_query.h" #include "BKE_main.h" @@ -74,12 +75,18 @@ ListBase TreeDisplayOverrideLibraryHierarchies::buildTree(const TreeSourceData & return tree; } +bool TreeDisplayOverrideLibraryHierarchies::is_lazy_built() const +{ + return true; +} + /* -------------------------------------------------------------------- */ /** \name Library override hierarchy building * \{ */ class OverrideIDHierarchyBuilder { SpaceOutliner &space_outliner_; + Main &bmain_; MainIDRelations &id_relations_; struct HierarchyBuildData { @@ -93,8 +100,10 @@ class OverrideIDHierarchyBuilder { }; public: - OverrideIDHierarchyBuilder(SpaceOutliner &space_outliner, MainIDRelations &id_relations) - : space_outliner_(space_outliner), id_relations_(id_relations) + OverrideIDHierarchyBuilder(SpaceOutliner &space_outliner, + Main &bmain, + MainIDRelations &id_relations) + : space_outliner_(space_outliner), bmain_(bmain), id_relations_(id_relations) { } @@ -115,7 +124,7 @@ ListBase TreeDisplayOverrideLibraryHierarchies::build_hierarchy_for_lib_or_main( * returning. */ BKE_main_relations_create(bmain, 0); - OverrideIDHierarchyBuilder builder(space_outliner_, *bmain->relations); + OverrideIDHierarchyBuilder builder(space_outliner_, *bmain, *bmain->relations); /* Keep track over which ID base elements were already added, and expand them once added. */ Map<ID_Type, TreeElement *> id_base_te_map; @@ -161,11 +170,16 @@ void OverrideIDHierarchyBuilder::build_hierarchy_for_ID(ID &override_root_id, build_hierarchy_for_ID_recursive(override_root_id, build_data, te_to_expand); } +enum ForeachChildReturn { + FOREACH_CONTINUE, + FOREACH_BREAK, +}; /* Helpers (defined below). */ static void foreach_natural_hierarchy_child(const MainIDRelations &id_relations, const ID &parent_id, - FunctionRef<void(ID &)> fn); -static bool id_is_in_override_hierarchy(const ID &id, + FunctionRef<ForeachChildReturn(ID &)> fn); +static bool id_is_in_override_hierarchy(const Main &bmain, + const ID &id, const ID &relationship_parent_id, const ID &override_root_id); @@ -177,20 +191,32 @@ void OverrideIDHierarchyBuilder::build_hierarchy_for_ID_recursive(const ID &pare build_data.parent_ids.add(&parent_id); foreach_natural_hierarchy_child(id_relations_, parent_id, [&](ID &id) { - if (!id_is_in_override_hierarchy(id, parent_id, build_data.override_root_id_)) { - return; + /* Some IDs can use themselves, early abort. */ + if (&id == &parent_id) { + return FOREACH_CONTINUE; + } + if (!id_is_in_override_hierarchy(bmain_, id, parent_id, build_data.override_root_id_)) { + return FOREACH_CONTINUE; } /* Avoid endless recursion: If there is an ancestor for this ID already, it recurses into * itself. */ if (build_data.parent_ids.lookup_key_default(&id, nullptr)) { - return; + return FOREACH_CONTINUE; } /* Avoid duplicates: If there is a sibling for this ID already, the same ID is just used * multiple times by the same parent. */ if (build_data.sibling_ids.lookup_key_default(&id, nullptr)) { - return; + return FOREACH_CONTINUE; + } + + /* We only want to add children whose parent isn't collapsed. Otherwise, in complex scenes with + * thousands of relationships, the building can slow down tremendously. Tag the parent to allow + * un-collapsing, but don't actually add the children. */ + if (!TSELEM_OPEN(TREESTORE(&te_to_expand), &space_outliner_)) { + te_to_expand.flag |= TE_PRETEND_HAS_CHILDREN; + return FOREACH_BREAK; } TreeElement *new_te = outliner_add_element( @@ -204,6 +230,8 @@ void OverrideIDHierarchyBuilder::build_hierarchy_for_ID_recursive(const ID &pare child_build_data.parent_ids.add(&id); child_build_data.sibling_ids.reserve(10); build_hierarchy_for_ID_recursive(id, child_build_data, *new_te); + + return FOREACH_CONTINUE; }); } @@ -229,7 +257,7 @@ void OverrideIDHierarchyBuilder::build_hierarchy_for_ID_recursive(const ID &pare */ static void foreach_natural_hierarchy_child(const MainIDRelations &id_relations, const ID &parent_id, - FunctionRef<void(ID &)> fn) + FunctionRef<ForeachChildReturn(ID &)> fn) { const MainIDRelationsEntry *relations_of_id = static_cast<MainIDRelationsEntry *>( BLI_ghash_lookup(id_relations.relations_from_pointers, &parent_id)); @@ -250,12 +278,16 @@ static void foreach_natural_hierarchy_child(const MainIDRelations &id_relations, if (GS(target_id.name) == ID_OB) { const Object &potential_child_ob = reinterpret_cast<const Object &>(target_id); if (potential_child_ob.parent) { - fn(potential_child_ob.parent->id); + if (fn(potential_child_ob.parent->id) == FOREACH_BREAK) { + return; + } continue; } } - fn(target_id); + if (fn(target_id) == FOREACH_BREAK) { + return; + } } /* If the ID is an object, find and iterate over any child objects. */ @@ -268,15 +300,20 @@ static void foreach_natural_hierarchy_child(const MainIDRelations &id_relations, continue; } - Object &potential_child_ob = reinterpret_cast<Object &>(potential_child_id); - if (potential_child_ob.parent && &potential_child_ob.parent->id == &parent_id) { - fn(potential_child_id); + const Object &potential_child_ob = reinterpret_cast<Object &>(potential_child_id); + if (!potential_child_ob.parent || &potential_child_ob.parent->id != &parent_id) { + continue; + } + + if (fn(potential_child_id) == FOREACH_BREAK) { + return; } } } } -static bool id_is_in_override_hierarchy(const ID &id, +static bool id_is_in_override_hierarchy(const Main &bmain, + const ID &id, const ID &relationship_parent_id, const ID &override_root_id) { @@ -286,20 +323,12 @@ static bool id_is_in_override_hierarchy(const ID &id, const ID *real_override_id = &id; if (ID_IS_OVERRIDE_LIBRARY_VIRTUAL(&id)) { - /* This assumes that the parent ID is always the owner of the 'embedded' one, I.e. that no - * other ID directly uses the embedded one. Should be true, but the debug code adds some checks - * to validate this assumption. */ - real_override_id = &relationship_parent_id; - -#ifndef NDEBUG - if (GS(id.name) == ID_KE) { - const Key *key = (Key *)&id; - BLI_assert(real_override_id == key->from); - } - else { - BLI_assert((id.flag & LIB_EMBEDDED_DATA) != 0); - } -#endif + /* In many cases, `relationship_parent_id` is the owner, but not always (e.g. there can be + * drivers directly between an object and a shape-key). */ + BKE_lib_override_library_get(const_cast<Main *>(&bmain), + const_cast<ID *>(&id), + const_cast<ID *>(&relationship_parent_id), + const_cast<ID **>(&real_override_id)); } if (!ID_IS_OVERRIDE_LIBRARY(real_override_id)) { |