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