From a211937892f55ac9510e0f9b625c1bd24cc12550 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 24 Oct 2018 14:45:18 +0200 Subject: Fix T57361: Creating a new scene with a full copy doesn't work. BKE_scene_copy() & co. were pretty much doing nothing right... Was a tough fight, but at least now they should behave a tad better (and reported issue is fixed). Proper fix is to fully rewrite that PoS, it was already a mess without collections, now it's even hairier to handle properly, we need to use modern new ID handling API for that (and maybe extend it a bit as needed). But way too late to do that in 2.80. --- source/blender/editors/object/object_relations.c | 59 +++++++++++------------- 1 file changed, 27 insertions(+), 32 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 306cdc9472a..8464c49f374 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1626,64 +1626,56 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot) /**************************** Make Single User ********************************/ -static Object *single_object_users_object(Main *bmain, Object *ob) -{ - /* base gets copy of object */ - Object *obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); - - - id_us_plus(&obn->id); - id_us_min(&ob->id); - return obn; -} - static void libblock_relink_collection(Collection *collection) { - for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { - BKE_libblock_relink_to_newid(&cob->ob->id); - } + BKE_libblock_relink_to_newid(&collection->id); for (CollectionChild *child = collection->children.first; child; child = child->next) { libblock_relink_collection(child->collection); } } -static void single_object_users_collection(Main *bmain, Scene *scene, Collection *collection, const int flag, const bool copy_collections) +static void single_object_users_collection( + Main *bmain, Scene *scene, Collection *collection, + const int flag, const bool copy_collections, const bool is_master_collection) { + /* Generate new copies for objects in given collection and all its children, + * and optionnaly also copy collections themselves. */ + if (copy_collections && !is_master_collection) { + collection = ID_NEW_SET(collection, BKE_collection_copy(bmain, NULL, collection)); + } + + /* We do not remap to new objects here, this is done in separate step. */ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { Object *ob = cob->ob; /* an object may be in more than one collection */ if ((ob->id.newid == NULL) && ((ob->flag & flag) == flag)) { if (!ID_IS_LINKED(ob) && ob->id.us > 1) { - cob->ob = single_object_users_object(bmain, cob->ob); + ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); } } } for (CollectionChild *child = collection->children.first; child; child = child->next) { - single_object_users_collection(bmain, scene, child->collection, flag, copy_collections); + single_object_users_collection(bmain, scene, child->collection, flag, copy_collections, false); } } /* Warning, sets ID->newid pointers of objects and collections, but does not clear them. */ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_collections) { - Collection *collection, *collectionn; - - /* duplicate all the objects of the scene */ + /* duplicate all the objects of the scene (and matching collections, if required). */ Collection *master_collection = BKE_collection_master(scene); - single_object_users_collection(bmain, scene, master_collection, flag, copy_collections); - - /* loop over ViewLayers and assign the pointers accordingly */ - for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - ID_NEW_REMAP(base->object); - } - } + single_object_users_collection(bmain, scene, master_collection, flag, copy_collections, true); /* duplicate collections that consist entirely of duplicated objects */ - for (collection = bmain->collection.first; collection; collection = collection->id.next) { - if (copy_collections) { + /* XXX I guess that was designed for calls from 'make single user' operator... But since copy_collection is + * always false then, was not doing anything. And that kind of behavior should be added at operator level, + * not in a utility function also used by rather different code... */ +#if 0 + if (copy_collections) { + Collection *collection, *collectionn; + for (collection = bmain->collection.first; collection; collection = collection->id.next) { bool all_duplicated = true; bool any_duplicated = false; @@ -1705,6 +1697,10 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in } } } +#endif + + /* Collection and object pointers in collections */ + libblock_relink_collection(master_collection); /* collection pointers in scene */ BKE_scene_groups_relink(scene); @@ -1713,8 +1709,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in ID_NEW_REMAP(scene->camera); if (v3d) ID_NEW_REMAP(v3d->camera); - /* object and collection pointers */ - libblock_relink_collection(master_collection); + BKE_scene_collection_sync(scene); } /* not an especially efficient function, only added so the single user -- cgit v1.2.3