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.
This commit is contained in:
Bastien Montagne 2018-10-24 14:45:18 +02:00
parent 91c6beb28a
commit a211937892
Notes: blender-bot 2023-02-14 05:09:28 +01:00
Referenced by issue #57373, NLA tracks created by script do not animate.
Referenced by issue #57361, Creating a new scene with a full copy doesn't work ( objects are instanced )
1 changed files with 27 additions and 32 deletions

View File

@ -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