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:
authorBrecht Van Lommel <brechtvanlommel@gmail.com>2018-04-30 16:57:22 +0300
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2018-05-18 14:34:24 +0300
commit17bd5c9d4b1e9377b896c13043e24eaa7e979714 (patch)
tree60ca4e4118c01d88ccc04919d4f7ed46014875c1 /source/blender/blenkernel/intern/layer.c
parent70aec3732d0f03138d6477fd04c81dfd9fd21256 (diff)
Collections and groups unification
OVERVIEW * In 2.7 terminology, all layers and groups are now collection datablocks. * These collections are nestable, linkable, instanceable, overrideable, .. which opens up new ways to set up scenes and link + override data. * Viewport/render visibility and selectability are now a part of the collection and shared across all view layers and linkable. * View layers define which subset of the scene collection hierarchy is excluded for each. For many workflows one view layer can be used, these are more of an advanced feature now. OUTLINER * The outliner now has a "View Layer" display mode instead of "Collections", which can display the collections and/or objects in the view layer. * In this display mode, collections can be excluded with the right click menu. These will then be greyed out and their objects will be excluded. * To view collections not linked to any scene, the "Blender File" display mode can be used, with the new filtering option to just see Colleciton datablocks. * The outliner right click menus for collections and objects were reorganized. * Drag and drop still needs to be improved. Like before, dragging the icon or text gives different results, we'll unify this later. LINKING AND OVERRIDES * Collections can now be linked into the scene without creating an instance, with the link/append operator or from the collections view in the outliner. * Collections can get static overrides with the right click menu in the outliner, but this is rather unreliable and not clearly communicated at the moment. * We still need to improve the make override operator to turn collection instances into collections with overrides directly in the scene. PERFORMANCE * We tried to make performance not worse than before and improve it in some cases. The main thing that's still a bit slower is multiple scenes, we have to change the layer syncing to only updated affected scenes. * Collections keep a list of their parent collections for faster incremental updates in syncing and caching. * View layer bases are now in a object -> base hash to avoid quadratic time lookups internally and in API functions like visible_get(). VERSIONING * Compatibility with 2.7 files should be improved due to the new visibility controls. Of course users may not want to set up their scenes differently now to avoid having separate layers and groups. * Compatibility with 2.8 is mostly there, and was tested on Eevee demo and Hero files. There's a few things which are know to be not quite compatible, like nested layer collections inside groups. * The versioning code for 2.8 files is quite complicated, and isolated behind #ifdef so it can be removed at the end of the release cycle. KNOWN ISSUES * The G-key group operators in the 3D viewport were left mostly as is, they need to be modified still to fit better. * Same for the groups panel in the object properties. This needs to be updated still, or perhaps replaced by something better. * Collections must all have a unique name. Less restrictive namespacing is to be done later, we'll have to see how important this is as all objects within the collections must also have a unique name anyway. * Full scene copy and delete scene are exactly doing the right thing yet. Differential Revision: https://developer.blender.org/D3383 https://code.blender.org/2018/05/collections-and-groups/
Diffstat (limited to 'source/blender/blenkernel/intern/layer.c')
-rw-r--r--source/blender/blenkernel/intern/layer.c1272
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);
}