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