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