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