Editmesh: select more/less can now step over adjacent faces
This keeps a square shaped selection when using grid topology.
This commit is contained in:
@@ -173,8 +173,9 @@ static BMOpDefine bmo_region_extend_def = {
|
|||||||
"region_extend",
|
"region_extend",
|
||||||
/* slots_in */
|
/* slots_in */
|
||||||
{{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input geometry */
|
{{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input geometry */
|
||||||
{"use_constrict", BMO_OP_SLOT_BOOL}, /* find boundary inside the regions, not outside. */
|
{"use_contract", BMO_OP_SLOT_BOOL}, /* find boundary inside the regions, not outside. */
|
||||||
{"use_faces", BMO_OP_SLOT_BOOL}, /* extend from faces instead of edges */
|
{"use_faces", BMO_OP_SLOT_BOOL}, /* extend from faces instead of edges */
|
||||||
|
{"use_face_step", BMO_OP_SLOT_BOOL}, /* step over connected faces */
|
||||||
{{'\0'}},
|
{{'\0'}},
|
||||||
},
|
},
|
||||||
/* slots_out */
|
/* slots_out */
|
||||||
|
@@ -177,42 +177,94 @@ void bmo_rotate_edges_exec(BMesh *bm, BMOperator *op)
|
|||||||
#define SEL_FLAG 1
|
#define SEL_FLAG 1
|
||||||
#define SEL_ORIG 2
|
#define SEL_ORIG 2
|
||||||
|
|
||||||
static void bmo_region_extend_extend(BMesh *bm, BMOperator *op, const bool use_faces)
|
static void bmo_face_flag_set_flush(BMesh *bm, BMFace *f, const short oflag, const bool value)
|
||||||
|
{
|
||||||
|
BMLoop *l_iter;
|
||||||
|
BMLoop *l_first;
|
||||||
|
|
||||||
|
BMO_elem_flag_set(bm, f, oflag, value);
|
||||||
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
||||||
|
do {
|
||||||
|
BMO_elem_flag_set(bm, l_iter->e, oflag, value);
|
||||||
|
BMO_elem_flag_set(bm, l_iter->v, oflag, value);
|
||||||
|
} while ((l_iter = l_iter->next) != l_first);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void bmo_region_extend_expand(
|
||||||
|
BMesh *bm, BMOperator *op,
|
||||||
|
const bool use_faces, const bool use_faces_step)
|
||||||
{
|
{
|
||||||
BMVert *v;
|
|
||||||
BMEdge *e;
|
|
||||||
BMIter eiter;
|
|
||||||
BMOIter siter;
|
BMOIter siter;
|
||||||
|
|
||||||
if (!use_faces) {
|
if (!use_faces) {
|
||||||
|
BMVert *v;
|
||||||
|
|
||||||
BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) {
|
BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) {
|
||||||
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
|
bool found = false;
|
||||||
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN))
|
|
||||||
if (!BMO_elem_flag_test(bm, e, SEL_ORIG))
|
{
|
||||||
|
BMIter eiter;
|
||||||
|
BMEdge *e;
|
||||||
|
|
||||||
|
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
|
||||||
|
if (!BMO_elem_flag_test(bm, e, SEL_ORIG)) {
|
||||||
|
found = true;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e) {
|
if (found) {
|
||||||
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
|
if (!use_faces_step) {
|
||||||
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
|
BMIter eiter;
|
||||||
BMO_elem_flag_enable(bm, e, SEL_FLAG);
|
BMEdge *e;
|
||||||
BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG);
|
|
||||||
|
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
|
||||||
|
if (!BMO_elem_flag_test(bm, e, SEL_FLAG)) {
|
||||||
|
BMO_elem_flag_enable(bm, e, SEL_FLAG);
|
||||||
|
BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BMIter fiter;
|
||||||
|
BMFace *f;
|
||||||
|
|
||||||
|
BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
|
||||||
|
if (!BMO_elem_flag_test(bm, f, SEL_FLAG)) {
|
||||||
|
bmo_face_flag_set_flush(bm, f, SEL_FLAG, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
BMIter liter, fiter;
|
BMFace *f;
|
||||||
BMFace *f, *f2;
|
|
||||||
BMLoop *l;
|
|
||||||
|
|
||||||
BMO_ITER (f, &siter, op->slots_in, "geom", BM_FACE) {
|
BMO_ITER (f, &siter, op->slots_in, "geom", BM_FACE) {
|
||||||
|
BMIter liter;
|
||||||
|
BMLoop *l;
|
||||||
|
|
||||||
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
|
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
|
||||||
BM_ITER_ELEM (f2, &fiter, l->e, BM_FACES_OF_EDGE) {
|
if (!use_faces_step) {
|
||||||
if (!BM_elem_flag_test(f2, BM_ELEM_HIDDEN)) {
|
BMIter fiter;
|
||||||
if (!BMO_elem_flag_test(bm, f2, SEL_ORIG)) {
|
BMFace *f_other;
|
||||||
BMO_elem_flag_enable(bm, f2, SEL_FLAG);
|
|
||||||
|
BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) {
|
||||||
|
if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG)) {
|
||||||
|
BMO_elem_flag_enable(bm, f_other, SEL_FLAG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BMIter fiter;
|
||||||
|
BMFace *f_other;
|
||||||
|
|
||||||
|
BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) {
|
||||||
|
if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG)) {
|
||||||
|
BMO_elem_flag_enable(bm, f_other, SEL_FLAG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,43 +273,79 @@ static void bmo_region_extend_extend(BMesh *bm, BMOperator *op, const bool use_f
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bmo_region_extend_constrict(BMesh *bm, BMOperator *op, const bool use_faces)
|
static void bmo_region_extend_contract(
|
||||||
|
BMesh *bm, BMOperator *op,
|
||||||
|
const bool use_faces, const bool use_faces_step)
|
||||||
{
|
{
|
||||||
BMVert *v;
|
|
||||||
BMEdge *e;
|
|
||||||
BMIter eiter;
|
|
||||||
BMOIter siter;
|
BMOIter siter;
|
||||||
|
|
||||||
if (!use_faces) {
|
if (!use_faces) {
|
||||||
|
BMVert *v;
|
||||||
|
|
||||||
BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) {
|
BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) {
|
||||||
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
|
bool found = false;
|
||||||
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN))
|
|
||||||
if (!BMO_elem_flag_test(bm, e, SEL_ORIG))
|
if (!use_faces_step) {
|
||||||
|
BMIter eiter;
|
||||||
|
BMEdge *e;
|
||||||
|
|
||||||
|
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
|
||||||
|
if (!BMO_elem_flag_test(bm, e, SEL_ORIG)) {
|
||||||
|
found = true;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BMIter fiter;
|
||||||
|
BMFace *f;
|
||||||
|
|
||||||
|
BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
|
||||||
|
if (!BMO_elem_flag_test(bm, f, SEL_ORIG)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e) {
|
if (found) {
|
||||||
|
BMIter eiter;
|
||||||
|
BMEdge *e;
|
||||||
|
|
||||||
BMO_elem_flag_enable(bm, v, SEL_FLAG);
|
BMO_elem_flag_enable(bm, v, SEL_FLAG);
|
||||||
|
|
||||||
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
|
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
|
||||||
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
|
BMO_elem_flag_enable(bm, e, SEL_FLAG);
|
||||||
BMO_elem_flag_enable(bm, e, SEL_FLAG);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
BMIter liter, fiter;
|
BMFace *f;
|
||||||
BMFace *f, *f2;
|
|
||||||
BMLoop *l;
|
|
||||||
|
|
||||||
BMO_ITER (f, &siter, op->slots_in, "geom", BM_FACE) {
|
BMO_ITER (f, &siter, op->slots_in, "geom", BM_FACE) {
|
||||||
|
BMIter liter;
|
||||||
|
BMLoop *l;
|
||||||
|
|
||||||
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
|
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
|
||||||
BM_ITER_ELEM (f2, &fiter, l->e, BM_FACES_OF_EDGE) {
|
|
||||||
if (!BM_elem_flag_test(f2, BM_ELEM_HIDDEN)) {
|
if (!use_faces_step) {
|
||||||
if (!BMO_elem_flag_test(bm, f2, SEL_ORIG)) {
|
BMIter fiter;
|
||||||
|
BMFace *f_other;
|
||||||
|
|
||||||
|
BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) {
|
||||||
|
if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG)) {
|
||||||
|
BMO_elem_flag_enable(bm, f, SEL_FLAG);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BMIter fiter;
|
||||||
|
BMFace *f_other;
|
||||||
|
|
||||||
|
BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) {
|
||||||
|
if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG)) {
|
||||||
BMO_elem_flag_enable(bm, f, SEL_FLAG);
|
BMO_elem_flag_enable(bm, f, SEL_FLAG);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -271,14 +359,17 @@ static void bmo_region_extend_constrict(BMesh *bm, BMOperator *op, const bool us
|
|||||||
void bmo_region_extend_exec(BMesh *bm, BMOperator *op)
|
void bmo_region_extend_exec(BMesh *bm, BMOperator *op)
|
||||||
{
|
{
|
||||||
const bool use_faces = BMO_slot_bool_get(op->slots_in, "use_faces");
|
const bool use_faces = BMO_slot_bool_get(op->slots_in, "use_faces");
|
||||||
const bool constrict = BMO_slot_bool_get(op->slots_in, "use_constrict");
|
const bool use_face_step = BMO_slot_bool_get(op->slots_in, "use_face_step");
|
||||||
|
const bool constrict = BMO_slot_bool_get(op->slots_in, "use_contract");
|
||||||
|
|
||||||
BMO_slot_buffer_flag_enable(bm, op->slots_in, "geom", BM_ALL_NOLOOP, SEL_ORIG);
|
BMO_slot_buffer_flag_enable(bm, op->slots_in, "geom", BM_ALL_NOLOOP, SEL_ORIG);
|
||||||
|
|
||||||
if (constrict)
|
if (constrict) {
|
||||||
bmo_region_extend_constrict(bm, op, use_faces);
|
bmo_region_extend_contract(bm, op, use_faces, use_face_step);
|
||||||
else
|
}
|
||||||
bmo_region_extend_extend(bm, op, use_faces);
|
else {
|
||||||
|
bmo_region_extend_expand(bm, op, use_faces, use_face_step);
|
||||||
|
}
|
||||||
|
|
||||||
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, SEL_FLAG);
|
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, SEL_FLAG);
|
||||||
}
|
}
|
||||||
|
@@ -101,8 +101,8 @@ struct DerivedMesh *EDBM_mesh_deform_dm_get(struct BMEditMesh *em);
|
|||||||
* verts select/deselect edges and faces, if in edge select mode,
|
* verts select/deselect edges and faces, if in edge select mode,
|
||||||
* edges select/deselect faces and vertices, and in face select mode faces select/deselect
|
* edges select/deselect faces and vertices, and in face select mode faces select/deselect
|
||||||
* edges and vertices.*/
|
* edges and vertices.*/
|
||||||
void EDBM_select_more(struct BMEditMesh *em);
|
void EDBM_select_more(struct BMEditMesh *em, const bool use_face_step);
|
||||||
void EDBM_select_less(struct BMEditMesh *em);
|
void EDBM_select_less(struct BMEditMesh *em, const bool use_face_step);
|
||||||
|
|
||||||
void EDBM_selectmode_flush_ex(struct BMEditMesh *em, const short selectmode);
|
void EDBM_selectmode_flush_ex(struct BMEditMesh *em, const short selectmode);
|
||||||
void EDBM_selectmode_flush(struct BMEditMesh *em);
|
void EDBM_selectmode_flush(struct BMEditMesh *em);
|
||||||
|
@@ -2473,12 +2473,13 @@ void MESH_OT_select_mirror(wmOperatorType *ot)
|
|||||||
|
|
||||||
/* ******************** **************** */
|
/* ******************** **************** */
|
||||||
|
|
||||||
static int edbm_select_more_exec(bContext *C, wmOperator *UNUSED(op))
|
static int edbm_select_more_exec(bContext *C, wmOperator *op)
|
||||||
{
|
{
|
||||||
Object *obedit = CTX_data_edit_object(C);
|
Object *obedit = CTX_data_edit_object(C);
|
||||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||||
|
const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
|
||||||
|
|
||||||
EDBM_select_more(em);
|
EDBM_select_more(em, use_face_step);
|
||||||
|
|
||||||
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
|
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
|
||||||
return OPERATOR_FINISHED;
|
return OPERATOR_FINISHED;
|
||||||
@@ -2497,14 +2498,17 @@ void MESH_OT_select_more(wmOperatorType *ot)
|
|||||||
|
|
||||||
/* flags */
|
/* flags */
|
||||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
|
|
||||||
|
RNA_def_boolean(ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int edbm_select_less_exec(bContext *C, wmOperator *UNUSED(op))
|
static int edbm_select_less_exec(bContext *C, wmOperator *op)
|
||||||
{
|
{
|
||||||
Object *obedit = CTX_data_edit_object(C);
|
Object *obedit = CTX_data_edit_object(C);
|
||||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||||
|
const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
|
||||||
|
|
||||||
EDBM_select_less(em);
|
EDBM_select_less(em, use_face_step);
|
||||||
|
|
||||||
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
|
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
|
||||||
return OPERATOR_FINISHED;
|
return OPERATOR_FINISHED;
|
||||||
@@ -2523,6 +2527,8 @@ void MESH_OT_select_less(wmOperatorType *ot)
|
|||||||
|
|
||||||
/* flags */
|
/* flags */
|
||||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
|
|
||||||
|
RNA_def_boolean(ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -432,14 +432,14 @@ void EDBM_select_flush(BMEditMesh *em)
|
|||||||
BM_mesh_select_flush(em->bm);
|
BM_mesh_select_flush(em->bm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EDBM_select_more(BMEditMesh *em)
|
void EDBM_select_more(BMEditMesh *em, const bool use_face_step)
|
||||||
{
|
{
|
||||||
BMOperator bmop;
|
BMOperator bmop;
|
||||||
int use_faces = em->selectmode == SCE_SELECT_FACE;
|
const bool use_faces = (em->selectmode == SCE_SELECT_FACE);
|
||||||
|
|
||||||
BMO_op_initf(em->bm, &bmop, BMO_FLAG_DEFAULTS,
|
BMO_op_initf(em->bm, &bmop, BMO_FLAG_DEFAULTS,
|
||||||
"region_extend geom=%hvef use_constrict=%b use_faces=%b",
|
"region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
|
||||||
BM_ELEM_SELECT, false, use_faces);
|
BM_ELEM_SELECT, false, use_faces, use_face_step);
|
||||||
BMO_op_exec(em->bm, &bmop);
|
BMO_op_exec(em->bm, &bmop);
|
||||||
/* don't flush selection in edge/vertex mode */
|
/* don't flush selection in edge/vertex mode */
|
||||||
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false);
|
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false);
|
||||||
@@ -448,14 +448,14 @@ void EDBM_select_more(BMEditMesh *em)
|
|||||||
EDBM_selectmode_flush(em);
|
EDBM_selectmode_flush(em);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EDBM_select_less(BMEditMesh *em)
|
void EDBM_select_less(BMEditMesh *em, const bool use_face_step)
|
||||||
{
|
{
|
||||||
BMOperator bmop;
|
BMOperator bmop;
|
||||||
int use_faces = em->selectmode == SCE_SELECT_FACE;
|
const bool use_faces = (em->selectmode == SCE_SELECT_FACE);
|
||||||
|
|
||||||
BMO_op_initf(em->bm, &bmop, BMO_FLAG_DEFAULTS,
|
BMO_op_initf(em->bm, &bmop, BMO_FLAG_DEFAULTS,
|
||||||
"region_extend geom=%hvef use_constrict=%b use_faces=%b",
|
"region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
|
||||||
BM_ELEM_SELECT, true, use_faces);
|
BM_ELEM_SELECT, true, use_faces, use_face_step);
|
||||||
BMO_op_exec(em->bm, &bmop);
|
BMO_op_exec(em->bm, &bmop);
|
||||||
/* don't flush selection in edge/vertex mode */
|
/* don't flush selection in edge/vertex mode */
|
||||||
BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false);
|
BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false);
|
||||||
|
@@ -1309,10 +1309,10 @@ static int uv_select_more_less(bContext *C, const bool select)
|
|||||||
|
|
||||||
if (ts->uv_flag & UV_SYNC_SELECTION) {
|
if (ts->uv_flag & UV_SYNC_SELECTION) {
|
||||||
if (select) {
|
if (select) {
|
||||||
EDBM_select_more(em);
|
EDBM_select_more(em, true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
EDBM_select_less(em);
|
EDBM_select_less(em, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
|
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
|
||||||
|
Reference in New Issue
Block a user