forked from bartvdbraak/blender
BMesh: edge-offset feature (Ctrl+Shift+R)
Ability to quickly add 2x edge loops on either side of selected loops.
This commit is contained in:
parent
3efc0aca54
commit
d8e994b35f
@ -327,6 +327,7 @@ class VIEW3D_PT_tools_meshedit(View3DPanel, Panel):
|
||||
col.operator("mesh.edge_face_add")
|
||||
col.operator("mesh.subdivide")
|
||||
col.operator("mesh.loopcut_slide")
|
||||
col.operator("mesh.offset_edge_loops_slide")
|
||||
col.operator("mesh.duplicate_move", text="Duplicate")
|
||||
row = col.row(align=True)
|
||||
row.operator("mesh.spin")
|
||||
|
@ -61,6 +61,7 @@ set(SRC
|
||||
operators/bmo_mesh_conv.c
|
||||
operators/bmo_mirror.c
|
||||
operators/bmo_normals.c
|
||||
operators/bmo_offset_edgeloops.c
|
||||
operators/bmo_planar_faces.c
|
||||
operators/bmo_poke.c
|
||||
operators/bmo_primitive.c
|
||||
|
@ -1865,6 +1865,26 @@ static BMOpDefine bmo_inset_region_def = {
|
||||
BMO_OPTYPE_FLAG_SELECT_FLUSH),
|
||||
};
|
||||
|
||||
/*
|
||||
* Edgeloop Offset.
|
||||
*
|
||||
* Creates edge loops based on simple edge-outset method.
|
||||
*/
|
||||
static BMOpDefine bmo_offset_edgeloops_def = {
|
||||
"offset_edgeloops",
|
||||
/* slots_in */
|
||||
{{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input faces */
|
||||
{{'\0'}},
|
||||
},
|
||||
/* slots_out */
|
||||
{{"edges.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* output faces */
|
||||
{{'\0'}},
|
||||
},
|
||||
bmo_offset_edgeloops_exec,
|
||||
(BMO_OPTYPE_FLAG_NORMALS_CALC |
|
||||
BMO_OPTYPE_FLAG_SELECT_FLUSH),
|
||||
};
|
||||
|
||||
/*
|
||||
* Wire Frame.
|
||||
*
|
||||
@ -2021,6 +2041,7 @@ const BMOpDefine *bmo_opdefines[] = {
|
||||
&bmo_duplicate_def,
|
||||
&bmo_holes_fill_def,
|
||||
&bmo_face_attribute_fill_def,
|
||||
&bmo_offset_edgeloops_def,
|
||||
&bmo_edgeloop_fill_def,
|
||||
&bmo_edgenet_fill_def,
|
||||
&bmo_edgenet_prepare_def,
|
||||
|
@ -82,6 +82,7 @@ void bmo_pointmerge_exec(BMesh *bm, BMOperator *op);
|
||||
void bmo_pointmerge_facedata_exec(BMesh *bm, BMOperator *op);
|
||||
void bmo_recalc_face_normals_exec(BMesh *bm, BMOperator *op);
|
||||
void bmo_poke_exec(BMesh *bm, BMOperator *op);
|
||||
void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op);
|
||||
void bmo_planar_faces_exec(BMesh *bm, BMOperator *op);
|
||||
void bmo_region_extend_exec(BMesh *bm, BMOperator *op);
|
||||
void bmo_remove_doubles_exec(BMesh *bm, BMOperator *op);
|
||||
|
@ -5181,6 +5181,57 @@ void MESH_OT_wireframe(wmOperatorType *ot)
|
||||
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2);
|
||||
}
|
||||
|
||||
static int edbm_offset_edgeloop_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
BMOperator bmop;
|
||||
|
||||
EDBM_op_init(
|
||||
em, &bmop, op,
|
||||
"offset_edgeloops edges=%he",
|
||||
BM_ELEM_SELECT);
|
||||
|
||||
BMO_op_exec(em->bm, &bmop);
|
||||
|
||||
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
|
||||
|
||||
/* If in face-only select mode, switch to edge select mode so that
|
||||
* an edge-only selection is not inconsistent state */
|
||||
if (em->selectmode == SCE_SELECT_FACE) {
|
||||
em->selectmode = SCE_SELECT_EDGE;
|
||||
EDBM_selectmode_set(em);
|
||||
EDBM_selectmode_to_scene(C);
|
||||
}
|
||||
|
||||
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
|
||||
|
||||
if (!EDBM_op_finish(em, &bmop, op, true)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
else {
|
||||
EDBM_update_generic(em, true, true);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
}
|
||||
|
||||
void MESH_OT_offset_edge_loops(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Offset Edge Loop";
|
||||
ot->idname = "MESH_OT_offset_edge_loops";
|
||||
ot->description = "Creates offset edge loop from the current selection";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = edbm_offset_edgeloop_exec;
|
||||
ot->poll = ED_operator_editmesh;
|
||||
|
||||
/* Keep internal, since this is only meant to be accessed via 'MESH_OT_offset_edge_loops_slide' */
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
#ifdef WITH_BULLET
|
||||
static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
|
@ -176,6 +176,7 @@ void MESH_OT_vert_connect_nonplanar(struct wmOperatorType *ot);
|
||||
void MESH_OT_face_make_planar(struct wmOperatorType *ot);
|
||||
void MESH_OT_edge_split(struct wmOperatorType *ot);
|
||||
void MESH_OT_bridge_edge_loops(struct wmOperatorType *ot);
|
||||
void MESH_OT_offset_edge_loops(struct wmOperatorType *ot);
|
||||
void MESH_OT_wireframe(struct wmOperatorType *ot);
|
||||
void MESH_OT_convex_hull(struct wmOperatorType *ot);
|
||||
void MESH_OT_symmetrize(struct wmOperatorType *ot);
|
||||
|
@ -177,6 +177,7 @@ void ED_operatortypes_mesh(void)
|
||||
|
||||
WM_operatortype_append(MESH_OT_bridge_edge_loops);
|
||||
WM_operatortype_append(MESH_OT_inset);
|
||||
WM_operatortype_append(MESH_OT_offset_edge_loops);
|
||||
WM_operatortype_append(MESH_OT_intersect);
|
||||
WM_operatortype_append(MESH_OT_face_split_by_edges);
|
||||
WM_operatortype_append(MESH_OT_poke);
|
||||
@ -225,6 +226,13 @@ void ED_operatormacros_mesh(void)
|
||||
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_edge_slide");
|
||||
RNA_boolean_set(otmacro->ptr, "release_confirm", false);
|
||||
|
||||
ot = WM_operatortype_append_macro("MESH_OT_offset_edge_loops_slide", "Offset Edge Slide", "Offset edge loop slide",
|
||||
OPTYPE_UNDO | OPTYPE_REGISTER);
|
||||
WM_operatortype_macro_define(ot, "MESH_OT_offset_edge_loops");
|
||||
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_edge_slide");
|
||||
RNA_boolean_set(otmacro->ptr, "release_confirm", false);
|
||||
RNA_boolean_set(otmacro->ptr, "single_side", true);
|
||||
|
||||
ot = WM_operatortype_append_macro("MESH_OT_duplicate_move", "Add Duplicate", "Duplicate mesh and move",
|
||||
OPTYPE_UNDO | OPTYPE_REGISTER);
|
||||
WM_operatortype_macro_define(ot, "MESH_OT_duplicate");
|
||||
@ -302,7 +310,8 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
|
||||
keymap = WM_keymap_find(keyconf, "Mesh", 0, 0);
|
||||
keymap->poll = ED_operator_editmesh;
|
||||
|
||||
WM_keymap_add_item(keymap, "MESH_OT_loopcut_slide", RKEY, KM_PRESS, KM_CTRL, 0);
|
||||
WM_keymap_add_item(keymap, "MESH_OT_loopcut_slide", RKEY, KM_PRESS, KM_CTRL, 0);
|
||||
WM_keymap_add_item(keymap, "MESH_OT_offset_edge_loops_slide", RKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
|
||||
WM_keymap_add_item(keymap, "MESH_OT_inset", IKEY, KM_PRESS, 0, 0);
|
||||
WM_keymap_add_item(keymap, "MESH_OT_poke", PKEY, KM_PRESS, KM_ALT, 0);
|
||||
kmi = WM_keymap_add_item(keymap, "MESH_OT_bevel", BKEY, KM_PRESS, KM_CTRL, 0);
|
||||
|
@ -167,6 +167,7 @@ static void applyBoneEnvelope(TransInfo *t, const int mval[2]);
|
||||
static void initBoneRoll(TransInfo *t);
|
||||
static void applyBoneRoll(TransInfo *t, const int mval[2]);
|
||||
|
||||
static void initEdgeSlide_ex(TransInfo *t, bool use_double_side);
|
||||
static void initEdgeSlide(TransInfo *t);
|
||||
static eRedrawFlag handleEventEdgeSlide(TransInfo *t, const struct wmEvent *event);
|
||||
static void applyEdgeSlide(TransInfo *t, const int mval[2]);
|
||||
@ -2229,8 +2230,11 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
|
||||
initBoneEnvelope(t);
|
||||
break;
|
||||
case TFM_EDGE_SLIDE:
|
||||
initEdgeSlide(t);
|
||||
{
|
||||
const bool use_double_side = (op ? !RNA_boolean_get(op->ptr, "single_side") : true);
|
||||
initEdgeSlide_ex(t, use_double_side);
|
||||
break;
|
||||
}
|
||||
case TFM_VERT_SLIDE:
|
||||
initVertSlide(t);
|
||||
break;
|
||||
@ -5684,8 +5688,11 @@ static void calcEdgeSlide_mval_range(
|
||||
float projectMat[4][4];
|
||||
BMBVHTree *btree;
|
||||
|
||||
/* only for use_calc_direction */
|
||||
float (*loop_dir)[3] = NULL, *loop_maxdist = NULL;
|
||||
|
||||
float mval_start[2], mval_end[2];
|
||||
float mval_dir[3], dist_best_sq, (*loop_dir)[3], *loop_maxdist;
|
||||
float mval_dir[3], dist_best_sq;
|
||||
BMIter iter;
|
||||
BMEdge *e;
|
||||
|
||||
@ -5715,9 +5722,11 @@ static void calcEdgeSlide_mval_range(
|
||||
zero_v3(mval_dir);
|
||||
dist_best_sq = -1.0f;
|
||||
|
||||
loop_dir = MEM_callocN(sizeof(float[3]) * loop_nr, "sv loop_dir");
|
||||
loop_maxdist = MEM_mallocN(sizeof(float) * loop_nr, "sv loop_maxdist");
|
||||
copy_vn_fl(loop_maxdist, loop_nr, -1.0f);
|
||||
if (use_calc_direction) {
|
||||
loop_dir = MEM_callocN(sizeof(float[3]) * loop_nr, "sv loop_dir");
|
||||
loop_maxdist = MEM_mallocN(sizeof(float) * loop_nr, "sv loop_maxdist");
|
||||
copy_vn_fl(loop_maxdist, loop_nr, -1.0f);
|
||||
}
|
||||
|
||||
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
|
||||
if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
|
||||
@ -5773,11 +5782,13 @@ static void calcEdgeSlide_mval_range(
|
||||
sub_v3_v3v3(mval_dir, sco_b, sco_a);
|
||||
}
|
||||
|
||||
/* per loop direction */
|
||||
l_nr = sv_array[j].loop_nr;
|
||||
if (loop_maxdist[l_nr] == -1.0f || dist_sq < loop_maxdist[l_nr]) {
|
||||
loop_maxdist[l_nr] = dist_sq;
|
||||
sub_v3_v3v3(loop_dir[l_nr], sco_b, sco_a);
|
||||
if (use_calc_direction) {
|
||||
/* per loop direction */
|
||||
l_nr = sv_array[j].loop_nr;
|
||||
if (loop_maxdist[l_nr] == -1.0f || dist_sq < loop_maxdist[l_nr]) {
|
||||
loop_maxdist[l_nr] = dist_sq;
|
||||
sub_v3_v3v3(loop_dir[l_nr], sco_b, sco_a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5795,6 +5806,9 @@ static void calcEdgeSlide_mval_range(
|
||||
SWAP(BMVert *, sv_array->v_side[0], sv_array->v_side[1]);
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(loop_dir);
|
||||
MEM_freeN(loop_maxdist);
|
||||
}
|
||||
|
||||
/* possible all of the edge loops are pointing directly at the view */
|
||||
@ -5819,9 +5833,6 @@ static void calcEdgeSlide_mval_range(
|
||||
if (btree) {
|
||||
BKE_bmbvh_free(btree);
|
||||
}
|
||||
|
||||
MEM_freeN(loop_dir);
|
||||
MEM_freeN(loop_maxdist);
|
||||
}
|
||||
|
||||
static void calcEdgeSlide_non_proportional(
|
||||
@ -5870,7 +5881,7 @@ static void calcEdgeSlide_non_proportional(
|
||||
}
|
||||
}
|
||||
|
||||
static bool createEdgeSlideVerts(TransInfo *t)
|
||||
static bool createEdgeSlideVerts_double_side(TransInfo *t)
|
||||
{
|
||||
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
|
||||
BMesh *bm = em->bm;
|
||||
@ -6211,6 +6222,198 @@ static bool createEdgeSlideVerts(TransInfo *t)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple version of #createEdgeSlideVerts
|
||||
* Which assumes the longest unselected.
|
||||
*/
|
||||
static bool createEdgeSlideVerts_single_side(TransInfo *t)
|
||||
{
|
||||
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
|
||||
BMesh *bm = em->bm;
|
||||
BMIter iter;
|
||||
BMEdge *e;
|
||||
BMVert *v;
|
||||
TransDataEdgeSlideVert *sv_array;
|
||||
int sv_tot;
|
||||
int *sv_table; /* BMVert -> sv_array index */
|
||||
EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
|
||||
float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
|
||||
int i, j, loop_nr;
|
||||
bool use_btree_disp = false;
|
||||
View3D *v3d = NULL;
|
||||
RegionView3D *rv3d = NULL;
|
||||
|
||||
if (t->spacetype == SPACE_VIEW3D) {
|
||||
/* background mode support */
|
||||
v3d = t->sa ? t->sa->spacedata.first : NULL;
|
||||
rv3d = t->ar ? t->ar->regiondata : NULL;
|
||||
}
|
||||
|
||||
slide_origdata_init_flag(t, &sld->orig_data);
|
||||
|
||||
sld->is_proportional = true;
|
||||
sld->curr_sv_index = 0;
|
||||
/* heppans to be best for single-sided */
|
||||
sld->flipped_vtx = true;
|
||||
|
||||
/* ensure valid selection */
|
||||
j = 0;
|
||||
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
|
||||
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
|
||||
float len_sq_max = -1.0f;
|
||||
BMIter iter2;
|
||||
BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
|
||||
if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) {
|
||||
float len_sq = BM_edge_calc_length_squared(e);
|
||||
if (len_sq > len_sq_max) {
|
||||
len_sq_max = len_sq;
|
||||
v->e = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (len_sq_max != -1.0f) {
|
||||
j++;
|
||||
}
|
||||
}
|
||||
BM_elem_index_set(v, i); /* set_inline */
|
||||
}
|
||||
bm->elem_index_dirty &= ~BM_VERT;
|
||||
|
||||
if (!j) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
sv_tot = j;
|
||||
BLI_assert(sv_tot != 0);
|
||||
/* over alloc */
|
||||
sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * bm->totvertsel, "sv_array");
|
||||
|
||||
/* same loop for all loops, weak but we dont connect loops in this case */
|
||||
loop_nr = 1;
|
||||
|
||||
sv_table = MEM_mallocN(sizeof(*sv_table) * bm->totvert, __func__);
|
||||
|
||||
j = 0;
|
||||
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
|
||||
sv_table[i] = -1;
|
||||
if ((v->e != NULL) && (BM_elem_flag_test(v, BM_ELEM_SELECT))) {
|
||||
if (BM_elem_flag_test(v->e, BM_ELEM_SELECT) == 0) {
|
||||
TransDataEdgeSlideVert *sv;
|
||||
sv = &sv_array[j];
|
||||
sv->v = v;
|
||||
copy_v3_v3(sv->v_co_orig, v->co);
|
||||
sv->v_side[0] = BM_edge_other_vert(v->e, v);
|
||||
sub_v3_v3v3(sv->dir_side[0], sv->v_side[0]->co, v->co);
|
||||
sv->loop_nr = 0;
|
||||
sv_table[i] = j;
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check for wire vertices,
|
||||
* interpolate the directions of wire verts between non-wire verts */
|
||||
if (sv_tot != bm->totvert) {
|
||||
const int sv_tot_nowire = sv_tot;
|
||||
TransDataEdgeSlideVert *sv_iter = sv_array;
|
||||
int i;
|
||||
for (i = 0; i < sv_tot_nowire; i++, sv_iter++) {
|
||||
BMIter eiter;
|
||||
BM_ITER_ELEM (e, &eiter, sv_iter->v, BM_EDGES_OF_VERT) {
|
||||
/* walk over wire */
|
||||
TransDataEdgeSlideVert *sv_end = NULL;
|
||||
BMEdge *e_step = e;
|
||||
BMVert *v = sv_iter->v;
|
||||
|
||||
j = sv_tot;
|
||||
|
||||
while (1) {
|
||||
BMVert *v_other = BM_edge_other_vert(e_step, v);
|
||||
int endpoint = (
|
||||
(sv_table[BM_elem_index_get(v_other)] != -1) +
|
||||
(BM_vert_is_edge_pair(v_other) == false));
|
||||
|
||||
if ((BM_elem_flag_test(e_step, BM_ELEM_SELECT) &&
|
||||
BM_elem_flag_test(v_other, BM_ELEM_SELECT)) &&
|
||||
(endpoint == 0))
|
||||
{
|
||||
/* scan down the list */
|
||||
TransDataEdgeSlideVert *sv;
|
||||
BLI_assert(sv_table[BM_elem_index_get(v_other)] == -1);
|
||||
sv_table[BM_elem_index_get(v_other)] = j;
|
||||
sv = &sv_array[j];
|
||||
sv->v = v_other;
|
||||
copy_v3_v3(sv->v_co_orig, v_other->co);
|
||||
copy_v3_v3(sv->dir_side[0], sv_iter->dir_side[0]);
|
||||
j++;
|
||||
|
||||
/* advance! */
|
||||
v = v_other;
|
||||
e_step = BM_DISK_EDGE_NEXT(e_step, v_other);
|
||||
}
|
||||
else {
|
||||
if ((endpoint == 2) && (sv_tot != j)) {
|
||||
BLI_assert(BM_elem_index_get(v_other) != -1);
|
||||
sv_end = &sv_array[sv_table[BM_elem_index_get(v_other)]];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sv_end) {
|
||||
int sv_tot_prev = sv_tot;
|
||||
const float *co_src = sv_iter->v->co;
|
||||
const float *co_dst = sv_end->v->co;
|
||||
const float *dir_src = sv_iter->dir_side[0];
|
||||
const float *dir_dst = sv_end->dir_side[0];
|
||||
sv_tot = j;
|
||||
|
||||
while (j-- != sv_tot_prev) {
|
||||
float factor;
|
||||
factor = line_point_factor_v3(sv_array[j].v->co, co_src, co_dst);
|
||||
interp_v3_v3v3(sv_array[j].dir_side[0], dir_src, dir_dst, factor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
|
||||
|
||||
sld->sv = sv_array;
|
||||
sld->totsv = sv_tot;
|
||||
|
||||
/* use for visibility checks */
|
||||
if (t->spacetype == SPACE_VIEW3D) {
|
||||
v3d = t->sa ? t->sa->spacedata.first : NULL;
|
||||
rv3d = t->ar ? t->ar->regiondata : NULL;
|
||||
use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
|
||||
}
|
||||
|
||||
calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_btree_disp, false);
|
||||
|
||||
/* create copies of faces for customdata projection */
|
||||
bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
|
||||
slide_origdata_init_data(t, &sld->orig_data);
|
||||
slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
|
||||
|
||||
if (rv3d) {
|
||||
calcEdgeSlide_non_proportional(t, sld, mval);
|
||||
}
|
||||
|
||||
sld->em = em;
|
||||
|
||||
sld->perc = 0.0f;
|
||||
|
||||
t->customData = sld;
|
||||
|
||||
MEM_freeN(sv_table);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void projectEdgeSlideData(TransInfo *t, bool is_final)
|
||||
{
|
||||
EdgeSlideData *sld = t->customData;
|
||||
@ -6247,15 +6450,23 @@ void freeEdgeSlideVerts(TransInfo *t)
|
||||
recalcData(t);
|
||||
}
|
||||
|
||||
static void initEdgeSlide(TransInfo *t)
|
||||
static void initEdgeSlide_ex(TransInfo *t, bool use_double_side)
|
||||
{
|
||||
EdgeSlideData *sld;
|
||||
bool ok;
|
||||
|
||||
t->mode = TFM_EDGE_SLIDE;
|
||||
t->transform = applyEdgeSlide;
|
||||
t->handleEvent = handleEventEdgeSlide;
|
||||
|
||||
if (!createEdgeSlideVerts(t)) {
|
||||
if (use_double_side) {
|
||||
ok = createEdgeSlideVerts_double_side(t);
|
||||
}
|
||||
else {
|
||||
ok = createEdgeSlideVerts_single_side(t);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
t->state = TRANS_CANCEL;
|
||||
return;
|
||||
}
|
||||
@ -6284,6 +6495,11 @@ static void initEdgeSlide(TransInfo *t)
|
||||
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
|
||||
}
|
||||
|
||||
static void initEdgeSlide(TransInfo *t)
|
||||
{
|
||||
initEdgeSlide_ex(t, true);
|
||||
}
|
||||
|
||||
static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event)
|
||||
{
|
||||
if (t->mode == TFM_EDGE_SLIDE) {
|
||||
|
@ -837,6 +837,8 @@ static void TRANSFORM_OT_mirror(struct wmOperatorType *ot)
|
||||
|
||||
static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "Edge Slide";
|
||||
ot->description = "Slide an edge loop along a mesh";
|
||||
@ -852,6 +854,9 @@ static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
|
||||
|
||||
RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f);
|
||||
|
||||
prop = RNA_def_boolean(ot->srna, "single_side", false, "Single Side", "");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
|
||||
|
||||
Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user