Fix T71865: Separating mesh parts breaks shape keys

This was an old bug which could be caused by saving after separating.
Changes from 79b703bb63 made this fail reliably.

Update shape key indices when they may be used again later.
This commit is contained in:
Campbell Barton 2019-11-28 06:12:17 +11:00
parent e7502ee0aa
commit 7711231838
Notes: blender-bot 2023-02-14 06:17:14 +01:00
Referenced by issue #71969, linux mint 18.3: crash on clean install of 2.81 when repeatedly doing ctrl-pagedown
Referenced by issue #71865, Separating mesh parts breaks shape keys
9 changed files with 40 additions and 4 deletions

View File

@ -1284,6 +1284,7 @@ static void prepare_mesh_for_viewport_render(Main *bmain, const ViewLayer *view_
mesh,
(&(struct BMeshToMeshParams){
.calc_object_remap = true,
.update_shapekey_indices = true,
}));
DEG_id_tag_update(&mesh->id, 0);
}

View File

@ -972,6 +972,16 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
if (ofs) {
MEM_freeN(ofs);
}
if (params->update_shapekey_indices) {
/* We have written a new shape key, if this mesh is _not_ going to be freed,
* update the shape key indices to match the newly updated. */
if (cd_shape_keyindex_offset != -1) {
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
BM_ELEM_CD_SET_INT(eve, cd_shape_keyindex_offset, i);
}
}
}
}
if (oldverts != NULL) {

View File

@ -48,6 +48,16 @@ void BM_mesh_bm_from_me(BMesh *bm, const struct Mesh *me, const struct BMeshFrom
struct BMeshToMeshParams {
/** Update object hook indices & vertex parents. */
uint calc_object_remap : 1;
/**
* This re-assigns shape-key indices. Only do if the BMesh will have continued use
* to update the mesh & shape key in the future.
* In the case the BMesh is freed immediately, this can be left false.
*
* This is needed when flushing changes from edit-mode into object mode,
* so a second flush or edit-mode exit doesn't run with indices
* that have become invalid from updating the shape-key, see T71865.
*/
uint update_shapekey_indices : 1;
struct CustomData_MeshMasks cd_mask_extra;
};
void BM_mesh_bm_to_me(struct Main *bmain,

View File

@ -83,6 +83,7 @@ void EDBM_mesh_clear(struct BMEditMesh *em);
void EDBM_selectmode_to_scene(struct bContext *C);
void EDBM_mesh_make(struct Object *ob, const int select_mode, const bool add_key_index);
void EDBM_mesh_free(struct BMEditMesh *em);
void EDBM_mesh_load_ex(struct Main *bmain, struct Object *ob, bool free_data);
void EDBM_mesh_load(struct Main *bmain, struct Object *ob);
/* flushes based on the current select mode. if in vertex select mode,

View File

@ -4197,7 +4197,12 @@ static bool mesh_separate_loose(
BM_mesh_elem_hflag_disable_all(bm_old, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
if (clear_object_data) {
BM_mesh_bm_to_me(NULL, bm_old, me_old, (&(struct BMeshToMeshParams){0}));
BM_mesh_bm_to_me(NULL,
bm_old,
me_old,
(&(struct BMeshToMeshParams){
.update_shapekey_indices = true,
}));
}
finally:

View File

@ -521,6 +521,7 @@ static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key)
(&(struct BMeshToMeshParams){
/* Undo code should not be manipulating 'G_MAIN->object' hooks/vertex-parent. */
.calc_object_remap = false,
.update_shapekey_indices = false,
.cd_mask_extra = {.vmask = CD_MASK_SHAPE_KEYINDEX},
}));

View File

@ -325,7 +325,7 @@ void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
* \warning This can invalidate the #Mesh runtime cache of other objects (for linked duplicates).
* Most callers should run #DEG_id_tag_update on \a ob->data, see: T46738, T46913
*/
void EDBM_mesh_load(Main *bmain, Object *ob)
void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data)
{
Mesh *me = ob->data;
BMesh *bm = me->edit_mesh->bm;
@ -341,6 +341,7 @@ void EDBM_mesh_load(Main *bmain, Object *ob)
me,
(&(struct BMeshToMeshParams){
.calc_object_remap = true,
.update_shapekey_indices = !free_data,
}));
/* Free derived mesh. usually this would happen through depsgraph but there
@ -380,6 +381,11 @@ void EDBM_mesh_clear(BMEditMesh *em)
}
}
void EDBM_mesh_load(Main *bmain, Object *ob)
{
EDBM_mesh_load_ex(bmain, ob, true);
}
/**
* Should only be called on the active editmesh, otherwise call #BKE_editmesh_free
*/

View File

@ -445,7 +445,7 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f
return false;
}
EDBM_mesh_load(bmain, obedit);
EDBM_mesh_load_ex(bmain, obedit, freedata);
if (freedata) {
EDBM_mesh_free(me->edit_mesh);

View File

@ -1091,7 +1091,9 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args)
bm = self->bm;
struct Main *bmain = NULL;
struct BMeshToMeshParams params = {0};
struct BMeshToMeshParams params = {
.update_shapekey_indices = true,
};
if (me->id.tag & LIB_TAG_NO_MAIN) {
/* Mesh might be coming from a self-contained source like object.to_mesh(). No need to remap
* anything in this case. */