From e7ea99af1b0d933b9323be39d8b1c6f683bfba52 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Tue, 26 Feb 2019 16:15:30 -0300 Subject: Outliner: Collection - Duplicate Hierarchy, and Duplicate Linked Hierarchy As per the suggestion on T57064, this introduces two new options to duplicate collections. We then have: * Duplicate > Collection (New collection with linked content). * Duplicate > Hierachy (Duplicate entire hierarchy and make all contents single user). * Duplicate > Linked Hierarchy (Duplicate entire hierarchy keeping content linked with original). Development TODO: `single_object_users` can/should use the new functions. Reviewers: brecht, mont29 Subscribers: pablovazquez, billreynish, JulienKaspar Differential Revision: https://developer.blender.org/D4394 --- source/blender/blenkernel/intern/object.c | 234 ++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) (limited to 'source/blender/blenkernel/intern/object.c') diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 3c57a5f7086..c4d80fdd5e2 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1427,6 +1427,240 @@ Object *BKE_object_copy(Main *bmain, const Object *ob) return ob_copy; } +Object *BKE_object_duplicate(Main *bmain, const Object *ob, const int dupflag) +{ + Material ***matarar; + ID *id; + int a, didit; + Object *obn = BKE_object_copy(bmain, ob); + + /* 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); + } + + if (dupflag & USER_DUP_MAT) { + for (a = 0; a < obn->totcol; a++) { + id = (ID *)obn->mat[a]; + if (id) { + ID_NEW_REMAP_US(obn->mat[a]) + else { + obn->mat[a] = ID_NEW_SET(obn->mat[a], BKE_material_copy(bmain, obn->mat[a])); + } + id_us_min(id); + + if (dupflag & USER_DUP_ACT) { + BKE_animdata_copy_id_action(bmain, &obn->mat[a]->id, true); + } + } + } + } + if (dupflag & USER_DUP_PSYS) { + ParticleSystem *psys; + for (psys = obn->particlesystem.first; psys; psys = psys->next) { + id = (ID *) psys->part; + if (id) { + 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); + } + + id_us_min(id); + } + } + } + + id = obn->data; + didit = 0; + + 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; + } + 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; + } + 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; + } + 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; + } + 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; + } + id_us_min(id); + } + break; + case OB_ARMATURE: + DEG_id_tag_update(&obn->id, ID_RECALC_GEOMETRY); + if (obn->pose) + BKE_pose_tag_recalc(bmain, obn->pose); + 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); + } + 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; + } + 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; + } + id_us_min(id); + } + break; + case OB_LIGHTPROBE: + if (dupflag != 0) { + ID_NEW_REMAP_US2(obn->data) + else { + obn->data = ID_NEW_SET(obn->data, BKE_lightprobe_copy(bmain, obn->data)); + didit = 1; + } + 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; + } + id_us_min(id); + } + break; + case OB_GPENCIL: + if (dupflag != 0) { + ID_NEW_REMAP_US2(obn->data) + else { + obn->data = ID_NEW_SET(obn->data, BKE_gpencil_copy(bmain, obn->data)); + didit = 1; + } + id_us_min(id); + } + break; + } + + /* Check if obdata is copied. */ + if (didit) { + 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 *)obn->data, true); + if (key) { + BKE_animdata_copy_id_action(bmain, (ID *)key, true); + } + } + + if (dupflag & USER_DUP_MAT) { + matarar = give_matarar(obn); + if (matarar) { + for (a = 0; a < obn->totcol; a++) { + id = (ID *)(*matarar)[a]; + if (id) { + ID_NEW_REMAP_US((*matarar)[a]) + else { + (*matarar)[a] = ID_NEW_SET((*matarar)[a], BKE_material_copy(bmain, (*matarar)[a])); + } + id_us_min(id); + } + } + } + } + } + +#undef ID_NEW_REMAP_US +#undef ID_NEW_REMAP_US2 + + BKE_libblock_relink_to_newid(&obn->id); + + /* DAG_relations_tag_update(bmain); */ /* caller must do */ + + if (ob->data != NULL) { + DEG_id_tag_update_ex(bmain, (ID *)obn->data, ID_RECALC_EDITORS); + } + + /* BKE_main_id_clear_newpoins(bmain); */ /* Called must do. */ + + return obn; +} + void BKE_object_make_local_ex(Main *bmain, Object *ob, const bool lib_local, const bool clear_proxy) { bool is_local = false, is_lib = false; -- cgit v1.2.3