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:
authormano-wii <germano.costa@ig.com.br>2019-09-11 19:48:42 +0300
committermano-wii <germano.costa@ig.com.br>2019-09-11 19:49:18 +0300
commit3bd4f229beb1e18802d93c9f5a44b0ec80828a26 (patch)
tree1776fbabac0554092f0f45b2e22de457235b75b1 /source/blender/editors/transform/transform_convert_mesh.c
parent003802db83b561f9ff061811c6cde83356e5b277 (diff)
Transform: Edit Mesh: Support mirror on all axes
Part of T68930 Now two other mirror options that can be enabled simultaneously: Mirror Y and Z. Reviewers: campbellbarton Reviewed By: campbellbarton Subscribers: ThatAsherGuy Differential Revision: https://developer.blender.org/D5720
Diffstat (limited to 'source/blender/editors/transform/transform_convert_mesh.c')
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c720
1 files changed, 624 insertions, 96 deletions
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index 98ae15ed2dc..32239dd0bd7 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -27,8 +27,10 @@
#include "MEM_guardedalloc.h"
+#include "BLI_alloca.h"
#include "BLI_bitmap.h"
#include "BLI_math.h"
+#include "BLI_memarena.h"
#include "BLI_linklist_stack.h"
#include "BKE_context.h"
@@ -52,6 +54,9 @@
#include "transform_convert.h"
#include "bmesh.h"
+/* Used for both mirror epsilon and TD_MIRROR_EDGE_ */
+#define TRANSFORM_MAXDIST_MIRROR 0.00002f
+
/* when transforming islands */
struct TransIslandData {
float co[3];
@@ -395,6 +400,164 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
return trans_islands;
}
+static bool is_in_quadrant_v3(const float co[3], const int quadrant[3], const float epsilon)
+{
+ if (quadrant[0] && ((co[0] * quadrant[0]) < -epsilon)) {
+ return false;
+ }
+ if (quadrant[1] && ((co[1] * quadrant[1]) < -epsilon)) {
+ return false;
+ }
+ if (quadrant[2] && ((co[2] * quadrant[2]) < -epsilon)) {
+ return false;
+ }
+ return true;
+}
+
+static TransDataMirror *editmesh_mirror_data_calc(BMEditMesh *em,
+ bool use_select,
+ const bool use_topology,
+ const bool mirror_axis[3],
+ int *r_mirror_data_len,
+ BLI_bitmap **r_mirror_bitmap)
+{
+ BMesh *bm = em->bm;
+ int *index[3] = {NULL};
+ int i;
+
+ bool test_selected_only = use_select && (mirror_axis[0] + mirror_axis[1] + mirror_axis[2]) == 1;
+ for (i = 0; i < 3; i++) {
+ if (mirror_axis[i]) {
+ index[i] = MEM_mallocN(bm->totvert * sizeof(int), __func__);
+ EDBM_verts_mirror_cache_begin_ex(
+ em, i, false, test_selected_only, use_topology, TRANSFORM_MAXDIST_MIRROR, index[i]);
+ }
+ }
+
+ BMVert *eve;
+ BMIter iter;
+
+ int quadrant[3];
+ {
+ float select_sum[3] = {0};
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ add_v3_v3(select_sum, eve->co);
+ }
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (mirror_axis[i]) {
+ quadrant[i] = select_sum[i] >= 0.0f ? 1 : -1;
+ }
+ else {
+ quadrant[i] = 0;
+ }
+ }
+ }
+
+ /* Tag only elements that will be transformed within the quadrant. */
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+ if ((!use_select || BM_elem_flag_test(eve, BM_ELEM_SELECT)) &&
+ is_in_quadrant_v3(eve->co, quadrant, TRANSFORM_MAXDIST_MIRROR)) {
+ BM_elem_flag_enable(eve, BM_ELEM_TAG);
+ BM_elem_index_set(eve, i);
+ }
+ else {
+ BM_elem_flag_disable(eve, BM_ELEM_TAG);
+ BM_elem_index_set(eve, -1);
+ }
+ }
+
+ for (int a = 0; a < 3; a++) {
+ int *index_iter = index[a];
+ if (index_iter == NULL) {
+ continue;
+ }
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+ if (test_selected_only && !BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ continue;
+ }
+ int elem_index = BM_elem_index_get(eve);
+ if (elem_index != -1) {
+ int i_mirr = index_iter[i];
+ if (i_mirr >= 0) {
+ BMVert *vmir = BM_vert_at_index(bm, i_mirr);
+ BM_elem_index_set(vmir, elem_index);
+
+ /* The slot of this element in the index array no longer needs to be read.
+ * Use to set the mirror sign. */
+ if (index[0] && a > 0) {
+ index[0][i_mirr] = index[0][i];
+ }
+ if (index[1] && a > 1) {
+ index[1][i_mirr] = index[1][i];
+ }
+ /* Use -2 to differ from -1, but both can work. */
+ index_iter[i_mirr] = -2;
+ }
+ }
+ }
+ }
+
+ /* Count mirror elements. */
+ uint mirror_elem_len = 0;
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN | BM_ELEM_TAG)) {
+ /* Not a mirror element. */
+ BM_elem_index_set(eve, -1);
+ continue;
+ }
+ int elem_index = BM_elem_index_get(eve);
+ if (elem_index != -1) {
+ mirror_elem_len++;
+ }
+ }
+
+ TransDataMirror *mirror_data_iter, *mirror_data = NULL;
+ if (mirror_elem_len != 0) {
+ mirror_data = MEM_mallocN(mirror_elem_len * sizeof(*mirror_data), __func__);
+ mirror_data_iter = &mirror_data[0];
+
+ *r_mirror_bitmap = BLI_BITMAP_NEW(bm->totvert, __func__);
+
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ int elem_index = BM_elem_index_get(eve);
+ if (elem_index != -1) {
+ BMVert *v_src = BM_vert_at_index(bm, elem_index);
+
+ mirror_data_iter->loc_src = v_src->co;
+ mirror_data_iter->loc_dst = eve->co;
+ mirror_data_iter->sign_x = index[0] && index[0][i] == -2 ? -1 : 1;
+ mirror_data_iter->sign_y = index[1] && index[1][i] == -2 ? -1 : 1;
+ mirror_data_iter->sign_z = index[2] && index[2][i] == -2 ? -1 : 1;
+ mirror_data_iter->extra = eve;
+
+ mirror_data_iter++;
+
+ BLI_BITMAP_ENABLE(*r_mirror_bitmap, i);
+ }
+ }
+ }
+
+ MEM_SAFE_FREE(index[0]);
+ MEM_SAFE_FREE(index[1]);
+ MEM_SAFE_FREE(index[2]);
+
+ bm->elem_index_dirty |= BM_VERT;
+ *r_mirror_data_len = mirror_elem_len;
+ return mirror_data;
+}
+
/* way to overwrite what data is edited with transform */
static void VertsToTransData(TransInfo *t,
TransData *td,
@@ -448,7 +611,7 @@ static void VertsToTransData(TransInfo *t,
td->ext = NULL;
td->val = NULL;
- td->extra = NULL;
+ td->extra = eve;
if (t->mode == TFM_BWEIGHT) {
td->val = bweight;
td->ival = *bweight;
@@ -487,9 +650,7 @@ void createTransEditVerts(TransInfo *t)
float *dists = NULL;
int a;
const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
- int mirror = 0;
int cd_vert_bweight_offset = -1;
- bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
struct TransIslandData *island_info = NULL;
int island_info_tot;
@@ -510,11 +671,6 @@ void createTransEditVerts(TransInfo *t)
* Optional, allocate if needed. */
int *dists_index = NULL;
- if (tc->mirror.axis_flag) {
- EDBM_verts_mirror_cache_begin(em, 0, false, (t->flag & T_PROP_EDIT) == 0, use_topology);
- mirror = 1;
- }
-
/**
* Quick check if we can transform.
*
@@ -531,16 +687,23 @@ void createTransEditVerts(TransInfo *t)
cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
}
+ BLI_bitmap *mirror_bitmap = NULL;
+ if (tc->mirror.use_mirror_any) {
+ bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+ bool use_select = (t->flag & T_PROP_EDIT) == 0;
+ bool mirror_axis[3] = {tc->mirror.axis_x, tc->mirror.axis_y, tc->mirror.axis_z};
+ tc->mirror.data = editmesh_mirror_data_calc(
+ em, use_select, use_topology, mirror_axis, &tc->mirror.data_len, &mirror_bitmap);
+ }
+
+ int data_len = 0;
if (prop_mode) {
- unsigned int count = 0;
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- count++;
+ data_len++;
}
}
- tc->data_len = count;
-
/* allocating scratch arrays */
if (prop_mode & T_PROP_CONNECTED) {
dists = MEM_mallocN(em->bm->totvert * sizeof(float), __func__);
@@ -550,10 +713,23 @@ void createTransEditVerts(TransInfo *t)
}
}
else {
- tc->data_len = bm->totvertsel;
+ data_len = bm->totvertsel;
+ }
+
+ if (mirror_bitmap) {
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
+ if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ if (BLI_BITMAP_TEST(mirror_bitmap, a)) {
+ data_len--;
+ }
+ }
+ }
}
- tob = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Mesh EditMode)");
+ BLI_assert(data_len != 0);
+
+ tc->data_len = data_len;
+ tc->data = tob = MEM_callocN(data_len * sizeof(TransData), "TransObData(Mesh EditMode)");
if (ELEM(t->mode, TFM_SKIN_RESIZE, TFM_SHRINKFATTEN)) {
/* warning, this is overkill, we only need 2 extra floats,
* but this stores loads of extra stuff, for TFM_SHRINKFATTEN its even more overkill
@@ -622,95 +798,91 @@ void createTransEditVerts(TransInfo *t)
}
}
- /* find out which half we do */
- if (mirror) {
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve->co[0] != 0.0f) {
- if (eve->co[0] < 0.0f) {
- tc->mirror.sign = -1.0f;
- mirror = -1;
- }
- break;
- }
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ continue;
}
- }
+ if (mirror_bitmap && BLI_BITMAP_TEST(mirror_bitmap, a)) {
+ continue;
+ }
+ if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ struct TransIslandData *v_island = NULL;
+ float *bweight = (cd_vert_bweight_offset != -1) ?
+ BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) :
+ NULL;
+
+ if (island_info) {
+ const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
+ v_island = (island_vert_map[connected_index] != -1) ?
+ &island_info[island_vert_map[connected_index]] :
+ NULL;
+ }
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- struct TransIslandData *v_island = NULL;
- float *bweight = (cd_vert_bweight_offset != -1) ?
- BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) :
- NULL;
-
- if (island_info) {
- const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
- v_island = (island_vert_map[connected_index] != -1) ?
- &island_info[island_vert_map[connected_index]] :
- NULL;
- }
+ /* Do not use the island center in case we are using islands
+ * only to get axis for snap/rotate to normal... */
+ VertsToTransData(t, tob, tx, em, eve, bweight, v_island, is_snap_rotate);
+ if (tx) {
+ tx++;
+ }
- /* Do not use the island center in case we are using islands
- * only to get axis for snap/rotate to normal... */
- VertsToTransData(t, tob, tx, em, eve, bweight, v_island, is_snap_rotate);
- if (tx) {
- tx++;
- }
+ /* selected */
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ tob->flag |= TD_SELECTED;
+ }
- /* selected */
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- tob->flag |= TD_SELECTED;
+ if (prop_mode) {
+ if (prop_mode & T_PROP_CONNECTED) {
+ tob->dist = dists[a];
}
-
- if (prop_mode) {
- if (prop_mode & T_PROP_CONNECTED) {
- tob->dist = dists[a];
- }
- else {
- tob->flag |= TD_NOTCONNECTED;
- tob->dist = FLT_MAX;
- }
+ else {
+ tob->flag |= TD_NOTCONNECTED;
+ tob->dist = FLT_MAX;
}
+ }
- /* CrazySpace */
- const bool use_quats = quats && BM_elem_flag_test(eve, BM_ELEM_TAG);
- if (use_quats || defmats) {
- float mat[3][3], qmat[3][3], imat[3][3];
+ /* CrazySpace */
+ const bool use_quats = quats && BM_elem_flag_test(eve, BM_ELEM_TAG);
+ if (use_quats || defmats) {
+ float mat[3][3], qmat[3][3], imat[3][3];
- /* Use both or either quat and defmat correction. */
- if (use_quats) {
- quat_to_mat3(qmat, quats[BM_elem_index_get(eve)]);
+ /* Use both or either quat and defmat correction. */
+ if (use_quats) {
+ quat_to_mat3(qmat, quats[BM_elem_index_get(eve)]);
- if (defmats) {
- mul_m3_series(mat, defmats[a], qmat, mtx);
- }
- else {
- mul_m3_m3m3(mat, mtx, qmat);
- }
+ if (defmats) {
+ mul_m3_series(mat, defmats[a], qmat, mtx);
}
else {
- mul_m3_m3m3(mat, mtx, defmats[a]);
+ mul_m3_m3m3(mat, mtx, qmat);
}
-
- invert_m3_m3(imat, mat);
-
- copy_m3_m3(tob->smtx, imat);
- copy_m3_m3(tob->mtx, mat);
}
else {
- copy_m3_m3(tob->smtx, smtx);
- copy_m3_m3(tob->mtx, mtx);
+ mul_m3_m3m3(mat, mtx, defmats[a]);
}
- /* Mirror? */
- if ((mirror > 0 && tob->iloc[0] > 0.0f) || (mirror < 0 && tob->iloc[0] < 0.0f)) {
- BMVert *vmir = EDBM_verts_mirror_get(em, eve); // t->obedit, em, eve, tob->iloc, a);
- if (vmir && vmir != eve) {
- tob->extra = vmir;
- }
+ invert_m3_m3(imat, mat);
+
+ copy_m3_m3(tob->smtx, imat);
+ copy_m3_m3(tob->mtx, mat);
+ }
+ else {
+ copy_m3_m3(tob->smtx, smtx);
+ copy_m3_m3(tob->mtx, mtx);
+ }
+
+ if (tc->mirror.use_mirror_any) {
+ if (tc->mirror.axis_x && fabsf(tob->loc[0]) < TRANSFORM_MAXDIST_MIRROR) {
+ tob->flag |= TD_MIRROR_EDGE_X;
+ }
+ if (tc->mirror.axis_y && fabsf(tob->loc[1]) < TRANSFORM_MAXDIST_MIRROR) {
+ tob->flag |= TD_MIRROR_EDGE_Y;
+ }
+ if (tc->mirror.axis_z && fabsf(tob->loc[2]) < TRANSFORM_MAXDIST_MIRROR) {
+ tob->flag |= TD_MIRROR_EDGE_Z;
}
- tob++;
}
+
+ tob++;
}
}
@@ -719,15 +891,6 @@ void createTransEditVerts(TransInfo *t)
MEM_freeN(island_vert_map);
}
- if (mirror != 0) {
- tob = tc->data;
- for (a = 0; a < tc->data_len; a++, tob++) {
- if (ABS(tob->loc[0]) <= 0.00001f) {
- tob->flag |= TD_MIRROR_EDGE;
- }
- }
- }
-
cleanup:
/* crazy space free */
if (quats) {
@@ -742,9 +905,374 @@ void createTransEditVerts(TransInfo *t)
if (dists_index) {
MEM_freeN(dists_index);
}
+ if (mirror_bitmap) {
+ MEM_freeN(mirror_bitmap);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name CustomData Layer Correction (for meshes)
+ *
+ * \{ */
+
+struct TransCustomDataLayerVert {
+ BMVert *v;
+ float co_orig_3d[3];
+ struct LinkNode **cd_loop_groups;
+};
+
+struct TransCustomDataLayer {
+ BMesh *bm;
+
+ 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;
+};
+
+static void trans_mesh_customdata_free_cb(struct TransInfo *t,
+ struct TransDataContainer *tc,
+ struct TransCustomData *custom_data)
+{
+ struct TransCustomDataLayer *tcld = custom_data->data;
+ bmesh_edit_end(tcld->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
+
+ if (tcld->bm_origfaces) {
+ BM_mesh_free(tcld->bm_origfaces);
+ }
+ if (tcld->origfaces) {
+ BLI_ghash_free(tcld->origfaces, NULL, NULL);
+ }
+ if (tcld->origverts) {
+ BLI_ghash_free(tcld->origverts, NULL, NULL);
+ }
+ if (tcld->arena) {
+ BLI_memarena_free(tcld->arena);
+ }
+ if (tcld->layer_math_map) {
+ MEM_freeN(tcld->layer_math_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)
+{
+ 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);
+ for (j = 0; j < l_num; j++) {
+ BMLoop *l = BM_iter_step(&liter);
+ BMLoop *l_prev, *l_next;
+ 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);
+ }
+ else {
+ loop_weights[j] = 0.0f;
+ }
+ }
+
+ /* 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);
+ }
+ }
+ 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);
+}
+
+void trans_mesh_customdata_correction_init(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ BLI_assert(tc->custom.type.data == NULL);
+ int i;
+
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BMesh *bm = em->bm;
+
+ bool use_origfaces;
+ int cd_loop_mdisp_offset;
+ {
+ const bool has_layer_math = CustomData_has_math(&bm->ldata);
+ cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
+ if ((t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) &&
+ /* don't do this at all for non-basis shape keys, too easy to
+ * accidentally break uv maps or vertex colors then */
+ (bm->shapenr <= 1) && (has_layer_math || (cd_loop_mdisp_offset != -1))) {
+ use_origfaces = true;
+ cd_loop_mdisp_offset = cd_loop_mdisp_offset;
+ }
+ else {
+ use_origfaces = false;
+ cd_loop_mdisp_offset = -1;
+ }
+ }
+
+ if (use_origfaces) {
+ /* create copies of faces for customdata projection */
+ bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
+
+ struct GHash *origfaces = BLI_ghash_ptr_new(__func__);
+ struct BMesh *bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){
+ .use_toolflags = false,
+ }));
+
+ /* we need to have matching customdata */
+ BM_mesh_copy_init_customdata(bm_origfaces, bm, NULL);
+
+ int *layer_math_map = NULL;
+ int layer_index_dst = 0;
+ {
+ /* TODO: We don't need `sod->layer_math_map` when there are no loops linked
+ * to one of the sliding vertices. */
+ if (CustomData_has_math(&bm->ldata)) {
+ /* over alloc, only 'math' layers are indexed */
+ layer_math_map = MEM_mallocN(bm->ldata.totlayer * sizeof(int), __func__);
+ for (i = 0; i < bm->ldata.totlayer; i++) {
+ if (CustomData_layer_has_math(&bm->ldata, i)) {
+ layer_math_map[layer_index_dst++] = i;
+ }
+ }
+ BLI_assert(layer_index_dst != 0);
+ }
+ }
+
+ struct TransCustomDataLayer *tcld;
+ tc->custom.type.data = tcld = MEM_mallocN(sizeof(*tcld), __func__);
+ tc->custom.type.free_cb = trans_mesh_customdata_free_cb;
+
+ 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_index_dst;
+ tcld->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+
+ int data_len = tc->data_len + tc->mirror.data_len;
+ struct GHash *origverts = BLI_ghash_ptr_new_ex(__func__, data_len);
+ tcld->origverts = origverts;
+
+ struct TransCustomDataLayerVert *tcld_vert, *tcld_vert_iter;
+ tcld_vert = BLI_memarena_alloc(tcld->arena, data_len * sizeof(*tcld_vert));
+ tcld_vert_iter = &tcld_vert[0];
+
+ TransData *tob;
+ for (i = tc->data_len, tob = tc->data; i--; tob++, tcld_vert_iter++) {
+ BMVert *v = tob->extra;
+ create_trans_vert_customdata_layer(v, tcld, tcld_vert_iter);
+ }
+
+ TransDataMirror *tdm;
+ for (i = tc->mirror.data_len, tdm = tc->mirror.data; i--; tdm++, tcld_vert_iter++) {
+ BMVert *v = tdm->extra;
+ create_trans_vert_customdata_layer(v, tcld, tcld_vert_iter);
+ }
+
+ tcld->data = tcld_vert;
+ tcld->data_len = data_len;
+ }
+ }
+}
+
+/**
+ * If we're sliding the vert, return its original location, if not, the current location is good.
+ */
+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;
+}
+
+static void trans_mesh_customdata_correction_apply_vert(struct TransCustomDataLayer *tcld,
+ struct TransCustomDataLayerVert *tcld_vert,
+ bool is_final)
+{
+ BMesh *bm = tcld->bm;
+ BMVert *v = tcld_vert->v;
+ const float *co_orig_3d = tcld_vert->co_orig_3d;
+ struct LinkNode **cd_loop_groups = tcld_vert->cd_loop_groups;
+
+ 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 = tcld->layer_math_map_num && is_moved;
+ const bool do_loop_mdisps = is_final && is_moved && (tcld->cd_loop_mdisp_offset != -1);
+ 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];
+
+ if (do_loop_weight || do_loop_mdisps) {
+ project_plane_normalized_v3_v3v3(v_proj[1], co_orig_3d, v_proj_axis);
+ }
+
+ // 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 = do_loop_weight ? BLI_array_alloca(loop_weights, l_num) : NULL;
+ for (j = 0; j < l_num; j++) {
+ BMFace *f_copy; /* the copy of 'f' */
+ BMLoop *l = BM_iter_step(&liter);
+
+ f_copy = BLI_ghash_lookup(tcld->origfaces, l->f);
+
+ /* only loop data, no vertex data since that contains shape keys,
+ * and we do not want to mess up other shape keys */
+ BM_loop_interp_from_face(bm, l, f_copy, false, false);
+
+ /* make sure face-attributes are correct (e.g. #MLoopUV, #MLoopCol) */
+ BM_elem_attrs_copy_ex(tcld->bm_origfaces, bm, f_copy, l->f, 0x0, CD_MASK_NORMAL);
+
+ /* weight the loop */
+ if (do_loop_weight) {
+ const float eps = 1.0e-8f;
+ const BMLoop *l_prev = l->prev;
+ const BMLoop *l_next = l->next;
+ const float *co_prev = trans_vert_orig_co_get(tcld, l_prev->v);
+ const float *co_next = trans_vert_orig_co_get(tcld, l_next->v);
+ bool co_prev_ok;
+ bool co_next_ok;
+
+ /* In the unlikely case that we're next to a zero length edge -
+ * walk around the to the next.
+ *
+ * Since we only need to check if the vertex is in this corner,
+ * its not important _which_ loop - as long as its not overlapping
+ * 'sv->co_orig_3d', see: T45096. */
+ project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
+ while (UNLIKELY(((co_prev_ok = (len_squared_v3v3(v_proj[1], v_proj[0]) > eps)) == false) &&
+ ((l_prev = l_prev->prev) != l->next))) {
+ co_prev = trans_vert_orig_co_get(tcld, l_prev->v);
+ project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
+ }
+ project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis);
+ while (UNLIKELY(((co_next_ok = (len_squared_v3v3(v_proj[1], v_proj[2]) > eps)) == false) &&
+ ((l_next = l_next->next) != l->prev))) {
+ co_next = trans_vert_orig_co_get(tcld, l_next->v);
+ project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis);
+ }
+
+ if (co_prev_ok && co_next_ok) {
+ const float dist = dist_signed_squared_to_corner_v3v3v3(
+ v->co, UNPACK3(v_proj), v_proj_axis);
+
+ loop_weights[j] = (dist >= 0.0f) ? 1.0f : ((dist <= -eps) ? 0.0f : (1.0f + (dist / eps)));
+ if (UNLIKELY(!isfinite(loop_weights[j]))) {
+ loop_weights[j] = 0.0f;
+ }
+ }
+ else {
+ loop_weights[j] = 0.0f;
+ }
+ }
+ }
+
+ 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);
+ }
+ }
+ 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]);
+ }
+ }
+ }
+
+ /* Special handling for multires
+ *
+ * Interpolate from every other loop (not ideal)
+ * However values will only be taken from loops which overlap other mdisps.
+ * */
+ if (do_loop_mdisps) {
+ float(*faces_center)[3] = BLI_array_alloca(faces_center, l_num);
+ BMLoop *l;
+
+ BM_ITER_ELEM_INDEX (l, &liter, v, BM_LOOPS_OF_VERT, j) {
+ BM_face_calc_center_median(l->f, faces_center[j]);
+ }
+
+ BM_ITER_ELEM_INDEX (l, &liter, v, BM_LOOPS_OF_VERT, j) {
+ BMFace *f_copy = BLI_ghash_lookup(tcld->origfaces, l->f);
+ float f_copy_center[3];
+ BMIter liter_other;
+ BMLoop *l_other;
+ int j_other;
+
+ BM_face_calc_center_median(f_copy, f_copy_center);
+
+ BM_ITER_ELEM_INDEX (l_other, &liter_other, v, BM_LOOPS_OF_VERT, j_other) {
+ BM_face_interp_multires_ex(bm,
+ l_other->f,
+ f_copy,
+ faces_center[j_other],
+ f_copy_center,
+ tcld->cd_loop_mdisp_offset);
+ }
+ }
+ }
+}
+
+void trans_mesh_customdata_correction_apply(struct TransDataContainer *tc, bool is_final)
+{
+ struct TransCustomDataLayer *tcld = tc->custom.type.data;
+ if (!tcld) {
+ return;
+ }
+
+ const bool has_mdisps = (tcld->cd_loop_mdisp_offset != -1);
+ struct TransCustomDataLayerVert *tcld_vert_iter = &tcld->data[0];
- if (tc->mirror.axis_flag) {
- EDBM_verts_mirror_cache_end(em);
+ for (int i = tcld->data_len; i--; tcld_vert_iter++) {
+ if (tcld_vert_iter->cd_loop_groups || has_mdisps) {
+ trans_mesh_customdata_correction_apply_vert(tcld, tcld_vert_iter, is_final);
}
}
}