diff options
author | Bastien Montagne <bastien@blender.org> | 2020-06-17 18:01:21 +0300 |
---|---|---|
committer | Bastien Montagne <bastien@blender.org> | 2020-06-17 18:06:05 +0300 |
commit | 13f591d400e2d17633bf7ebba9c7890fd563e4d2 (patch) | |
tree | 361374096efc8d2d2258bdec2946c352439680b2 | |
parent | c84fee1ffeab3842d01779f1a2e5bfd826b48e60 (diff) |
ID Duplicate: Factorize a lot the code.
Now that we have a uniform consistent behavior in all our ID duplicate
funtions, we can easily factorize it greatly. Code gets cleaner,
smaller, and less error-prone.
Note that ultimately, this duplicate/deep copy behavior could be added
as a callback of IDTypeInfo.
We could also rethink the duplicate flags (some data, even some obdata,
like Lattice, are not coverred currently).
And so on. But at least code should now be much more easily maintainable
and extendable.
-rw-r--r-- | source/blender/blenkernel/BKE_lib_id.h | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/collection.c | 13 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/lib_id.c | 43 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/object.c | 269 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/scene.c | 39 |
5 files changed, 138 insertions, 230 deletions
diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index 8ee5562baae..e6a711732c9 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -227,6 +227,10 @@ bool id_single_user(struct bContext *C, bool BKE_id_copy_is_allowed(const struct ID *id); bool BKE_id_copy(struct Main *bmain, const struct ID *id, struct ID **newid); bool BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag); +struct ID *BKE_id_copy_for_duplicate(struct Main *bmain, + struct ID *id, + const bool is_owner_id_liboverride, + const uint duplicate_flags); void BKE_lib_id_swap(struct Main *bmain, struct ID *id_a, struct ID *id_b); void BKE_lib_id_swap_full(struct Main *bmain, struct ID *id_a, struct ID *id_b); diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index f115b9e8b7b..dddbf7d45b2 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -345,17 +345,8 @@ static Collection *collection_duplicate_recursive(Main *bmain, do_full_process = true; } else if (collection_old->id.newid == NULL) { - BKE_id_copy(bmain, &collection_old->id, (ID **)&collection_new); - - /* Copying add one user by default, need to get rid of that one. */ - id_us_min(&collection_new->id); - - ID_NEW_SET(collection_old, collection_new); - - if (duplicate_flags & USER_DUP_ACT) { - BKE_animdata_copy_id_action(bmain, &collection_new->id, true); - } - + collection_new = (Collection *)BKE_id_copy_for_duplicate( + bmain, (ID *)collection_old, is_collection_liboverride, duplicate_flags); do_full_process = true; } else { diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index ab9b11f436a..4d36530fccc 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -608,6 +608,49 @@ 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) +{ + if (id == NULL) { + return NULL; + } + 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); + } + + /* 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. */ + + 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. */ + } + } + } + return id->newid; +} + +/** * Does a mere memory swap over the whole IDs data (including type-specific memory). * \note Most internal ID data itself is not swapped (only IDProperties are). */ diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 28f7a9f12d0..7385fbf3f33 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1771,8 +1771,6 @@ Object *BKE_object_duplicate(Main *bmain, } Material ***matarar; - ID *id, *id_new = NULL; - int a; const bool is_object_liboverride = ID_IS_OVERRIDE_LIBRARY(ob); Object *obn; @@ -1793,203 +1791,106 @@ Object *BKE_object_duplicate(Main *bmain, } if (dupflag & USER_DUP_MAT) { - for (a = 0; a < obn->totcol; a++) { - id = (ID *)obn->mat[a]; - if (id && id->newid == NULL) { - if (is_object_liboverride && ID_IS_LINKED(id)) { - continue; - } - 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); - } - } + for (int i = 0; i < obn->totcol; i++) { + BKE_id_copy_for_duplicate(bmain, (ID *)obn->mat[i], is_object_liboverride, dupflag); } } if (dupflag & USER_DUP_PSYS) { ParticleSystem *psys; for (psys = obn->particlesystem.first; psys; psys = psys->next) { - id = (ID *)psys->part; - if (id && id->newid == NULL) { - if (is_object_liboverride && ID_IS_LINKED(id)) { - continue; - } - 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); - } - } + BKE_id_copy_for_duplicate(bmain, (ID *)psys->part, is_object_liboverride, dupflag); } } - id = obn->data; - bool duplicated_obdata = false; + ID *id = obn->data; + ID *id_new = NULL; + const bool need_to_duplicate_obdata = (id->newid == NULL); - 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; - } - 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; - } - 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; - } - 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; - } - 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; - } - 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) { - 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) { - BKE_id_copy(bmain, id, &id_new); - id_us_min(id_new); - ID_NEW_SET(id, id_new); - duplicated_obdata = true; - } - 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; - } - 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; - } - 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; - } - 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; - } - 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; - } - 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; - } - 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; - } - break; + switch (obn->type) { + case OB_MESH: + if (dupflag & USER_DUP_MESH) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); } - } - } - - /* Check if obdata is copied. */ - if (duplicated_obdata) { - BLI_assert(id_new != NULL); - - Key *key = BKE_key_from_object(obn); - - Key *oldkey = BKE_key_from_object(ob); - if (oldkey != NULL) { - ID_NEW_SET(oldkey, key); - } - - if (dupflag & USER_DUP_ACT) { - BKE_animdata_copy_id_action(bmain, id_new, true); - if (key) { - BKE_animdata_copy_id_action(bmain, (ID *)key, true); + break; + case OB_CURVE: + if (dupflag & USER_DUP_CURVE) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); } - } + break; + case OB_SURF: + if (dupflag & USER_DUP_SURF) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_FONT: + if (dupflag & USER_DUP_FONT) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_MBALL: + if (dupflag & USER_DUP_MBALL) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_LAMP: + if (dupflag & USER_DUP_LAMP) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_ARMATURE: + if (dupflag & USER_DUP_ARM) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_LATTICE: + if (dupflag != 0) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_CAMERA: + if (dupflag != 0) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_LIGHTPROBE: + if (dupflag & USER_DUP_LIGHTPROBE) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_SPEAKER: + if (dupflag != 0) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_GPENCIL: + if (dupflag & USER_DUP_GPENCIL) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_HAIR: + if (dupflag & USER_DUP_HAIR) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_POINTCLOUD: + if (dupflag & USER_DUP_POINTCLOUD) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag); + } + break; + case OB_VOLUME: + if (dupflag & USER_DUP_VOLUME) { + id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, 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 (dupflag & USER_DUP_MAT) { matarar = BKE_object_material_array_p(obn); if (matarar) { - for (a = 0; a < obn->totcol; a++) { - id = (ID *)(*matarar)[a]; - if (id && id->newid == NULL) { - if (is_object_liboverride && ID_IS_LINKED(id)) { - continue; - } - 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); - } - } + for (int i = 0; i < obn->totcol; i++) { + BKE_id_copy_for_duplicate(bmain, (ID *)(*matarar)[i], is_object_liboverride, dupflag); } } } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 82e219e60f0..0537f1a65ad 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -837,7 +837,6 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type) 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); @@ -848,46 +847,16 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type) LISTBASE_FOREACH (ViewLayer *, view_layer_dst, &sce_copy->view_layers) { LISTBASE_FOREACH ( FreestyleLineSet *, lineset, &view_layer_dst->freestyle_config.linesets) { - id = &lineset->linestyle->id; - if (id && id->newid == NULL) { - if (is_scene_liboverride && ID_IS_LINKED(id)) { - continue; - } - BKE_id_copy(bmain, id, &id_new); - 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); - } - } + BKE_id_copy_for_duplicate( + bmain, &lineset->linestyle->id, is_scene_liboverride, duplicate_flags); } } /* Full copy of world (included animations) */ - id = &sce->world->id; - if (id && id->newid == NULL) { - if (!is_scene_liboverride || !ID_IS_LINKED(id)) { - BKE_id_copy(bmain, id, &id_new); - 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); - } - } - } + BKE_id_copy_for_duplicate(bmain, &sce->world->id, is_scene_liboverride, duplicate_flags); /* Full copy of GreasePencil. */ - id = &sce->gpd->id; - if (id && id->newid == NULL) { - if (!is_scene_liboverride || !ID_IS_LINKED(id)) { - BKE_id_copy(bmain, id, &id_new); - 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); - } - } - } + BKE_id_copy_for_duplicate(bmain, &sce->gpd->id, is_scene_liboverride, duplicate_flags); /* Deep-duplicate collections and objects (using preferences' settings for which sub-data to * duplicate along the object itself). */ |