Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/bmesh/intern')
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.cc496
-rw-r--r--source/blender/bmesh/intern/bmesh_query.c8
2 files changed, 306 insertions, 198 deletions
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
index ae6b4da6003..ecdc86d31cf 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
@@ -54,6 +54,19 @@
*
* This has the effect from the users POV of leaving the mesh un-touched,
* and only editing the active shape key-block.
+ *
+ * \subsection other_notes Other Notes
+ *
+ * Other details noted here which might not be so obvious:
+ *
+ * - The #CD_SHAPEKEY layer is only used in edit-mode,
+ * and the #Mesh.key is only used in object-mode.
+ * Although the #CD_SHAPEKEY custom-data layer is converted into #Key data-blocks for each
+ * undo-step while in edit-mode.
+ * - The #CD_SHAPE_KEYINDEX layer is used to check if vertices existed when entering edit-mode.
+ * Values of the indices are only used for shape-keys when the #CD_SHAPEKEY layer can't be found,
+ * allowing coordinates from the #Key to be used to prevent data-loss.
+ * These indices are also used to maintain correct indices for hook modifiers and vertex parents.
*/
#include "DNA_key_types.h"
@@ -84,6 +97,10 @@
#include "bmesh.h"
#include "intern/bmesh_private.h" /* For element checking. */
+#include "CLG_log.h"
+
+static CLG_LogRef LOG = {"bmesh.mesh.convert"};
+
using blender::Array;
using blender::IndexRange;
using blender::Span;
@@ -195,10 +212,10 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
if (!me || !me->totvert) {
if (me && is_new) { /* No verts? still copy custom-data layout. */
- CustomData_copy(&me->vdata, &bm->vdata, mask.vmask, CD_ASSIGN, 0);
- CustomData_copy(&me->edata, &bm->edata, mask.emask, CD_ASSIGN, 0);
- CustomData_copy(&me->ldata, &bm->ldata, mask.lmask, CD_ASSIGN, 0);
- CustomData_copy(&me->pdata, &bm->pdata, mask.pmask, CD_ASSIGN, 0);
+ CustomData_copy(&me->vdata, &bm->vdata, mask.vmask, CD_DEFAULT, 0);
+ CustomData_copy(&me->edata, &bm->edata, mask.emask, CD_DEFAULT, 0);
+ CustomData_copy(&me->ldata, &bm->ldata, mask.lmask, CD_DEFAULT, 0);
+ CustomData_copy(&me->pdata, &bm->pdata, mask.pmask, CD_DEFAULT, 0);
CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT);
CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE);
@@ -553,8 +570,89 @@ static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert)
return vertMap;
}
+/* -------------------------------------------------------------------- */
+/** \name Edit-Mesh to Shape Key Conversion
+ *
+ * There are some details relating to using data from shape keys that need to be
+ * considered carefully for shape key synchronization logic.
+ *
+ * Key Block Usage
+ * ***************
+ *
+ * Key blocks (data in #Mesh.key must be used carefully).
+ *
+ * They can be used to query which key blocks are relative to the basis
+ * since it's not possible to add/remove/reorder key blocks while in edit-mode.
+ *
+ * Key Block Coordinates
+ * =====================
+ *
+ * Key blocks locations must *not* be used. This was done from v2.67 to 3.0,
+ * causing bugs T35170 & T44415.
+ *
+ * Shape key synchronizing could work under the assumption that the key-block is
+ * fixed-in-place when entering edit-mode allowing them to be used as a reference when exiting.
+ * It often does work but isn't reliable since for e.g. rendering may flush changes
+ * from the edit-mesh to the key-block (there are a handful of other situations where
+ * changes may be flushed, see #ED_editors_flush_edits and related functions).
+ * When using undo, it's not known if the data in key-block is from the past or future,
+ * so just don't use this data as it causes pain and suffering for users and developers alike.
+ *
+ * Instead, use the shape-key values stored in #CD_SHAPEKEY since they are reliably
+ * based on the original locations, unless explicitly manipulated.
+ * It's important to write the final shape-key values back to the #CD_SHAPEKEY so applying
+ * the difference between the original-basis and the new coordinates isn't done multiple times.
+ * Therefore #ED_editors_flush_edits and other flushing calls will update both the #Mesh.key
+ * and the edit-mode #CD_SHAPEKEY custom-data layers.
+ *
+ * WARNING: There is an exception to the rule of ignoring coordinates in the destination:
+ * that is when shape-key data in `bm` can't be found (which is itself an error/exception).
+ * In this case our own rule is violated as the alternative is loosing the shape-data entirely.
+ *
+ * Flushing Coordinates Back to the #BMesh
+ * ---------------------------------------
+ *
+ * The edit-mesh may be flushed back to the #Mesh and #Key used to generate it.
+ * When this is done, the new values are written back to the #BMesh's #CD_SHAPEKEY as well.
+ * This is necessary when editing basis-shapes so the difference in shape keys
+ * is not applied multiple times. If it were important to avoid it could be skipped while
+ * exiting edit-mode (as the entire #BMesh is freed in that case), however it's just copying
+ * back a `float[3]` so the work to check if it's necessary isn't worth the overhead.
+ *
+ * In general updating the #BMesh's #CD_SHAPEKEY makes shake-key logic easier to reason about
+ * since it means flushing data back to the mesh has the same behavior as exiting and entering
+ * edit-mode (a more common operation). Meaning there is one less corner-case to have to consider.
+ *
+ * Exceptional Cases
+ * *****************
+ *
+ * There are some situations that should not happen in typical usage but are
+ * still handled in this code, since failure to handle them could loose user-data.
+ * These could be investigated further since if they never happen in practice,
+ * we might consider removing them. However, the possibility of an mesh directly
+ * being modified by Python or some other low level logic that changes key-blocks
+ * means there is a potential this to happen so keeping code to these cases remain supported.
+ *
+ * - Custom Data & Mesh Key Block Synchronization.
+ * Key blocks in `me->key->block` should always have an associated
+ * #CD_SHAPEKEY layer in `bm->vdata`.
+ * If they don't there are two fall-backs for setting the location,
+ * - Use the value from the original shape key
+ * WARNING: this is technically incorrect! (see note on "Key Block Usage").
+ * - Use the current vertex location,
+ * Also not correct but it's better then having it zeroed for e.g.
+ *
+ * - Missing key-index layer.
+ * In this case the basis key wont apply it's deltas to other keys and in the case
+ * a shape-key layer is missing, its coordinates will be initialized from the edit-mesh
+ * vertex locations instead of attempting to remap the shape-keys coordinates.
+ *
+ * \note These cases are considered abnormal and shouldn't occur in typical usage.
+ * A warning is logged in this case to help troubleshooting bugs with shape-keys.
+ * \{ */
+
/**
- * Returns custom-data shapekey index from a keyblock or -1
+ * Returns custom-data shape-key index from a key-block or -1
* \note could split this out into a more generic function.
*/
static int bm_to_mesh_shape_layer_index_from_kb(BMesh *bm, KeyBlock *currkey)
@@ -573,6 +671,196 @@ static int bm_to_mesh_shape_layer_index_from_kb(BMesh *bm, KeyBlock *currkey)
return -1;
}
+/**
+ * Update `key` with shape key data stored in `bm`.
+ *
+ * \param bm: The source BMesh.
+ * \param key: The destination key.
+ * \param mvert: The destination vertex array (in some situations it's coordinates are updated).
+ */
+static void bm_to_mesh_shape(BMesh *bm, Key *key, MVert *mvert)
+{
+ KeyBlock *actkey = static_cast<KeyBlock *>(BLI_findlink(&key->block, bm->shapenr - 1));
+
+ /* It's unlikely this ever remains false, check for correctness. */
+ bool actkey_has_layer = false;
+
+ /* Go through and find any shape-key custom-data layers
+ * that might not have corresponding KeyBlocks, and add them if necessary. */
+ for (int i = 0; i < bm->vdata.totlayer; i++) {
+ if (bm->vdata.layers[i].type != CD_SHAPEKEY) {
+ continue;
+ }
+
+ KeyBlock *currkey;
+ for (currkey = (KeyBlock *)key->block.first; currkey; currkey = currkey->next) {
+ if (currkey->uid == bm->vdata.layers[i].uid) {
+ break;
+ }
+ }
+
+ if (currkey) {
+ if (currkey == actkey) {
+ actkey_has_layer = true;
+ }
+ }
+ else {
+ currkey = BKE_keyblock_add(key, bm->vdata.layers[i].name);
+ currkey->uid = bm->vdata.layers[i].uid;
+ }
+ }
+
+ const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
+ BMIter iter;
+ BMVert *eve;
+ float(*ofs)[3] = nullptr;
+
+ /* Editing the basis key updates others. */
+ if ((key->type == KEY_RELATIVE) &&
+ /* The shape-key coordinates used from entering edit-mode are used. */
+ (actkey_has_layer == true) &&
+ /* Original key-indices are only used to check the vertex existed when entering edit-mode. */
+ (cd_shape_keyindex_offset != -1) &&
+ /* Offsets are only needed if the current shape is a basis for others. */
+ BKE_keyblock_is_basis(key, bm->shapenr - 1)) {
+
+ BLI_assert(actkey != nullptr); /* Assured by `actkey_has_layer` check. */
+ const int actkey_uuid = bm_to_mesh_shape_layer_index_from_kb(bm, actkey);
+
+ /* Since `actkey_has_layer == true`, this must never fail. */
+ BLI_assert(actkey_uuid != -1);
+
+ const int cd_shape_offset = CustomData_get_n_offset(&bm->vdata, CD_SHAPEKEY, actkey_uuid);
+
+ ofs = static_cast<float(*)[3]>(MEM_mallocN(sizeof(float[3]) * bm->totvert, __func__));
+ int i;
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
+ /* Check the vertex existed when entering edit-mode (otherwise don't apply an offset). */
+ if (keyi != ORIGINDEX_NONE) {
+ float *co_orig = (float *)BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset);
+ /* Could use 'eve->co' or the destination #MVert.co, they're the same at this point. */
+ sub_v3_v3v3(ofs[i], eve->co, co_orig);
+ }
+ else {
+ /* If there are new vertices in the mesh, we can't propagate the offset
+ * because it will only work for the existing vertices and not the new
+ * ones, creating a mess when doing e.g. subdivide + translate. */
+ MEM_freeN(ofs);
+ ofs = nullptr;
+ break;
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (KeyBlock *, currkey, &key->block) {
+ int keyi;
+ float(*currkey_data)[3];
+
+ const int currkey_uuid = bm_to_mesh_shape_layer_index_from_kb(bm, currkey);
+ const int cd_shape_offset = (currkey_uuid == -1) ?
+ -1 :
+ CustomData_get_n_offset(&bm->vdata, CD_SHAPEKEY, currkey_uuid);
+
+ /* Common case, the layer data is available, use it where possible. */
+ if (cd_shape_offset != -1) {
+ const bool apply_offset = (ofs != nullptr) && (currkey != actkey) &&
+ (bm->shapenr - 1 == currkey->relative);
+
+ if (currkey->data && (currkey->totelem == bm->totvert)) {
+ /* Use memory in-place. */
+ }
+ else {
+ currkey->data = MEM_reallocN(currkey->data, key->elemsize * bm->totvert);
+ currkey->totelem = bm->totvert;
+ }
+ currkey_data = (float(*)[3])currkey->data;
+
+ int i;
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ float *co_orig = (float *)BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset);
+
+ if (currkey == actkey) {
+ copy_v3_v3(currkey_data[i], eve->co);
+
+ if (actkey != key->refkey) {
+ /* Without this, the real mesh coordinates (uneditable) as soon as you create
+ * the Basis shape, see: T30771 for details. */
+ if (cd_shape_keyindex_offset != -1) {
+ keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
+ if (keyi != ORIGINDEX_NONE) {
+ copy_v3_v3(mvert[i].co, co_orig);
+ }
+ }
+ }
+ }
+ else {
+ copy_v3_v3(currkey_data[i], co_orig);
+ }
+
+ /* Propagate edited basis offsets to other shapes. */
+ if (apply_offset) {
+ add_v3_v3(currkey_data[i], ofs[i]);
+ }
+
+ /* Apply back new coordinates shape-keys that have offset into #BMesh.
+ * Otherwise, in case we call again #BM_mesh_bm_to_me on same #BMesh,
+ * we'll apply diff from previous call to #BM_mesh_bm_to_me,
+ * to shape-key values from original creation of the #BMesh. See T50524. */
+ copy_v3_v3(co_orig, currkey_data[i]);
+ }
+ }
+ else {
+ /* No original layer data, use fallback information. */
+ if (currkey->data && (cd_shape_keyindex_offset != -1)) {
+ CLOG_WARN(&LOG,
+ "Found shape-key but no CD_SHAPEKEY layers to read from, "
+ "using existing shake-key data where possible");
+ }
+ else {
+ CLOG_WARN(&LOG,
+ "Found shape-key but no CD_SHAPEKEY layers to read from, "
+ "using basis shape-key data");
+ }
+
+ currkey_data = static_cast<float(*)[3]>(
+ MEM_mallocN(key->elemsize * bm->totvert, "currkey->data"));
+
+ int i;
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+
+ if ((currkey->data != nullptr) && (cd_shape_keyindex_offset != -1) &&
+ ((keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset)) != ORIGINDEX_NONE) &&
+ (keyi < currkey->totelem)) {
+ /* Reconstruct keys via vertices original key indices.
+ * WARNING(@campbellbarton): `currkey->data` is known to be unreliable as the edit-mesh
+ * coordinates may be flushed back to the shape-key when exporting or rendering.
+ * This is a last resort! If this branch is running as part of regular usage
+ * it can be considered a bug. */
+ const float(*oldkey)[3] = static_cast<const float(*)[3]>(currkey->data);
+ copy_v3_v3(currkey_data[i], oldkey[keyi]);
+ }
+ else {
+ /* Fail! fill in with dummy value. */
+ copy_v3_v3(currkey_data[i], eve->co);
+ }
+ }
+
+ currkey->totelem = bm->totvert;
+ if (currkey->data) {
+ MEM_freeN(currkey->data);
+ }
+ currkey->data = currkey_data;
+ }
+ }
+
+ if (ofs) {
+ MEM_freeN(ofs);
+ }
+}
+
+/** \} */
+
BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
{
/* This is a cheap way to set the edge draw, its not precise and will
@@ -604,23 +892,8 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
- MVert *oldverts = nullptr;
const int ototvert = me->totvert;
- if (me->key && (cd_shape_keyindex_offset != -1)) {
- /* Keep the old verts in case we are working on* a key, which is done at the end. */
-
- /* Use the array in-place instead of duplicating the array. */
-#if 0
- oldverts = MEM_dupallocN(me->mvert);
-#else
- oldverts = me->mvert;
- me->mvert = nullptr;
- CustomData_update_typemap(&me->vdata);
- CustomData_set_layer(&me->vdata, CD_MVERT, nullptr);
-#endif
- }
-
/* Free custom data. */
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
@@ -661,9 +934,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, mloop, me->totloop);
CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, mpoly, me->totpoly);
- /* There is no way to tell if BMesh normals are dirty or not. Instead of calculating the normals
- * on the BMesh possibly unnecessarily, just tag them dirty on the resulting mesh. */
- BKE_mesh_normals_tag_dirty(me);
+ /* Clear normals on the mesh completely, since the original vertex and polygon count might be
+ * different than the BMesh's. */
+ BKE_mesh_clear_derived_normals(me);
me->cd_flag = BM_mesh_cd_flag_from_bmesh(bm);
@@ -846,152 +1119,8 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
}
}
- /* See comment below, this logic is in twice. */
-
if (me->key) {
- KeyBlock *currkey;
- KeyBlock *actkey = static_cast<KeyBlock *>(BLI_findlink(&me->key->block, bm->shapenr - 1));
-
- float(*ofs)[3] = nullptr;
-
- /* Go through and find any shape-key custom-data layers
- * that might not have corresponding KeyBlocks, and add them if necessary. */
- for (i = 0; i < bm->vdata.totlayer; i++) {
- if (bm->vdata.layers[i].type != CD_SHAPEKEY) {
- continue;
- }
-
- for (currkey = (KeyBlock *)me->key->block.first; currkey; currkey = currkey->next) {
- if (currkey->uid == bm->vdata.layers[i].uid) {
- break;
- }
- }
-
- if (!currkey) {
- currkey = BKE_keyblock_add(me->key, bm->vdata.layers[i].name);
- currkey->uid = bm->vdata.layers[i].uid;
- }
- }
-
- /* Editing the base key should update others. */
- if (/* Only need offsets for relative shape keys. */
- (me->key->type == KEY_RELATIVE) &&
-
- /* Unlikely, but the active key may not be valid if the
- * BMesh and the mesh are out of sync. */
- (actkey != nullptr) &&
-
- /* Not used here, but 'oldverts' is used later for applying 'ofs'. */
- (oldverts != nullptr) &&
-
- /* Needed for referencing oldverts. */
- (cd_shape_keyindex_offset != -1)) {
-
- const bool act_is_basis = BKE_keyblock_is_basis(me->key, bm->shapenr - 1);
-
- /* Active key is a base. */
- if (act_is_basis) {
- const float(*fp)[3] = static_cast<const float(*)[3]>(actkey->data);
-
- ofs = static_cast<float(*)[3]>(
- MEM_callocN(sizeof(float[3]) * bm->totvert, "currkey->data"));
- mvert = me->mvert;
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
-
- /* Could use 'eve->co' or 'mvert->co', they're the same at this point. */
- if (keyi != ORIGINDEX_NONE && keyi < actkey->totelem) {
- sub_v3_v3v3(ofs[i], mvert->co, fp[keyi]);
- }
- else {
- /* If there are new vertices in the mesh, we can't propagate the offset
- * because it will only work for the existing vertices and not the new
- * ones, creating a mess when doing e.g. subdivide + translate. */
- MEM_freeN(ofs);
- ofs = nullptr;
- break;
- }
-
- mvert++;
- }
- }
- }
-
- LISTBASE_FOREACH (KeyBlock *, currkey, &me->key->block) {
- int keyi;
- const float(*ofs_pt)[3] = ofs;
- float *newkey, (*oldkey)[3], *fp;
-
- const int currkey_uuid = bm_to_mesh_shape_layer_index_from_kb(bm, currkey);
- const int cd_shape_offset = (currkey_uuid == -1) ? -1 :
- CustomData_get_n_offset(&bm->vdata,
- CD_SHAPEKEY,
- currkey_uuid);
- const bool apply_offset = (cd_shape_offset != -1) && (ofs != nullptr) &&
- (currkey != actkey) && (bm->shapenr - 1 == currkey->relative);
-
- fp = newkey = static_cast<float *>(
- MEM_callocN(me->key->elemsize * bm->totvert, "currkey->data"));
- oldkey = static_cast<float(*)[3]>(currkey->data);
-
- mvert = me->mvert;
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
-
- if (currkey == actkey) {
- copy_v3_v3(fp, eve->co);
-
- if (actkey != me->key->refkey) { /* Important see bug T30771. */
- if (cd_shape_keyindex_offset != -1) {
- if (oldverts) {
- keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
- if (keyi != ORIGINDEX_NONE && keyi < currkey->totelem) { /* Valid old vertex. */
- copy_v3_v3(mvert->co, oldverts[keyi].co);
- }
- }
- }
- }
- }
- else if (cd_shape_offset != -1) {
- /* In most cases this runs. */
- copy_v3_v3(fp, (const float *)BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset));
- }
- else if ((oldkey != nullptr) && (cd_shape_keyindex_offset != -1) &&
- ((keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset)) != ORIGINDEX_NONE) &&
- (keyi < currkey->totelem)) {
- /* Old method of reconstructing keys via vertices original key indices,
- * currently used if the new method above fails
- * (which is theoretically possible in certain cases of undo). */
- copy_v3_v3(fp, oldkey[keyi]);
- }
- else {
- /* Fail! fill in with dummy value. */
- copy_v3_v3(fp, mvert->co);
- }
-
- /* Propagate edited basis offsets to other shapes. */
- if (apply_offset) {
- add_v3_v3(fp, *ofs_pt++);
- /* Apply back new coordinates shape-keys that have offset into BMesh.
- * Otherwise, in case we call again #BM_mesh_bm_to_me on same BMesh,
- * we'll apply diff from previous call to #BM_mesh_bm_to_me,
- * to shape-key values from *original creation of the BMesh*. See T50524. */
- copy_v3_v3((float *)BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset), fp);
- }
-
- fp += 3;
- mvert++;
- }
-
- currkey->totelem = bm->totvert;
- if (currkey->data) {
- MEM_freeN(currkey->data);
- }
- currkey->data = newkey;
- }
-
- if (ofs) {
- MEM_freeN(ofs);
- }
+ bm_to_mesh_shape(bm, me->key, me->mvert);
}
/* Run this even when shape keys aren't used since it may be used for hooks or vertex parents. */
@@ -1005,10 +1134,6 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
}
}
- if (oldverts != nullptr) {
- MEM_freeN(oldverts);
- }
-
/* Topology could be changed, ensure #CD_MDISPS are ok. */
multires_topology_changed(me);
@@ -1028,10 +1153,6 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
me->totloop = bm->totloop;
me->totpoly = bm->totface;
- CustomData_add_layer(&me->vdata, CD_ORIGINDEX, CD_CALLOC, nullptr, bm->totvert);
- CustomData_add_layer(&me->edata, CD_ORIGINDEX, CD_CALLOC, nullptr, bm->totedge);
- CustomData_add_layer(&me->pdata, CD_ORIGINDEX, CD_CALLOC, nullptr, bm->totface);
-
CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, bm->totvert);
CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, nullptr, bm->totedge);
CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, nullptr, bm->totloop);
@@ -1059,22 +1180,18 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
MEdge *medge = me->medge;
MLoop *mloop = me->mloop;
MPoly *mpoly = me->mpoly;
- int *index, add_orig;
unsigned int i, j;
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);
- BKE_mesh_normals_tag_dirty(me);
+ /* Clear normals on the mesh completely, since the original vertex and polygon count might be
+ * different than the BMesh's. */
+ BKE_mesh_clear_derived_normals(me);
me->runtime.deformed_only = true;
- /* Don't add origindex layer if one already exists. */
- add_orig = !CustomData_has_layer(&bm->pdata, CD_ORIGINDEX);
-
- index = (int *)CustomData_get_layer(&me->vdata, CD_ORIGINDEX);
-
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
MVert *mv = &mvert[i];
@@ -1088,15 +1205,10 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
mv->bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eve, cd_vert_bweight_offset);
}
- if (add_orig) {
- *index++ = i;
- }
-
CustomData_from_bmesh_block(&bm->vdata, &me->vdata, eve->head.data, i);
}
bm->elem_index_dirty &= ~BM_VERT;
- index = (int *)CustomData_get_layer(&me->edata, CD_ORIGINDEX);
BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
MEdge *med = &medge[i];
@@ -1123,13 +1235,9 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
}
CustomData_from_bmesh_block(&bm->edata, &me->edata, eed->head.data, i);
- if (add_orig) {
- *index++ = i;
- }
}
bm->elem_index_dirty &= ~BM_EDGE;
- index = (int *)CustomData_get_layer(&me->pdata, CD_ORIGINDEX);
j = 0;
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
BMLoop *l_iter;
@@ -1156,10 +1264,6 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
} while ((l_iter = l_iter->next) != l_first);
CustomData_from_bmesh_block(&bm->pdata, &me->pdata, efa->head.data, i);
-
- if (add_orig) {
- *index++ = i;
- }
}
bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP);
diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c
index 45a42c29d84..1bc5b70f874 100644
--- a/source/blender/bmesh/intern/bmesh_query.c
+++ b/source/blender/bmesh/intern/bmesh_query.c
@@ -2234,7 +2234,9 @@ int BM_mesh_calc_face_groups(BMesh *bm,
MEM_freeN(stack);
/* reduce alloc to required size */
- group_index = MEM_reallocN(group_index, sizeof(*group_index) * group_curr);
+ if (group_index_len != group_curr) {
+ group_index = MEM_reallocN(group_index, sizeof(*group_index) * group_curr);
+ }
*r_group_index = group_index;
return group_curr;
@@ -2354,7 +2356,9 @@ int BM_mesh_calc_edge_groups(BMesh *bm,
MEM_freeN(stack);
/* reduce alloc to required size */
- group_index = MEM_reallocN(group_index, sizeof(*group_index) * group_curr);
+ if (group_index_len != group_curr) {
+ group_index = MEM_reallocN(group_index, sizeof(*group_index) * group_curr);
+ }
*r_group_index = group_index;
return group_curr;