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