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