From 92736a7b75920ffe4b8016a2d097ff8e36687c70 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Mon, 19 Aug 2019 14:25:29 -0300 Subject: [PATCH] Per-Viewport Collection Visibility Support per-viewport collection visibility options. Note 1: There is no way to show a collection that was not visible before due to depsgraph. Otherwise we would risk having all the collections in the depsgraph and I believe this is not the idea. An alternative would be to have a new depsgraph for viewports that are not local. Something to keep in mind if we do per-viewport current frame in the future. So for now what we do is to only allow collections visibility to be disabled/hidden in this mode. Note 2: hide_viewport (the eye icon) doesn't really matter for depsgraph. So after the merge we can still ignore it to show the collections locally in a viewport with no problems for the depsgraph. Reviewers: brecht, sergey Subscribers: billreynish Related task: T61327 Differential Revision: https://developer.blender.org/D5611 --- release/scripts/startup/bl_ui/space_view3d.py | 27 +++- source/blender/blenkernel/BKE_layer.h | 5 + source/blender/blenkernel/intern/layer.c | 112 +++++++++++++++ .../blender/blenkernel/intern/object_update.c | 1 + .../blenloader/intern/versioning_280.c | 21 ++- source/blender/draw/intern/draw_manager.c | 23 ++- source/blender/editors/include/ED_view3d.h | 4 + source/blender/editors/object/object_edit.c | 20 ++- .../editors/space_view3d/view3d_view.c | 136 +++++++++++++++++- source/blender/makesdna/DNA_layer_types.h | 6 + source/blender/makesdna/DNA_object_types.h | 3 +- source/blender/makesdna/DNA_scene_types.h | 2 + source/blender/makesdna/DNA_view3d_types.h | 4 +- source/blender/makesrna/intern/rna_layer.c | 27 ++++ source/blender/makesrna/intern/rna_space.c | 21 +++ .../blender/windowmanager/intern/wm_files.c | 1 + 16 files changed, 395 insertions(+), 18 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index e98a3684ddc..acb42e0545b 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -4997,7 +4997,7 @@ class VIEW3D_PT_collections(Panel): bl_label = "Collections" bl_options = {'DEFAULT_CLOSED'} - def _draw_collection(self, layout, view_layer, collection, index): + def _draw_collection(self, layout, view_layer, use_local_collections, collection, index): need_separator = index for child in collection.children: index += 1 @@ -5023,6 +5023,7 @@ class VIEW3D_PT_collections(Panel): pass row = layout.row() + row.use_property_decorate = False sub = row.split(factor=0.98) subrow = sub.row() subrow.alignment = 'LEFT' @@ -5033,11 +5034,21 @@ class VIEW3D_PT_collections(Panel): sub = row.split() subrow = sub.row(align=True) subrow.alignment = 'RIGHT' - subrow.active = collection.is_visible # Parent collection runtime visibility - subrow.prop(child, "hide_viewport", text="", emboss=False) + if not use_local_collections: + subrow.active = collection.is_visible # Parent collection runtime visibility + subrow.prop(child, "hide_viewport", text="", emboss=False) + elif not child.is_visible: + subrow.active = False + subrow.label(text="", icon='REMOVE') + else: + subrow.active = collection.visible_get() # Parent collection runtime visibility + icon = 'HIDE_OFF' if child.visible_get() else 'HIDE_ON' + props = subrow.operator("object.hide_collection", text="", icon=icon, emboss=False) + props.collection_index = index + props.toggle = True for child in collection.children: - index = self._draw_collection(layout, view_layer, child, index) + index = self._draw_collection(layout, view_layer, use_local_collections, child, index) return index @@ -5045,11 +5056,17 @@ class VIEW3D_PT_collections(Panel): layout = self.layout layout.use_property_split = False + view = context.space_data view_layer = context.view_layer + + layout.use_property_split = True + layout.prop(view, "use_local_collections") + layout.separator() + # We pass index 0 here because the index is increased # so the first real index is 1 # And we start with index as 1 because we skip the master collection - self._draw_collection(layout, view_layer, view_layer.layer_collection, 0) + self._draw_collection(layout, view_layer, view.use_local_collections, view_layer.layer_collection, 0) class VIEW3D_PT_object_type_visibility(Panel): diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index eb65b7641e1..535980840c1 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -90,6 +90,7 @@ int BKE_layer_collection_findindex(struct ViewLayer *view_layer, const struct La void BKE_main_collection_sync(const struct Main *bmain); void BKE_scene_collection_sync(const struct Scene *scene); void BKE_layer_collection_sync(const struct Scene *scene, struct ViewLayer *view_layer); +void BKE_layer_collection_local_sync(struct ViewLayer *view_layer, struct View3D *v3d); void BKE_main_collection_sync_remap(const struct Main *bmain); @@ -117,6 +118,10 @@ void BKE_layer_collection_isolate(struct Scene *scene, struct ViewLayer *view_layer, struct LayerCollection *lc, bool extend); +void BKE_layer_collection_local_isolate(struct ViewLayer *view_layer, + struct View3D *v3d, + struct LayerCollection *lc, + bool extend); void BKE_layer_collection_set_visible(struct ViewLayer *view_layer, struct LayerCollection *lc, const bool visible, diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index de105b9b62a..f3c0d5da6ee 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -68,6 +68,7 @@ static LayerCollection *layer_collection_add(ListBase *lb_parent, Collection *co { LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base"); lc->collection = collection; + lc->local_collections_bits = ~(0); BLI_addtail(lb_parent, lc); return lc; @@ -1083,6 +1084,117 @@ void BKE_layer_collection_isolate(Scene *scene, BKE_layer_collection_sync(scene, view_layer); } +static void layer_collection_local_visibility_set_recursive(LayerCollection *layer_collection, + const int local_collections_uuid) +{ + layer_collection->local_collections_bits |= local_collections_uuid; + for (LayerCollection *child = layer_collection->layer_collections.first; child; + child = child->next) { + layer_collection_local_visibility_set_recursive(child, local_collections_uuid); + } +} + +static void layer_collection_local_visibility_unset_recursive(LayerCollection *layer_collection, + const int local_collections_uuid) +{ + layer_collection->local_collections_bits &= ~local_collections_uuid; + for (LayerCollection *child = layer_collection->layer_collections.first; child; + child = child->next) { + layer_collection_local_visibility_unset_recursive(child, local_collections_uuid); + } +} + +static void layer_collection_local_sync(ViewLayer *view_layer, + LayerCollection *layer_collection, + const unsigned short local_collections_uuid, + bool visible) +{ + if ((layer_collection->local_collections_bits & local_collections_uuid) == 0) { + visible = false; + } + + if (visible) { + for (CollectionObject *cob = layer_collection->collection->gobject.first; cob; + cob = cob->next) { + BLI_assert(cob->ob); + Base *base = BKE_view_layer_base_find(view_layer, cob->ob); + base->local_collections_bits |= local_collections_uuid; + } + } + + LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) { + layer_collection_local_sync(view_layer, child, local_collections_uuid, visible); + } +} + +void BKE_layer_collection_local_sync(ViewLayer *view_layer, View3D *v3d) +{ + const unsigned short local_collections_uuid = v3d->local_collections_uuid; + + /* Reset flags and set the bases visible by default. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + base->local_collections_bits &= ~local_collections_uuid; + } + + LISTBASE_FOREACH (LayerCollection *, layer_collection, &view_layer->layer_collections) { + layer_collection_local_sync(view_layer, layer_collection, local_collections_uuid, true); + } +} + +/** + * Isolate the collection locally + * + * Same as BKE_layer_collection_local_isolate but for a viewport + */ +void BKE_layer_collection_local_isolate(ViewLayer *view_layer, + View3D *v3d, + LayerCollection *lc, + bool extend) +{ + LayerCollection *lc_master = view_layer->layer_collections.first; + bool hide_it = extend && ((v3d->local_collections_uuid & lc->local_collections_bits) != 0); + + if (!extend) { + /* Hide all collections. */ + for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter; + lc_iter = lc_iter->next) { + layer_collection_local_visibility_unset_recursive(lc_iter, v3d->local_collections_uuid); + } + } + + /* Make all the direct parents visible. */ + if (hide_it) { + lc->local_collections_bits &= ~(v3d->local_collections_uuid); + } + else { + LayerCollection *lc_parent = lc; + for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter; + lc_iter = lc_iter->next) { + if (BKE_layer_collection_has_layer_collection(lc_iter, lc)) { + lc_parent = lc_iter; + break; + } + } + + while (lc_parent != lc) { + lc_parent->local_collections_bits |= v3d->local_collections_uuid; + + for (LayerCollection *lc_iter = lc_parent->layer_collections.first; lc_iter; + lc_iter = lc_iter->next) { + if (BKE_layer_collection_has_layer_collection(lc_iter, lc)) { + lc_parent = lc_iter; + break; + } + } + } + + /* Make all the children visible. */ + layer_collection_local_visibility_set_recursive(lc, v3d->local_collections_uuid); + } + + BKE_layer_collection_local_sync(view_layer, v3d); +} + static void layer_collection_bases_show_recursive(ViewLayer *view_layer, LayerCollection *lc) { if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) { diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 3a330ea0d5a..01f3f2e309b 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -453,6 +453,7 @@ void BKE_object_eval_eval_base_flags(Depsgraph *depsgraph, object->base_flag &= ~(BASE_SELECTED | BASE_SELECTABLE); } object->base_local_view_bits = base->local_view_bits; + object->runtime.local_collections_bits = base->local_collections_bits; if (object->mode == OB_MODE_PARTICLE_EDIT) { for (ParticleSystem *psys = object->particlesystem.first; psys != NULL; psys = psys->next) { diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index e9b4650d7d6..6d21d9c1490 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -849,6 +849,14 @@ static void do_versions_material_convert_legacy_blend_mode(bNodeTree *ntree, cha } } +static void do_versions_local_collection_bits_set(LayerCollection *layer_collection) +{ + layer_collection->local_collections_bits = ~(0); + LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) { + do_versions_local_collection_bits_set(child); + } +} + void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports)) { bool use_collection_compat_28 = true; @@ -2919,7 +2927,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } case SPACE_VIEW3D: { View3D *v3d = (View3D *)sl; - v3d->flag &= ~(V3D_FLAG_UNUSED_0 | V3D_FLAG_UNUSED_1 | V3D_FLAG_UNUSED_10 | + v3d->flag &= ~(V3D_LOCAL_COLLECTIONS | V3D_FLAG_UNUSED_1 | V3D_FLAG_UNUSED_10 | V3D_FLAG_UNUSED_12); v3d->flag2 &= ~(V3D_FLAG2_UNUSED_3 | V3D_FLAG2_UNUSED_6 | V3D_FLAG2_UNUSED_12 | V3D_FLAG2_UNUSED_13 | V3D_FLAG2_UNUSED_14 | V3D_FLAG2_UNUSED_15); @@ -3854,5 +3862,16 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) { /* Versioning code until next subversion bump goes here. */ + + if (!DNA_struct_elem_find( + fd->filesdna, "LayerCollection", "short", "local_collections_bits")) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { + LISTBASE_FOREACH (LayerCollection *, layer_collection, &view_layer->layer_collections) { + do_versions_local_collection_bits_set(layer_collection); + } + } + } + } } } diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index eea23211c5c..66e3905b212 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1565,6 +1565,20 @@ void DRW_draw_view(const bContext *C) DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, viewport, C); } +static bool is_object_visible_in_viewport(View3D *v3d, Object *ob) +{ + if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) { + return false; + } + + if ((v3d->flag & V3D_LOCAL_COLLECTIONS) && + ((v3d->local_collections_uuid & ob->runtime.local_collections_bits) == 0)) { + return false; + } + + return true; +} + /** * Used for both regular and off-screen drawing. * Need to reset DST before calling this function @@ -1640,7 +1654,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, if ((object_type_exclude_viewport & (1 << ob->type)) != 0) { continue; } - if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) { + if (!is_object_visible_in_viewport(v3d, ob)) { continue; } DST.dupli_parent = data_.dupli_parent; @@ -2336,10 +2350,9 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, v3d->object_type_exclude_select); bool filter_exclude = false; DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) { - if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) { + if (!is_object_visible_in_viewport(v3d, ob)) { continue; } - if ((ob->base_flag & BASE_SELECTABLE) && (object_type_exclude_select & (1 << ob->type)) == 0) { if (object_filter_fn != NULL) { @@ -2458,11 +2471,9 @@ static void drw_draw_depth_loop_imp(void) if ((object_type_exclude_viewport & (1 << ob->type)) != 0) { continue; } - - if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) { + if (!is_object_visible_in_viewport(v3d, ob)) { continue; } - DST.dupli_parent = data_.dupli_parent; DST.dupli_source = data_.dupli_object_current; drw_duplidata_load(DST.dupli_source); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 139b306b533..dc7b25392e8 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -741,4 +741,8 @@ void ED_view3d_buttons_region_layout_ex(const struct bContext *C, struct ARegion *ar, const char *category_override); +/* view3d_view.c */ +bool ED_view3d_local_collections_set(struct Main *bmain, struct View3D *v3d); +void ED_view3d_local_collections_reset(struct bContext *C, const bool reset_all); + #endif /* __ED_VIEW3D_H__ */ diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 37063a42906..74abe104134 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -271,9 +271,11 @@ void OBJECT_OT_hide_view_set(wmOperatorType *ot) static int object_hide_collection_exec(bContext *C, wmOperator *op) { wmWindow *win = CTX_wm_window(C); + View3D *v3d = CTX_wm_view3d(C); int index = RNA_int_get(op->ptr, "collection_index"); - const bool extend = (win->eventstate->shift != 0) || RNA_boolean_get(op->ptr, "toggle"); + const bool extend = (win->eventstate->shift != 0); + const bool toggle = RNA_boolean_get(op->ptr, "toggle"); if (win->eventstate->alt != 0) { index += 10; @@ -289,7 +291,21 @@ static int object_hide_collection_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - BKE_layer_collection_isolate(scene, view_layer, lc, extend); + if (v3d->flag & V3D_LOCAL_COLLECTIONS) { + if ((lc->runtime_flag & LAYER_COLLECTION_VISIBLE) == 0) { + return OPERATOR_CANCELLED; + } + if (toggle) { + lc->local_collections_bits ^= v3d->local_collections_uuid; + BKE_layer_collection_local_sync(view_layer, v3d); + } + else { + BKE_layer_collection_local_isolate(view_layer, v3d, lc, extend); + } + } + else { + BKE_layer_collection_isolate(scene, view_layer, lc, extend); + } WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 2515ee6e482..e5e1b1297f6 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -27,6 +27,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_rect.h" #include "BLI_utildefines.h" @@ -1187,7 +1188,7 @@ finally: /** \name Local View Operators * \{ */ -static uint free_localbit(Main *bmain) +static uint free_localview_bit(Main *bmain) { ScrArea *sa; bScreen *sc; @@ -1242,7 +1243,7 @@ static bool view3d_localview_init(const Depsgraph *depsgraph, INIT_MINMAX(min, max); - local_view_bit = free_localbit(bmain); + local_view_bit = free_localview_bit(bmain); if (local_view_bit == 0) { /* TODO(dfelinto): We can kick one of the other 3D views out of local view @@ -1534,3 +1535,134 @@ void VIEW3D_OT_localview_remove_from(wmOperatorType *ot) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Local Collections + * \{ */ + +static uint free_localcollection_bit(Main *bmain, + unsigned short local_collections_uuid, + bool *reset) +{ + ScrArea *sa; + bScreen *sc; + + ushort local_view_bits = 0; + + /* Check all areas: which localviews are in use? */ + for (sc = bmain->screens.first; sc; sc = sc->id.next) { + for (sa = sc->areabase.first; sa; sa = sa->next) { + SpaceLink *sl = sa->spacedata.first; + for (; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + if (v3d->flag & V3D_LOCAL_COLLECTIONS) { + local_view_bits |= v3d->local_collections_uuid; + } + } + } + } + } + + /* First try to keep the old uuid. */ + if (local_collections_uuid && ((local_collections_uuid & local_view_bits) == 0)) { + return local_collections_uuid; + } + + /* Otherwise get the first free available. */ + for (int i = 0; i < 16; i++) { + if ((local_view_bits & (1 << i)) == 0) { + *reset = true; + return (1 << i); + } + } + + return 0; +} + +static void local_collections_reset_uuid(LayerCollection *layer_collection, + const unsigned short local_view_bit) +{ + layer_collection->local_collections_bits |= local_view_bit; + LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) { + local_collections_reset_uuid(child, local_view_bit); + } +} + +static void view3d_local_collections_reset(Main *bmain, const uint local_view_bit) +{ + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { + LISTBASE_FOREACH (LayerCollection *, layer_collection, &view_layer->layer_collections) { + local_collections_reset_uuid(layer_collection, local_view_bit); + } + } + } +} + +/** + * See if current uuid is valid, otherwise set a valid uuid to v3d, + * Try to keep the same uuid previously used to allow users to + * quickly toggle back and forth. + */ +bool ED_view3d_local_collections_set(Main *bmain, struct View3D *v3d) +{ + if ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0) { + return true; + } + + bool reset = false; + v3d->flag &= ~V3D_LOCAL_COLLECTIONS; + uint local_view_bit = free_localcollection_bit(bmain, v3d->local_collections_uuid, &reset); + + if (local_view_bit == 0) { + return false; + } + + v3d->local_collections_uuid = local_view_bit; + v3d->flag |= V3D_LOCAL_COLLECTIONS; + + if (reset) { + view3d_local_collections_reset(bmain, local_view_bit); + } + + return true; +} + +void ED_view3d_local_collections_reset(struct bContext *C, const bool reset_all) +{ + Main *bmain = CTX_data_main(C); + uint local_view_bit = ~(0); + bool do_reset = false; + + /* Reset only the ones that are not in use. */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + if (v3d->local_collections_uuid) { + if (v3d->flag & V3D_LOCAL_COLLECTIONS) { + local_view_bit &= ~v3d->local_collections_uuid; + } + else { + do_reset = true; + } + } + } + } + } + } + + if (do_reset) { + view3d_local_collections_reset(bmain, local_view_bit); + } + else if (reset_all && (do_reset || (local_view_bit != ~(0)))) { + view3d_local_collections_reset(bmain, ~(0)); + View3D v3d = {.local_collections_uuid = ~(0)}; + BKE_layer_collection_local_sync(CTX_data_view_layer(C), &v3d); + DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_BASE_FLAGS); + } +} + +/** \} */ diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 5f64e3220b7..3af1da46f80 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -45,6 +45,8 @@ typedef struct Base { struct Object *object; unsigned int lay DNA_DEPRECATED; int flag_legacy; + unsigned short local_collections_bits; + short _pad2[3]; /* Pointer to an original base. Is initialized for evaluated view layer. * NOTE: Only allowed to be accessed from within active dependency graph. */ @@ -66,8 +68,12 @@ typedef struct LayerCollection { short flag; short runtime_flag; char _pad[4]; + /** Synced with collection->children. */ ListBase layer_collections; + + unsigned short local_collections_bits; + short _pad2[3]; } LayerCollection; typedef struct ViewLayer { diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index b4d65aa7ea9..82a90dfe7a2 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -183,7 +183,8 @@ typedef struct Object_Runtime { /** Runtime grease pencil evaluated data created by modifiers */ struct bGPDframe *gpencil_evaluated_frames; - void *_pad2; /* Padding is here for win32s unconventional struct alignment rules. */ + unsigned short local_collections_bits; + short _pad2[3]; } Object_Runtime; typedef struct Object { diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 3334b1eafe8..ca572f1ddf1 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1979,6 +1979,8 @@ extern const char *RE_engine_id_CYCLES; #define BASE_VISIBLE(v3d, base) \ (((v3d == NULL) || ((v3d)->localvd == NULL) || \ ((v3d)->local_view_uuid & (base)->local_view_bits)) && \ + ((v3d == NULL) || (((v3d)->flag & V3D_LOCAL_COLLECTIONS) == 0) || \ + ((v3d)->local_collections_uuid & (base)->local_collections_bits)) && \ ((v3d == NULL) || \ (((1 << (base)->object->type) & (v3d)->object_type_exclude_viewport) == 0)) && \ (((base)->flag & BASE_VISIBLE) != 0)) diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 106bf1252b2..10c61446d9d 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -266,6 +266,8 @@ typedef struct View3D { unsigned short local_view_uuid; char _pad6[2]; int layact DNA_DEPRECATED; + unsigned short local_collections_uuid; + short _pad7[3]; /** Optional bool for 3d cursor to define center. */ short ob_centre_cursor; @@ -329,7 +331,7 @@ typedef struct View3D { #define V3D_S3D_DISPVOLUME (1 << 2) /** #View3D.flag */ -#define V3D_FLAG_UNUSED_0 (1 << 0) /* cleared */ +#define V3D_LOCAL_COLLECTIONS (1 << 0) #define V3D_FLAG_UNUSED_1 (1 << 1) /* cleared */ #define V3D_HIDE_HELPLINES (1 << 2) #define V3D_INVALID_BACKBUF (1 << 3) diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index 3c1b30ab7bd..bab7375f01b 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -120,6 +120,26 @@ static IDProperty *rna_ViewLayer_idprops(PointerRNA *ptr, bool create) return view_layer->id_properties; } +static bool rna_LayerCollection_visible_get(LayerCollection *layer_collection, bContext *C) +{ + View3D *v3d = CTX_wm_view3d(C); + const bool runtime_visible = (layer_collection->runtime_flag & LAYER_COLLECTION_VISIBLE) != 0; + + if (v3d == NULL) { + return runtime_visible; + } + + if ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0) { + return runtime_visible; + } + + if (v3d->local_collections_uuid & layer_collection->local_collections_bits) { + return true; + } + + return false; +} + static void rna_ViewLayer_update_render_passes(ID *id) { Scene *scene = (Scene *)id; @@ -386,6 +406,13 @@ static void rna_def_layer_collection(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Hide in Viewport", "Temporarily hide in viewport"); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_update"); + func = RNA_def_function(srna, "visible_get", "rna_LayerCollection_visible_get"); + RNA_def_function_ui_description(func, + "Whether this collection is visible, take into account the " + "collection parent and the viewport"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + RNA_def_function_return(func, RNA_def_boolean(func, "result", 0, "", "")); + /* Run-time flags. */ prop = RNA_def_property(srna, "is_visible", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "runtime_flag", LAYER_COLLECTION_VISIBLE); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 3b616e7e823..2a5fc3103c9 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -1218,6 +1218,19 @@ static const EnumPropertyItem *rna_View3DShading_studio_light_itemf(bContext *UN return item; } +static void rna_SpaceView3D_use_local_collections_update(bContext *C, PointerRNA *ptr) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = (View3D *)ptr->data; + + if (ED_view3d_local_collections_set(bmain, v3d)) { + BKE_layer_collection_local_sync(view_layer, v3d); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + } +} + static const EnumPropertyItem *rna_SpaceView3D_stereo3d_camera_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), @@ -3951,6 +3964,14 @@ static void rna_def_space_view3d(BlenderRNA *brna) RNA_def_property_ui_text(prop, "FX Options", "Options used for real time compositing"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + prop = RNA_def_property(srna, "use_local_collections", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_LOCAL_COLLECTIONS); + RNA_def_property_ui_text( + prop, "Local Collections", "Display a different set of collections in this viewport"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update( + prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_use_local_collections_update"); + /* Stereo Settings */ prop = RNA_def_property(srna, "stereo_3d_eye", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "multiview_eye"); diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 01e3cf4f329..bb66c2e7d35 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -2245,6 +2245,7 @@ static int wm_open_mainfile__open(bContext *C, wmOperator *op) if (G.fileflags & G_FILE_NO_UI) { ED_outliner_select_sync_from_all_tag(C); } + ED_view3d_local_collections_reset(C, (G.fileflags & G_FILE_NO_UI) != 0); return OPERATOR_FINISHED; } else {