Fix build error on Windows 32 bit.
[blender-staging.git] / source / blender / editors / mesh / editmesh_select.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
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.
8  *
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.
13  *
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.
17  *
18  * The Original Code is Copyright (C) 2004 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/mesh/editmesh_select.c
29  *  \ingroup edmesh
30  */
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_bitmap.h"
35 #include "BLI_bitmap_draw_2d.h"
36 #include "BLI_listbase.h"
37 #include "BLI_linklist.h"
38 #include "BLI_linklist_stack.h"
39 #include "BLI_math.h"
40 #include "BLI_math_bits.h"
41 #include "BLI_rand.h"
42 #include "BLI_array.h"
43
44 #include "BKE_context.h"
45 #include "BKE_report.h"
46 #include "BKE_paint.h"
47 #include "BKE_editmesh.h"
48
49 #include "IMB_imbuf_types.h"
50 #include "IMB_imbuf.h"
51
52 #include "WM_api.h"
53 #include "WM_types.h"
54
55 #include "RNA_access.h"
56 #include "RNA_define.h"
57 #include "RNA_enum_types.h"
58
59 #include "ED_mesh.h"
60 #include "ED_screen.h"
61 #include "ED_view3d.h"
62
63 #include "DNA_mesh_types.h"
64 #include "DNA_meshdata_types.h"
65 #include "DNA_object_types.h"
66
67 #include "UI_resources.h"
68
69 #include "bmesh_tools.h"
70
71 #include "mesh_intern.h"  /* own include */
72
73 /* use bmesh operator flags for a few operators */
74 #define BMO_ELE_TAG 1
75
76 /* -------------------------------------------------------------------- */
77 /** \name Select Mirror
78  * \{ */
79
80 void EDBM_select_mirrored(
81         BMEditMesh *em, const int axis, const bool extend,
82         int *r_totmirr, int *r_totfail)
83 {
84         Mesh *me = (Mesh *)em->ob->data;
85         BMesh *bm = em->bm;
86         BMIter iter;
87         int totmirr = 0;
88         int totfail = 0;
89         bool use_topology = (me && (me->editflag & ME_EDIT_MIRROR_TOPO));
90
91         *r_totmirr = *r_totfail = 0;
92
93         /* select -> tag */
94         if (bm->selectmode & SCE_SELECT_VERTEX) {
95                 BMVert *v;
96                 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
97                         BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT));
98                 }
99         }
100         else if (em->selectmode & SCE_SELECT_EDGE) {
101                 BMEdge *e;
102                 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
103                         BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
104                 }
105         }
106         else {
107                 BMFace *f;
108                 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
109                         BM_elem_flag_set(f, BM_ELEM_TAG, BM_elem_flag_test(f, BM_ELEM_SELECT));
110                 }
111         }
112
113         EDBM_verts_mirror_cache_begin(em, axis, true, true, use_topology);
114
115         if (!extend)
116                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
117
118
119         if (bm->selectmode & SCE_SELECT_VERTEX) {
120                 BMVert *v;
121                 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
122                         if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN) && BM_elem_flag_test(v, BM_ELEM_TAG)) {
123                                 BMVert *v_mirr = EDBM_verts_mirror_get(em, v);
124                                 if (v_mirr && !BM_elem_flag_test(v_mirr, BM_ELEM_HIDDEN)) {
125                                         BM_vert_select_set(bm, v_mirr, true);
126                                         totmirr++;
127                                 }
128                                 else {
129                                         totfail++;
130                                 }
131                         }
132                 }
133         }
134         else if (em->selectmode & SCE_SELECT_EDGE) {
135                 BMEdge *e;
136                 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
137                         if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && BM_elem_flag_test(e, BM_ELEM_TAG)) {
138                                 BMEdge *e_mirr = EDBM_verts_mirror_get_edge(em, e);
139                                 if (e_mirr && !BM_elem_flag_test(e_mirr, BM_ELEM_HIDDEN)) {
140                                         BM_edge_select_set(bm, e_mirr, true);
141                                         totmirr++;
142                                 }
143                                 else {
144                                         totfail++;
145                                 }
146                         }
147                 }
148         }
149         else {
150                 BMFace *f;
151                 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
152                         if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN) && BM_elem_flag_test(f, BM_ELEM_TAG)) {
153                                 BMFace *f_mirr = EDBM_verts_mirror_get_face(em, f);
154                                 if (f_mirr && !BM_elem_flag_test(f_mirr, BM_ELEM_HIDDEN)) {
155                                         BM_face_select_set(bm, f_mirr, true);
156                                         totmirr++;
157                                 }
158                                 else {
159                                         totfail++;
160                                 }
161                         }
162                 }
163         }
164
165         EDBM_verts_mirror_cache_end(em);
166
167         *r_totmirr = totmirr;
168         *r_totfail = totfail;
169 }
170
171 /** \} */
172
173 /* -------------------------------------------------------------------- */
174 /** \name Select Auto-Merge
175  *
176  * Used after transform operations.
177  * \{ */
178
179 void EDBM_automerge(Scene *scene, Object *obedit, bool update, const char hflag)
180 {
181         bool ok;
182         BMEditMesh *em = BKE_editmesh_from_object(obedit);
183
184         ok = BMO_op_callf(
185                 em->bm, BMO_FLAG_DEFAULTS,
186                 "automerge verts=%hv dist=%f",
187                 hflag, scene->toolsettings->doublimit);
188
189         if (LIKELY(ok) && update) {
190                 EDBM_update_generic(em, true, true);
191         }
192 }
193
194 /** \} */
195
196 /* -------------------------------------------------------------------- */
197 /** \name Back-Buffer OpenGL Selection
198  * \{ */
199
200 unsigned int bm_solidoffs = 0, bm_wireoffs = 0, bm_vertoffs = 0;    /* set in drawobject.c ... for colorindices */
201
202 /* facilities for border select and circle select */
203 static BLI_bitmap *selbuf = NULL;
204
205 static BLI_bitmap *edbm_backbuf_alloc(const int size)
206 {
207         return BLI_BITMAP_NEW(size, "selbuf");
208 }
209
210 /* reads rect, and builds selection array for quick lookup */
211 /* returns if all is OK */
212 bool EDBM_backbuf_border_init(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
213 {
214         struct ImBuf *buf;
215         unsigned int *dr;
216         int a;
217
218         if (vc->obedit == NULL || !V3D_IS_ZBUF(vc->v3d)) {
219                 return false;
220         }
221
222         buf = ED_view3d_backbuf_read(vc, xmin, ymin, xmax, ymax);
223         if ((buf == NULL) || (bm_vertoffs == 0)) {
224                 return false;
225         }
226
227         dr = buf->rect;
228
229         /* build selection lookup */
230         selbuf = edbm_backbuf_alloc(bm_vertoffs + 1);
231
232         a = (xmax - xmin + 1) * (ymax - ymin + 1);
233         while (a--) {
234                 if (*dr > 0 && *dr <= bm_vertoffs) {
235                         BLI_BITMAP_ENABLE(selbuf, *dr);
236                 }
237                 dr++;
238         }
239         IMB_freeImBuf(buf);
240         return true;
241 }
242
243 bool EDBM_backbuf_check(unsigned int index)
244 {
245         /* odd logic, if selbuf is NULL we assume no zbuf-selection is enabled
246          * and just ignore the depth buffer, this is error prone since its possible
247          * code doesn't set the depth buffer by accident, but leave for now. - Campbell */
248         if (selbuf == NULL)
249                 return true;
250
251         if (index > 0 && index <= bm_vertoffs)
252                 return BLI_BITMAP_TEST_BOOL(selbuf, index);
253
254         return false;
255 }
256
257 void EDBM_backbuf_free(void)
258 {
259         if (selbuf) MEM_freeN(selbuf);
260         selbuf = NULL;
261 }
262
263 struct LassoMaskData {
264         unsigned int *px;
265         int width;
266 };
267
268 static void edbm_mask_lasso_px_cb(int x, int x_end, int y, void *user_data)
269 {
270         struct LassoMaskData *data = user_data;
271         unsigned int *px = &data->px[(y * data->width) + x];
272         do {
273                 *px = true;
274                 px++;
275         } while (++x != x_end);
276 }
277
278
279 /* mcords is a polygon mask
280  * - grab backbuffer,
281  * - draw with black in backbuffer,
282  * - grab again and compare
283  * returns 'OK'
284  */
285 bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
286 {
287         unsigned int *dr, *dr_mask, *dr_mask_arr;
288         struct ImBuf *buf;
289         int a;
290         struct LassoMaskData lasso_mask_data;
291
292         /* method in use for face selecting too */
293         if (vc->obedit == NULL) {
294                 if (!BKE_paint_select_elem_test(vc->obact)) {
295                         return false;
296                 }
297         }
298         else if (!V3D_IS_ZBUF(vc->v3d)) {
299                 return false;
300         }
301
302         buf = ED_view3d_backbuf_read(vc, xmin, ymin, xmax, ymax);
303         if ((buf == NULL) || (bm_vertoffs == 0)) {
304                 return false;
305         }
306
307         dr = buf->rect;
308
309         dr_mask = dr_mask_arr = MEM_callocN(sizeof(*dr_mask) * buf->x * buf->y, __func__);
310         lasso_mask_data.px = dr_mask;
311         lasso_mask_data.width = (xmax - xmin) + 1;
312
313         BLI_bitmap_draw_2d_poly_v2i_n(
314                xmin, ymin, xmax + 1, ymax + 1,
315                mcords, tot,
316                edbm_mask_lasso_px_cb, &lasso_mask_data);
317
318         /* build selection lookup */
319         selbuf = edbm_backbuf_alloc(bm_vertoffs + 1);
320
321         a = (xmax - xmin + 1) * (ymax - ymin + 1);
322         while (a--) {
323                 if (*dr > 0 && *dr <= bm_vertoffs && *dr_mask == true) {
324                         BLI_BITMAP_ENABLE(selbuf, *dr);
325                 }
326                 dr++; dr_mask++;
327         }
328         IMB_freeImBuf(buf);
329         MEM_freeN(dr_mask_arr);
330
331         return true;
332 }
333
334 /* circle shaped sample area */
335 bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads)
336 {
337         struct ImBuf *buf;
338         unsigned int *dr;
339         short xmin, ymin, xmax, ymax, xc, yc;
340         int radsq;
341
342         /* method in use for face selecting too */
343         if (vc->obedit == NULL) {
344                 if (!BKE_paint_select_elem_test(vc->obact)) {
345                         return false;
346                 }
347         }
348         else if (!V3D_IS_ZBUF(vc->v3d)) {
349                 return false;
350         }
351
352         xmin = xs - rads; xmax = xs + rads;
353         ymin = ys - rads; ymax = ys + rads;
354         buf = ED_view3d_backbuf_read(vc, xmin, ymin, xmax, ymax);
355         if ((buf == NULL) || (bm_vertoffs == 0)) {
356                 return false;
357         }
358
359         dr = buf->rect;
360
361         /* build selection lookup */
362         selbuf = edbm_backbuf_alloc(bm_vertoffs + 1);
363         radsq = rads * rads;
364         for (yc = -rads; yc <= rads; yc++) {
365                 for (xc = -rads; xc <= rads; xc++, dr++) {
366                         if (xc * xc + yc * yc < radsq) {
367                                 if (*dr > 0 && *dr <= bm_vertoffs) {
368                                         BLI_BITMAP_ENABLE(selbuf, *dr);
369                                 }
370                         }
371                 }
372         }
373
374         IMB_freeImBuf(buf);
375         return true;
376
377 }
378
379 /** \} */
380
381 /* -------------------------------------------------------------------- */
382 /** \name Find Nearest Vert/Edge/Face
383  *
384  * \note Screen-space manhatten distances are used here,
385  * since its faster and good enough for the purpose of selection.
386  *
387  * \note \a dist_bias is used so we can bias against selected items.
388  * when choosing between elements of a single type, but return the real distance
389  * to avoid the bias interfering with distance comparisons when mixing types.
390  * \{ */
391
392 #define FIND_NEAR_SELECT_BIAS 5
393 #define FIND_NEAR_CYCLE_THRESHOLD_MIN 3
394
395 struct NearestVertUserData_Hit {
396         float   dist;
397         float   dist_bias;
398         int     index;
399         BMVert *vert;
400 };
401
402 struct NearestVertUserData {
403         float mval_fl[2];
404         bool use_select_bias;
405         bool use_cycle;
406         int cycle_index_prev;
407
408         struct NearestVertUserData_Hit hit;
409         struct NearestVertUserData_Hit hit_cycle;
410 };
411
412 static void findnearestvert__doClosest(void *userData, BMVert *eve, const float screen_co[2], int index)
413 {
414         struct NearestVertUserData *data = userData;
415         float dist_test, dist_test_bias;
416
417         dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
418
419         if (data->use_select_bias && BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
420                 dist_test_bias += FIND_NEAR_SELECT_BIAS;
421         }
422
423         if (dist_test_bias < data->hit.dist_bias) {
424                 data->hit.dist_bias = dist_test_bias;
425                 data->hit.dist = dist_test;
426                 data->hit.index = index;
427                 data->hit.vert = eve;
428         }
429
430         if (data->use_cycle) {
431                 if ((data->hit_cycle.vert == NULL) &&
432                     (index > data->cycle_index_prev) &&
433                     (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN))
434                 {
435                         data->hit_cycle.dist_bias = dist_test_bias;
436                         data->hit_cycle.dist = dist_test;
437                         data->hit_cycle.index = index;
438                         data->hit_cycle.vert = eve;
439                 }
440         }
441 }
442
443 /**
444  * Nearest vertex under the cursor.
445  *
446  * \param r_dist (in/out), minimal distance to the nearest and at the end, actual distance
447  * \param use_select_bias
448  * - When true, selected vertice are given a 5 pixel bias to make them further than unselect verts.
449  * - When false, unselected vertice are given the bias.
450  * \param use_cycle Cycle over elements within #FIND_NEAR_CYCLE_THRESHOLD_MIN in order of index.
451  */
452 BMVert *EDBM_vert_find_nearest_ex(
453         ViewContext *vc, float *r_dist,
454         const bool use_select_bias, bool use_cycle)
455 {
456         BMesh *bm = vc->em->bm;
457
458         if (V3D_IS_ZBUF(vc->v3d)) {
459                 const int dist_px = ED_view3d_backbuf_sample_size_clamp(vc->ar, *r_dist);
460                 float dist_test;
461                 unsigned int index;
462                 BMVert *eve;
463
464                 /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
465                 ED_view3d_backbuf_validate(vc);
466
467                 index = ED_view3d_backbuf_sample_rect(
468                         vc, vc->mval, dist_px, bm_wireoffs, 0xFFFFFF, &dist_test);
469                 eve = index ? BM_vert_at_index_find_or_table(bm, index - 1) : NULL;
470
471                 if (eve) {
472                         if (dist_test < *r_dist) {
473                                 *r_dist = dist_test;
474                                 return eve;
475                         }
476                 }
477                 return NULL;
478         }
479         else {
480                 struct NearestVertUserData data = {{0}};
481                 const struct NearestVertUserData_Hit *hit;
482                 const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT;
483
484                 static int prev_select_index = 0;
485                 static const BMVert *prev_select_elem = NULL;
486
487                 if ((use_cycle == false) ||
488                     (prev_select_elem && (prev_select_elem != BM_vert_at_index_find_or_table(bm, prev_select_index))))
489                 {
490                         prev_select_index = 0;
491                         prev_select_elem = NULL;
492                 }
493
494                 data.mval_fl[0] = vc->mval[0];
495                 data.mval_fl[1] = vc->mval[1];
496                 data.use_select_bias = use_select_bias;
497                 data.use_cycle = use_cycle;
498                 data.hit.dist      = data.hit_cycle.dist = \
499                 data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist;
500                 data.cycle_index_prev = prev_select_index;
501
502                 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
503                 mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, clip_flag);
504
505                 hit = (data.use_cycle && data.hit_cycle.vert) ? &data.hit_cycle : &data.hit;
506                 *r_dist = hit->dist;
507
508                 prev_select_elem = hit->vert;
509                 prev_select_index = hit->index;
510
511                 return hit->vert;
512         }
513 }
514
515 BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *r_dist)
516 {
517         return EDBM_vert_find_nearest_ex(vc, r_dist, false, false);
518 }
519
520 /* find the distance to the edge we already have */
521 struct NearestEdgeUserData_ZBuf {
522         float mval_fl[2];
523         float dist;
524         const BMEdge *edge_test;
525 };
526
527 static void find_nearest_edge_center__doZBuf(
528         void *userData, BMEdge *eed,
529         const float screen_co_a[2], const float screen_co_b[2],
530         int UNUSED(index))
531 {
532         struct NearestEdgeUserData_ZBuf *data = userData;
533
534         if (eed == data->edge_test) {
535                 float dist_test;
536                 float screen_co_mid[2];
537
538                 mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
539                 dist_test = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
540
541                 if (dist_test < data->dist) {
542                         data->dist = dist_test;
543                 }
544         }
545 }
546
547 struct NearestEdgeUserData_Hit {
548         float   dist;
549         float   dist_bias;
550         int     index;
551         BMEdge *edge;
552
553         /* edges only, un-biased manhatten distance to which ever edge we pick
554          * (not used for choosing) */
555         float   dist_center;
556 };
557
558 struct NearestEdgeUserData {
559         ViewContext vc;
560         float mval_fl[2];
561         bool use_select_bias;
562         bool use_cycle;
563         int cycle_index_prev;
564
565         struct NearestEdgeUserData_Hit hit;
566         struct NearestEdgeUserData_Hit hit_cycle;
567 };
568
569 /* note; uses v3d, so needs active 3d window */
570 static void find_nearest_edge__doClosest(
571         void *userData, BMEdge *eed,
572         const float screen_co_a[2], const float screen_co_b[2],
573         int index)
574 {
575         struct NearestEdgeUserData *data = userData;
576         float dist_test, dist_test_bias;
577
578         float fac = line_point_factor_v2(data->mval_fl, screen_co_a, screen_co_b);
579         float screen_co[2];
580
581         if (fac <= 0.0f) {
582                 fac = 0.0f;
583                 copy_v2_v2(screen_co, screen_co_a);
584         }
585         else if (fac >= 1.0f) {
586                 fac = 1.0f;
587                 copy_v2_v2(screen_co, screen_co_b);
588         }
589         else {
590                 interp_v2_v2v2(screen_co, screen_co_a, screen_co_b, fac);
591         }
592
593         dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
594
595         if (data->use_select_bias && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
596                 dist_test_bias += FIND_NEAR_SELECT_BIAS;
597         }
598
599         if (data->vc.rv3d->rflag & RV3D_CLIPPING) {
600                 float vec[3];
601
602                 interp_v3_v3v3(vec, eed->v1->co, eed->v2->co, fac);
603                 if (ED_view3d_clipping_test(data->vc.rv3d, vec, true)) {
604                         return;
605                 }
606         }
607
608         if (dist_test_bias < data->hit.dist_bias) {
609                 float screen_co_mid[2];
610
611                 data->hit.dist_bias = dist_test_bias;
612                 data->hit.dist = dist_test;
613                 data->hit.index = index;
614                 data->hit.edge = eed;
615
616                 mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
617                 data->hit.dist_center = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
618         }
619
620         if (data->use_cycle) {
621                 if ((data->hit_cycle.edge == NULL) &&
622                     (index > data->cycle_index_prev) &&
623                     (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN))
624                 {
625                         float screen_co_mid[2];
626
627                         data->hit_cycle.dist_bias = dist_test_bias;
628                         data->hit_cycle.dist = dist_test;
629                         data->hit_cycle.index = index;
630                         data->hit_cycle.edge = eed;
631
632                         mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
633                         data->hit_cycle.dist_center = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
634                 }
635         }
636 }
637
638 BMEdge *EDBM_edge_find_nearest_ex(
639         ViewContext *vc, float *r_dist,
640         float *r_dist_center,
641         const bool use_select_bias, const bool use_cycle,
642         BMEdge **r_eed_zbuf)
643 {
644         BMesh *bm = vc->em->bm;
645
646         if (V3D_IS_ZBUF(vc->v3d)) {
647                 const int dist_px = ED_view3d_backbuf_sample_size_clamp(vc->ar, *r_dist);
648                 float dist_test = 0.0f;
649                 unsigned int index;
650                 BMEdge *eed;
651
652                 /* Make sure that the edges are considered for selection.
653                  * TODO: cleanup: add `selectmode` as a parameter */
654                 const short ts_selectmode = vc->scene->toolsettings->selectmode;
655                 vc->scene->toolsettings->selectmode |= SCE_SELECT_EDGE;
656
657                 /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
658                 ED_view3d_backbuf_validate(vc);
659
660                 /* restore `selectmode` */
661                 vc->scene->toolsettings->selectmode = ts_selectmode;
662
663                 index = ED_view3d_backbuf_sample_rect(vc, vc->mval, dist_px, bm_solidoffs, bm_wireoffs, &dist_test);
664                 eed = index ? BM_edge_at_index_find_or_table(bm, index - 1) : NULL;
665
666                 if (r_eed_zbuf) {
667                         *r_eed_zbuf = eed;
668                 }
669
670                 /* exception for faces (verts don't need this) */
671                 if (r_dist_center && eed) {
672                         struct NearestEdgeUserData_ZBuf data;
673
674                         data.mval_fl[0] = vc->mval[0];
675                         data.mval_fl[1] = vc->mval[1];
676                         data.dist = FLT_MAX;
677                         data.edge_test = eed;
678
679                         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
680
681                         mesh_foreachScreenEdge(vc, find_nearest_edge_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
682
683                         *r_dist_center = data.dist;
684                 }
685                 /* end exception */
686
687                 if (eed) {
688                         if (dist_test < *r_dist) {
689                                 *r_dist = dist_test;
690                                 return eed;
691                         }
692                 }
693                 return NULL;
694         }
695         else {
696                 struct NearestEdgeUserData data = {{0}};
697                 const struct NearestEdgeUserData_Hit *hit;
698                 /* interpolate along the edge before doing a clipping plane test */
699                 const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT & ~V3D_PROJ_TEST_CLIP_BB;
700
701                 static int prev_select_index = 0;
702                 static const BMEdge *prev_select_elem = NULL;
703
704                 if ((use_cycle == false) ||
705                     (prev_select_elem && (prev_select_elem != BM_edge_at_index_find_or_table(bm, prev_select_index))))
706                 {
707                         prev_select_index = 0;
708                         prev_select_elem = NULL;
709                 }
710
711                 data.vc = *vc;
712                 data.mval_fl[0] = vc->mval[0];
713                 data.mval_fl[1] = vc->mval[1];
714                 data.use_select_bias = use_select_bias;
715                 data.use_cycle = use_cycle;
716                 data.hit.dist      = data.hit_cycle.dist = \
717                 data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist;
718                 data.cycle_index_prev = prev_select_index;
719
720                 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
721                 mesh_foreachScreenEdge(vc, find_nearest_edge__doClosest, &data, clip_flag);
722
723                 hit = (data.use_cycle && data.hit_cycle.edge) ? &data.hit_cycle : &data.hit;
724                 *r_dist = hit->dist;
725                 if (r_dist_center) {
726                         *r_dist_center = hit->dist_center;
727                 }
728
729                 prev_select_elem = hit->edge;
730                 prev_select_index = hit->index;
731
732                 return hit->edge;
733         }
734 }
735
736 BMEdge *EDBM_edge_find_nearest(
737         ViewContext *vc, float *r_dist)
738 {
739         return EDBM_edge_find_nearest_ex(vc, r_dist, NULL, false, false, NULL);
740 }
741
742 /* find the distance to the face we already have */
743 struct NearestFaceUserData_ZBuf {
744         float mval_fl[2];
745         float dist;
746         const BMFace *face_test;
747 };
748
749 static void find_nearest_face_center__doZBuf(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
750 {
751         struct NearestFaceUserData_ZBuf *data = userData;
752
753         if (efa == data->face_test) {
754                 const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
755
756                 if (dist_test < data->dist) {
757                         data->dist = dist_test;
758                 }
759         }
760 }
761
762
763 struct NearestFaceUserData_Hit {
764         float   dist;
765         float   dist_bias;
766         int     index;
767         BMFace *face;
768 };
769
770 struct NearestFaceUserData {
771         float mval_fl[2];
772         bool use_select_bias;
773         bool use_cycle;
774         int cycle_index_prev;
775
776         struct NearestFaceUserData_Hit hit;
777         struct NearestFaceUserData_Hit hit_cycle;
778 };
779
780 static void findnearestface__doClosest(void *userData, BMFace *efa, const float screen_co[2], int index)
781 {
782         struct NearestFaceUserData *data = userData;
783         float dist_test, dist_test_bias;
784
785         dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
786
787         if (data->use_select_bias && BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
788                 dist_test_bias += FIND_NEAR_SELECT_BIAS;
789         }
790
791         if (dist_test_bias < data->hit.dist_bias) {
792                 data->hit.dist_bias = dist_test_bias;
793                 data->hit.dist = dist_test;
794                 data->hit.index = index;
795                 data->hit.face = efa;
796         }
797
798         if (data->use_cycle) {
799                 if ((data->hit_cycle.face == NULL) &&
800                     (index > data->cycle_index_prev) &&
801                     (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN))
802                 {
803                         data->hit_cycle.dist_bias = dist_test_bias;
804                         data->hit_cycle.dist = dist_test;
805                         data->hit_cycle.index = index;
806                         data->hit_cycle.face = efa;
807                 }
808         }
809 }
810
811
812 BMFace *EDBM_face_find_nearest_ex(
813         ViewContext *vc, float *r_dist,
814         float *r_dist_center,
815         const bool use_select_bias, const bool use_cycle,
816         BMFace **r_efa_zbuf)
817 {
818         BMesh *bm = vc->em->bm;
819
820         if (V3D_IS_ZBUF(vc->v3d)) {
821                 float dist_test = 0.0f;
822                 unsigned int index;
823                 BMFace *efa;
824
825                 ED_view3d_backbuf_validate(vc);
826
827                 index = ED_view3d_backbuf_sample(vc, vc->mval[0], vc->mval[1]);
828                 efa = index ? BM_face_at_index_find_or_table(bm, index - 1) : NULL;
829
830                 if (r_efa_zbuf) {
831                         *r_efa_zbuf = efa;
832                 }
833
834                 /* exception for faces (verts don't need this) */
835                 if (r_dist_center && efa) {
836                         struct NearestFaceUserData_ZBuf data;
837
838                         data.mval_fl[0] = vc->mval[0];
839                         data.mval_fl[1] = vc->mval[1];
840                         data.dist = FLT_MAX;
841                         data.face_test = efa;
842
843                         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
844
845                         mesh_foreachScreenFace(vc, find_nearest_face_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
846
847                         *r_dist_center = data.dist;
848                 }
849                 /* end exception */
850
851                 if (efa) {
852                         if (dist_test < *r_dist) {
853                                 *r_dist = dist_test;
854                                 return efa;
855                         }
856                 }
857                 return NULL;
858         }
859         else {
860                 struct NearestFaceUserData data = {{0}};
861                 const struct NearestFaceUserData_Hit *hit;
862                 const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT;
863
864                 static int prev_select_index = 0;
865                 static const BMFace *prev_select_elem = NULL;
866
867                 if ((use_cycle == false) ||
868                     (prev_select_elem && (prev_select_elem != BM_face_at_index_find_or_table(bm, prev_select_index))))
869                 {
870                         prev_select_index = 0;
871                         prev_select_elem = NULL;
872                 }
873
874                 data.mval_fl[0] = vc->mval[0];
875                 data.mval_fl[1] = vc->mval[1];
876                 data.use_select_bias = use_select_bias;
877                 data.use_cycle = use_cycle;
878                 data.hit.dist      = data.hit_cycle.dist = \
879                 data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist;
880                 data.cycle_index_prev = prev_select_index;
881
882                 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
883                 mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, clip_flag);
884
885                 hit = (data.use_cycle && data.hit_cycle.face) ? &data.hit_cycle : &data.hit;
886                 *r_dist = hit->dist;
887                 if (r_dist_center) {
888                         *r_dist_center = hit->dist;
889                 }
890
891                 prev_select_elem = hit->face;
892                 prev_select_index = hit->index;
893
894                 return hit->face;
895         }
896 }
897
898 BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist)
899 {
900         return EDBM_face_find_nearest_ex(vc, r_dist, NULL, false, false, NULL);
901 }
902
903 #undef FIND_NEAR_SELECT_BIAS
904 #undef FIND_NEAR_CYCLE_THRESHOLD_MIN
905
906
907 /* best distance based on screen coords.
908  * use em->selectmode to define how to use
909  * selected vertices and edges get disadvantage
910  * return 1 if found one
911  */
912 static int unified_findnearest(ViewContext *vc, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
913 {
914         BMEditMesh *em = vc->em;
915         static short mval_prev[2] = {-1, -1};
916         /* only cycle while the mouse remains still */
917         const bool use_cycle = ((mval_prev[0] == vc->mval[0]) && (mval_prev[1] == vc->mval[1]));
918         const float dist_init = ED_view3d_select_dist_px();
919         /* since edges select lines, we give dots advantage of ~20 pix */
920         const float dist_margin = (dist_init / 2);
921         float dist = dist_init;
922         BMFace *efa_zbuf = NULL;
923         BMEdge *eed_zbuf = NULL;
924
925         BMVert *eve = NULL;
926         BMEdge *eed = NULL;
927         BMFace *efa = NULL;
928
929
930         /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
931         ED_view3d_backbuf_validate(vc);
932
933         if ((dist > 0.0f) && em->selectmode & SCE_SELECT_FACE) {
934                 float dist_center = 0.0f;
935                 float *dist_center_p = (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_VERTEX)) ? &dist_center : NULL;
936                 efa = EDBM_face_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf);
937                 if (efa && dist_center_p) {
938                         dist = min_ff(dist_margin, dist_center);
939                 }
940         }
941
942         if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_EDGE)) {
943                 float dist_center = 0.0f;
944                 float *dist_center_p = (em->selectmode & SCE_SELECT_VERTEX) ? &dist_center : NULL;
945                 eed = EDBM_edge_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf);
946                 if (eed && dist_center_p) {
947                         dist = min_ff(dist_margin, dist_center);
948                 }
949         }
950
951         if ((dist > 0.0f) && em->selectmode & SCE_SELECT_VERTEX) {
952                 eve = EDBM_vert_find_nearest_ex(vc, &dist, true, use_cycle);
953         }
954
955         /* return only one of 3 pointers, for frontbuffer redraws */
956         if (eve) {
957                 efa = NULL; eed = NULL;
958         }
959         else if (eed) {
960                 efa = NULL;
961         }
962
963         /* there may be a face under the cursor, who's center if too far away
964          * use this if all else fails, it makes sense to select this */
965         if ((eve || eed || efa) == 0) {
966                 if (eed_zbuf) {
967                         eed = eed_zbuf;
968                 }
969                 else if (efa_zbuf) {
970                         efa = efa_zbuf;
971                 }
972         }
973
974         mval_prev[0] = vc->mval[0];
975         mval_prev[1] = vc->mval[1];
976
977         *r_eve = eve;
978         *r_eed = eed;
979         *r_efa = efa;
980
981         return (eve || eed || efa);
982 }
983
984 /** \} */
985
986 /* -------------------------------------------------------------------- */
987 /** \name Select Similar (Vert/Edge/Face) Operator
988  * \{ */
989
990 static const EnumPropertyItem prop_similar_compare_types[] = {
991         {SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
992         {SIM_CMP_GT, "GREATER", 0, "Greater", ""},
993         {SIM_CMP_LT, "LESS", 0, "Less", ""},
994
995         {0, NULL, 0, NULL, NULL}
996 };
997
998 static const EnumPropertyItem prop_similar_types[] = {
999         {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""},
1000         {SIMVERT_FACE, "FACE", 0, "Amount of Adjacent Faces", ""},
1001         {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""},
1002         {SIMVERT_EDGE, "EDGE", 0, "Amount of connecting edges", ""},
1003
1004         {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""},
1005         {SIMEDGE_DIR, "DIR", 0, "Direction", ""},
1006         {SIMEDGE_FACE, "FACE", 0, "Amount of Faces Around an Edge", ""},
1007         {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""},
1008         {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""},
1009         {SIMEDGE_BEVEL, "BEVEL", 0, "Bevel", ""},
1010         {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
1011         {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
1012 #ifdef WITH_FREESTYLE
1013         {SIMEDGE_FREESTYLE, "FREESTYLE_EDGE", 0, "Freestyle Edge Marks", ""},
1014 #endif
1015
1016         {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
1017         {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
1018         {SIMFACE_AREA, "AREA", 0, "Area", ""},
1019         {SIMFACE_SIDES, "SIDES", 0, "Polygon Sides", ""},
1020         {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
1021         {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
1022         {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
1023         {SIMFACE_SMOOTH, "SMOOTH", 0, "Flat/Smooth", ""},
1024 #ifdef WITH_FREESTYLE
1025         {SIMFACE_FREESTYLE, "FREESTYLE_FACE", 0, "Freestyle Face Marks", ""},
1026 #endif
1027
1028         {0, NULL, 0, NULL, NULL}
1029 };
1030
1031 /* selects new faces/edges/verts based on the existing selection */
1032
1033 static int similar_face_select_exec(bContext *C, wmOperator *op)
1034 {
1035         Object *ob = CTX_data_edit_object(C);
1036         BMEditMesh *em = BKE_editmesh_from_object(ob);
1037         BMOperator bmop;
1038
1039         /* get the type from RNA */
1040         const int type = RNA_enum_get(op->ptr, "type");
1041         const float thresh = RNA_float_get(op->ptr, "threshold");
1042         const int compare = RNA_enum_get(op->ptr, "compare");
1043
1044         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
1045         EDBM_op_init(em, &bmop, op,
1046                      "similar_faces faces=%hf type=%i thresh=%f compare=%i",
1047                      BM_ELEM_SELECT, type, thresh, compare);
1048
1049         /* execute the operator */
1050         BMO_op_exec(em->bm, &bmop);
1051
1052         /* clear the existing selection */
1053         EDBM_flag_disable_all(em, BM_ELEM_SELECT);
1054
1055         /* select the output */
1056         BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
1057
1058         /* finish the operator */
1059         if (!EDBM_op_finish(em, &bmop, op, true)) {
1060                 return OPERATOR_CANCELLED;
1061         }
1062
1063         EDBM_update_generic(em, false, false);
1064
1065         return OPERATOR_FINISHED;
1066 }
1067
1068 /* ***************************************************** */
1069
1070 /* EDGE GROUP */
1071
1072 /* wrap the above function but do selection flushing edge to face */
1073 static int similar_edge_select_exec(bContext *C, wmOperator *op)
1074 {
1075         Object *ob = CTX_data_edit_object(C);
1076         BMEditMesh *em = BKE_editmesh_from_object(ob);
1077         BMOperator bmop;
1078
1079         /* get the type from RNA */
1080         const int type = RNA_enum_get(op->ptr, "type");
1081         const float thresh = RNA_float_get(op->ptr, "threshold");
1082         const int compare = RNA_enum_get(op->ptr, "compare");
1083
1084         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
1085         EDBM_op_init(em, &bmop, op,
1086                      "similar_edges edges=%he type=%i thresh=%f compare=%i",
1087                      BM_ELEM_SELECT, type, thresh, compare);
1088
1089         /* execute the operator */
1090         BMO_op_exec(em->bm, &bmop);
1091
1092         /* clear the existing selection */
1093         EDBM_flag_disable_all(em, BM_ELEM_SELECT);
1094
1095         /* select the output */
1096         BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
1097         EDBM_selectmode_flush(em);
1098
1099         /* finish the operator */
1100         if (!EDBM_op_finish(em, &bmop, op, true)) {
1101                 return OPERATOR_CANCELLED;
1102         }
1103
1104         EDBM_update_generic(em, false, false);
1105
1106         return OPERATOR_FINISHED;
1107 }
1108
1109 /* ********************************* */
1110
1111 /*
1112  * VERT GROUP
1113  * mode 1: same normal
1114  * mode 2: same number of face users
1115  * mode 3: same vertex groups
1116  */
1117 static int similar_vert_select_exec(bContext *C, wmOperator *op)
1118 {
1119         Object *ob = CTX_data_edit_object(C);
1120         BMEditMesh *em = BKE_editmesh_from_object(ob);
1121         BMOperator bmop;
1122         /* get the type from RNA */
1123         const int type = RNA_enum_get(op->ptr, "type");
1124         const float thresh = RNA_float_get(op->ptr, "threshold");
1125         const int compare = RNA_enum_get(op->ptr, "compare");
1126
1127         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
1128         EDBM_op_init(em, &bmop, op,
1129                      "similar_verts verts=%hv type=%i thresh=%f compare=%i",
1130                      BM_ELEM_SELECT, type, thresh, compare);
1131
1132         /* execute the operator */
1133         BMO_op_exec(em->bm, &bmop);
1134
1135         /* clear the existing selection */
1136         EDBM_flag_disable_all(em, BM_ELEM_SELECT);
1137
1138         /* select the output */
1139         BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "verts.out", BM_VERT, BM_ELEM_SELECT, true);
1140
1141         /* finish the operator */
1142         if (!EDBM_op_finish(em, &bmop, op, true)) {
1143                 return OPERATOR_CANCELLED;
1144         }
1145
1146         EDBM_selectmode_flush(em);
1147
1148         EDBM_update_generic(em, false, false);
1149
1150         return OPERATOR_FINISHED;
1151 }
1152
1153 static int edbm_select_similar_exec(bContext *C, wmOperator *op)
1154 {
1155         ToolSettings *ts = CTX_data_tool_settings(C);
1156         PropertyRNA *prop = RNA_struct_find_property(op->ptr, "threshold");
1157
1158         const int type = RNA_enum_get(op->ptr, "type");
1159
1160         if (!RNA_property_is_set(op->ptr, prop)) {
1161                 RNA_property_float_set(op->ptr, prop, ts->select_thresh);
1162         }
1163         else {
1164                 ts->select_thresh = RNA_property_float_get(op->ptr, prop);
1165         }
1166
1167         if      (type < 100) return similar_vert_select_exec(C, op);
1168         else if (type < 200) return similar_edge_select_exec(C, op);
1169         else                 return similar_face_select_exec(C, op);
1170 }
1171
1172 static const EnumPropertyItem *select_similar_type_itemf(
1173         bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
1174         bool *r_free)
1175 {
1176         Object *obedit;
1177
1178         if (!C) /* needed for docs and i18n tools */
1179                 return prop_similar_types;
1180
1181         obedit = CTX_data_edit_object(C);
1182
1183         if (obedit && obedit->type == OB_MESH) {
1184                 EnumPropertyItem *item = NULL;
1185                 int a, totitem = 0;
1186                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1187
1188                 if (em->selectmode & SCE_SELECT_VERTEX) {
1189                         for (a = SIMVERT_NORMAL; a < SIMEDGE_LENGTH; a++) {
1190                                 RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
1191                         }
1192                 }
1193                 else if (em->selectmode & SCE_SELECT_EDGE) {
1194                         for (a = SIMEDGE_LENGTH; a < SIMFACE_MATERIAL; a++) {
1195                                 RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
1196                         }
1197                 }
1198                 else if (em->selectmode & SCE_SELECT_FACE) {
1199 #ifdef WITH_FREESTYLE
1200                         const int a_end = SIMFACE_FREESTYLE;
1201 #else
1202                         const int a_end = SIMFACE_SMOOTH;
1203 #endif
1204                         for (a = SIMFACE_MATERIAL; a <= a_end; a++) {
1205                                 RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
1206                         }
1207                 }
1208                 RNA_enum_item_end(&item, &totitem);
1209
1210                 *r_free = true;
1211
1212                 return item;
1213         }
1214
1215         return prop_similar_types;
1216 }
1217
1218 void MESH_OT_select_similar(wmOperatorType *ot)
1219 {
1220         PropertyRNA *prop;
1221
1222         /* identifiers */
1223         ot->name = "Select Similar";
1224         ot->idname = "MESH_OT_select_similar";
1225         ot->description = "Select similar vertices, edges or faces by property types";
1226
1227         /* api callbacks */
1228         ot->invoke = WM_menu_invoke;
1229         ot->exec = edbm_select_similar_exec;
1230         ot->poll = ED_operator_editmesh;
1231
1232         /* flags */
1233         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1234
1235         /* properties */
1236         prop = ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", "");
1237         RNA_def_enum_funcs(prop, select_similar_type_itemf);
1238
1239         RNA_def_enum(ot->srna, "compare", prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
1240
1241         RNA_def_float(ot->srna, "threshold", 0.0f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
1242 }
1243
1244 /** \} */
1245
1246 /* -------------------------------------------------------------------- */
1247 /** \name Select Similar Region Operator
1248  * \{ */
1249
1250 static int edbm_select_similar_region_exec(bContext *C, wmOperator *op)
1251 {
1252         Object *obedit = CTX_data_edit_object(C);
1253         BMEditMesh *em = BKE_editmesh_from_object(obedit);
1254         BMesh *bm = em->bm;
1255         bool changed = false;
1256
1257         /* group vars */
1258         int *groups_array;
1259         int (*group_index)[2];
1260         int group_tot;
1261         int i;
1262
1263         if (bm->totfacesel < 2) {
1264                 BKE_report(op->reports, RPT_ERROR, "No face regions selected");
1265                 return OPERATOR_CANCELLED;
1266         }
1267
1268         groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__);
1269         group_tot = BM_mesh_calc_face_groups(
1270                 bm, groups_array, &group_index,
1271                 NULL, NULL,
1272                 BM_ELEM_SELECT, BM_VERT);
1273
1274         BM_mesh_elem_table_ensure(bm, BM_FACE);
1275
1276         for (i = 0; i < group_tot; i++) {
1277                 ListBase faces_regions;
1278                 int tot;
1279
1280                 const int fg_sta = group_index[i][0];
1281                 const int fg_len = group_index[i][1];
1282                 int j;
1283                 BMFace **fg = MEM_mallocN(sizeof(*fg) * fg_len, __func__);
1284
1285
1286                 for (j = 0; j < fg_len; j++) {
1287                         fg[j] = BM_face_at_index(bm, groups_array[fg_sta + j]);
1288                 }
1289
1290                 tot = BM_mesh_region_match(bm, fg, fg_len, &faces_regions);
1291
1292                 MEM_freeN(fg);
1293
1294                 if (tot) {
1295                         LinkData *link;
1296                         while ((link = BLI_pophead(&faces_regions))) {
1297                                 BMFace *f, **faces = link->data;
1298                                 while ((f = *(faces++))) {
1299                                         BM_face_select_set(bm, f, true);
1300                                 }
1301                                 MEM_freeN(link->data);
1302                                 MEM_freeN(link);
1303
1304                                 changed = true;
1305                         }
1306                 }
1307         }
1308
1309         MEM_freeN(groups_array);
1310         MEM_freeN(group_index);
1311
1312         if (changed) {
1313                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
1314         }
1315         else {
1316                 BKE_report(op->reports, RPT_WARNING, "No matching face regions found");
1317         }
1318
1319         return OPERATOR_FINISHED;
1320 }
1321
1322 void MESH_OT_select_similar_region(wmOperatorType *ot)
1323 {
1324         /* identifiers */
1325         ot->name = "Select Similar Regions";
1326         ot->idname = "MESH_OT_select_similar_region";
1327         ot->description = "Select similar face regions to the current selection";
1328
1329         /* api callbacks */
1330         ot->exec = edbm_select_similar_region_exec;
1331         ot->poll = ED_operator_editmesh;
1332
1333         /* flags */
1334         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1335 }
1336
1337 /** \} */
1338
1339 /* -------------------------------------------------------------------- */
1340 /** \name Select Mode Vert/Edge/Face Operator
1341  * \{ */
1342
1343 static int edbm_select_mode_exec(bContext *C, wmOperator *op)
1344 {
1345         const int type        = RNA_enum_get(op->ptr,    "type");
1346         const int action      = RNA_enum_get(op->ptr,    "action");
1347         const bool use_extend = RNA_boolean_get(op->ptr, "use_extend");
1348         const bool use_expand = RNA_boolean_get(op->ptr, "use_expand");
1349
1350         if (EDBM_selectmode_toggle(C, type, action, use_extend, use_expand)) {
1351                 return OPERATOR_FINISHED;
1352         }
1353         else {
1354                 return OPERATOR_CANCELLED;
1355         }
1356 }
1357
1358 static int edbm_select_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1359 {
1360         /* detecting these options based on shift/ctrl here is weak, but it's done
1361          * to make this work when clicking buttons or menus */
1362         if (!RNA_struct_property_is_set(op->ptr, "use_extend"))
1363                 RNA_boolean_set(op->ptr, "use_extend", event->shift);
1364         if (!RNA_struct_property_is_set(op->ptr, "use_expand"))
1365                 RNA_boolean_set(op->ptr, "use_expand", event->ctrl);
1366
1367         return edbm_select_mode_exec(C, op);
1368 }
1369
1370 void MESH_OT_select_mode(wmOperatorType *ot)
1371 {
1372         PropertyRNA *prop;
1373
1374         static const EnumPropertyItem elem_items[] = {
1375                 {SCE_SELECT_VERTEX, "VERT", ICON_VERTEXSEL, "Vertices", ""},
1376                 {SCE_SELECT_EDGE,   "EDGE", ICON_EDGESEL, "Edges", ""},
1377                 {SCE_SELECT_FACE,   "FACE", ICON_FACESEL, "Faces", ""},
1378                 {0, NULL, 0, NULL, NULL},
1379         };
1380
1381         static const EnumPropertyItem actions_items[] = {
1382                 {0, "DISABLE", 0, "Disable", "Disable selected markers"},
1383                 {1, "ENABLE", 0, "Enable", "Enable selected markers"},
1384                 {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
1385                 {0, NULL, 0, NULL, NULL}
1386         };
1387
1388         /* identifiers */
1389         ot->name = "Select Mode";
1390         ot->idname = "MESH_OT_select_mode";
1391         ot->description = "Change selection mode";
1392
1393         /* api callbacks */
1394         ot->invoke = edbm_select_mode_invoke;
1395         ot->exec = edbm_select_mode_exec;
1396         ot->poll = ED_operator_editmesh;
1397
1398         /* flags */
1399         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1400
1401         /* properties */
1402         prop = RNA_def_boolean(ot->srna, "use_extend", false, "Extend", "");
1403         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1404         prop = RNA_def_boolean(ot->srna, "use_expand", false, "Expand", "");
1405         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1406         ot->prop = prop = RNA_def_enum(ot->srna, "type", elem_items, 0, "Type", "");
1407         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1408
1409         RNA_def_enum(ot->srna, "action", actions_items, 2, "Action", "Selection action to execute");
1410 }
1411
1412 /** \} */
1413
1414 /* -------------------------------------------------------------------- */
1415 /** \name Select Loop (Non Modal) Operator
1416  * \{ */
1417
1418 static void walker_select_count(
1419         BMEditMesh *em, int walkercode, void *start, const bool select, const bool select_mix,
1420         int *r_totsel, int *r_totunsel)
1421 {
1422         BMesh *bm = em->bm;
1423         BMElem *ele;
1424         BMWalker walker;
1425         int tot[2] = {0, 0};
1426
1427         BMW_init(&walker, bm, walkercode,
1428                  BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
1429                  BMW_FLAG_TEST_HIDDEN,
1430                  BMW_NIL_LAY);
1431
1432         for (ele = BMW_begin(&walker, start); ele; ele = BMW_step(&walker)) {
1433                 tot[(BM_elem_flag_test_bool(ele, BM_ELEM_SELECT) != select)] += 1;
1434
1435                 if (!select_mix && tot[0] && tot[1]) {
1436                         tot[0] = tot[1] = -1;
1437                         break;
1438                 }
1439         }
1440
1441         *r_totsel = tot[0];
1442         *r_totunsel = tot[1];
1443
1444         BMW_end(&walker);
1445 }
1446
1447 static void walker_select(BMEditMesh *em, int walkercode, void *start, const bool select)
1448 {
1449         BMesh *bm = em->bm;
1450         BMElem *ele;
1451         BMWalker walker;
1452
1453         BMW_init(&walker, bm, walkercode,
1454                  BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
1455                  BMW_FLAG_TEST_HIDDEN,
1456                  BMW_NIL_LAY);
1457
1458         for (ele = BMW_begin(&walker, start); ele; ele = BMW_step(&walker)) {
1459                 if (!select) {
1460                         BM_select_history_remove(bm, ele);
1461                 }
1462                 BM_elem_select_set(bm, ele, select);
1463         }
1464         BMW_end(&walker);
1465 }
1466
1467 static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op)
1468 {
1469         Object *obedit = CTX_data_edit_object(C);
1470         BMEditMesh *em = BKE_editmesh_from_object(obedit);
1471         BMEdge *eed;
1472         BMEdge **edarray;
1473         int edindex;
1474         const bool is_ring = RNA_boolean_get(op->ptr, "ring");
1475
1476         BMIter iter;
1477         int totedgesel = 0;
1478
1479         BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1480                 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1481                         totedgesel++;
1482                 }
1483         }
1484
1485         edarray = MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array");
1486         edindex = 0;
1487
1488         BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1489                 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1490                         edarray[edindex] = eed;
1491                         edindex++;
1492                 }
1493         }
1494
1495         if (is_ring) {
1496                 for (edindex = 0; edindex < totedgesel; edindex += 1) {
1497                         eed = edarray[edindex];
1498                         walker_select(em, BMW_EDGERING, eed, true);
1499                 }
1500                 EDBM_selectmode_flush(em);
1501         }
1502         else {
1503                 for (edindex = 0; edindex < totedgesel; edindex += 1) {
1504                         eed = edarray[edindex];
1505                         walker_select(em, BMW_EDGELOOP, eed, true);
1506                 }
1507                 EDBM_selectmode_flush(em);
1508         }
1509         MEM_freeN(edarray);
1510 //      if (EM_texFaceCheck())
1511
1512         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
1513
1514         return OPERATOR_FINISHED;
1515 }
1516
1517 void MESH_OT_loop_multi_select(wmOperatorType *ot)
1518 {
1519         /* identifiers */
1520         ot->name = "Multi Select Loops";
1521         ot->idname = "MESH_OT_loop_multi_select";
1522         ot->description = "Select a loop of connected edges by connection type";
1523
1524         /* api callbacks */
1525         ot->exec = edbm_loop_multiselect_exec;
1526         ot->poll = ED_operator_editmesh;
1527
1528         /* flags */
1529         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1530
1531         /* properties */
1532         RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
1533 }
1534
1535 /** \} */
1536
1537 /* -------------------------------------------------------------------- */
1538 /** \name Select Loop (Cursor Pick) Operator
1539  * \{ */
1540
1541 static void mouse_mesh_loop_face(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear)
1542 {
1543         if (select_clear) {
1544                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
1545         }
1546
1547         walker_select(em, BMW_FACELOOP, eed, select);
1548 }
1549
1550 static void mouse_mesh_loop_edge_ring(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear)
1551 {
1552         if (select_clear) {
1553                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
1554         }
1555
1556         walker_select(em, BMW_EDGERING, eed, select);
1557 }
1558
1559 static void mouse_mesh_loop_edge(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear, bool select_cycle)
1560 {
1561         bool edge_boundary = false;
1562
1563         /* cycle between BMW_EDGELOOP / BMW_EDGEBOUNDARY  */
1564         if (select_cycle && BM_edge_is_boundary(eed)) {
1565                 int tot[2];
1566
1567                 /* if the loops selected toggle the boundaries */
1568                 walker_select_count(em, BMW_EDGELOOP, eed, select, false,
1569                                     &tot[0], &tot[1]);
1570                 if (tot[select] == 0) {
1571                         edge_boundary = true;
1572
1573                         /* if the boundaries selected, toggle back to the loop */
1574                         walker_select_count(em, BMW_EDGEBOUNDARY, eed, select, false,
1575                                             &tot[0], &tot[1]);
1576                         if (tot[select] == 0) {
1577                                 edge_boundary = false;
1578                         }
1579                 }
1580         }
1581
1582         if (select_clear) {
1583                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
1584         }
1585
1586         if (edge_boundary) {
1587                 walker_select(em, BMW_EDGEBOUNDARY, eed, select);
1588         }
1589         else {
1590                 walker_select(em, BMW_EDGELOOP, eed, select);
1591         }
1592 }
1593
1594 static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, bool ring)
1595 {
1596         ViewContext vc;
1597         BMEditMesh *em;
1598         BMEdge *eed;
1599         bool select = true;
1600         bool select_clear = false;
1601         bool select_cycle = true;
1602         float dist = ED_view3d_select_dist_px() * 0.6666f;
1603         float mvalf[2];
1604
1605         em_setup_viewcontext(C, &vc);
1606         mvalf[0] = (float)(vc.mval[0] = mval[0]);
1607         mvalf[1] = (float)(vc.mval[1] = mval[1]);
1608         em = vc.em;
1609
1610         /* Make sure that the edges are also considered for selection.
1611          * TODO: cleanup: add `selectmode` as a parameter */
1612         const short ts_selectmode = vc.scene->toolsettings->selectmode;
1613         vc.scene->toolsettings->selectmode |= SCE_SELECT_EDGE;
1614
1615         /* no afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad */
1616         ED_view3d_backbuf_validate(&vc);
1617
1618         /* restore `selectmode` */
1619         vc.scene->toolsettings->selectmode = ts_selectmode;
1620
1621         eed = EDBM_edge_find_nearest_ex(&vc, &dist, NULL, true, true, NULL);
1622         if (eed == NULL) {
1623                 return false;
1624         }
1625
1626         if (extend == false && deselect == false && toggle == false) {
1627                 select_clear = true;
1628         }
1629
1630         if (extend) {
1631                 select = true;
1632         }
1633         else if (deselect) {
1634                 select = false;
1635         }
1636         else if (select_clear || (BM_elem_flag_test(eed, BM_ELEM_SELECT) == 0)) {
1637                 select = true;
1638         }
1639         else if (toggle) {
1640                 select = false;
1641                 select_cycle = false;
1642         }
1643
1644         if (em->selectmode & SCE_SELECT_FACE) {
1645                 mouse_mesh_loop_face(em, eed, select, select_clear);
1646         }
1647         else {
1648                 if (ring) {
1649                         mouse_mesh_loop_edge_ring(em, eed, select, select_clear);
1650                 }
1651                 else {
1652                         mouse_mesh_loop_edge(em, eed, select, select_clear, select_cycle);
1653                 }
1654         }
1655
1656         EDBM_selectmode_flush(em);
1657
1658         /* sets as active, useful for other tools */
1659         if (select) {
1660                 if (em->selectmode & SCE_SELECT_VERTEX) {
1661                         /* Find nearest vert from mouse
1662                          * (initialize to large values incase only one vertex can be projected) */
1663                         float v1_co[2], v2_co[2];
1664                         float length_1 = FLT_MAX;
1665                         float length_2 = FLT_MAX;
1666
1667                         /* We can't be sure this has already been set... */
1668                         ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
1669
1670                         if (ED_view3d_project_float_object(
1671                                     vc.ar, eed->v1->co, v1_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
1672                         {
1673                                 length_1 = len_squared_v2v2(mvalf, v1_co);
1674                         }
1675
1676                         if (ED_view3d_project_float_object(
1677                                     vc.ar, eed->v2->co, v2_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
1678                         {
1679                                 length_2 = len_squared_v2v2(mvalf, v2_co);
1680                         }
1681 #if 0
1682                         printf("mouse to v1: %f\nmouse to v2: %f\n", len_squared_v2v2(mvalf, v1_co),
1683                                len_squared_v2v2(mvalf, v2_co));
1684 #endif
1685                         BM_select_history_store(em->bm, (length_1 < length_2) ? eed->v1 : eed->v2);
1686                 }
1687                 else if (em->selectmode & SCE_SELECT_EDGE) {
1688                         BM_select_history_store(em->bm, eed);
1689                 }
1690                 else if (em->selectmode & SCE_SELECT_FACE) {
1691                         /* Select the face of eed which is the nearest of mouse. */
1692                         BMFace *f, *efa = NULL;
1693                         BMIter iterf;
1694                         float best_dist = FLT_MAX;
1695
1696                         /* We can't be sure this has already been set... */
1697                         ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
1698
1699                         BM_ITER_ELEM (f, &iterf, eed, BM_FACES_OF_EDGE) {
1700                                 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
1701                                         float cent[3];
1702                                         float co[2], tdist;
1703
1704                                         BM_face_calc_center_mean(f, cent);
1705                                         if (ED_view3d_project_float_object(
1706                                                     vc.ar, cent, co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
1707                                         {
1708                                                 tdist = len_squared_v2v2(mvalf, co);
1709                                                 if (tdist < best_dist) {
1710 /*                                                      printf("Best face: %p (%f)\n", f, tdist);*/
1711                                                         best_dist = tdist;
1712                                                         efa = f;
1713                                                 }
1714                                         }
1715                                 }
1716                         }
1717                         if (efa) {
1718                                 BM_mesh_active_face_set(em->bm, efa);
1719                                 BM_select_history_store(em->bm, efa);
1720                         }
1721                 }
1722         }
1723
1724         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
1725
1726         return true;
1727 }
1728
1729 static int edbm_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1730 {
1731
1732         view3d_operator_needs_opengl(C);
1733
1734         if (mouse_mesh_loop(
1735                     C, event->mval,
1736                     RNA_boolean_get(op->ptr, "extend"),
1737                     RNA_boolean_get(op->ptr, "deselect"),
1738                     RNA_boolean_get(op->ptr, "toggle"),
1739                     RNA_boolean_get(op->ptr, "ring")))
1740         {
1741                 return OPERATOR_FINISHED;
1742         }
1743         else {
1744                 return OPERATOR_CANCELLED;
1745         }
1746 }
1747
1748 void MESH_OT_loop_select(wmOperatorType *ot)
1749 {
1750         /* identifiers */
1751         ot->name = "Loop Select";
1752         ot->idname = "MESH_OT_loop_select";
1753         ot->description = "Select a loop of connected edges";
1754
1755         /* api callbacks */
1756         ot->invoke = edbm_select_loop_invoke;
1757         ot->poll = ED_operator_editmesh_region_view3d;
1758
1759         /* flags */
1760         ot->flag = OPTYPE_UNDO;
1761
1762         /* properties */
1763         RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "Extend the selection");
1764         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from the selection");
1765         RNA_def_boolean(ot->srna, "toggle", 0, "Toggle Select", "Toggle the selection");
1766         RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "Select ring");
1767 }
1768
1769 void MESH_OT_edgering_select(wmOperatorType *ot)
1770 {
1771         /* description */
1772         ot->name = "Edge Ring Select";
1773         ot->idname = "MESH_OT_edgering_select";
1774         ot->description = "Select an edge ring";
1775
1776         /* callbacks */
1777         ot->invoke = edbm_select_loop_invoke;
1778         ot->poll = ED_operator_editmesh_region_view3d;
1779
1780         /* flags */
1781         ot->flag = OPTYPE_UNDO;
1782
1783         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
1784         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from the selection");
1785         RNA_def_boolean(ot->srna, "toggle", 0, "Toggle Select", "Toggle the selection");
1786         RNA_def_boolean(ot->srna, "ring", 1, "Select Ring", "Select ring");
1787 }
1788
1789 /** \} */
1790
1791 /* -------------------------------------------------------------------- */
1792 /** \name (De)Select All Operator
1793  * \{ */
1794
1795 static int edbm_select_all_exec(bContext *C, wmOperator *op)
1796 {
1797         Object *obedit = CTX_data_edit_object(C);
1798         BMEditMesh *em = BKE_editmesh_from_object(obedit);
1799         const int action = RNA_enum_get(op->ptr, "action");
1800
1801         switch (action) {
1802                 case SEL_TOGGLE:
1803                         EDBM_select_toggle_all(em);
1804                         break;
1805                 case SEL_SELECT:
1806                         EDBM_flag_enable_all(em, BM_ELEM_SELECT);
1807                         break;
1808                 case SEL_DESELECT:
1809                         EDBM_flag_disable_all(em, BM_ELEM_SELECT);
1810                         break;
1811                 case SEL_INVERT:
1812                         EDBM_select_swap(em);
1813                         EDBM_selectmode_flush(em);
1814                         break;
1815         }
1816
1817         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
1818
1819         return OPERATOR_FINISHED;
1820 }
1821
1822 void MESH_OT_select_all(wmOperatorType *ot)
1823 {
1824         /* identifiers */
1825         ot->name = "(De)select All";
1826         ot->idname = "MESH_OT_select_all";
1827         ot->description = "(De)select all vertices, edges or faces";
1828
1829         /* api callbacks */
1830         ot->exec = edbm_select_all_exec;
1831         ot->poll = ED_operator_editmesh;
1832
1833         /* flags */
1834         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1835
1836         WM_operator_properties_select_all(ot);
1837 }
1838
1839 /** \} */
1840
1841 /* -------------------------------------------------------------------- */
1842 /** \name Select Interior Faces Operator
1843  * \{ */
1844
1845 static int edbm_faces_select_interior_exec(bContext *C, wmOperator *UNUSED(op))
1846 {
1847         Object *obedit = CTX_data_edit_object(C);
1848         BMEditMesh *em = BKE_editmesh_from_object(obedit);
1849
1850         if (EDBM_select_interior_faces(em)) {
1851                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
1852
1853                 return OPERATOR_FINISHED;
1854         }
1855         else {
1856                 return OPERATOR_CANCELLED;
1857         }
1858
1859 }
1860
1861 void MESH_OT_select_interior_faces(wmOperatorType *ot)
1862 {
1863         /* identifiers */
1864         ot->name = "Select Interior Faces";
1865         ot->idname = "MESH_OT_select_interior_faces";
1866         ot->description = "Select faces where all edges have more than 2 face users";
1867
1868         /* api callbacks */
1869         ot->exec = edbm_faces_select_interior_exec;
1870         ot->poll = ED_operator_editmesh;
1871
1872         /* flags */
1873         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1874 }
1875
1876 /** \} */
1877
1878 /* -------------------------------------------------------------------- */
1879 /** \name Select Picking API
1880  *
1881  * Here actual select happens,
1882  * Gets called via generic mouse select operator.
1883  * \{ */
1884
1885 bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
1886 {
1887         ViewContext vc;
1888         BMVert *eve = NULL;
1889         BMEdge *eed = NULL;
1890         BMFace *efa = NULL;
1891
1892         /* setup view context for argument to callbacks */
1893         em_setup_viewcontext(C, &vc);
1894         vc.mval[0] = mval[0];
1895         vc.mval[1] = mval[1];
1896
1897         if (unified_findnearest(&vc, &eve, &eed, &efa)) {
1898
1899                 /* Deselect everything */
1900                 if (extend == false && deselect == false && toggle == false)
1901                         EDBM_flag_disable_all(vc.em, BM_ELEM_SELECT);
1902
1903                 if (efa) {
1904                         if (extend) {
1905                                 /* set the last selected face */
1906                                 BM_mesh_active_face_set(vc.em->bm, efa);
1907
1908                                 /* Work-around: deselect first, so we can guarantee it will */
1909                                 /* be active even if it was already selected */
1910                                 BM_select_history_remove(vc.em->bm, efa);
1911                                 BM_face_select_set(vc.em->bm, efa, false);
1912                                 BM_select_history_store(vc.em->bm, efa);
1913                                 BM_face_select_set(vc.em->bm, efa, true);
1914                         }
1915                         else if (deselect) {
1916                                 BM_select_history_remove(vc.em->bm, efa);
1917                                 BM_face_select_set(vc.em->bm, efa, false);
1918                         }
1919                         else {
1920                                 /* set the last selected face */
1921                                 BM_mesh_active_face_set(vc.em->bm, efa);
1922
1923                                 if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1924                                         BM_select_history_store(vc.em->bm, efa);
1925                                         BM_face_select_set(vc.em->bm, efa, true);
1926                                 }
1927                                 else if (toggle) {
1928                                         BM_select_history_remove(vc.em->bm, efa);
1929                                         BM_face_select_set(vc.em->bm, efa, false);
1930                                 }
1931                         }
1932                 }
1933                 else if (eed) {
1934                         if (extend) {
1935                                 /* Work-around: deselect first, so we can guarantee it will */
1936                                 /* be active even if it was already selected */
1937                                 BM_select_history_remove(vc.em->bm, eed);
1938                                 BM_edge_select_set(vc.em->bm, eed, false);
1939                                 BM_select_history_store(vc.em->bm, eed);
1940                                 BM_edge_select_set(vc.em->bm, eed, true);
1941                         }
1942                         else if (deselect) {
1943                                 BM_select_history_remove(vc.em->bm, eed);
1944                                 BM_edge_select_set(vc.em->bm, eed, false);
1945                         }
1946                         else {
1947                                 if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1948                                         BM_select_history_store(vc.em->bm, eed);
1949                                         BM_edge_select_set(vc.em->bm, eed, true);
1950                                 }
1951                                 else if (toggle) {
1952                                         BM_select_history_remove(vc.em->bm, eed);
1953                                         BM_edge_select_set(vc.em->bm, eed, false);
1954                                 }
1955                         }
1956                 }
1957                 else if (eve) {
1958                         if (extend) {
1959                                 /* Work-around: deselect first, so we can guarantee it will */
1960                                 /* be active even if it was already selected */
1961                                 BM_select_history_remove(vc.em->bm, eve);
1962                                 BM_vert_select_set(vc.em->bm, eve, false);
1963                                 BM_select_history_store(vc.em->bm, eve);
1964                                 BM_vert_select_set(vc.em->bm, eve, true);
1965                         }
1966                         else if (deselect) {
1967                                 BM_select_history_remove(vc.em->bm, eve);
1968                                 BM_vert_select_set(vc.em->bm, eve, false);
1969                         }
1970                         else {
1971                                 if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
1972                                         BM_select_history_store(vc.em->bm, eve);
1973                                         BM_vert_select_set(vc.em->bm, eve, true);
1974                                 }
1975                                 else if (toggle) {
1976                                         BM_select_history_remove(vc.em->bm, eve);
1977                                         BM_vert_select_set(vc.em->bm, eve, false);
1978                                 }
1979                         }
1980                 }
1981
1982                 EDBM_selectmode_flush(vc.em);
1983
1984                 /* change active material on object */
1985                 if (efa && efa->mat_nr != vc.obedit->actcol - 1) {
1986                         vc.obedit->actcol = efa->mat_nr + 1;
1987                         vc.em->mat_nr = efa->mat_nr;
1988
1989                         WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL);
1990
1991                 }
1992
1993                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
1994                 return true;
1995         }
1996
1997         return false;
1998 }
1999
2000 /** \} */
2001
2002 /* -------------------------------------------------------------------- */
2003 /** \name Select Mode Utilities
2004  * \{ */
2005
2006 static void edbm_strip_selections(BMEditMesh *em)
2007 {
2008         BMEditSelection *ese, *nextese;
2009
2010         if (!(em->selectmode & SCE_SELECT_VERTEX)) {
2011                 ese = em->bm->selected.first;
2012                 while (ese) {
2013                         nextese = ese->next;
2014                         if (ese->htype == BM_VERT) BLI_freelinkN(&(em->bm->selected), ese);
2015                         ese = nextese;
2016                 }
2017         }
2018         if (!(em->selectmode & SCE_SELECT_EDGE)) {
2019                 ese = em->bm->selected.first;
2020                 while (ese) {
2021                         nextese = ese->next;
2022                         if (ese->htype == BM_EDGE) BLI_freelinkN(&(em->bm->selected), ese);
2023                         ese = nextese;
2024                 }
2025         }
2026         if (!(em->selectmode & SCE_SELECT_FACE)) {
2027                 ese = em->bm->selected.first;
2028                 while (ese) {
2029                         nextese = ese->next;
2030                         if (ese->htype == BM_FACE) BLI_freelinkN(&(em->bm->selected), ese);
2031                         ese = nextese;
2032                 }
2033         }
2034 }
2035
2036 /* when switching select mode, makes sure selection is consistent for editing */
2037 /* also for paranoia checks to make sure edge or face mode works */
2038 void EDBM_selectmode_set(BMEditMesh *em)
2039 {
2040         BMVert *eve;
2041         BMEdge *eed;
2042         BMFace *efa;
2043         BMIter iter;
2044
2045         em->bm->selectmode = em->selectmode;
2046
2047         edbm_strip_selections(em); /* strip BMEditSelections from em->selected that are not relevant to new mode */
2048
2049         if (em->bm->totvertsel == 0 &&
2050             em->bm->totedgesel == 0 &&
2051             em->bm->totfacesel == 0)
2052         {
2053                 return;
2054         }
2055
2056         if (em->selectmode & SCE_SELECT_VERTEX) {
2057                 if (em->bm->totvertsel) {
2058                         EDBM_select_flush(em);
2059                 }
2060         }
2061         else if (em->selectmode & SCE_SELECT_EDGE) {
2062                 /* deselect vertices, and select again based on edge select */
2063                 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2064                         BM_vert_select_set(em->bm, eve, false);
2065                 }
2066
2067                 if (em->bm->totedgesel) {
2068                         BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2069                                 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2070                                         BM_edge_select_set(em->bm, eed, true);
2071                                 }
2072                         }
2073
2074                         /* selects faces based on edge status */
2075                         EDBM_selectmode_flush(em);
2076                 }
2077         }
2078         else if (em->selectmode & SCE_SELECT_FACE) {
2079                 /* deselect eges, and select again based on face select */
2080                 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2081                         BM_edge_select_set(em->bm, eed, false);
2082                 }
2083
2084                 if (em->bm->totfacesel) {
2085                         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2086                                 if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2087                                         BM_face_select_set(em->bm, efa, true);
2088                                 }
2089                         }
2090                 }
2091         }
2092 }
2093
2094 /**
2095  * Expand & Contract the Selection
2096  * (used when changing modes and Ctrl key held)
2097  *
2098  * Flush the selection up:
2099  * - vert -> edge
2100  * - vert -> face
2101  * - edge -> face
2102  *
2103  * Flush the selection down:
2104  * - face -> edge
2105  * - face -> vert
2106  * - edge -> vert
2107  */
2108 void EDBM_selectmode_convert(BMEditMesh *em, const short selectmode_old, const short selectmode_new)
2109 {
2110         BMesh *bm = em->bm;
2111
2112         BMVert *eve;
2113         BMEdge *eed;
2114         BMFace *efa;
2115         BMIter iter;
2116
2117         /* first tag-to-select, then select --- this avoids a feedback loop */
2118
2119         /* have to find out what the selectionmode was previously */
2120         if (selectmode_old == SCE_SELECT_VERTEX) {
2121                 if (bm->totvertsel == 0) {
2122                         /* pass */
2123                 }
2124                 else if (selectmode_new == SCE_SELECT_EDGE) {
2125                         /* flush up (vert -> edge) */
2126
2127                         /* select all edges associated with every selected vert */
2128                         BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
2129                                 BM_elem_flag_set(eed, BM_ELEM_TAG, BM_edge_is_any_vert_flag_test(eed, BM_ELEM_SELECT));
2130                         }
2131
2132                         BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
2133                                 if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
2134                                         BM_edge_select_set(bm, eed, true);
2135                                 }
2136                         }
2137                 }
2138                 else if (selectmode_new == SCE_SELECT_FACE) {
2139                         /* flush up (vert -> face) */
2140
2141                         /* select all faces associated with every selected vert */
2142                         BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2143                                 BM_elem_flag_set(efa, BM_ELEM_TAG, BM_face_is_any_vert_flag_test(efa, BM_ELEM_SELECT));
2144                         }
2145
2146                         BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2147                                 if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2148                                         BM_face_select_set(bm, efa, true);
2149                                 }
2150                         }
2151                 }
2152         }
2153         else if (selectmode_old == SCE_SELECT_EDGE) {
2154                 if (bm->totedgesel == 0) {
2155                         /* pass */
2156                 }
2157                 else if (selectmode_new == SCE_SELECT_FACE) {
2158                         /* flush up (edge -> face) */
2159
2160                         /* select all faces associated with every selected edge */
2161                         BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2162                                 BM_elem_flag_set(efa, BM_ELEM_TAG, BM_face_is_any_edge_flag_test(efa, BM_ELEM_SELECT));
2163                         }
2164
2165                         BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2166                                 if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2167                                         BM_face_select_set(bm, efa, true);
2168                                 }
2169                         }
2170                 }
2171                 else if (selectmode_new == SCE_SELECT_VERTEX) {
2172                         /* flush down (edge -> vert) */
2173
2174                         BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
2175                                 if (!BM_vert_is_all_edge_flag_test(eve, BM_ELEM_SELECT, true)) {
2176                                         BM_vert_select_set(bm, eve, false);
2177                                 }
2178                         }
2179                         /* deselect edges without both verts selected */
2180                         BM_mesh_deselect_flush(bm);
2181                 }
2182         }
2183         else if (selectmode_old == SCE_SELECT_FACE) {
2184                 if (bm->totfacesel == 0) {
2185                         /* pass */
2186                 }
2187                 else if (selectmode_new == SCE_SELECT_EDGE) {
2188                         /* flush down (face -> edge) */
2189
2190                         BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
2191                                 if (!BM_edge_is_all_face_flag_test(eed, BM_ELEM_SELECT, true)) {
2192                                         BM_edge_select_set(bm, eed, false);
2193                                 }
2194                         }
2195                 }
2196                 else if (selectmode_new == SCE_SELECT_VERTEX) {
2197                         /* flush down (face -> vert) */
2198
2199                         BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
2200                                 if (!BM_vert_is_all_face_flag_test(eve, BM_ELEM_SELECT, true)) {
2201                                         BM_vert_select_set(bm, eve, false);
2202                                 }
2203                         }
2204                         /* deselect faces without verts selected */
2205                         BM_mesh_deselect_flush(bm);
2206                 }
2207         }
2208 }
2209
2210 /* user facing function, does notification */
2211 bool EDBM_selectmode_toggle(
2212         bContext *C, const short selectmode_new,
2213         const int action, const bool use_extend, const bool use_expand)
2214 {
2215         ToolSettings *ts = CTX_data_tool_settings(C);
2216         Object *obedit = CTX_data_edit_object(C);
2217         BMEditMesh *em = NULL;
2218         bool ret = false;
2219
2220         if (obedit && obedit->type == OB_MESH) {
2221                 em = BKE_editmesh_from_object(obedit);
2222         }
2223
2224         if (em == NULL) {
2225                 return ret;
2226         }
2227
2228         switch (action) {
2229                 case -1:
2230                         /* already set */
2231                         break;
2232                 case 0:  /* disable */
2233                         /* check we have something to do */
2234                         if ((em->selectmode & selectmode_new) == 0) {
2235                                 return false;
2236                         }
2237                         em->selectmode &= ~selectmode_new;
2238                         break;
2239                 case 1:  /* enable */
2240                         /* check we have something to do */
2241                         if ((em->selectmode & selectmode_new) != 0) {
2242                                 return false;
2243                         }
2244                         em->selectmode |= selectmode_new;
2245                         break;
2246                 case 2:  /* toggle */
2247                         /* can't disable this flag if its the only one set */
2248                         if (em->selectmode == selectmode_new) {
2249                                 return false;
2250                         }
2251                         em->selectmode ^= selectmode_new;
2252                         break;
2253                 default:
2254                         BLI_assert(0);
2255                         break;
2256         }
2257
2258         if (use_extend == 0 || em->selectmode == 0) {
2259                 if (use_expand) {
2260                         const short selmode_max = highest_order_bit_s(ts->selectmode);
2261                         EDBM_selectmode_convert(em, selmode_max, selectmode_new);
2262                 }
2263         }
2264
2265         switch (selectmode_new) {
2266                 case SCE_SELECT_VERTEX:
2267                         if (use_extend == 0 || em->selectmode == 0) {
2268                                 em->selectmode = SCE_SELECT_VERTEX;
2269                         }
2270                         ts->selectmode = em->selectmode;
2271                         EDBM_selectmode_set(em);
2272                         ret = true;
2273                         break;
2274                 case SCE_SELECT_EDGE:
2275                         if (use_extend == 0 || em->selectmode == 0) {
2276                                 em->selectmode = SCE_SELECT_EDGE;
2277                         }
2278                         ts->selectmode = em->selectmode;
2279                         EDBM_selectmode_set(em);
2280                         ret = true;
2281                         break;
2282                 case SCE_SELECT_FACE:
2283                         if (use_extend == 0 || em->selectmode == 0) {
2284                                 em->selectmode = SCE_SELECT_FACE;
2285                         }
2286                         ts->selectmode = em->selectmode;
2287                         EDBM_selectmode_set(em);
2288                         ret = true;
2289                         break;
2290                 default:
2291                         BLI_assert(0);
2292                         break;
2293         }
2294
2295         if (ret == true) {
2296                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2297                 WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
2298         }
2299
2300         return ret;
2301 }
2302
2303 /**
2304  * Use to disable a selectmode if its enabled, Using another mode as a fallback
2305  * if the disabled mode is the only mode set.
2306  *
2307  * \return true if the mode is changed.
2308  */
2309 bool EDBM_selectmode_disable(
2310         Scene *scene, BMEditMesh *em,
2311         const short selectmode_disable,
2312         const short selectmode_fallback)
2313 {
2314         /* note essential, but switch out of vertex mode since the
2315          * selected regions wont be nicely isolated after flushing */
2316         if (em->selectmode & selectmode_disable) {
2317                 if (em->selectmode == selectmode_disable) {
2318                         em->selectmode = selectmode_fallback;
2319                 }
2320                 else {
2321                         em->selectmode &= ~selectmode_disable;
2322                 }
2323                 scene->toolsettings->selectmode = em->selectmode;
2324                 EDBM_selectmode_set(em);
2325
2326                 WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, scene);
2327
2328                 return true;
2329         }
2330         else {
2331                 return false;
2332         }
2333 }
2334
2335 /** \} */
2336
2337 /* -------------------------------------------------------------------- */
2338 /** \name Select Toggle
2339  * \{ */
2340
2341 void EDBM_deselect_by_material(BMEditMesh *em, const short index, const bool select)
2342 {
2343         BMIter iter;
2344         BMFace *efa;
2345
2346         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2347                 if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
2348                         continue;
2349                 if (efa->mat_nr == index) {
2350                         BM_face_select_set(em->bm, efa, select);
2351                 }
2352         }
2353 }
2354
2355 void EDBM_select_toggle_all(BMEditMesh *em) /* exported for UV */
2356 {
2357         if (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel)
2358                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
2359         else
2360                 EDBM_flag_enable_all(em, BM_ELEM_SELECT);
2361 }
2362
2363 void EDBM_select_swap(BMEditMesh *em) /* exported for UV */
2364 {
2365         BMIter iter;
2366         BMVert *eve;
2367         BMEdge *eed;
2368         BMFace *efa;
2369
2370         if (em->bm->selectmode & SCE_SELECT_VERTEX) {
2371                 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2372                         if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
2373                                 continue;
2374                         BM_vert_select_set(em->bm, eve, !BM_elem_flag_test(eve, BM_ELEM_SELECT));
2375                 }
2376         }
2377         else if (em->selectmode & SCE_SELECT_EDGE) {
2378                 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2379                         if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
2380                                 continue;
2381                         BM_edge_select_set(em->bm, eed, !BM_elem_flag_test(eed, BM_ELEM_SELECT));
2382                 }
2383         }
2384         else {
2385                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2386                         if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
2387                                 continue;
2388                         BM_face_select_set(em->bm, efa, !BM_elem_flag_test(efa, BM_ELEM_SELECT));
2389                 }
2390
2391         }
2392 }
2393
2394 /** \} */
2395
2396 /* -------------------------------------------------------------------- */
2397 /** \name Select Interior Faces
2398  *
2399  * \note This algorithm is limited to single faces and could be improved, see:
2400  * https://blender.stackexchange.com/questions/18916
2401  * \{ */
2402
2403 bool EDBM_select_interior_faces(BMEditMesh *em)
2404 {
2405         BMesh *bm = em->bm;
2406         BMIter iter;
2407         BMIter eiter;
2408         BMFace *efa;
2409         BMEdge *eed;
2410         bool ok;
2411         bool changed = false;
2412
2413         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2414                 if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
2415                         continue;
2416
2417
2418                 ok = true;
2419                 BM_ITER_ELEM (eed, &eiter, efa, BM_EDGES_OF_FACE) {
2420                         if (!BM_edge_face_count_is_over(eed, 2)) {
2421                                 ok = false;
2422                                 break;
2423                         }
2424                 }
2425
2426                 if (ok) {
2427                         BM_face_select_set(bm, efa, true);
2428                         changed = true;
2429                 }
2430         }
2431
2432         return changed;
2433 }
2434
2435 /** \} */
2436
2437 /* -------------------------------------------------------------------- */
2438 /** \name Select Linked Operator
2439  *
2440  * Support delimiting on different edge properties.
2441  * \{ */
2442
2443 /* so we can have last-used default depend on selection mode (rare exception!) */
2444 #define USE_LINKED_SELECT_DEFAULT_HACK
2445
2446 struct DelimitData {
2447         int cd_loop_type;
2448         int cd_loop_offset;
2449 };
2450
2451 static bool select_linked_delimit_test(
2452         BMEdge *e, int delimit,
2453         const struct DelimitData *delimit_data)
2454 {
2455         BLI_assert(delimit);
2456
2457         if (delimit & BMO_DELIM_SEAM) {
2458                 if (BM_elem_flag_test(e, BM_ELEM_SEAM)) {
2459                         return true;
2460                 }
2461         }
2462
2463         if (delimit & BMO_DELIM_SHARP) {
2464                 if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0) {
2465                         return true;
2466                 }
2467         }
2468
2469         if (delimit & BMO_DELIM_NORMAL) {
2470                 if (!BM_edge_is_contiguous(e)) {
2471                         return true;
2472                 }
2473         }
2474
2475         if (delimit & BMO_DELIM_MATERIAL) {
2476                 if (e->l && e->l->radial_next != e->l) {
2477                         const short mat_nr = e->l->f->mat_nr;
2478                         BMLoop *l_iter = e->l->radial_next;
2479                         do {
2480                                 if (l_iter->f->mat_nr != mat_nr) {
2481                                         return true;
2482                                 }
2483                         } while ((l_iter = l_iter->radial_next) != e->l);
2484                 }
2485         }
2486
2487         if (delimit & BMO_DELIM_UV) {
2488                 if (BM_edge_is_contiguous_loop_cd(e, delimit_data->cd_loop_type, delimit_data->cd_loop_offset) == 0) {
2489                         return true;
2490                 }
2491         }
2492
2493         return false;
2494 }
2495
2496 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
2497 /**
2498  * Gets the default from the operator fallback to own last-used value
2499  * (selected based on mode)
2500  */
2501 static int select_linked_delimit_default_from_op(wmOperator *op, int select_mode)
2502 {
2503         static char delimit_last_store[2] = {0, BMO_DELIM_SEAM};
2504         int delimit_last_index = (select_mode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0;
2505         char *delimit_last = &delimit_last_store[delimit_last_index];
2506         PropertyRNA *prop_delimit = RNA_struct_find_property(op->ptr, "delimit");
2507         int delimit;
2508
2509         if (RNA_property_is_set(op->ptr, prop_delimit)) {
2510                 delimit = RNA_property_enum_get(op->ptr, prop_delimit);
2511                 *delimit_last = delimit;
2512         }
2513         else {
2514                 delimit = *delimit_last;
2515                 RNA_property_enum_set(op->ptr, prop_delimit, delimit);
2516         }
2517         return delimit;
2518 }
2519 #endif
2520
2521 static void select_linked_delimit_validate(BMesh *bm, int *delimit)
2522 {
2523         if ((*delimit) & BMO_DELIM_UV) {
2524                 if (!CustomData_has_layer(&bm->ldata, CD_MLOOPUV)) {
2525                         (*delimit) &= ~BMO_DELIM_UV;
2526                 }
2527         }
2528 }
2529
2530 static void select_linked_delimit_begin(BMesh *bm, int delimit)
2531 {
2532         struct DelimitData delimit_data = {0};
2533
2534         if (delimit & BMO_DELIM_UV) {
2535                 delimit_data.cd_loop_type = CD_MLOOPUV;
2536                 delimit_data.cd_loop_offset = CustomData_get_offset(&bm->ldata, delimit_data.cd_loop_type);
2537                 if (delimit_data.cd_loop_offset == -1) {
2538                         delimit &= ~BMO_DELIM_UV;
2539                 }
2540         }
2541
2542         /* grr, shouldn't need to alloc BMO flags here */
2543         BM_mesh_elem_toolflags_ensure(bm);
2544
2545         {
2546                 BMIter iter;
2547                 BMEdge *e;
2548
2549                 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
2550                         const bool is_walk_ok = (
2551                                 (select_linked_delimit_test(e, delimit, &delimit_data) == false));
2552
2553                         BMO_edge_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok);
2554                 }
2555         }
2556 }
2557
2558 static void select_linked_delimit_end(BMEditMesh *em)
2559 {
2560         BMesh *bm = em->bm;
2561
2562         BM_mesh_elem_toolflags_clear(bm);
2563 }
2564
2565 static int edbm_select_linked_exec(bContext *C, wmOperator *op)
2566 {
2567         Object *obedit = CTX_data_edit_object(C);
2568         BMEditMesh *em = BKE_editmesh_from_object(obedit);
2569         BMesh *bm = em->bm;
2570         BMIter iter;
2571         BMWalker walker;
2572
2573 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
2574         int delimit = select_linked_delimit_default_from_op(op, em->selectmode);
2575 #else
2576         int delimit = RNA_enum_get(op->ptr, "delimit");
2577 #endif
2578
2579         select_linked_delimit_validate(bm, &delimit);
2580
2581         if (delimit) {
2582                 select_linked_delimit_begin(em->bm, delimit);
2583         }
2584
2585         if (em->selectmode & SCE_SELECT_VERTEX) {
2586                 BMVert *v;
2587
2588                 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2589                         BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT));
2590                 }
2591
2592                 /* exclude all delimited verts */
2593                 if (delimit) {
2594                         BMEdge *e;
2595                         BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
2596                                 if (!BMO_edge_flag_test(bm, e, BMO_ELE_TAG)) {
2597                                         BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
2598                                         BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
2599                                 }
2600                         }
2601                 }
2602
2603                 BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
2604                          BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
2605                          BMW_FLAG_TEST_HIDDEN,
2606                          BMW_NIL_LAY);
2607
2608                 if (delimit) {
2609                         BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2610                                 if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
2611                                         BMElem *ele_walk;
2612                                         BMW_ITER (ele_walk, &walker, v) {
2613                                                 if (ele_walk->head.htype == BM_LOOP) {
2614                                                         BMVert *v_step = ((BMLoop *)ele_walk)->v;
2615                                                         BM_vert_select_set(em->bm, v_step, true);
2616                                                         BM_elem_flag_disable(v_step, BM_ELEM_TAG);
2617                                                 }
2618                                                 else {
2619                                                         BMEdge *e_step = (BMEdge *)ele_walk;
2620                                                         BLI_assert(ele_walk->head.htype == BM_EDGE);
2621                                                         BM_edge_select_set(em->bm, e_step, true);
2622                                                         BM_elem_flag_disable(e_step->v1, BM_ELEM_TAG);
2623                                                         BM_elem_flag_disable(e_step->v2, BM_ELEM_TAG);
2624                                                 }
2625                                         }
2626                                 }
2627                         }
2628                 }
2629                 else {
2630                         BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2631                                 if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
2632                                         BMEdge *e_walk;
2633                                         BMW_ITER (e_walk, &walker, v) {
2634                                                 BM_edge_select_set(em->bm, e_walk, true);
2635                                                 BM_elem_flag_disable(e_walk, BM_ELEM_TAG);
2636                                         }
2637                                 }
2638                         }
2639                 }
2640
2641                 BMW_end(&walker);
2642
2643                 EDBM_selectmode_flush(em);
2644         }
2645         else if (em->selectmode & SCE_SELECT_EDGE) {
2646                 BMEdge *e;
2647
2648                 if (delimit) {
2649                         BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
2650                                 BM_elem_flag_set(
2651                                         e, BM_ELEM_TAG,
2652                                         (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_edge_flag_test(bm, e, BMO_ELE_TAG)));
2653                         }
2654                 }
2655                 else {
2656                         BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
2657                                 BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
2658                         }
2659                 }
2660
2661                 BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
2662                          BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
2663                          BMW_FLAG_TEST_HIDDEN,
2664                          BMW_NIL_LAY);
2665
2666                 if (delimit) {
2667                         BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
2668                                 if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
2669                                         BMElem *ele_walk;
2670                                         BMW_ITER (ele_walk, &walker, e) {
2671                                                 if (ele_walk->head.htype == BM_LOOP) {
2672                                                         BMLoop *l_step = (BMLoop *)ele_walk;
2673                                                         BM_edge_select_set(em->bm, l_step->e, true);
2674                                                         BM_edge_select_set(em->bm, l_step->prev->e, true);
2675                                                         BM_elem_flag_disable(l_step->e, BM_ELEM_TAG);
2676                                                 }
2677                                                 else {
2678                                                         BMEdge *e_step = (BMEdge *)ele_walk;
2679                                                         BLI_assert(ele_walk->head.htype == BM_EDGE);
2680                                                         BM_edge_select_set(em->bm, e_step, true);
2681                                                         BM_elem_flag_disable(e_step, BM_ELEM_TAG);
2682                                                 }
2683                                         }
2684                                 }
2685                         }
2686                 }
2687                 else {
2688                         BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
2689                                 if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
2690                                         BMEdge *e_walk;
2691                                         BMW_ITER (e_walk, &walker, e) {
2692                                                 BM_edge_select_set(em->bm, e_walk, true);
2693                                                 BM_elem_flag_disable(e_walk, BM_ELEM_TAG);
2694                                         }
2695                                 }
2696                         }
2697                 }
2698
2699                 BMW_end(&walker);
2700
2701                 EDBM_selectmode_flush(em);
2702         }
2703         else {
2704                 BMFace *f;
2705
2706                 BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
2707                         BM_elem_flag_set(f, BM_ELEM_TAG, BM_elem_flag_test(f, BM_ELEM_SELECT));
2708                 }
2709
2710                 BMW_init(&walker, bm, BMW_ISLAND,
2711                          BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
2712                          BMW_FLAG_TEST_HIDDEN,
2713                          BMW_NIL_LAY);
2714
2715                 BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
2716                         if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
2717                                 BMFace *f_walk;
2718                                 BMW_ITER (f_walk, &walker, f) {
2719                                         BM_face_select_set(bm, f_walk, true);
2720                                         BM_elem_flag_disable(f_walk, BM_ELEM_TAG);
2721                                 }
2722                         }
2723                 }
2724
2725                 BMW_end(&walker);
2726         }
2727
2728         if (delimit) {
2729                 select_linked_delimit_end(em);
2730         }
2731
2732         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2733
2734         return OPERATOR_FINISHED;
2735 }
2736
2737 void MESH_OT_select_linked(wmOperatorType *ot)
2738 {
2739         PropertyRNA *prop;
2740
2741         /* identifiers */
2742         ot->name = "Select Linked All";
2743         ot->idname = "MESH_OT_select_linked";
2744         ot->description = "Select all vertices connected to the current selection";
2745
2746         /* api callbacks */
2747         ot->exec = edbm_select_linked_exec;
2748         ot->poll = ED_operator_editmesh;
2749
2750         /* flags */
2751         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2752
2753         prop = RNA_def_enum_flag(ot->srna, "delimit", rna_enum_mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit",
2754                                  "Delimit selected region");
2755 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
2756         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2757 #else
2758         UNUSED_VARS(prop);
2759 #endif
2760 }
2761
2762 /** \} */
2763
2764 /* -------------------------------------------------------------------- */
2765 /** \name Select Linked (Cursor Pick) Operator
2766  * \{ */
2767
2768 static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op);
2769
2770 static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, int delimit)
2771 {
2772         BMesh *bm = em->bm;
2773         BMWalker walker;
2774
2775         select_linked_delimit_validate(bm, &delimit);
2776
2777         if (delimit) {
2778                 select_linked_delimit_begin(bm, delimit);
2779         }
2780
2781         /* Note: logic closely matches 'edbm_select_linked_exec', keep in sync */
2782
2783         if (ele->head.htype == BM_VERT) {
2784                 BMVert *eve = (BMVert *)ele;
2785
2786                 BMW_init(&walker, bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
2787                          BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
2788                          BMW_FLAG_TEST_HIDDEN,
2789                          BMW_NIL_LAY);
2790
2791                 if (delimit) {
2792                         BMElem *ele_walk;
2793                         BMW_ITER (ele_walk, &walker, eve) {
2794                                 if (ele_walk->head.htype == BM_LOOP) {
2795                                         BMVert *v_step = ((BMLoop *)ele_walk)->v;
2796                                         BM_vert_select_set(bm, v_step, sel);
2797                                 }
2798                                 else {
2799                                         BMEdge *e_step = (BMEdge *)ele_walk;
2800                                         BLI_assert(ele_walk->head.htype == BM_EDGE);
2801                                         BM_edge_select_set(bm, e_step, sel);
2802                                 }
2803                         }
2804                 }
2805                 else {
2806                         BMEdge *e_walk;
2807                         BMW_ITER (e_walk, &walker, eve) {
2808                                 BM_edge_select_set(bm, e_walk, sel);
2809                         }
2810                 }
2811
2812                 BMW_end(&walker);
2813
2814                 EDBM_selectmode_flush(em);
2815         }
2816         else if (ele->head.htype == BM_EDGE) {
2817                 BMEdge *eed = (BMEdge *)ele;
2818
2819                 BMW_init(&walker, bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
2820                          BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
2821                          BMW_FLAG_TEST_HIDDEN,
2822                          BMW_NIL_LAY);
2823
2824                 if (delimit) {
2825                         BMElem *ele_walk;
2826                         BMW_ITER (ele_walk, &walker, eed) {
2827                                 if (ele_walk->head.htype == BM_LOOP) {
2828                                         BMEdge *e_step = ((BMLoop *)ele_walk)->e;
2829                                         BM_edge_select_set(bm, e_step, sel);
2830                                 }
2831                                 else {
2832                                         BMEdge *e_step = (BMEdge *)ele_walk;
2833                                         BLI_assert(ele_walk->head.htype == BM_EDGE);
2834                                         BM_edge_select_set(bm, e_step, sel);
2835                                 }
2836                         }
2837                 }
2838                 else {
2839                         BMEdge *e_walk;
2840                         BMW_ITER (e_walk, &walker, eed) {
2841                                 BM_edge_select_set(bm, e_walk, sel);
2842                         }
2843                 }
2844
2845                 BMW_end(&walker);
2846
2847                 EDBM_selectmode_flush(em);
2848         }
2849         else if (ele->head.htype == BM_FACE) {
2850                 BMFace *efa = (BMFace *)ele;
2851
2852                 BMW_init(&walker, bm, BMW_ISLAND,
2853                          BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
2854                          BMW_FLAG_TEST_HIDDEN,
2855                          BMW_NIL_LAY);
2856
2857                 {
2858                         BMFace *f_walk;
2859                         BMW_ITER (f_walk, &walker, efa) {
2860                                 BM_face_select_set(bm, f_walk, sel);
2861                                 BM_elem_flag_disable(f_walk, BM_ELEM_TAG);
2862                         }
2863                 }
2864
2865                 BMW_end(&walker);
2866         }
2867
2868         if (delimit) {
2869                 select_linked_delimit_end(em);
2870         }
2871 }
2872
2873 static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2874 {
2875         Object *obedit = CTX_data_edit_object(C);
2876         ViewContext vc;
2877         BMEditMesh *em;
2878         BMesh *bm;
2879         BMVert *eve;
2880         BMEdge *eed;
2881         BMFace *efa;
2882         const bool sel = !RNA_boolean_get(op->ptr, "deselect");
2883         int index;
2884
2885         if (RNA_struct_property_is_set(op->ptr, "index")) {
2886                 return edbm_select_linked_pick_exec(C, op);
2887         }
2888
2889         /* unified_finednearest needs ogl */
2890         view3d_operator_needs_opengl(C);
2891
2892         /* setup view context for argument to callbacks */
2893         em_setup_viewcontext(C, &vc);
2894         em = vc.em;
2895         bm = em->bm;
2896
2897         if (bm->totedge == 0) {
2898                 return OPERATOR_CANCELLED;
2899         }
2900
2901         vc.mval[0] = event->mval[0];
2902         vc.mval[1] = event->mval[1];
2903
2904         /* return warning! */
2905         if (unified_findnearest(&vc, &eve, &eed, &efa) == 0) {
2906                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2907
2908                 return OPERATOR_CANCELLED;
2909         }
2910
2911 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
2912         int delimit = select_linked_delimit_default_from_op(op, em->selectmode);
2913 #else
2914         int delimit = RNA_enum_get(op->ptr, "delimit");
2915 #endif
2916
2917         BMElem *ele = EDBM_elem_from_selectmode(em, eve, eed, efa);
2918
2919         edbm_select_linked_pick_ex(em, ele, sel, delimit);
2920
2921         /* to support redo */
2922         BM_mesh_elem_index_ensure(bm, ele->head.htype);
2923         index = EDBM_elem_to_index_any(em, ele);
2924
2925         RNA_int_set(op->ptr, "index", index);
2926
2927         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2928
2929         return OPERATOR_FINISHED;
2930 }
2931
2932
2933 static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op)
2934 {
2935         Object *obedit = CTX_data_edit_object(C);
2936         BMEditMesh *em = BKE_editmesh_from_object(obedit);
2937         BMesh *bm = em->bm;
2938         int index;
2939         const bool sel = !RNA_boolean_get(op->ptr, "deselect");
2940
2941         index = RNA_int_get(op->ptr, "index");
2942         if (index < 0 || index >= (bm->totvert + bm->totedge + bm->totface)) {
2943                 return OPERATOR_CANCELLED;
2944         }
2945
2946         BMElem *ele = EDBM_elem_from_index_any(em, index);
2947
2948 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
2949         int delimit = select_linked_delimit_default_from_op(op, em->selectmode);
2950 #else
2951         int delimit = RNA_enum_get(op->ptr, "delimit");
2952 #endif
2953
2954         edbm_select_linked_pick_ex(em, ele, sel, delimit);
2955
2956         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2957
2958         return OPERATOR_FINISHED;
2959 }
2960
2961 void MESH_OT_select_linked_pick(wmOperatorType *ot)
2962 {
2963         PropertyRNA *prop;
2964
2965         /* identifiers */
2966         ot->name = "Select Linked";
2967         ot->idname = "MESH_OT_select_linked_pick";
2968         ot->description = "(De)select all vertices linked to the edge under the mouse cursor";
2969
2970         /* api callbacks */
2971         ot->invoke = edbm_select_linked_pick_invoke;
2972         ot->exec = edbm_select_linked_pick_exec;
2973         ot->poll = ED_operator_editmesh;
2974
2975         /* flags */
2976         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2977
2978         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
2979         prop = RNA_def_enum_flag(ot->srna, "delimit", rna_enum_mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit",
2980                                  "Delimit selected region");
2981 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
2982         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2983 #endif
2984
2985         /* use for redo */
2986         prop = RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "", "", 0, INT_MAX);
2987         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
2988 }
2989
2990 /** \} */
2991
2992 /* -------------------------------------------------------------------- */
2993 /** \name Select Face by Sides Operator
2994  * \{ */
2995
2996 static int edbm_select_face_by_sides_exec(bContext *C, wmOperator *op)
2997 {
2998         Object *obedit = CTX_data_edit_object(C);
2999         BMEditMesh *em = BKE_editmesh_from_object(obedit);
3000         BMFace *efa;
3001         BMIter iter;
3002         const int numverts = RNA_int_get(op->ptr, "number");
3003         const int type = RNA_enum_get(op->ptr, "type");
3004
3005         if (!RNA_boolean_get(op->ptr, "extend"))
3006                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
3007
3008         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3009
3010                 bool select;
3011
3012                 switch (type) {
3013                         case 0:
3014                                 select = (efa->len < numverts);
3015                                 break;
3016                         case 1:
3017                                 select = (efa->len == numverts);
3018                                 break;
3019                         case 2:
3020                                 select = (efa->len > numverts);
3021                                 break;
3022                         case 3:
3023                                 select = (efa->len != numverts);
3024                                 break;
3025                         default:
3026                                 BLI_assert(0);
3027                                 select = false;
3028                                 break;
3029                 }
3030
3031                 if (select) {
3032                         BM_face_select_set(em->bm, efa, true);
3033                 }
3034         }
3035
3036         EDBM_selectmode_flush(em);
3037
3038         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
3039         return OPERATOR_FINISHED;
3040 }
3041
3042 void MESH_OT_select_face_by_sides(wmOperatorType *ot)
3043 {
3044         static const EnumPropertyItem type_items[] = {
3045                 {0, "LESS", 0, "Less Than", ""},
3046                 {1, "EQUAL", 0, "Equal To", ""},
3047                 {2, "GREATER", 0, "Greater Than", ""},
3048                 {3, "NOTEQUAL", 0, "Not Equal To", ""},
3049                 {0, NULL, 0, NULL, NULL}
3050         };
3051
3052         /* identifiers */
3053         ot->name = "Select Faces by Sides";
3054         ot->description = "Select vertices or faces by the number of polygon sides";
3055         ot->idname = "MESH_OT_select_face_by_sides";
3056
3057         /* api callbacks */
3058         ot->exec = edbm_select_face_by_sides_exec;
3059         ot->poll = ED_operator_editmesh;
3060
3061         /* flags */
3062         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3063
3064         /* properties */
3065         RNA_def_int(ot->srna, "number", 4, 3, INT_MAX, "Number of Vertices", "", 3, INT_MAX);
3066         RNA_def_enum(ot->srna, "type", type_items, 1, "Type", "Type of comparison to make");
3067         RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection");
3068 }
3069
3070 /** \} */
3071
3072 /* -------------------------------------------------------------------- */
3073 /** \name Select Loose Operator
3074  * \{ */
3075
3076 static int edbm_select_loose_exec(bContext *C, wmOperator *op)
3077 {
3078         Object *obedit = CTX_data_edit_object(C);
3079         BMEditMesh *em = BKE_editmesh_from_object(obedit);
3080         BMesh *bm = em->bm;
3081         BMIter iter;
3082
3083         if (!RNA_boolean_get(op->ptr, "extend"))
3084                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
3085
3086         if (em->selectmode & SCE_SELECT_VERTEX) {
3087                 BMVert *eve;
3088                 BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
3089                         if (!eve->e) {
3090                                 BM_vert_select_set(bm, eve, true);
3091                         }
3092                 }
3093         }
3094
3095         if (em->selectmode & SCE_SELECT_EDGE) {
3096                 BMEdge *eed;
3097                 BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
3098                         if (BM_edge_is_wire(eed)) {
3099                                 BM_edge_select_set(bm, eed, true);
3100                         }
3101                 }
3102         }
3103
3104         if (em->selectmode & SCE_SELECT_FACE) {
3105                 BMFace *efa;
3106                 BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
3107                         BMIter liter;
3108                         BMLoop *l;
3109                         bool is_loose = true;
3110                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3111                                 if (!BM_edge_is_boundary(l->e)) {
3112                                         is_loose = false;
3113                                         break;
3114                                 }
3115                         }
3116                         if (is_loose) {
3117                                 BM_face_select_set(bm, efa, true);
3118                         }
3119                 }
3120         }
3121
3122         EDBM_selectmode_flush(em);
3123
3124         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
3125         return OPERATOR_FINISHED;
3126 }
3127
3128 void MESH_OT_select_loose(wmOperatorType *ot)
3129 {
3130         /* identifiers */
3131         ot->name = "Select Loose Geometry";
3132         ot->description = "Select loose geometry based on the selection mode";
3133         ot->idname = "MESH_OT_select_loose";
3134
3135         /* api callbacks */
3136         ot->exec = edbm_select_loose_exec;
3137         ot->poll = ED_operator_editmesh;
3138
3139         /* flags */
3140         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3141
3142         /* props */
3143         RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
3144 }
3145
3146 /** \} */
3147
3148 /* -------------------------------------------------------------------- */
3149 /** \name Select Mirror Operator
3150  * \{ */
3151
3152 static int edbm_select_mirror_exec(bContext *C, wmOperator *op)
3153 {
3154         Object *obedit = CTX_data_edit_object(C);
3155         BMEditMesh *em = BKE_editmesh_from_object(obedit);
3156         const int axis_flag = RNA_enum_get(op->ptr, "axis");
3157         const bool extend = RNA_boolean_get(op->ptr, "extend");
3158
3159         if (em->bm->totvert && em->bm->totvertsel) {
3160                 int totmirr, totfail;
3161
3162                 for (int axis = 0; axis < 3; axis++) {
3163                         if ((1 << axis) & axis_flag) {
3164                                 EDBM_select_mirrored(em, axis, extend, &totmirr, &totfail);
3165                         }
3166                 }
3167
3168                 if (totmirr) {
3169                         EDBM_selectmode_flush(em);
3170                         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
3171                 }
3172
3173                 ED_mesh_report_mirror_ex(op, totmirr, totfail, em->bm->selectmode);
3174         }
3175
3176         return OPERATOR_FINISHED;
3177 }
3178
3179 void MESH_OT_select_mirror(wmOperatorType *ot)
3180 {
3181         /* identifiers */
3182         ot->name = "Select Mirror";
3183         ot->description = "Select mesh items at mirrored locations";
3184         ot->idname = "MESH_OT_select_mirror";
3185
3186         /* api callbacks */
3187         ot->exec = edbm_select_mirror_exec;
3188         ot->poll = ED_operator_editmesh;
3189
3190         /* flags */
3191         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3192
3193         /* props */
3194         RNA_def_enum_flag(ot->srna, "axis", rna_enum_axis_flag_xyz_items, (1 << 0), "Axis", "");
3195
3196         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection");
3197 }
3198
3199 /** \} */
3200
3201 /* -------------------------------------------------------------------- */
3202 /** \name Select More Operator
3203  * \{ */
3204
3205 static int edbm_select_more_exec(bContext *C, wmOperator *op)
3206 {
3207         Object *obedit = CTX_data_edit_object(C);
3208         BMEditMesh *em = BKE_editmesh_from_object(obedit);
3209         const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
3210
3211         EDBM_select_more(em, use_face_step);
3212
3213         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
3214         return OPERATOR_FINISHED;
3215 }
3216
3217 void MESH_OT_select_more(wmOperatorType *ot)
3218 {
3219         /* identifiers */
3220         ot->name = "Select More";
3221         ot->idname = "MESH_OT_select_more";
3222         ot->description = "Select more vertices, edges or faces connected to initial selection";
3223
3224         /* api callbacks */
3225         ot->exec = edbm_select_more_exec;
3226         ot->poll = ED_operator_editmesh;
3227
3228         /* flags */
3229         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3230
3231         RNA_def_boolean(ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)");
3232 }
3233
3234 /** \} */
3235
3236 /* -------------------------------------------------------------------- */
3237 /** \name Select More Operator
3238  * \{ */
3239
3240 static int edbm_select_less_exec(bContext *C, wmOperator *op)
3241 {
3242         Object *obedit = CTX_data_edit_object(C);
3243         BMEditMesh *em = BKE_editmesh_from_object(obedit);
3244         const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
3245
3246         EDBM_select_less(em, use_face_step);
3247
3248         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
3249         return OPERATOR_FINISHED;
3250 }
3251
3252 void MESH_OT_select_less(wmOperatorType *ot)
3253 {
3254         /* identifiers */
3255         ot->name = "Select Less";
3256         ot->idname = "MESH_OT_select_less";
3257         ot->description = "Deselect vertices, edges or faces at the boundary of each selection region";
3258
3259         /* api callbacks */
3260         ot->exec = edbm_select_less_exec;
3261         ot->poll = ED_operator_editmesh;
3262
3263         /* flags */
3264         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3265
3266         RNA_def_boolean(ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)");
3267 }
3268
3269 /** \} */
3270
3271 /* -------------------------------------------------------------------- */
3272 /** \name Select N'th Operator
3273  * \{ */
3274
3275 /**
3276  * Check if we're connected to another selected efge.
3277  */
3278 static bool bm_edge_is_select_isolated(BMEdge *e)
3279 {
3280         BMIter viter;
3281         BMVert *v;
3282
3283         BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) {
3284                 BMIter eiter;
3285                 BMEdge *e_other;
3286
3287                 BM_ITER_ELEM (e_other, &eiter, v, BM_EDGES_OF_VERT) {
3288                         if ((e_other != e) && BM_elem_flag_test(e_other, BM_ELEM_SELECT)) {
3289                                 return false;
3290                         }
3291                 }
3292         }
3293         return true;
3294 }
3295
3296 /* Walk all reachable elements of the same type as h_act in breadth-first
3297  * order, starting from h_act. Deselects elements if the depth when they
3298  * are reached is not a multiple of "nth". */
3299 static void walker_deselect_nth(
3300         BMEditMesh *em, const struct CheckerIntervalParams *op_params,
3301         BMHeader *h_act)
3302 {
3303         BMElem *ele;
3304         BMesh *bm = em->bm;
3305         BMWalker walker;
3306         BMIter iter;
3307         int walktype = 0, itertype = 0, flushtype = 0;
3308         short mask_vert = 0, mask_edge = 0, mask_face = 0;
3309
3310         /* No active element from which to start - nothing to do */
3311         if (h_act == NULL) {
3312                 return;
3313         }
3314
3315         /* Determine which type of iter, walker, and select flush to use
3316          * based on type of the elements being deselected */
3317         switch (h_act->htype) {
3318                 case BM_VERT:
3319                         itertype = BM_VERTS_OF_MESH;
3320                         walktype = BMW_CONNECTED_VERTEX;
3321                         flushtype = SCE_SELECT_VERTEX;
3322                         mask_vert = BMO_ELE_TAG;
3323                         break;
3324                 case BM_EDGE:
3325                         /* When an edge has no connected-selected edges,
3326                          * use face-stepping (supports edge-rings) */
3327                         itertype = BM_EDGES_OF_MESH;
3328                         walktype = bm_edge_is_select_isolated((BMEdge *)h_act) ? BMW_FACE_SHELL : BMW_VERT_SHELL;
3329                         flushtype = SCE_SELECT_EDGE;
3330                         mask_edge = BMO_ELE_TAG;
3331                         break;
3332                 case BM_FACE:
3333                         itertype = BM_FACES_OF_MESH;
3334                         walktype = BMW_ISLAND;
3335                         flushtype = SCE_SELECT_FACE;
3336                         mask_face = BMO_ELE_TAG;
3337                         break;
3338         }
3339
3340         /* grr, shouldn't need to alloc BMO flags here */
3341         BM_mesh_elem_toolflags_ensure(bm);
3342
3343         /* Walker restrictions uses BMO flags, not header flags,
3344          * so transfer BM_ELEM_SELECT from HFlags onto a BMO flag layer. */
3345         BMO_push(bm, NULL);
3346         BM_ITER_MESH (ele, &iter, bm, itertype) {
3347                 if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
3348                         BMO_elem_flag_enable(bm, (BMElemF *)ele, BMO_ELE_TAG);
3349                 }
3350         }
3351
3352         /* Walk over selected elements starting at active */
3353         BMW_init(&walker, bm, walktype,
3354                  mask_vert, mask_edge, mask_face,
3355                  BMW_FLAG_NOP, /* don't use BMW_FLAG_TEST_HIDDEN here since we want to desel all */
3356                  BMW_NIL_LAY);
3357
3358         /* use tag to avoid touching the same verts twice */
3359         BM_ITER_MESH (ele, &iter, bm, itertype) {
3360                 BM_elem_flag_disable(ele, BM_ELEM_TAG);
3361         }
3362
3363         BLI_assert(walker.order == BMW_BREADTH_FIRST);
3364         for (ele = BMW_begin(&walker, h_act); ele != NULL; ele = BMW_step(&walker)) {
3365                 if (!BM_elem_flag_test(ele, BM_ELEM_TAG)) {
3366                         /* Deselect elements that aren't at "nth" depth from active */
3367                         const int depth = BMW_current_depth(&walker) - 1;
3368                         if (WM_operator_properties_checker_interval_test(op_params, depth)) {
3369                                 BM_elem_select_set(bm, ele, false);
3370                         }
3371                         BM_elem_flag_enable(ele, BM_ELEM_TAG);
3372                 }
3373         }
3374         BMW_end(&walker);
3375
3376         BMO_pop(bm);
3377
3378         /* Flush selection up */
3379         EDBM_selectmode_flush_ex(em, flushtype);
3380 }
3381
3382 static void deselect_nth_active(BMEditMesh *em, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
3383 {
3384         BMIter iter;
3385         BMElem *ele;
3386
3387         *r_eve = NULL;
3388         *r_eed = NULL;
3389         *r_efa = NULL;
3390
3391         EDBM_selectmode_flush(em);
3392         ele = BM_mesh_active_elem_get(em->bm);
3393
3394         if (ele && BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
3395                 switch (ele->head.htype) {
3396                         case BM_VERT:
3397                                 *r_eve = (BMVert *)ele;
3398                                 return;
3399                         case BM_EDGE:
3400                                 *r_eed = (BMEdge *)ele;
3401                                 return;
3402                         case BM_FACE:
3403                                 *r_efa = (BMFace *)ele;
3404                                 return;
3405                 }
3406         }
3407
3408         if (em->selectmode & SCE_SELECT_VERTEX) {
3409                 BMVert *v;
3410                 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
3411                         if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
3412                                 *r_eve = v;
3413                                 return;
3414                         }
3415                 }
3416         }
3417         else if (em->selectmode & SCE_SELECT_EDGE) {
3418                 BMEdge *e;
3419                 BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
3420                         if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
3421                                 *r_eed = e;
3422                                 return;
3423                         }
3424                 }
3425         }
3426         else if (em->selectmode & SCE_SELECT_FACE) {
3427                 BMFace *f = BM_mesh_active_face_get(em->bm, true, false);
3428                 if (f && BM_elem_flag_test(f, BM_ELEM_SELECT)) {
3429                         *r_efa = f;
3430                         return;
3431                 }
3432         }
3433 }
3434
3435 static bool edbm_deselect_nth(BMEditMesh *em, const struct CheckerIntervalParams *op_params)
3436 {
3437         BMVert *v;
3438         BMEdge *e;
3439         BMFace *f;
3440
3441         deselect_nth_active(em, &v, &e, &f);
3442
3443         if (v) {
3444                 walker_deselect_nth(em, op_params, &v->head);
3445                 return true;
3446         }
3447         else if (e) {
3448                 walker_deselect_nth(em, op_params, &e->head);
3449                 return true;
3450         }
3451         else if (f) {
3452                 walker_deselect_nth(em, op_params, &f->head);
3453                 return true;
3454         }
3455
3456         return false;
3457 }
3458
3459 static int edbm_select_nth_exec(bContext *C, wmOperator *op)
3460 {
3461         Object *obedit = CTX_data_edit_object(C);
3462         BMEditMesh *em = BKE_editmesh_from_object(obedit);
3463         struct CheckerIntervalParams op_params;
3464
3465         WM_operator_properties_checker_interval_from_op(op, &op_params);
3466
3467         if (edbm_deselect_nth(em, &op_params) == false) {
3468                 BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face");
3469                 return OPERATOR_CANCELLED;
3470         }
3471
3472         EDBM_update_generic(em, false, false);
3473
3474         return OPERATOR_FINISHED;
3475 }
3476
3477
3478 void MESH_OT_select_nth(wmOperatorType *ot)
3479 {
3480         /* identifiers */
3481         ot->name = "Checker Deselect";
3482         ot->idname = "MESH_OT_select_nth";
3483         ot->description = "Deselect every Nth element starting from the active vertex, edge or face";
3484
3485         /* api callbacks */
3486         ot->exec = edbm_select_nth_exec;
3487         ot->poll = ED_operator_editmesh;
3488
3489         /* flags */
3490         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3491
3492         WM_operator_properties_checker_interval(ot, false);
3493 }
3494
3495 void em_setup_viewcontext(bContext *C, ViewContext *vc)
3496 {
3497         ED_view3d_viewcontext_init(C, vc);
3498
3499         if (vc->obedit) {
3500                 vc->em = BKE_editmesh_from_object(vc->obedit);
3501         }
3502 }
3503
3504 /** \} */
3505
3506 /* -------------------------------------------------------------------- */
3507 /** \name Select Sharp Edges Operator
3508  * \{ */
3509
3510 static int edbm_select_sharp_edges_exec(bContext *C, wmOperator *op)
3511 {
3512         /* Find edges that have exactly two neighboring faces,
3513          * check the angle between those faces, and if angle is
3514          * small enough, select the edge
3515          */
3516         Object *obedit = CTX_data_edit_object(C);
3517         BMEditMesh *em = BKE_editmesh_from_object(obedit);
3518         BMIter iter;
3519         BMEdge *e;
3520         BMLoop *l1, *l2;
3521         const float angle_limit_cos = cosf(RNA_float_get(op->ptr, "sharpness"));
3522
3523         BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
3524                 if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false &&
3525                     BM_edge_loop_pair(e, &l1, &l2))
3526                 {
3527                         /* edge has exactly two neighboring faces, check angle */
3528                         const float angle_cos = dot_v3v3(l1->f->no, l2->f->no);
3529
3530                         if (angle_cos < angle_limit_cos) {
3531                                 BM_edge_select_set(em->bm, e, true);
3532                         }
3533                 }
3534         }
3535
3536         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
3537
3538         return OPERATOR_FINISHED;
3539 }
3540
3541 void MESH_OT_edges_select_sharp(wmOperatorType *ot)
3542 {
3543         PropertyRNA *prop;
3544
3545         /* identifiers */
3546         ot->name = "Select Sharp Edges";
3547         ot->description = "Select all sharp-enough edges";
3548         ot->idname = "MESH_OT_edges_select_sharp";
3549
3550         /* api callbacks */