Fix T71865: Separating mesh parts breaks shape keys
authorCampbell Barton <ideasman42@gmail.com>
Wed, 27 Nov 2019 19:12:17 +0000 (06:12 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 27 Nov 2019 19:17:14 +0000 (06:17 +1100)
This was an old bug which could be caused by saving after separating.
Changes from 79b703bb635e made this fail reliably.

Update shape key indices when they may be used again later.

source/blender/blenkernel/intern/scene.c
source/blender/bmesh/intern/bmesh_mesh_conv.c
source/blender/bmesh/intern/bmesh_mesh_conv.h
source/blender/editors/include/ED_mesh.h
source/blender/editors/mesh/editmesh_tools.c
source/blender/editors/mesh/editmesh_undo.c
source/blender/editors/mesh/editmesh_utils.c
source/blender/editors/object/object_edit.c
source/blender/python/bmesh/bmesh_py_types.c

index 9dcebbba56ebd47ce5f96e502a3655207b14b58b..ab72b7d3b0db9d3aa6d04b5ce098f02fee997f5b 100644 (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);
       }
index 9bcc9b9e84b361ae881bebe9c602ff266c070333..4e65ac40dd44adfbda88ea33a5ed5d22aabf097a 100644 (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) {
index f0302764a5ff7530251ad6c22a69ab94a7430606..65d5c6d54943382e911ce3c9734752da5f981b27 100644 (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,
index 835e1b4e26f357809805571d0095bd31e019a67e..4bf43a2034ad7b33900b0ff702987920dcd842d5 100644 (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,
index 8df392fb04b7183109ce0fa1a541317710946c10..59090acf433194e0fe8a4bc2a39b9fad1416f5de 100644 (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:
index 44984251243d9fb7653ea5ec58ad40386cb91df9..d07ba05de20b4c3a9ae21e166f4ae240395c8117 100644 (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},
       }));
 
index 522c2f32d27bb4c0d2456c1ce03cbf6ae3ae9585..42404554ed86305e0cf98e06199b4c203e14af68 100644 (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
  */
index be815fb0d10f5a9560f20856103547137bfec02e..b7c9579e277b745c220f8ca563ed6cbdd69a751d 100644 (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);
index af595de2ee468facfb8cce556d38b02dc33c3119..b601a35f7f2169984cad7a0b1147803766b60ddb 100644 (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. */