Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_collection.h4
-rw-r--r--source/blender/blenkernel/BKE_lib_id.h10
-rw-r--r--source/blender/blenkernel/BKE_object.h5
-rw-r--r--source/blender/blenkernel/intern/collection.c62
-rw-r--r--source/blender/blenkernel/intern/object.c382
-rw-r--r--source/blender/blenkernel/intern/scene.c68
-rw-r--r--source/blender/editors/object/object_add.c18
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c3
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h7
-rw-r--r--tests/python/bl_pyapi_idprop_datablock.py6
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():