diff options
Diffstat (limited to 'source')
11 files changed, 614 insertions, 120 deletions
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index cff80ef3467..65c0202ef66 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -109,7 +109,8 @@ bool BKE_layer_collection_has_layer_collection( struct LayerCollection *lc_parent, struct LayerCollection *lc_child); void BKE_base_set_visible(struct Scene *scene, struct ViewLayer *view_layer, struct Base *base, bool extend); -void BKE_layer_collection_set_visible(struct Scene *scene, struct ViewLayer *view_layer, struct LayerCollection *lc, bool extend); +bool BKE_layer_collection_isolate(struct Scene *scene, struct ViewLayer *view_layer, struct LayerCollection *lc, bool extend); +bool BKE_layer_collection_set_visible(struct ViewLayer *view_layer, struct LayerCollection *lc, const bool visible, const bool hierarchy); /* evaluation */ diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 0b49a389ab1..f9d39c840e2 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -669,7 +669,9 @@ static short layer_collection_sync( lc->runtime_flag = child_runtime_flag; } - if ((child_layer_restrict & LAYER_COLLECTION_RESTRICT_VIEW) == 0) { + if (((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) && + ((child_layer_restrict & LAYER_COLLECTION_RESTRICT_VIEW) == 0)) + { lc->runtime_flag |= LAYER_COLLECTION_VISIBLE; } @@ -701,15 +703,18 @@ static short layer_collection_sync( int object_restrict = base->object->restrictflag; if (((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) && - ((child_layer_restrict & LAYER_COLLECTION_RESTRICT_VIEW) == 0) && ((object_restrict & OB_RESTRICT_VIEW) == 0)) { - base->flag |= BASE_VISIBLE | BASE_ENABLED | BASE_ENABLED_VIEWPORT; + base->flag |= BASE_ENABLED | BASE_ENABLED_VIEWPORT; - if (((child_restrict & COLLECTION_RESTRICT_SELECT) == 0) && - ((object_restrict & OB_RESTRICT_SELECT) == 0)) - { - base->flag |= BASE_SELECTABLE; + if ((child_layer_restrict & LAYER_COLLECTION_RESTRICT_VIEW) == 0) { + base->flag |= BASE_VISIBLE; + + if (((child_restrict & COLLECTION_RESTRICT_SELECT) == 0) && + ((object_restrict & OB_RESTRICT_SELECT) == 0)) + { + base->flag |= BASE_SELECTABLE; + } } } @@ -720,7 +725,7 @@ static short layer_collection_sync( } /* Update runtime flags used for display and tools. */ - if (base->flag & BASE_VISIBLE) { + if (base->flag & BASE_ENABLED) { lc->runtime_flag |= LAYER_COLLECTION_HAS_ENABLED_OBJECTS; } @@ -987,48 +992,124 @@ static void layer_collection_flag_unset_recursive(LayerCollection *lc, const int } /** - * Set collection per-view layer visiblity. - * When not extending, we show all the direct parents and all children of the layer collection. + * Return true if something changed. */ +static bool layer_collection_collection_flag_unset_recursive(LayerCollection *lc, const int flag) +{ + bool changed = (lc->collection->flag & flag) != 0; + + lc->collection->flag &= ~flag; + for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) { + changed |= layer_collection_collection_flag_unset_recursive(lc_iter, flag); + } + + return changed; +} + +/** + * Isolate the collection - hide all other collections but this one. + * Make sure to show all the direct parents and all children of the layer collection as well. + * When extending we simply show the collections and its direct family. + * + * Return whether depsgraph needs update. */ -void BKE_layer_collection_set_visible(Scene *scene, ViewLayer *view_layer, LayerCollection *lc, bool extend) +bool BKE_layer_collection_isolate(Scene *scene, ViewLayer *view_layer, LayerCollection *lc, bool extend) { + bool depsgraph_need_update = false; if (!extend) { - /* Make only this collection visible. */ + /* Hide all collections . */ for (LayerCollection *lc_iter = view_layer->layer_collections.first; lc_iter; lc_iter = lc_iter->next) { layer_collection_flag_set_recursive(lc_iter, LAYER_COLLECTION_RESTRICT_VIEW); } + } - /* Make all the direct parents visible. */ - LayerCollection *lc_parent = lc; - LayerCollection *lc_master = view_layer->layer_collections.first; - for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter; lc_iter = lc_iter->next) { + /* Make all the direct parents visible. */ + LayerCollection *lc_parent = lc; + LayerCollection *lc_master = view_layer->layer_collections.first; + 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) { + depsgraph_need_update |= (lc_parent->collection->flag & COLLECTION_RESTRICT_VIEW) != 0; + lc_parent->collection->flag &= ~COLLECTION_RESTRICT_VIEW; + lc_parent->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW; + + 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; } } + } - while (lc_parent != lc) { - lc_parent->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW; + /* Make all the children visible. */ + layer_collection_flag_unset_recursive(lc, LAYER_COLLECTION_RESTRICT_VIEW); + depsgraph_need_update |= layer_collection_collection_flag_unset_recursive(lc, COLLECTION_RESTRICT_VIEW); - 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; - } - } - } + BKE_layer_collection_activate(view_layer, lc); + + BKE_layer_collection_sync(scene, view_layer); + + return depsgraph_need_update; +} - /* Make all the children visible. */ - layer_collection_flag_unset_recursive(lc, LAYER_COLLECTION_RESTRICT_VIEW); +static void layer_collection_bases_show_recursive(ViewLayer *view_layer, LayerCollection *lc) +{ + for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) { + Base *base = BKE_view_layer_base_find(view_layer, cob->ob); + base->flag &= ~BASE_HIDDEN; + base->object->restrictflag &= ~OB_RESTRICT_VIEW; + } + for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) { + layer_collection_bases_show_recursive(view_layer, lc_iter); + } +} - BKE_layer_collection_activate(view_layer, lc); +static void layer_collection_bases_hide_recursive(ViewLayer *view_layer, LayerCollection *lc) +{ + for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) { + Base *base = BKE_view_layer_base_find(view_layer, cob->ob); + base->flag |= BASE_HIDDEN; } - else { - lc->flag ^= LAYER_COLLECTION_RESTRICT_VIEW; + for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) { + layer_collection_bases_hide_recursive(view_layer, lc_iter); } +} - BKE_layer_collection_sync(scene, view_layer); +/** + * Hide/show all the elements of a collection. + * Enable a disable collection if needs be. + * + * Return true if depsgraph needs update. + */ +bool BKE_layer_collection_set_visible(ViewLayer *view_layer, LayerCollection *lc, const bool visible, const bool hierarchy) +{ + bool depsgraph_changed = false; + if (hierarchy) { + if (visible) { + depsgraph_changed |= layer_collection_collection_flag_unset_recursive(lc, COLLECTION_RESTRICT_VIEW); + layer_collection_flag_unset_recursive(lc, LAYER_COLLECTION_RESTRICT_VIEW); + layer_collection_bases_show_recursive(view_layer, lc); + } + else { + layer_collection_flag_set_recursive(lc, LAYER_COLLECTION_RESTRICT_VIEW); + layer_collection_bases_hide_recursive(view_layer, lc); + } + } + else { + if (visible) { + depsgraph_changed |= (lc->collection->flag & COLLECTION_RESTRICT_VIEW) != 0; + lc->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW; + lc->collection->flag &= ~COLLECTION_RESTRICT_VIEW; + } + else { + lc->flag |= LAYER_COLLECTION_RESTRICT_VIEW; + } + } + return depsgraph_changed; } /* ---------------------------------------------------------------------- */ @@ -1384,7 +1465,7 @@ void BKE_layer_eval_view_layer( /* Visibility based on depsgraph mode. */ const eEvaluationMode mode = DEG_get_mode(depsgraph); - const int base_visible_flag = (mode == DAG_EVAL_VIEWPORT) + const int base_enabled_flag = (mode == DAG_EVAL_VIEWPORT) ? BASE_ENABLED_VIEWPORT : BASE_ENABLED_RENDER; /* Create array of bases, for fast index-based lookup. */ @@ -1395,10 +1476,12 @@ void BKE_layer_eval_view_layer( int base_index = 0; for (Base *base = view_layer->object_bases.first; base; base = base->next) { /* Compute visibility for depsgraph evaluation mode. */ - if (base->flag & base_visible_flag) { - base->flag |= BASE_ENABLED | BASE_VISIBLE; - if (mode == DAG_EVAL_VIEWPORT && (base->flag & BASE_HIDDEN)) { - base->flag &= ~BASE_VISIBLE; + if (base->flag & base_enabled_flag) { + base->flag |= BASE_ENABLED; + + /* When rendering, visibility is controlled by the enable/disable option. */ + if (mode == DAG_EVAL_RENDER) { + base->flag |= BASE_VISIBLE; } } else { @@ -1416,7 +1499,7 @@ void BKE_layer_eval_view_layer( Base *base_orig = view_layer_orig->object_bases.first; const Base *base_eval = view_layer->object_bases.first; while (base_orig != NULL) { - if (base_orig->flag & base_visible_flag) { + if (base_orig->flag & base_enabled_flag) { base_orig->flag = base_eval->flag; base_eval = base_eval->next; } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc index 00981d75665..cc2d58dbe51 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc @@ -64,11 +64,6 @@ void DepsgraphNodeBuilder::build_layer_collections(ListBase *lb) COLLECTION_RESTRICT_VIEW : COLLECTION_RESTRICT_RENDER; for (LayerCollection *lc = (LayerCollection *)lb->first; lc; lc = lc->next) { - if ((graph_->mode == DAG_EVAL_VIEWPORT) && - ((lc->flag & LAYER_COLLECTION_RESTRICT_VIEW) != 0)) - { - continue; - } if (lc->collection->flag & restrict_flag) { continue; } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc index 7f4a388718f..c0fe5243e58 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc @@ -65,11 +65,6 @@ void DepsgraphRelationBuilder::build_layer_collections(ListBase *lb) COLLECTION_RESTRICT_VIEW : COLLECTION_RESTRICT_RENDER; for (LayerCollection *lc = (LayerCollection *)lb->first; lc; lc = lc->next) { - if ((graph_->mode == DAG_EVAL_VIEWPORT) && - ((lc->flag & LAYER_COLLECTION_RESTRICT_VIEW) != 0)) - { - continue; - } if ((lc->collection->flag & restrict_flag)) { continue; } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index ff3128a2fb6..c705026b640 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -359,23 +359,23 @@ void scene_remove_unused_view_layers(const Depsgraph *depsgraph, scene_cow->view_layers.last = view_layer_eval; } -/* Makes it so given view layer only has bases corresponding to a visible +/* Makes it so given view layer only has bases corresponding to enabled * objects. */ -void view_layer_remove_invisible_bases(const Depsgraph *depsgraph, - ViewLayer *view_layer) +void view_layer_remove_disabled_bases(const Depsgraph *depsgraph, + ViewLayer *view_layer) { - const int base_visible_flag = (depsgraph->mode == DAG_EVAL_VIEWPORT) ? + const int base_enabled_flag = (depsgraph->mode == DAG_EVAL_VIEWPORT) ? BASE_ENABLED_VIEWPORT : BASE_ENABLED_RENDER; - ListBase visible_bases = {NULL, NULL}; + ListBase enabled_bases = {NULL, NULL}; for (Base *base = reinterpret_cast<Base *>(view_layer->object_bases.first), *base_next; base != NULL; base = base_next) { base_next = base->next; - const bool is_object_visible = (base->flag & base_visible_flag); - if (is_object_visible) { - BLI_addtail(&visible_bases, base); + const bool is_object_enabled = (base->flag & base_enabled_flag); + if (is_object_enabled) { + BLI_addtail(&enabled_bases, base); } else { if (base == view_layer->basact) { @@ -384,13 +384,13 @@ void view_layer_remove_invisible_bases(const Depsgraph *depsgraph, MEM_freeN(base); } } - view_layer->object_bases = visible_bases; + view_layer->object_bases = enabled_bases; } void scene_cleanup_view_layers(const Depsgraph *depsgraph, Scene *scene_cow) { scene_remove_unused_view_layers(depsgraph, scene_cow); - view_layer_remove_invisible_bases( + view_layer_remove_disabled_bases( depsgraph, reinterpret_cast<ViewLayer *>(scene_cow->view_layers.first)); /* TODO(sergey): Remove objects from collections as well. diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 686c03b3e16..9bd0de83ca5 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -283,10 +283,12 @@ static int object_hide_collection_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BKE_layer_collection_set_visible(scene, view_layer, lc, extend); - - DEG_relations_tag_update(CTX_data_main(C)); DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + + if (BKE_layer_collection_isolate(scene, view_layer, lc, extend)) { + DEG_relations_tag_update(CTX_data_main(C)); + } + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 772f3f8b3ff..0d8c88ecede 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -820,6 +820,348 @@ void OUTLINER_OT_collection_indirect_only_clear(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/************************** Visibility Operators ******************************/ + +static int collection_isolate_exec(bContext *C, wmOperator *op) { + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + bool depsgraph_changed = false; + struct CollectionEditData data = {.scene = scene, .soops = soops,}; + data.collections_to_edit = BLI_gset_ptr_new(__func__); + + /* Hide all collections before the isolate function - needed in order to support. */ + if (!extend) { + for (LayerCollection *lc_iter = view_layer->layer_collections.first; lc_iter; lc_iter = lc_iter->next) { + lc_iter->flag |= LAYER_COLLECTION_RESTRICT_VIEW; + layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_RESTRICT_VIEW); + } + } + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data); + + GSetIterator collections_to_edit_iter; + GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { + LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + depsgraph_changed |= BKE_layer_collection_isolate(scene, view_layer, layer_collection, true); + } + BLI_gset_free(data.collections_to_edit, NULL); + + BKE_layer_collection_sync(scene, view_layer); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + + if (depsgraph_changed) { + DEG_relations_tag_update(CTX_data_main(C)); + } + + WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); + return OPERATOR_FINISHED; +} + +static int collection_isolate_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "extend"); + if (!RNA_property_is_set(op->ptr, prop) && (event->shift)) { + RNA_property_boolean_set(op->ptr, prop, true); + } + return collection_isolate_exec(C, op); +} + +void OUTLINER_OT_collection_isolate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Isolate Collection"; + ot->idname = "OUTLINER_OT_collection_isolate"; + ot->description = "Hide all but this collection and its parents"; + + /* api callbacks */ + ot->exec = collection_isolate_exec; + ot->invoke = collection_isolate_invoke; + ot->poll = ED_outliner_collections_editor_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + PropertyRNA *prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend current visible collections"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + +static bool collection_show_poll(bContext *C) +{ + return collections_view_layer_poll(C, true, LAYER_COLLECTION_RESTRICT_VIEW); +} + +static bool collection_hide_poll(bContext *C) +{ + return collections_view_layer_poll(C, false, LAYER_COLLECTION_RESTRICT_VIEW); +} + +static bool collection_inside_poll(bContext *C) +{ + if (!ED_outliner_collections_editor_poll(C)) { + return false; + } + return outliner_active_layer_collection(C) != NULL; +} + +static int collection_visibility_exec(bContext *C, wmOperator *op) { + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + const bool is_inside = strstr(op->idname, "inside") != NULL; + const bool show = strstr(op->idname, "show") != NULL; + bool depsgraph_changed = false; + struct CollectionEditData data = {.scene = scene, .soops = soops,}; + data.collections_to_edit = BLI_gset_ptr_new(__func__); + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data); + + GSetIterator collections_to_edit_iter; + GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { + LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + depsgraph_changed |= BKE_layer_collection_set_visible(view_layer, layer_collection, show, is_inside); + } + BLI_gset_free(data.collections_to_edit, NULL); + + BKE_layer_collection_sync(scene, view_layer); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + + if (depsgraph_changed) { + DEG_relations_tag_update(CTX_data_main(C)); + } + + WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_collection_show(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Show Collection"; + ot->idname = "OUTLINER_OT_collection_show"; + ot->description = "Show the collection in this view layer"; + + /* api callbacks */ + ot->exec = collection_visibility_exec; + ot->poll = collection_show_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void OUTLINER_OT_collection_hide(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Hide Collection"; + ot->idname = "OUTLINER_OT_collection_hide"; + ot->description = "Hide the collection in this view layer"; + + /* api callbacks */ + ot->exec = collection_visibility_exec; + ot->poll = collection_hide_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void OUTLINER_OT_collection_show_inside(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Show Inside Collection"; + ot->idname = "OUTLINER_OT_collection_show_inside"; + ot->description = "Show all the objects and collections inside the collection"; + + /* api callbacks */ + ot->exec = collection_visibility_exec; + ot->poll = collection_inside_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void OUTLINER_OT_collection_hide_inside(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Hide Inside Collection"; + ot->idname = "OUTLINER_OT_collection_hide_inside"; + ot->description = "Hide all the objects and collections inside the collection"; + + /* api callbacks */ + ot->exec = collection_visibility_exec; + ot->poll = collection_inside_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static bool collection_flag_poll(bContext *C, bool clear, int flag) +{ + if (!ED_outliner_collections_editor_poll(C)) { + return false; + } + + TreeElement *te = outliner_active_collection(C); + if (te == NULL) { + return false; + } + + Collection *collection = outliner_collection_from_tree_element(te); + if (collection == NULL) { + return false; + } + + if (clear && (collection->flag & flag)) { + return true; + } + else if (!clear && !(collection->flag & flag)) { + return true; + } + + return false; +} + +static bool collection_enable_poll(bContext *C) +{ + return collection_flag_poll(C, true, COLLECTION_RESTRICT_VIEW); +} + +static bool collection_disable_poll(bContext *C) +{ + return collection_flag_poll(C, false, COLLECTION_RESTRICT_VIEW); +} + +static bool collection_enable_render_poll(bContext *C) +{ + return collection_flag_poll(C, true, COLLECTION_RESTRICT_RENDER); +} + +static bool collection_disable_render_poll(bContext *C) +{ + return collection_flag_poll(C, false, COLLECTION_RESTRICT_RENDER); +} + +static int collection_flag_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + const bool is_render = strstr(op->idname, "render"); + const bool clear = strstr(op->idname, "show") || strstr(op->idname, "enable"); + int flag = is_render ? COLLECTION_RESTRICT_RENDER : COLLECTION_RESTRICT_VIEW; + struct CollectionEditData data = {.scene = scene, .soops = soops,}; + data.collections_to_edit = BLI_gset_ptr_new(__func__); + const bool has_layer_collection = soops->outlinevis == SO_VIEW_LAYER; + + if (has_layer_collection) { + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data); + GSetIterator collections_to_edit_iter; + GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { + LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + Collection *collection = layer_collection->collection; + + if (clear) { + collection->flag &= ~flag; + } + else { + collection->flag |= flag; + } + + /* Make sure (at least for this view layer) the collection is visible. */ + if (clear && !is_render) { + layer_collection->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW; + } + } + BLI_gset_free(data.collections_to_edit, NULL); + } + else { + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data); + GSetIterator collections_to_edit_iter; + GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { + Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + + if (clear) { + collection->flag &= ~flag; + } + else { + collection->flag |= flag; + } + } + BLI_gset_free(data.collections_to_edit, NULL); + } + + BKE_layer_collection_sync(scene, view_layer); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + + if (!is_render) { + DEG_relations_tag_update(CTX_data_main(C)); + } + + WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_collection_enable(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Enable Collection"; + ot->idname = "OUTLINER_OT_collection_enable"; + ot->description = "Enable viewport drawing in the view layers"; + + /* api callbacks */ + ot->exec = collection_flag_exec; + ot->poll = collection_enable_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void OUTLINER_OT_collection_disable(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Disable Collection"; + ot->idname = "OUTLINER_OT_collection_disable"; + ot->description = "Disable viewport drawing in the view layers"; + + /* api callbacks */ + ot->exec = collection_flag_exec; + ot->poll = collection_disable_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void OUTLINER_OT_collection_enable_render(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Enable Collection in Render"; + ot->idname = "OUTLINER_OT_collection_enable_render"; + ot->description = "Render the collection"; + + /* api callbacks */ + ot->exec = collection_flag_exec; + ot->poll = collection_enable_render_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void OUTLINER_OT_collection_disable_render(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Disable Collection in Render"; + ot->idname = "OUTLINER_OT_collection_disable_render"; + ot->description = "Do not render this collection"; + + /* api callbacks */ + ot->exec = collection_flag_exec; + ot->poll = collection_disable_render_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /** * Populates the \param objects: ListBase with all the outliner selected objects * We store it as (Object *)LinkData->data diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 7a2ac82cf54..f0befd1df49 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -267,41 +267,72 @@ static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void static void hidebutton_base_flag_cb(bContext *C, void *poin, void *poin2) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = poin; Base *base = poin2; - bool extend = (CTX_wm_window(C)->eventstate->ctrl == 0); - - /* Undo button toggle, let function do it. */ - base->flag ^= BASE_HIDDEN; - - BKE_base_set_visible(scene, view_layer, base, extend); + Object *ob = base->object; + bool freeze = (CTX_wm_window(C)->eventstate->alt != 0); + bool changed_restrict_view = false; - if (!extend && (base->flag & BASE_VISIBLE)) { - /* Auto select solo-ed object. */ - ED_object_base_select(base, BA_SELECT); - view_layer->basact = base; + if (freeze) { + ob->restrictflag |= OB_RESTRICT_VIEW; + changed_restrict_view = true; + } + else if (ob->restrictflag & OB_RESTRICT_VIEW) { + ob->restrictflag &= ~OB_RESTRICT_VIEW; + base->flag &= ~BASE_HIDDEN; + changed_restrict_view = true; + } + else { + base->flag ^= BASE_HIDDEN; } - DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + if (changed_restrict_view) { + BKE_main_collection_sync(bmain); + DEG_id_tag_update(&ob->id, LIB_TAG_COPIED_ON_WRITE); + DEG_relations_tag_update(bmain); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, &ob->id); + } + if (!freeze) { + BKE_layer_collection_sync(scene, view_layer); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + } } static void hidebutton_layer_collection_flag_cb(bContext *C, void *poin, void *poin2) { + wmWindow *win = CTX_wm_window(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = poin; LayerCollection *lc = poin2; - bool extend = (CTX_wm_window(C)->eventstate->ctrl == 0); - - /* Undo button toggle, let function do it. */ - lc->flag ^= LAYER_COLLECTION_RESTRICT_VIEW; - - BKE_layer_collection_set_visible(scene, view_layer, lc, extend); + Collection *collection = lc->collection; + bool do_disable = (win->eventstate->alt != 0); + bool do_isolate = (win->eventstate->ctrl != 0) && !do_disable; + bool extend = (win->eventstate->shift != 0); + bool depsgraph_changed = false; + + if (do_disable) { + collection->flag |= COLLECTION_RESTRICT_VIEW; + depsgraph_changed = true; + } + else if (do_isolate) { + depsgraph_changed |= BKE_layer_collection_isolate(scene, view_layer, lc, extend); + } + else { + bool make_visible = ((lc->flag & LAYER_COLLECTION_RESTRICT_VIEW) != 0) || + ((collection->flag & COLLECTION_RESTRICT_VIEW) != 0); + depsgraph_changed |= BKE_layer_collection_set_visible(view_layer, lc, make_visible, extend); + } - DEG_relations_tag_update(CTX_data_main(C)); + BKE_layer_collection_sync(scene, view_layer); DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + + if (depsgraph_changed) { + DEG_relations_tag_update(CTX_data_main(C)); + } + WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); } static void namebutton_cb(bContext *C, void *tsep, char *oldname) @@ -517,27 +548,32 @@ static void outliner_draw_restrictbuts( UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); } else if (tselem->type == 0 && te->idcode == ID_OB) { + PointerRNA ptr; Object *ob = (Object *)tselem->id; + RNA_pointer_create(&ob->id, &RNA_Object, ob, &ptr); Base *base = BKE_view_layer_base_find(view_layer, ob); if (base) { - bt = uiDefIconButBitS( - block, UI_BTYPE_ICON_TOGGLE, BASE_HIDDEN, 0, ICON_HIDE_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_HIDEX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &base->flag, 0, 0, 0, 0, - TIP_("Hide object in viewport (Ctrl to isolate)")); + int icon = ICON_RESTRICT_VIEW_ON; + if ((ob->restrictflag & OB_RESTRICT_VIEW) == 0) { + icon = (base->flag & BASE_HIDDEN) != 0 ? + ICON_HIDE_ON : + ICON_HIDE_OFF; + } + bt = uiDefIconBut( + block, UI_BTYPE_ICON_TOGGLE, 0, icon, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y, + NULL, 0, 0, 0, 0, + TIP_("Hide object in viewport (Alt to disable for all viewports)")); UI_but_func_set(bt, hidebutton_base_flag_cb, view_layer, base); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); } - - PointerRNA ptr; - RNA_pointer_create(&ob->id, &RNA_Object, ob, &ptr); - - bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, props.object_hide_viewport, -1, 0, 0, -1, -1, NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + else { + bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, 0, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y, + &ptr, props.object_hide_viewport, -1, 0, 0, -1, -1, NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, 0, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, UI_UNIT_Y, @@ -641,23 +677,34 @@ static void outliner_draw_restrictbuts( if ((!lc || !(lc->flag & LAYER_COLLECTION_EXCLUDE)) && !(collection->flag & COLLECTION_IS_MASTER)) { - bt = uiDefIconButBitS( - block, UI_BTYPE_ICON_TOGGLE, LAYER_COLLECTION_RESTRICT_VIEW, 0, ICON_HIDE_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_HIDEX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &lc->flag, 0, 0, 0, 0, - TIP_("Hide collection in viewport (Ctrl to isolate)")); - UI_but_func_set(bt, hidebutton_layer_collection_flag_cb, view_layer, lc); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); - PointerRNA collection_ptr; RNA_id_pointer_create(&collection->id, &collection_ptr); - bt = uiDefIconButR_prop( - block, UI_BTYPE_ICON_TOGGLE, 0, 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &collection_ptr, props.collection_hide_viewport, -1, 0, 0, 0, 0, NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (lc != NULL) { + int icon = ICON_RESTRICT_VIEW_ON; + if ((collection->flag & COLLECTION_RESTRICT_VIEW) == 0) { + icon = (lc->flag & LAYER_COLLECTION_RESTRICT_VIEW) != 0 ? + ICON_HIDE_ON : + ICON_HIDE_OFF; + } + bt = uiDefIconBut( + block, UI_BTYPE_TOGGLE, 0, icon, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y, + NULL, 0, 0, 0, 0, + TIP_("Hide collection in viewport\n" + "* Alt to disable for all viewports\n" + "* Ctrl to isolate visibility\n" + "* Shift to hide inside objects and collections")); + UI_but_func_set(bt, hidebutton_layer_collection_flag_cb, view_layer, lc); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } + else { + bt = uiDefIconButR_prop( + block, UI_BTYPE_ICON_TOGGLE, 0, 0, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, + UI_UNIT_Y, &collection_ptr, props.collection_hide_viewport, -1, 0, 0, 0, 0, NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } bt = uiDefIconButR_prop( block, UI_BTYPE_ICON_TOGGLE, 0, 0, @@ -2115,10 +2162,7 @@ static void outliner_draw_restrictcols(ARegion *ar) uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); immUniformThemeColorShadeAlpha(TH_BACK, -15, -200); - immBegin(GPU_PRIM_LINES, 8); - - immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_HIDEX), (int)ar->v2d.cur.ymax); - immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_HIDEX), (int)ar->v2d.cur.ymin); + immBegin(GPU_PRIM_LINES, 6); immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)ar->v2d.cur.ymax); immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)ar->v2d.cur.ymin); diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 96399d3c129..d978acb6062 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -123,12 +123,11 @@ typedef enum { /* size constants */ #define OL_Y_OFFSET 2 -#define OL_TOG_HIDEX (UI_UNIT_X * 4.0f + V2D_SCROLL_WIDTH) #define OL_TOG_RESTRICT_SELECTX (UI_UNIT_X * 3.0f + V2D_SCROLL_WIDTH) #define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 2.0f + V2D_SCROLL_WIDTH) #define OL_TOG_RESTRICT_RENDERX (UI_UNIT_X + V2D_SCROLL_WIDTH) -#define OL_TOGW OL_TOG_HIDEX +#define OL_TOGW OL_TOG_RESTRICT_SELECTX #define OL_RNA_COLX (UI_UNIT_X * 15) #define OL_RNA_COL_SIZEX (UI_UNIT_X * 7.5f) @@ -329,6 +328,16 @@ void OUTLINER_OT_collection_holdout_clear(struct wmOperatorType *ot); void OUTLINER_OT_collection_indirect_only_set(struct wmOperatorType *ot); void OUTLINER_OT_collection_indirect_only_clear(struct wmOperatorType *ot); +void OUTLINER_OT_collection_isolate(struct wmOperatorType *ot); +void OUTLINER_OT_collection_show(struct wmOperatorType *ot); +void OUTLINER_OT_collection_hide(struct wmOperatorType *ot); +void OUTLINER_OT_collection_show_inside(struct wmOperatorType *ot); +void OUTLINER_OT_collection_hide_inside(struct wmOperatorType *ot); +void OUTLINER_OT_collection_enable(struct wmOperatorType *ot); +void OUTLINER_OT_collection_disable(struct wmOperatorType *ot); +void OUTLINER_OT_collection_enable_render(struct wmOperatorType *ot); +void OUTLINER_OT_collection_disable_render(struct wmOperatorType *ot); + /* outliner_utils.c ---------------------------------------------- */ TreeElement *outliner_find_item_at_y(const SpaceOops *soops, const ListBase *tree, float view_co_y); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index d01fa066500..3334206beac 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -105,6 +105,16 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_collection_holdout_clear); WM_operatortype_append(OUTLINER_OT_collection_indirect_only_set); WM_operatortype_append(OUTLINER_OT_collection_indirect_only_clear); + + WM_operatortype_append(OUTLINER_OT_collection_isolate); + WM_operatortype_append(OUTLINER_OT_collection_disable); + WM_operatortype_append(OUTLINER_OT_collection_enable); + WM_operatortype_append(OUTLINER_OT_collection_hide); + WM_operatortype_append(OUTLINER_OT_collection_show); + WM_operatortype_append(OUTLINER_OT_collection_disable_render); + WM_operatortype_append(OUTLINER_OT_collection_enable_render); + WM_operatortype_append(OUTLINER_OT_collection_hide_inside); + WM_operatortype_append(OUTLINER_OT_collection_show_inside); } void outliner_keymap(wmKeyConfig *keyconf) diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index 82082ec6022..0fb48652c2c 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -196,7 +196,7 @@ int rna_LayerCollection_name_length(PointerRNA *ptr) return strlen(id->name + 2); } -static void rna_LayerCollection_use_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_LayerCollection_exclude_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->id.data; LayerCollection *lc = (LayerCollection *)ptr->data; @@ -209,6 +209,19 @@ static void rna_LayerCollection_use_update(Main *bmain, Scene *UNUSED(scene), Po WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); } +static void rna_LayerCollection_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + Scene *scene = (Scene *)ptr->id.data; + LayerCollection *lc = (LayerCollection *)ptr->data; + ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, lc); + + BKE_layer_collection_sync(scene, view_layer); + + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + + WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); +} + static bool rna_LayerCollection_has_objects(LayerCollection *lc) { return (lc->runtime_flag & LAYER_COLLECTION_HAS_OBJECTS) != 0; @@ -273,13 +286,13 @@ static void rna_def_layer_collection(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", LAYER_COLLECTION_EXCLUDE); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Exclude", "Exclude collection from view layer"); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_LayerCollection_use_update"); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_LayerCollection_exclude_update"); prop = RNA_def_property(srna, "holdout", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", LAYER_COLLECTION_HOLDOUT); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Holdout", "Mask out objects in collection from view layer"); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_LayerCollection_use_update"); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_LayerCollection_update"); prop = RNA_def_property(srna, "indirect_only", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", LAYER_COLLECTION_INDIRECT_ONLY); @@ -287,14 +300,14 @@ static void rna_def_layer_collection(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Indirect Only", "Objects in collection only contribute indirectly (through shadows and reflections) " "in the view layer"); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_LayerCollection_use_update"); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_LayerCollection_update"); prop = RNA_def_property(srna, "hide_viewport", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", LAYER_COLLECTION_RESTRICT_VIEW); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1); RNA_def_property_ui_text(prop, "Disable Viewport", "Disable collection in viewport for this view layer"); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_use_update"); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_update"); prop = RNA_def_property(srna, "is_visible", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "runtime_flag", LAYER_COLLECTION_VISIBLE); |