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:
authorBastien Montagne <bastien@blender.org>2020-07-09 16:33:34 +0300
committerBastien Montagne <bastien@blender.org>2020-07-09 18:56:05 +0300
commit7b1c406b5431ce65d84ddb5f2c53977c25c18373 (patch)
treed10874f81e0ca717dc288ae2071bc127c6da990a /source/blender/blenkernel/intern
parent78b629a98f0c7c5c2c8f3b6b6d1081646cbe6fde (diff)
Implement T77959: Never duplicate linked data during deep-copy.
Note that this behavior is enforced on user level for now, but on code side it is controlled with a flag, which should make it easy to refine that behavior if needed. Only exception is when we duplicate a linked ID directly (then we assume user wants a local deep-copy of that linked data, and we always also duplicate linked sub-data-blocks). Note that this commit also slightly refactor the handling of actions of animdata, by simplifying `BKE_animdata_copy_id_action()` and adding an explicit new `BKE_animdata_duplicate_id_action()` to be used during ID duplication (deep copy). This also allows us to get rid of the special case for liboverrides.
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r--source/blender/blenkernel/intern/anim_data.c27
-rw-r--r--source/blender/blenkernel/intern/collection.c33
-rw-r--r--source/blender/blenkernel/intern/lib_id.c54
-rw-r--r--source/blender/blenkernel/intern/object.c55
-rw-r--r--source/blender/blenkernel/intern/scene.c19
5 files changed, 105 insertions, 83 deletions
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index 3e2c69fbcea..61181278c60 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -375,17 +375,19 @@ bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const int flag)
return true;
}
-void BKE_animdata_copy_id_action(Main *bmain, ID *id, const bool set_newid)
+static void animdata_copy_id_action(Main *bmain,
+ ID *id,
+ const bool set_newid,
+ const bool do_linked_id)
{
- const bool is_id_liboverride = ID_IS_OVERRIDE_LIBRARY(id);
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
- if (adt->action && (!is_id_liboverride || !ID_IS_LINKED(adt->action))) {
+ if (adt->action && (do_linked_id || !ID_IS_LINKED(adt->action))) {
id_us_min((ID *)adt->action);
adt->action = set_newid ? ID_NEW_SET(adt->action, BKE_action_copy(bmain, adt->action)) :
BKE_action_copy(bmain, adt->action);
}
- if (adt->tmpact && (!is_id_liboverride || !ID_IS_LINKED(adt->tmpact))) {
+ if (adt->tmpact && (do_linked_id || !ID_IS_LINKED(adt->tmpact))) {
id_us_min((ID *)adt->tmpact);
adt->tmpact = set_newid ? ID_NEW_SET(adt->tmpact, BKE_action_copy(bmain, adt->tmpact)) :
BKE_action_copy(bmain, adt->tmpact);
@@ -393,12 +395,27 @@ void BKE_animdata_copy_id_action(Main *bmain, ID *id, const bool set_newid)
}
bNodeTree *ntree = ntreeFromID(id);
if (ntree) {
- BKE_animdata_copy_id_action(bmain, &ntree->id, set_newid);
+ animdata_copy_id_action(bmain, &ntree->id, set_newid, do_linked_id);
}
/* Note that collections are not animatable currently, so no need to handle scenes' master
* collection here. */
}
+void BKE_animdata_copy_id_action(Main *bmain, ID *id)
+{
+ const bool is_id_liboverride = ID_IS_OVERRIDE_LIBRARY(id);
+ animdata_copy_id_action(bmain, id, false, !is_id_liboverride);
+}
+
+void BKE_animdata_duplicate_id_action(struct Main *bmain,
+ struct ID *id,
+ const eDupli_ID_Flags duplicate_flags)
+{
+ if (duplicate_flags & USER_DUP_ACT) {
+ animdata_copy_id_action(bmain, id, true, (duplicate_flags & USER_DUP_LINKED_ID) != 0);
+ }
+}
+
/* Merge copies of the data from the src AnimData into the destination AnimData */
void BKE_animdata_merge_copy(
Main *bmain, ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers)
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 080d61f1500..7e22048379b 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -333,7 +333,6 @@ static Collection *collection_duplicate_recursive(Main *bmain,
Collection *collection_new;
bool do_full_process = false;
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;
@@ -346,7 +345,12 @@ static Collection *collection_duplicate_recursive(Main *bmain,
}
else if (collection_old->id.newid == NULL) {
collection_new = (Collection *)BKE_id_copy_for_duplicate(
- bmain, (ID *)collection_old, is_collection_liboverride, duplicate_flags);
+ bmain, (ID *)collection_old, duplicate_flags);
+
+ if (collection_new == collection_old) {
+ return collection_new;
+ }
+
do_full_process = true;
}
else {
@@ -382,17 +386,15 @@ static Collection *collection_duplicate_recursive(Main *bmain,
Object *ob_old = cob->ob;
Object *ob_new = (Object *)ob_old->id.newid;
- /* If collection is an override, we do not want to duplicate any linked data-block, as that
- * would generate a purely local data. */
- if (is_collection_liboverride && ID_IS_LINKED(ob_old)) {
- continue;
- }
-
if (ob_new == NULL) {
ob_new = BKE_object_duplicate(
bmain, ob_old, duplicate_flags, duplicate_options | LIB_ID_DUPLICATE_IS_SUBPROCESS);
}
+ if (ob_new == ob_old) {
+ continue;
+ }
+
collection_object_add(bmain, collection_new, ob_new, 0, true);
collection_object_remove(bmain, collection_new, ob_old, false);
}
@@ -403,13 +405,11 @@ static Collection *collection_duplicate_recursive(Main *bmain,
LISTBASE_FOREACH_MUTABLE (CollectionChild *, child, &collection_old->children) {
Collection *child_collection_old = child->collection;
- if (is_collection_liboverride && ID_IS_LINKED(child_collection_old)) {
- continue;
- }
-
- collection_duplicate_recursive(
+ Collection *child_collection_new = collection_duplicate_recursive(
bmain, collection_new, child_collection_old, duplicate_flags, duplicate_options);
- collection_child_remove(collection_new, child_collection_old);
+ if (child_collection_new != child_collection_old) {
+ collection_child_remove(collection_new, child_collection_old);
+ }
}
return collection_new;
@@ -434,6 +434,11 @@ Collection *BKE_collection_duplicate(Main *bmain,
if (!is_subprocess) {
BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false);
BKE_main_id_clear_newpoins(bmain);
+ /* In case root duplicated ID is linked, assume we want to get a local copy of it and duplicate
+ * all expected linked data. */
+ if (ID_IS_LINKED(collection)) {
+ duplicate_flags |= USER_DUP_LINKED_ID;
+ }
}
Collection *collection_new = collection_duplicate_recursive(
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index 7c09ae51344..eb440de1a6f 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -611,41 +611,39 @@ bool BKE_id_copy(Main *bmain, const ID *id, ID **newid)
* Invokes the appropriate copy method for the block and returns the result in
* newid, unless test. Returns true if the block can be copied.
*/
-ID *BKE_id_copy_for_duplicate(Main *bmain,
- ID *id,
- const bool is_owner_id_liboverride,
- const eDupli_ID_Flags duplicate_flags)
+ID *BKE_id_copy_for_duplicate(Main *bmain, ID *id, const eDupli_ID_Flags duplicate_flags)
{
if (id == NULL) {
- return NULL;
+ return id;
}
if (id->newid == NULL) {
- if (!is_owner_id_liboverride || !ID_IS_LINKED(id)) {
- ID *id_new;
- BKE_id_copy(bmain, id, &id_new);
- /* Copying add one user by default, need to get rid of that one. */
- id_us_min(id_new);
- ID_NEW_SET(id, id_new);
-
- /* Shape keys are always copied with their owner ID, by default. */
- ID *key_new = (ID *)BKE_key_from_id(id_new);
- ID *key = (ID *)BKE_key_from_id(id);
- if (key != NULL) {
- ID_NEW_SET(key, key_new);
- }
+ const bool do_linked_id = (duplicate_flags & USER_DUP_LINKED_ID) != 0;
+ if (!(do_linked_id || !ID_IS_LINKED(id))) {
+ return id;
+ }
- /* Note: embedded data (root nodetrees and master collections) should never be referenced by
- * anything else, so we do not need to set their newid pointer and flag. */
+ ID *id_new;
+ BKE_id_copy(bmain, id, &id_new);
+ /* Copying add one user by default, need to get rid of that one. */
+ id_us_min(id_new);
+ ID_NEW_SET(id, id_new);
- if (duplicate_flags & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(bmain, id_new, true);
- if (key_new != NULL) {
- BKE_animdata_copy_id_action(bmain, key_new, true);
- }
- /* Note that actions of embedded data (root nodetrees and master collections) are handled
- * by `BKE_animdata_copy_id_action` as well. */
- }
+ /* Shape keys are always copied with their owner ID, by default. */
+ ID *key_new = (ID *)BKE_key_from_id(id_new);
+ ID *key = (ID *)BKE_key_from_id(id);
+ if (key != NULL) {
+ ID_NEW_SET(key, key_new);
+ }
+
+ /* Note: embedded data (root nodetrees and master collections) should never be referenced by
+ * anything else, so we do not need to set their newid pointer and flag. */
+
+ BKE_animdata_duplicate_id_action(bmain, id_new, duplicate_flags);
+ if (key_new != NULL) {
+ BKE_animdata_duplicate_id_action(bmain, id_new, duplicate_flags);
}
+ /* Note that actions of embedded data (root nodetrees and master collections) are handled
+ * by `BKE_animdata_duplicate_id_action` as well. */
}
return id->newid;
}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 6331f87f09f..d48ea33cc65 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1760,7 +1760,7 @@ Object *BKE_object_copy(Main *bmain, const Object *ob)
*/
Object *BKE_object_duplicate(Main *bmain,
Object *ob,
- const eDupli_ID_Flags dupflag,
+ eDupli_ID_Flags dupflag,
const eLibIDDuplicateFlags duplicate_options)
{
const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0;
@@ -1768,10 +1768,14 @@ Object *BKE_object_duplicate(Main *bmain,
if (!is_subprocess) {
BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false);
BKE_main_id_clear_newpoins(bmain);
+ /* In case root duplicated ID is linked, assume we want to get a local copy of it and duplicate
+ * all expected linked data. */
+ if (ID_IS_LINKED(ob)) {
+ dupflag |= USER_DUP_LINKED_ID;
+ }
}
Material ***matarar;
- const bool is_object_liboverride = ID_IS_OVERRIDE_LIBRARY(ob);
Object *obn;
BKE_id_copy(bmain, &ob->id, (ID **)&obn);
@@ -1785,112 +1789,109 @@ Object *BKE_object_duplicate(Main *bmain,
return obn;
}
- /* duplicates using userflags */
- if (dupflag & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(bmain, &obn->id, true);
- }
+ BKE_animdata_duplicate_id_action(bmain, &obn->id, dupflag);
if (dupflag & USER_DUP_MAT) {
for (int i = 0; i < obn->totcol; i++) {
- BKE_id_copy_for_duplicate(bmain, (ID *)obn->mat[i], is_object_liboverride, dupflag);
+ BKE_id_copy_for_duplicate(bmain, (ID *)obn->mat[i], dupflag);
}
}
if (dupflag & USER_DUP_PSYS) {
ParticleSystem *psys;
for (psys = obn->particlesystem.first; psys; psys = psys->next) {
- BKE_id_copy_for_duplicate(bmain, (ID *)psys->part, is_object_liboverride, dupflag);
+ BKE_id_copy_for_duplicate(bmain, (ID *)psys->part, dupflag);
}
}
- ID *id = obn->data;
+ ID *id_old = obn->data;
ID *id_new = NULL;
- const bool need_to_duplicate_obdata = (id != NULL) && (id->newid == NULL);
+ const bool need_to_duplicate_obdata = (id_old != NULL) && (id_old->newid == NULL);
switch (obn->type) {
case OB_MESH:
if (dupflag & USER_DUP_MESH) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_CURVE:
if (dupflag & USER_DUP_CURVE) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_SURF:
if (dupflag & USER_DUP_SURF) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_FONT:
if (dupflag & USER_DUP_FONT) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_MBALL:
if (dupflag & USER_DUP_MBALL) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_LAMP:
if (dupflag & USER_DUP_LAMP) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_ARMATURE:
if (dupflag & USER_DUP_ARM) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_LATTICE:
if (dupflag != 0) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_CAMERA:
if (dupflag != 0) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_LIGHTPROBE:
if (dupflag & USER_DUP_LIGHTPROBE) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_SPEAKER:
if (dupflag != 0) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_GPENCIL:
if (dupflag & USER_DUP_GPENCIL) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_HAIR:
if (dupflag & USER_DUP_HAIR) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_POINTCLOUD:
if (dupflag & USER_DUP_POINTCLOUD) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_VOLUME:
if (dupflag & USER_DUP_VOLUME) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
}
/* If obdata has been copied, we may also have to duplicate the materials assigned to it. */
- if (need_to_duplicate_obdata && id_new != NULL) {
+ if (need_to_duplicate_obdata && !ELEM(id_new, NULL, id_old)) {
if (dupflag & USER_DUP_MAT) {
matarar = BKE_object_material_array_p(obn);
if (matarar) {
for (int i = 0; i < obn->totcol; i++) {
- BKE_id_copy_for_duplicate(bmain, (ID *)(*matarar)[i], is_object_liboverride, dupflag);
+ BKE_id_copy_for_duplicate(bmain, (ID *)(*matarar)[i], dupflag);
}
}
}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index a457d278e1d..5ae2f4b9005 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -770,7 +770,6 @@ void BKE_scene_copy_data_eevee(Scene *sce_dst, const Scene *sce_src)
Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type)
{
- const bool is_scene_liboverride = ID_IS_OVERRIDE_LIBRARY(sce);
Scene *sce_copy;
/* TODO this should/could most likely be replaced by call to more generic code at some point...
@@ -841,15 +840,13 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type)
return sce_copy;
}
else {
- const eDupli_ID_Flags duplicate_flags = U.dupflag | USER_DUP_OBJECT;
+ eDupli_ID_Flags duplicate_flags = U.dupflag | USER_DUP_OBJECT;
BKE_id_copy(bmain, (ID *)sce, (ID **)&sce_copy);
id_us_min(&sce_copy->id);
id_us_ensure_real(&sce_copy->id);
- if (duplicate_flags & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(bmain, &sce_copy->id, true);
- }
+ BKE_animdata_duplicate_id_action(bmain, &sce_copy->id, duplicate_flags);
/* Extra actions, most notably SCE_FULL_COPY also duplicates several 'children' datablocks. */
@@ -860,22 +857,26 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type)
if (!is_subprocess) {
BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false);
BKE_main_id_clear_newpoins(bmain);
+ /* In case root duplicated ID is linked, assume we want to get a local copy of it and
+ * duplicate all expected linked data. */
+ if (ID_IS_LINKED(sce)) {
+ duplicate_flags |= USER_DUP_LINKED_ID;
+ }
}
/* Copy Freestyle LineStyle datablocks. */
LISTBASE_FOREACH (ViewLayer *, view_layer_dst, &sce_copy->view_layers) {
LISTBASE_FOREACH (
FreestyleLineSet *, lineset, &view_layer_dst->freestyle_config.linesets) {
- BKE_id_copy_for_duplicate(
- bmain, &lineset->linestyle->id, is_scene_liboverride, duplicate_flags);
+ BKE_id_copy_for_duplicate(bmain, (ID *)lineset->linestyle, duplicate_flags);
}
}
/* Full copy of world (included animations) */
- BKE_id_copy_for_duplicate(bmain, &sce->world->id, is_scene_liboverride, duplicate_flags);
+ BKE_id_copy_for_duplicate(bmain, (ID *)sce->world, duplicate_flags);
/* Full copy of GreasePencil. */
- BKE_id_copy_for_duplicate(bmain, &sce->gpd->id, is_scene_liboverride, duplicate_flags);
+ BKE_id_copy_for_duplicate(bmain, (ID *)sce->gpd, duplicate_flags);
/* Deep-duplicate collections and objects (using preferences' settings for which sub-data to
* duplicate along the object itself). */