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
This commit is contained in:
parent
003802db83
commit
3bd4f229be
Notes:
blender-bot
2023-02-14 06:32:27 +01:00
Referenced by issue #70873, Pivot Center doesn't compute mirror elements Referenced by issue #69785, Crash - select + drag on empty space Referenced by issue #66683, Edge slide with X-mirror and Topology mirror crashes
|
@ -177,11 +177,21 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
|
|||
ob = context.active_object
|
||||
mesh = ob.data
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(mesh, "use_mirror_x")
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.alignment = 'RIGHT'
|
||||
col.label(text="Mirror")
|
||||
|
||||
col = split.column()
|
||||
|
||||
row = col.row(align=True)
|
||||
row.active = ob.data.use_mirror_x
|
||||
row.prop(mesh, "use_mirror_x", text="X", toggle=True)
|
||||
row.prop(mesh, "use_mirror_y", text="Y", toggle=True)
|
||||
row.prop(mesh, "use_mirror_z", text="Z", toggle=True)
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.active = ob.data.use_mirror_x or ob.data.use_mirror_y or ob.data.use_mirror_z
|
||||
row.prop(mesh, "use_mirror_topology")
|
||||
|
||||
|
||||
|
|
|
@ -6389,367 +6389,6 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
|
|||
}
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Original Data Store */
|
||||
|
||||
/** \name Orig-Data Store Utility Functions
|
||||
* \{ */
|
||||
|
||||
static void slide_origdata_init_flag(TransInfo *t, TransDataContainer *tc, SlideOrigData *sod)
|
||||
{
|
||||
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
|
||||
BMesh *bm = em->bm;
|
||||
const bool has_layer_math = CustomData_has_math(&bm->ldata);
|
||||
const int 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))) {
|
||||
sod->use_origfaces = true;
|
||||
sod->cd_loop_mdisp_offset = cd_loop_mdisp_offset;
|
||||
}
|
||||
else {
|
||||
sod->use_origfaces = false;
|
||||
sod->cd_loop_mdisp_offset = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void slide_origdata_init_data(TransDataContainer *tc, SlideOrigData *sod)
|
||||
{
|
||||
if (sod->use_origfaces) {
|
||||
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
|
||||
BMesh *bm = em->bm;
|
||||
|
||||
sod->origfaces = BLI_ghash_ptr_new(__func__);
|
||||
sod->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(sod->bm_origfaces, bm, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void slide_origdata_create_data_vert(BMesh *bm,
|
||||
SlideOrigData *sod,
|
||||
TransDataGenericSlideVert *sv)
|
||||
{
|
||||
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, sv->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(sod->origfaces, l->f, &val_p)) {
|
||||
BMFace *f_copy = BM_face_copy(sod->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 (sod->layer_math_map_num && (l_num != 0)) {
|
||||
sv->cd_loop_groups = BLI_memarena_alloc(sod->arena, sod->layer_math_map_num * sizeof(void *));
|
||||
for (j = 0; j < sod->layer_math_map_num; j++) {
|
||||
const int layer_nr = sod->layer_math_map[j];
|
||||
sv->cd_loop_groups[j] = BM_vert_loop_groups_data_layer_create(
|
||||
bm, sv->v, layer_nr, loop_weights, sod->arena);
|
||||
}
|
||||
}
|
||||
else {
|
||||
sv->cd_loop_groups = NULL;
|
||||
}
|
||||
|
||||
BLI_ghash_insert(sod->origverts, sv->v, sv);
|
||||
}
|
||||
|
||||
static void slide_origdata_create_data(TransDataContainer *tc,
|
||||
SlideOrigData *sod,
|
||||
TransDataGenericSlideVert *sv_array,
|
||||
unsigned int v_stride,
|
||||
unsigned int v_num)
|
||||
{
|
||||
if (sod->use_origfaces) {
|
||||
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
|
||||
BMesh *bm = em->bm;
|
||||
unsigned int i;
|
||||
TransDataGenericSlideVert *sv;
|
||||
|
||||
int layer_index_dst;
|
||||
int j;
|
||||
|
||||
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 */
|
||||
sod->layer_math_map = MEM_mallocN(bm->ldata.totlayer * sizeof(int), __func__);
|
||||
for (j = 0; j < bm->ldata.totlayer; j++) {
|
||||
if (CustomData_layer_has_math(&bm->ldata, j)) {
|
||||
sod->layer_math_map[layer_index_dst++] = j;
|
||||
}
|
||||
}
|
||||
BLI_assert(layer_index_dst != 0);
|
||||
}
|
||||
|
||||
sod->layer_math_map_num = layer_index_dst;
|
||||
|
||||
sod->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
|
||||
|
||||
sod->origverts = BLI_ghash_ptr_new_ex(__func__, v_num);
|
||||
|
||||
for (i = 0, sv = sv_array; i < v_num; i++, sv = POINTER_OFFSET(sv, v_stride)) {
|
||||
slide_origdata_create_data_vert(bm, sod, sv);
|
||||
}
|
||||
|
||||
if (tc->mirror.axis_flag) {
|
||||
TransData *td = tc->data;
|
||||
TransDataGenericSlideVert *sv_mirror;
|
||||
|
||||
sod->sv_mirror = MEM_callocN(sizeof(*sv_mirror) * tc->data_len, __func__);
|
||||
sod->totsv_mirror = tc->data_len;
|
||||
|
||||
sv_mirror = sod->sv_mirror;
|
||||
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
BMVert *eve = td->extra;
|
||||
/* Check the vertex has been used since both sides
|
||||
* of the mirror may be selected & sliding. */
|
||||
if (eve && !BLI_ghash_haskey(sod->origverts, eve)) {
|
||||
sv_mirror->v = eve;
|
||||
copy_v3_v3(sv_mirror->co_orig_3d, eve->co);
|
||||
|
||||
slide_origdata_create_data_vert(bm, sod, sv_mirror);
|
||||
sv_mirror++;
|
||||
}
|
||||
else {
|
||||
sod->totsv_mirror--;
|
||||
}
|
||||
}
|
||||
|
||||
if (sod->totsv_mirror == 0) {
|
||||
MEM_freeN(sod->sv_mirror);
|
||||
sod->sv_mirror = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If we're sliding the vert, return its original location, if not, the current location is good.
|
||||
*/
|
||||
static const float *slide_origdata_orig_vert_co(SlideOrigData *sod, BMVert *v)
|
||||
{
|
||||
TransDataGenericSlideVert *sv = BLI_ghash_lookup(sod->origverts, v);
|
||||
return sv ? sv->co_orig_3d : v->co;
|
||||
}
|
||||
|
||||
static void slide_origdata_interp_data_vert(SlideOrigData *sod,
|
||||
BMesh *bm,
|
||||
bool is_final,
|
||||
TransDataGenericSlideVert *sv)
|
||||
{
|
||||
BMIter liter;
|
||||
int j, l_num;
|
||||
float *loop_weights;
|
||||
const bool is_moved = (len_squared_v3v3(sv->v->co, sv->co_orig_3d) > FLT_EPSILON);
|
||||
const bool do_loop_weight = sod->layer_math_map_num && is_moved;
|
||||
const bool do_loop_mdisps = is_final && is_moved && (sod->cd_loop_mdisp_offset != -1);
|
||||
const float *v_proj_axis = sv->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], sv->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, sv->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(sod->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(sod->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 = slide_origdata_orig_vert_co(sod, l_prev->v);
|
||||
const float *co_next = slide_origdata_orig_vert_co(sod, 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 = slide_origdata_orig_vert_co(sod, 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 = slide_origdata_orig_vert_co(sod, 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(
|
||||
sv->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 (sod->layer_math_map_num && sv->cd_loop_groups) {
|
||||
if (do_loop_weight) {
|
||||
for (j = 0; j < sod->layer_math_map_num; j++) {
|
||||
BM_vert_loop_groups_data_layer_merge_weights(
|
||||
bm, sv->cd_loop_groups[j], sod->layer_math_map[j], loop_weights);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (j = 0; j < sod->layer_math_map_num; j++) {
|
||||
BM_vert_loop_groups_data_layer_merge(bm, sv->cd_loop_groups[j], sod->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, sv->v, BM_LOOPS_OF_VERT, j) {
|
||||
BM_face_calc_center_median(l->f, faces_center[j]);
|
||||
}
|
||||
|
||||
BM_ITER_ELEM_INDEX (l, &liter, sv->v, BM_LOOPS_OF_VERT, j) {
|
||||
BMFace *f_copy = BLI_ghash_lookup(sod->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, sv->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,
|
||||
sod->cd_loop_mdisp_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void slide_origdata_interp_data(Object *obedit,
|
||||
SlideOrigData *sod,
|
||||
TransDataGenericSlideVert *sv,
|
||||
unsigned int v_stride,
|
||||
unsigned int v_num,
|
||||
bool is_final)
|
||||
{
|
||||
if (sod->use_origfaces) {
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
BMesh *bm = em->bm;
|
||||
unsigned int i;
|
||||
const bool has_mdisps = (sod->cd_loop_mdisp_offset != -1);
|
||||
|
||||
for (i = 0; i < v_num; i++, sv = POINTER_OFFSET(sv, v_stride)) {
|
||||
|
||||
if (sv->cd_loop_groups || has_mdisps) {
|
||||
slide_origdata_interp_data_vert(sod, bm, is_final, sv);
|
||||
}
|
||||
}
|
||||
|
||||
if (sod->sv_mirror) {
|
||||
sv = sod->sv_mirror;
|
||||
for (i = 0; i < v_num; i++, sv++) {
|
||||
if (sv->cd_loop_groups || has_mdisps) {
|
||||
slide_origdata_interp_data_vert(sod, bm, is_final, sv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void slide_origdata_free_date(SlideOrigData *sod)
|
||||
{
|
||||
if (sod->use_origfaces) {
|
||||
if (sod->bm_origfaces) {
|
||||
BM_mesh_free(sod->bm_origfaces);
|
||||
sod->bm_origfaces = NULL;
|
||||
}
|
||||
|
||||
if (sod->origfaces) {
|
||||
BLI_ghash_free(sod->origfaces, NULL, NULL);
|
||||
sod->origfaces = NULL;
|
||||
}
|
||||
|
||||
if (sod->origverts) {
|
||||
BLI_ghash_free(sod->origverts, NULL, NULL);
|
||||
sod->origverts = NULL;
|
||||
}
|
||||
|
||||
if (sod->arena) {
|
||||
BLI_memarena_free(sod->arena);
|
||||
sod->arena = NULL;
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(sod->layer_math_map);
|
||||
|
||||
MEM_SAFE_FREE(sod->sv_mirror);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Transform (Edge Slide) */
|
||||
|
||||
|
@ -7201,8 +6840,6 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, TransDataContainer *t
|
|||
View3D *v3d = NULL;
|
||||
RegionView3D *rv3d = NULL;
|
||||
|
||||
slide_origdata_init_flag(t, tc, &sld->orig_data);
|
||||
|
||||
sld->curr_sv_index = 0;
|
||||
|
||||
/*ensure valid selection*/
|
||||
|
@ -7533,18 +7170,10 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, TransDataContainer *t
|
|||
|
||||
calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, true);
|
||||
|
||||
/* create copies of faces for customdata projection */
|
||||
bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
|
||||
slide_origdata_init_data(tc, &sld->orig_data);
|
||||
slide_origdata_create_data(
|
||||
tc, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
|
||||
|
||||
if (rv3d) {
|
||||
calcEdgeSlide_even(t, tc, sld, mval);
|
||||
}
|
||||
|
||||
sld->em = em;
|
||||
|
||||
tc->custom.mode.data = sld;
|
||||
|
||||
MEM_freeN(sv_table);
|
||||
|
@ -7578,8 +7207,6 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *t
|
|||
rv3d = t->ar ? t->ar->regiondata : NULL;
|
||||
}
|
||||
|
||||
slide_origdata_init_flag(t, tc, &sld->orig_data);
|
||||
|
||||
sld->curr_sv_index = 0;
|
||||
/* ensure valid selection */
|
||||
{
|
||||
|
@ -7728,18 +7355,10 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *t
|
|||
|
||||
calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, false);
|
||||
|
||||
/* create copies of faces for customdata projection */
|
||||
bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
|
||||
slide_origdata_init_data(tc, &sld->orig_data);
|
||||
slide_origdata_create_data(
|
||||
tc, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
|
||||
|
||||
if (rv3d) {
|
||||
calcEdgeSlide_even(t, tc, sld, mval);
|
||||
}
|
||||
|
||||
sld->em = em;
|
||||
|
||||
tc->custom.mode.data = sld;
|
||||
|
||||
MEM_freeN(sv_table);
|
||||
|
@ -7756,25 +7375,10 @@ void projectEdgeSlideData(TransInfo *t, bool is_final)
|
|||
continue;
|
||||
}
|
||||
|
||||
SlideOrigData *sod = &sld->orig_data;
|
||||
if (sod->use_origfaces == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
slide_origdata_interp_data(tc->obedit,
|
||||
sod,
|
||||
(TransDataGenericSlideVert *)sld->sv,
|
||||
sizeof(*sld->sv),
|
||||
sld->totsv,
|
||||
is_final);
|
||||
trans_mesh_customdata_correction_apply(tc, is_final);
|
||||
}
|
||||
}
|
||||
|
||||
void freeEdgeSlideTempFaces(EdgeSlideData *sld)
|
||||
{
|
||||
slide_origdata_free_date(&sld->orig_data);
|
||||
}
|
||||
|
||||
void freeEdgeSlideVerts(TransInfo *UNUSED(t),
|
||||
TransDataContainer *UNUSED(tc),
|
||||
TransCustomData *custom_data)
|
||||
|
@ -7785,10 +7389,6 @@ void freeEdgeSlideVerts(TransInfo *UNUSED(t),
|
|||
return;
|
||||
}
|
||||
|
||||
freeEdgeSlideTempFaces(sld);
|
||||
|
||||
bmesh_edit_end(sld->em->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
|
||||
|
||||
MEM_freeN(sld->sv);
|
||||
MEM_freeN(sld);
|
||||
|
||||
|
@ -7847,6 +7447,8 @@ static void initEdgeSlide_ex(
|
|||
tc->custom.mode.free_cb = freeEdgeSlideVerts;
|
||||
}
|
||||
|
||||
trans_mesh_customdata_correction_init(t);
|
||||
|
||||
/* set custom point first if you want value to be initialized by init */
|
||||
calcEdgeSlideCustomPoints(t);
|
||||
initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO_FLIP);
|
||||
|
@ -8322,8 +7924,6 @@ static bool createVertSlideVerts(TransInfo *t, TransDataContainer *tc)
|
|||
VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
|
||||
int j;
|
||||
|
||||
slide_origdata_init_flag(t, tc, &sld->orig_data);
|
||||
|
||||
sld->curr_sv_index = 0;
|
||||
|
||||
j = 0;
|
||||
|
@ -8387,13 +7987,6 @@ static bool createVertSlideVerts(TransInfo *t, TransDataContainer *tc)
|
|||
sld->sv = sv_array;
|
||||
sld->totsv = j;
|
||||
|
||||
bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
|
||||
slide_origdata_init_data(tc, &sld->orig_data);
|
||||
slide_origdata_create_data(
|
||||
tc, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
|
||||
|
||||
sld->em = em;
|
||||
|
||||
tc->custom.mode.data = sld;
|
||||
|
||||
/* most likely will be set below */
|
||||
|
@ -8423,23 +8016,10 @@ void projectVertSlideData(TransInfo *t, bool is_final)
|
|||
{
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
VertSlideData *sld = tc->custom.mode.data;
|
||||
SlideOrigData *sod = &sld->orig_data;
|
||||
if (sod->use_origfaces == true) {
|
||||
slide_origdata_interp_data(tc->obedit,
|
||||
sod,
|
||||
(TransDataGenericSlideVert *)sld->sv,
|
||||
sizeof(*sld->sv),
|
||||
sld->totsv,
|
||||
is_final);
|
||||
}
|
||||
trans_mesh_customdata_correction_apply(tc, is_final);
|
||||
}
|
||||
}
|
||||
|
||||
void freeVertSlideTempFaces(VertSlideData *sld)
|
||||
{
|
||||
slide_origdata_free_date(&sld->orig_data);
|
||||
}
|
||||
|
||||
void freeVertSlideVerts(TransInfo *UNUSED(t),
|
||||
TransDataContainer *UNUSED(tc),
|
||||
TransCustomData *custom_data)
|
||||
|
@ -8450,10 +8030,6 @@ void freeVertSlideVerts(TransInfo *UNUSED(t),
|
|||
return;
|
||||
}
|
||||
|
||||
freeVertSlideTempFaces(sld);
|
||||
|
||||
bmesh_edit_end(sld->em->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
|
||||
|
||||
if (sld->totsv > 0) {
|
||||
TransDataVertSlideVert *sv = sld->sv;
|
||||
int i = 0;
|
||||
|
@ -8503,6 +8079,8 @@ static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use
|
|||
return;
|
||||
}
|
||||
|
||||
trans_mesh_customdata_correction_init(t);
|
||||
|
||||
/* set custom point first if you want value to be initialized by init */
|
||||
calcVertSlideCustomPoints(t);
|
||||
initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO);
|
||||
|
|
|
@ -294,38 +294,11 @@ typedef struct TransDataEdgeSlideVert {
|
|||
int loop_nr;
|
||||
} TransDataEdgeSlideVert;
|
||||
|
||||
/* store original data so we can correct UV's and similar when sliding */
|
||||
typedef struct SlideOrigData {
|
||||
/** Set when #origfaces is initialized. */
|
||||
bool use_origfaces;
|
||||
int cd_loop_mdisp_offset;
|
||||
|
||||
/** map {BMVert: TransDataGenericSlideVert} */
|
||||
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 TransDataVertSlideVert.cd_group index to absolute CustomData layer index */
|
||||
int *layer_math_map;
|
||||
|
||||
/** Array of slide vert data especially for mirror verts. */
|
||||
TransDataGenericSlideVert *sv_mirror;
|
||||
int totsv_mirror;
|
||||
} SlideOrigData;
|
||||
|
||||
typedef struct EdgeSlideData {
|
||||
TransDataEdgeSlideVert *sv;
|
||||
int totsv;
|
||||
|
||||
int mval_start[2], mval_end[2];
|
||||
struct BMEditMesh *em;
|
||||
|
||||
SlideOrigData orig_data;
|
||||
|
||||
int curr_sv_index;
|
||||
|
||||
/** when un-clamped - use this index: #TransDataEdgeSlideVert.dir_side */
|
||||
|
@ -354,11 +327,6 @@ typedef struct TransDataVertSlideVert {
|
|||
typedef struct VertSlideData {
|
||||
TransDataVertSlideVert *sv;
|
||||
int totsv;
|
||||
|
||||
struct BMEditMesh *em;
|
||||
|
||||
SlideOrigData orig_data;
|
||||
|
||||
int curr_sv_index;
|
||||
|
||||
/* result of ED_view3d_ob_project_mat_get */
|
||||
|
@ -449,6 +417,18 @@ typedef struct TransData {
|
|||
short protectflag;
|
||||
} TransData;
|
||||
|
||||
typedef struct TransDataMirror {
|
||||
/** location of mirrored reference data. */
|
||||
const float *loc_src;
|
||||
/** Location of the data to transform. */
|
||||
float *loc_dst;
|
||||
void *extra;
|
||||
/* `sign` can be -2, -1, 0 or 1. */
|
||||
int sign_x : 2;
|
||||
int sign_y : 2;
|
||||
int sign_z : 2;
|
||||
} TransDataMirror;
|
||||
|
||||
typedef struct MouseInput {
|
||||
void (*apply)(struct TransInfo *t, struct MouseInput *mi, const double mval[2], float output[3]);
|
||||
void (*post)(struct TransInfo *t, float values[3]);
|
||||
|
@ -549,10 +529,18 @@ typedef struct TransDataContainer {
|
|||
* Mirror option
|
||||
*/
|
||||
struct {
|
||||
/* Currently for mesh X mirror only. */
|
||||
int axis_flag;
|
||||
/** Set to -1.0f or 1.0 when use_mirror is set. */
|
||||
float sign;
|
||||
union {
|
||||
struct {
|
||||
uint axis_x : 1;
|
||||
uint axis_y : 1;
|
||||
uint axis_z : 1;
|
||||
};
|
||||
/* For easy checking. */
|
||||
char use_mirror_any;
|
||||
};
|
||||
/** Mirror data array. */
|
||||
TransDataMirror *data;
|
||||
int data_len;
|
||||
} mirror;
|
||||
|
||||
TransCustomDataContainer custom;
|
||||
|
@ -860,16 +848,18 @@ enum {
|
|||
/** For Graph Editor - curves that can only have int-values
|
||||
* need their keyframes tagged with this. */
|
||||
TD_INTVALUES = 1 << 15,
|
||||
/** For editmode mirror, clamp to x = 0 */
|
||||
TD_MIRROR_EDGE = 1 << 16,
|
||||
/** For editmode mirror, clamp axis to 0 */
|
||||
TD_MIRROR_EDGE_X = 1 << 16,
|
||||
TD_MIRROR_EDGE_Y = 1 << 17,
|
||||
TD_MIRROR_EDGE_Z = 1 << 18,
|
||||
/** For fcurve handles, move them along with their keyframes */
|
||||
TD_MOVEHANDLE1 = 1 << 17,
|
||||
TD_MOVEHANDLE2 = 1 << 18,
|
||||
TD_MOVEHANDLE1 = 1 << 19,
|
||||
TD_MOVEHANDLE2 = 1 << 20,
|
||||
/** Exceptional case with pose bone rotating when a parent bone has 'Local Location'
|
||||
* option enabled and rotating also transforms it. */
|
||||
TD_PBONE_LOCAL_MTX_P = 1 << 19,
|
||||
TD_PBONE_LOCAL_MTX_P = 1 << 21,
|
||||
/** Same as above but for a child bone. */
|
||||
TD_PBONE_LOCAL_MTX_C = 1 << 20,
|
||||
TD_PBONE_LOCAL_MTX_C = 1 << 22,
|
||||
};
|
||||
|
||||
/** #TransSnap.status */
|
||||
|
@ -1091,11 +1081,9 @@ int getTransformOrientation(const struct bContext *C, float normal[3], float pla
|
|||
|
||||
void freeCustomNormalArray(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
|
||||
|
||||
void freeEdgeSlideTempFaces(EdgeSlideData *sld);
|
||||
void freeEdgeSlideVerts(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
|
||||
void projectEdgeSlideData(TransInfo *t, bool is_final);
|
||||
|
||||
void freeVertSlideTempFaces(VertSlideData *sld);
|
||||
void freeVertSlideVerts(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
|
||||
void projectVertSlideData(TransInfo *t, bool is_final);
|
||||
|
||||
|
|
|
@ -1778,18 +1778,16 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
|
|||
char hflag;
|
||||
bool has_face_sel = (bm->totfacesel != 0);
|
||||
|
||||
if (tc->mirror.axis_flag) {
|
||||
TransData *td;
|
||||
if (tc->mirror.use_mirror_any) {
|
||||
TransDataMirror *tdm;
|
||||
int i;
|
||||
|
||||
/* Rather then adjusting the selection (which the user would notice)
|
||||
* tag all mirrored verts, then auto-merge those. */
|
||||
BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false);
|
||||
|
||||
for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
|
||||
if (td->extra) {
|
||||
BM_elem_flag_enable((BMVert *)td->extra, BM_ELEM_TAG);
|
||||
}
|
||||
for (i = tc->mirror.data_len, tdm = tc->mirror.data; i--; tdm++) {
|
||||
BM_elem_flag_enable((BMVert *)tdm->extra, BM_ELEM_TAG);
|
||||
}
|
||||
|
||||
hflag = BM_ELEM_SELECT | BM_ELEM_TAG;
|
||||
|
@ -1850,26 +1848,10 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
|
|||
* on transform completion since it's
|
||||
* really slow -joeedh */
|
||||
projectEdgeSlideData(t, true);
|
||||
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
EdgeSlideData *sld = tc->custom.mode.data;
|
||||
|
||||
if (sld == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Free temporary faces to avoid auto-merging and deleting
|
||||
* during cleanup - psy-fi. */
|
||||
freeEdgeSlideTempFaces(sld);
|
||||
}
|
||||
}
|
||||
else if (t->mode == TFM_VERT_SLIDE) {
|
||||
/* as above */
|
||||
projectVertSlideData(t, true);
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
VertSlideData *sld = tc->custom.mode.data;
|
||||
freeVertSlideTempFaces(sld);
|
||||
}
|
||||
}
|
||||
|
||||
if (t->obedit_type == OB_MESH) {
|
||||
|
|
|
@ -69,6 +69,8 @@ void flushTransGraphData(TransInfo *t);
|
|||
void flushTransMasking(TransInfo *t);
|
||||
/* transform_convert_mesh.c */
|
||||
void flushTransUVs(TransInfo *t);
|
||||
void trans_mesh_customdata_correction_init(TransInfo *t);
|
||||
void trans_mesh_customdata_correction_apply(struct TransDataContainer *tc, bool is_final);
|
||||
/* transform_convert_node.c */
|
||||
void flushTransNodes(TransInfo *t);
|
||||
/* transform_convert_object.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;
|
||||
}
|
||||
|
||||
tob = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Mesh EditMode)");
|
||||
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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
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 (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;
|
||||
}
|
||||
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];
|
||||
}
|
||||
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];
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mul_m3_m3m3(mat, mtx, defmats[a]);
|
||||
}
|
||||
|
||||
invert_m3_m3(imat, mat);
|
||||
|
||||
copy_m3_m3(tob->smtx, imat);
|
||||
copy_m3_m3(tob->mtx, mat);
|
||||
if (prop_mode) {
|
||||
if (prop_mode & T_PROP_CONNECTED) {
|
||||
tob->dist = dists[a];
|
||||
}
|
||||
else {
|
||||
copy_m3_m3(tob->smtx, smtx);
|
||||
copy_m3_m3(tob->mtx, mtx);
|
||||
tob->flag |= TD_NOTCONNECTED;
|
||||
tob->dist = FLT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
/* 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)]);
|
||||
|
||||
if (defmats) {
|
||||
mul_m3_series(mat, defmats[a], qmat, mtx);
|
||||
}
|
||||
else {
|
||||
mul_m3_m3m3(mat, mtx, qmat);
|
||||
}
|
||||
}
|
||||
tob++;
|
||||
else {
|
||||
mul_m3_m3m3(mat, mtx, defmats[a]);
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tc->mirror.axis_flag) {
|
||||
EDBM_verts_mirror_cache_end(em);
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \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];
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -224,35 +224,31 @@ static void clipMirrorModifier(TransInfo *t)
|
|||
}
|
||||
|
||||
/* assumes obedit set to mesh object */
|
||||
static void editbmesh_apply_to_mirror(TransInfo *t)
|
||||
static void transform_apply_to_mirror(TransInfo *t)
|
||||
{
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
if (tc->mirror.axis_flag) {
|
||||
TransData *td = tc->data;
|
||||
BMVert *eve;
|
||||
if (tc->mirror.use_mirror_any) {
|
||||
int i;
|
||||
TransData *td;
|
||||
for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & (TD_MIRROR_EDGE_X | TD_MIRROR_EDGE_Y | TD_MIRROR_EDGE_Z)) {
|
||||
if (td->flag & TD_MIRROR_EDGE_X) {
|
||||
td->loc[0] = 0.0f;
|
||||
}
|
||||
if (td->flag & TD_MIRROR_EDGE_Y) {
|
||||
td->loc[1] = 0.0f;
|
||||
}
|
||||
if (td->flag & TD_MIRROR_EDGE_Z) {
|
||||
td->loc[2] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_NOACTION) {
|
||||
break;
|
||||
}
|
||||
if (td->loc == NULL) {
|
||||
break;
|
||||
}
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
eve = td->extra;
|
||||
if (eve) {
|
||||
eve->co[0] = -td->loc[0];
|
||||
eve->co[1] = td->loc[1];
|
||||
eve->co[2] = td->loc[2];
|
||||
}
|
||||
|
||||
if (td->flag & TD_MIRROR_EDGE) {
|
||||
td->loc[0] = 0;
|
||||
}
|
||||
TransDataMirror *tdm;
|
||||
for (i = 0, tdm = tc->mirror.data; i < tc->mirror.data_len; i++, tdm++) {
|
||||
tdm->loc_dst[0] = tdm->loc_src[0] * tdm->sign_x;
|
||||
tdm->loc_dst[1] = tdm->loc_src[1] * tdm->sign_y;
|
||||
tdm->loc_dst[2] = tdm->loc_src[2] * tdm->sign_z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -889,7 +885,7 @@ static void recalcData_objects(TransInfo *t)
|
|||
clipMirrorModifier(t);
|
||||
}
|
||||
if ((t->flag & T_NO_MIRROR) == 0 && (t->options & CTX_NO_MIRROR) == 0) {
|
||||
editbmesh_apply_to_mirror(t);
|
||||
transform_apply_to_mirror(t);
|
||||
}
|
||||
|
||||
if (t->mode == TFM_EDGE_SLIDE) {
|
||||
|
@ -1361,11 +1357,12 @@ void initTransDataContainers_FromObjectData(TransInfo *t,
|
|||
|
||||
for (int i = 0; i < objects_len; i++) {
|
||||
TransDataContainer *tc = &t->data_container[i];
|
||||
/* TODO, multiple axes. */
|
||||
tc->mirror.axis_flag = (((t->flag & T_NO_MIRROR) == 0) &&
|
||||
((t->options & CTX_NO_MIRROR) == 0) &&
|
||||
(objects[i]->type == OB_MESH) &&
|
||||
(((Mesh *)objects[i]->data)->editflag & ME_EDIT_MIRROR_X) != 0);
|
||||
if (((t->flag & T_NO_MIRROR) == 0) && ((t->options & CTX_NO_MIRROR) == 0) &&
|
||||
(objects[i]->type == OB_MESH)) {
|
||||
tc->mirror.axis_x = (((Mesh *)objects[i]->data)->editflag & ME_EDIT_MIRROR_X) != 0;
|
||||
tc->mirror.axis_y = (((Mesh *)objects[i]->data)->editflag & ME_EDIT_MIRROR_Y) != 0;
|
||||
tc->mirror.axis_z = (((Mesh *)objects[i]->data)->editflag & ME_EDIT_MIRROR_Z) != 0;
|
||||
}
|
||||
|
||||
if (object_mode & OB_MODE_EDIT) {
|
||||
tc->obedit = objects[i];
|
||||
|
@ -1902,6 +1899,7 @@ void postTrans(bContext *C, TransInfo *t)
|
|||
|
||||
MEM_SAFE_FREE(tc->data_ext);
|
||||
MEM_SAFE_FREE(tc->data_2d);
|
||||
MEM_SAFE_FREE(tc->mirror.data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2349,11 +2347,6 @@ void calculatePropRatio(TransInfo *t)
|
|||
if (td->flag & TD_SELECTED) {
|
||||
td->factor = 1.0f;
|
||||
}
|
||||
else if (tc->mirror.axis_flag && (td->loc[0] * tc->mirror.sign) < -0.00001f) {
|
||||
td->flag |= TD_SKIP;
|
||||
td->factor = 0.0f;
|
||||
restoreElement(td);
|
||||
}
|
||||
else if ((connected && (td->flag & TD_NOTCONNECTED || td->dist > t->prop_size)) ||
|
||||
(connected == 0 && td->rdist > t->prop_size)) {
|
||||
/*
|
||||
|
|
|
@ -3088,7 +3088,6 @@ static void rna_def_mesh(BlenderRNA *brna)
|
|||
RNA_def_property_ui_text(prop, "X Mirror", "X Axis mirror editing");
|
||||
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
|
||||
|
||||
# if 0
|
||||
prop = RNA_def_property(srna, "use_mirror_y", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_MIRROR_Y);
|
||||
RNA_def_property_ui_text(prop, "Y Mirror", "Y Axis mirror editing");
|
||||
|
@ -3096,7 +3095,6 @@ static void rna_def_mesh(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "use_mirror_z", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_MIRROR_Z);
|
||||
RNA_def_property_ui_text(prop, "Z Mirror", "Z Axis mirror editing");
|
||||
# endif
|
||||
|
||||
prop = RNA_def_property(srna, "use_mirror_topology", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_MIRROR_TOPO);
|
||||
|
|
Loading…
Reference in New Issue