Commit: aeaf87bbeb011e9a571eefa12d81fa6fb2b8bd5b Author: Dalai Felinto Date: Fri Dec 1 12:23:05 2017 -0200 Branches: blender2.8 https://developer.blender.org/rBaeaf87bbeb011e9a571eefa12d81fa6fb2b8bd5b
Groups and collection: create group from collection You could still create groups as before, with Ctl + G. This will create a group with a single visible collection. However you can also create a group from an existing collection. Just go to the menu you get in the outliner when clicking in a collection and pick "Create Group". Remember to instance the group afterwards, or link it into a new scene or file. The group and the collection are not kept in sync afterwards. You need to manually edit the group for further changes. =================================================================== M source/blender/blenkernel/BKE_collection.h M source/blender/blenkernel/intern/collection.c M source/blender/editors/space_outliner/outliner_tools.c M source/blender/makesrna/intern/rna_layer.c M tests/python/view_layer/CMakeLists.txt A tests/python/view_layer/test_group_a.py A tests/python/view_layer/test_group_b.py A tests/python/view_layer/test_group_c.py A tests/python/view_layer/test_group_d.py =================================================================== diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h index c305a05ddd0..48b4ff881ae 100644 --- a/source/blender/blenkernel/BKE_collection.h +++ b/source/blender/blenkernel/BKE_collection.h @@ -58,6 +58,8 @@ bool BKE_collection_object_remove(struct Main *bmain, struct ID *owner_id, struc bool BKE_collections_object_remove(struct Main *bmain, struct ID *owner_id, struct Object *object, const bool free_us); void BKE_collection_object_move(struct ID *owner_id, struct SceneCollection *sc_dst, struct SceneCollection *sc_src, struct Object *ob); +struct Group *BKE_collection_group_create(struct Main *bmain, struct Scene *scene, struct LayerCollection *lc); + void BKE_collection_reinsert_after(const struct Scene *scene, struct SceneCollection *sc_reinsert, struct SceneCollection *sc_after); void BKE_collection_reinsert_into(struct SceneCollection *sc_reinsert, struct SceneCollection *sc_into); diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index aa5b9e7eb25..8d69563f5ff 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -34,6 +34,7 @@ #include "BLI_string_utils.h" #include "BKE_collection.h" +#include "BKE_group.h" #include "BKE_idprop.h" #include "BKE_layer.h" #include "BKE_library.h" @@ -48,6 +49,9 @@ #include "MEM_guardedalloc.h" +/* Prototypes. */ +static bool is_collection_in_tree(const struct SceneCollection *sc_reference, struct SceneCollection *sc_parent); + static SceneCollection *collection_master_from_id(const ID *owner_id) { switch (GS(owner_id->name)) { @@ -407,6 +411,82 @@ bool BKE_collections_object_remove(Main *bmain, ID *owner_id, Object *ob, const return removed; } +static void layer_collection_sync(LayerCollection *lc_dst, LayerCollection *lc_src) +{ + lc_dst->flag = lc_src->flag; + + /* Pending: sync overrides. */ + IDP_MergeGroup(lc_dst->properties, lc_src->properties, true); + + /* Continue recursively. */ + LayerCollection *lc_dst_nested, *lc_src_nested; + lc_src_nested = lc_src->layer_collections.first; + for (lc_dst_nested = lc_dst->layer_collections.first; + lc_dst_nested && lc_src_nested; + lc_dst_nested = lc_dst_nested->next, lc_src_nested = lc_src_nested->next) + { + layer_collection_sync(lc_dst_nested, lc_src_nested); + } +} + +/** + * Leave only the master collection in, remove everything else. + * @param group + */ +static void collection_group_cleanup(Group *group) +{ + /* Unlink all the LayerCollections. */ + while (group->view_layer->layer_collections.last != NULL) { + BKE_collection_unlink(group->view_layer, group->view_layer->layer_collections.last); + } + + /* Remove all the SceneCollections but the master. */ + collection_free(group->collection, false); +} + +/** + * Create a group from a collection + * + * Any ViewLayer that may have this the related SceneCollection linked is converted + * to a Group Collection. + */ +Group *BKE_collection_group_create(Main *bmain, Scene *scene, LayerCollection *lc_src) +{ + SceneCollection *sc_dst, *sc_src = lc_src->scene_collection; + LayerCollection *lc_dst; + + /* The master collection can't be converted. */ + if (sc_src == BKE_collection_master(&scene->id)) { + return NULL; + } + + /* If a sub-collection of sc_dst is directly linked into a ViewLayer we can't convert. */ + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + for (LayerCollection *lc_child = view_layer->layer_collections.first; lc_child; lc_child = lc_child->next) { + if (is_collection_in_tree(lc_child->scene_collection, sc_src)) { + return NULL; + } + } + } + + /* Create new group with the same data as the original collection. */ + Group *group = BKE_group_add(bmain, sc_src->name); + collection_group_cleanup(group); + + sc_dst = BKE_collection_add(&group->id, NULL, COLLECTION_TYPE_GROUP_INTERNAL, sc_src->name); + BKE_collection_copy_data(sc_dst, sc_src, 0); + FOREACH_SCENE_COLLECTION(&group->id, sc_group) + { + sc_group->type = COLLECTION_TYPE_GROUP_INTERNAL; + } + FOREACH_SCENE_COLLECTION_END + + lc_dst = BKE_collection_link(group->view_layer, sc_dst); + layer_collection_sync(lc_dst, lc_src); + + return group; +} + /* ---------------------------------------------------------------------- */ /* Outliner drag and drop */ diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 203942b3c9b..99fd539293f 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -664,6 +664,7 @@ typedef enum eOutliner_PropCollectionOps { OL_COLLECTION_OP_COLLECTION_NEW, OL_COLLECTION_OP_COLLECTION_DEL, OL_COLLECTION_OP_COLLECTION_UNLINK, + OL_COLLECTION_OP_GROUP_CREATE, } eOutliner_PropCollectionOps; static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg)) @@ -878,6 +879,17 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel TODO_LAYER_OPERATORS; /* this shouldn't be in the menu in those cases */ } } + else if (event == OL_COLLECTION_OP_GROUP_CREATE) { + Main *bmain = CTX_data_main(C); + BKE_collection_group_create(bmain, scene, lc); + DEG_relations_tag_update(bmain); + /* TODO(sergey): Use proper flag for tagging here. */ + DEG_id_tag_update(&scene->id, 0); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + } + else { + BLI_assert(!"Collection operation not fully implemented!"); + } } static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb, @@ -1808,6 +1820,7 @@ static EnumPropertyItem prop_collection_op_none_types[] = { {OL_COLLECTION_OP_COLLECTION_NEW, "COLLECTION_NEW", ICON_NEW, "New Collection", "Add a new nested collection"}, {OL_COLLECTION_OP_COLLECTION_UNLINK, "COLLECTION_UNLINK", ICON_UNLINKED, "Unlink", "Unlink collection"}, {OL_COLLECTION_OP_COLLECTION_DEL, "COLLECTION_DEL", ICON_X, "Delete Collection", "Delete the collection"}, + {OL_COLLECTION_OP_GROUP_CREATE, "GROUP_CREATE", ICON_GROUP, "Create Group", "Turn the collection into a group collection"}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index df6c2188799..557b9a11997 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -738,6 +738,32 @@ static void rna_LayerCollection_enable_set( WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); } +static Group *rna_LayerCollection_create_group( + ID *id, LayerCollection *layer_collection, Main *bmain, bContext *C, ReportList *reports) +{ + Group *group; + Scene *scene = (Scene *)id; + SceneCollection *scene_collection = layer_collection->scene_collection; + + /* The master collection can't be converted. */ + if (scene_collection == BKE_collection_master(&scene->id)) { + BKE_report(reports, RPT_ERROR, "The master collection can't be converted to group"); + return NULL; + } + + group = BKE_collection_group_create(bmain, scene, layer_collection); + if (group == NULL) { + BKE_reportf(reports, RPT_ERROR, "Failed to convert collection %s", scene_collection->name); + return NULL; + } + + DEG_relations_tag_update(bmain); + /* TODO(sergey): Use proper flag for tagging here. */ + DEG_id_tag_update(&scene->id, 0); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + return group; +} + static int rna_LayerCollections_active_collection_index_get(PointerRNA *ptr) { ViewLayer *view_layer = (ViewLayer *)ptr->data; @@ -2019,6 +2045,12 @@ static void rna_def_layer_collection(BlenderRNA *brna) parm = RNA_def_boolean(func, "value", 1, "Enable", ""); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + func = RNA_def_function(srna, "create_group", "rna_LayerCollection_create_group"); + RNA_def_function_ui_description(func, "Enable or disable a collection"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, "result", "Group", "", "Newly created Group"); + RNA_def_function_return(func, parm); + /* Flags */ prop = RNA_def_property(srna, "is_enabled", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_DISABLED); diff --git a/tests/python/view_layer/CMakeLists.txt b/tests/python/view_layer/CMakeLists.txt index e5b271dcb1e..22cfcd344f3 100644 --- a/tests/python/view_layer/CMakeLists.txt +++ b/tests/python/view_layer/CMakeLists.txt @@ -87,6 +87,10 @@ VIEW_LAYER_TEST(evaluation_selectability_c) VIEW_LAYER_TEST(evaluation_selectability_d) VIEW_LAYER_TEST(evaluation_selectability_e) VIEW_LAYER_TEST(evaluation_selectability_f) +VIEW_LAYER_TEST(group_a) +VIEW_LAYER_TEST(group_b) +VIEW_LAYER_TEST(group_c) +VIEW_LAYER_TEST(group_d) VIEW_LAYER_TEST(object_add_cylinder) VIEW_LAYER_TEST(object_add_empty) VIEW_LAYER_TEST(object_add_torus) diff --git a/tests/python/view_layer/test_group_a.py b/tests/python/view_layer/test_group_a.py new file mode 100644 index 00000000000..6e1b83efbe5 --- /dev/null +++ b/tests/python/view_layer/test_group_a.py @@ -0,0 +1,46 @@ +# ############################################################ +# Importing - Same For All Render Layer Tests +# ############################################################ + +import unittest +import os +import sys + +from view_layer_common import * + + +# ############################################################ +# Testing +# ############################################################ + +class UnitTesting(ViewLayerTesting): + def test_group_create_basic(self): + """ + See if the creation of new groups is not crashing anything. + """ + import bpy + scene = bpy.context.scene + layer_collection = bpy.context.layer_collection + + # Cleanup Viewport view layer + # technically this shouldn't be needed but + # for now we need it because depsgraph build all the view layers + # at once. + + while l @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org https://lists.blender.org/mailman/listinfo/bf-blender-cvs