diff options
author | Dalai Felinto <dfelinto@gmail.com> | 2019-02-26 22:15:30 +0300 |
---|---|---|
committer | Dalai Felinto <dfelinto@gmail.com> | 2019-03-01 17:44:19 +0300 |
commit | e7ea99af1b0d933b9323be39d8b1c6f683bfba52 (patch) | |
tree | 461d23594737af40f62f533dbe357d2264134d1d /source/blender/blenkernel/intern/collection.c | |
parent | 619c65a4b3372b45a8d6d7317672c48d248104ca (diff) |
Outliner: Collection - Duplicate Hierarchy, and Duplicate Linked Hierarchy
As per the suggestion on T57064, this introduces two new options to duplicate collections.
We then have:
* Duplicate > Collection (New collection with linked content).
* Duplicate > Hierachy (Duplicate entire hierarchy and make all contents single user).
* Duplicate > Linked Hierarchy (Duplicate entire hierarchy keeping content linked with original).
Development TODO: `single_object_users` can/should use the new functions.
Reviewers: brecht, mont29
Subscribers: pablovazquez, billreynish, JulienKaspar
Differential Revision: https://developer.blender.org/D4394
Diffstat (limited to 'source/blender/blenkernel/intern/collection.c')
-rw-r--r-- | source/blender/blenkernel/intern/collection.c | 65 |
1 files changed, 62 insertions, 3 deletions
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 37ee6fbeaae..ce7a5b141a4 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -209,17 +209,72 @@ void BKE_collection_copy_data( } } +static void collection_duplicate_recursive(Main *bmain, GHash *visited, Collection *collection, const int dupflag) +{ + const bool is_first_run = (visited == NULL); + if (is_first_run) { + visited = BLI_ghash_ptr_new(__func__); + BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false); + } + + if (collection->id.tag & LIB_TAG_DOIT) { + return; + } + collection->id.tag |= LIB_TAG_DOIT; + + ListBase collection_object_list = {NULL, NULL}; + BLI_duplicatelist(&collection_object_list, &collection->gobject); + for (CollectionObject *cob = collection_object_list.first; cob; cob = cob->next) { + Object *ob_old = cob->ob; + Object *ob_new = NULL; + void **ob_key_p, **ob_value_p; + + if (!BLI_ghash_ensure_p_ex(visited, ob_old, &ob_key_p, &ob_value_p)) { + ob_new = BKE_object_duplicate(bmain, ob_old, dupflag); + *ob_key_p = ob_old; + *ob_value_p = ob_new; + } + else { + ob_new = *ob_value_p; + } + + collection_object_add(bmain, collection, ob_new, 0, true); + collection_object_remove(bmain, collection, ob_old, false); + } + BLI_freelistN(&collection_object_list); + + ListBase collection_child_list = {NULL, NULL}; + BLI_duplicatelist(&collection_child_list, &collection->children); + for (CollectionChild *child = collection_child_list.first; child; child = child->next) { + Collection *child_collection_old = child->collection; + Collection *child_collection_new = BKE_collection_copy(bmain, collection, child_collection_old); + + collection_duplicate_recursive(bmain, visited, child_collection_new, dupflag); + collection_child_remove(collection, child_collection_old); + } + BLI_freelistN(&collection_child_list); + + if (is_first_run) { + BLI_ghash_free(visited, NULL, NULL); + } +} + /** * Makes a shallow copy of a Collection * - * Add a new collection in the same level as the old one, copy any nested collections - * but link the objects to the new collection (as oppose to copy them). + * Add a new collection in the same level as the old one, link any nested collections + * and finally link the objects to the new collection (as oppose to copy them). */ Collection *BKE_collection_copy(Main *bmain, Collection *parent, Collection *collection) { + return BKE_collection_duplicate(bmain, parent, collection, false, false); +} + +Collection *BKE_collection_duplicate(Main *bmain, Collection *parent, Collection *collection, const bool do_hierarchy, const bool do_deep_copy) +{ /* It's not allowed to copy the master collection. */ if (collection->flag & COLLECTION_IS_MASTER) { - BLI_assert("!Master collection can't be copied"); + BLI_assert("!Master collection can't be duplicated"); return NULL; } @@ -241,6 +296,10 @@ Collection *BKE_collection_copy(Main *bmain, Collection *parent, Collection *col } } + if (do_hierarchy) { + collection_duplicate_recursive(bmain, NULL, collection_new, (do_deep_copy) ? U.dupflag : 0); + } + BKE_main_collection_sync(bmain); return collection_new; |