diff options
Diffstat (limited to 'source/blender/blenkernel/intern/layer.c')
-rw-r--r-- | source/blender/blenkernel/intern/layer.c | 1272 |
1 files changed, 323 insertions, 949 deletions
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index da068802586..685c007da6b 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -31,12 +31,12 @@ #include "BLI_string.h" #include "BLI_string_utf8.h" #include "BLI_string_utils.h" +#include "BLI_threads.h" #include "BLT_translation.h" #include "BKE_collection.h" #include "BKE_freestyle.h" #include "BKE_global.h" -#include "BKE_group.h" #include "BKE_idprop.h" #include "BKE_layer.h" #include "BKE_main.h" @@ -61,24 +61,51 @@ #include "MEM_guardedalloc.h" + /* prototype */ -struct EngineSettingsCB_Type; -static void layer_collections_sync_flags(ListBase *layer_collections_dst, const ListBase *layer_collections_src); -static void layer_collection_free(ViewLayer *view_layer, LayerCollection *lc); -static void layer_collection_objects_populate(ViewLayer *view_layer, LayerCollection *lc, ListBase *objects); -static LayerCollection *layer_collection_add(ViewLayer *view_layer, LayerCollection *parent, SceneCollection *sc); -static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const SceneCollection *sc); static void object_bases_iterator_next(BLI_Iterator *iter, const int flag); + +/*********************** Layer Collections and bases *************************/ + +static LayerCollection *layer_collection_add(ListBase *lb_parent, Collection *collection) +{ + LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base"); + lc->collection = collection; + BLI_addtail(lb_parent, lc); + + return lc; +} + +static void layer_collection_free(ViewLayer *view_layer, LayerCollection *lc) +{ + if (lc == view_layer->active_collection) { + view_layer->active_collection = view_layer->layer_collections.first; + } + + for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { + layer_collection_free(view_layer, nlc); + } + + BLI_freelistN(&lc->layer_collections); +} + +static Base *object_base_new(Object *ob) +{ + Base *base = MEM_callocN(sizeof(Base), "Object Base"); + base->object = ob; + return base; +} + +/********************************* View Layer ********************************/ + + /* RenderLayer */ /* Returns the default view layer to view in workspaces if there is * none linked to the workspace yet. */ ViewLayer *BKE_view_layer_default_view(const Scene *scene) { - /* TODO: it makes more sense to have the Viewport layer as the default, - * but this breaks view layer tests so change it later. */ -#if 0 for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { if (!(view_layer->flag & VIEW_LAYER_RENDER)) { return view_layer; @@ -87,9 +114,6 @@ ViewLayer *BKE_view_layer_default_view(const Scene *scene) BLI_assert(scene->view_layers.first); return scene->view_layers.first; -#else - return BKE_view_layer_default_render(scene); -#endif } /* Returns the default view layer to render if we need to render just one. */ @@ -123,7 +147,7 @@ ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const Scene *scene) return scene->view_layers.first; } -static ViewLayer *view_layer_add(const char *name, SceneCollection *master_scene_collection) +static ViewLayer *view_layer_add(const char *name) { if (!name) { name = DATA_("View Layer"); @@ -134,9 +158,6 @@ static ViewLayer *view_layer_add(const char *name, SceneCollection *master_scene BLI_strncpy_utf8(view_layer->name, name, sizeof(view_layer->name)); - /* Link the master collection by default. */ - layer_collection_add(view_layer, NULL, master_scene_collection); - /* Pure rendering pipeline settings. */ view_layer->layflag = 0x7FFF; /* solid ztra halo edge strand */ view_layer->passflag = SCE_PASS_COMBINED | SCE_PASS_Z; @@ -152,8 +173,7 @@ static ViewLayer *view_layer_add(const char *name, SceneCollection *master_scene */ ViewLayer *BKE_view_layer_add(Scene *scene, const char *name) { - SceneCollection *sc = BKE_collection_master(&scene->id); - ViewLayer *view_layer = view_layer_add(name, sc); + ViewLayer *view_layer = view_layer_add(name); BLI_addtail(&scene->view_layers, view_layer); @@ -162,18 +182,8 @@ ViewLayer *BKE_view_layer_add(Scene *scene, const char *name) &scene->view_layers, view_layer, DATA_("ViewLayer"), '.', offsetof(ViewLayer, name), sizeof(view_layer->name)); - return view_layer; -} + BKE_layer_collection_sync(scene, view_layer); -/** - * Add a ViewLayer for a Group - * It should be added only once - */ -ViewLayer *BKE_view_layer_group_add(Group *group) -{ - BLI_assert(group->view_layer == NULL); - SceneCollection *sc = BKE_collection_master(&group->id); - ViewLayer *view_layer = view_layer_add(group->id.name + 2, sc); return view_layer; } @@ -191,8 +201,12 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user) BLI_freelistN(&view_layer->object_bases); + if (view_layer->object_bases_hash) { + BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL); + } + for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) { - layer_collection_free(NULL, lc); + layer_collection_free(view_layer, lc); } BLI_freelistN(&view_layer->layer_collections); @@ -235,22 +249,6 @@ void BKE_view_layer_selected_objects_tag(ViewLayer *view_layer, const int tag) } } -/** - * Return the first ViewLayer for a given id - */ -ViewLayer *BKE_view_layer_first_from_id(const ID *owner_id) -{ - switch (GS(owner_id->name)) { - case ID_SCE: - return ((Scene *)owner_id)->view_layers.first; - case ID_GR: - return ((Group *)owner_id)->view_layer; - default: - BLI_assert(!"ID doesn't support view layers"); - return NULL; - } -} - static bool find_scene_collection_in_scene_collections(ListBase *lb, const LayerCollection *lc) { for (LayerCollection *lcn = lb->first; lcn; lcn = lcn->next) { @@ -285,32 +283,43 @@ Object *BKE_view_layer_camera_find(ViewLayer *view_layer) /** * Find the ViewLayer a LayerCollection belongs to */ -ViewLayer *BKE_view_layer_find_from_collection(const ID *owner_id, LayerCollection *lc) +ViewLayer *BKE_view_layer_find_from_collection(const Scene *scene, LayerCollection *lc) { - switch (GS(owner_id->name)) { - case ID_GR: - return ((Group *)owner_id)->view_layer; - case ID_SCE: - { - Scene *scene = (Scene *)owner_id; - for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { - if (find_scene_collection_in_scene_collections(&view_layer->layer_collections, lc)) { - return view_layer; - } - } - return NULL; + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + if (find_scene_collection_in_scene_collections(&view_layer->layer_collections, lc)) { + return view_layer; } - default: - BLI_assert(!"ID doesn't support scene layers"); - return NULL; } + + return NULL; } /* Base */ +static void view_layer_bases_hash_create(ViewLayer *view_layer) +{ + static ThreadMutex hash_lock = BLI_MUTEX_INITIALIZER; + + if (!view_layer->object_bases_hash) { + BLI_mutex_lock(&hash_lock); + + view_layer->object_bases_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); + + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + BLI_ghash_insert(view_layer->object_bases_hash, base->object, base); + } + + BLI_mutex_unlock(&hash_lock); + } +} + Base *BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob) { - return BLI_findptr(&view_layer->object_bases, ob, offsetof(Base, object)); + if (!view_layer->object_bases_hash) { + view_layer_bases_hash_create(view_layer); + } + + return BLI_ghash_lookup(view_layer->object_bases_hash, ob); } void BKE_view_layer_base_deselect_all(ViewLayer *view_layer) @@ -330,134 +339,32 @@ void BKE_view_layer_base_select(struct ViewLayer *view_layer, Base *selbase) } } -/****************************************************************************/ -/* Copying functions for datablocks that use ViewLayer/SceneCollection */ +/**************************** Copy View Layer and Layer Collections ***********************/ -/* Find the equivalent SceneCollection in the new tree */ -static SceneCollection *scene_collection_from_new_tree( - SceneCollection *sc_reference, SceneCollection *sc_dst, SceneCollection *sc_src) +static void layer_collections_copy_data(ListBase *layer_collections_dst, const ListBase *layer_collections_src) { - if (sc_src == sc_reference) { - return sc_dst; - } + BLI_duplicatelist(layer_collections_dst, layer_collections_src); - for (SceneCollection *nsc_src = sc_src->scene_collections.first, *nsc_dst = sc_dst->scene_collections.first; - nsc_src; - nsc_src = nsc_src->next, nsc_dst = nsc_dst->next) - { - SceneCollection *found = scene_collection_from_new_tree(sc_reference, nsc_dst, nsc_src); - if (found != NULL) { - return found; - } - } - return NULL; -} - -static void layer_collection_sync_flags( - LayerCollection *layer_collection_dst, - const LayerCollection *layer_collection_src) -{ - layer_collection_dst->flag = layer_collection_src->flag; - - layer_collections_sync_flags(&layer_collection_dst->layer_collections, - &layer_collection_src->layer_collections); -} + LayerCollection *layer_collection_dst = layer_collections_dst->first; + const LayerCollection *layer_collection_src = layer_collections_src->first; -static void layer_collections_sync_flags(ListBase *layer_collections_dst, const ListBase *layer_collections_src) -{ - BLI_assert(BLI_listbase_count(layer_collections_dst) == BLI_listbase_count(layer_collections_src)); - LayerCollection *layer_collection_dst = (LayerCollection *)layer_collections_dst->first; - const LayerCollection *layer_collection_src = (const LayerCollection *)layer_collections_src->first; while (layer_collection_dst != NULL) { - layer_collection_sync_flags(layer_collection_dst, layer_collection_src); + layer_collections_copy_data(&layer_collection_dst->layer_collections, + &layer_collection_src->layer_collections); + layer_collection_dst = layer_collection_dst->next; layer_collection_src = layer_collection_src->next; } } -static bool layer_collection_sync_if_match( - ListBase *lb, - const SceneCollection *scene_collection_dst, - const SceneCollection *scene_collection_src) -{ - for (LayerCollection *layer_collection = lb->first; - layer_collection; - layer_collection = layer_collection->next) - { - if (layer_collection->scene_collection == scene_collection_src) { - LayerCollection *layer_collection_dst = - BLI_findptr( - lb, - scene_collection_dst, - offsetof(LayerCollection, scene_collection)); - - if (layer_collection_dst != NULL) { - layer_collection_sync_flags(layer_collection_dst, layer_collection); - } - return true; - } - else { - if (layer_collection_sync_if_match( - &layer_collection->layer_collections, - scene_collection_dst, - scene_collection_src)) - { - return true; - } - } - } - return false; -} - -/** - * Sync sibling collections across all view layers - * - * Make sure every linked instance of \a scene_collection_dst has the same values - * (flags, overrides, ...) as the corresponding scene_collection_src. - * - * \note expect scene_collection_dst to be scene_collection_src->next, and it also - * expects both collections to have the same ammount of sub-collections. - */ -void BKE_layer_collection_sync_flags( - ID *owner_id, - SceneCollection *scene_collection_dst, - SceneCollection *scene_collection_src) -{ - for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { - for (LayerCollection *layer_collection = view_layer->layer_collections.first; - layer_collection; - layer_collection = layer_collection->next) - { - layer_collection_sync_if_match( - &layer_collection->layer_collections, - scene_collection_dst, - scene_collection_src); - } - } -} - -/* recreate the LayerCollection tree */ -static void layer_collections_recreate( - ViewLayer *view_layer_dst, ListBase *lb_src, SceneCollection *mc_dst, SceneCollection *mc_src) -{ - for (LayerCollection *lc_src = lb_src->first; lc_src; lc_src = lc_src->next) { - SceneCollection *sc_dst = scene_collection_from_new_tree(lc_src->scene_collection, mc_dst, mc_src); - BLI_assert(sc_dst); - - /* instead of synchronizing both trees we simply re-create it */ - BKE_collection_link(view_layer_dst, sc_dst); - } -} - /** * Only copy internal data of ViewLayer from source to already allocated/initialized destination. * - * \param mc_src Master Collection the source ViewLayer links in. - * \param mc_dst Master Collection the destination ViewLayer links in. * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). */ void BKE_view_layer_copy_data( - ViewLayer *view_layer_dst, ViewLayer *view_layer_src, SceneCollection *mc_dst, SceneCollection *mc_src, + Scene *UNUSED(scene_dst), const Scene *UNUSED(scene_src), + ViewLayer *view_layer_dst, const ViewLayer *view_layer_src, const int flag) { if (view_layer_dst->id_properties != NULL) { @@ -467,176 +374,16 @@ void BKE_view_layer_copy_data( view_layer_dst->stats = NULL; - /* we start fresh with no overrides and no visibility flags set - * instead of syncing both trees we simply unlink and relink the scene collection */ - BLI_listbase_clear(&view_layer_dst->layer_collections); - BLI_listbase_clear(&view_layer_dst->object_bases); + /* Clear temporary data. */ BLI_listbase_clear(&view_layer_dst->drawdata); - - layer_collections_recreate(view_layer_dst, &view_layer_src->layer_collections, mc_dst, mc_src); - - /* Now we handle the syncing for visibility, selectability, ... */ - layer_collections_sync_flags(&view_layer_dst->layer_collections, &view_layer_src->layer_collections); - - Object *active_ob = OBACT(view_layer_src); - for (Base *base_src = view_layer_src->object_bases.first, *base_dst = view_layer_dst->object_bases.first; - base_src; - base_src = base_src->next, base_dst = base_dst->next) - { - base_dst->flag = base_src->flag; - base_dst->flag_legacy = base_src->flag_legacy; - - if (base_dst->object == active_ob) { - view_layer_dst->basact = base_dst; - } - } - view_layer_dst->object_bases_array = NULL; -} - -/** - * Find and return the ListBase of LayerCollection that has \a lc_child as one of its directly - * nested LayerCollection. - * - * \param lb_parent Initial ListBase of LayerCollection to look into recursively - * usually the view layer's collection list - */ -static ListBase *find_layer_collection_parent_list_base(ListBase *lb_parent, const LayerCollection *lc_child) -{ - for (LayerCollection *lc_nested = lb_parent->first; lc_nested; lc_nested = lc_nested->next) { - if (lc_nested == lc_child) { - return lb_parent; - } + view_layer_dst->object_bases_hash = NULL; - ListBase *found = find_layer_collection_parent_list_base(&lc_nested->layer_collections, lc_child); - if (found != NULL) { - return found; - } - } + /* Copy layer collections and object bases. */ + BLI_duplicatelist(&view_layer_dst->object_bases, &view_layer_src->object_bases); + layer_collections_copy_data(&view_layer_dst->layer_collections, &view_layer_src->layer_collections); - return NULL; -} - -/** - * Makes a shallow copy of a LayerCollection - * - * Add a new collection in the same level as the old one (linking if necessary), - * and copy all the collection data across them. - */ -struct LayerCollection *BKE_layer_collection_duplicate(struct ID *owner_id, struct LayerCollection *layer_collection) -{ - SceneCollection *scene_collection, *scene_collection_new; - - scene_collection = layer_collection->scene_collection; - scene_collection_new = BKE_collection_duplicate(owner_id, scene_collection); - - LayerCollection *layer_collection_new = NULL; - - /* If the original layer_collection was directly linked to the view layer - we need to link the new scene collection here as well. */ - for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { - if (BLI_findindex(&view_layer->layer_collections, layer_collection) != -1) { - layer_collection_new = BKE_collection_link(view_layer, scene_collection_new); - layer_collection_sync_flags(layer_collection_new, layer_collection); - - if (layer_collection_new != layer_collection->next) { - BLI_remlink(&view_layer->layer_collections, layer_collection_new); - BLI_insertlinkafter(&view_layer->layer_collections, layer_collection, layer_collection_new); - } - break; - } - } - - /* Otherwise just try to find the corresponding layer collection to return it back. */ - if (layer_collection_new == NULL) { - for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { - ListBase *layer_collections_parent; - layer_collections_parent = find_layer_collection_parent_list_base( - &view_layer->layer_collections, - layer_collection); - if (layer_collections_parent != NULL) { - layer_collection_new = BLI_findptr( - layer_collections_parent, - scene_collection_new, - offsetof(LayerCollection, scene_collection)); - break; - } - } - } - return layer_collection_new; -} - -static void view_layer_object_base_unref(ViewLayer *view_layer, Base *base) -{ - base->refcount--; - - /* It only exists in the RenderLayer */ - if (base->refcount == 0) { - if (view_layer->basact == base) { - view_layer->basact = NULL; - } - - BLI_remlink(&view_layer->object_bases, base); - MEM_freeN(base); - } -} - -/** - * Return the base if existent, or create it if necessary - * Always bump the refcount - */ -static Base *object_base_add(ViewLayer *view_layer, Object *ob) -{ - Base *base; - base = BKE_view_layer_base_find(view_layer, ob); - - if (base == NULL) { - base = MEM_callocN(sizeof(Base), "Object Base"); - - /* Do not bump user count, leave it for SceneCollections. */ - base->object = ob; - BLI_addtail(&view_layer->object_bases, base); - } - - base->refcount++; - return base; -} - -/* LayerCollection */ - -static void layer_collection_objects_unpopulate(ViewLayer *view_layer, LayerCollection *lc) -{ - if (view_layer) { - for (LinkData *link = lc->object_bases.first; link; link = link->next) { - view_layer_object_base_unref(view_layer, link->data); - } - } - - BLI_freelistN(&lc->object_bases); -} - -/** - * When freeing the entire ViewLayer at once we don't bother with unref - * otherwise ViewLayer is passed to keep the syncing of the LayerCollection tree - */ -static void layer_collection_free(ViewLayer *view_layer, LayerCollection *lc) -{ - layer_collection_objects_unpopulate(view_layer, lc); - - for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { - layer_collection_free(view_layer, nlc); - } - - BLI_freelistN(&lc->layer_collections); -} - -/** - * Free (or release) LayerCollection from ViewLayer - * (does not free the LayerCollection itself). - */ -void BKE_layer_collection_free(ViewLayer *view_layer, LayerCollection *lc) -{ - layer_collection_free(view_layer, lc); + // TODO: not always safe to free BKE_layer_collection_sync(scene_dst, view_layer_dst); } /* LayerCollection */ @@ -675,28 +422,46 @@ LayerCollection *BKE_layer_collection_from_index(ViewLayer *view_layer, const in */ LayerCollection *BKE_layer_collection_get_active(ViewLayer *view_layer) { - int i = 0; - return collection_from_index(&view_layer->layer_collections, view_layer->active_collection, &i); + return view_layer->active_collection; } +/* + * Activate collection + */ +bool BKE_layer_collection_activate(ViewLayer *view_layer, LayerCollection *lc) +{ + if (lc->flag & LAYER_COLLECTION_EXCLUDE) { + return false; + } + + view_layer->active_collection = lc; + return true; +} /** - * Return layer collection to add new object(s). - * Create one if none exists. + * Activate first parent collection */ -LayerCollection *BKE_layer_collection_get_active_ensure(Scene *scene, ViewLayer *view_layer) +LayerCollection *BKE_layer_collection_activate_parent(ViewLayer *view_layer, LayerCollection *lc) { - LayerCollection *lc = BKE_layer_collection_get_active(view_layer); + CollectionParent *parent = lc->collection->parents.first; + + if (parent) { + lc = BKE_layer_collection_first_from_scene_collection(view_layer, parent->collection); + } + else { + lc = NULL; + } + + if (lc && (lc->flag & LAYER_COLLECTION_EXCLUDE)) { + /* Don't activate excluded collections. */ + return BKE_layer_collection_activate_parent(view_layer, lc); + } - if (lc == NULL) { - BLI_assert(BLI_listbase_is_empty(&view_layer->layer_collections)); - /* When there is no collection linked to this ViewLayer, create one. */ - SceneCollection *sc = BKE_collection_add(&scene->id, NULL, COLLECTION_TYPE_NONE, NULL); - lc = BKE_collection_link(view_layer, sc); - /* New collection has to be the active one. */ - BLI_assert(lc == BKE_layer_collection_get_active(view_layer)); + if (!lc) { + lc = view_layer->layer_collections.first; } + view_layer->active_collection = lc; return lc; } @@ -750,348 +515,208 @@ int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection return index_from_collection(&view_layer->layer_collections, lc, &i); } -/** - * Lookup the listbase that contains \a lc. - */ -static ListBase *layer_collection_listbase_find(ListBase *lb, LayerCollection *lc) -{ - for (LayerCollection *lc_iter = lb->first; lc_iter; lc_iter = lc_iter->next) { - if (lc_iter == lc) { - return lb; +/*********************************** Syncing ********************************* + * + * The layer collection tree mirrors the scene collection tree. Whenever that + * changes we need to synchronize them so that there is a corresponding layer + * collection for each collection. Note that the scene collection tree can + * contain link or override collections, and so this is also called on .blend + * file load to ensure any new or removed collections are synced. + * + * The view layer also contains a list of bases for each object that exists + * in at least one layer collection. That list is also synchronized here, and + * stores state like selection. */ + +static void layer_collection_sync(ViewLayer *view_layer, + const ListBase *lb_scene, + ListBase *lb_layer, + ListBase *new_object_bases, + int parent_exclude, + int parent_restrict) +{ + /* TODO: support recovery after removal of intermediate collections, reordering, .. + * For local edits we can make editing operating do the appropriate thing, but for + * linking we can only sync after the fact. */ + + /* Remove layer collections that no longer have a corresponding scene collection. */ + for (LayerCollection *lc = lb_layer->first; lc;) { + /* Note ID remap can set lc->collection to NULL when deleting collections. */ + LayerCollection *lc_next = lc->next; + Collection *collection = (lc->collection) ? BLI_findptr(lb_scene, lc->collection, offsetof(CollectionChild, collection)) : NULL; + + if (!collection) { + /* Free recursively. */ + layer_collection_free(view_layer, lc); + BLI_freelinkN(lb_layer, lc); } - ListBase *lb_child_result; - if ((lb_child_result = layer_collection_listbase_find(&lc_iter->layer_collections, lc))) { - return lb_child_result; - } + lc = lc_next; } - return NULL; -} + /* Add layer collections for any new scene collections, and ensure order is the same. */ + ListBase new_lb_layer = {NULL, NULL}; -#if 0 -/** - * Lookup the listbase that contains \a sc. - */ -static ListBase *scene_collection_listbase_find(ListBase *lb, SceneCollection *sc) -{ - for (SceneCollection *sc_iter = lb->first; sc_iter; sc_iter = sc_iter->next) { - if (sc_iter == sc) { - return lb; + for (const CollectionChild *child = lb_scene->first; child; child = child->next) { + Collection *collection = child->collection; + LayerCollection *lc = BLI_findptr(lb_layer, collection, offsetof(LayerCollection, collection)); + + if (lc) { + BLI_remlink(lb_layer, lc); + BLI_addtail(&new_lb_layer, lc); + } + else { + lc = layer_collection_add(&new_lb_layer, collection); + lc->flag = parent_exclude; } - ListBase *lb_child_result; - if ((lb_child_result = scene_collection_listbase_find(&sc_iter->scene_collections, sc))) { - return lb_child_result; + /* Collection restrict is inherited. */ + int child_restrict = parent_restrict; + if (!(collection->flag & COLLECTION_IS_MASTER)) { + child_restrict |= collection->flag; } - } - return NULL; -} -#endif + /* Sync child collections. */ + layer_collection_sync(view_layer, &collection->children, &lc->layer_collections, new_object_bases, lc->flag, child_restrict); -/* ---------------------------------------------------------------------- */ -/* Outliner drag and drop */ + /* Layer collection exclude is not inherited. */ + if (lc->flag & LAYER_COLLECTION_EXCLUDE) { + continue; + } -/** - * Nest a LayerCollection into another one - * Both collections must be from the same ViewLayer, return true if succeded. - * - * The LayerCollection will effectively be moved into the - * new (nested) position. So all the settings, overrides, ... go with it, and - * if the collection was directly linked to the ViewLayer it's then unlinked. - * - * For the other ViewLayers we simply resync the tree, without changing directly - * linked collections (even if they link to the same SceneCollection) - * - * \param lc_src LayerCollection to nest into \a lc_dst - * \param lc_dst LayerCollection to have \a lc_src inserted into - */ + /* Sync objects, except if collection was excluded. */ + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + Base *base = BLI_ghash_lookup(view_layer->object_bases_hash, cob->ob); + + if (base) { + /* Move from old base list to new base list. Base might have already + * been moved to the new base list and the first/last test ensure that + * case also works. */ + if (!ELEM(base, new_object_bases->first, new_object_bases->last)) { + BLI_remlink(&view_layer->object_bases, base); + BLI_addtail(new_object_bases, base); + } + } + else { + /* Create new base. */ + base = object_base_new(cob->ob); + BLI_addtail(new_object_bases, base); + BLI_ghash_insert(view_layer->object_bases_hash, base->object, base); + } -static void layer_collection_swap( - ViewLayer *view_layer, ListBase *lb_a, ListBase *lb_b, - LayerCollection *lc_a, LayerCollection *lc_b) -{ - if (lb_a == NULL) { - lb_a = layer_collection_listbase_find(&view_layer->layer_collections, lc_a); - } + if ((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) { + base->flag |= BASE_VISIBLED | BASE_VISIBLE_VIEWPORT; - if (lb_b == NULL) { - lb_b = layer_collection_listbase_find(&view_layer->layer_collections, lc_b); + if ((child_restrict & COLLECTION_RESTRICT_SELECT) == 0) { + base->flag |= BASE_SELECTABLED; + } + } + if ((child_restrict & COLLECTION_RESTRICT_RENDER) == 0) { + base->flag |= BASE_VISIBLE_RENDER; + } + } } - BLI_assert(lb_a); - BLI_assert(lb_b); - - BLI_listbases_swaplinks(lb_a, lb_b, lc_a, lc_b); + /* Replace layer collection list with new one. */ + *lb_layer = new_lb_layer; + BLI_assert(BLI_listbase_count(lb_scene) == BLI_listbase_count(lb_layer)); } /** - * Move \a lc_src into \a lc_dst. Both have to be stored in \a view_layer. - * If \a lc_src is directly linked to the ViewLayer it's unlinked + * Update view layer collection tree from collections used in the scene. + * This is used when collections are removed or added, both while editing + * and on file loaded in case linked data changed or went missing. */ -bool BKE_layer_collection_move_into(const ID *owner_id, LayerCollection *lc_dst, LayerCollection *lc_src) +void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer) { - ViewLayer *view_layer = BKE_view_layer_find_from_collection(owner_id, lc_src); - bool is_directly_linked = false; - - if ((!view_layer) || (view_layer != BKE_view_layer_find_from_collection(owner_id, lc_dst))) { - return false; - } - - /* We can't nest the collection into itself */ - if (lc_src->scene_collection == lc_dst->scene_collection) { - return false; - } - - /* Collection is already where we wanted it to be */ - if (lc_dst->layer_collections.last == lc_src) { - return false; + if (!scene->master_collection) { + /* Happens for old files that don't have versioning applied yet. */ + return; } - /* Collection is already where we want it to be in the scene tree - * but we want to swap it in the layer tree still */ - if (lc_dst->scene_collection->scene_collections.last == lc_src->scene_collection) { - LayerCollection *lc_swap = lc_dst->layer_collections.last; - layer_collection_swap(view_layer, &lc_dst->layer_collections, NULL, lc_dst->layer_collections.last, lc_src); - - if (BLI_findindex(&view_layer->layer_collections, lc_swap) != -1) { - BKE_collection_unlink(view_layer, lc_swap); - } - return true; - } - else { - LayerCollection *lc_temp; - is_directly_linked = BLI_findindex(&view_layer->layer_collections, lc_src) != -1; - - if (!is_directly_linked) { - /* lc_src will be invalid after BKE_collection_move_into! - * so we swap it with lc_temp to preserve its settings */ - lc_temp = BKE_collection_link(view_layer, lc_src->scene_collection); - layer_collection_swap(view_layer, &view_layer->layer_collections, NULL, lc_temp, lc_src); - } + /* Free cache. */ + MEM_SAFE_FREE(view_layer->object_bases_array); - if (!BKE_collection_move_into(owner_id, lc_dst->scene_collection, lc_src->scene_collection)) { - if (!is_directly_linked) { - /* Swap back and remove */ - layer_collection_swap(view_layer, NULL, NULL, lc_temp, lc_src); - BKE_collection_unlink(view_layer, lc_temp); - } - return false; - } + /* Create object to base hash if it does not exist yet. */ + if (!view_layer->object_bases_hash) { + view_layer_bases_hash_create(view_layer); } - LayerCollection *lc_new = BLI_findptr( - &lc_dst->layer_collections, lc_src->scene_collection, offsetof(LayerCollection, scene_collection)); - BLI_assert(lc_new); - layer_collection_swap(view_layer, &lc_dst->layer_collections, NULL, lc_new, lc_src); - - /* If it's directly linked, unlink it after the swap */ - if (BLI_findindex(&view_layer->layer_collections, lc_new) != -1) { - BKE_collection_unlink(view_layer, lc_new); + /* Clear visible and selectable flags to be reset. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + base->flag &= ~(BASE_VISIBLED | BASE_SELECTABLED | BASE_VISIBLE_VIEWPORT | BASE_VISIBLE_RENDER); } - return true; -} + /* Generate new layer connections and object bases when collections changed. */ + CollectionChild child = {NULL, NULL, scene->master_collection}; + const ListBase collections = {&child, &child}; + ListBase new_object_bases = {NULL, NULL}; -/** - * Move \a lc_src above \a lc_dst. Both have to be stored in \a view_layer. - * If \a lc_src is directly linked to the ViewLayer it's unlinked - */ -bool BKE_layer_collection_move_above(const ID *owner_id, LayerCollection *lc_dst, LayerCollection *lc_src) -{ - ViewLayer *view_layer = BKE_view_layer_find_from_collection(owner_id, lc_src); - const bool is_directly_linked_src = BLI_findindex(&view_layer->layer_collections, lc_src) != -1; - const bool is_directly_linked_dst = BLI_findindex(&view_layer->layer_collections, lc_dst) != -1; + const int parent_exclude = 0, parent_restrict = 0; + layer_collection_sync(view_layer, &collections, &view_layer->layer_collections, &new_object_bases, parent_exclude, parent_restrict); - if ((!view_layer) || (view_layer != BKE_view_layer_find_from_collection(owner_id, lc_dst))) { - return false; - } + /* Any remaning object bases are to be removed. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if (view_layer->basact == base) { + view_layer->basact = NULL; + } - /* Collection is already where we wanted it to be */ - if (lc_dst->prev == lc_src) { - return false; + BLI_ghash_remove(view_layer->object_bases_hash, base->object, NULL, NULL); } - /* Collection is already where we want it to be in the scene tree - * but we want to swap it in the layer tree still */ - if (lc_dst->prev && lc_dst->prev->scene_collection == lc_src->scene_collection) { - LayerCollection *lc_swap = lc_dst->prev; - layer_collection_swap(view_layer, NULL, NULL, lc_dst->prev, lc_src); - - if (BLI_findindex(&view_layer->layer_collections, lc_swap) != -1) { - BKE_collection_unlink(view_layer, lc_swap); - } - return true; - } - /* We don't allow to move above/below a directly linked collection - * unless the source collection is also directly linked */ - else if (is_directly_linked_dst) { - /* Both directly linked to the ViewLayer, just need to swap */ - if (is_directly_linked_src) { - BLI_remlink(&view_layer->layer_collections, lc_src); - BLI_insertlinkbefore(&view_layer->layer_collections, lc_dst, lc_src); - return true; - } - else { - return false; - } - } - else { - LayerCollection *lc_temp; + BLI_freelistN(&view_layer->object_bases); + view_layer->object_bases = new_object_bases; - if (!is_directly_linked_src) { - /* lc_src will be invalid after BKE_collection_move_into! - * so we swap it with lc_temp to preserve its settings */ - lc_temp = BKE_collection_link(view_layer, lc_src->scene_collection); - layer_collection_swap(view_layer, &view_layer->layer_collections, NULL, lc_temp, lc_src); - } + /* Always set a valid active collection. */ + LayerCollection *active = view_layer->active_collection; - if (!BKE_collection_move_above(owner_id, lc_dst->scene_collection, lc_src->scene_collection)) { - if (!is_directly_linked_src) { - /* Swap back and remove */ - layer_collection_swap(view_layer, NULL, NULL, lc_temp, lc_src); - BKE_collection_unlink(view_layer, lc_temp); - } - return false; - } + if (active && (active->flag & LAYER_COLLECTION_EXCLUDE)) { + BKE_layer_collection_activate_parent(view_layer, active); } - - LayerCollection *lc_new = lc_dst->prev; - BLI_assert(lc_new); - layer_collection_swap(view_layer, NULL, NULL, lc_new, lc_src); - - /* If it's directly linked, unlink it after the swap */ - if (BLI_findindex(&view_layer->layer_collections, lc_new) != -1) { - BKE_collection_unlink(view_layer, lc_new); + else if (active == NULL) { + view_layer->active_collection = view_layer->layer_collections.first; } - - return true; } -/** - * Move \a lc_src below \a lc_dst. Both have to be stored in \a view_layer. - * If \a lc_src is directly linked to the ViewLayer it's unlinked - */ -bool BKE_layer_collection_move_below(const ID *owner_id, LayerCollection *lc_dst, LayerCollection *lc_src) +void BKE_scene_collection_sync(const Scene *scene) { - ViewLayer *view_layer = BKE_view_layer_find_from_collection(owner_id, lc_src); - const bool is_directly_linked_src = BLI_findindex(&view_layer->layer_collections, lc_src) != -1; - const bool is_directly_linked_dst = BLI_findindex(&view_layer->layer_collections, lc_dst) != -1; - - if ((!view_layer) || (view_layer != BKE_view_layer_find_from_collection(owner_id, lc_dst))) { - return false; - } - - /* Collection is already where we wanted it to be */ - if (lc_dst->next == lc_src) { - return false; - } - - /* Collection is already where we want it to be in the scene tree - * but we want to swap it in the layer tree still */ - if (lc_dst->next && lc_dst->next->scene_collection == lc_src->scene_collection) { - LayerCollection *lc_swap = lc_dst->next; - layer_collection_swap(view_layer, NULL, NULL, lc_dst->next, lc_src); - - if (BLI_findindex(&view_layer->layer_collections, lc_swap) != -1) { - BKE_collection_unlink(view_layer, lc_swap); - } - return true; - } - /* We don't allow to move above/below a directly linked collection - * unless the source collection is also directly linked */ - else if (is_directly_linked_dst) { - /* Both directly linked to the ViewLayer, just need to swap */ - if (is_directly_linked_src) { - BLI_remlink(&view_layer->layer_collections, lc_src); - BLI_insertlinkafter(&view_layer->layer_collections, lc_dst, lc_src); - return true; - } - else { - return false; - } + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + BKE_layer_collection_sync(scene, view_layer); } - else { - LayerCollection *lc_temp; - - if (!is_directly_linked_src) { - /* lc_src will be invalid after BKE_collection_move_into! - * so we swap it with lc_temp to preserve its settings */ - lc_temp = BKE_collection_link(view_layer, lc_src->scene_collection); - layer_collection_swap(view_layer, &view_layer->layer_collections, NULL, lc_temp, lc_src); - } +} - if (!BKE_collection_move_below(owner_id, lc_dst->scene_collection, lc_src->scene_collection)) { - if (!is_directly_linked_src) { - /* Swap back and remove */ - layer_collection_swap(view_layer, NULL, NULL, lc_temp, lc_src); - BKE_collection_unlink(view_layer, lc_temp); - } - return false; - } - } +void BKE_main_collection_sync(const Main *bmain) +{ + /* TODO: if a single collection changed, figure out which + * scenes it belongs to and only update those. */ - LayerCollection *lc_new = lc_dst->next; - BLI_assert(lc_new); - layer_collection_swap(view_layer, NULL, NULL, lc_new, lc_src); + /* TODO: optimize for file load so only linked collections get checked? */ - /* If it's directly linked, unlink it after the swap */ - if (BLI_findindex(&view_layer->layer_collections, lc_new) != -1) { - BKE_collection_unlink(view_layer, lc_new); + for (const Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + BKE_scene_collection_sync(scene); } - - return true; } -static bool layer_collection_resync(ViewLayer *view_layer, LayerCollection *lc, const SceneCollection *sc) +void BKE_main_collection_sync_remap(const Main *bmain) { - if (lc->scene_collection == sc) { - ListBase collections = {NULL}; - BLI_movelisttolist(&collections, &lc->layer_collections); + /* On remapping of object or collection pointers free caches. */ + /* TODO: try to make this faster */ - for (SceneCollection *sc_nested = sc->scene_collections.first; sc_nested; sc_nested = sc_nested->next) { - LayerCollection *lc_nested = BLI_findptr(&collections, sc_nested, offsetof(LayerCollection, scene_collection)); - if (lc_nested) { - BLI_remlink(&collections, lc_nested); - BLI_addtail(&lc->layer_collections, lc_nested); - } - else { - layer_collection_add(view_layer, lc, sc_nested); - } - } + for (const Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + MEM_SAFE_FREE(view_layer->object_bases_array); - for (LayerCollection *lc_nested = collections.first; lc_nested; lc_nested = lc_nested->next) { - layer_collection_free(view_layer, lc_nested); + if (view_layer->object_bases_hash) { + BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL); + view_layer->object_bases_hash = NULL; + } } - BLI_freelistN(&collections); - - BLI_assert(BLI_listbase_count(&lc->layer_collections) == - BLI_listbase_count(&sc->scene_collections)); - - return true; } - for (LayerCollection *lc_nested = lc->layer_collections.first; lc_nested; lc_nested = lc_nested->next) { - if (layer_collection_resync(view_layer, lc_nested, sc)) { - return true; - } + for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) { + BKE_collection_object_cache_free(collection); } - return false; -} - -/** - * Update the scene layers so that any LayerCollection that points - * to \a sc is re-synced again - */ -void BKE_layer_collection_resync(const ID *owner_id, const SceneCollection *sc) -{ - for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { - for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) { - layer_collection_resync(view_layer, lc, sc); - } - } + BKE_main_collection_sync(bmain); } /* ---------------------------------------------------------------------- */ @@ -1102,161 +727,69 @@ void BKE_layer_collection_resync(const ID *owner_id, const SceneCollection *sc) * It also select the objects that are in nested collections. * \note Recursive */ -void BKE_layer_collection_objects_select(struct LayerCollection *layer_collection) +bool BKE_layer_collection_objects_select(ViewLayer *view_layer, LayerCollection *lc, bool deselect) { - if ((layer_collection->flag & COLLECTION_DISABLED) || - ((layer_collection->flag & COLLECTION_SELECTABLE) == 0)) - { - return; - } - - for (LinkData *link = layer_collection->object_bases.first; link; link = link->next) { - Base *base = link->data; - if (base->flag & BASE_SELECTABLED) { - base->flag |= BASE_SELECTED; - } - } - - for (LayerCollection *iter = layer_collection->layer_collections.first; iter; iter = iter->next) { - BKE_layer_collection_objects_select(iter); - } -} - -/* ---------------------------------------------------------------------- */ - -/** - * Link a collection to a renderlayer - * The collection needs to be created separately - */ -LayerCollection *BKE_collection_link(ViewLayer *view_layer, SceneCollection *sc) -{ - LayerCollection *lc = layer_collection_add(view_layer, NULL, sc); - view_layer->active_collection = BKE_layer_collection_findindex(view_layer, lc); - return lc; -} - -/** - * Unlink a collection base from a renderlayer - * The corresponding collection is not removed from the master collection - */ -void BKE_collection_unlink(ViewLayer *view_layer, LayerCollection *lc) -{ - BKE_layer_collection_free(view_layer, lc); - BLI_remlink(&view_layer->layer_collections, lc); - MEM_freeN(lc); - view_layer->active_collection = 0; -} - -/** - * Recursively enable nested collections - */ -static void layer_collection_enable(ViewLayer *view_layer, LayerCollection *lc) -{ - layer_collection_objects_populate(view_layer, lc, &lc->scene_collection->objects); - - for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { - layer_collection_enable(view_layer, nlc); - } -} - -/** - * Enable collection - * Add its objects bases to ViewLayer - * - * Only around for doversion. - */ -void BKE_collection_enable(ViewLayer *view_layer, LayerCollection *lc) -{ - if ((lc->flag & COLLECTION_DISABLED) == 0) { - return; + if (lc->collection->flag & COLLECTION_RESTRICT_SELECT) { + return false; } - lc->flag &= ~COLLECTION_DISABLED; - layer_collection_enable(view_layer, lc); -} - -static void layer_collection_object_add(ViewLayer *view_layer, LayerCollection *lc, Object *ob) -{ - Base *base = object_base_add(view_layer, ob); - - /* Only add an object once. */ - if (BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data))) { - return; - } + bool changed = false; - bool is_visible = ((lc->flag & COLLECTION_VIEWPORT) != 0) && ((lc->flag & COLLECTION_DISABLED) == 0); - bool is_selectable = is_visible && ((lc->flag & COLLECTION_SELECTABLE) != 0); + if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) { + for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) { + Base *base = BKE_view_layer_base_find(view_layer, cob->ob); - if (is_visible) { - base->flag |= BASE_VISIBLED; + if (base) { + if (deselect) { + if (base->flag & BASE_SELECTED) { + base->flag &= ~BASE_SELECTED; + changed = true; + } + } + else { + if ((base->flag & BASE_SELECTABLED) && !(base->flag & BASE_SELECTED)) { + base->flag |= BASE_SELECTED; + changed = true; + } + } + } + } } - if (is_selectable) { - base->flag |= BASE_SELECTABLED; + for (LayerCollection *iter = lc->layer_collections.first; iter; iter = iter->next) { + changed |= BKE_layer_collection_objects_select(view_layer, iter, deselect); } - BLI_addtail(&lc->object_bases, BLI_genericNodeN(base)); + return changed; } -static void layer_collection_object_remove(ViewLayer *view_layer, LayerCollection *lc, Object *ob) -{ - Base *base; - base = BKE_view_layer_base_find(view_layer, ob); - - LinkData *link = BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data)); - BLI_remlink(&lc->object_bases, link); - MEM_freeN(link); - - view_layer_object_base_unref(view_layer, base); -} +/* ---------------------------------------------------------------------- */ -static void layer_collection_objects_populate(ViewLayer *view_layer, LayerCollection *lc, ListBase *objects) +static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const Collection *collection) { - for (LinkData *link = objects->first; link; link = link->next) { - layer_collection_object_add(view_layer, lc, link->data); + if (lc->collection == collection) { + return lc; } -} -static void layer_collection_populate(ViewLayer *view_layer, LayerCollection *lc, SceneCollection *sc) -{ - layer_collection_objects_populate(view_layer, lc, &sc->objects); - - for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { - layer_collection_add(view_layer, lc, nsc); - } -} - -static LayerCollection *layer_collection_add(ViewLayer *view_layer, LayerCollection *parent, SceneCollection *sc) -{ - LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base"); - - lc->scene_collection = sc; - lc->flag = COLLECTION_SELECTABLE | COLLECTION_VIEWPORT | COLLECTION_RENDER; - - if (parent != NULL) { - BLI_addtail(&parent->layer_collections, lc); - } - else { - BLI_addtail(&view_layer->layer_collections, lc); + for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { + LayerCollection *found = find_layer_collection_by_scene_collection(nlc, collection); + if (found) { + return found; + } } - - layer_collection_populate(view_layer, lc, sc); - - return lc; + return NULL; } -/* ---------------------------------------------------------------------- */ - /** - * Return the first matching LayerCollection in the ViewLayer for the SceneCollection. + * Return the first matching LayerCollection in the ViewLayer for the Collection. */ -LayerCollection *BKE_layer_collection_first_from_scene_collection(ViewLayer *view_layer, const SceneCollection *scene_collection) +LayerCollection *BKE_layer_collection_first_from_scene_collection(ViewLayer *view_layer, const Collection *collection) { for (LayerCollection *layer_collection = view_layer->layer_collections.first; layer_collection != NULL; layer_collection = layer_collection->next) { - LayerCollection *found = find_layer_collection_by_scene_collection(layer_collection, scene_collection); + LayerCollection *found = find_layer_collection_by_scene_collection(layer_collection, collection); if (found != NULL) { return found; @@ -1268,9 +801,9 @@ LayerCollection *BKE_layer_collection_first_from_scene_collection(ViewLayer *vie /** * See if view layer has the scene collection linked directly, or indirectly (nested) */ -bool BKE_view_layer_has_collection(ViewLayer *view_layer, const SceneCollection *scene_collection) +bool BKE_view_layer_has_collection(ViewLayer *view_layer, const Collection *collection) { - return BKE_layer_collection_first_from_scene_collection(view_layer, scene_collection) != NULL; + return BKE_layer_collection_first_from_scene_collection(view_layer, collection) != NULL; } /** @@ -1287,70 +820,6 @@ bool BKE_scene_has_object(Scene *scene, Object *ob) return false; } - -/* ---------------------------------------------------------------------- */ -/* Syncing */ - -static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const SceneCollection *sc) -{ - if (lc->scene_collection == sc) { - return lc; - } - - for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { - LayerCollection *found = find_layer_collection_by_scene_collection(nlc, sc); - if (found) { - return found; - } - } - return NULL; -} - -/** - * Add a new LayerCollection for all the ViewLayers that have sc_parent - */ -void BKE_layer_sync_new_scene_collection(ID *owner_id, const SceneCollection *sc_parent, SceneCollection *sc) -{ - for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { - for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) { - LayerCollection *lc_parent = find_layer_collection_by_scene_collection(lc, sc_parent); - if (lc_parent) { - layer_collection_add(view_layer, lc_parent, sc); - } - } - } -} - -/** - * Add a corresponding ObjectBase to all the equivalent LayerCollection - */ -void BKE_layer_sync_object_link(const ID *owner_id, SceneCollection *sc, Object *ob) -{ - for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { - for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) { - LayerCollection *found = find_layer_collection_by_scene_collection(lc, sc); - if (found) { - layer_collection_object_add(view_layer, found, ob); - } - } - } -} - -/** - * Remove the equivalent object base to all layers that have this collection - */ -void BKE_layer_sync_object_unlink(const ID *owner_id, SceneCollection *sc, Object *ob) -{ - for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { - for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) { - LayerCollection *found = find_layer_collection_by_scene_collection(lc, sc); - if (found) { - layer_collection_object_remove(view_layer, found, ob); - } - } - } -} - /* ---------------------------------------------------------------------- */ /* Override */ @@ -1677,93 +1146,28 @@ void BKE_view_layer_bases_in_mode_iterator_end(BLI_Iterator *UNUSED(iter)) /* Evaluation */ -static void layer_eval_layer_collection_pre(Depsgraph *depsgraph, ID *UNUSED(owner_id), ViewLayer *view_layer) +void BKE_layer_eval_view_layer(struct Depsgraph *depsgraph, + struct Scene *UNUSED(scene), + ViewLayer *view_layer) { DEG_debug_print_eval(depsgraph, __func__, view_layer->name, view_layer); - //Scene *scene = (GS(owner_id->name) == ID_SCE) ? (Scene *)owner_id : NULL; - for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) { - base->flag &= ~(BASE_VISIBLED | BASE_SELECTABLED); - } + /* Set visibility based on depsgraph mode. */ + const eEvaluationMode mode = DEG_get_mode(depsgraph); + const int base_flag = (mode == DAG_EVAL_VIEWPORT) ? BASE_VISIBLE_VIEWPORT : BASE_VISIBLE_RENDER; - /* TODO(sergey): Is it always required? */ - view_layer->flag |= VIEW_LAYER_ENGINE_DIRTY; -} - -static const char *collection_type_lookup[] = -{ - "None", /* COLLECTION_TYPE_NONE */ - "Group Internal", /* COLLECTION_TYPE_GROUP_INTERNAL */ -}; - -/** - * \note We can't use layer_collection->flag because of 3 level nesting (where parent is visible, but not grand-parent) - * So layer_collection->flag_evaluated is expected to be up to date with layer_collection->flag. - */ -static bool layer_collection_visible_get(Depsgraph *depsgraph, LayerCollection *layer_collection) -{ - if (layer_collection->flag_evaluated & COLLECTION_DISABLED) { - return false; - } - - if (DEG_get_mode(depsgraph) == DAG_EVAL_VIEWPORT) { - return (layer_collection->flag_evaluated & COLLECTION_VIEWPORT) != 0; - } - else { - return (layer_collection->flag_evaluated & COLLECTION_RENDER) != 0; - } -} - -static void layer_eval_layer_collection(Depsgraph *depsgraph, - LayerCollection *layer_collection, - LayerCollection *parent_layer_collection) -{ - DEG_debug_print_eval_parent_typed( - depsgraph, - __func__, - layer_collection->scene_collection->name, - layer_collection->scene_collection, - collection_type_lookup[layer_collection->scene_collection->type], - "parent", - (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection->name : "NONE", - (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection : NULL, - (parent_layer_collection != NULL) ? collection_type_lookup[parent_layer_collection->scene_collection->type] : ""); - BLI_assert(layer_collection != parent_layer_collection); - - /* visibility */ - layer_collection->flag_evaluated = layer_collection->flag; - - if (parent_layer_collection != NULL) { - if (layer_collection_visible_get(depsgraph, parent_layer_collection) == false) { - layer_collection->flag_evaluated |= COLLECTION_DISABLED; - } - - if ((parent_layer_collection->flag_evaluated & COLLECTION_DISABLED) || - (parent_layer_collection->flag_evaluated & COLLECTION_SELECTABLE) == 0) - { - layer_collection->flag_evaluated &= ~COLLECTION_SELECTABLE; - } - } - - const bool is_visible = layer_collection_visible_get(depsgraph, layer_collection); - const bool is_selectable = is_visible && ((layer_collection->flag_evaluated & COLLECTION_SELECTABLE) != 0); - - for (LinkData *link = layer_collection->object_bases.first; link != NULL; link = link->next) { - Base *base = link->data; - - if (is_visible) { + for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) { + if (base->flag & base_flag) { base->flag |= BASE_VISIBLED; } - - if (is_selectable) { - base->flag |= BASE_SELECTABLED; + else { + base->flag &= ~BASE_VISIBLED; } } -} -static void layer_eval_layer_collection_post(Depsgraph *depsgraph, ViewLayer *view_layer) -{ - DEG_debug_print_eval(depsgraph, __func__, view_layer->name, view_layer); + /* TODO(sergey): Is it always required? */ + view_layer->flag |= VIEW_LAYER_ENGINE_DIRTY; + /* Create array of bases, for fast index-based lookup. */ const int num_object_bases = BLI_listbase_count(&view_layer->object_bases); MEM_SAFE_FREE(view_layer->object_bases_array); @@ -1780,42 +1184,12 @@ static void layer_eval_layer_collection_post(Depsgraph *depsgraph, ViewLayer *vi } } -static void layer_eval_collections_recurse(Depsgraph *depsgraph, - ListBase *layer_collections, - LayerCollection *parent_layer_collection) -{ - for (LayerCollection *layer_collection = layer_collections->first; - layer_collection != NULL; - layer_collection = layer_collection->next) - { - layer_eval_layer_collection(depsgraph, - layer_collection, - parent_layer_collection); - layer_eval_collections_recurse(depsgraph, - &layer_collection->layer_collections, - layer_collection); - } -} - -void BKE_layer_eval_view_layer(struct Depsgraph *depsgraph, - struct ID *owner_id, - ViewLayer *view_layer) -{ - layer_eval_layer_collection_pre(depsgraph, owner_id, view_layer); - layer_eval_collections_recurse(depsgraph, - &view_layer->layer_collections, - NULL); - layer_eval_layer_collection_post(depsgraph, view_layer); -} - void BKE_layer_eval_view_layer_indexed(struct Depsgraph *depsgraph, - struct ID *owner_id, + struct Scene *scene, int view_layer_index) { - BLI_assert(GS(owner_id->name) == ID_SCE); BLI_assert(view_layer_index >= 0); - Scene *scene = (Scene *)owner_id; ViewLayer *view_layer = BLI_findlink(&scene->view_layers, view_layer_index); BLI_assert(view_layer != NULL); - BKE_layer_eval_view_layer(depsgraph, owner_id, view_layer); + BKE_layer_eval_view_layer(depsgraph, scene, view_layer); } |