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"
60 #include "ED_uvedit.h"
61 #include "ED_object.h"
62 #include "ED_view3d.h"
66 #include "DNA_scene_types.h"
67 #include "DNA_object_types.h"
68 #include "DNA_mesh_types.h"
70 #include "mesh_intern.h"
72 #include "UI_resources.h"
74 /* ****************************** MIRROR **************** */
76 void EDBM_select_mirrored(Object *UNUSED(obedit), BMEditMesh *em, int extend)
81 BM_ITER_MESH (v1, &iter, em->bm, BM_VERTS_OF_MESH) {
82 if (!BM_elem_flag_test(v1, BM_ELEM_SELECT) || BM_elem_flag_test(v1, BM_ELEM_HIDDEN)) {
83 BM_elem_flag_disable(v1, BM_ELEM_TAG);
86 BM_elem_flag_enable(v1, BM_ELEM_TAG);
90 EDBM_verts_mirror_cache_begin(em, TRUE);
93 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
95 BM_ITER_MESH (v1, &iter, em->bm, BM_VERTS_OF_MESH) {
96 if (!BM_elem_flag_test(v1, BM_ELEM_TAG) || BM_elem_flag_test(v1, BM_ELEM_HIDDEN))
99 v2 = EDBM_verts_mirror_get(em, v1);
100 if (v2 && !BM_elem_flag_test(v2, BM_ELEM_HIDDEN)) {
101 BM_vert_select_set(em->bm, v2, TRUE);
105 EDBM_verts_mirror_cache_end(em);
108 void EDBM_automerge(Scene *scene, Object *obedit, int update)
112 if ((scene->toolsettings->automerge) &&
113 (obedit && obedit->type == OB_MESH))
115 em = BMEdit_FromObject(obedit);
119 BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS,
120 "automerge verts=%hv dist=%f",
121 BM_ELEM_SELECT, scene->toolsettings->doublimit);
123 DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
124 BMEdit_RecalcTessellation(em);
129 /* ****************************** SELECTION ROUTINES **************** */
131 unsigned int bm_solidoffs = 0, bm_wireoffs = 0, bm_vertoffs = 0; /* set in drawobject.c ... for colorindices */
133 /* facilities for border select and circle select */
134 static char *selbuf = NULL;
136 /* opengl doesn't support concave... */
137 static void draw_triangulated(const int mcords[][2], const short tot)
139 ListBase lb = {NULL, NULL};
145 dl = MEM_callocN(sizeof(DispList), "poly disp");
149 dl->verts = fp = MEM_callocN(tot * 3 * sizeof(float), "poly verts");
150 BLI_addtail(&lb, dl);
152 for (a = 0; a < tot; a++, fp += 3) {
153 fp[0] = (float)mcords[a][0];
154 fp[1] = (float)mcords[a][1];
158 BKE_displist_fill(&lb, &lb, 0);
161 dl = lb.first; /* filldisplist adds in head of list */
162 if (dl->type == DL_INDEX3) {
168 glBegin(GL_TRIANGLES);
170 glVertex3fv(fp + 3 * index[0]);
171 glVertex3fv(fp + 3 * index[1]);
172 glVertex3fv(fp + 3 * index[2]);
178 BKE_displist_free(&lb);
182 /* reads rect, and builds selection array for quick lookup */
183 /* returns if all is OK */
184 int EDBM_backbuf_border_init(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
190 if (vc->obedit == NULL || vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) {
194 buf = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
195 if (buf == NULL) return 0;
196 if (bm_vertoffs == 0) return 0;
200 /* build selection lookup */
201 selbuf = MEM_callocN(bm_vertoffs + 1, "selbuf");
203 a = (xmax - xmin + 1) * (ymax - ymin + 1);
205 if (*dr > 0 && *dr <= bm_vertoffs)
213 int EDBM_backbuf_check(unsigned int index)
215 if (selbuf == NULL) return 1;
216 if (index > 0 && index <= bm_vertoffs)
217 return selbuf[index];
221 void EDBM_backbuf_free(void)
223 if (selbuf) MEM_freeN(selbuf);
227 /* mcords is a polygon mask
229 * - draw with black in backbuffer,
230 * - grab again and compare
233 int EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
235 unsigned int *dr, *drm;
236 struct ImBuf *buf, *bufmask;
239 /* method in use for face selecting too */
240 if (vc->obedit == NULL) {
241 if (!(paint_facesel_test(vc->obact) || paint_vertsel_test(vc->obact))) {
245 else if (vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) {
249 buf = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
250 if (buf == NULL) return 0;
251 if (bm_vertoffs == 0) return 0;
256 glDisable(GL_DEPTH_TEST);
260 /* yah, opengl doesn't do concave... tsk! */
261 ED_region_pixelspace(vc->ar);
262 draw_triangulated(mcords, tot);
264 glBegin(GL_LINE_LOOP); /* for zero sized masks, lines */
265 for (a = 0; a < tot; a++) {
266 glVertex2iv(mcords[a]);
270 glFinish(); /* to be sure readpixels sees mask */
273 bufmask = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
275 if (bufmask == NULL) {
276 return 0; /* only when mem alloc fails, go crash somewhere else! */
282 /* build selection lookup */
283 selbuf = MEM_callocN(bm_vertoffs + 1, "selbuf");
285 a = (xmax - xmin + 1) * (ymax - ymin + 1);
287 if (*dr > 0 && *dr <= bm_vertoffs && *drm == 0) selbuf[*dr] = 1;
291 IMB_freeImBuf(bufmask);
296 /* circle shaped sample area */
297 int EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads)
301 short xmin, ymin, xmax, ymax, xc, yc;
304 /* method in use for face selecting too */
305 if (vc->obedit == NULL) {
306 if (!(paint_facesel_test(vc->obact) || paint_vertsel_test(vc->obact))) {
310 else if (vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) return 0;
312 xmin = xs - rads; xmax = xs + rads;
313 ymin = ys - rads; ymax = ys + rads;
314 buf = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
315 if (bm_vertoffs == 0) return 0;
316 if (buf == NULL) return 0;
320 /* build selection lookup */
321 selbuf = MEM_callocN(bm_vertoffs + 1, "selbuf");
323 for (yc = -rads; yc <= rads; yc++) {
324 for (xc = -rads; xc <= rads; xc++, dr++) {
325 if (xc * xc + yc * yc < radsq) {
326 if (*dr > 0 && *dr <= bm_vertoffs) selbuf[*dr] = 1;
336 static void findnearestvert__doClosest(void *userData, BMVert *eve, const float screen_co[2], int index)
338 struct { float mval_fl[2], pass, select, strict; float dist, lastIndex, closestIndex; BMVert *closest; } *data = userData;
340 if (data->pass == 0) {
341 if (index <= data->lastIndex)
345 if (index > data->lastIndex)
349 if (data->dist > 3) {
350 float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
351 if (BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->select) {
352 if (data->strict == 1) {
360 if (dist_test < data->dist) {
361 data->dist = dist_test;
363 data->closestIndex = index;
371 static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index)
373 BMEditMesh *em = (BMEditMesh *)handle;
374 BMVert *eve = BM_vert_at_index(em->bm, index - 1);
376 if (eve && BM_elem_flag_test(eve, BM_ELEM_SELECT)) return 0;
382 * dist (in/out): minimal distance to the nearest and at the end, actual distance
383 * sel: selection bias
384 * if SELECT, selected vertice are given a 5 pixel bias to make them further than unselect verts
385 * if 0, unselected vertice are given the bias
386 * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
388 BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *r_dist, const short sel, const short strict)
390 if (vc->v3d->drawtype > OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
396 index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance,
397 strict, vc->em, findnearestvert__backbufIndextest);
400 index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance,
404 eve = BM_vert_at_index(vc->em->bm, index - 1);
406 if (eve && distance < *r_dist) {
416 struct { float mval_fl[2], pass, select, strict; float dist, lastIndex, closestIndex; BMVert *closest; } data;
417 static int lastSelectedIndex = 0;
418 static BMVert *lastSelected = NULL;
420 if (lastSelected && BM_vert_at_index(vc->em->bm, lastSelectedIndex) != lastSelected) {
421 lastSelectedIndex = 0;
425 data.lastIndex = lastSelectedIndex;
426 data.mval_fl[0] = vc->mval[0];
427 data.mval_fl[1] = vc->mval[1];
430 data.strict = strict;
432 data.closestIndex = 0;
436 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
438 mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
442 mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
446 lastSelected = data.closest;
447 lastSelectedIndex = data.closestIndex;
453 /* returns labda for closest distance v1 to line-piece v2 - v3 */
454 float labda_PdistVL2Dfl(const float v1[2], const float v2[2], const float v3[2])
458 rc[0] = v3[0] - v2[0];
459 rc[1] = v3[1] - v2[1];
460 len = rc[0] * rc[0] + rc[1] * rc[1];
464 return (rc[0] * (v1[0] - v2[0]) + rc[1] * (v1[1] - v2[1])) / len;
467 /* note; uses v3d, so needs active 3d window */
468 static void findnearestedge__doClosest(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int UNUSED(index))
470 struct { ViewContext vc; float mval_fl[2]; float dist; BMEdge *closest; } *data = userData;
473 distance = dist_to_line_segment_v2(data->mval_fl, screen_co_a, screen_co_b);
475 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
479 if (distance < data->dist) {
480 if (data->vc.rv3d->rflag & RV3D_CLIPPING) {
481 float labda = labda_PdistVL2Dfl(data->mval_fl, screen_co_a, screen_co_b);
484 vec[0] = eed->v1->co[0] + labda * (eed->v2->co[0] - eed->v1->co[0]);
485 vec[1] = eed->v1->co[1] + labda * (eed->v2->co[1] - eed->v1->co[1]);
486 vec[2] = eed->v1->co[2] + labda * (eed->v2->co[2] - eed->v1->co[2]);
488 if (ED_view3d_clipping_test(data->vc.rv3d, vec, TRUE) == 0) {
489 data->dist = distance;
494 data->dist = distance;
499 BMEdge *EDBM_edge_find_nearest(ViewContext *vc, float *r_dist)
502 if (vc->v3d->drawtype > OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
507 view3d_validate_backbuf(vc);
509 index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_solidoffs, bm_wireoffs, &distance, 0, NULL, NULL);
510 eed = BM_edge_at_index(vc->em->bm, index - 1);
512 if (eed && distance < *r_dist) {
521 struct { ViewContext vc; float mval_fl[2]; float dist; BMEdge *closest; } data;
524 data.mval_fl[0] = vc->mval[0];
525 data.mval_fl[1] = vc->mval[1];
528 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
530 mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, V3D_PROJ_TEST_CLIP_WIN);
537 static void findnearestface__getDistance(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
539 struct { float mval_fl[2]; float dist; BMFace *toFace; } *data = userData;
541 if (efa == data->toFace) {
542 const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
544 if (dist_test < data->dist) {
545 data->dist = dist_test;
549 static void findnearestface__doClosest(void *userData, BMFace *efa, const float screen_co[2], int index)
551 struct { float mval_fl[2], pass; float dist, lastIndex, closestIndex; BMFace *closest; } *data = userData;
553 if (data->pass == 0) {
554 if (index <= data->lastIndex)
558 if (index > data->lastIndex)
562 if (data->dist > 3) {
563 const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
565 if (dist_test < data->dist) {
566 data->dist = dist_test;
568 data->closestIndex = index;
573 BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist)
576 if (vc->v3d->drawtype > OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
580 view3d_validate_backbuf(vc);
582 index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]);
583 efa = BM_face_at_index(vc->em->bm, index - 1);
586 struct { float mval_fl[2]; float dist; BMFace *toFace; } data;
588 data.mval_fl[0] = vc->mval[0];
589 data.mval_fl[1] = vc->mval[1];
590 data.dist = 0x7FFF; /* largest short */
593 mesh_foreachScreenFace(vc, findnearestface__getDistance, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
595 if ((vc->em->selectmode == SCE_SELECT_FACE) || (data.dist < *r_dist)) { /* only faces, no dist check */
604 struct { float mval_fl[2], pass; float dist, lastIndex, closestIndex; BMFace *closest; } data;
605 static int lastSelectedIndex = 0;
606 static BMFace *lastSelected = NULL;
608 if (lastSelected && BM_face_at_index(vc->em->bm, lastSelectedIndex) != lastSelected) {
609 lastSelectedIndex = 0;
613 data.lastIndex = lastSelectedIndex;
614 data.mval_fl[0] = vc->mval[0];
615 data.mval_fl[1] = vc->mval[1];
618 data.closestIndex = 0;
619 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
622 mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
624 if (data.dist > 3.0f) {
626 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
627 mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
631 lastSelected = data.closest;
632 lastSelectedIndex = data.closestIndex;
638 /* best distance based on screen coords.
639 * use em->selectmode to define how to use
640 * selected vertices and edges get disadvantage
641 * return 1 if found one
643 static int unified_findnearest(ViewContext *vc, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
645 BMEditMesh *em = vc->em;
652 /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
653 view3d_validate_backbuf(vc);
655 if (em->selectmode & SCE_SELECT_VERTEX)
656 *r_eve = EDBM_vert_find_nearest(vc, &dist, BM_ELEM_SELECT, 0);
657 if (em->selectmode & SCE_SELECT_FACE)
658 *r_efa = EDBM_face_find_nearest(vc, &dist);
660 dist -= 20; /* since edges select lines, we give dots advantage of 20 pix */
661 if (em->selectmode & SCE_SELECT_EDGE)
662 *r_eed = EDBM_edge_find_nearest(vc, &dist);
664 /* return only one of 3 pointers, for frontbuffer redraws */
666 *r_efa = NULL; *r_eve = NULL;
672 return (*r_eve || *r_eed || *r_efa);
675 /* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
676 static EnumPropertyItem prop_similar_compare_types[] = {
677 {SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
678 {SIM_CMP_GT, "GREATER", 0, "Greater", ""},
679 {SIM_CMP_LT, "LESS", 0, "Less", ""},
681 {0, NULL, 0, NULL, NULL}
684 static EnumPropertyItem prop_similar_types[] = {
685 {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""},
686 {SIMVERT_FACE, "FACE", 0, "Amount of Adjacent Faces", ""},
687 {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""},
688 {SIMVERT_EDGE, "EDGE", 0, "Amount of connecting edges", ""},
690 {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""},
691 {SIMEDGE_DIR, "DIR", 0, "Direction", ""},
692 {SIMEDGE_FACE, "FACE", 0, "Amount of Faces Around an Edge", ""},
693 {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""},
694 {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""},
695 {SIMEDGE_BEVEL, "BEVEL", 0, "Bevel", ""},
696 {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
697 {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
698 {SIMEDGE_FREESTYLE, "FREESTYLE_EDGE", 0, "Freestyle Edge Marks", ""},
700 {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
701 {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
702 {SIMFACE_AREA, "AREA", 0, "Area", ""},
703 {SIMFACE_SIDES, "SIDES", 0, "Polygon Sides", ""},
704 {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
705 {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
706 {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
707 {SIMFACE_FREESTYLE, "FREESTYLE_FACE", 0, "Freestyle Face Marks", ""},
709 {0, NULL, 0, NULL, NULL}
712 /* selects new faces/edges/verts based on the existing selection */
714 static int similar_face_select_exec(bContext *C, wmOperator *op)
716 Object *ob = CTX_data_edit_object(C);
717 BMEditMesh *em = BMEdit_FromObject(ob);
720 /* get the type from RNA */
721 const int type = RNA_enum_get(op->ptr, "type");
722 const float thresh = RNA_float_get(op->ptr, "threshold");
723 const int compare = RNA_enum_get(op->ptr, "compare");
725 /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
726 EDBM_op_init(em, &bmop, op,
727 "similar_faces faces=%hf type=%i thresh=%f compare=%i",
728 BM_ELEM_SELECT, type, thresh, compare);
730 /* execute the operator */
731 BMO_op_exec(em->bm, &bmop);
733 /* clear the existing selection */
734 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
736 /* select the output */
737 BMO_slot_buffer_hflag_enable(em->bm, &bmop, "faceout", BM_ALL, BM_ELEM_SELECT, TRUE);
739 /* finish the operator */
740 if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
741 return OPERATOR_CANCELLED;
744 EDBM_update_generic(C, em, FALSE);
747 return OPERATOR_FINISHED;
750 /* ***************************************************** */
754 /* wrap the above function but do selection flushing edge to face */
755 static int similar_edge_select_exec(bContext *C, wmOperator *op)
757 Object *ob = CTX_data_edit_object(C);
758 BMEditMesh *em = BMEdit_FromObject(ob);
761 /* get the type from RNA */
762 const int type = RNA_enum_get(op->ptr, "type");
763 const float thresh = RNA_float_get(op->ptr, "threshold");
764 const int compare = RNA_enum_get(op->ptr, "compare");
766 /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
767 EDBM_op_init(em, &bmop, op,
768 "similar_edges edges=%he type=%i thresh=%f compare=%i",
769 BM_ELEM_SELECT, type, thresh, compare);
771 /* execute the operator */
772 BMO_op_exec(em->bm, &bmop);
774 /* clear the existing selection */
775 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
777 /* select the output */
778 BMO_slot_buffer_hflag_enable(em->bm, &bmop, "edgeout", BM_ALL, BM_ELEM_SELECT, TRUE);
779 EDBM_selectmode_flush(em);
781 /* finish the operator */
782 if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
783 return OPERATOR_CANCELLED;
786 EDBM_update_generic(C, em, FALSE);
789 return OPERATOR_FINISHED;
792 /* ********************************* */
796 * mode 1: same normal
797 * mode 2: same number of face users
798 * mode 3: same vertex groups
800 static int similar_vert_select_exec(bContext *C, wmOperator *op)
802 Object *ob = CTX_data_edit_object(C);
803 BMEditMesh *em = BMEdit_FromObject(ob);
805 /* get the type from RNA */
806 const int type = RNA_enum_get(op->ptr, "type");
807 float thresh = RNA_float_get(op->ptr, "threshold");
808 const int compare = RNA_enum_get(op->ptr, "compare");
810 /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
811 EDBM_op_init(em, &bmop, op,
812 "similar_verts verts=%hv type=%i thresh=%f compare=%i",
813 BM_ELEM_SELECT, type, thresh, compare);
815 /* execute the operator */
816 BMO_op_exec(em->bm, &bmop);
818 /* clear the existing selection */
819 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
821 /* select the output */
822 BMO_slot_buffer_hflag_enable(em->bm, &bmop, "vertout", BM_ALL, BM_ELEM_SELECT, TRUE);
824 /* finish the operator */
825 if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
826 return OPERATOR_CANCELLED;
829 EDBM_selectmode_flush(em);
831 EDBM_update_generic(C, em, FALSE);
834 return OPERATOR_FINISHED;
837 static int edbm_select_similar_exec(bContext *C, wmOperator *op)
839 ToolSettings *ts = CTX_data_tool_settings(C);
840 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "threshold");
842 const int type = RNA_enum_get(op->ptr, "type");
844 if (!RNA_property_is_set(op->ptr, prop)) {
845 RNA_property_float_set(op->ptr, prop, ts->select_thresh);
848 ts->select_thresh = RNA_property_float_get(op->ptr, prop);
851 if (type < 100) return similar_vert_select_exec(C, op);
852 else if (type < 200) return similar_edge_select_exec(C, op);
853 else return similar_face_select_exec(C, op);
856 static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
861 if (!C) /* needed for docs and i18n tools */
862 return prop_similar_types;
864 obedit = CTX_data_edit_object(C);
866 if (obedit && obedit->type == OB_MESH) {
867 EnumPropertyItem *item = NULL;
869 BMEditMesh *em = BMEdit_FromObject(obedit);
871 if (em->selectmode & SCE_SELECT_VERTEX) {
872 for (a = SIMVERT_NORMAL; a < SIMEDGE_LENGTH; a++) {
873 RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
876 else if (em->selectmode & SCE_SELECT_EDGE) {
877 for (a = SIMEDGE_LENGTH; a < SIMFACE_MATERIAL; a++) {
878 RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
881 else if (em->selectmode & SCE_SELECT_FACE) {
882 for (a = SIMFACE_MATERIAL; a <= SIMFACE_FREESTYLE; a++) {
883 RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
886 RNA_enum_item_end(&item, &totitem);
896 void MESH_OT_select_similar(wmOperatorType *ot)
901 ot->name = "Select Similar";
902 ot->idname = "MESH_OT_select_similar";
903 ot->description = "Select similar vertices, edges or faces by property types";
906 ot->invoke = WM_menu_invoke;
907 ot->exec = edbm_select_similar_exec;
908 ot->poll = ED_operator_editmesh;
911 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
914 prop = ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", "");
915 RNA_def_enum_funcs(prop, select_similar_type_itemf);
917 RNA_def_enum(ot->srna, "compare", prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
919 RNA_def_float(ot->srna, "threshold", 0.0, 0.0, 1.0, "Threshold", "", 0.0, 1.0);
923 /* **************** Mode Select *************** */
925 static int edbm_select_mode_exec(bContext *C, wmOperator *op)
927 const int type = RNA_enum_get(op->ptr, "type");
928 const int action = RNA_enum_get(op->ptr, "action");
929 const int use_extend = RNA_boolean_get(op->ptr, "use_extend");
930 const int use_expand = RNA_boolean_get(op->ptr, "use_expand");
932 if (EDBM_selectmode_toggle(C, type, action, use_extend, use_expand)) {
933 return OPERATOR_FINISHED;
936 return OPERATOR_CANCELLED;
940 static int edbm_select_mode_invoke(bContext *C, wmOperator *op, wmEvent *event)
942 // RNA_enum_set(op->ptr, "type"); /* type must be set already */
943 RNA_boolean_set(op->ptr, "use_extend", event->shift);
944 RNA_boolean_set(op->ptr, "use_expand", event->ctrl);
945 return edbm_select_mode_exec(C, op);
948 void MESH_OT_select_mode(wmOperatorType *ot)
952 static EnumPropertyItem elem_items[] = {
953 {SCE_SELECT_VERTEX, "VERT", ICON_VERTEXSEL, "Vertices", ""},
954 {SCE_SELECT_EDGE, "EDGE", ICON_EDGESEL, "Edges", ""},
955 {SCE_SELECT_FACE, "FACE", ICON_FACESEL, "Faces", ""},
956 {0, NULL, 0, NULL, NULL},
959 static EnumPropertyItem actions_items[] = {
960 {0, "DISABLE", 0, "Disable", "Disable selected markers"},
961 {1, "ENABLE", 0, "Enable", "Enable selected markers"},
962 {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
963 {0, NULL, 0, NULL, NULL}
967 ot->name = "Select Mode";
968 ot->idname = "MESH_OT_select_mode";
969 ot->description = "Change selection mode";
972 ot->invoke = edbm_select_mode_invoke;
973 ot->exec = edbm_select_mode_exec;
974 ot->poll = ED_operator_editmesh;
977 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
980 prop = RNA_def_boolean(ot->srna, "use_extend", FALSE, "Extend", "");
981 RNA_def_property_flag(prop, PROP_SKIP_SAVE);
982 prop = RNA_def_boolean(ot->srna, "use_expand", FALSE, "Expand", "");
983 RNA_def_property_flag(prop, PROP_SKIP_SAVE);
984 ot->prop = prop = RNA_def_enum(ot->srna, "type", elem_items, 0, "Type", "");
985 RNA_def_property_flag(prop, PROP_SKIP_SAVE);
987 RNA_def_enum(ot->srna, "action", actions_items, 2, "Action", "Selection action to execute");
990 /* ***************************************************** */
992 /* **************** LOOP SELECTS *************** */
994 static void walker_select(BMEditMesh *em, int walkercode, void *start, int select)
1000 BMW_init(&walker, bm, walkercode,
1001 BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
1002 BMW_FLAG_TEST_HIDDEN,
1004 ele = BMW_begin(&walker, start);
1005 for (; ele; ele = BMW_step(&walker)) {
1007 BM_select_history_remove(bm, ele);
1009 BM_elem_select_set(bm, ele, select);
1014 static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op)
1016 Object *obedit = CTX_data_edit_object(C);
1017 BMEditMesh *em = BMEdit_FromObject(obedit);
1021 int looptype = RNA_boolean_get(op->ptr, "ring");
1026 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1027 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1032 edarray = MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array");
1035 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1036 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1037 edarray[edindex] = eed;
1043 for (edindex = 0; edindex < totedgesel; edindex += 1) {
1044 eed = edarray[edindex];
1045 walker_select(em, BMW_EDGERING, eed, TRUE);
1047 EDBM_selectmode_flush(em);
1050 for (edindex = 0; edindex < totedgesel; edindex += 1) {
1051 eed = edarray[edindex];
1052 walker_select(em, BMW_LOOP, eed, TRUE);
1054 EDBM_selectmode_flush(em);
1057 // if (EM_texFaceCheck())
1059 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
1061 return OPERATOR_FINISHED;
1064 void MESH_OT_loop_multi_select(wmOperatorType *ot)
1067 ot->name = "Multi Select Loops";
1068 ot->idname = "MESH_OT_loop_multi_select";
1069 ot->description = "Select a loop of connected edges by connection type";
1072 ot->exec = edbm_loop_multiselect_exec;
1073 ot->poll = ED_operator_editmesh;
1076 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1079 RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
1083 /* ***************** MAIN MOUSE SELECTION ************** */
1086 /* ***************** loop select (non modal) ************** */
1088 static void mouse_mesh_loop(bContext *C, int mval[2], short extend, short ring)
1097 em_setup_viewcontext(C, &vc);
1098 mvalf[0] = (float)(vc.mval[0] = mval[0]);
1099 mvalf[1] = (float)(vc.mval[1] = mval[1]);
1102 /* no afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad */
1103 view3d_validate_backbuf(&vc);
1105 eed = EDBM_edge_find_nearest(&vc, &dist);
1108 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
1111 if (BM_elem_flag_test(eed, BM_ELEM_SELECT) == 0) {
1118 if (em->selectmode & SCE_SELECT_FACE) {
1119 walker_select(em, BMW_FACELOOP, eed, select);
1121 else if (em->selectmode & SCE_SELECT_EDGE) {
1123 walker_select(em, BMW_EDGERING, eed, select);
1125 walker_select(em, BMW_LOOP, eed, select);
1127 else if (em->selectmode & SCE_SELECT_VERTEX) {
1129 walker_select(em, BMW_EDGERING, eed, select);
1132 walker_select(em, BMW_LOOP, eed, select);
1135 EDBM_selectmode_flush(em);
1137 /* sets as active, useful for other tools */
1139 if (em->selectmode & SCE_SELECT_VERTEX) {
1140 /* Find nearest vert from mouse
1141 * (initialize to large values incase only one vertex can be projected) */
1142 float v1_co[2], v2_co[2];
1143 float length_1 = FLT_MAX;
1144 float length_2 = FLT_MAX;
1146 /* We can't be sure this has already been set... */
1147 ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
1149 if (ED_view3d_project_float_object(vc.ar, eed->v1->co, v1_co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
1150 length_1 = len_squared_v2v2(mvalf, v1_co);
1153 if (ED_view3d_project_float_object(vc.ar, eed->v2->co, v2_co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
1154 length_2 = len_squared_v2v2(mvalf, v2_co);
1157 printf("mouse to v1: %f\nmouse to v2: %f\n", len_squared_v2v2(mvalf, v1_co),
1158 len_squared_v2v2(mvalf, v2_co));
1160 BM_select_history_store(em->bm, (length_1 < length_2) ? eed->v1 : eed->v2);
1162 else if (em->selectmode & SCE_SELECT_EDGE) {
1163 BM_select_history_store(em->bm, eed);
1165 else if (em->selectmode & SCE_SELECT_FACE) {
1166 /* Select the face of eed which is the nearest of mouse. */
1167 BMFace *f, *efa = NULL;
1169 float best_dist = MAXFLOAT;
1171 /* We can't be sure this has already been set... */
1172 ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
1174 BM_ITER_ELEM(f, &iterf, eed, BM_FACES_OF_EDGE) {
1175 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
1179 BM_face_calc_center_mean(f, cent);
1180 if (ED_view3d_project_float_object(vc.ar, cent, co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
1181 tdist = len_squared_v2v2(mvalf, co);
1182 if (tdist < best_dist) {
1183 /* printf("Best face: %p (%f)\n", f, tdist);*/
1191 BM_active_face_set(em->bm, efa);
1192 BM_select_history_store(em->bm, efa);
1197 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit);
1201 static int edbm_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
1204 view3d_operator_needs_opengl(C);
1206 mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"),
1207 RNA_boolean_get(op->ptr, "ring"));
1209 /* cannot do tweaks for as long this keymap is after transform map */
1210 return OPERATOR_FINISHED;
1213 void MESH_OT_loop_select(wmOperatorType *ot)
1216 ot->name = "Loop Select";
1217 ot->idname = "MESH_OT_loop_select";
1218 ot->description = "Select a loop of connected edges";
1221 ot->invoke = edbm_select_loop_invoke;
1222 ot->poll = ED_operator_editmesh_region_view3d;
1225 ot->flag = OPTYPE_UNDO;
1228 RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "Extend the selection");
1229 RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "Select ring");
1232 void MESH_OT_edgering_select(wmOperatorType *ot)
1235 ot->name = "Edge Ring Select";
1236 ot->idname = "MESH_OT_edgering_select";
1237 ot->description = "Select an edge ring";
1240 ot->invoke = edbm_select_loop_invoke;
1241 ot->poll = ED_operator_editmesh_region_view3d;
1244 ot->flag = OPTYPE_UNDO;
1246 RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
1247 RNA_def_boolean(ot->srna, "ring", 1, "Select Ring", "Select ring");
1250 /* ******************* generic tag_shortest_path and helpers ****************** */
1252 static float step_cost_3_v3(const float v1[3], const float v2[3], const float v3[3])
1254 float cost, d1[3], d2[3];
1257 /* The cost is based on the simple sum of the length of the two edgees... */
1258 sub_v3_v3v3(d1, v2, v1);
1259 sub_v3_v3v3(d2, v3, v2);
1260 cost = len_v3(d1) + len_v3(d2);
1262 /* but is biased to give higher values to sharp turns, so that it will take
1263 * paths with fewer "turns" when selecting between equal-weighted paths between
1265 cost = cost + 0.5f * cost * (2.0f - sqrtf(fabsf(dot_v3v3(d1, d2))));
1270 /* ******************* edgetag_shortest_path and helpers ****************** */
1272 static float edgetag_cut_cost(BMEdge *e1, BMEdge *e2, BMVert *v)
1274 BMVert *v1 = BM_edge_other_vert(e1, v);
1275 BMVert *v2 = BM_edge_other_vert(e2, v);
1276 return step_cost_3_v3(v1->co, v->co, v2->co);
1279 static void edgetag_add_adjacent(Heap *heap, BMEdge *e1, BMEdge **edges_prev, float *cost)
1287 const int e1_index = BM_elem_index_get(e1);
1289 BM_ITER_ELEM (v, &viter, e1, BM_VERTS_OF_EDGE) {
1290 BM_ITER_ELEM (e2, &eiter, v, BM_EDGES_OF_VERT) {
1291 if (!BM_elem_flag_test(e2, BM_ELEM_TAG)) {
1292 /* we know 'e2' is not visited, check it out! */
1293 const int e2_index = BM_elem_index_get(e2);
1294 const float cost_cut = edgetag_cut_cost(e1, e2, v);
1295 const float cost_new = cost[e1_index] + cost_cut;
1297 if (cost[e2_index] > cost_new) {
1298 cost[e2_index] = cost_new;
1299 edges_prev[e2_index] = e1;
1300 BLI_heap_insert(heap, cost_new, e2);
1307 static void edgetag_context_set(BMesh *bm, Scene *scene, BMEdge *e, int val)
1310 switch (scene->toolsettings->edge_mode) {
1311 case EDGE_MODE_SELECT:
1312 BM_edge_select_set(bm, e, val);
1314 case EDGE_MODE_TAG_SEAM:
1315 BM_elem_flag_set(e, BM_ELEM_SEAM, val);
1317 case EDGE_MODE_TAG_SHARP:
1318 BM_elem_flag_set(e, BM_ELEM_SMOOTH, !val);
1320 case EDGE_MODE_TAG_FREESTYLE:
1321 BM_elem_flag_set(e, BM_ELEM_FREESTYLE, val);
1323 case EDGE_MODE_TAG_CREASE:
1324 BM_elem_float_data_set(&bm->edata, e, CD_CREASE, (val) ? 1.0f : 0.0f);
1326 case EDGE_MODE_TAG_BEVEL:
1327 BM_elem_float_data_set(&bm->edata, e, CD_BWEIGHT, (val) ? 1.0f : 0.0f);
1332 static int edgetag_context_check(Scene *scene, BMesh *bm, BMEdge *e)
1334 switch (scene->toolsettings->edge_mode) {
1335 case EDGE_MODE_SELECT:
1336 return BM_elem_flag_test(e, BM_ELEM_SELECT) ? TRUE : FALSE;
1337 case EDGE_MODE_TAG_SEAM:
1338 return BM_elem_flag_test(e, BM_ELEM_SEAM);
1339 case EDGE_MODE_TAG_SHARP:
1340 return !BM_elem_flag_test(e, BM_ELEM_SMOOTH);
1341 case EDGE_MODE_TAG_FREESTYLE:
1342 return !BM_elem_flag_test(e, BM_ELEM_FREESTYLE);
1343 case EDGE_MODE_TAG_CREASE:
1344 return BM_elem_float_data_get(&bm->edata, e, CD_CREASE) ? TRUE : FALSE;
1345 case EDGE_MODE_TAG_BEVEL:
1346 return BM_elem_float_data_get(&bm->edata, e, CD_BWEIGHT) ? TRUE : FALSE;
1351 static int edgetag_shortest_path(Scene *scene, BMesh *bm, BMEdge *e_src, BMEdge *e_dst)
1353 /* BM_ELEM_TAG flag is used to store visited edges */
1358 BMEdge **edges_prev;
1361 /* note, would pass BM_EDGE except we are looping over all edges anyway */
1362 BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */);
1364 BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) {
1365 if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == FALSE) {
1366 BM_elem_flag_disable(e, BM_ELEM_TAG);
1369 BM_elem_flag_enable(e, BM_ELEM_TAG);
1372 BM_elem_index_set(e, i); /* set_inline */
1374 bm->elem_index_dirty &= ~BM_EDGE;
1377 totedge = bm->totedge;
1378 edges_prev = MEM_callocN(sizeof(*edges_prev) * totedge, "SeamPathPrevious");
1379 cost = MEM_mallocN(sizeof(*cost) * totedge, "SeamPathCost");
1381 fill_vn_fl(cost, totedge, 1e20f);
1384 * Arrays are now filled as follows:
1386 * As the search continues, prevedge[n] will be the previous edge on the shortest
1387 * path found so far to edge n. The visitedhash will of course contain entries
1388 * for edges that have been visited, cost[n] will contain the length of the shortest
1389 * path to edge n found so far, Finally, heap is a priority heap which is built on the
1390 * the same data as the cost array, but inverted: it is a worklist of edges prioritized
1391 * by the shortest path found so far to the edge.
1394 /* regular dijkstra shortest path, but over edges instead of vertices */
1395 heap = BLI_heap_new();
1396 BLI_heap_insert(heap, 0.0f, e_src);
1397 cost[BM_elem_index_get(e_src)] = 0.0f;
1401 while (!BLI_heap_is_empty(heap)) {
1402 e = BLI_heap_popmin(heap);
1407 if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
1408 BM_elem_flag_enable(e, BM_ELEM_TAG);
1409 edgetag_add_adjacent(heap, e, edges_prev, cost);
1414 short all_set = TRUE;
1416 /* Check whether the path is already completely tagged.
1417 * if it is, the tags will be cleared instead of set. */
1420 if (!edgetag_context_check(scene, bm, e)) {
1424 } while ((e = edges_prev[BM_elem_index_get(e)]));
1426 /* Follow path back and source and add or remove tags */
1429 edgetag_context_set(bm, scene, e, !all_set);
1430 } while ((e = edges_prev[BM_elem_index_get(e)]));
1433 MEM_freeN(edges_prev);
1435 BLI_heap_free(heap, NULL);
1440 /* ******************* mesh shortest path select, uses prev-selected edge ****************** */
1442 /* since you want to create paths with multiple selects, it doesn't have extend option */
1443 static int mouse_mesh_shortest_path_edge(bContext *C, ViewContext *vc)
1445 BMEditMesh *em = vc->em;
1449 e_dst = EDBM_edge_find_nearest(vc, &dist);
1451 Mesh *me = vc->obedit->data;
1454 if (em->bm->selected.last) {
1455 BMEditSelection *ese = em->bm->selected.last;
1457 if (ese && ese->htype == BM_EDGE) {
1459 e_act = (BMEdge *)ese->ele;
1460 if (e_act != e_dst) {
1461 if (edgetag_shortest_path(vc->scene, em->bm, e_act, e_dst)) {
1462 BM_select_history_remove(em->bm, e_act);
1469 int act = (edgetag_context_check(vc->scene, em->bm, e_dst) == 0);
1470 edgetag_context_set(em->bm, vc->scene, e_dst, act); /* switch the edge option */
1473 EDBM_selectmode_flush(em);
1475 /* even if this is selected it may not be in the selection list */
1476 if (edgetag_context_check(vc->scene, em->bm, e_dst) == 0)
1477 BM_select_history_remove(em->bm, e_dst);
1479 BM_select_history_store(em->bm, e_dst);
1481 /* force drawmode for mesh */
1482 switch (CTX_data_tool_settings(C)->edge_mode) {
1484 case EDGE_MODE_TAG_SEAM:
1485 me->drawflag |= ME_DRAWSEAMS;
1486 ED_uvedit_live_unwrap(vc->scene, vc->obedit);
1488 case EDGE_MODE_TAG_SHARP:
1489 me->drawflag |= ME_DRAWSHARP;
1491 case EDGE_MODE_TAG_CREASE:
1492 me->drawflag |= ME_DRAWCREASES;
1494 case EDGE_MODE_TAG_BEVEL:
1495 me->drawflag |= ME_DRAWBWEIGHTS;
1497 case EDGE_MODE_TAG_FREESTYLE:
1498 me->drawflag |= ME_DRAW_FREESTYLE_EDGE;
1502 EDBM_update_generic(C, em, FALSE);
1512 /* ******************* facetag_shortest_path and helpers ****************** */
1515 static float facetag_cut_cost(BMFace *f1, BMFace *f2, BMEdge *e)
1521 BM_face_calc_center_mean(f1, f1_cent);
1522 BM_face_calc_center_mean(f2, f2_cent);
1523 mid_v3_v3v3(e_cent, e->v1->co, e->v2->co);
1525 return step_cost_3_v3(f1_cent, e_cent, f2_cent);
1528 static void facetag_add_adjacent(Heap *heap, BMFace *f1, BMFace **faces_prev, float *cost)
1534 const int f1_index = BM_elem_index_get(f1);
1536 /* loop over faces of face, but do so by first looping over loops */
1537 BM_ITER_ELEM (l2, &liter, f1, BM_LOOPS_OF_FACE) {
1541 l_iter = l_first = l2;
1544 if (!BM_elem_flag_test(f2, BM_ELEM_TAG)) {
1545 /* we know 'f2' is not visited, check it out! */
1546 const int f2_index = BM_elem_index_get(f2);
1547 const float cost_cut = facetag_cut_cost(f1, f2, l_iter->e);
1548 const float cost_new = cost[f1_index] + cost_cut;
1550 if (cost[f2_index] > cost_new) {
1551 cost[f2_index] = cost_new;
1552 faces_prev[f2_index] = f1;
1553 BLI_heap_insert(heap, cost_new, f2);
1556 } while ((l_iter = l_iter->radial_next) != l_first);
1560 static void facetag_context_set(BMesh *bm, Scene *UNUSED(scene), BMFace *f, int val)
1562 BM_face_select_set(bm, f, val);
1565 static int facetag_context_check(Scene *UNUSED(scene), BMesh *UNUSED(bm), BMFace *f)
1567 return BM_elem_flag_test(f, BM_ELEM_SELECT) ? 1 : 0;
1570 static int facetag_shortest_path(Scene *scene, BMesh *bm, BMFace *f_src, BMFace *f_dst)
1572 /* BM_ELEM_TAG flag is used to store visited edges */
1577 BMFace **faces_prev;
1580 /* note, would pass BM_EDGE except we are looping over all faces anyway */
1581 // BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */); // NOT NEEDED FOR FACETAG
1583 BM_ITER_MESH_INDEX (f, &fiter, bm, BM_FACES_OF_MESH, i) {
1584 if (BM_elem_flag_test(f, BM_ELEM_HIDDEN) == FALSE) {
1585 BM_elem_flag_disable(f, BM_ELEM_TAG);
1588 BM_elem_flag_enable(f, BM_ELEM_TAG);
1591 BM_elem_index_set(f, i); /* set_inline */
1593 bm->elem_index_dirty &= ~BM_FACE;
1596 totface = bm->totface;
1597 faces_prev = MEM_callocN(sizeof(*faces_prev) * totface, "SeamPathPrevious");
1598 cost = MEM_mallocN(sizeof(*cost) * totface, "SeamPathCost");
1600 fill_vn_fl(cost, totface, 1e20f);
1603 * Arrays are now filled as follows:
1605 * As the search continues, faces_prev[n] will be the previous face on the shortest
1606 * path found so far to face n. The visitedhash will of course contain entries
1607 * for faces that have been visited, cost[n] will contain the length of the shortest
1608 * path to face n found so far, Finally, heap is a priority heap which is built on the
1609 * the same data as the cost array, but inverted: it is a worklist of faces prioritized
1610 * by the shortest path found so far to the face.
1613 /* regular dijkstra shortest path, but over faces instead of vertices */
1614 heap = BLI_heap_new();
1615 BLI_heap_insert(heap, 0.0f, f_src);
1616 cost[BM_elem_index_get(f_src)] = 0.0f;
1620 while (!BLI_heap_is_empty(heap)) {
1621 f = BLI_heap_popmin(heap);
1626 if (!BM_elem_flag_test(f, BM_ELEM_TAG)) {
1627 BM_elem_flag_enable(f, BM_ELEM_TAG);
1628 facetag_add_adjacent(heap, f, faces_prev, cost);
1633 short all_set = TRUE;
1635 /* Check whether the path is already completely tagged.
1636 * if it is, the tags will be cleared instead of set. */
1639 if (!facetag_context_check(scene, bm, f)) {
1643 } while ((f = faces_prev[BM_elem_index_get(f)]));
1645 /* Follow path back and source and add or remove tags */
1648 facetag_context_set(bm, scene, f, !all_set);
1649 } while ((f = faces_prev[BM_elem_index_get(f)]));
1652 MEM_freeN(faces_prev);
1654 BLI_heap_free(heap, NULL);
1659 static int mouse_mesh_shortest_path_face(bContext *C, ViewContext *vc)
1661 BMEditMesh *em = vc->em;
1665 f_dst = EDBM_face_find_nearest(vc, &dist);
1668 BMFace *f_act = BM_active_face_get(em->bm, FALSE, TRUE);
1671 if (f_act != f_dst) {
1672 if (facetag_shortest_path(vc->scene, em->bm, f_act, f_dst)) {
1673 BM_select_history_remove(em->bm, f_act);
1679 int act = (facetag_context_check(vc->scene, em->bm, f_dst) == 0);
1680 facetag_context_set(em->bm, vc->scene, f_dst, act); /* switch the face option */
1683 EDBM_selectmode_flush(em);
1685 /* even if this is selected it may not be in the selection list */
1686 if (facetag_context_check(vc->scene, em->bm, f_dst) == 0)
1687 BM_select_history_remove(em->bm, f_dst);
1689 BM_select_history_store(em->bm, f_dst);
1691 BM_active_face_set(em->bm, f_dst);
1693 EDBM_update_generic(C, em, FALSE);
1703 /* ******************* operator for edge and face tag ****************** */
1705 static int edbm_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
1710 view3d_operator_needs_opengl(C);
1712 em_setup_viewcontext(C, &vc);
1713 vc.mval[0] = event->mval[0];
1714 vc.mval[1] = event->mval[1];
1717 if (em->selectmode & SCE_SELECT_EDGE) {
1718 if (mouse_mesh_shortest_path_edge(C, &vc)) {
1719 return OPERATOR_FINISHED;
1722 return OPERATOR_PASS_THROUGH;
1725 else if (em->selectmode & SCE_SELECT_FACE) {
1726 if (mouse_mesh_shortest_path_face(C, &vc)) {
1727 return OPERATOR_FINISHED;
1730 return OPERATOR_PASS_THROUGH;
1734 return OPERATOR_PASS_THROUGH;
1737 static int edbm_shortest_path_select_poll(bContext *C)
1739 if (ED_operator_editmesh_region_view3d(C)) {
1740 Object *obedit = CTX_data_edit_object(C);
1741 BMEditMesh *em = BMEdit_FromObject(obedit);
1742 return (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_FACE)) != 0;
1747 void MESH_OT_select_shortest_path(wmOperatorType *ot)
1750 ot->name = "Shortest Path Select";
1751 ot->idname = "MESH_OT_select_shortest_path";
1752 ot->description = "Select shortest path between two selections";
1755 ot->invoke = edbm_shortest_path_select_invoke;
1756 ot->poll = edbm_shortest_path_select_poll;
1759 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1762 RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
1765 /* ************************************************** */
1766 /* here actual select happens */
1767 /* gets called via generic mouse select operator */
1768 int EDBM_select_pick(bContext *C, const int mval[2], short extend, short deselect, short toggle)
1775 /* setup view context for argument to callbacks */
1776 em_setup_viewcontext(C, &vc);
1777 vc.mval[0] = mval[0];
1778 vc.mval[1] = mval[1];
1780 if (unified_findnearest(&vc, &eve, &eed, &efa)) {
1782 /* Deselect everything */
1783 if (extend == 0 && deselect == 0 && toggle == 0)
1784 EDBM_flag_disable_all(vc.em, BM_ELEM_SELECT);
1788 /* set the last selected face */
1789 BM_active_face_set(vc.em->bm, efa);
1791 /* Work-around: deselect first, so we can guarantee it will */
1792 /* be active even if it was already selected */
1793 BM_select_history_remove(vc.em->bm, efa);
1794 BM_face_select_set(vc.em->bm, efa, FALSE);
1795 BM_select_history_store(vc.em->bm, efa);
1796 BM_face_select_set(vc.em->bm, efa, TRUE);
1798 else if (deselect) {
1799 BM_select_history_remove(vc.em->bm, efa);
1800 BM_face_select_set(vc.em->bm, efa, FALSE);
1803 /* set the last selected face */
1804 BM_active_face_set(vc.em->bm, efa);
1806 if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1807 BM_select_history_store(vc.em->bm, efa);
1808 BM_face_select_set(vc.em->bm, efa, TRUE);
1811 BM_select_history_remove(vc.em->bm, efa);
1812 BM_face_select_set(vc.em->bm, efa, FALSE);
1818 /* Work-around: deselect first, so we can guarantee it will */
1819 /* be active even if it was already selected */
1820 BM_select_history_remove(vc.em->bm, eed);
1821 BM_edge_select_set(vc.em->bm, eed, FALSE);
1822 BM_select_history_store(vc.em->bm, eed);
1823 BM_edge_select_set(vc.em->bm, eed, TRUE);
1825 else if (deselect) {
1826 BM_select_history_remove(vc.em->bm, eed);
1827 BM_edge_select_set(vc.em->bm, eed, FALSE);
1830 if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1831 BM_select_history_store(vc.em->bm, eed);
1832 BM_edge_select_set(vc.em->bm, eed, TRUE);
1835 BM_select_history_remove(vc.em->bm, eed);
1836 BM_edge_select_set(vc.em->bm, eed, FALSE);
1842 /* Work-around: deselect first, so we can guarantee it will */
1843 /* be active even if it was already selected */
1844 BM_select_history_remove(vc.em->bm, eve);
1845 BM_vert_select_set(vc.em->bm, eve, FALSE);
1846 BM_select_history_store(vc.em->bm, eve);
1847 BM_vert_select_set(vc.em->bm, eve, TRUE);
1849 else if (deselect) {
1850 BM_select_history_remove(vc.em->bm, eve);
1851 BM_vert_select_set(vc.em->bm, eve, FALSE);
1854 if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
1855 BM_select_history_store(vc.em->bm, eve);
1856 BM_vert_select_set(vc.em->bm, eve, TRUE);
1859 BM_select_history_remove(vc.em->bm, eve);
1860 BM_vert_select_set(vc.em->bm, eve, FALSE);
1865 EDBM_selectmode_flush(vc.em);
1867 /* change active material on object */
1868 if (efa && efa->mat_nr != vc.obedit->actcol - 1) {
1869 vc.obedit->actcol = efa->mat_nr + 1;
1870 vc.em->mat_nr = efa->mat_nr;
1872 WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING, NULL);
1876 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit);
1883 static void edbm_strip_selections(BMEditMesh *em)
1885 BMEditSelection *ese, *nextese;
1887 if (!(em->selectmode & SCE_SELECT_VERTEX)) {
1888 ese = em->bm->selected.first;
1890 nextese = ese->next;
1891 if (ese->htype == BM_VERT) BLI_freelinkN(&(em->bm->selected), ese);
1895 if (!(em->selectmode & SCE_SELECT_EDGE)) {
1896 ese = em->bm->selected.first;
1898 nextese = ese->next;
1899 if (ese->htype == BM_EDGE) BLI_freelinkN(&(em->bm->selected), ese);
1903 if (!(em->selectmode & SCE_SELECT_FACE)) {
1904 ese = em->bm->selected.first;
1906 nextese = ese->next;
1907 if (ese->htype == BM_FACE) BLI_freelinkN(&(em->bm->selected), ese);
1913 /* when switching select mode, makes sure selection is consistent for editing */
1914 /* also for paranoia checks to make sure edge or face mode works */
1915 void EDBM_selectmode_set(BMEditMesh *em)
1922 em->bm->selectmode = em->selectmode;
1924 edbm_strip_selections(em); /* strip BMEditSelections from em->selected that are not relevant to new mode */
1926 if (em->selectmode & SCE_SELECT_VERTEX) {
1927 EDBM_select_flush(em);
1929 else if (em->selectmode & SCE_SELECT_EDGE) {
1930 /* deselect vertices, and select again based on edge select */
1931 eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
1932 for (; eve; eve = BM_iter_step(&iter)) BM_vert_select_set(em->bm, eve, FALSE);
1934 eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
1935 for (; eed; eed = BM_iter_step(&iter)) {
1936 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1937 BM_edge_select_set(em->bm, eed, TRUE);
1941 /* selects faces based on edge status */
1942 EDBM_selectmode_flush(em);
1944 else if (em->selectmode & SCE_SELECT_FACE) {
1945 /* deselect eges, and select again based on face select */
1946 eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
1947 for (; eed; eed = BM_iter_step(&iter)) BM_edge_select_set(em->bm, eed, FALSE);
1949 efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL);
1950 for (; efa; efa = BM_iter_step(&iter)) {
1951 if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1952 BM_face_select_set(em->bm, efa, TRUE);
1958 void EDBM_selectmode_convert(BMEditMesh *em, const short selectmode_old, const short selectmode_new)
1964 /* first tag-to-select, then select --- this avoids a feedback loop */
1966 /* have to find out what the selectionmode was previously */
1967 if (selectmode_old == SCE_SELECT_VERTEX) {
1968 if (selectmode_new == SCE_SELECT_EDGE) {
1969 /* select all edges associated with every selected vert */
1970 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1971 BM_elem_flag_set(eed, BM_ELEM_TAG, BM_edge_is_any_vert_flag_test(eed, BM_ELEM_SELECT));
1974 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1975 if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
1976 BM_edge_select_set(em->bm, eed, TRUE);
1980 else if (selectmode_new == SCE_SELECT_FACE) {
1981 /* select all faces associated with every selected vert */
1982 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1983 BM_elem_flag_set(efa, BM_ELEM_TAG, BM_face_is_any_vert_flag_test(efa, BM_ELEM_SELECT));
1986 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1987 if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
1988 BM_face_select_set(em->bm, efa, TRUE);
1993 else if (selectmode_old == SCE_SELECT_EDGE) {
1994 if (selectmode_new == SCE_SELECT_FACE) {
1995 /* select all faces associated with every selected edge */
1996 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1997 BM_elem_flag_set(efa, BM_ELEM_TAG, BM_face_is_any_edge_flag_test(efa, BM_ELEM_SELECT));
2000 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2001 if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2002 BM_face_select_set(em->bm, efa, TRUE);
2009 /* user facing function, does notification and undo push */
2010 int EDBM_selectmode_toggle(bContext *C, const short selectmode_new,
2011 const int action, const int use_extend, const int use_expand)
2013 ToolSettings *ts = CTX_data_tool_settings(C);
2014 Object *obedit = CTX_data_edit_object(C);
2015 BMEditMesh *em = NULL;
2018 if (obedit && obedit->type == OB_MESH) {
2019 em = BMEdit_FromObject(obedit);
2030 case 0: /* disable */
2031 /* check we have something to do */
2032 if ((em->selectmode & selectmode_new) == 0) {
2035 em->selectmode &= ~selectmode_new;
2037 case 1: /* enable */
2038 /* check we have something to do */
2039 if ((em->selectmode & selectmode_new) != 0) {
2042 em->selectmode |= selectmode_new;
2044 case 2: /* toggle */
2045 /* can't disable this flag if its the only one set */
2046 if (em->selectmode == selectmode_new) {
2049 em->selectmode ^= selectmode_new;
2055 switch (selectmode_new) {
2056 case SCE_SELECT_VERTEX:
2057 if (use_extend == 0 || em->selectmode == 0)
2058 em->selectmode = SCE_SELECT_VERTEX;
2059 ts->selectmode = em->selectmode;
2060 EDBM_selectmode_set(em);
2063 case SCE_SELECT_EDGE:
2064 if (use_extend == 0 || em->selectmode == 0) {
2066 const short selmode_max = highest_order_bit_s(ts->selectmode);
2067 if (selmode_max == SCE_SELECT_VERTEX) {
2068 EDBM_selectmode_convert(em, selmode_max, SCE_SELECT_EDGE);
2071 em->selectmode = SCE_SELECT_EDGE;
2073 ts->selectmode = em->selectmode;
2074 EDBM_selectmode_set(em);
2077 case SCE_SELECT_FACE:
2078 if (use_extend == 0 || em->selectmode == 0) {
2080 const short selmode_max = highest_order_bit_s(ts->selectmode);
2081 if (ELEM(selmode_max, SCE_SELECT_VERTEX, SCE_SELECT_EDGE)) {
2082 EDBM_selectmode_convert(em, selmode_max, SCE_SELECT_FACE);
2086 em->selectmode = SCE_SELECT_FACE;
2088 ts->selectmode = em->selectmode;
2089 EDBM_selectmode_set(em);
2098 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2099 WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
2105 void EDBM_deselect_by_material(BMEditMesh *em, const short index, const short select)
2110 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2111 if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
2113 if (efa->mat_nr == index) {
2114 BM_face_select_set(em->bm, efa, select);
2119 void EDBM_select_toggle_all(BMEditMesh *em) /* exported for UV */
2121 if (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel)
2122 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
2124 EDBM_flag_enable_all(em, BM_ELEM_SELECT);
2127 void EDBM_select_swap(BMEditMesh *em) /* exported for UV */
2134 if (em->bm->selectmode & SCE_SELECT_VERTEX) {
2135 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2136 if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
2138 BM_vert_select_set(em->bm, eve, !BM_elem_flag_test(eve, BM_ELEM_SELECT));
2141 else if (em->selectmode & SCE_SELECT_EDGE) {
2142 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2143 if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
2145 BM_edge_select_set(em->bm, eed, !BM_elem_flag_test(eed, BM_ELEM_SELECT));
2149 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2150 if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
2152 BM_face_select_set(em->bm, efa, !BM_elem_flag_test(efa, BM_ELEM_SELECT));
2156 // if (EM_texFaceCheck())
2159 int EDBM_select_interior_faces(BMEditMesh *em)
2169 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2170 if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
2175 BM_ITER_ELEM (eed, &eiter, efa, BM_EDGES_OF_FACE) {
2176 if (BM_edge_face_count(eed) < 3) {
2183 BM_face_select_set(bm, efa, TRUE);
2191 static void linked_limit_default(bContext *C, wmOperator *op)
2193 if (!RNA_struct_property_is_set(op->ptr, "limit")) {
2194 Object *obedit = CTX_data_edit_object(C);
2195 BMEditMesh *em = BMEdit_FromObject(obedit);
2196 if (em->selectmode == SCE_SELECT_FACE)
2197 RNA_boolean_set(op->ptr, "limit", TRUE);
2199 RNA_boolean_set(op->ptr, "limit", FALSE);
2203 static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
2205 Object *obedit = CTX_data_edit_object(C);
2213 int sel = !RNA_boolean_get(op->ptr, "deselect");
2217 linked_limit_default(C, op);
2219 limit = RNA_boolean_get(op->ptr, "limit");
2221 /* unified_finednearest needs ogl */
2222 view3d_operator_needs_opengl(C);
2224 /* setup view context for argument to callbacks */
2225 em_setup_viewcontext(C, &vc);
2228 if (em->bm->totedge == 0)
2229 return OPERATOR_CANCELLED;
2233 vc.mval[0] = event->mval[0];
2234 vc.mval[1] = event->mval[1];
2236 /* return warning! */
2238 if (unified_findnearest(&vc, &eve, &eed, &efa) == 0) {
2239 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
2241 return OPERATOR_CANCELLED;
2244 if (em->selectmode == SCE_SELECT_FACE) {
2248 return OPERATOR_CANCELLED;
2251 /* hflag no-seam --> bmo-tag */
2252 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
2253 /* BMESH_TODO, don't use 'BM_ELEM_SELECT' here, its a HFLAG only! */
2254 BMO_elem_flag_set(bm, e, BM_ELEM_SELECT, !BM_elem_flag_test(e, BM_ELEM_SEAM));
2259 BMW_init(&walker, bm, BMW_ISLAND,
2260 BMW_MASK_NOP, limit ? BM_ELEM_SELECT : BMW_MASK_NOP, BMW_MASK_NOP,
2261 BMW_FLAG_TEST_HIDDEN,
2264 e = BMW_begin(&walker, efa);
2265 for (; efa; efa = BMW_step(&walker)) {
2266 BM_face_select_set(bm, efa, sel);
2272 eed = BM_FACE_FIRST_LOOP(efa)->e;
2275 if (!eve || !eve->e)
2276 return OPERATOR_CANCELLED;
2281 BMW_init(&walker, bm, BMW_SHELL,
2282 BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
2283 BMW_FLAG_TEST_HIDDEN,
2286 e = BMW_begin(&walker, eed->v1);
2287 for (; e; e = BMW_step(&walker)) {
2288 BM_edge_select_set(bm, e, sel);
2292 EDBM_selectmode_flush(em);
2295 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
2296 return OPERATOR_FINISHED;
2299 void MESH_OT_select_linked_pick(wmOperatorType *ot)
2302 ot->name = "Select Linked";
2303 ot->idname = "MESH_OT_select_linked_pick";
2304 ot->description = "(De)select all vertices linked to the edge under the mouse cursor";
2307 ot->invoke = edbm_select_linked_pick_invoke;
2308 ot->poll = ED_operator_editmesh;
2311 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2313 RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
2314 RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
2318 static int edbm_select_linked_exec(bContext *C, wmOperator *op)
2320 Object *obedit = CTX_data_edit_object(C);
2321 BMEditMesh *em = BMEdit_FromObject(obedit);
2330 linked_limit_default(C, op);
2332 limit = RNA_boolean_get(op->ptr, "limit");
2334 if (em->selectmode == SCE_SELECT_FACE) {
2337 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2338 BM_elem_flag_set(efa, BM_ELEM_TAG, (BM_elem_flag_test(efa, BM_ELEM_SELECT) &&
2339 !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)));
2343 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
2344 /* BMESH_TODO, don't use 'BM_ELEM_SELECT' here, its a HFLAG only! */
2345 BMO_elem_flag_set(bm, e, BM_ELEM_SELECT, !BM_elem_flag_test(e, BM_ELEM_SEAM));
2349 BMW_init(&walker, bm, BMW_ISLAND,
2350 BMW_MASK_NOP, limit ? BM_ELEM_SELECT : BMW_MASK_NOP, BMW_MASK_NOP,
2351 BMW_FLAG_TEST_HIDDEN,
2354 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2355 if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2356 e = BMW_begin(&walker, efa);
2357 for (; efa; efa = BMW_step(&walker)) {
2358 BM_face_select_set(bm, efa, TRUE);
2365 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2366 if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
2367 BM_elem_flag_enable(v, BM_ELEM_TAG);
2370 BM_elem_flag_disable(v, BM_ELEM_TAG);
2374 BMW_init(&walker, em->bm, BMW_SHELL,
2375 BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
2376 BMW_FLAG_TEST_HIDDEN,
2379 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2380 if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
2381 e = BMW_begin(&walker, v);
2382 for (; e; e = BMW_step(&walker)) {
2383 BM_vert_select_set(em->bm, e->v1, TRUE);
2384 BM_vert_select_set(em->bm, e->v2, TRUE);
2390 EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
2392 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
2394 return OPERATOR_FINISHED;
2397 void MESH_OT_select_linked(wmOperatorType *ot)
2400 ot->name = "Select Linked All";
2401 ot->idname = "MESH_OT_select_linked";
2402 ot->description = "Select all vertices linked to the active mesh";
2405 ot->exec = edbm_select_linked_exec;
2406 ot->poll = ED_operator_editmesh;
2409 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2411 RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
2414 /* ******************** **************** */
2416 static int edbm_select_more_exec(bContext *C, wmOperator *UNUSED(op))
2418 Object *obedit = CTX_data_edit_object(C);
2419 BMEditMesh *em = BMEdit_FromObject(obedit);
2421 EDBM_select_more(em);
2423 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
2424 return OPERATOR_FINISHED;
2427 void MESH_OT_select_more(wmOperatorType *ot)
2430 ot->name = "Select More";
2431 ot->idname = "MESH_OT_select_more";
2432 ot->description = "Select more vertices, edges or faces connected to initial selection";
2435 ot->exec = edbm_select_more_exec;
2436 ot->poll = ED_operator_editmesh;
2439 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2442 static int edbm_select_less_exec(bContext *C, wmOperator *UNUSED(op))
2444 Object *obedit = CTX_data_edit_object(C);
2445 BMEditMesh *em = BMEdit_FromObject(obedit);
2447 EDBM_select_less(em);
2449 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
2450 return OPERATOR_FINISHED;
2453 void MESH_OT_select_less(wmOperatorType *ot)
2456 ot->name = "Select Less";
2457 ot->idname = "MESH_OT_select_less";
2458 ot->description = "Deselect vertices, edges or faces at the boundary of each selection region";
2461 ot->exec = edbm_select_less_exec;
2462 ot->poll = ED_operator_editmesh;
2465 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2468 /* Walk all reachable elements of the same type as h_act in breadth-first
2469 * order, starting from h_act. Deselects elements if the depth when they
2470 * are reached is not a multiple of "nth". */
2471 static void walker_deselect_nth(BMEditMesh *em, int nth, int offset, BMHeader *h_act)
2477 int walktype = 0, itertype = 0, flushtype = 0;
2478 short mask_vert = 0, mask_edge = 0, mask_face = 0;
2480 /* No active element from which to start - nothing to do */
2481 if (h_act == NULL) {
2485 /* Determine which type of iter, walker, and select flush to use
2486 * based on type of the elements being deselected */
2487 switch (h_act->htype) {
2489 itertype = BM_VERTS_OF_MESH;
2490 walktype = BMW_CONNECTED_VERTEX;
2491 flushtype = SCE_SELECT_VERTEX;
2492 mask_vert = BM_ELEM_SELECT;
2495 itertype = BM_EDGES_OF_MESH;
2496 walktype = BMW_SHELL;
2497 flushtype = SCE_SELECT_EDGE;
2498 mask_edge = BM_ELEM_SELECT;
2501 itertype = BM_FACES_OF_MESH;
2502 walktype = BMW_ISLAND;
2503 flushtype = SCE_SELECT_FACE;
2504 mask_face = BM_ELEM_SELECT;
2508 /* Walker restrictions uses BMO flags, not header flags,
2509 * so transfer BM_ELEM_SELECT from HFlags onto a BMO flag layer. */
2511 BM_ITER_MESH (ele, &iter, bm, itertype) {
2512 if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
2513 /* BMESH_TODO, don't use 'BM_ELEM_SELECT' here, its a HFLAG only! */
2514 BMO_elem_flag_enable(bm, (BMElemF *)ele, BM_ELEM_SELECT);
2518 /* Walk over selected elements starting at active */
2519 BMW_init(&walker, bm, walktype,
2520 mask_vert, mask_edge, mask_face,
2521 BMW_FLAG_NOP, /* don't use BMW_FLAG_TEST_HIDDEN here since we want to desel all */
2524 /* use tag to avoid touching the same verts twice */
2525 BM_ITER_MESH (ele, &iter, bm, itertype) {
2526 BM_elem_flag_disable(ele, BM_ELEM_TAG);
2529 BLI_assert(walker.order == BMW_BREADTH_FIRST);
2530 for (ele = BMW_begin(&walker, h_act); ele != NULL; ele = BMW_step(&walker)) {
2531 if (!BM_elem_flag_test(ele, BM_ELEM_TAG)) {
2532 /* Deselect elements that aren't at "nth" depth from active */
2533 if ((offset + BMW_current_depth(&walker)) % nth) {
2534 BM_elem_select_set(bm, ele, FALSE);
2536 BM_elem_flag_enable(ele, BM_ELEM_TAG);
2543 /* Flush selection up */
2544 EDBM_selectmode_flush_ex(em, flushtype);
2547 static void deselect_nth_active(BMEditMesh *em, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
2553 BMEditSelection *ese;
2559 EDBM_selectmode_flush(em);
2560 ese = (BMEditSelection *)em->bm->selected.last;
2563 switch (ese->htype) {
2565 *r_eve = (BMVert *)ese->ele;
2568 *r_eed = (BMEdge *)ese->ele;
2571 *r_efa = (BMFace *)ese->ele;
2576 if (em->selectmode & SCE_SELECT_VERTEX) {
2577 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2578 if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
2584 else if (em->selectmode & SCE_SELECT_EDGE) {
2585 BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
2586 if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
2592 else if (em->selectmode & SCE_SELECT_FACE) {
2593 f = BM_active_face_get(em->bm, TRUE, FALSE);
2601 static int edbm_deselect_nth(BMEditMesh *em, int nth, int offset)
2607 deselect_nth_active(em, &v, &e, &f);
2610 walker_deselect_nth(em, nth, offset, &v->head);
2614 walker_deselect_nth(em, nth, offset, &e->head);
2618 walker_deselect_nth(em, nth, offset, &f->head);
2625 static int edbm_select_nth_exec(bContext *C, wmOperator *op)
2627 Object *obedit = CTX_data_edit_object(C);
2628 BMEditMesh *em = BMEdit_FromObject(obedit);
2629 int nth = RNA_int_get(op->ptr, "nth");
2630 int offset = RNA_int_get(op->ptr, "offset");
2632 offset = MIN2(nth, offset);
2634 if (edbm_deselect_nth(em, nth, offset) == 0) {
2635 BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face");
2636 return OPERATOR_CANCELLED;
2639 EDBM_update_generic(C, em, FALSE);
2641 return OPERATOR_FINISHED;
2645 void MESH_OT_select_nth(wmOperatorType *ot)
2648 ot->name = "Checker Deselect";
2649 ot->idname = "MESH_OT_select_nth";
2650 ot->description = "Deselect every Nth element starting from a selected vertex, edge or face";
2653 ot->exec = edbm_select_nth_exec;
2654 ot->poll = ED_operator_editmesh;
2657 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2659 RNA_def_int(ot->srna, "nth", 2, 2, INT_MAX, "Nth Selection", "", 2, 100);
2660 RNA_def_int(ot->srna, "offset", 0, 0, INT_MAX, "Offset", "", 0, 100);
2663 void em_setup_viewcontext(bContext *C, ViewContext *vc)
2665 view3d_set_viewcontext(C, vc);
2668 vc->em = BMEdit_FromObject(vc->obedit);
2672 /* poll call for mesh operators requiring a view3d context */
2673 int EM_view3d_poll(bContext *C)
2675 if (ED_operator_editmesh(C) && ED_operator_view3d_active(C))
2682 static int edbm_select_sharp_edges_exec(bContext *C, wmOperator *op)
2684 /* Find edges that have exactly two neighboring faces,
2685 * check the angle between those faces, and if angle is
2686 * small enough, select the edge
2688 Object *obedit = CTX_data_edit_object(C);
2689 BMEditMesh *em = BMEdit_FromObject(obedit);
2693 const float sharp = RNA_float_get(op->ptr, "sharpness");
2695 BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
2696 if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == FALSE &&
2697 BM_edge_loop_pair(e, &l1, &l2))
2699 /* edge has exactly two neighboring faces, check angle */
2700 const float angle = angle_normalized_v3v3(l1->f->no, l2->f->no);
2702 if (fabsf(angle) > sharp) {
2703 BM_edge_select_set(em->bm, e, TRUE);
2708 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2710 return OPERATOR_FINISHED;
2713 void MESH_OT_edges_select_sharp(wmOperatorType *ot)
2718 ot->name = "Select Sharp Edges";
2719 ot->description = "Select all sharp-enough edges";
2720 ot->idname = "MESH_OT_edges_select_sharp";
2723 ot->exec = edbm_select_sharp_edges_exec;
2724 ot->poll = ED_operator_editmesh;
2727 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2730 prop = RNA_def_float_rotation(ot->srna, "sharpness", 0, NULL, DEG2RADF(0.01f), DEG2RADF(180.0f),
2731 "Sharpness", "", DEG2RADF(1.0f), DEG2RADF(180.0f));
2732 RNA_def_property_float_default(prop, DEG2RADF(30.0f));
2735 static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op)
2737 Object *obedit = CTX_data_edit_object(C);
2738 BMEditMesh *em = BMEdit_FromObject(obedit);
2739 BMIter iter, liter, liter2;
2740 BMFace *f, **stack = NULL;
2741 BLI_array_declare(stack);
2743 float sharp = RNA_float_get(op->ptr, "sharpness");
2746 BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
2747 BM_elem_flag_disable(f, BM_ELEM_TAG);
2750 BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
2751 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))
2754 BLI_array_empty(stack);
2757 BLI_array_grow_one(stack);
2764 BM_face_select_set(em->bm, f, TRUE);
2766 BM_elem_flag_enable(f, BM_ELEM_TAG);
2768 BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
2769 BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) {
2772 if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) || BM_elem_flag_test(l2->f, BM_ELEM_HIDDEN))
2775 /* edge has exactly two neighboring faces, check angle */
2776 angle = angle_normalized_v3v3(f->no, l2->f->no);
2778 /* invalidate: edge too sharp */
2779 if (angle < sharp) {
2780 BLI_array_grow_one(stack);
2789 BLI_array_free(stack);
2791 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2793 return OPERATOR_FINISHED;
2796 void MESH_OT_faces_select_linked_flat(wmOperatorType *ot)
2801 ot->name = "Select Linked Flat Faces";
2802 ot->description = "Select linked faces by angle";
2803 ot->idname = "MESH_OT_faces_select_linked_flat";
2806 ot->exec = edbm_select_linked_flat_faces_exec;
2807 ot->poll = ED_operator_editmesh;
2810 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2813 prop = RNA_def_float_rotation(ot->srna, "sharpness", 0, NULL, DEG2RADF(0.01f), DEG2RADF(180.0f),
2814 "Sharpness", "", DEG2RADF(1.0f), DEG2RADF(180.0f));
2815 RNA_def_property_float_default(prop, DEG2RADF(1.0f));
2818 static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
2820 Object *obedit = CTX_data_edit_object(C);
2821 BMEditMesh *em = BMEdit_FromObject(obedit);
2826 /* Selects isolated verts, and edges that do not have 2 neighboring
2830 if (em->selectmode == SCE_SELECT_FACE) {
2831 BKE_report(op->reports, RPT_ERROR, "Does not work in face selection mode");
2832 return OPERATOR_CANCELLED;
2835 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2836 if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN) && !BM_vert_is_manifold(v)) {
2837 BM_vert_select_set(em->bm, v, TRUE);
2841 BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
2842 if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && !BM_edge_is_manifold(e)) {
2843 BM_edge_select_set(em->bm, e, TRUE);
2847 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2849 return OPERATOR_FINISHED;
2852 void MESH_OT_select_non_manifold(wmOperatorType *ot)
2855 ot->name = "Select Non Manifold";
2856 ot->description = "Select all non-manifold vertices or edges";
2857 ot->idname = "MESH_OT_select_non_manifold";
2860 ot->exec = edbm_select_non_manifold_exec;
2861 ot->poll = ED_operator_editmesh;
2864 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2867 static int edbm_select_random_exec(bContext *C, wmOperator *op)
2869 Object *obedit = CTX_data_edit_object(C);
2870 BMEditMesh *em = BMEdit_FromObject(obedit);
2875 float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
2877 BLI_srand(BLI_rand()); /* random seed */
2879 if (!RNA_boolean_get(op->ptr, "extend"))
2880 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
2882 if (em->selectmode & SCE_SELECT_VERTEX) {
2883 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2884 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BLI_frand() < randfac) {
2885 BM_vert_select_set(em->bm, eve, TRUE);
2888 EDBM_selectmode_flush(em);
2890 else if (em->selectmode & SCE_SELECT_EDGE) {
2891 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2892 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BLI_frand() < randfac) {
2893 BM_edge_select_set(em->bm, eed, TRUE);
2896 EDBM_selectmode_flush(em);
2899 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2900 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BLI_frand() < randfac) {
2901 BM_face_select_set(em->bm, efa, TRUE);
2904 EDBM_selectmode_flush(em);
2907 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2909 return OPERATOR_FINISHED;
2912 void MESH_OT_select_random(wmOperatorType *ot)
2915 ot->name = "Select Random";
2916 ot->description = "Randomly select vertices";
2917 ot->idname = "MESH_OT_select_random";
2920 ot->exec = edbm_select_random_exec;
2921 ot->poll = ED_operator_editmesh;
2924 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2927 RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f,
2928 "Percent", "Percentage of elements to select randomly", 0.f, 100.0f);
2929 RNA_def_boolean(ot->srna, "extend", 0,
2930 "Extend Selection", "Extend selection instead of deselecting everything first");
2933 static int edbm_select_next_loop_exec(bContext *C, wmOperator *UNUSED(op))
2935 Object *obedit = CTX_data_edit_object(C);
2936 BMEditMesh *em = BMEdit_FromObject(obedit);
2941 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2942 BM_elem_flag_disable(v, BM_ELEM_TAG);
2945 BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
2949 BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
2950 if (BM_elem_flag_test(l->v, BM_ELEM_SELECT)) {
2951 BM_elem_flag_enable(l->next->v, BM_ELEM_TAG);
2952 BM_vert_select_set(em->bm, l->v, FALSE);
2957 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2958 if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
2959 BM_vert_select_set(em->bm, v, TRUE);
2963 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
2964 return OPERATOR_FINISHED;
2967 void MESH_OT_select_next_loop(wmOperatorType *ot)
2970 ot->name = "Select Next Loop";
2971 ot->idname = "MESH_OT_select_next_loop";
2972 ot->description = "Select next edge loop adjacent to a selected loop";
2975 ot->exec = edbm_select_next_loop_exec;
2976 ot->poll = ED_operator_editmesh;
2979 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2983 static int edbm_region_to_loop_exec(bContext *C, wmOperator *UNUSED(op))
2985 Object *obedit = CTX_data_edit_object(C);
2986 BMEditMesh *em = BMEdit_FromObject(obedit);
2991 BM_mesh_elem_hflag_disable_all(em->bm, BM_EDGE, BM_ELEM_TAG, FALSE);
2993 BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
2995 BMIter liter1, liter2;
2997 BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) {
2998 int tot = 0, totsel = 0;
3000 BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) {
3002 totsel += BM_elem_flag_test(l2->f, BM_ELEM_SELECT) != 0;
3005 if ((tot != totsel && totsel > 0) || (totsel == 1 && tot == 1))
3006 BM_elem_flag_enable(l1->e, BM_ELEM_TAG);
3010 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
3012 BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
3013 if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
3014 BM_edge_select_set(em->bm, e, TRUE);
3018 /* If in face-only select mode, switch to edge select mode so that
3019 * an edge-only selection is not inconsistent state */
3020 if (em->selectmode == SCE_SELECT_FACE) {
3021 em->selectmode = SCE_SELECT_EDGE;
3022 EDBM_selectmode_set(em);
3023 EDBM_selectmode_to_scene(C);
3026 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
3028 return OPERATOR_FINISHED;
3031 void MESH_OT_region_to_loop(wmOperatorType *ot)
3034 ot->name = "Select Boundary Loop";
3035 ot->idname = "MESH_OT_region_to_loop";
3036 ot->description = "Select boundary edges around the selected faces";
3039 ot->exec = edbm_region_to_loop_exec;
3040 ot->poll = ED_operator_editmesh;
3043 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3046 static int loop_find_region(BMLoop *l, int flag,
3047 SmallHash *fhash, BMFace ***region_out)
3049 BLI_array_declare(region);
3050 BLI_array_declare(stack);
3051 BMFace **region = NULL;
3052 BMFace **stack = NULL;
3055 BLI_array_append(stack, l->f);
3056 BLI_smallhash_insert(fhash, (uintptr_t)l->f, NULL);
3058 while (BLI_array_count(stack) > 0) {
3059 BMIter liter1, liter2;
3062 f = BLI_array_pop(stack);
3063 BLI_array_append(region, f);
3065 BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) {
3066 if (BM_elem_flag_test(l1->e, flag))
3069 BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) {
3070 if (BLI_smallhash_haskey(fhash, (uintptr_t)l2->f))
3073 BLI_array_append(stack, l2->f);
3074 BLI_smallhash_insert(fhash, (uintptr_t)l2->f, NULL);
3079 BLI_array_free(stack);
3081 *region_out = region;
3082 return BLI_array_count(region);
3085 static int verg_radial(const void *va, const void *vb)
3087 BMEdge *e1 = *((void **)va);
3088 BMEdge *e2 = *((void **)vb);
3091 a = BM_edge_face_count(e1);
3092 b = BM_edge_face_count(e2);
3094 if (a > b) return -1;
3095 if (a == b) return 0;
3096 if (a < b) return 1;
3101 static int loop_find_regions(BMEditMesh *em, int selbigger)
3103 SmallHash visithash;
3105 BMEdge *e, **edges = NULL;
3106 BLI_array_declare(edges);
3110 BLI_smallhash_init(&visithash);
3112 BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
3113 BM_elem_flag_disable(f, BM_ELEM_TAG);
3116 BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
3117 if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
3118 BLI_array_append(edges, e);
3119 BM_elem_flag_enable(e, BM_ELEM_TAG);