From 6a689b5047b23bccd5e36ae9cbd74cc64f4427b3 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Tue, 28 Jul 2020 09:35:58 -0300 Subject: Transform: Correct Face Attributes: Option to merge attributes Keeping face attributes connected is now optional. Keeping UV's connected is useful for organic modeling, but bad for architectural. Differential Revision: https://developer.blender.org/D8360 --- .../editors/transform/transform_convert_mesh.c | 425 ++++++++++++--------- 1 file changed, 235 insertions(+), 190 deletions(-) (limited to 'source/blender/editors/transform/transform_convert_mesh.c') diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index 31b9b771047..289057b612e 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -958,41 +958,44 @@ void createTransEditVerts(TransInfo *t) /** \} */ /* -------------------------------------------------------------------- */ -/** \name CustomData Layer Correction (for meshes) +/** \name CustomData Layer Correction * * \{ */ -struct TransCustomDataLayerVert { - BMVert *v; - float co_orig_3d[3]; +struct TransCustomDataMergeGroup { + /** map {BMVert: TransCustomDataLayerVert} */ struct LinkNode **cd_loop_groups; }; struct TransCustomDataLayer { BMesh *bm; + struct MemArena *arena; - int cd_loop_mdisp_offset; - - /** map {BMVert: TransCustomDataLayerVert} */ - struct GHash *origverts; struct GHash *origfaces; struct BMesh *bm_origfaces; - struct MemArena *arena; - /** Number of math BMLoop layers. */ - int layer_math_map_num; - /** Array size of 'layer_math_map_num' - * maps TransCustomDataLayerVert.cd_group index to absolute CustomData layer index */ - int *layer_math_map; - - /* Array with all elements transformed. */ - struct TransCustomDataLayerVert *data; - int data_len; + /* Special handle for multi-resolution. */ + int cd_loop_mdisp_offset; + + /* Optionally merge custom-data groups (this keeps UVs connected for example). */ + struct { + /** map {BMVert: TransDataBasic} */ + struct GHash *origverts; + struct TransCustomDataMergeGroup *data; + int data_len; + /** Array size of 'layer_math_map_len' + * maps #TransCustomDataLayerVert.cd_group index to absolute #CustomData layer index */ + int *customdatalayer_map; + /** Number of math BMLoop layers. */ + int customdatalayer_map_len; + } merge_group; + + bool use_merge_group; }; -static void trans_mesh_customdata_free_cb(struct TransInfo *UNUSED(t), - struct TransDataContainer *UNUSED(tc), - struct TransCustomData *custom_data) +static void mesh_customdatacorrect_free_cb(struct TransInfo *UNUSED(t), + struct TransDataContainer *UNUSED(tc), + struct TransCustomData *custom_data) { struct TransCustomDataLayer *tcld = custom_data->data; bmesh_edit_end(tcld->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES); @@ -1003,77 +1006,129 @@ static void trans_mesh_customdata_free_cb(struct TransInfo *UNUSED(t), if (tcld->origfaces) { BLI_ghash_free(tcld->origfaces, NULL, NULL); } - if (tcld->origverts) { - BLI_ghash_free(tcld->origverts, NULL, NULL); + if (tcld->merge_group.origverts) { + BLI_ghash_free(tcld->merge_group.origverts, NULL, NULL); } if (tcld->arena) { BLI_memarena_free(tcld->arena); } - if (tcld->layer_math_map) { - MEM_freeN(tcld->layer_math_map); + if (tcld->merge_group.customdatalayer_map) { + MEM_freeN(tcld->merge_group.customdatalayer_map); } MEM_freeN(tcld); custom_data->data = NULL; } -static void create_trans_vert_customdata_layer(BMVert *v, - struct TransCustomDataLayer *tcld, - struct TransCustomDataLayerVert *r_tcld_vert) +static void mesh_customdatacorrect_init_vert(struct TransCustomDataLayer *tcld, + BMVert *v, + const int index) { BMesh *bm = tcld->bm; BMIter liter; int j, l_num; float *loop_weights; - /* copy face data */ // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) { BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, v); l_num = liter.count; - loop_weights = BLI_array_alloca(loop_weights, l_num); + loop_weights = tcld->use_merge_group ? BLI_array_alloca(loop_weights, l_num) : NULL; for (j = 0; j < l_num; j++) { BMLoop *l = BM_iter_step(&liter); BMLoop *l_prev, *l_next; + + /* Generic custom-data correction. Copy face data. */ void **val_p; if (!BLI_ghash_ensure_p(tcld->origfaces, l->f, &val_p)) { BMFace *f_copy = BM_face_copy(tcld->bm_origfaces, bm, l->f, true, true); *val_p = f_copy; } - if ((l_prev = BM_loop_find_prev_nodouble(l, l->next, FLT_EPSILON)) && - (l_next = BM_loop_find_next_nodouble(l, l_prev, FLT_EPSILON))) { - loop_weights[j] = angle_v3v3v3(l_prev->v->co, l->v->co, l_next->v->co); + if (tcld->use_merge_group) { + if ((l_prev = BM_loop_find_prev_nodouble(l, l->next, FLT_EPSILON)) && + (l_next = BM_loop_find_next_nodouble(l, l_prev, FLT_EPSILON))) { + loop_weights[j] = angle_v3v3v3(l_prev->v->co, l->v->co, l_next->v->co); + } + else { + loop_weights[j] = 0.0f; + } + } + } + + if (tcld->use_merge_group) { + /* Store cd_loop_groups. */ + struct TransCustomDataMergeGroup *merge_data = &tcld->merge_group.data[index]; + if (l_num != 0) { + merge_data->cd_loop_groups = BLI_memarena_alloc( + tcld->arena, tcld->merge_group.customdatalayer_map_len * sizeof(void *)); + for (j = 0; j < tcld->merge_group.customdatalayer_map_len; j++) { + const int layer_nr = tcld->merge_group.customdatalayer_map[j]; + merge_data->cd_loop_groups[j] = BM_vert_loop_groups_data_layer_create( + bm, v, layer_nr, loop_weights, tcld->arena); + } } else { - loop_weights[j] = 0.0f; + merge_data->cd_loop_groups = NULL; } + + BLI_ghash_insert(tcld->merge_group.origverts, v, merge_data); } +} + +static void mesh_customdatacorrect_init_container_generic(TransDataContainer *UNUSED(tc), + struct TransCustomDataLayer *tcld) +{ + BMesh *bm = tcld->bm; + + struct GHash *origfaces = BLI_ghash_ptr_new(__func__); + struct BMesh *bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default, + &((struct BMeshCreateParams){ + .use_toolflags = false, + })); - /* store cd_loop_groups */ - if (tcld->layer_math_map_num && (l_num != 0)) { - r_tcld_vert->cd_loop_groups = BLI_memarena_alloc(tcld->arena, - tcld->layer_math_map_num * sizeof(void *)); - for (j = 0; j < tcld->layer_math_map_num; j++) { - const int layer_nr = tcld->layer_math_map[j]; - r_tcld_vert->cd_loop_groups[j] = BM_vert_loop_groups_data_layer_create( - bm, v, layer_nr, loop_weights, tcld->arena); + /* We need to have matching custom-data. */ + BM_mesh_copy_init_customdata(bm_origfaces, bm, NULL); + tcld->origfaces = origfaces; + tcld->bm_origfaces = bm_origfaces; + + bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES); + tcld->cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); +} + +static void mesh_customdatacorrect_init_container_merge_group(TransDataContainer *tc, + struct TransCustomDataLayer *tcld) +{ + BMesh *bm = tcld->bm; + BLI_assert(CustomData_has_math(&bm->ldata)); + + /* TODO: We don't need `layer_math_map` when there are no loops linked + * to one of the sliding vertices. */ + + /* Over allocate, only 'math' layers are indexed. */ + int *customdatalayer_map = MEM_mallocN(sizeof(int) * bm->ldata.totlayer, __func__); + int layer_math_map_len = 0; + for (int i = 0; i < bm->ldata.totlayer; i++) { + if (CustomData_layer_has_math(&bm->ldata, i)) { + customdatalayer_map[layer_math_map_len++] = i; } } - else { - r_tcld_vert->cd_loop_groups = NULL; - } - - r_tcld_vert->v = v; - copy_v3_v3(r_tcld_vert->co_orig_3d, v->co); - BLI_ghash_insert(tcld->origverts, v, r_tcld_vert); + BLI_assert(layer_math_map_len != 0); + + tcld->merge_group.data_len = tc->data_len + tc->data_mirror_len; + tcld->merge_group.customdatalayer_map = customdatalayer_map; + tcld->merge_group.customdatalayer_map_len = layer_math_map_len; + tcld->merge_group.origverts = BLI_ghash_ptr_new_ex(__func__, tcld->merge_group.data_len); + tcld->merge_group.data = BLI_memarena_alloc( + tcld->arena, tcld->merge_group.data_len * sizeof(*tcld->merge_group.data)); } -static void trans_mesh_customdata_correction_init_container(TransDataContainer *tc) +static void mesh_customdatacorrect_init_container(TransDataContainer *tc, + const bool use_merge_group) { if (tc->custom.type.data) { - /* Custom data correction has initiated before. */ - BLI_assert(tc->custom.type.free_cb == trans_mesh_customdata_free_cb); - return; + /* The custom-data correction has been initiated before. + * Free since some modes have different settings. */ + mesh_customdatacorrect_free_cb(NULL, tc, &tc->custom.type); } BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); @@ -1082,135 +1137,81 @@ static void trans_mesh_customdata_correction_init_container(TransDataContainer * if (bm->shapenr > 1) { /* Don't do this at all for non-basis shape keys, too easy to * accidentally break uv maps or vertex colors then */ - /* create copies of faces for customdata projection. */ + /* create copies of faces for custom-data projection. */ return; } - - const bool has_layer_math = CustomData_has_math(&bm->ldata); - const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); - if (!has_layer_math && (cd_loop_mdisp_offset == -1)) { + if (!CustomData_has_math(&bm->ldata) && !CustomData_has_layer(&bm->ldata, CD_MDISPS)) { + /* There is no custom-data to correct. */ return; } - bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES); + struct TransCustomDataLayer *tcld = MEM_callocN(sizeof(*tcld), __func__); + tcld->bm = bm; + tcld->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - struct GHash *origfaces = BLI_ghash_ptr_new(__func__); - struct BMesh *bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default, - &((struct BMeshCreateParams){ - .use_toolflags = false, - })); + /* Init `cd_loop_mdisp_offset` to -1 to avoid problems with a valid index. */ + tcld->cd_loop_mdisp_offset = -1; + tcld->use_merge_group = use_merge_group; - /* we need to have matching customdata */ - BM_mesh_copy_init_customdata(bm_origfaces, bm, NULL); + mesh_customdatacorrect_init_container_generic(tc, tcld); - int *layer_math_map = NULL; - int layer_math_map_len = 0; - { - /* TODO: We don't need `sod->layer_math_map` when there are no loops linked - * to one of the sliding vertices. */ - if (has_layer_math) { - /* over alloc, only 'math' layers are indexed */ - layer_math_map = MEM_mallocN(bm->ldata.totlayer * sizeof(int), __func__); - for (int i = 0; i < bm->ldata.totlayer; i++) { - if (CustomData_layer_has_math(&bm->ldata, i)) { - layer_math_map[layer_math_map_len++] = i; - } - } - BLI_assert(layer_math_map_len != 0); - } + if (tcld->use_merge_group) { + mesh_customdatacorrect_init_container_merge_group(tc, tcld); } - struct TransCustomDataLayer *tcld = MEM_mallocN(sizeof(*tcld), __func__); - int data_len = tc->data_len + tc->data_mirror_len; - - tcld->bm = bm; - tcld->origfaces = origfaces; - tcld->bm_origfaces = bm_origfaces; - tcld->cd_loop_mdisp_offset = cd_loop_mdisp_offset; - tcld->layer_math_map = layer_math_map; - tcld->layer_math_map_num = layer_math_map_len; - tcld->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - tcld->origverts = BLI_ghash_ptr_new_ex(__func__, data_len); - tcld->data = BLI_memarena_alloc(tcld->arena, data_len * sizeof(*tcld->data)); - tcld->data_len = data_len; - { /* Setup Verts. */ - struct TransCustomDataLayerVert *tcld_vert_iter = &tcld->data[0]; + int i = 0; TransData *tob = tc->data; - for (int i = tc->data_len; i--; tob++, tcld_vert_iter++) { + for (int j = tc->data_len; j--; tob++, i++) { BMVert *v = tob->extra; - create_trans_vert_customdata_layer(v, tcld, tcld_vert_iter); + mesh_customdatacorrect_init_vert(tcld, v, i); } TransDataMirror *td_mirror = tc->data_mirror; - for (int i = tc->data_mirror_len; i--; td_mirror++, tcld_vert_iter++) { + for (int j = tc->data_mirror_len; j--; td_mirror++, i++) { BMVert *v = td_mirror->extra; - create_trans_vert_customdata_layer(v, tcld, tcld_vert_iter); + mesh_customdatacorrect_init_vert(tcld, v, i); } } tc->custom.type.data = tcld; - tc->custom.type.free_cb = trans_mesh_customdata_free_cb; + tc->custom.type.free_cb = mesh_customdatacorrect_free_cb; } -void trans_mesh_customdata_correction_init(TransInfo *t) +void mesh_customdatacorrect_init(TransInfo *t) { - if (!ELEM(t->mode, - TFM_TRANSLATION, - TFM_ROTATION, - TFM_RESIZE, - TFM_TOSPHERE, - TFM_SHEAR, - TFM_BEND, - TFM_SHRINKFATTEN, - TFM_TRACKBALL, - TFM_PUSHPULL, - TFM_ALIGN, - TFM_EDGE_SLIDE, - TFM_VERT_SLIDE)) { - /* Currently only modes that change the position of vertices are supported. */ - return; - } - - const char uvcalc_correct_flag = ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE) ? - UVCALC_TRANSFORM_CORRECT_SLIDE : - UVCALC_TRANSFORM_CORRECT; - - if (t->settings->uvcalc_flag & uvcalc_correct_flag) { - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - trans_mesh_customdata_correction_init_container(tc); + bool use_merge_group = false; + if (ELEM(t->mode, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { + if (!(t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT_SLIDE)) { + /* No custom-data correction. */ + return; } + use_merge_group = true; } -} - -static void trans_mesh_customdata_correction_restore(struct TransDataContainer *tc) -{ - struct TransCustomDataLayer *tcld = tc->custom.type.data; - if (!tcld) { - return; + else if (ELEM(t->mode, + TFM_TRANSLATION, + TFM_ROTATION, + TFM_RESIZE, + TFM_TOSPHERE, + TFM_SHEAR, + TFM_BEND, + TFM_SHRINKFATTEN, + TFM_TRACKBALL, + TFM_PUSHPULL, + TFM_ALIGN)) { + { + if (!(t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) { + /* No custom-data correction. */ + return; + } + use_merge_group = (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT_KEEP_CONNECTED) != 0; + } } - BMesh *bm = tcld->bm; - BMesh *bm_copy = tcld->bm_origfaces; - - GHashIterator gh_iter; - GHASH_ITER (gh_iter, tcld->origfaces) { - BMFace *f = BLI_ghashIterator_getKey(&gh_iter); - BMFace *f_copy = BLI_ghashIterator_getValue(&gh_iter); - BLI_assert(f->len == f_copy->len); - - BMLoop *l_iter, *l_first, *l_copy; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - l_copy = BM_FACE_FIRST_LOOP(f_copy); - do { - /* TODO: Restore only the elements that transform. */ - BM_elem_attrs_copy(bm_copy, bm, l_copy, l_iter); - l_copy = l_copy->next; - } while ((l_iter = l_iter->next) != l_first); - - BM_elem_attrs_copy_ex(bm_copy, bm, f_copy, f, BM_ELEM_SELECT, CD_MASK_NORMAL); + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + mesh_customdatacorrect_init_container(tc, use_merge_group); } } @@ -1219,23 +1220,24 @@ static void trans_mesh_customdata_correction_restore(struct TransDataContainer * */ static const float *trans_vert_orig_co_get(struct TransCustomDataLayer *tcld, BMVert *v) { - struct TransCustomDataLayerVert *tcld_vert = BLI_ghash_lookup(tcld->origverts, v); - return tcld_vert ? tcld_vert->co_orig_3d : v->co; + TransDataBasic *td = BLI_ghash_lookup(tcld->merge_group.origverts, v); + return td ? td->iloc : v->co; } -static void trans_mesh_customdata_correction_apply_vert(struct TransCustomDataLayer *tcld, - struct TransCustomDataLayerVert *tcld_vert, - bool do_loop_mdisps) +static void mesh_customdatacorrect_apply_vert(struct TransCustomDataLayer *tcld, + struct TransDataBasic *td, + struct TransCustomDataMergeGroup *merge_data, + bool do_loop_mdisps) { BMesh *bm = tcld->bm; - BMVert *v = tcld_vert->v; - const float *co_orig_3d = tcld_vert->co_orig_3d; + BMVert *v = td->extra; + const float *co_orig_3d = td->iloc; BMIter liter; int j, l_num; float *loop_weights; const bool is_moved = (len_squared_v3v3(v->co, co_orig_3d) > FLT_EPSILON); - const bool do_loop_weight = is_moved && tcld->layer_math_map_num; + const bool do_loop_weight = is_moved && tcld->merge_group.customdatalayer_map_len; const float *v_proj_axis = v->no; /* original (l->prev, l, l->next) projections for each loop ('l' remains unchanged) */ float v_proj[3][3]; @@ -1305,17 +1307,20 @@ static void trans_mesh_customdata_correction_apply_vert(struct TransCustomDataLa } } - struct LinkNode **cd_loop_groups = tcld_vert->cd_loop_groups; - if (tcld->layer_math_map_num && cd_loop_groups) { - if (do_loop_weight) { - for (j = 0; j < tcld->layer_math_map_num; j++) { - BM_vert_loop_groups_data_layer_merge_weights( - bm, cd_loop_groups[j], tcld->layer_math_map[j], loop_weights); + if (tcld->use_merge_group) { + struct LinkNode **cd_loop_groups = merge_data->cd_loop_groups; + if (tcld->merge_group.customdatalayer_map_len && cd_loop_groups) { + if (do_loop_weight) { + for (j = 0; j < tcld->merge_group.customdatalayer_map_len; j++) { + BM_vert_loop_groups_data_layer_merge_weights( + bm, cd_loop_groups[j], tcld->merge_group.customdatalayer_map[j], loop_weights); + } } - } - else { - for (j = 0; j < tcld->layer_math_map_num; j++) { - BM_vert_loop_groups_data_layer_merge(bm, cd_loop_groups[j], tcld->layer_math_map[j]); + else { + for (j = 0; j < tcld->merge_group.customdatalayer_map_len; j++) { + BM_vert_loop_groups_data_layer_merge( + bm, cd_loop_groups[j], tcld->merge_group.customdatalayer_map[j]); + } } } } @@ -1355,19 +1360,63 @@ static void trans_mesh_customdata_correction_apply_vert(struct TransCustomDataLa } } -static void trans_mesh_customdata_correction_apply(struct TransDataContainer *tc, bool is_final) +static void mesh_customdatacorrect_apply(TransInfo *t, bool is_final) { - struct TransCustomDataLayer *tcld = tc->custom.type.data; - if (!tcld) { - return; + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + if (!tc->custom.type.data) { + continue; + } + struct TransCustomDataLayer *tcld = tc->custom.type.data; + const bool use_merge_group = tcld->use_merge_group; + + struct TransCustomDataMergeGroup *merge_data = tcld->merge_group.data; + TransData *tob = tc->data; + for (int i = tc->data_len; i--; tob++) { + mesh_customdatacorrect_apply_vert(tcld, (TransDataBasic *)tob, merge_data, is_final); + + if (use_merge_group) { + merge_data++; + } + } + + TransDataMirror *td_mirror = tc->data_mirror; + for (int i = tc->data_mirror_len; i--; td_mirror++) { + mesh_customdatacorrect_apply_vert(tcld, (TransDataBasic *)td_mirror, merge_data, is_final); + + if (use_merge_group) { + merge_data++; + } + } } +} - const bool do_loop_mdisps = is_final && (tcld->cd_loop_mdisp_offset != -1); - struct TransCustomDataLayerVert *tcld_vert_iter = &tcld->data[0]; +static void mesh_customdatacorrect_restore(struct TransInfo *t) +{ + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + struct TransCustomDataLayer *tcld = tc->custom.type.data; + if (!tcld) { + continue; + } - for (int i = tcld->data_len; i--; tcld_vert_iter++) { - if (tcld_vert_iter->cd_loop_groups || do_loop_mdisps) { - trans_mesh_customdata_correction_apply_vert(tcld, tcld_vert_iter, do_loop_mdisps); + BMesh *bm = tcld->bm; + BMesh *bm_copy = tcld->bm_origfaces; + + GHashIterator gh_iter; + GHASH_ITER (gh_iter, tcld->origfaces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + BMFace *f_copy = BLI_ghashIterator_getValue(&gh_iter); + BLI_assert(f->len == f_copy->len); + + BMLoop *l_iter, *l_first, *l_copy; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + l_copy = BM_FACE_FIRST_LOOP(f_copy); + do { + /* TODO: Restore only the elements that transform. */ + BM_elem_attrs_copy(bm_copy, bm, l_copy, l_iter); + l_copy = l_copy->next; + } while ((l_iter = l_iter->next) != l_first); + + BM_elem_attrs_copy_ex(bm_copy, bm, f_copy, f, BM_ELEM_SELECT, CD_MASK_NORMAL); } } } @@ -1428,16 +1477,14 @@ void recalcData_mesh(TransInfo *t) if ((t->flag & T_NO_MIRROR) == 0 && (t->options & CTX_NO_MIRROR) == 0) { transform_apply_to_mirror(t); } + + mesh_customdatacorrect_apply(t, false); + } + else { + mesh_customdatacorrect_restore(t); } FOREACH_TRANS_DATA_CONTAINER (t, tc) { - if (is_cancelling) { - trans_mesh_customdata_correction_restore(tc); - } - else { - trans_mesh_customdata_correction_apply(tc, false); - } - DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); EDBM_mesh_normals_update(em); @@ -1455,13 +1502,11 @@ void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) const bool is_cancelling = (t->state == TRANS_CANCEL); const bool use_automerge = !is_cancelling && (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0; - if (!is_cancelling && TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.type.data != NULL) { + if (!is_cancelling && ELEM(t->mode, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { /* Handle multires re-projection, done * on transform completion since it's * really slow -joeedh. */ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - trans_mesh_customdata_correction_apply(tc, true); - } + mesh_customdatacorrect_apply(t, true); } if (use_automerge) { -- cgit v1.2.3