From c37121f16c14519a9056217a2f02fc9078b6e05e Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 21 Oct 2021 17:34:05 +0200 Subject: Fix T91410: Make Single User operation ignores linked data-blocks. Now 'Make Single User' will also create local copy of linked data as needed. IMPORTANT: Unlike with local data, this always happen, even if linked data has only one user. This avoids e.g. cases like two local objects sharing a same linked mesh, then when calling 'Make Single User -> Object and ObData' on both objects, yu expect both of your objects to get localized meshes, not one of them keeping its linked, un-editable mesh. --- source/blender/editors/object/object_relations.c | 52 +++++++++++++++--------- 1 file changed, 32 insertions(+), 20 deletions(-) (limited to 'source/blender/editors/object/object_relations.c') diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 5c7e1e1fa01..1cc293ba227 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1677,6 +1677,14 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot) /** \name Make Single User Operator * \{ */ +static bool single_data_needs_duplication(ID *id) +{ + /* NOTE: When dealing with linked data, we always make alocal copy of it. + * While in theory we could rather make it local when it only has one user, this is difficult + * in practice with current code of this function. */ + return (id != NULL && (id->us > 1 || ID_IS_LINKED(id))); +} + static void libblock_relink_collection(Collection *collection, const bool do_collection) { if (do_collection) { @@ -1800,8 +1808,7 @@ static void single_obdata_users( FOREACH_OBJECT_FLAG_BEGIN (scene, view_layer, v3d, flag, ob) { if (!ID_IS_LINKED(ob)) { id = ob->data; - - if (id && id->us > 1 && !ID_IS_LINKED(id)) { + if (single_data_needs_duplication(id)) { DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); switch (ob->type) { @@ -1895,8 +1902,16 @@ static void single_object_action_users( { FOREACH_OBJECT_FLAG_BEGIN (scene, view_layer, v3d, flag, ob) { if (!ID_IS_LINKED(ob)) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - BKE_animdata_copy_id_action(bmain, &ob->id); + AnimData *adt = BKE_animdata_from_id(&ob->id); + if (adt == NULL) { + continue; + } + + ID *id_act = (ID *)adt->action; + if (single_data_needs_duplication(id_act)) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + BKE_animdata_duplicate_id_action(bmain, &ob->id, USER_DUP_ACT | USER_DUP_LINKED_ID); + } } } FOREACH_OBJECT_FLAG_END; @@ -1909,10 +1924,14 @@ static void single_objectdata_action_users( if (!ID_IS_LINKED(ob) && ob->data != NULL) { ID *id_obdata = (ID *)ob->data; AnimData *adt = BKE_animdata_from_id(id_obdata); + if (adt == NULL) { + continue; + } + ID *id_act = (ID *)adt->action; - if (id_act && id_act->us > 1) { + if (single_data_needs_duplication(id_act)) { DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - BKE_animdata_copy_id_action(bmain, id_obdata); + BKE_animdata_duplicate_id_action(bmain, &ob->id, USER_DUP_ACT | USER_DUP_LINKED_ID); } } } @@ -1928,18 +1947,13 @@ static void single_mat_users( FOREACH_OBJECT_FLAG_BEGIN (scene, view_layer, v3d, flag, ob) { if (!ID_IS_LINKED(ob)) { for (a = 1; a <= ob->totcol; a++) { - ma = BKE_object_material_get(ob, a); - if (ma) { - /* do not test for LIB_TAG_NEW or use newid: - * this functions guaranteed delivers single_users! */ - - if (ma->id.us > 1) { - man = (Material *)BKE_id_copy(bmain, &ma->id); - BKE_animdata_copy_id_action(bmain, &man->id); + ma = BKE_object_material_get(ob, (short)a); + if (single_data_needs_duplication(&ma->id)) { + man = (Material *)BKE_id_copy(bmain, &ma->id); + BKE_animdata_copy_id_action(bmain, &man->id); - man->id.us = 0; - BKE_object_material_assign(bmain, ob, man, a, BKE_MAT_ASSIGN_USERPREF); - } + man->id.us = 0; + BKE_object_material_assign(bmain, ob, man, (short)a, BKE_MAT_ASSIGN_USERPREF); } } } @@ -1982,9 +1996,7 @@ static void tag_localizable_objects(bContext *C, const int mode) CTX_DATA_BEGIN (C, Object *, object, selected_objects) { object->id.tag |= LIB_TAG_DOIT; - /* If data is also gonna to become local, mark data we're interested in - * as gonna-to-be-local. - */ + /* If obdata is also going to become local, mark it as such too. */ if (mode == MAKE_LOCAL_SELECT_OBDATA && object->data) { ID *data_id = (ID *)object->data; data_id->tag |= LIB_TAG_DOIT; -- cgit v1.2.3