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