2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2004 Blender Foundation.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): none yet.
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/editors/mesh/editmesh_select.c
32 #include "MEM_guardedalloc.h"
34 #include "BLI_blenlib.h"
37 #include "BLI_array.h"
38 #include "BLI_smallhash.h"
41 #include "BKE_context.h"
42 #include "BKE_displist.h"
43 #include "BKE_depsgraph.h"
44 #include "BKE_report.h"
45 #include "BKE_paint.h"
46 #include "BKE_tessmesh.h"
48 #include "IMB_imbuf_types.h"
49 #include "IMB_imbuf.h"
54 #include "RNA_access.h"
55 #include "RNA_define.h"
58 #include "ED_screen.h"
59 #include "ED_uvedit.h"
60 #include "ED_object.h"
61 #include "ED_view3d.h"
65 #include "DNA_scene_types.h"
66 #include "DNA_object_types.h"
67 #include "DNA_mesh_types.h"
69 #include "mesh_intern.h"
72 /* ****************************** MIRROR **************** */
74 void EDBM_select_mirrored(Object *UNUSED(obedit), BMEditMesh *em, int extend)
79 BM_ITER_MESH (v1, &iter, em->bm, BM_VERTS_OF_MESH) {
80 if (!BM_elem_flag_test(v1, BM_ELEM_SELECT) || BM_elem_flag_test(v1, BM_ELEM_HIDDEN)) {
81 BM_elem_flag_disable(v1, BM_ELEM_TAG);
84 BM_elem_flag_enable(v1, BM_ELEM_TAG);
88 EDBM_verts_mirror_cache_begin(em, TRUE);
91 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
93 BM_ITER_MESH (v1, &iter, em->bm, BM_VERTS_OF_MESH) {
94 if (!BM_elem_flag_test(v1, BM_ELEM_TAG) || BM_elem_flag_test(v1, BM_ELEM_HIDDEN))
97 v2 = EDBM_verts_mirror_get(em, v1);
98 if (v2 && !BM_elem_flag_test(v2, BM_ELEM_HIDDEN)) {
99 BM_vert_select_set(em->bm, v2, TRUE);
103 EDBM_verts_mirror_cache_end(em);
106 void EDBM_automerge(Scene *scene, Object *obedit, int update)
110 if ((scene->toolsettings->automerge) &&
111 (obedit && obedit->type == OB_MESH))
113 em = BMEdit_FromObject(obedit);
117 BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS,
118 "automerge verts=%hv dist=%f",
119 BM_ELEM_SELECT, scene->toolsettings->doublimit);
121 DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
122 BMEdit_RecalcTessellation(em);
127 /* ****************************** SELECTION ROUTINES **************** */
129 unsigned int bm_solidoffs = 0, bm_wireoffs = 0, bm_vertoffs = 0; /* set in drawobject.c ... for colorindices */
131 /* facilities for border select and circle select */
132 static char *selbuf = NULL;
134 /* opengl doesn't support concave... */
135 static void draw_triangulated(const int mcords[][2], const short tot)
137 ListBase lb = {NULL, NULL};
143 dl = MEM_callocN(sizeof(DispList), "poly disp");
147 dl->verts = fp = MEM_callocN(tot * 3 * sizeof(float), "poly verts");
148 BLI_addtail(&lb, dl);
150 for (a = 0; a < tot; a++, fp += 3) {
151 fp[0] = (float)mcords[a][0];
152 fp[1] = (float)mcords[a][1];
156 BKE_displist_fill(&lb, &lb, 0);
159 dl = lb.first; /* filldisplist adds in head of list */
160 if (dl->type == DL_INDEX3) {
166 glBegin(GL_TRIANGLES);
168 glVertex3fv(fp + 3 * index[0]);
169 glVertex3fv(fp + 3 * index[1]);
170 glVertex3fv(fp + 3 * index[2]);
176 BKE_displist_free(&lb);
180 /* reads rect, and builds selection array for quick lookup */
181 /* returns if all is OK */
182 int EDBM_backbuf_border_init(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
188 if (vc->obedit == NULL || vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) {
192 buf = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
193 if (buf == NULL) return 0;
194 if (bm_vertoffs == 0) return 0;
198 /* build selection lookup */
199 selbuf = MEM_callocN(bm_vertoffs + 1, "selbuf");
201 a = (xmax - xmin + 1) * (ymax - ymin + 1);
203 if (*dr > 0 && *dr <= bm_vertoffs)
211 int EDBM_backbuf_check(unsigned int index)
213 if (selbuf == NULL) return 1;
214 if (index > 0 && index <= bm_vertoffs)
215 return selbuf[index];
219 void EDBM_backbuf_free(void)
221 if (selbuf) MEM_freeN(selbuf);
225 /* mcords is a polygon mask
227 * - draw with black in backbuffer,
228 * - grab again and compare
231 int EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
233 unsigned int *dr, *drm;
234 struct ImBuf *buf, *bufmask;
237 /* method in use for face selecting too */
238 if (vc->obedit == NULL) {
239 if (!(paint_facesel_test(vc->obact) || paint_vertsel_test(vc->obact))) {
243 else if (vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) {
247 buf = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
248 if (buf == NULL) return 0;
249 if (bm_vertoffs == 0) return 0;
254 glDisable(GL_DEPTH_TEST);
258 /* yah, opengl doesn't do concave... tsk! */
259 ED_region_pixelspace(vc->ar);
260 draw_triangulated(mcords, tot);
262 glBegin(GL_LINE_LOOP); /* for zero sized masks, lines */
263 for (a = 0; a < tot; a++) {
264 glVertex2iv(mcords[a]);
268 glFinish(); /* to be sure readpixels sees mask */
271 bufmask = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
273 if (bufmask == NULL) {
274 return 0; /* only when mem alloc fails, go crash somewhere else! */
280 /* build selection lookup */
281 selbuf = MEM_callocN(bm_vertoffs + 1, "selbuf");
283 a = (xmax - xmin + 1) * (ymax - ymin + 1);
285 if (*dr > 0 && *dr <= bm_vertoffs && *drm == 0) selbuf[*dr] = 1;
289 IMB_freeImBuf(bufmask);
294 /* circle shaped sample area */
295 int EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads)
299 short xmin, ymin, xmax, ymax, xc, yc;
302 /* method in use for face selecting too */
303 if (vc->obedit == NULL) {
304 if (!(paint_facesel_test(vc->obact) || paint_vertsel_test(vc->obact))) {
308 else if (vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) return 0;
310 xmin = xs - rads; xmax = xs + rads;
311 ymin = ys - rads; ymax = ys + rads;
312 buf = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
313 if (bm_vertoffs == 0) return 0;
314 if (buf == NULL) return 0;
318 /* build selection lookup */
319 selbuf = MEM_callocN(bm_vertoffs + 1, "selbuf");
321 for (yc = -rads; yc <= rads; yc++) {
322 for (xc = -rads; xc <= rads; xc++, dr++) {
323 if (xc * xc + yc * yc < radsq) {
324 if (*dr > 0 && *dr <= bm_vertoffs) selbuf[*dr] = 1;
334 static void findnearestvert__doClosest(void *userData, BMVert *eve, const float screen_co[2], int index)
336 struct { float mval_fl[2], pass, select, strict; float dist, lastIndex, closestIndex; BMVert *closest; } *data = userData;
338 if (data->pass == 0) {
339 if (index <= data->lastIndex)
343 if (index > data->lastIndex)
347 if (data->dist > 3) {
348 float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
349 if (BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->select) {
350 if (data->strict == 1) {
358 if (dist_test < data->dist) {
359 data->dist = dist_test;
361 data->closestIndex = index;
369 static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index)
371 BMEditMesh *em = (BMEditMesh *)handle;
372 BMVert *eve = BM_vert_at_index(em->bm, index - 1);
374 if (eve && BM_elem_flag_test(eve, BM_ELEM_SELECT)) return 0;
380 * dist (in/out): minimal distance to the nearest and at the end, actual distance
381 * sel: selection bias
382 * if SELECT, selected vertice are given a 5 pixel bias to make them further than unselect verts
383 * if 0, unselected vertice are given the bias
384 * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
386 BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *r_dist, const short sel, const short strict)
388 if (vc->v3d->drawtype > OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
394 index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance,
395 strict, vc->em, findnearestvert__backbufIndextest);
398 index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance,
402 eve = BM_vert_at_index(vc->em->bm, index - 1);
404 if (eve && distance < *r_dist) {
414 struct { float mval_fl[2], pass, select, strict; float dist, lastIndex, closestIndex; BMVert *closest; } data;
415 static int lastSelectedIndex = 0;
416 static BMVert *lastSelected = NULL;
418 if (lastSelected && BM_vert_at_index(vc->em->bm, lastSelectedIndex) != lastSelected) {
419 lastSelectedIndex = 0;
423 data.lastIndex = lastSelectedIndex;
424 data.mval_fl[0] = vc->mval[0];
425 data.mval_fl[1] = vc->mval[1];
428 data.strict = strict;
430 data.closestIndex = 0;
434 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
436 mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
440 mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
444 lastSelected = data.closest;
445 lastSelectedIndex = data.closestIndex;
451 /* returns labda for closest distance v1 to line-piece v2 - v3 */
452 float labda_PdistVL2Dfl(const float v1[2], const float v2[2], const float v3[2])
456 rc[0] = v3[0] - v2[0];
457 rc[1] = v3[1] - v2[1];
458 len = rc[0] * rc[0] + rc[1] * rc[1];
462 return (rc[0] * (v1[0] - v2[0]) + rc[1] * (v1[1] - v2[1])) / len;
465 /* note; uses v3d, so needs active 3d window */
466 static void findnearestedge__doClosest(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int UNUSED(index))
468 struct { ViewContext vc; float mval_fl[2]; float dist; BMEdge *closest; } *data = userData;
471 distance = dist_to_line_segment_v2(data->mval_fl, screen_co_a, screen_co_b);
473 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
477 if (distance < data->dist) {
478 if (data->vc.rv3d->rflag & RV3D_CLIPPING) {
479 float labda = labda_PdistVL2Dfl(data->mval_fl, screen_co_a, screen_co_b);
482 vec[0] = eed->v1->co[0] + labda * (eed->v2->co[0] - eed->v1->co[0]);
483 vec[1] = eed->v1->co[1] + labda * (eed->v2->co[1] - eed->v1->co[1]);
484 vec[2] = eed->v1->co[2] + labda * (eed->v2->co[2] - eed->v1->co[2]);
486 if (ED_view3d_clipping_test(data->vc.rv3d, vec, TRUE) == 0) {
487 data->dist = distance;
492 data->dist = distance;
497 BMEdge *EDBM_edge_find_nearest(ViewContext *vc, float *r_dist)
500 if (vc->v3d->drawtype > OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
505 view3d_validate_backbuf(vc);
507 index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_solidoffs, bm_wireoffs, &distance, 0, NULL, NULL);
508 eed = BM_edge_at_index(vc->em->bm, index - 1);
510 if (eed && distance < *r_dist) {
519 struct { ViewContext vc; float mval_fl[2]; float dist; BMEdge *closest; } data;
522 data.mval_fl[0] = vc->mval[0];
523 data.mval_fl[1] = vc->mval[1];
526 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
528 mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, V3D_PROJ_TEST_CLIP_WIN);
535 static void findnearestface__getDistance(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
537 struct { float mval_fl[2]; float dist; BMFace *toFace; } *data = userData;
539 if (efa == data->toFace) {
540 const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
542 if (dist_test < data->dist) {
543 data->dist = dist_test;
547 static void findnearestface__doClosest(void *userData, BMFace *efa, const float screen_co[2], int index)
549 struct { float mval_fl[2], pass; float dist, lastIndex, closestIndex; BMFace *closest; } *data = userData;
551 if (data->pass == 0) {
552 if (index <= data->lastIndex)
556 if (index > data->lastIndex)
560 if (data->dist > 3) {
561 const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
563 if (dist_test < data->dist) {
564 data->dist = dist_test;
566 data->closestIndex = index;
571 BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist)
574 if (vc->v3d->drawtype > OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
578 view3d_validate_backbuf(vc);
580 index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]);
581 efa = BM_face_at_index(vc->em->bm, index - 1);
584 struct { float mval_fl[2]; float dist; BMFace *toFace; } data;
586 data.mval_fl[0] = vc->mval[0];
587 data.mval_fl[1] = vc->mval[1];
588 data.dist = 0x7FFF; /* largest short */
591 mesh_foreachScreenFace(vc, findnearestface__getDistance, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
593 if ((vc->em->selectmode == SCE_SELECT_FACE) || (data.dist < *r_dist)) { /* only faces, no dist check */
602 struct { float mval_fl[2], pass; float dist, lastIndex, closestIndex; BMFace *closest; } data;
603 static int lastSelectedIndex = 0;
604 static BMFace *lastSelected = NULL;
606 if (lastSelected && BM_face_at_index(vc->em->bm, lastSelectedIndex) != lastSelected) {
607 lastSelectedIndex = 0;
611 data.lastIndex = lastSelectedIndex;
612 data.mval_fl[0] = vc->mval[0];
613 data.mval_fl[1] = vc->mval[1];
616 data.closestIndex = 0;
617 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
620 mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
622 if (data.dist > 3.0f) {
624 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
625 mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
629 lastSelected = data.closest;
630 lastSelectedIndex = data.closestIndex;
636 /* best distance based on screen coords.
637 * use em->selectmode to define how to use
638 * selected vertices and edges get disadvantage
639 * return 1 if found one
641 static int unified_findnearest(ViewContext *vc, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
643 BMEditMesh *em = vc->em;
650 /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
651 view3d_validate_backbuf(vc);
653 if (em->selectmode & SCE_SELECT_VERTEX)
654 *r_eve = EDBM_vert_find_nearest(vc, &dist, BM_ELEM_SELECT, 0);
655 if (em->selectmode & SCE_SELECT_FACE)
656 *r_efa = EDBM_face_find_nearest(vc, &dist);
658 dist -= 20; /* since edges select lines, we give dots advantage of 20 pix */
659 if (em->selectmode & SCE_SELECT_EDGE)
660 *r_eed = EDBM_edge_find_nearest(vc, &dist);
662 /* return only one of 3 pointers, for frontbuffer redraws */
664 *r_efa = NULL; *r_eve = NULL;
670 return (*r_eve || *r_eed || *r_efa);
673 /* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
674 static EnumPropertyItem prop_similar_compare_types[] = {
675 {SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
676 {SIM_CMP_GT, "GREATER", 0, "Greater", ""},
677 {SIM_CMP_LT, "LESS", 0, "Less", ""},
679 {0, NULL, 0, NULL, NULL}
682 static EnumPropertyItem prop_similar_types[] = {
683 {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""},
684 {SIMVERT_FACE, "FACE", 0, "Amount of Adjacent Faces", ""},
685 {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""},
686 {SIMVERT_EDGE, "EDGE", 0, "Amount of connecting edges", ""},
688 {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""},
689 {SIMEDGE_DIR, "DIR", 0, "Direction", ""},
690 {SIMEDGE_FACE, "FACE", 0, "Amount of Faces Around an Edge", ""},
691 {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""},
692 {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""},
693 {SIMEDGE_BEVEL, "BEVEL", 0, "Bevel", ""},
694 {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
695 {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
697 {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
698 {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
699 {SIMFACE_AREA, "AREA", 0, "Area", ""},
700 {SIMFACE_SIDES, "SIDES", 0, "Polygon Sides", ""},
701 {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
702 {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
703 {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
705 {0, NULL, 0, NULL, NULL}
708 /* selects new faces/edges/verts based on the existing selection */
710 static int similar_face_select_exec(bContext *C, wmOperator *op)
712 Object *ob = CTX_data_edit_object(C);
713 BMEditMesh *em = BMEdit_FromObject(ob);
716 /* get the type from RNA */
717 const int type = RNA_enum_get(op->ptr, "type");
718 const float thresh = RNA_float_get(op->ptr, "threshold");
719 const int compare = RNA_enum_get(op->ptr, "compare");
721 /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
722 EDBM_op_init(em, &bmop, op,
723 "similar_faces faces=%hf type=%i thresh=%f compare=%i",
724 BM_ELEM_SELECT, type, thresh, compare);
726 /* execute the operator */
727 BMO_op_exec(em->bm, &bmop);
729 /* clear the existing selection */
730 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
732 /* select the output */
733 BMO_slot_buffer_hflag_enable(em->bm, &bmop, "faceout", BM_ALL, BM_ELEM_SELECT, TRUE);
735 /* finish the operator */
736 if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
737 return OPERATOR_CANCELLED;
740 EDBM_update_generic(C, em, FALSE);
743 return OPERATOR_FINISHED;
746 /* ***************************************************** */
750 /* wrap the above function but do selection flushing edge to face */
751 static int similar_edge_select_exec(bContext *C, wmOperator *op)
753 Object *ob = CTX_data_edit_object(C);
754 BMEditMesh *em = BMEdit_FromObject(ob);
757 /* get the type from RNA */
758 const int type = RNA_enum_get(op->ptr, "type");
759 const float thresh = RNA_float_get(op->ptr, "threshold");
760 const int compare = RNA_enum_get(op->ptr, "compare");
762 /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
763 EDBM_op_init(em, &bmop, op,
764 "similar_edges edges=%he type=%i thresh=%f compare=%i",
765 BM_ELEM_SELECT, type, thresh, compare);
767 /* execute the operator */
768 BMO_op_exec(em->bm, &bmop);
770 /* clear the existing selection */
771 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
773 /* select the output */
774 BMO_slot_buffer_hflag_enable(em->bm, &bmop, "edgeout", BM_ALL, BM_ELEM_SELECT, TRUE);
775 EDBM_selectmode_flush(em);
777 /* finish the operator */
778 if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
779 return OPERATOR_CANCELLED;
782 EDBM_update_generic(C, em, FALSE);
785 return OPERATOR_FINISHED;
788 /* ********************************* */
792 * mode 1: same normal
793 * mode 2: same number of face users
794 * mode 3: same vertex groups
796 static int similar_vert_select_exec(bContext *C, wmOperator *op)
798 Object *ob = CTX_data_edit_object(C);
799 BMEditMesh *em = BMEdit_FromObject(ob);
801 /* get the type from RNA */
802 const int type = RNA_enum_get(op->ptr, "type");
803 float thresh = RNA_float_get(op->ptr, "threshold");
804 const int compare = RNA_enum_get(op->ptr, "compare");
806 /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
807 EDBM_op_init(em, &bmop, op,
808 "similar_verts verts=%hv type=%i thresh=%f compare=%i",
809 BM_ELEM_SELECT, type, thresh, compare);
811 /* execute the operator */
812 BMO_op_exec(em->bm, &bmop);
814 /* clear the existing selection */
815 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
817 /* select the output */
818 BMO_slot_buffer_hflag_enable(em->bm, &bmop, "vertout", BM_ALL, BM_ELEM_SELECT, TRUE);
820 /* finish the operator */
821 if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
822 return OPERATOR_CANCELLED;
825 EDBM_selectmode_flush(em);
827 EDBM_update_generic(C, em, FALSE);
830 return OPERATOR_FINISHED;
833 static int edbm_select_similar_exec(bContext *C, wmOperator *op)
835 ToolSettings *ts = CTX_data_tool_settings(C);
836 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "threshold");
838 const int type = RNA_enum_get(op->ptr, "type");
840 if (!RNA_property_is_set(op->ptr, prop)) {
841 RNA_property_float_set(op->ptr, prop, ts->select_thresh);
844 ts->select_thresh = RNA_property_float_get(op->ptr, prop);
847 if (type < 100) return similar_vert_select_exec(C, op);
848 else if (type < 200) return similar_edge_select_exec(C, op);
849 else return similar_face_select_exec(C, op);
852 static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
857 if (!C) /* needed for docs and i18n tools */
858 return prop_similar_types;
860 obedit = CTX_data_edit_object(C);
862 if (obedit && obedit->type == OB_MESH) {
863 EnumPropertyItem *item = NULL;
865 BMEditMesh *em = BMEdit_FromObject(obedit);
867 if (em->selectmode & SCE_SELECT_VERTEX) {
868 for (a = SIMVERT_NORMAL; a < SIMEDGE_LENGTH; a++) {
869 RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
872 else if (em->selectmode & SCE_SELECT_EDGE) {
873 for (a = SIMEDGE_LENGTH; a < SIMFACE_MATERIAL; a++) {
874 RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
877 else if (em->selectmode & SCE_SELECT_FACE) {
878 for (a = SIMFACE_MATERIAL; a <= SIMFACE_COPLANAR; a++) {
879 RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
882 RNA_enum_item_end(&item, &totitem);
892 void MESH_OT_select_similar(wmOperatorType *ot)
897 ot->name = "Select Similar";
898 ot->idname = "MESH_OT_select_similar";
899 ot->description = "Select similar vertices, edges or faces by property types";
902 ot->invoke = WM_menu_invoke;
903 ot->exec = edbm_select_similar_exec;
904 ot->poll = ED_operator_editmesh;
907 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
910 prop = ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", "");
911 RNA_def_enum_funcs(prop, select_similar_type_itemf);
913 RNA_def_enum(ot->srna, "compare", prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
915 RNA_def_float(ot->srna, "threshold", 0.0, 0.0, 1.0, "Threshold", "", 0.0, 1.0);
918 /* ***************************************************** */
920 /* **************** LOOP SELECTS *************** */
922 static void walker_select(BMEditMesh *em, int walkercode, void *start, int select)
928 BMW_init(&walker, bm, walkercode,
929 BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
930 BMW_FLAG_TEST_HIDDEN,
932 ele = BMW_begin(&walker, start);
933 for (; ele; ele = BMW_step(&walker)) {
935 BM_select_history_remove(bm, ele);
937 BM_elem_select_set(bm, ele, select);
942 static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op)
944 Object *obedit = CTX_data_edit_object(C);
945 BMEditMesh *em = BMEdit_FromObject(obedit);
949 int looptype = RNA_boolean_get(op->ptr, "ring");
954 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
955 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
960 edarray = MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array");
963 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
964 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
965 edarray[edindex] = eed;
971 for (edindex = 0; edindex < totedgesel; edindex += 1) {
972 eed = edarray[edindex];
973 walker_select(em, BMW_EDGERING, eed, TRUE);
975 EDBM_selectmode_flush(em);
978 for (edindex = 0; edindex < totedgesel; edindex += 1) {
979 eed = edarray[edindex];
980 walker_select(em, BMW_LOOP, eed, TRUE);
982 EDBM_selectmode_flush(em);
985 // if (EM_texFaceCheck())
987 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
989 return OPERATOR_FINISHED;
992 void MESH_OT_loop_multi_select(wmOperatorType *ot)
995 ot->name = "Multi Select Loops";
996 ot->idname = "MESH_OT_loop_multi_select";
997 ot->description = "Select a loop of connected edges by connection type";
1000 ot->exec = edbm_loop_multiselect_exec;
1001 ot->poll = ED_operator_editmesh;
1004 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1007 RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
1011 /* ***************** MAIN MOUSE SELECTION ************** */
1014 /* ***************** loop select (non modal) ************** */
1016 static void mouse_mesh_loop(bContext *C, int mval[2], short extend, short ring)
1025 em_setup_viewcontext(C, &vc);
1026 mvalf[0] = (float)(vc.mval[0] = mval[0]);
1027 mvalf[1] = (float)(vc.mval[1] = mval[1]);
1030 /* no afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad */
1031 view3d_validate_backbuf(&vc);
1033 eed = EDBM_edge_find_nearest(&vc, &dist);
1036 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
1039 if (BM_elem_flag_test(eed, BM_ELEM_SELECT) == 0) {
1046 if (em->selectmode & SCE_SELECT_FACE) {
1047 walker_select(em, BMW_FACELOOP, eed, select);
1049 else if (em->selectmode & SCE_SELECT_EDGE) {
1051 walker_select(em, BMW_EDGERING, eed, select);
1053 walker_select(em, BMW_LOOP, eed, select);
1055 else if (em->selectmode & SCE_SELECT_VERTEX) {
1057 walker_select(em, BMW_EDGERING, eed, select);
1060 walker_select(em, BMW_LOOP, eed, select);
1063 EDBM_selectmode_flush(em);
1065 /* sets as active, useful for other tools */
1067 if (em->selectmode & SCE_SELECT_VERTEX) {
1068 /* Find nearest vert from mouse
1069 * (initialize to large values incase only one vertex can be projected) */
1070 float v1_co[2], v2_co[2];
1071 float length_1 = FLT_MAX;
1072 float length_2 = FLT_MAX;
1074 /* We can't be sure this has already been set... */
1075 ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
1077 if (ED_view3d_project_float_object(vc.ar, eed->v1->co, v1_co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
1078 length_1 = len_squared_v2v2(mvalf, v1_co);
1081 if (ED_view3d_project_float_object(vc.ar, eed->v2->co, v2_co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
1082 length_2 = len_squared_v2v2(mvalf, v2_co);
1085 printf("mouse to v1: %f\nmouse to v2: %f\n", len_squared_v2v2(mvalf, v1_co),
1086 len_squared_v2v2(mvalf, v2_co));
1088 BM_select_history_store(em->bm, (length_1 < length_2) ? eed->v1 : eed->v2);
1090 else if (em->selectmode & SCE_SELECT_EDGE) {
1091 BM_select_history_store(em->bm, eed);
1093 else if (em->selectmode & SCE_SELECT_FACE) {
1094 /* Select the face of eed which is the nearest of mouse. */
1095 BMFace *f, *efa = NULL;
1097 float best_dist = MAXFLOAT;
1099 /* We can't be sure this has already been set... */
1100 ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
1102 BM_ITER_ELEM(f, &iterf, eed, BM_FACES_OF_EDGE) {
1103 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
1107 BM_face_calc_center_mean(f, cent);
1108 if (ED_view3d_project_float_object(vc.ar, cent, co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
1109 tdist = len_squared_v2v2(mvalf, co);
1110 if (tdist < best_dist) {
1111 /* printf("Best face: %p (%f)\n", f, tdist);*/
1119 BM_active_face_set(em->bm, efa);
1120 BM_select_history_store(em->bm, efa);
1125 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit);
1129 static int edbm_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
1132 view3d_operator_needs_opengl(C);
1134 mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"),
1135 RNA_boolean_get(op->ptr, "ring"));
1137 /* cannot do tweaks for as long this keymap is after transform map */
1138 return OPERATOR_FINISHED;
1141 void MESH_OT_loop_select(wmOperatorType *ot)
1144 ot->name = "Loop Select";
1145 ot->idname = "MESH_OT_loop_select";
1146 ot->description = "Select a loop of connected edges";
1149 ot->invoke = edbm_select_loop_invoke;
1150 ot->poll = ED_operator_editmesh_region_view3d;
1153 ot->flag = OPTYPE_UNDO;
1156 RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "Extend the selection");
1157 RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "Select ring");
1160 void MESH_OT_edgering_select(wmOperatorType *ot)
1163 ot->name = "Edge Ring Select";
1164 ot->idname = "MESH_OT_edgering_select";
1165 ot->description = "Select an edge ring";
1168 ot->invoke = edbm_select_loop_invoke;
1169 ot->poll = ED_operator_editmesh_region_view3d;
1172 ot->flag = OPTYPE_UNDO;
1174 RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
1175 RNA_def_boolean(ot->srna, "ring", 1, "Select Ring", "Select ring");
1178 /* ******************* generic tag_shortest_path and helpers ****************** */
1180 static float step_cost_3_v3(const float v1[3], const float v2[3], const float v3[3])
1182 float cost, d1[3], d2[3];
1185 /* The cost is based on the simple sum of the length of the two edgees... */
1186 sub_v3_v3v3(d1, v2, v1);
1187 sub_v3_v3v3(d2, v3, v2);
1188 cost = len_v3(d1) + len_v3(d2);
1190 /* but is biased to give higher values to sharp turns, so that it will take
1191 * paths with fewer "turns" when selecting between equal-weighted paths between
1193 cost = cost + 0.5f * cost * (2.0f - sqrtf(fabsf(dot_v3v3(d1, d2))));
1198 /* ******************* edgetag_shortest_path and helpers ****************** */
1200 static float edgetag_cut_cost(BMEdge *e1, BMEdge *e2, BMVert *v)
1202 BMVert *v1 = BM_edge_other_vert(e1, v);
1203 BMVert *v2 = BM_edge_other_vert(e2, v);
1204 return step_cost_3_v3(v1->co, v->co, v2->co);
1207 static void edgetag_add_adjacent(Heap *heap, BMEdge *e1, BMEdge **edges_prev, float *cost)
1215 const int e1_index = BM_elem_index_get(e1);
1217 BM_ITER_ELEM (v, &viter, e1, BM_VERTS_OF_EDGE) {
1218 BM_ITER_ELEM (e2, &eiter, v, BM_EDGES_OF_VERT) {
1219 if (!BM_elem_flag_test(e2, BM_ELEM_TAG)) {
1220 /* we know 'e2' is not visited, check it out! */
1221 const int e2_index = BM_elem_index_get(e2);
1222 const float cost_cut = edgetag_cut_cost(e1, e2, v);
1223 const float cost_new = cost[e1_index] + cost_cut;
1225 if (cost[e2_index] > cost_new) {
1226 cost[e2_index] = cost_new;
1227 edges_prev[e2_index] = e1;
1228 BLI_heap_insert(heap, cost_new, e2);
1235 static void edgetag_context_set(BMesh *bm, Scene *scene, BMEdge *e, int val)
1238 switch (scene->toolsettings->edge_mode) {
1239 case EDGE_MODE_SELECT:
1240 BM_edge_select_set(bm, e, val);
1242 case EDGE_MODE_TAG_SEAM:
1243 BM_elem_flag_set(e, BM_ELEM_SEAM, val);
1245 case EDGE_MODE_TAG_SHARP:
1246 BM_elem_flag_set(e, BM_ELEM_SMOOTH, !val);
1248 case EDGE_MODE_TAG_CREASE:
1249 BM_elem_float_data_set(&bm->edata, e, CD_CREASE, (val) ? 1.0f : 0.0f);
1251 case EDGE_MODE_TAG_BEVEL:
1252 BM_elem_float_data_set(&bm->edata, e, CD_BWEIGHT, (val) ? 1.0f : 0.0f);
1257 static int edgetag_context_check(Scene *scene, BMesh *bm, BMEdge *e)
1259 switch (scene->toolsettings->edge_mode) {
1260 case EDGE_MODE_SELECT:
1261 return BM_elem_flag_test(e, BM_ELEM_SELECT) ? TRUE : FALSE;
1262 case EDGE_MODE_TAG_SEAM:
1263 return BM_elem_flag_test(e, BM_ELEM_SEAM);
1264 case EDGE_MODE_TAG_SHARP:
1265 return !BM_elem_flag_test(e, BM_ELEM_SMOOTH);
1266 case EDGE_MODE_TAG_CREASE:
1267 return BM_elem_float_data_get(&bm->edata, e, CD_CREASE) ? TRUE : FALSE;
1268 case EDGE_MODE_TAG_BEVEL:
1269 return BM_elem_float_data_get(&bm->edata, e, CD_BWEIGHT) ? TRUE : FALSE;
1274 static int edgetag_shortest_path(Scene *scene, BMesh *bm, BMEdge *e_src, BMEdge *e_dst)
1276 /* BM_ELEM_TAG flag is used to store visited edges */
1281 BMEdge **edges_prev;
1284 /* note, would pass BM_EDGE except we are looping over all edges anyway */
1285 BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */);
1287 BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) {
1288 if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == FALSE) {
1289 BM_elem_flag_disable(e, BM_ELEM_TAG);
1292 BM_elem_flag_enable(e, BM_ELEM_TAG);
1295 BM_elem_index_set(e, i); /* set_inline */
1297 bm->elem_index_dirty &= ~BM_EDGE;
1300 totedge = bm->totedge;
1301 edges_prev = MEM_callocN(sizeof(*edges_prev) * totedge, "SeamPathPrevious");
1302 cost = MEM_mallocN(sizeof(*cost) * totedge, "SeamPathCost");
1304 fill_vn_fl(cost, totedge, 1e20f);
1307 * Arrays are now filled as follows:
1309 * As the search continues, prevedge[n] will be the previous edge on the shortest
1310 * path found so far to edge n. The visitedhash will of course contain entries
1311 * for edges that have been visited, cost[n] will contain the length of the shortest
1312 * path to edge n found so far, Finally, heap is a priority heap which is built on the
1313 * the same data as the cost array, but inverted: it is a worklist of edges prioritized
1314 * by the shortest path found so far to the edge.
1317 /* regular dijkstra shortest path, but over edges instead of vertices */
1318 heap = BLI_heap_new();
1319 BLI_heap_insert(heap, 0.0f, e_src);
1320 cost[BM_elem_index_get(e_src)] = 0.0f;
1324 while (!BLI_heap_is_empty(heap)) {
1325 e = BLI_heap_popmin(heap);
1330 if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
1331 BM_elem_flag_enable(e, BM_ELEM_TAG);
1332 edgetag_add_adjacent(heap, e, edges_prev, cost);
1337 short all_set = TRUE;
1339 /* Check whether the path is already completely tagged.
1340 * if it is, the tags will be cleared instead of set. */
1343 if (!edgetag_context_check(scene, bm, e)) {
1347 } while ((e = edges_prev[BM_elem_index_get(e)]));
1349 /* Follow path back and source and add or remove tags */
1352 edgetag_context_set(bm, scene, e, !all_set);
1353 } while ((e = edges_prev[BM_elem_index_get(e)]));
1356 MEM_freeN(edges_prev);
1358 BLI_heap_free(heap, NULL);
1363 /* ******************* mesh shortest path select, uses prev-selected edge ****************** */
1365 /* since you want to create paths with multiple selects, it doesn't have extend option */
1366 static int mouse_mesh_shortest_path_edge(bContext *C, ViewContext *vc)
1368 BMEditMesh *em = vc->em;
1372 e_dst = EDBM_edge_find_nearest(vc, &dist);
1374 Mesh *me = vc->obedit->data;
1377 if (em->bm->selected.last) {
1378 BMEditSelection *ese = em->bm->selected.last;
1380 if (ese && ese->htype == BM_EDGE) {
1382 e_act = (BMEdge *)ese->ele;
1383 if (e_act != e_dst) {
1384 if (edgetag_shortest_path(vc->scene, em->bm, e_act, e_dst)) {
1385 BM_select_history_remove(em->bm, e_act);
1392 int act = (edgetag_context_check(vc->scene, em->bm, e_dst) == 0);
1393 edgetag_context_set(em->bm, vc->scene, e_dst, act); /* switch the edge option */
1396 EDBM_selectmode_flush(em);
1398 /* even if this is selected it may not be in the selection list */
1399 if (edgetag_context_check(vc->scene, em->bm, e_dst) == 0)
1400 BM_select_history_remove(em->bm, e_dst);
1402 BM_select_history_store(em->bm, e_dst);
1404 /* force drawmode for mesh */
1405 switch (CTX_data_tool_settings(C)->edge_mode) {
1407 case EDGE_MODE_TAG_SEAM:
1408 me->drawflag |= ME_DRAWSEAMS;
1409 ED_uvedit_live_unwrap(vc->scene, vc->obedit);
1411 case EDGE_MODE_TAG_SHARP:
1412 me->drawflag |= ME_DRAWSHARP;
1414 case EDGE_MODE_TAG_CREASE:
1415 me->drawflag |= ME_DRAWCREASES;
1417 case EDGE_MODE_TAG_BEVEL:
1418 me->drawflag |= ME_DRAWBWEIGHTS;
1422 EDBM_update_generic(C, em, FALSE);
1432 /* ******************* facetag_shortest_path and helpers ****************** */
1435 static float facetag_cut_cost(BMFace *f1, BMFace *f2, BMEdge *e)
1441 BM_face_calc_center_mean(f1, f1_cent);
1442 BM_face_calc_center_mean(f2, f2_cent);
1443 mid_v3_v3v3(e_cent, e->v1->co, e->v2->co);
1445 return step_cost_3_v3(f1_cent, e_cent, f2_cent);
1448 static void facetag_add_adjacent(Heap *heap, BMFace *f1, BMFace **faces_prev, float *cost)
1454 const int f1_index = BM_elem_index_get(f1);
1456 /* loop over faces of face, but do so by first looping over loops */
1457 BM_ITER_ELEM (l2, &liter, f1, BM_LOOPS_OF_FACE) {
1461 l_iter = l_first = l2;
1464 if (!BM_elem_flag_test(f2, BM_ELEM_TAG)) {
1465 /* we know 'f2' is not visited, check it out! */
1466 const int f2_index = BM_elem_index_get(f2);
1467 const float cost_cut = facetag_cut_cost(f1, f2, l_iter->e);
1468 const float cost_new = cost[f1_index] + cost_cut;
1470 if (cost[f2_index] > cost_new) {
1471 cost[f2_index] = cost_new;
1472 faces_prev[f2_index] = f1;
1473 BLI_heap_insert(heap, cost_new, f2);
1476 } while ((l_iter = l_iter->radial_next) != l_first);
1480 static void facetag_context_set(BMesh *bm, Scene *UNUSED(scene), BMFace *f, int val)
1482 BM_face_select_set(bm, f, val);
1485 static int facetag_context_check(Scene *UNUSED(scene), BMesh *UNUSED(bm), BMFace *f)
1487 return BM_elem_flag_test(f, BM_ELEM_SELECT) ? 1 : 0;
1490 static int facetag_shortest_path(Scene *scene, BMesh *bm, BMFace *f_src, BMFace *f_dst)
1492 /* BM_ELEM_TAG flag is used to store visited edges */
1497 BMFace **faces_prev;
1500 /* note, would pass BM_EDGE except we are looping over all faces anyway */
1501 // BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */); // NOT NEEDED FOR FACETAG
1503 BM_ITER_MESH_INDEX (f, &fiter, bm, BM_FACES_OF_MESH, i) {
1504 if (BM_elem_flag_test(f, BM_ELEM_HIDDEN) == FALSE) {
1505 BM_elem_flag_disable(f, BM_ELEM_TAG);
1508 BM_elem_flag_enable(f, BM_ELEM_TAG);
1511 BM_elem_index_set(f, i); /* set_inline */
1513 bm->elem_index_dirty &= ~BM_FACE;
1516 totface = bm->totface;
1517 faces_prev = MEM_callocN(sizeof(*faces_prev) * totface, "SeamPathPrevious");
1518 cost = MEM_mallocN(sizeof(*cost) * totface, "SeamPathCost");
1520 fill_vn_fl(cost, totface, 1e20f);
1523 * Arrays are now filled as follows:
1525 * As the search continues, faces_prev[n] will be the previous face on the shortest
1526 * path found so far to face n. The visitedhash will of course contain entries
1527 * for faces that have been visited, cost[n] will contain the length of the shortest
1528 * path to face n found so far, Finally, heap is a priority heap which is built on the
1529 * the same data as the cost array, but inverted: it is a worklist of faces prioritized
1530 * by the shortest path found so far to the face.
1533 /* regular dijkstra shortest path, but over faces instead of vertices */
1534 heap = BLI_heap_new();
1535 BLI_heap_insert(heap, 0.0f, f_src);
1536 cost[BM_elem_index_get(f_src)] = 0.0f;
1540 while (!BLI_heap_is_empty(heap)) {
1541 f = BLI_heap_popmin(heap);
1546 if (!BM_elem_flag_test(f, BM_ELEM_TAG)) {
1547 BM_elem_flag_enable(f, BM_ELEM_TAG);
1548 facetag_add_adjacent(heap, f, faces_prev, cost);
1553 short all_set = TRUE;
1555 /* Check whether the path is already completely tagged.
1556 * if it is, the tags will be cleared instead of set. */
1559 if (!facetag_context_check(scene, bm, f)) {
1563 } while ((f = faces_prev[BM_elem_index_get(f)]));
1565 /* Follow path back and source and add or remove tags */
1568 facetag_context_set(bm, scene, f, !all_set);
1569 } while ((f = faces_prev[BM_elem_index_get(f)]));
1572 MEM_freeN(faces_prev);
1574 BLI_heap_free(heap, NULL);
1579 static int mouse_mesh_shortest_path_face(bContext *C, ViewContext *vc)
1581 BMEditMesh *em = vc->em;
1585 f_dst = EDBM_face_find_nearest(vc, &dist);
1588 BMFace *f_act = BM_active_face_get(em->bm, FALSE, TRUE);
1591 if (f_act != f_dst) {
1592 if (facetag_shortest_path(vc->scene, em->bm, f_act, f_dst)) {
1593 BM_select_history_remove(em->bm, f_act);
1599 int act = (facetag_context_check(vc->scene, em->bm, f_dst) == 0);
1600 facetag_context_set(em->bm, vc->scene, f_dst, act); /* switch the face option */
1603 EDBM_selectmode_flush(em);
1605 /* even if this is selected it may not be in the selection list */
1606 if (facetag_context_check(vc->scene, em->bm, f_dst) == 0)
1607 BM_select_history_remove(em->bm, f_dst);
1609 BM_select_history_store(em->bm, f_dst);
1611 BM_active_face_set(em->bm, f_dst);
1613 EDBM_update_generic(C, em, FALSE);
1623 /* ******************* operator for edge and face tag ****************** */
1625 static int edbm_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
1630 view3d_operator_needs_opengl(C);
1632 em_setup_viewcontext(C, &vc);
1633 vc.mval[0] = event->mval[0];
1634 vc.mval[1] = event->mval[1];
1637 if (em->selectmode & SCE_SELECT_EDGE) {
1638 if (mouse_mesh_shortest_path_edge(C, &vc)) {
1639 return OPERATOR_FINISHED;
1642 return OPERATOR_PASS_THROUGH;
1645 else if (em->selectmode & SCE_SELECT_FACE) {
1646 if (mouse_mesh_shortest_path_face(C, &vc)) {
1647 return OPERATOR_FINISHED;
1650 return OPERATOR_PASS_THROUGH;
1654 return OPERATOR_PASS_THROUGH;
1657 static int edbm_shortest_path_select_poll(bContext *C)
1659 if (ED_operator_editmesh_region_view3d(C)) {
1660 Object *obedit = CTX_data_edit_object(C);
1661 BMEditMesh *em = BMEdit_FromObject(obedit);
1662 return (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_FACE)) != 0;
1667 void MESH_OT_select_shortest_path(wmOperatorType *ot)
1670 ot->name = "Shortest Path Select";
1671 ot->idname = "MESH_OT_select_shortest_path";
1672 ot->description = "Select shortest path between two selections";
1675 ot->invoke = edbm_shortest_path_select_invoke;
1676 ot->poll = edbm_shortest_path_select_poll;
1679 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1682 RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
1685 /* ************************************************** */
1686 /* here actual select happens */
1687 /* gets called via generic mouse select operator */
1688 int EDBM_select_pick(bContext *C, const int mval[2], short extend, short deselect, short toggle)
1695 /* setup view context for argument to callbacks */
1696 em_setup_viewcontext(C, &vc);
1697 vc.mval[0] = mval[0];
1698 vc.mval[1] = mval[1];
1700 if (unified_findnearest(&vc, &eve, &eed, &efa)) {
1702 /* Deselect everything */
1703 if (extend == 0 && deselect == 0 && toggle == 0)
1704 EDBM_flag_disable_all(vc.em, BM_ELEM_SELECT);
1708 /* set the last selected face */
1709 BM_active_face_set(vc.em->bm, efa);
1711 /* Work-around: deselect first, so we can guarantee it will */
1712 /* be active even if it was already selected */
1713 BM_select_history_remove(vc.em->bm, efa);
1714 BM_face_select_set(vc.em->bm, efa, FALSE);
1715 BM_select_history_store(vc.em->bm, efa);
1716 BM_face_select_set(vc.em->bm, efa, TRUE);
1718 else if (deselect) {
1719 BM_select_history_remove(vc.em->bm, efa);
1720 BM_face_select_set(vc.em->bm, efa, FALSE);
1723 /* set the last selected face */
1724 BM_active_face_set(vc.em->bm, efa);
1726 if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1727 BM_select_history_store(vc.em->bm, efa);
1728 BM_face_select_set(vc.em->bm, efa, TRUE);
1731 BM_select_history_remove(vc.em->bm, efa);
1732 BM_face_select_set(vc.em->bm, efa, FALSE);
1738 /* Work-around: deselect first, so we can guarantee it will */
1739 /* be active even if it was already selected */
1740 BM_select_history_remove(vc.em->bm, eed);
1741 BM_edge_select_set(vc.em->bm, eed, FALSE);
1742 BM_select_history_store(vc.em->bm, eed);
1743 BM_edge_select_set(vc.em->bm, eed, TRUE);
1745 else if (deselect) {
1746 BM_select_history_remove(vc.em->bm, eed);
1747 BM_edge_select_set(vc.em->bm, eed, FALSE);
1750 if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1751 BM_select_history_store(vc.em->bm, eed);
1752 BM_edge_select_set(vc.em->bm, eed, TRUE);
1755 BM_select_history_remove(vc.em->bm, eed);
1756 BM_edge_select_set(vc.em->bm, eed, FALSE);
1762 /* Work-around: deselect first, so we can guarantee it will */
1763 /* be active even if it was already selected */
1764 BM_select_history_remove(vc.em->bm, eve);
1765 BM_vert_select_set(vc.em->bm, eve, FALSE);
1766 BM_select_history_store(vc.em->bm, eve);
1767 BM_vert_select_set(vc.em->bm, eve, TRUE);
1769 else if (deselect) {
1770 BM_select_history_remove(vc.em->bm, eve);
1771 BM_vert_select_set(vc.em->bm, eve, FALSE);
1774 if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
1775 BM_select_history_store(vc.em->bm, eve);
1776 BM_vert_select_set(vc.em->bm, eve, TRUE);
1779 BM_select_history_remove(vc.em->bm, eve);
1780 BM_vert_select_set(vc.em->bm, eve, FALSE);
1785 EDBM_selectmode_flush(vc.em);
1787 /* change active material on object */
1788 if (efa && efa->mat_nr != vc.obedit->actcol - 1) {
1789 vc.obedit->actcol = efa->mat_nr + 1;
1790 vc.em->mat_nr = efa->mat_nr;
1792 WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING, NULL);
1796 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit);
1803 static void edbm_strip_selections(BMEditMesh *em)
1805 BMEditSelection *ese, *nextese;
1807 if (!(em->selectmode & SCE_SELECT_VERTEX)) {
1808 ese = em->bm->selected.first;
1810 nextese = ese->next;
1811 if (ese->htype == BM_VERT) BLI_freelinkN(&(em->bm->selected), ese);
1815 if (!(em->selectmode & SCE_SELECT_EDGE)) {
1816 ese = em->bm->selected.first;
1818 nextese = ese->next;
1819 if (ese->htype == BM_EDGE) BLI_freelinkN(&(em->bm->selected), ese);
1823 if (!(em->selectmode & SCE_SELECT_FACE)) {
1824 ese = em->bm->selected.first;
1826 nextese = ese->next;
1827 if (ese->htype == BM_FACE) BLI_freelinkN(&(em->bm->selected), ese);
1833 /* when switching select mode, makes sure selection is consistent for editing */
1834 /* also for paranoia checks to make sure edge or face mode works */
1835 void EDBM_selectmode_set(BMEditMesh *em)
1842 em->bm->selectmode = em->selectmode;
1844 edbm_strip_selections(em); /* strip BMEditSelections from em->selected that are not relevant to new mode */
1846 if (em->selectmode & SCE_SELECT_VERTEX) {
1847 EDBM_select_flush(em);
1849 else if (em->selectmode & SCE_SELECT_EDGE) {
1850 /* deselect vertices, and select again based on edge select */
1851 eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
1852 for (; eve; eve = BM_iter_step(&iter)) BM_vert_select_set(em->bm, eve, FALSE);
1854 eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
1855 for (; eed; eed = BM_iter_step(&iter)) {
1856 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1857 BM_edge_select_set(em->bm, eed, TRUE);
1861 /* selects faces based on edge status */
1862 EDBM_selectmode_flush(em);
1864 else if (em->selectmode & SCE_SELECT_FACE) {
1865 /* deselect eges, and select again based on face select */
1866 eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
1867 for (; eed; eed = BM_iter_step(&iter)) BM_edge_select_set(em->bm, eed, FALSE);
1869 efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL);
1870 for (; efa; efa = BM_iter_step(&iter)) {
1871 if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1872 BM_face_select_set(em->bm, efa, TRUE);
1878 void EDBM_selectmode_convert(BMEditMesh *em, const short selectmode_old, const short selectmode_new)
1884 /* first tag-to-select, then select --- this avoids a feedback loop */
1886 /* have to find out what the selectionmode was previously */
1887 if (selectmode_old == SCE_SELECT_VERTEX) {
1888 if (selectmode_new == SCE_SELECT_EDGE) {
1889 /* select all edges associated with every selected vert */
1890 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1891 BM_elem_flag_set(eed, BM_ELEM_TAG, BM_edge_is_any_vert_flag_test(eed, BM_ELEM_SELECT));
1894 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1895 if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
1896 BM_edge_select_set(em->bm, eed, TRUE);
1900 else if (selectmode_new == SCE_SELECT_FACE) {
1901 /* select all faces associated with every selected vert */
1902 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1903 BM_elem_flag_set(efa, BM_ELEM_TAG, BM_face_is_any_vert_flag_test(efa, BM_ELEM_SELECT));
1906 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1907 if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
1908 BM_face_select_set(em->bm, efa, TRUE);
1913 else if (selectmode_old == SCE_SELECT_EDGE) {
1914 if (selectmode_new == SCE_SELECT_FACE) {
1915 /* select all faces associated with every selected edge */
1916 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1917 BM_elem_flag_set(efa, BM_ELEM_TAG, BM_face_is_any_edge_flag_test(efa, BM_ELEM_SELECT));
1920 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1921 if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
1922 BM_face_select_set(em->bm, efa, TRUE);
1930 void EDBM_deselect_by_material(BMEditMesh *em, const short index, const short select)
1935 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1936 if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
1938 if (efa->mat_nr == index) {
1939 BM_face_select_set(em->bm, efa, select);
1944 void EDBM_select_toggle_all(BMEditMesh *em) /* exported for UV */
1946 if (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel)
1947 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
1949 EDBM_flag_enable_all(em, BM_ELEM_SELECT);
1952 void EDBM_select_swap(BMEditMesh *em) /* exported for UV */
1959 if (em->bm->selectmode & SCE_SELECT_VERTEX) {
1960 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
1961 if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
1963 BM_vert_select_set(em->bm, eve, !BM_elem_flag_test(eve, BM_ELEM_SELECT));
1966 else if (em->selectmode & SCE_SELECT_EDGE) {
1967 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1968 if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
1970 BM_edge_select_set(em->bm, eed, !BM_elem_flag_test(eed, BM_ELEM_SELECT));
1974 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1975 if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
1977 BM_face_select_set(em->bm, efa, !BM_elem_flag_test(efa, BM_ELEM_SELECT));
1981 // if (EM_texFaceCheck())
1984 int EDBM_select_interior_faces(BMEditMesh *em)
1994 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1995 if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
2000 BM_ITER_ELEM (eed, &eiter, efa, BM_EDGES_OF_FACE) {
2001 if (BM_edge_face_count(eed) < 3) {
2008 BM_face_select_set(bm, efa, TRUE);
2016 static void linked_limit_default(bContext *C, wmOperator *op)
2018 if (!RNA_struct_property_is_set(op->ptr, "limit")) {
2019 Object *obedit = CTX_data_edit_object(C);
2020 BMEditMesh *em = BMEdit_FromObject(obedit);
2021 if (em->selectmode == SCE_SELECT_FACE)
2022 RNA_boolean_set(op->ptr, "limit", TRUE);
2024 RNA_boolean_set(op->ptr, "limit", FALSE);
2028 static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
2030 Object *obedit = CTX_data_edit_object(C);
2038 int sel = !RNA_boolean_get(op->ptr, "deselect");
2042 linked_limit_default(C, op);
2044 limit = RNA_boolean_get(op->ptr, "limit");
2046 /* unified_finednearest needs ogl */
2047 view3d_operator_needs_opengl(C);
2049 /* setup view context for argument to callbacks */
2050 em_setup_viewcontext(C, &vc);
2053 if (em->bm->totedge == 0)
2054 return OPERATOR_CANCELLED;
2058 vc.mval[0] = event->mval[0];
2059 vc.mval[1] = event->mval[1];
2061 /* return warning! */
2063 if (unified_findnearest(&vc, &eve, &eed, &efa) == 0) {
2064 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
2066 return OPERATOR_CANCELLED;
2069 if (em->selectmode == SCE_SELECT_FACE) {
2073 return OPERATOR_CANCELLED;
2076 /* hflag no-seam --> bmo-tag */
2077 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
2078 /* BMESH_TODO, don't use 'BM_ELEM_SELECT' here, its a HFLAG only! */
2079 BMO_elem_flag_set(bm, e, BM_ELEM_SELECT, !BM_elem_flag_test(e, BM_ELEM_SEAM));
2084 BMW_init(&walker, bm, BMW_ISLAND,
2085 BMW_MASK_NOP, limit ? BM_ELEM_SELECT : BMW_MASK_NOP, BMW_MASK_NOP,
2086 BMW_FLAG_TEST_HIDDEN,
2089 e = BMW_begin(&walker, efa);
2090 for (; efa; efa = BMW_step(&walker)) {
2091 BM_face_select_set(bm, efa, sel);
2097 eed = BM_FACE_FIRST_LOOP(efa)->e;
2100 if (!eve || !eve->e)
2101 return OPERATOR_CANCELLED;
2106 BMW_init(&walker, bm, BMW_SHELL,
2107 BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
2108 BMW_FLAG_TEST_HIDDEN,
2111 e = BMW_begin(&walker, eed->v1);
2112 for (; e; e = BMW_step(&walker)) {
2113 BM_edge_select_set(bm, e, sel);
2117 EDBM_selectmode_flush(em);
2120 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
2121 return OPERATOR_FINISHED;
2124 void MESH_OT_select_linked_pick(wmOperatorType *ot)
2127 ot->name = "Select Linked";
2128 ot->idname = "MESH_OT_select_linked_pick";
2129 ot->description = "(De)select all vertices linked to the edge under the mouse cursor";
2132 ot->invoke = edbm_select_linked_pick_invoke;
2133 ot->poll = ED_operator_editmesh;
2136 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2138 RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
2139 RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
2143 static int edbm_select_linked_exec(bContext *C, wmOperator *op)
2145 Object *obedit = CTX_data_edit_object(C);
2146 BMEditMesh *em = BMEdit_FromObject(obedit);
2155 linked_limit_default(C, op);
2157 limit = RNA_boolean_get(op->ptr, "limit");
2159 if (em->selectmode == SCE_SELECT_FACE) {
2162 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2163 BM_elem_flag_set(efa, BM_ELEM_TAG, (BM_elem_flag_test(efa, BM_ELEM_SELECT) &&
2164 !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)));
2168 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
2169 /* BMESH_TODO, don't use 'BM_ELEM_SELECT' here, its a HFLAG only! */
2170 BMO_elem_flag_set(bm, e, BM_ELEM_SELECT, !BM_elem_flag_test(e, BM_ELEM_SEAM));
2174 BMW_init(&walker, bm, BMW_ISLAND,
2175 BMW_MASK_NOP, limit ? BM_ELEM_SELECT : BMW_MASK_NOP, BMW_MASK_NOP,
2176 BMW_FLAG_TEST_HIDDEN,
2179 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2180 if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2181 e = BMW_begin(&walker, efa);
2182 for (; efa; efa = BMW_step(&walker)) {
2183 BM_face_select_set(bm, efa, TRUE);
2190 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2191 if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
2192 BM_elem_flag_enable(v, BM_ELEM_TAG);
2195 BM_elem_flag_disable(v, BM_ELEM_TAG);
2199 BMW_init(&walker, em->bm, BMW_SHELL,
2200 BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
2201 BMW_FLAG_TEST_HIDDEN,
2204 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2205 if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
2206 e = BMW_begin(&walker, v);
2207 for (; e; e = BMW_step(&walker)) {
2208 BM_vert_select_set(em->bm, e->v1, TRUE);
2209 BM_vert_select_set(em->bm, e->v2, TRUE);
2215 EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
2217 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
2219 return OPERATOR_FINISHED;
2222 void MESH_OT_select_linked(wmOperatorType *ot)
2225 ot->name = "Select Linked All";
2226 ot->idname = "MESH_OT_select_linked";
2227 ot->description = "Select all vertices linked to the active mesh";
2230 ot->exec = edbm_select_linked_exec;
2231 ot->poll = ED_operator_editmesh;
2234 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2236 RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
2239 /* ******************** **************** */
2241 static int edbm_select_more_exec(bContext *C, wmOperator *UNUSED(op))
2243 Object *obedit = CTX_data_edit_object(C);
2244 BMEditMesh *em = BMEdit_FromObject(obedit);
2246 EDBM_select_more(em);
2248 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
2249 return OPERATOR_FINISHED;
2252 void MESH_OT_select_more(wmOperatorType *ot)
2255 ot->name = "Select More";
2256 ot->idname = "MESH_OT_select_more";
2257 ot->description = "Select more vertices, edges or faces connected to initial selection";
2260 ot->exec = edbm_select_more_exec;
2261 ot->poll = ED_operator_editmesh;
2264 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2267 static int edbm_select_less_exec(bContext *C, wmOperator *UNUSED(op))
2269 Object *obedit = CTX_data_edit_object(C);
2270 BMEditMesh *em = BMEdit_FromObject(obedit);
2272 EDBM_select_less(em);
2274 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
2275 return OPERATOR_FINISHED;
2278 void MESH_OT_select_less(wmOperatorType *ot)
2281 ot->name = "Select Less";
2282 ot->idname = "MESH_OT_select_less";
2283 ot->description = "Deselect vertices, edges or faces at the boundary of each selection region";
2286 ot->exec = edbm_select_less_exec;
2287 ot->poll = ED_operator_editmesh;
2290 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2293 /* Walk all reachable elements of the same type as h_act in breadth-first
2294 * order, starting from h_act. Deselects elements if the depth when they
2295 * are reached is not a multiple of "nth". */
2296 static void walker_deselect_nth(BMEditMesh *em, int nth, int offset, BMHeader *h_act)
2302 int walktype = 0, itertype = 0, flushtype = 0;
2303 short mask_vert = 0, mask_edge = 0, mask_face = 0;
2305 /* No active element from which to start - nothing to do */
2306 if (h_act == NULL) {
2310 /* Determine which type of iter, walker, and select flush to use
2311 * based on type of the elements being deselected */
2312 switch (h_act->htype) {
2314 itertype = BM_VERTS_OF_MESH;
2315 walktype = BMW_CONNECTED_VERTEX;
2316 flushtype = SCE_SELECT_VERTEX;
2317 mask_vert = BM_ELEM_SELECT;
2320 itertype = BM_EDGES_OF_MESH;
2321 walktype = BMW_SHELL;
2322 flushtype = SCE_SELECT_EDGE;
2323 mask_edge = BM_ELEM_SELECT;
2326 itertype = BM_FACES_OF_MESH;
2327 walktype = BMW_ISLAND;
2328 flushtype = SCE_SELECT_FACE;
2329 mask_face = BM_ELEM_SELECT;
2333 /* Walker restrictions uses BMO flags, not header flags,
2334 * so transfer BM_ELEM_SELECT from HFlags onto a BMO flag layer. */
2336 BM_ITER_MESH (ele, &iter, bm, itertype) {
2337 if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
2338 /* BMESH_TODO, don't use 'BM_ELEM_SELECT' here, its a HFLAG only! */
2339 BMO_elem_flag_enable(bm, (BMElemF *)ele, BM_ELEM_SELECT);
2343 /* Walk over selected elements starting at active */
2344 BMW_init(&walker, bm, walktype,
2345 mask_vert, mask_edge, mask_face,
2346 BMW_FLAG_NOP, /* don't use BMW_FLAG_TEST_HIDDEN here since we want to desel all */
2349 /* use tag to avoid touching the same verts twice */
2350 BM_ITER_MESH (ele, &iter, bm, itertype) {
2351 BM_elem_flag_disable(ele, BM_ELEM_TAG);
2354 BLI_assert(walker.order == BMW_BREADTH_FIRST);
2355 for (ele = BMW_begin(&walker, h_act); ele != NULL; ele = BMW_step(&walker)) {
2356 if (!BM_elem_flag_test(ele, BM_ELEM_TAG)) {
2357 /* Deselect elements that aren't at "nth" depth from active */
2358 if ((offset + BMW_current_depth(&walker)) % nth) {
2359 BM_elem_select_set(bm, ele, FALSE);
2361 BM_elem_flag_enable(ele, BM_ELEM_TAG);
2368 /* Flush selection up */
2369 EDBM_selectmode_flush_ex(em, flushtype);
2372 static void deselect_nth_active(BMEditMesh *em, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
2378 BMEditSelection *ese;
2384 EDBM_selectmode_flush(em);
2385 ese = (BMEditSelection *)em->bm->selected.last;
2388 switch (ese->htype) {
2390 *r_eve = (BMVert *)ese->ele;
2393 *r_eed = (BMEdge *)ese->ele;
2396 *r_efa = (BMFace *)ese->ele;
2401 if (em->selectmode & SCE_SELECT_VERTEX) {
2402 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2403 if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
2409 else if (em->selectmode & SCE_SELECT_EDGE) {
2410 BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
2411 if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
2417 else if (em->selectmode & SCE_SELECT_FACE) {
2418 f = BM_active_face_get(em->bm, TRUE, FALSE);
2426 static int edbm_deselect_nth(BMEditMesh *em, int nth, int offset)
2432 deselect_nth_active(em, &v, &e, &f);
2435 walker_deselect_nth(em, nth, offset, &v->head);
2439 walker_deselect_nth(em, nth, offset, &e->head);
2443 walker_deselect_nth(em, nth, offset, &f->head);
2450 static int edbm_select_nth_exec(bContext *C, wmOperator *op)
2452 Object *obedit = CTX_data_edit_object(C);
2453 BMEditMesh *em = BMEdit_FromObject(obedit);
2454 int nth = RNA_int_get(op->ptr, "nth");
2455 int offset = RNA_int_get(op->ptr, "offset");
2457 offset = MIN2(nth, offset);
2459 if (edbm_deselect_nth(em, nth, offset) == 0) {
2460 BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face");
2461 return OPERATOR_CANCELLED;
2464 EDBM_update_generic(C, em, FALSE);
2466 return OPERATOR_FINISHED;
2470 void MESH_OT_select_nth(wmOperatorType *ot)
2473 ot->name = "Checker Deselect";
2474 ot->idname = "MESH_OT_select_nth";
2475 ot->description = "Deselect every Nth element starting from a selected vertex, edge or face";
2478 ot->exec = edbm_select_nth_exec;
2479 ot->poll = ED_operator_editmesh;
2482 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2484 RNA_def_int(ot->srna, "nth", 2, 2, INT_MAX, "Nth Selection", "", 2, 100);
2485 RNA_def_int(ot->srna, "offset", 0, 0, INT_MAX, "Offset", "", 0, 100);
2488 void em_setup_viewcontext(bContext *C, ViewContext *vc)
2490 view3d_set_viewcontext(C, vc);
2493 vc->em = BMEdit_FromObject(vc->obedit);
2497 /* poll call for mesh operators requiring a view3d context */
2498 int EM_view3d_poll(bContext *C)
2500 if (ED_operator_editmesh(C) && ED_operator_view3d_active(C))
2507 static int edbm_select_sharp_edges_exec(bContext *C, wmOperator *op)
2509 /* Find edges that have exactly two neighboring faces,
2510 * check the angle between those faces, and if angle is
2511 * small enough, select the edge
2513 Object *obedit = CTX_data_edit_object(C);
2514 BMEditMesh *em = BMEdit_FromObject(obedit);
2518 const float sharp = RNA_float_get(op->ptr, "sharpness");
2520 BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
2521 if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == FALSE &&
2522 BM_edge_loop_pair(e, &l1, &l2))
2524 /* edge has exactly two neighboring faces, check angle */
2525 const float angle = angle_normalized_v3v3(l1->f->no, l2->f->no);
2527 if (fabsf(angle) > sharp) {
2528 BM_edge_select_set(em->bm, e, TRUE);
2533 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2535 return OPERATOR_FINISHED;
2538 void MESH_OT_edges_select_sharp(wmOperatorType *ot)
2543 ot->name = "Select Sharp Edges";
2544 ot->description = "Select all sharp-enough edges";
2545 ot->idname = "MESH_OT_edges_select_sharp";
2548 ot->exec = edbm_select_sharp_edges_exec;
2549 ot->poll = ED_operator_editmesh;
2552 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2555 prop = RNA_def_float_rotation(ot->srna, "sharpness", 0, NULL, DEG2RADF(0.01f), DEG2RADF(180.0f),
2556 "Sharpness", "", DEG2RADF(1.0f), DEG2RADF(180.0f));
2557 RNA_def_property_float_default(prop, DEG2RADF(30.0f));
2560 static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op)
2562 Object *obedit = CTX_data_edit_object(C);
2563 BMEditMesh *em = BMEdit_FromObject(obedit);
2564 BMIter iter, liter, liter2;
2565 BMFace *f, **stack = NULL;
2566 BLI_array_declare(stack);
2568 float sharp = RNA_float_get(op->ptr, "sharpness");
2571 BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
2572 BM_elem_flag_disable(f, BM_ELEM_TAG);
2575 BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
2576 if (BM_elem_flag_test(f, BM_ELEM_HIDDEN) || !BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_TAG))
2579 BLI_array_empty(stack);
2582 BLI_array_grow_one(stack);
2589 BM_face_select_set(em->bm, f, TRUE);
2591 BM_elem_flag_enable(f, BM_ELEM_TAG);
2593 BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
2594 BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) {
2597 if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) || BM_elem_flag_test(l2->f, BM_ELEM_HIDDEN))
2600 /* edge has exactly two neighboring faces, check angle */
2601 angle = angle_normalized_v3v3(f->no, l2->f->no);
2603 /* invalidate: edge too sharp */
2604 if (angle < sharp) {
2605 BLI_array_grow_one(stack);
2614 BLI_array_free(stack);
2616 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2618 return OPERATOR_FINISHED;
2621 void MESH_OT_faces_select_linked_flat(wmOperatorType *ot)
2626 ot->name = "Select Linked Flat Faces";
2627 ot->description = "Select linked faces by angle";
2628 ot->idname = "MESH_OT_faces_select_linked_flat";
2631 ot->exec = edbm_select_linked_flat_faces_exec;
2632 ot->poll = ED_operator_editmesh;
2635 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2638 prop = RNA_def_float_rotation(ot->srna, "sharpness", 0, NULL, DEG2RADF(0.01f), DEG2RADF(180.0f),
2639 "Sharpness", "", DEG2RADF(1.0f), DEG2RADF(180.0f));
2640 RNA_def_property_float_default(prop, DEG2RADF(1.0f));
2643 static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
2645 Object *obedit = CTX_data_edit_object(C);
2646 BMEditMesh *em = BMEdit_FromObject(obedit);
2651 /* Selects isolated verts, and edges that do not have 2 neighboring
2655 if (em->selectmode == SCE_SELECT_FACE) {
2656 BKE_report(op->reports, RPT_ERROR, "Does not work in face selection mode");
2657 return OPERATOR_CANCELLED;
2660 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2661 if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN) && !BM_vert_is_manifold(v)) {
2662 BM_vert_select_set(em->bm, v, TRUE);
2666 BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
2667 if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && !BM_edge_is_manifold(e)) {
2668 BM_edge_select_set(em->bm, e, TRUE);
2672 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2674 return OPERATOR_FINISHED;
2677 void MESH_OT_select_non_manifold(wmOperatorType *ot)
2680 ot->name = "Select Non Manifold";
2681 ot->description = "Select all non-manifold vertices or edges";
2682 ot->idname = "MESH_OT_select_non_manifold";
2685 ot->exec = edbm_select_non_manifold_exec;
2686 ot->poll = ED_operator_editmesh;
2689 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2692 static int edbm_select_random_exec(bContext *C, wmOperator *op)
2694 Object *obedit = CTX_data_edit_object(C);
2695 BMEditMesh *em = BMEdit_FromObject(obedit);
2700 float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
2702 BLI_srand(BLI_rand()); /* random seed */
2704 if (!RNA_boolean_get(op->ptr, "extend"))
2705 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
2707 if (em->selectmode & SCE_SELECT_VERTEX) {
2708 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2709 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BLI_frand() < randfac) {
2710 BM_vert_select_set(em->bm, eve, TRUE);
2713 EDBM_selectmode_flush(em);
2715 else if (em->selectmode & SCE_SELECT_EDGE) {
2716 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2717 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BLI_frand() < randfac) {
2718 BM_edge_select_set(em->bm, eed, TRUE);
2721 EDBM_selectmode_flush(em);
2724 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2725 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BLI_frand() < randfac) {
2726 BM_face_select_set(em->bm, efa, TRUE);
2729 EDBM_selectmode_flush(em);
2732 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2734 return OPERATOR_FINISHED;
2737 void MESH_OT_select_random(wmOperatorType *ot)
2740 ot->name = "Select Random";
2741 ot->description = "Randomly select vertices";
2742 ot->idname = "MESH_OT_select_random";
2745 ot->exec = edbm_select_random_exec;
2746 ot->poll = ED_operator_editmesh;
2749 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2752 RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f,
2753 "Percent", "Percentage of elements to select randomly", 0.f, 100.0f);
2754 RNA_def_boolean(ot->srna, "extend", 0,
2755 "Extend Selection", "Extend selection instead of deselecting everything first");
2758 static int edbm_select_next_loop_exec(bContext *C, wmOperator *UNUSED(op))
2760 Object *obedit = CTX_data_edit_object(C);
2761 BMEditMesh *em = BMEdit_FromObject(obedit);
2766 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2767 BM_elem_flag_disable(v, BM_ELEM_TAG);
2770 BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
2774 BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
2775 if (BM_elem_flag_test(l->v, BM_ELEM_SELECT)) {
2776 BM_elem_flag_enable(l->next->v, BM_ELEM_TAG);
2777 BM_vert_select_set(em->bm, l->v, FALSE);
2782 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2783 if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
2784 BM_vert_select_set(em->bm, v, TRUE);
2788 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
2789 return OPERATOR_FINISHED;
2792 void MESH_OT_select_next_loop(wmOperatorType *ot)
2795 ot->name = "Select Next Loop";
2796 ot->idname = "MESH_OT_select_next_loop";
2797 ot->description = "Select next edge loop adjacent to a selected loop";
2800 ot->exec = edbm_select_next_loop_exec;
2801 ot->poll = ED_operator_editmesh;
2804 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2808 static int edbm_region_to_loop_exec(bContext *C, wmOperator *UNUSED(op))
2810 Object *obedit = CTX_data_edit_object(C);
2811 BMEditMesh *em = BMEdit_FromObject(obedit);
2816 BM_mesh_elem_hflag_disable_all(em->bm, BM_EDGE, BM_ELEM_TAG, FALSE);
2818 BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
2820 BMIter liter1, liter2;
2822 BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) {
2823 int tot = 0, totsel = 0;
2825 BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) {
2827 totsel += BM_elem_flag_test(l2->f, BM_ELEM_SELECT) != 0;
2830 if ((tot != totsel && totsel > 0) || (totsel == 1 && tot == 1))
2831 BM_elem_flag_enable(l1->e, BM_ELEM_TAG);
2835 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
2837 BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
2838 if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
2839 BM_edge_select_set(em->bm, e, TRUE);
2843 /* If in face-only select mode, switch to edge select mode so that
2844 * an edge-only selection is not inconsistent state */
2845 if (em->selectmode == SCE_SELECT_FACE) {
2846 em->selectmode = SCE_SELECT_EDGE;
2847 EDBM_selectmode_set(em);
2848 EDBM_selectmode_to_scene(C);
2851 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2853 return OPERATOR_FINISHED;
2856 void MESH_OT_region_to_loop(wmOperatorType *ot)
2859 ot->name = "Select Boundary Loop";
2860 ot->idname = "MESH_OT_region_to_loop";
2861 ot->description = "Select boundary edges around the selected faces";
2864 ot->exec = edbm_region_to_loop_exec;
2865 ot->poll = ED_operator_editmesh;
2868 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2871 static int loop_find_region(BMLoop *l, int flag,
2872 SmallHash *fhash, BMFace ***region_out)
2874 BLI_array_declare(region);
2875 BLI_array_declare(stack);
2876 BMFace **region = NULL;
2877 BMFace **stack = NULL;
2880 BLI_array_append(stack, l->f);
2881 BLI_smallhash_insert(fhash, (uintptr_t)l->f, NULL);
2883 while (BLI_array_count(stack) > 0) {
2884 BMIter liter1, liter2;
2887 f = BLI_array_pop(stack);
2888 BLI_array_append(region, f);
2890 BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) {
2891 if (BM_elem_flag_test(l1->e, flag))
2894 BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) {
2895 if (BLI_smallhash_haskey(fhash, (uintptr_t)l2->f))
2898 BLI_array_append(stack, l2->f);
2899 BLI_smallhash_insert(fhash, (uintptr_t)l2->f, NULL);
2904 BLI_array_free(stack);
2906 *region_out = region;
2907 return BLI_array_count(region);
2910 static int verg_radial(const void *va, const void *vb)
2912 BMEdge *e1 = *((void **)va);
2913 BMEdge *e2 = *((void **)vb);
2916 a = BM_edge_face_count(e1);
2917 b = BM_edge_face_count(e2);
2919 if (a > b) return -1;
2920 if (a == b) return 0;
2921 if (a < b) return 1;
2926 static int loop_find_regions(BMEditMesh *em, int selbigger)
2928 SmallHash visithash;
2930 BMEdge *e, **edges = NULL;
2931 BLI_array_declare(edges);
2935 BLI_smallhash_init(&visithash);
2937 BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
2938 BM_elem_flag_disable(f, BM_ELEM_TAG);
2941 BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
2942 if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
2943 BLI_array_append(edges, e);
2944 BM_elem_flag_enable(e, BM_ELEM_TAG);
2947 BM_elem_flag_disable(e, BM_ELEM_TAG);
2951 /* sort edges by radial cycle length */
2952 qsort(edges, BLI_array_count(edges), sizeof(void *), verg_radial);
2954 for (i = 0; i < BLI_array_count(edges); i++) {
2957 BMFace **region = NULL, **region_out;
2962 if (!BM_elem_flag_test(e, BM_ELEM_TAG))
2965 BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) {
2966 if (BLI_smallhash_haskey(&visithash, (uintptr_t)l->f))
2969 c = loop_find_region(l, BM_ELEM_SELECT, &visithash, ®ion_out);
2971 if (!region || (selbigger ? c >= tot : c < tot)) {
2972 /* this region is the best seen so far */
2975 /* free the previous best */
2978 /* track the current region as the new best */
2979 region = region_out;
2982 /* this region is not as good as best so far, just free it */
2983 MEM_freeN(region_out);
2990 for (j = 0; j < tot; j++) {
2991 BM_elem_flag_enable(region[j], BM_ELEM_TAG);
2992 BM_ITER_ELEM (l, &liter, region[j], BM_LOOPS_OF_FACE) {
2993 BM_elem_flag_disable(l->e, BM_ELEM_TAG);
3003 BLI_array_free(edges);
3004 BLI_smallhash_release(&visithash);
3009 static int edbm_loop_to_region_exec(bContext *C, wmOperator *op)
3011 Object *obedit = CTX_data_edit_object(C);
3012 BMEditMesh *em = BMEdit_FromObject(obedit);
3015 int selbigger = RNA_boolean_get(op->ptr, "select_bigger");
3018 /* find the set of regions with smallest number of total faces */
3019 a = loop_find_regions(em, selbigger);
3020 b = loop_find_regions(em, !selbigger);
3022 if ((a <= b) ^ selbigger) {
3023 loop_find_regions(em, selbigger);
3026 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
3028 BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
3029 if (BM_elem_flag_test(f, BM_ELEM_TAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
3030 BM_face_select_set(em->bm, f, TRUE);
3034 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
3035 return OPERATOR_FINISHED;
3038 void MESH_OT_loop_to_region(wmOperatorType *ot)
3041 ot->name = "Select Loop Inner-Region";
3042 ot->idname = "MESH_OT_loop_to_region";
3043 ot->description = "Select region of faces inside of a selected loop of edges";
3046 ot->exec = edbm_loop_to_region_exec;
3047 ot->poll = ED_operator_editmesh;
3050 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3052 RNA_def_boolean(ot->srna, "select_bigger", 0, "Select Bigger", "Select bigger regions instead of smaller ones");