diff options
-rw-r--r-- | source/blender/blenkernel/BKE_collection.h | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_lib_id.h | 10 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_object.h | 5 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/collection.c | 62 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/object.c | 382 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/scene.c | 68 | ||||
-rw-r--r-- | source/blender/editors/object/object_add.c | 18 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/outliner_collections.c | 3 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_userdef_types.h | 7 | ||||
-rw-r--r-- | tests/python/bl_pyapi_idprop_datablock.py | 6 |
10 files changed, 310 insertions, 255 deletions
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h index 2db2be131df..4cf33640ebd 100644 --- a/source/blender/blenkernel/BKE_collection.h +++ b/source/blender/blenkernel/BKE_collection.h @@ -62,8 +62,8 @@ bool BKE_collection_delete(struct Main *bmain, struct Collection *collection, bo struct Collection *BKE_collection_duplicate(struct Main *bmain, struct Collection *parent, struct Collection *collection, - const bool do_objects, - const bool do_obdata); + const uint duplicate_flags, + const uint duplicate_options); /* Master Collection for Scene */ diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index 7f5a6e3e36a..8ee5562baae 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -144,6 +144,16 @@ struct ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +/** + * Duplicate (a.k.a. deep copy) common processing options. + * See also eDupli_ID_Flags for options controlling what kind of IDs to duplicate. + */ +typedef enum eLibIDDuplicateFlags { + /** This call to a duplicate function is part of another call for some parent ID. + * Therefore, this sub-process should not clear `newid` pointers, nor handle remapping itself. */ + LIB_ID_DUPLICATE_IS_SUBPROCESS = 1 << 0, +} eLibIDDuplicateFlags; + /* lib_remap.c (keep here since they're general functions) */ /** * New freeing logic options. diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 342e48f5016..d830a35dda0 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -138,8 +138,9 @@ bool BKE_object_is_libdata(const struct Object *ob); bool BKE_object_obdata_is_libdata(const struct Object *ob); struct Object *BKE_object_duplicate(struct Main *bmain, - const struct Object *ob, - const uint dupflag); + struct Object *ob, + const uint dupflag, + const uint duplicate_options); void BKE_object_obdata_size_init(struct Object *ob, const float scale); diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 9abcce7c38f..6127ad075f4 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -326,15 +326,16 @@ bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy) static Collection *collection_duplicate_recursive(Main *bmain, Collection *parent, Collection *collection_old, - const bool do_objects, - const bool do_obdata) + const eDupli_ID_Flags duplicate_flags, + const eLibIDDuplicateFlags duplicate_options) { Collection *collection_new; bool do_full_process = false; - const int object_dupflag = (do_obdata) ? U.dupflag : 0; const bool is_collection_master = (collection_old->flag & COLLECTION_IS_MASTER) != 0; const bool is_collection_liboverride = ID_IS_OVERRIDE_LIBRARY(collection_old); + const bool do_objects = (duplicate_flags & USER_DUP_OBJECT) != 0; + if (is_collection_master) { /* We never duplicate master collections here, but we can still deep-copy their objects and * collections. */ @@ -391,8 +392,8 @@ static Collection *collection_duplicate_recursive(Main *bmain, } if (ob_new == NULL) { - ob_new = BKE_object_duplicate(bmain, ob_old, (eDupli_ID_Flags)object_dupflag); - ID_NEW_SET(ob_old, ob_new); + ob_new = BKE_object_duplicate( + bmain, ob_old, duplicate_flags, duplicate_options | LIB_ID_DUPLICATE_IS_SUBPROCESS); } collection_object_add(bmain, collection_new, ob_new, 0, true); @@ -410,7 +411,7 @@ static Collection *collection_duplicate_recursive(Main *bmain, } collection_duplicate_recursive( - bmain, collection_new, child_collection_old, do_objects, do_obdata); + bmain, collection_new, child_collection_old, duplicate_flags, duplicate_options); collection_child_remove(collection_new, child_collection_old); } @@ -420,7 +421,9 @@ static Collection *collection_duplicate_recursive(Main *bmain, /** * Make a deep copy (aka duplicate) of the given collection and all of its children, recusrsively. * - * \warning This functions will clear all \a bmain id.idnew pointers. + * \warning This functions will clear all \a bmain #ID.idnew pointers, unless \a + * LIB_ID_DUPLICATE_IS_SUBPROCESS duplicate option is passed on, in which case caller is reponsible + * to reconstruct collection dependencies informations (i.e. call #BKE_main_collection_sync). * * \param do_objects: If true, it will also make copies of objects. * \param do_obdata: If true, it will also make duplicates of objects, @@ -430,23 +433,44 @@ static Collection *collection_duplicate_recursive(Main *bmain, Collection *BKE_collection_duplicate(Main *bmain, Collection *parent, Collection *collection, - const bool do_objects, - const bool do_obdata) + eDupli_ID_Flags duplicate_flags, + eLibIDDuplicateFlags duplicate_options) { - BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false); - BKE_main_id_clear_newpoins(bmain); + const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0; - Collection *collection_new = collection_duplicate_recursive( - bmain, parent, collection, do_objects, do_obdata); + if (!is_subprocess) { + BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false); + BKE_main_id_clear_newpoins(bmain); + } - /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW.*/ - BKE_libblock_relink_to_newid(&collection_new->id); + Collection *collection_new = collection_duplicate_recursive( + bmain, parent, collection, duplicate_flags, duplicate_options); + + if (!is_subprocess) { + /* `collection_duplicate_recursive` will also tag our 'root' collection, whic is not required + * unless its duplication is a subprocess of another one. */ + collection_new->id.tag &= ~LIB_TAG_NEW; + + /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW.*/ + BKE_libblock_relink_to_newid(&collection_new->id); + +#ifndef NDEBUG + /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */ + ID *id_iter; + FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { + if (id_iter->tag & LIB_TAG_NEW) { + BLI_assert((id_iter->tag & LIB_TAG_NEW) == 0); + } + } + FOREACH_MAIN_ID_END; +#endif - /* Cleanup. */ - BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false); - BKE_main_id_clear_newpoins(bmain); + /* Cleanup. */ + BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false); + BKE_main_id_clear_newpoins(bmain); - BKE_main_collection_sync(bmain); + BKE_main_collection_sync(bmain); + } return collection_new; } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index fd7ddc9eb6d..15cfe4a1d6a 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1758,31 +1758,35 @@ Object *BKE_object_copy(Main *bmain, const Object *ob) * \note Caller MUST free \a newid pointers itself (#BKE_main_id_clear_newpoins()) and call updates * of DEG too (#DAG_relations_tag_update()). */ -Object *BKE_object_duplicate(Main *bmain, const Object *ob, const uint dupflag) +Object *BKE_object_duplicate(Main *bmain, + Object *ob, + const eDupli_ID_Flags dupflag, + const eLibIDDuplicateFlags duplicate_options) { + const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0; + + if (!is_subprocess) { + BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false); + BKE_main_id_clear_newpoins(bmain); + } + Material ***matarar; - ID *id; - int a, didit; + ID *id, *id_new; + int a; const bool is_object_liboverride = ID_IS_OVERRIDE_LIBRARY(ob); - Object *obn = BKE_object_copy(bmain, ob); + Object *obn; + BKE_id_copy(bmain, &ob->id, (ID **)&obn); + id_us_min(&obn->id); + if (is_subprocess) { + ID_NEW_SET(ob, obn); + } /* 0 == full linked. */ if (dupflag == 0) { return obn; } -#define ID_NEW_REMAP_US(a) \ - if ((a)->id.newid) { \ - (a) = (void *)(a)->id.newid; \ - (a)->id.us++; \ - } -#define ID_NEW_REMAP_US2(a) \ - if (((ID *)a)->newid) { \ - (a) = ((ID *)a)->newid; \ - ((ID *)a)->us++; \ - } - /* duplicates using userflags */ if (dupflag & USER_DUP_ACT) { BKE_animdata_copy_id_action(bmain, &obn->id, true); @@ -1791,19 +1795,16 @@ Object *BKE_object_duplicate(Main *bmain, const Object *ob, const uint dupflag) if (dupflag & USER_DUP_MAT) { for (a = 0; a < obn->totcol; a++) { id = (ID *)obn->mat[a]; - if (id) { + if (id && id->newid == NULL) { if (is_object_liboverride && ID_IS_LINKED(id)) { continue; } - ID_NEW_REMAP_US(obn->mat[a]) - else - { - obn->mat[a] = ID_NEW_SET(obn->mat[a], BKE_material_copy(bmain, obn->mat[a])); - if (dupflag & USER_DUP_ACT) { - BKE_animdata_copy_id_action(bmain, &obn->mat[a]->id, true); - } + BKE_id_copy_ex(bmain, id, &id_new, 0); + id_us_min(id_new); + ID_NEW_SET(id, id_new); + if (dupflag & USER_DUP_ACT) { + BKE_animdata_copy_id_action(bmain, id_new, true); } - id_us_min(id); } } } @@ -1811,205 +1812,152 @@ Object *BKE_object_duplicate(Main *bmain, const Object *ob, const uint dupflag) ParticleSystem *psys; for (psys = obn->particlesystem.first; psys; psys = psys->next) { id = (ID *)psys->part; - if (id) { + if (id && id->newid == NULL) { if (is_object_liboverride && ID_IS_LINKED(id)) { continue; } - ID_NEW_REMAP_US(psys->part) - else - { - psys->part = ID_NEW_SET(psys->part, BKE_particlesettings_copy(bmain, psys->part)); - if (dupflag & USER_DUP_ACT) { - BKE_animdata_copy_id_action(bmain, &psys->part->id, true); - } + BKE_id_copy_ex(bmain, id, &id_new, 0); + id_us_min(id_new); + ID_NEW_SET(id, id_new); + if (dupflag & USER_DUP_ACT) { + BKE_animdata_copy_id_action(bmain, id_new, true); } - id_us_min(id); } } } id = obn->data; - didit = 0; - - if (!is_object_liboverride || !ID_IS_LINKED(id)) { - switch (obn->type) { - case OB_MESH: - if (dupflag & USER_DUP_MESH) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_mesh_copy(bmain, obn->data)); - didit = 1; - } - id_us_min(id); - } - break; - case OB_CURVE: - if (dupflag & USER_DUP_CURVE) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data)); - didit = 1; + bool duplicated_obdata = false; + + if (id && id->newid == NULL) { + if (!is_object_liboverride || !ID_IS_LINKED(id)) { + switch (obn->type) { + case OB_MESH: + if (dupflag & USER_DUP_MESH) { + BKE_id_copy(bmain, id, &id_new); + id_us_min(id_new); + ID_NEW_SET(id, id_new); + duplicated_obdata = true; } - id_us_min(id); - } - break; - case OB_SURF: - if (dupflag & USER_DUP_SURF) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data)); - didit = 1; + break; + case OB_CURVE: + if (dupflag & USER_DUP_CURVE) { + BKE_id_copy(bmain, id, &id_new); + id_us_min(id_new); + ID_NEW_SET(id, id_new); + duplicated_obdata = true; } - id_us_min(id); - } - break; - case OB_FONT: - if (dupflag & USER_DUP_FONT) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data)); - didit = 1; + break; + case OB_SURF: + if (dupflag & USER_DUP_SURF) { + BKE_id_copy(bmain, id, &id_new); + id_us_min(id_new); + ID_NEW_SET(id, id_new); + duplicated_obdata = true; } - id_us_min(id); - } - break; - case OB_MBALL: - if (dupflag & USER_DUP_MBALL) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_mball_copy(bmain, obn->data)); - didit = 1; + break; + case OB_FONT: + if (dupflag & USER_DUP_FONT) { + BKE_id_copy(bmain, id, &id_new); + id_us_min(id_new); + ID_NEW_SET(id, id_new); + duplicated_obdata = true; } - id_us_min(id); - } - break; - case OB_LAMP: - if (dupflag & USER_DUP_LAMP) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_light_copy(bmain, obn->data)); - didit = 1; + break; + case OB_MBALL: + if (dupflag & USER_DUP_MBALL) { + BKE_id_copy(bmain, id, &id_new); + id_us_min(id_new); + ID_NEW_SET(id, id_new); + duplicated_obdata = true; } - id_us_min(id); - } - break; - case OB_ARMATURE: - if (dupflag != 0) { - DEG_id_tag_update(&obn->id, ID_RECALC_GEOMETRY); - if (obn->pose) { - BKE_pose_tag_recalc(bmain, obn->pose); + break; + case OB_LAMP: + if (dupflag & USER_DUP_LAMP) { + BKE_id_copy(bmain, id, &id_new); + id_us_min(id_new); + ID_NEW_SET(id, id_new); + duplicated_obdata = true; } + break; + case OB_ARMATURE: if (dupflag & USER_DUP_ARM) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_armature_copy(bmain, obn->data)); - BKE_pose_rebuild(bmain, obn, obn->data, true); - didit = 1; - } - id_us_min(id); + BKE_id_copy(bmain, id, &id_new); + id_us_min(id_new); + ID_NEW_SET(id, id_new); + duplicated_obdata = true; } - } - break; - case OB_LATTICE: - if (dupflag != 0) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_lattice_copy(bmain, obn->data)); - didit = 1; + break; + case OB_LATTICE: + if (dupflag != 0) { + BKE_id_copy(bmain, id, &id_new); + id_us_min(id_new); + ID_NEW_SET(id, id_new); + duplicated_obdata = true; } - id_us_min(id); - } - break; - case OB_CAMERA: - if (dupflag != 0) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_camera_copy(bmain, obn->data)); - didit = 1; + break; + case OB_CAMERA: + if (dupflag != 0) { + BKE_id_copy(bmain, id, &id_new); + id_us_min(id_new); + ID_NEW_SET(id, id_new); + duplicated_obdata = true; } - id_us_min(id); - } - break; - case OB_LIGHTPROBE: - if (dupflag & USER_DUP_LIGHTPROBE) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_lightprobe_copy(bmain, obn->data)); - didit = 1; + break; + case OB_LIGHTPROBE: + if (dupflag & USER_DUP_LIGHTPROBE) { + BKE_id_copy(bmain, id, &id_new); + id_us_min(id_new); + ID_NEW_SET(id, id_new); + duplicated_obdata = true; } - id_us_min(id); - } - break; - case OB_SPEAKER: - if (dupflag != 0) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_speaker_copy(bmain, obn->data)); - didit = 1; + break; + case OB_SPEAKER: + if (dupflag != 0) { + BKE_id_copy(bmain, id, &id_new); + id_us_min(id_new); + ID_NEW_SET(id, id_new); + duplicated_obdata = true; } - id_us_min(id); - } - break; - case OB_GPENCIL: - if (dupflag & USER_DUP_GPENCIL) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_gpencil_copy(bmain, obn->data)); - didit = 1; + break; + case OB_GPENCIL: + if (dupflag & USER_DUP_GPENCIL) { + BKE_id_copy(bmain, id, &id_new); + id_us_min(id_new); + ID_NEW_SET(id, id_new); + duplicated_obdata = true; } - id_us_min(id); - } - break; - case OB_HAIR: - if (dupflag & USER_DUP_HAIR) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_hair_copy(bmain, obn->data)); - didit = 1; + break; + case OB_HAIR: + if (dupflag & USER_DUP_HAIR) { + BKE_id_copy(bmain, id, &id_new); + id_us_min(id_new); + ID_NEW_SET(id, id_new); + duplicated_obdata = true; } - id_us_min(id); - } - break; - case OB_POINTCLOUD: - if (dupflag & USER_DUP_POINTCLOUD) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_pointcloud_copy(bmain, obn->data)); - didit = 1; + break; + case OB_POINTCLOUD: + if (dupflag & USER_DUP_POINTCLOUD) { + BKE_id_copy(bmain, id, &id_new); + id_us_min(id_new); + ID_NEW_SET(id, id_new); + duplicated_obdata = true; } - id_us_min(id); - } - break; - case OB_VOLUME: - if (dupflag & USER_DUP_VOLUME) { - ID_NEW_REMAP_US2(obn->data) - else - { - obn->data = ID_NEW_SET(obn->data, BKE_volume_copy(bmain, obn->data)); - didit = 1; + break; + case OB_VOLUME: + if (dupflag & USER_DUP_VOLUME) { + BKE_id_copy(bmain, id, &id_new); + id_us_min(id_new); + ID_NEW_SET(id, id_new); + duplicated_obdata = true; } - id_us_min(id); - } - break; + break; + } } } /* Check if obdata is copied. */ - if (didit) { + if (duplicated_obdata) { Key *key = BKE_key_from_object(obn); Key *oldkey = BKE_key_from_object(ob); @@ -2018,7 +1966,7 @@ Object *BKE_object_duplicate(Main *bmain, const Object *ob, const uint dupflag) } if (dupflag & USER_DUP_ACT) { - BKE_animdata_copy_id_action(bmain, (ID *)obn->data, true); + BKE_animdata_copy_id_action(bmain, id_new, true); if (key) { BKE_animdata_copy_id_action(bmain, (ID *)key, true); } @@ -2029,29 +1977,49 @@ Object *BKE_object_duplicate(Main *bmain, const Object *ob, const uint dupflag) if (matarar) { for (a = 0; a < obn->totcol; a++) { id = (ID *)(*matarar)[a]; - if (id) { + if (id && id->newid == NULL) { if (is_object_liboverride && ID_IS_LINKED(id)) { continue; } - ID_NEW_REMAP_US((*matarar)[a]) - else - { - (*matarar)[a] = ID_NEW_SET((*matarar)[a], BKE_material_copy(bmain, (*matarar)[a])); - if (dupflag & USER_DUP_ACT) { - BKE_animdata_copy_id_action(bmain, &(*matarar)[a]->id, true); - } + BKE_id_copy_ex(bmain, id, &id_new, 0); + id_us_min(id_new); + ID_NEW_SET(id, id_new); + if (dupflag & USER_DUP_ACT) { + BKE_animdata_copy_id_action(bmain, id_new, true); } - id_us_min(id); } } } } } -#undef ID_NEW_REMAP_US -#undef ID_NEW_REMAP_US2 + if (!is_subprocess) { + /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW.*/ + BKE_libblock_relink_to_newid(&obn->id); + +#ifndef NDEBUG + /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */ + ID *id_iter; + FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { + BLI_assert((id_iter->tag & LIB_TAG_NEW) == 0); + } + FOREACH_MAIN_ID_END; +#endif + + /* Cleanup. */ + BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false); + BKE_main_id_clear_newpoins(bmain); + } + + if (obn->type == OB_ARMATURE) { + DEG_id_tag_update(&obn->id, ID_RECALC_GEOMETRY); + if (obn->pose) { + BKE_pose_tag_recalc(bmain, obn->pose); + } + // BKE_pose_rebuild(bmain, obn, obn->data, true); + } - if (ob->data != NULL) { + if (obn->data != NULL) { DEG_id_tag_update_ex(bmain, (ID *)obn->data, ID_RECALC_EDITORS); } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index d3f1efb5975..8e1800ad122 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -829,41 +829,79 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type) /* Extra actions, most notably SCE_FULL_COPY also duplicates several 'children' datablocks. */ if (type == SCE_COPY_FULL) { + /* Scene duplication is always root of duplication currently. */ + const bool is_subprocess = false; + ID *id, *id_new; + + if (!is_subprocess) { + BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false); + BKE_main_id_clear_newpoins(bmain); + } + /* Copy Freestyle LineStyle datablocks. */ LISTBASE_FOREACH (ViewLayer *, view_layer_dst, &sce_copy->view_layers) { LISTBASE_FOREACH ( FreestyleLineSet *, lineset, &view_layer_dst->freestyle_config.linesets) { - if (lineset->linestyle) { - if (is_scene_liboverride && ID_IS_LINKED(lineset->linestyle)) { + id = &lineset->linestyle->id; + if (id && id->newid == NULL) { + if (is_scene_liboverride && ID_IS_LINKED(id)) { continue; } - id_us_min(&lineset->linestyle->id); - BKE_id_copy_ex( - bmain, (ID *)lineset->linestyle, (ID **)&lineset->linestyle, LIB_ID_COPY_ACTIONS); + BKE_id_copy_ex(bmain, id, &id_new, LIB_ID_COPY_ACTIONS); + id_us_min(id_new); + ID_NEW_SET(id, id_new); } } } /* Full copy of world (included animations) */ - if (sce_copy->world) { - if (!is_scene_liboverride || !ID_IS_LINKED(sce_copy->world)) { - id_us_min(&sce_copy->world->id); - BKE_id_copy_ex( - bmain, (ID *)sce_copy->world, (ID **)&sce_copy->world, LIB_ID_COPY_ACTIONS); + id = &sce->world->id; + if (id && id->newid == NULL) { + if (!is_scene_liboverride || !ID_IS_LINKED(id)) { + BKE_id_copy_ex(bmain, id, &id_new, LIB_ID_COPY_ACTIONS); + id_us_min(id_new); + ID_NEW_SET(id, id_new); } } /* Full copy of GreasePencil. */ - if (sce_copy->gpd) { - if (!is_scene_liboverride || !ID_IS_LINKED(sce_copy->gpd)) { - id_us_min(&sce_copy->gpd->id); - BKE_id_copy_ex(bmain, (ID *)sce_copy->gpd, (ID **)&sce_copy->gpd, LIB_ID_COPY_ACTIONS); + id = &sce->gpd->id; + if (id && id->newid == NULL) { + if (!is_scene_liboverride || !ID_IS_LINKED(id)) { + BKE_id_copy_ex(bmain, id, &id_new, LIB_ID_COPY_ACTIONS); + id_us_min(id_new); + ID_NEW_SET(id, id_new); } } /* Deep-duplicate collections and objects (using preferences' settings for which sub-data to * duplicate along the object itself). */ - BKE_collection_duplicate(bmain, NULL, sce_copy->master_collection, true, true); + BKE_collection_duplicate(bmain, + NULL, + sce_copy->master_collection, + USER_DUP_OBJECT | U.dupflag, + LIB_ID_DUPLICATE_IS_SUBPROCESS); + + if (!is_subprocess) { + /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW.*/ + BKE_libblock_relink_to_newid(&sce_copy->id); + +#ifndef NDEBUG + /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those + * flags. */ + ID *id_iter; + FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { + BLI_assert((id_iter->tag & LIB_TAG_NEW) == 0); + } + FOREACH_MAIN_ID_END; +#endif + + /* Cleanup. */ + BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false); + BKE_main_id_clear_newpoins(bmain); + + BKE_main_collection_sync(bmain); + } } else { /* Remove sequencer if not full copy */ diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 653e9d39eca..b60ce459ba6 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -2797,8 +2797,12 @@ void OBJECT_OT_convert(wmOperatorType *ot) /* used below, assumes id.new is correct */ /* leaves selection of base/object unaltered */ /* Does set ID->newid pointers. */ -static Base *object_add_duplicate_internal( - Main *bmain, Scene *scene, ViewLayer *view_layer, Object *ob, const eDupli_ID_Flags dupflag) +static Base *object_add_duplicate_internal(Main *bmain, + Scene *scene, + ViewLayer *view_layer, + Object *ob, + const eDupli_ID_Flags dupflag, + const eLibIDDuplicateFlags duplicate_options) { Base *base, *basen = NULL; Object *obn; @@ -2807,7 +2811,7 @@ static Base *object_add_duplicate_internal( /* nothing? */ } else { - obn = ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag)); + obn = ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag, duplicate_options)); DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); base = BKE_view_layer_base_find(view_layer, ob); @@ -2851,7 +2855,8 @@ Base *ED_object_add_duplicate( Base *basen; Object *ob; - basen = object_add_duplicate_internal(bmain, scene, view_layer, base->object, dupflag); + basen = object_add_duplicate_internal( + bmain, scene, view_layer, base->object, dupflag, LIB_ID_DUPLICATE_IS_SUBPROCESS); if (basen == NULL) { return NULL; } @@ -2882,7 +2887,8 @@ static int duplicate_exec(bContext *C, wmOperator *op) const eDupli_ID_Flags dupflag = (linked) ? 0 : (eDupli_ID_Flags)U.dupflag; CTX_DATA_BEGIN (C, Base *, base, selected_bases) { - Base *basen = object_add_duplicate_internal(bmain, scene, view_layer, base->object, dupflag); + Base *basen = object_add_duplicate_internal( + bmain, scene, view_layer, base->object, dupflag, 0); /* note that this is safe to do with this context iterator, * the list is made in advance */ @@ -2976,7 +2982,7 @@ static int object_add_named_exec(bContext *C, wmOperator *op) } /* prepare dupli */ - basen = object_add_duplicate_internal(bmain, scene, view_layer, ob, dupflag); + basen = object_add_duplicate_internal(bmain, scene, view_layer, ob, dupflag, 0); if (basen == NULL) { BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated"); diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 6ff3ccc5bb4..131491fcc40 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -581,7 +581,8 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op) "it won't be linked to any view layer"); } - BKE_collection_duplicate(bmain, parent, collection, true, !linked); + const eDupli_ID_Flags dupli_flags = USER_DUP_OBJECT | (linked ? 0 : U.dupflag); + BKE_collection_duplicate(bmain, parent, collection, dupli_flags, 0); DEG_relations_tag_update(bmain); WM_main_add_notifier(NC_SCENE | ND_LAYER, CTX_data_scene(C)); diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 4b6d78a1d14..ab33b3a58f2 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -1150,6 +1150,13 @@ typedef enum eDupli_ID_Flags { USER_DUP_HAIR = (1 << 14), USER_DUP_POINTCLOUD = (1 << 15), USER_DUP_VOLUME = (1 << 16), + + USER_DUP_OBDATA = (~0) & ((1 << 24) - 1), + + /* Those are not exposed as user preferences, only used internaly. */ + USER_DUP_OBJECT = (1 << 24), + /* USER_DUP_COLLECTION = (1 << 25), */ /* UNUSED, keep because we may implement. */ + } eDupli_ID_Flags; /** diff --git a/tests/python/bl_pyapi_idprop_datablock.py b/tests/python/bl_pyapi_idprop_datablock.py index 44fec6a9043..ca52c1b01fe 100644 --- a/tests/python/bl_pyapi_idprop_datablock.py +++ b/tests/python/bl_pyapi_idprop_datablock.py @@ -157,10 +157,10 @@ def check_linked_scene_copying(): extern_sce = get_scene("lib.blend", "Scene_lib") # check node's props - # we made full copy from linked scene, so pointers must equal each other + # must point to own scene camera abort_if_false(intern_sce.node_tree.nodes['Render Layers']["prop"] and - intern_sce.node_tree.nodes['Render Layers']["prop"] == - extern_sce.node_tree.nodes['Render Layers']["prop"]) + not (intern_sce.node_tree.nodes['Render Layers']["prop"] == + extern_sce.node_tree.nodes['Render Layers']["prop"])) def check_scene_copying(): |