Fix T52515: Crash on BMesh.to_mesh()
authorCampbell Barton <ideasman42@gmail.com>
Sat, 26 Aug 2017 16:38:19 +0000 (02:38 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Sat, 26 Aug 2017 16:44:15 +0000 (02:44 +1000)
source/blender/bmesh/intern/bmesh_mesh_conv.c

index b340bc1a55cac810c095a819625e32090b45c977..2edc043cb131a38f3c0c48e550cf332e8c5b5974 100644 (file)
@@ -226,6 +226,9 @@ void BM_mesh_bm_from_me(
         BMesh *bm, Mesh *me,
         const struct BMeshFromMeshParams *params)
 {
+       const bool is_new =
+               !(bm->totvert ||
+                 (bm->vdata.totlayer || bm->edata.totlayer || bm->pdata.totlayer || bm->ldata.totlayer));
        MVert *mvert;
        MEdge *medge;
        MLoop *mloop;
@@ -235,17 +238,12 @@ void BM_mesh_bm_from_me(
        BMEdge *e, **etable = NULL;
        BMFace *f, **ftable = NULL;
        float (*keyco)[3] = NULL;
-       int totuv, totloops, i, j;
+       int totuv, totloops, i;
 
        /* free custom data */
-       /* this isnt needed in most cases but do just incase */
-       CustomData_free(&bm->vdata, bm->totvert);
-       CustomData_free(&bm->edata, bm->totedge);
-       CustomData_free(&bm->ldata, bm->totloop);
-       CustomData_free(&bm->pdata, bm->totface);
 
        if (!me || !me->totvert) {
-               if (me) { /*no verts? still copy customdata layout*/
+               if (me && is_new) { /*no verts? still copy customdata layout*/
                        CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_ASSIGN, 0);
                        CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_ASSIGN, 0);
                        CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_ASSIGN, 0);
@@ -259,19 +257,27 @@ void BM_mesh_bm_from_me(
                return; /* sanity check */
        }
 
-       vtable = MEM_mallocN(sizeof(BMVert **) * me->totvert, __func__);
+       if (is_new) {
+               CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+               CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+               CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
+               CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
 
-       CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
-       CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
-       CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
-       CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+               /* make sure uv layer names are consisten */
+               totuv = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+               for (i = 0; i < totuv; i++) {
+                       int li = CustomData_get_layer_index_n(&bm->pdata, CD_MTEXPOLY, i);
+                       CustomData_set_layer_name(&bm->ldata, CD_MLOOPUV, i, bm->pdata.layers[li].name);
+               }
+       }
 
-       /* make sure uv layer names are consisten */
-       totuv = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
-       for (i = 0; i < totuv; i++) {
-               int li = CustomData_get_layer_index_n(&bm->pdata, CD_MTEXPOLY, i);
-               CustomData_set_layer_name(&bm->ldata, CD_MLOOPUV, i, bm->pdata.layers[li].name);
+       /* -------------------------------------------------------------------- */
+       /* Shape Key */
+       int tot_shape_keys = me->key ? BLI_listbase_count(&me->key->block) : 0;
+       if (is_new == false) {
+               tot_shape_keys = min_ii(tot_shape_keys, CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY));
        }
+       const float (**shape_key_table)[3] = tot_shape_keys ? BLI_array_alloca(shape_key_table, tot_shape_keys) : NULL;
 
        if ((params->active_shapekey != 0) && (me->key != NULL)) {
                actkey = BLI_findlink(&me->key->block, params->active_shapekey - 1);
@@ -280,11 +286,10 @@ void BM_mesh_bm_from_me(
                actkey = NULL;
        }
 
-       const int tot_shape_keys = me->key ? BLI_listbase_count(&me->key->block) : 0;
-       const float (**shape_key_table)[3] = tot_shape_keys ? BLI_array_alloca(shape_key_table, tot_shape_keys) : NULL;
-
-       if (tot_shape_keys || params->add_key_index) {
-               CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0);
+       if (is_new) {
+               if (tot_shape_keys || params->add_key_index) {
+                       CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0);
+               }
        }
 
        if (tot_shape_keys) {
@@ -304,39 +309,43 @@ void BM_mesh_bm_from_me(
                }
 
                if (actkey && actkey->totelem == me->totvert) {
-                       keyco = actkey->data;
-                       bm->shapenr = params->active_shapekey;
+                       keyco = params->use_shapekey ? actkey->data : NULL;
+                       if (is_new) {
+                               bm->shapenr = params->active_shapekey;
+                       }
                }
 
-               for (i = 0, block = me->key->block.first; block; block = block->next, i++) {
-                       CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY,
-                                                  CD_ASSIGN, NULL, 0, block->name);
-
-                       j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i);
-                       bm->vdata.layers[j].uid = block->uid;
-
+               for (i = 0, block = me->key->block.first; i < tot_shape_keys; block = block->next, i++) {
+                       if (is_new) {
+                               CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY,
+                                                          CD_ASSIGN, NULL, 0, block->name);
+                               int j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i);
+                               bm->vdata.layers[j].uid = block->uid;
+                       }
                        shape_key_table[i] = (const float (*)[3])block->data;
                }
        }
 
-       CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT);
-       CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE);
-       CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP);
-       CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE);
+       if (is_new) {
+               CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT);
+               CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE);
+               CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP);
+               CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE);
 
-       BM_mesh_cd_flag_apply(bm, me->cd_flag);
+               BM_mesh_cd_flag_apply(bm, me->cd_flag);
+       }
 
        const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
        const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
        const int cd_edge_crease_offset  = CustomData_get_offset(&bm->edata, CD_CREASE);
        const int cd_shape_key_offset = me->key ? CustomData_get_offset(&bm->vdata, CD_SHAPEKEY) : -1;
-       const int cd_shape_keyindex_offset = (tot_shape_keys || params->add_key_index) ?
+       const int cd_shape_keyindex_offset = is_new && (tot_shape_keys || params->add_key_index) ?
                  CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX) : -1;
 
+       vtable = MEM_mallocN(sizeof(BMVert **) * me->totvert, __func__);
+
        for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) {
-               v = vtable[i] = BM_vert_create(
-                       bm, keyco && params->use_shapekey ? keyco[i] : mvert->co, NULL,
-                       BM_CREATE_SKIP_CD);
+               v = vtable[i] = BM_vert_create(bm, keyco ? keyco[i] : mvert->co, NULL, BM_CREATE_SKIP_CD);
                BM_elem_index_set(v, i); /* set_ok */
 
                /* transfer flag */
@@ -360,13 +369,14 @@ void BM_mesh_bm_from_me(
                /* set shapekey data */
                if (tot_shape_keys) {
                        float (*co_dst)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_shape_key_offset);
-                       for (j = 0; j < tot_shape_keys; j++, co_dst++) {
+                       for (int j = 0; j < tot_shape_keys; j++, co_dst++) {
                                copy_v3_v3(*co_dst, shape_key_table[j][i]);
                        }
                }
        }
-
-       bm->elem_index_dirty &= ~BM_VERT; /* added in order, clear dirty flag */
+       if (is_new) {
+               bm->elem_index_dirty &= ~BM_VERT; /* added in order, clear dirty flag */
+       }
 
        etable = MEM_mallocN(sizeof(BMEdge **) * me->totedge, __func__);
 
@@ -390,8 +400,14 @@ void BM_mesh_bm_from_me(
                if (cd_edge_crease_offset  != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset,  (float)medge->crease  / 255.0f);
 
        }
+       if (is_new) {
+               bm->elem_index_dirty &= ~BM_EDGE; /* added in order, clear dirty flag */
+       }
 
-       bm->elem_index_dirty &= ~BM_EDGE; /* added in order, clear dirty flag */
+       /* only needed for selection. */
+       if (me->mselect && me->totselect != 0) {
+               ftable = MEM_mallocN(sizeof(BMFace **) * me->totpoly, __func__);
+       }
 
        mloop = me->mloop;
        mp = me->mpoly;
@@ -401,6 +417,9 @@ void BM_mesh_bm_from_me(
 
                f = bm_face_create_from_mpoly(mp, mloop + mp->loopstart,
                                              bm, vtable, etable);
+               if (ftable != NULL) {
+                       ftable[i] = f;
+               }
 
                if (UNLIKELY(f == NULL)) {
                        printf("%s: Warning! Bad face in mesh"
@@ -423,7 +442,7 @@ void BM_mesh_bm_from_me(
                f->mat_nr = mp->mat_nr;
                if (i == me->act_face) bm->act_face = f;
 
-               j = mp->loopstart;
+               int j = mp->loopstart;
                l_iter = l_first = BM_FACE_FIRST_LOOP(f);
                do {
                        /* don't use 'j' since we may have skipped some faces, hence some loops. */
@@ -440,8 +459,9 @@ void BM_mesh_bm_from_me(
                        BM_face_normal_update(f);
                }
        }
-
-       bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); /* added in order, clear dirty flag */
+       if (is_new) {
+               bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); /* added in order, clear dirty flag */
+       }
 
        /* -------------------------------------------------------------------- */
        /* MSelect clears the array elements (avoid adding multiple times).
@@ -450,11 +470,6 @@ void BM_mesh_bm_from_me(
         */
 
        if (me->mselect && me->totselect != 0) {
-               if (ftable == NULL) {
-                       ftable = MEM_mallocN(sizeof(BMFace **) * bm->totface, __func__);
-                       BM_iter_as_array(bm, BM_FACES_OF_MESH, NULL, (void **)ftable, bm->totface);
-               }
-
                MSelect *msel;
                for (i = 0, msel = me->mselect; i < me->totselect; i++, msel++) {
                        BMElem **ele_p;