svn merge ^/trunk/blender -r43693:43733
[blender.git] / source / blender / editors / mesh / bmesh_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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 /*
29
30 BMEditMesh_mods.c, UI level access, no geometry changes 
31
32 */
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <math.h>
37
38 #include "MEM_guardedalloc.h"
39
40 #include "DNA_mesh_types.h"
41 #include "DNA_material_types.h"
42 #include "DNA_meshdata_types.h"
43 #include "DNA_modifier_types.h"
44 #include "DNA_object_types.h"
45 #include "DNA_texture_types.h"
46 #include "DNA_scene_types.h"
47 #include "DNA_screen_types.h"
48 #include "DNA_space_types.h"
49 #include "DNA_view3d_types.h"
50
51 #include "BLI_utildefines.h"
52 #include "BLI_blenlib.h"
53 #include "BLI_math.h"
54 #include "BLI_rand.h"
55 #include "BLI_array.h"
56 #include "BLI_smallhash.h"
57 #include "BLI_heap.h"
58
59 #include "BKE_context.h"
60 #include "BKE_displist.h"
61 #include "BKE_depsgraph.h"
62 #include "BKE_DerivedMesh.h"
63 #include "BKE_customdata.h"
64 #include "BKE_global.h"
65 #include "BKE_mesh.h"
66 #include "BKE_material.h"
67 #include "BKE_texture.h"
68 #include "BKE_report.h"
69 #include "BKE_tessmesh.h"
70 #include "BKE_paint.h"
71
72 #include "IMB_imbuf_types.h"
73 #include "IMB_imbuf.h"
74
75 #include "RE_render_ext.h"  /* externtex */
76
77 #include "WM_api.h"
78 #include "WM_types.h"
79
80 #include "RNA_access.h"
81 #include "RNA_define.h"
82
83 #include "ED_mesh.h"
84 #include "ED_screen.h"
85 #include "ED_view3d.h"
86 #include "bmesh.h"
87
88 #include "BIF_gl.h"
89 #include "BIF_glutil.h"
90
91 #include "UI_resources.h"
92
93 #include "mesh_intern.h"
94
95 #include "BLO_sys_types.h" // for intptr_t support
96
97 /* ****************************** MIRROR **************** */
98
99 static void EDBM_select_mirrored(Object *obedit, BMEditMesh *em)
100 {
101         if(em->selectmode & SCE_SELECT_VERTEX) {
102                 BMVert *eve, *v1;
103                 BMIter iter;
104                 int i;
105
106                 i= 0;
107                 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
108                         if (BM_TestHFlag(eve, BM_SELECT) && !BM_TestHFlag(eve, BM_HIDDEN)) {
109                                 v1= editbmesh_get_x_mirror_vert(obedit, em, eve, eve->co, i);
110                                 if(v1) {
111                                         BM_Select(em->bm, eve, FALSE);
112                                         BM_Select(em->bm, v1, TRUE);
113                                 }
114                         }
115                         i++;
116                 }
117         }
118 }
119
120 void EDBM_automerge(Scene *scene, Object *obedit, int update)
121 {
122         BMEditMesh *em;
123         
124         if ((scene->toolsettings->automerge) &&
125             (obedit && obedit->type==OB_MESH))
126         {
127                 em = ((Mesh*)obedit->data)->edit_btmesh;
128                 if (!em)
129                         return;
130
131                 BMO_CallOpf(em->bm, "automerge verts=%hv dist=%f", BM_SELECT, scene->toolsettings->doublimit);
132                 if (update) {
133                         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
134                 }
135         }
136 }
137
138 /* ****************************** SELECTION ROUTINES **************** */
139
140 unsigned int bm_solidoffs=0, bm_wireoffs=0, bm_vertoffs=0;      /* set in drawobject.c ... for colorindices */
141
142 /* facilities for border select and circle select */
143 static char *selbuf= NULL;
144
145 /* opengl doesn't support concave... */
146 static void draw_triangulated(int mcords[][2], short tot)
147 {
148         ListBase lb={NULL, NULL};
149         DispList *dl;
150         float *fp;
151         int a;
152         
153         /* make displist */
154         dl= MEM_callocN(sizeof(DispList), "poly disp");
155         dl->type= DL_POLY;
156         dl->parts= 1;
157         dl->nr= tot;
158         dl->verts= fp=  MEM_callocN(tot*3*sizeof(float), "poly verts");
159         BLI_addtail(&lb, dl);
160         
161         for(a=0; a<tot; a++, fp+=3) {
162                 fp[0]= (float)mcords[a][0];
163                 fp[1]= (float)mcords[a][1];
164         }
165         
166         /* do the fill */
167         filldisplist(&lb, &lb, 0);
168
169         /* do the draw */
170         dl= lb.first;   /* filldisplist adds in head of list */
171         if(dl->type==DL_INDEX3) {
172                 int *index;
173                 
174                 a= dl->parts;
175                 fp= dl->verts;
176                 index= dl->index;
177                 glBegin(GL_TRIANGLES);
178                 while(a--) {
179                         glVertex3fv(fp+3*index[0]);
180                         glVertex3fv(fp+3*index[1]);
181                         glVertex3fv(fp+3*index[2]);
182                         index+= 3;
183                 }
184                 glEnd();
185         }
186         
187         freedisplist(&lb);
188 }
189
190
191 /* reads rect, and builds selection array for quick lookup */
192 /* returns if all is OK */
193 int EDBM_init_backbuf_border(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
194 {
195         struct ImBuf *buf;
196         unsigned int *dr;
197         int a;
198         
199         if(vc->obedit==NULL || vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
200         
201         buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
202         if(buf==NULL) return 0;
203         if(bm_vertoffs==0) return 0;
204
205         dr = buf->rect;
206         
207         /* build selection lookup */
208         selbuf= MEM_callocN(bm_vertoffs+1, "selbuf");
209         
210         a= (xmax-xmin+1)*(ymax-ymin+1);
211         while(a--) {
212                 if(*dr>0 && *dr<=bm_vertoffs) 
213                         selbuf[*dr]= 1;
214                 dr++;
215         }
216         IMB_freeImBuf(buf);
217         return 1;
218 }
219
220 int EDBM_check_backbuf(unsigned int index)
221 {
222         if(selbuf==NULL) return 1;
223         if(index>0 && index<=bm_vertoffs)
224                 return selbuf[index];
225         return 0;
226 }
227
228 void EDBM_free_backbuf(void)
229 {
230         if(selbuf) MEM_freeN(selbuf);
231         selbuf= NULL;
232 }
233
234 /* mcords is a polygon mask
235    - grab backbuffer,
236    - draw with black in backbuffer, 
237    - grab again and compare
238    returns 'OK' 
239 */
240 int EDBM_mask_init_backbuf_border(ViewContext *vc, int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
241 {
242         unsigned int *dr, *drm;
243         struct ImBuf *buf, *bufmask;
244         int a;
245         
246         /* method in use for face selecting too */
247         if(vc->obedit==NULL) {
248                 if(paint_facesel_test(vc->obact));
249                 else if(paint_vertsel_test(vc->obact));
250                 else return 0;
251         }
252         else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
253
254         buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
255         if(buf==NULL) return 0;
256         if(bm_vertoffs==0) return 0;
257
258         dr = buf->rect;
259
260         /* draw the mask */
261         glDisable(GL_DEPTH_TEST);
262         
263         glColor3ub(0, 0, 0);
264         
265         /* yah, opengl doesn't do concave... tsk! */
266         ED_region_pixelspace(vc->ar);
267         draw_triangulated(mcords, tot); 
268         
269         glBegin(GL_LINE_LOOP);  /* for zero sized masks, lines */
270         for(a=0; a<tot; a++) glVertex2iv(mcords[a]);
271         glEnd();
272         
273         glFinish();     /* to be sure readpixels sees mask */
274         
275         /* grab mask */
276         bufmask= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
277         drm = bufmask->rect;
278         if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */
279         
280         /* build selection lookup */
281         selbuf= MEM_callocN(bm_vertoffs+1, "selbuf");
282         
283         a= (xmax-xmin+1)*(ymax-ymin+1);
284         while(a--) {
285                 if(*dr>0 && *dr<=bm_vertoffs && *drm==0) selbuf[*dr]= 1;
286                 dr++; drm++;
287         }
288         IMB_freeImBuf(buf);
289         IMB_freeImBuf(bufmask);
290         return 1;
291         
292 }
293
294 /* circle shaped sample area */
295 int EDBM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads)
296 {
297         struct ImBuf *buf;
298         unsigned int *dr;
299         short xmin, ymin, xmax, ymax, xc, yc;
300         int radsq;
301         
302         /* method in use for face selecting too */
303         if(vc->obedit==NULL) {
304                 if(paint_facesel_test(vc->obact));
305                 else if(paint_vertsel_test(vc->obact));
306                 else return 0;
307         }
308         else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
309         
310         xmin= xs-rads; xmax= xs+rads;
311         ymin= ys-rads; ymax= ys+rads;
312         buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
313         if(bm_vertoffs==0) return 0;
314         if(buf==NULL) return 0;
315
316         dr = buf->rect;
317         
318         /* build selection lookup */
319         selbuf= MEM_callocN(bm_vertoffs+1, "selbuf");
320         radsq= rads*rads;
321         for(yc= -rads; yc<=rads; yc++) {
322                 for(xc= -rads; xc<=rads; xc++, dr++) {
323                         if(xc*xc + yc*yc < radsq) {
324                                 if(*dr>0 && *dr<=bm_vertoffs) selbuf[*dr]= 1;
325                         }
326                 }
327         }
328
329         IMB_freeImBuf(buf);
330         return 1;
331         
332 }
333
334 static void findnearestvert__doClosest(void *userData, BMVert *eve, int x, int y, int index)
335 {
336         struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; BMVert *closest; } *data = userData;
337
338         if (data->pass==0) {
339                 if (index<=data->lastIndex)
340                         return;
341         } else {
342                 if (index>data->lastIndex)
343                         return;
344         }
345
346         if (data->dist>3) {
347                 int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y);
348                 if (BM_TestHFlag(eve, BM_SELECT) == data->select) {
349                         if (data->strict == 1)
350                                 return;
351                         else
352                                 temp += 5;
353                 }
354
355                 if (temp<data->dist) {
356                         data->dist = temp;
357                         data->closest = eve;
358                         data->closestIndex = index;
359                 }
360         }
361 }
362
363
364
365
366 static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index)
367 {
368         BMEditMesh *em= (BMEditMesh *)handle;
369         BMVert *eve = BM_Vert_AtIndex(em->bm, index-1);
370
371         if(eve && BM_TestHFlag(eve, BM_SELECT)) return 0;
372         return 1; 
373 }
374 /**
375  * findnearestvert
376  * 
377  * dist (in/out): minimal distance to the nearest and at the end, actual distance
378  * sel: selection bias
379  *              if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
380  *              if 0, unselected vertice are given the bias
381  * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased 
382  */
383 BMVert *EDBM_findnearestvert(ViewContext *vc, int *dist, short sel, short strict)
384 {
385         if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
386                 int distance;
387                 unsigned int index;
388                 BMVert *eve;
389                 
390                 if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance, strict, vc->em, findnearestvert__backbufIndextest); 
391                 else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance, 0, NULL, NULL); 
392                 
393                 eve = BM_Vert_AtIndex(vc->em->bm, index-1);
394                 
395                 if(eve && distance < *dist) {
396                         *dist = distance;
397                         return eve;
398                 } else {
399                         return NULL;
400                 }
401                         
402         }
403         else {
404                 struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; BMVert *closest; } data;
405                 static int lastSelectedIndex=0;
406                 static BMVert *lastSelected=NULL;
407                 
408                 if (lastSelected && BM_Vert_AtIndex(vc->em->bm, lastSelectedIndex) != lastSelected) {
409                         lastSelectedIndex = 0;
410                         lastSelected = NULL;
411                 }
412
413                 data.lastIndex = lastSelectedIndex;
414                 data.mval[0] = vc->mval[0];
415                 data.mval[1] = vc->mval[1];
416                 data.select = sel;
417                 data.dist = *dist;
418                 data.strict = strict;
419                 data.closest = NULL;
420                 data.closestIndex = 0;
421
422                 data.pass = 0;
423
424                 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
425
426                 mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, V3D_CLIP_TEST_RV3D_CLIPPING);
427
428                 if (data.dist>3) {
429                         data.pass = 1;
430                         mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, V3D_CLIP_TEST_RV3D_CLIPPING);
431                 }
432
433                 *dist = data.dist;
434                 lastSelected = data.closest;
435                 lastSelectedIndex = data.closestIndex;
436
437                 return data.closest;
438         }
439 }
440
441 /* returns labda for closest distance v1 to line-piece v2-v3 */
442 float labda_PdistVL2Dfl(const float v1[3], const float v2[3], const float v3[3])
443 {
444         float rc[2], len;
445         
446         rc[0]= v3[0]-v2[0];
447         rc[1]= v3[1]-v2[1];
448         len= rc[0]*rc[0]+ rc[1]*rc[1];
449         if(len==0.0f)
450                 return 0.0f;
451         
452         return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
453 }
454
455 /* note; uses v3d, so needs active 3d window */
456 static void findnearestedge__doClosest(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int UNUSED(index))
457 {
458         struct { ViewContext vc; float mval[2]; int dist; BMEdge *closest; } *data = userData;
459         float v1[2], v2[2];
460         int distance;
461                 
462         v1[0] = x0;
463         v1[1] = y0;
464         v2[0] = x1;
465         v2[1] = y1;
466                 
467         distance= dist_to_line_segment_v2(data->mval, v1, v2);
468                 
469         if(BM_TestHFlag(eed, BM_SELECT)) distance+=5;
470         if(distance < data->dist) {
471                 if(data->vc.rv3d->rflag & RV3D_CLIPPING) {
472                         float labda= labda_PdistVL2Dfl(data->mval, v1, v2);
473                         float vec[3];
474
475                         vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]);
476                         vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]);
477                         vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]);
478                         mul_m4_v3(data->vc.obedit->obmat, vec);
479
480                         if(ED_view3d_test_clipping(data->vc.rv3d, vec, 1)==0) {
481                                 data->dist = distance;
482                                 data->closest = eed;
483                         }
484                 }
485                 else {
486                         data->dist = distance;
487                         data->closest = eed;
488                 }
489         }
490 }
491 BMEdge *EDBM_findnearestedge(ViewContext *vc, int *dist)
492 {
493
494         if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
495                 int distance;
496                 unsigned int index;
497                 BMEdge *eed;
498                 
499                 view3d_validate_backbuf(vc);
500                 
501                 index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_solidoffs, bm_wireoffs, &distance,0, NULL, NULL);
502                 eed = BM_Edge_AtIndex(vc->em->bm, index-1);
503                 
504                 if (eed && distance<*dist) {
505                         *dist = distance;
506                         return eed;
507                 } else {
508                         return NULL;
509                 }
510         }
511         else {
512                 struct { ViewContext vc; float mval[2]; int dist; BMEdge *closest; } data;
513
514                 data.vc= *vc;
515                 data.mval[0] = vc->mval[0];
516                 data.mval[1] = vc->mval[1];
517                 data.dist = *dist;
518                 data.closest = NULL;
519                 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
520
521                 mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, 2);
522
523                 *dist = data.dist;
524                 return data.closest;
525         }
526 }
527
528 static void findnearestface__getDistance(void *userData, BMFace *efa, int x, int y, int UNUSED(index))
529 {
530         struct { short mval[2]; int dist; BMFace *toFace; } *data = userData;
531
532         if (efa==data->toFace) {
533                 int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
534
535                 if (temp<data->dist)
536                         data->dist = temp;
537         }
538 }
539 static void findnearestface__doClosest(void *userData, BMFace *efa, int x, int y, int index)
540 {
541         struct { short mval[2], pass; int dist, lastIndex, closestIndex; BMFace *closest; } *data = userData;
542
543         if (data->pass==0) {
544                 if (index<=data->lastIndex)
545                         return;
546         } else {
547                 if (index>data->lastIndex)
548                         return;
549         }
550
551         if (data->dist>3) {
552                 int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
553
554                 if (temp<data->dist) {
555                         data->dist = temp;
556                         data->closest = efa;
557                         data->closestIndex = index;
558                 }
559         }
560 }
561
562 BMFace *EDBM_findnearestface(ViewContext *vc, int *dist)
563 {
564
565         if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
566                 unsigned int index;
567                 BMFace *efa;
568
569                 view3d_validate_backbuf(vc);
570
571                 index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]);
572                 efa = BM_Face_AtIndex(vc->em->bm, index-1);
573                 
574                 if (efa) {
575                         struct { short mval[2]; int dist; BMFace *toFace; } data;
576
577                         data.mval[0] = vc->mval[0];
578                         data.mval[1] = vc->mval[1];
579                         data.dist = 0x7FFF;             /* largest short */
580                         data.toFace = efa;
581
582                         mesh_foreachScreenFace(vc, findnearestface__getDistance, &data);
583
584                         if(vc->em->selectmode == SCE_SELECT_FACE || data.dist<*dist) {  /* only faces, no dist check */
585                                 *dist= data.dist;
586                                 return efa;
587                         }
588                 }
589                 
590                 return NULL;
591         }
592         else {
593                 struct { short mval[2], pass; int dist, lastIndex, closestIndex; BMFace *closest; } data;
594                 static int lastSelectedIndex=0;
595                 static BMFace *lastSelected=NULL;
596
597                 if (lastSelected && BM_Face_AtIndex(vc->em->bm, lastSelectedIndex) != lastSelected) {
598                         lastSelectedIndex = 0;
599                         lastSelected = NULL;
600                 }
601
602                 data.lastIndex = lastSelectedIndex;
603                 data.mval[0] = vc->mval[0];
604                 data.mval[1] = vc->mval[1];
605                 data.dist = *dist;
606                 data.closest = NULL;
607                 data.closestIndex = 0;
608                 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
609
610                 data.pass = 0;
611                 mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
612
613                 if (data.dist>3) {
614                         data.pass = 1;
615                         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
616                         mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
617                 }
618
619                 *dist = data.dist;
620                 lastSelected = data.closest;
621                 lastSelectedIndex = data.closestIndex;
622
623                 return data.closest;
624         }
625 }
626
627 /* best distance based on screen coords. 
628    use em->selectmode to define how to use 
629    selected vertices and edges get disadvantage
630    return 1 if found one
631 */
632 static int unified_findnearest(ViewContext *vc, BMVert **eve, BMEdge **eed, BMFace **efa) 
633 {
634         BMEditMesh *em= vc->em;
635         int dist= 75;
636         
637         *eve= NULL;
638         *eed= NULL;
639         *efa= NULL;
640         
641         /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
642         view3d_validate_backbuf(vc);
643         
644         if(em->selectmode & SCE_SELECT_VERTEX)
645                 *eve= EDBM_findnearestvert(vc, &dist, BM_SELECT, 0);
646         if(em->selectmode & SCE_SELECT_FACE)
647                 *efa= EDBM_findnearestface(vc, &dist);
648
649         dist-= 20;      /* since edges select lines, we give dots advantage of 20 pix */
650         if(em->selectmode & SCE_SELECT_EDGE)
651                 *eed= EDBM_findnearestedge(vc, &dist);
652
653         /* return only one of 3 pointers, for frontbuffer redraws */
654         if(*eed) {
655                 *efa= NULL; *eve= NULL;
656         }
657         else if(*efa) {
658                 *eve= NULL;
659         }
660         
661         return (*eve || *eed || *efa);
662 }
663
664 /* ****************  SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
665
666 static EnumPropertyItem prop_similar_types[] = {
667         {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""},
668         {SIMVERT_FACE, "FACE", 0, "Amount of Adjacent Faces", ""},
669         {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""},
670
671         {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""},
672         {SIMEDGE_DIR, "DIR", 0, "Direction", ""},
673         {SIMEDGE_FACE, "FACE", 0, "Amount of Faces Around an Edge", ""},
674         {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""},
675         {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""},
676         {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
677         {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
678
679         {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
680         {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
681         {SIMFACE_AREA, "AREA", 0, "Area", ""},
682         {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
683         {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
684         {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
685
686         {0, NULL, 0, NULL, NULL}
687 };
688
689 /* selects new faces/edges/verts based on the existing selection */
690
691 static int similar_face_select_exec(bContext *C, wmOperator *op)
692 {
693         Object *ob = CTX_data_edit_object(C);
694         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
695         BMOperator bmop;
696
697         /* get the type from RNA */
698         int type = RNA_enum_get(op->ptr, "type");
699
700         float thresh = CTX_data_tool_settings(C)->select_thresh;
701
702         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
703         EDBM_InitOpf(em, &bmop, op, "similarfaces faces=%hf type=%d thresh=%f", BM_SELECT, type, thresh);
704
705         /* execute the operator */
706         BMO_Exec_Op(em->bm, &bmop);
707
708         /* clear the existing selection */
709         EDBM_clear_flag_all(em, BM_SELECT);
710
711         /* select the output */
712         BMO_HeaderFlag_Buffer(em->bm, &bmop, "faceout", BM_SELECT, BM_ALL);
713
714         /* finish the operator */
715         if( !EDBM_FinishOp(em, &bmop, op, 1) )
716                 return OPERATOR_CANCELLED;
717
718         /* dependencies graph and notification stuff */
719         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
720         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
721
722         /* we succeeded */
723         return OPERATOR_FINISHED;
724 }       
725
726 /* ***************************************************** */
727
728 /* EDGE GROUP */
729
730 /* wrap the above function but do selection flushing edge to face */
731 static int similar_edge_select_exec(bContext *C, wmOperator *op)
732 {
733         Object *ob = CTX_data_edit_object(C);
734         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
735         BMOperator bmop;
736
737         /* get the type from RNA */
738         int type = RNA_enum_get(op->ptr, "type");
739
740         float thresh = CTX_data_tool_settings(C)->select_thresh;
741
742         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
743         EDBM_InitOpf(em, &bmop, op, "similaredges edges=%he type=%d thresh=%f", BM_SELECT, type, thresh);
744
745         /* execute the operator */
746         BMO_Exec_Op(em->bm, &bmop);
747
748         /* clear the existing selection */
749         EDBM_clear_flag_all(em, BM_SELECT);
750
751         /* select the output */
752         BMO_HeaderFlag_Buffer(em->bm, &bmop, "edgeout", BM_SELECT, BM_ALL);
753         EDBM_selectmode_flush(em);
754
755         /* finish the operator */
756         if( !EDBM_FinishOp(em, &bmop, op, 1) )
757                 return OPERATOR_CANCELLED;
758
759         /* dependencies graph and notification stuff */
760         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
761         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
762
763         /* we succeeded */
764         return OPERATOR_FINISHED;
765 }
766
767 /* ********************************* */
768
769 /*
770 VERT GROUP
771  mode 1: same normal
772  mode 2: same number of face users
773  mode 3: same vertex groups
774 */
775
776
777 static int similar_vert_select_exec(bContext *C, wmOperator *op)
778 {
779         Object *ob = CTX_data_edit_object(C);
780         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
781         BMOperator bmop;
782         /* get the type from RNA */
783         int type = RNA_enum_get(op->ptr, "type");
784         float thresh = CTX_data_tool_settings(C)->select_thresh;
785
786         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
787         EDBM_InitOpf(em, &bmop, op, "similarverts verts=%hv type=%d thresh=%f", BM_SELECT, type, thresh);
788
789         /* execute the operator */
790         BMO_Exec_Op(em->bm, &bmop);
791
792         /* clear the existing selection */
793         EDBM_clear_flag_all(em, BM_SELECT);
794
795         /* select the output */
796         BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT, BM_ALL);
797
798         /* finish the operator */
799         if( !EDBM_FinishOp(em, &bmop, op, 1) )
800                 return OPERATOR_CANCELLED;
801
802         EDBM_selectmode_flush(em);
803
804         /* dependencies graph and notification stuff */
805         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
806         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
807
808         /* we succeeded */
809         return OPERATOR_FINISHED;
810 }
811
812 static int select_similar_exec(bContext *C, wmOperator *op)
813 {
814         int type= RNA_enum_get(op->ptr, "type");
815
816         if(type < 100)
817                 return similar_vert_select_exec(C, op);
818         else if(type < 200)
819                 return similar_edge_select_exec(C, op);
820         else
821                 return similar_face_select_exec(C, op);
822 }
823
824 static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
825 {
826         Object *obedit = CTX_data_edit_object(C);
827
828         if(obedit && obedit->type == OB_MESH) {
829                 EnumPropertyItem *item= NULL;
830                 int a, totitem= 0;
831                 BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; 
832
833                 if(em->selectmode & SCE_SELECT_VERTEX) {
834                         for (a=SIMVERT_NORMAL; a<SIMEDGE_LENGTH; a++) {
835                                 RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
836                         }
837                 } else if(em->selectmode & SCE_SELECT_EDGE) {
838                         for (a=SIMEDGE_LENGTH; a<SIMFACE_MATERIAL; a++) {
839                                 RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
840                         }
841                 } else if(em->selectmode & SCE_SELECT_FACE) {
842                         for (a=SIMFACE_MATERIAL; a<=SIMFACE_COPLANAR; a++) {
843                                 RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
844                         }
845                 }
846                 RNA_enum_item_end(&item, &totitem);
847
848                 *free= 1;
849
850                 return item;
851         }
852         
853         return NULL;
854 }
855
856 void MESH_OT_select_similar(wmOperatorType *ot)
857 {
858         PropertyRNA *prop;
859
860         /* identifiers */
861         ot->name= "Select Similar";
862         ot->idname= "MESH_OT_select_similar";
863         
864         /* api callbacks */
865         ot->invoke= WM_menu_invoke;
866         ot->exec= select_similar_exec;
867         ot->poll= ED_operator_editmesh;
868         ot->description= "Select similar vertices, edges or faces by property types";
869         
870         /* flags */
871         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
872         
873         /* properties */
874         prop= ot->prop= RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", "");
875         RNA_def_enum_funcs(prop, select_similar_type_itemf);
876 }
877
878 /* ***************************************************** */
879
880 /* ****************  LOOP SELECTS *************** */
881
882 static void walker_select(BMEditMesh *em, int walkercode, void *start, int select)
883 {
884         BMesh *bm = em->bm;
885         BMHeader *h;
886         BMWalker walker;
887
888         BMW_Init(&walker, bm, walkercode, 0,0,0,0, BMW_NIL_LAY);
889         h = BMW_Begin(&walker, start);
890         for (; h; h=BMW_Step(&walker)) {
891                 if (!select)
892                         BM_remove_selection(bm, h);
893                 BM_Select(bm, h, select);
894         }
895         BMW_End(&walker);
896 }
897
898 static int loop_multiselect(bContext *C, wmOperator *op)
899 {
900         Object *obedit= CTX_data_edit_object(C);
901         BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
902         BMEdge *eed;
903         BMEdge **edarray;
904         int edindex;
905         int looptype= RNA_boolean_get(op->ptr, "ring");
906         
907         BMIter iter;
908         int totedgesel = 0;
909
910         for(eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
911             eed; eed = BMIter_Step(&iter)) {
912
913                 if(BM_TestHFlag(eed, BM_SELECT)) {
914                         totedgesel++;
915                 }
916         }
917
918         
919         edarray = MEM_mallocN(sizeof(BMEdge*)*totedgesel,"edge array");
920         edindex = 0;
921         
922         for(eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
923             eed; eed = BMIter_Step(&iter)) {
924
925                 if(BM_TestHFlag(eed, BM_SELECT)) {
926                         edarray[edindex] = eed;
927                         edindex++;
928                 }
929         }
930         
931         if(looptype) {
932                 for(edindex = 0; edindex < totedgesel; edindex +=1) {
933                         eed = edarray[edindex];
934                         walker_select(em, BMW_EDGERING, eed, 1);
935                 }
936                 EDBM_selectmode_flush(em);
937         }
938         else{
939                 for(edindex = 0; edindex < totedgesel; edindex +=1) {
940                         eed = edarray[edindex];
941                         walker_select(em, BMW_LOOP, eed, 1);
942                 }
943                 EDBM_selectmode_flush(em);
944         }
945         MEM_freeN(edarray);
946 //      if (EM_texFaceCheck())
947         
948         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
949
950         return OPERATOR_FINISHED;       
951 }
952
953 void MESH_OT_loop_multi_select(wmOperatorType *ot)
954 {
955         /* identifiers */
956         ot->name= "Multi Select Loops";
957         ot->idname= "MESH_OT_loop_multi_select";
958         
959         /* api callbacks */
960         ot->exec= loop_multiselect;
961         ot->poll= ED_operator_editmesh;
962         ot->description= "Select a loop of connected edges by connection type";
963         
964         /* flags */
965         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
966         
967         /* properties */
968         RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
969 }
970
971                 
972 /* ***************** MAIN MOUSE SELECTION ************** */
973
974
975 /* ***************** loop select (non modal) ************** */
976
977 static void mouse_mesh_loop(bContext *C, int mval[2], short extend, short ring)
978 {
979         ViewContext vc;
980         BMEditMesh *em;
981         BMEdge *eed;
982         int select= 1;
983         int dist = 50;
984         
985         em_setup_viewcontext(C, &vc);
986         vc.mval[0]= mval[0];
987         vc.mval[1]= mval[1];
988         em= vc.em;
989         
990         /* no afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad */
991         view3d_validate_backbuf(&vc);
992
993         eed = EDBM_findnearestedge(&vc, &dist);
994         if (eed) {
995                 if(extend==0) EDBM_clear_flag_all(em, BM_SELECT);
996         
997                 if (BM_TestHFlag(eed, BM_SELECT)==0) {
998                         select=1;
999                 }
1000                 else if (extend) {
1001                         select=0;
1002                 }
1003
1004                 if(em->selectmode & SCE_SELECT_FACE) {
1005                         walker_select(em, BMW_FACELOOP, eed, select);
1006                 }
1007                 else if(em->selectmode & SCE_SELECT_EDGE) {
1008                         if(ring)
1009                                 walker_select(em, BMW_EDGERING, eed, select);
1010                         else
1011                                 walker_select(em, BMW_LOOP, eed, select);
1012                 }
1013                 else if(em->selectmode & SCE_SELECT_VERTEX) {
1014                         if(ring)
1015                                 walker_select(em, BMW_EDGERING, eed, select);
1016
1017                         else
1018                                 walker_select(em, BMW_LOOP, eed, select);
1019                 }
1020
1021                 EDBM_selectmode_flush(em);
1022 //                      if (EM_texFaceCheck())
1023                 
1024                 /* sets as active, useful for other tools */
1025                 if (select) {
1026                         if (em->selectmode & SCE_SELECT_VERTEX) {
1027                                 /* TODO: would be nice if the edge vertex chosen here
1028                                    was the one closer to the selection pointer, instead
1029                                    of arbitrarily selecting the first one */
1030                                 EDBM_store_selection(em, eed->v1);
1031                         }
1032                         else if(em->selectmode & SCE_SELECT_EDGE) {
1033                                 EDBM_store_selection(em, eed);
1034                         }
1035                         /* TODO: would be nice if the nearest face that
1036                            belongs to the selected edge could be set to
1037                            active here in face select mode */
1038                 }
1039
1040                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit);
1041         }
1042 }
1043
1044 static int mesh_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
1045 {
1046         
1047         view3d_operator_needs_opengl(C);
1048         
1049         mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"),
1050                                         RNA_boolean_get(op->ptr, "ring"));
1051         
1052         /* cannot do tweaks for as long this keymap is after transform map */
1053         return OPERATOR_FINISHED;
1054 }
1055
1056 void MESH_OT_loop_select(wmOperatorType *ot)
1057 {
1058         /* identifiers */
1059         ot->name= "Loop Select";
1060         ot->idname= "MESH_OT_loop_select";
1061         ot->description= "Select a loop";
1062         
1063         /* api callbacks */
1064         ot->invoke= mesh_select_loop_invoke;
1065         ot->poll= ED_operator_editmesh_region_view3d;
1066         ot->description= "Select a loop of connected edges";
1067         
1068         /* flags */
1069         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1070         
1071         /* properties */
1072         RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "Extend the selection");
1073         RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "Select ring");
1074 }
1075
1076 void MESH_OT_edgering_select (wmOperatorType *ot)
1077 {
1078         /* description */
1079         ot->name= "Edge Ring Select";
1080         ot->idname= "MESH_OT_edgering_select";
1081         ot->description= "Select an edge ring";
1082         
1083         /* callbacks */
1084         ot->invoke= mesh_select_loop_invoke;
1085         ot->poll= ED_operator_editmesh_region_view3d;
1086         
1087         /* flags */
1088         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1089
1090         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
1091         RNA_def_boolean(ot->srna, "ring", 1, "Select Ring", "Select ring");
1092 }
1093
1094 /* ******************* edgetag_shortest_path and helpers ****************** */
1095
1096 static float edgetag_cut_cost(BMEditMesh *UNUSED(em), BMEdge *e1, BMEdge *e2, BMVert* v)
1097 {
1098         BMVert *v1 = (e1->v1 == v) ? e1->v2 : e1->v1;
1099         BMVert *v2 = (e2->v1 == v) ? e2->v2 : e2->v1;
1100         float cost, d1[3], d2[3];
1101
1102         /*The cost is based on the simple sum of the length of the two edgees...*/
1103         sub_v3_v3v3(d1, v->co, v1->co);
1104         sub_v3_v3v3(d2, v2->co, v->co);
1105         cost = len_v3(d1);
1106         cost += len_v3(d2);
1107
1108         /*...but is biased to give higher values to sharp turns, so that it will take
1109           paths with fewer "turns" when selecting between equal-weighted paths between
1110           the two edges*/
1111         cost = cost + 0.5f*cost*(2.0f - sqrt(fabs(dot_v3v3(d1, d2))));
1112
1113         return cost;
1114 }
1115
1116 static void edgetag_add_adjacent(BMEditMesh *em, SmallHash *visithash, Heap *heap, int mednum, int vertnum, 
1117                                                                  int *nedges, int *edges, int *prevedge, float *cost)
1118 {
1119         BMEdge *e1 = EDBM_get_edge_for_index(em, mednum);
1120         BMVert *v = EDBM_get_vert_for_index(em, vertnum);
1121         int startadj, endadj = nedges[vertnum+1];
1122
1123         for (startadj = nedges[vertnum]; startadj < endadj; startadj++) {
1124                 int adjnum = edges[startadj];
1125                 BMEdge *e2 = EDBM_get_edge_for_index(em, adjnum);
1126                 float newcost;
1127                 float cutcost;
1128
1129                 if (BLI_smallhash_haskey(visithash, (uintptr_t)e2))
1130                         continue;
1131
1132                 cutcost = edgetag_cut_cost(em, e1, e2, v);
1133                 newcost = cost[mednum] + cutcost;
1134
1135                 if (cost[adjnum] > newcost) {
1136                         cost[adjnum] = newcost;
1137                         prevedge[adjnum] = mednum;
1138                         BLI_heap_insert(heap, newcost, SET_INT_IN_POINTER(adjnum));
1139                 }
1140         }
1141 }
1142
1143 static void edgetag_context_set(BMEditMesh *em, Scene *scene, BMEdge *e, int val)
1144 {
1145         
1146         switch (scene->toolsettings->edge_mode) {
1147         case EDGE_MODE_SELECT:
1148                 BM_Select(em->bm, e, val);
1149                 break;
1150         case EDGE_MODE_TAG_SEAM:
1151                 if (val)                {BM_SetHFlag(e, BM_SEAM);}
1152                 else                    {BM_ClearHFlag(e, BM_SEAM);}
1153                 break;
1154         case EDGE_MODE_TAG_SHARP:
1155                 if (val)                {BM_SetHFlag(e, BM_SEAM);}
1156                 else                    {BM_ClearHFlag(e, BM_SEAM);}
1157                 break;                          
1158         case EDGE_MODE_TAG_CREASE:
1159          {
1160                 float *crease = CustomData_bmesh_get(&em->bm->edata, e->head.data, CD_CREASE);
1161                 
1162                 if (val)                {*crease = 1.0f;}
1163                 else                    {*crease = 0.0f;}
1164                 break;
1165          }
1166         case EDGE_MODE_TAG_BEVEL:
1167          {
1168                 float *bweight = CustomData_bmesh_get(&em->bm->edata, e->head.data, CD_BWEIGHT);
1169
1170                 if (val)                {*bweight = 1.0f;}
1171                 else                    {*bweight = 0.0f;}
1172                 break;
1173          }
1174         }
1175 }
1176
1177 static int edgetag_context_check(Scene *scene, BMEditMesh *em, BMEdge *e)
1178 {
1179         switch (scene->toolsettings->edge_mode) {
1180         case EDGE_MODE_SELECT:
1181                 return BM_TestHFlag(e, BM_SELECT) ? 1 : 0;
1182         case EDGE_MODE_TAG_SEAM:
1183                 return BM_TestHFlag(e, BM_SEAM);
1184         case EDGE_MODE_TAG_SHARP:
1185                 return BM_TestHFlag(e, BM_SHARP);
1186         case EDGE_MODE_TAG_CREASE:      
1187                 return BM_GetCDf(&em->bm->edata, e, CD_CREASE) ? 1 : 0;
1188         case EDGE_MODE_TAG_BEVEL:
1189                 return BM_GetCDf(&em->bm->edata, e, CD_BWEIGHT) ? 1 : 0;
1190         }
1191         return 0;
1192 }
1193
1194 static int edgetag_shortest_path(Scene *scene, BMEditMesh *em, BMEdge *source, BMEdge *target)
1195 {
1196         BMEdge *e;
1197         BMIter iter;
1198         Heap *heap;
1199         SmallHash visithash;
1200         float *cost;
1201         int i, totvert=0, totedge=0, *nedges, *edges, *prevedge, mednum = -1, nedgeswap = 0;
1202         int targetnum;
1203
1204         BLI_smallhash_init(&visithash);
1205
1206         /* note, would pass BM_EDGE except we are looping over all edges anyway */
1207         BM_ElemIndex_Ensure(em->bm, BM_VERT /* | BM_EDGE */ );
1208
1209         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
1210                 e->head.flags[0].f = 0;
1211                 if (BM_TestHFlag(e, BM_HIDDEN)) {
1212                         BLI_smallhash_insert(&visithash, (uintptr_t)e, NULL);
1213                 }
1214
1215                 BM_SetIndex(e, totedge); /* set_inline */
1216                 totedge++;
1217         }
1218         em->bm->elem_index_dirty &= ~BM_EDGE;
1219
1220         /* alloc */
1221         totvert = em->bm->totvert;
1222         nedges = MEM_callocN(sizeof(*nedges)*totvert+1, "SeamPathNEdges");
1223         edges = MEM_mallocN(sizeof(*edges)*totedge*2, "SeamPathEdges");
1224         prevedge = MEM_mallocN(sizeof(*prevedge)*totedge, "SeamPathPrevious");
1225         cost = MEM_mallocN(sizeof(*cost)*totedge, "SeamPathCost");
1226
1227         /* count edges, compute adjacent edges offsets and fill adjacent */
1228         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
1229                 nedges[BM_GetIndex(e->v1)+1]++;
1230                 nedges[BM_GetIndex(e->v2)+1]++;
1231         }
1232
1233         for (i = 1; i < totvert; i++) {
1234                 int newswap = nedges[i+1];
1235                 nedges[i+1] = nedgeswap + nedges[i];
1236                 nedgeswap = newswap;
1237         }
1238         nedges[0] = nedges[1] = 0;
1239
1240         i = 0;
1241         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
1242                 edges[nedges[BM_GetIndex(e->v1)+1]++] = i;
1243                 edges[nedges[BM_GetIndex(e->v2)+1]++] = i;
1244
1245                 cost[i] = 1e20f;
1246                 prevedge[i] = -1;
1247                 i++;
1248         }
1249
1250         /*
1251          * Arrays are now filled as follows:
1252          *
1253          *      nedges[n] = sum of the # of edges incident to all vertices numbered 0 thru n-1
1254          *      edges[edges[n]..edges[n-1]] = the indices of of the edges incident to vertex n
1255          *
1256          * As the search continues, prevedge[n] will be the previous edge on the shortest
1257          * path found so far to edge n. The visitedhash will of course contain entries
1258          * for edges that have been visited, cost[n] will contain the length of the shortest
1259          * path to edge n found so far, Finally, heap is a priority heap which is built on the
1260          * the same data as the cost arry, but inverted: it is a worklist of edges prioritized
1261          * by the shortest path found so far to the edge.
1262         */
1263
1264 #if 0 /* UNUSED */ /* this block does nothing, not sure why its here? - campbell */
1265         for (i = 0; i < totvert; i++) {
1266                 int start = nedges[i], end = nedges[i+1], cur;
1267                 for (cur = start; cur < end; cur++) {
1268                         BMEdge* e = EDBM_get_edge_for_index(em, edges[cur]);
1269                 }
1270         }
1271 #endif
1272
1273         /* regular dijkstra shortest path, but over edges instead of vertices */
1274         heap = BLI_heap_new();
1275         BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(BM_GetIndex(source)));
1276         cost[BM_GetIndex(source)] = 0.0f;
1277         EDBM_init_index_arrays(em, 1, 1, 0);
1278         targetnum = BM_GetIndex(target);
1279
1280         while (!BLI_heap_empty(heap)) {
1281                 mednum = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
1282                 e = EDBM_get_edge_for_index(em, mednum);
1283
1284                 if (mednum == targetnum)
1285                         break;
1286
1287                 if (BLI_smallhash_haskey(&visithash, (uintptr_t)e))
1288                         continue;
1289
1290                 BLI_smallhash_insert(&visithash, (uintptr_t)e, NULL);
1291
1292                 edgetag_add_adjacent(em, &visithash, heap, mednum, BM_GetIndex(e->v1), nedges, edges, prevedge, cost);
1293                 edgetag_add_adjacent(em, &visithash, heap, mednum, BM_GetIndex(e->v2), nedges, edges, prevedge, cost);
1294         }
1295         
1296         if (mednum == targetnum) {
1297                 short allseams = 1;
1298
1299                 /*Check whether the path is already completely tagged.
1300                   if it is, the tags will be cleared instead of set.*/
1301                 mednum = targetnum;
1302                 do {
1303                         e = EDBM_get_edge_for_index(em, mednum);
1304                         if (!edgetag_context_check(scene, em, e)) {
1305                                 allseams = 0;
1306                                 break;
1307                         }
1308                         mednum = prevedge[mednum];
1309                 } while (mednum != BM_GetIndex(source));
1310
1311                 /*Follow path back and source and add or remove tags*/
1312                 mednum = targetnum;
1313                 do {
1314                         e = EDBM_get_edge_for_index(em, mednum);
1315                         if (allseams)
1316                                 edgetag_context_set(em, scene, e, 0);
1317                         else
1318                                 edgetag_context_set(em, scene, e, 1);
1319                         mednum = prevedge[mednum];
1320                 } while (mednum != -1);
1321         }
1322
1323         EDBM_free_index_arrays(em);
1324         MEM_freeN(nedges);
1325         MEM_freeN(edges);
1326         MEM_freeN(prevedge);
1327         MEM_freeN(cost);
1328         BLI_heap_free(heap, NULL);
1329         BLI_smallhash_release(&visithash);
1330
1331         return 1;
1332 }
1333
1334 /* ******************* mesh shortest path select, uses prev-selected edge ****************** */
1335
1336 /* since you want to create paths with multiple selects, it doesn't have extend option */
1337 static void mouse_mesh_shortest_path(bContext *C, int mval[2])
1338 {
1339         Object *ob = CTX_data_edit_object(C);
1340         ViewContext vc;
1341         BMEditMesh *em;
1342         BMEdge *e;
1343         int dist= 50;
1344         
1345         em_setup_viewcontext(C, &vc);
1346         vc.mval[0]= mval[0];
1347         vc.mval[1]= mval[1];
1348         em= vc.em;
1349         
1350         e= EDBM_findnearestedge(&vc, &dist);
1351         if(e) {
1352                 Mesh *me= vc.obedit->data;
1353                 int path = 0;
1354                 
1355                 if (em->bm->selected.last) {
1356                         BMEditSelection *ese= em->bm->selected.last;
1357                         
1358                         if(ese && ese->htype == BM_EDGE) {
1359                                 BMEdge *e_act;
1360                                 e_act = (BMEdge *)ese->data;
1361                                 if (e_act != e) {
1362                                         if (edgetag_shortest_path(vc.scene, em, e_act, e)) {
1363                                                 EDBM_remove_selection(em, e_act);
1364                                                 path = 1;
1365                                         }
1366                                 }
1367                         }
1368                 }
1369                 if (path==0) {
1370                         int act = (edgetag_context_check(vc.scene, em, e)==0);
1371                         edgetag_context_set(em, vc.scene, e, act); /* switch the edge option */
1372                 }
1373                 
1374                 EDBM_selectmode_flush(em);
1375
1376                 /* even if this is selected it may not be in the selection list */
1377                 if(edgetag_context_check(vc.scene, em, e)==0)
1378                         EDBM_remove_selection(em, e);
1379                 else
1380                         EDBM_store_selection(em, e);
1381         
1382                 /* force drawmode for mesh */
1383                 switch (CTX_data_tool_settings(C)->edge_mode) {
1384                         
1385                         case EDGE_MODE_TAG_SEAM:
1386                                 me->drawflag |= ME_DRAWSEAMS;
1387                                 break;
1388                         case EDGE_MODE_TAG_SHARP:
1389                                 me->drawflag |= ME_DRAWSHARP;
1390                                 break;
1391                         case EDGE_MODE_TAG_CREASE:      
1392                                 me->drawflag |= ME_DRAWCREASES;
1393                                 break;
1394                         case EDGE_MODE_TAG_BEVEL:
1395                                 me->drawflag |= ME_DRAWBWEIGHTS;
1396                                 break;
1397                 }
1398                 
1399                 DAG_id_tag_update(ob->data, OB_RECALC_DATA);
1400                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
1401         }
1402 }
1403
1404
1405 static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
1406 {
1407         
1408         view3d_operator_needs_opengl(C);
1409
1410         mouse_mesh_shortest_path(C, event->mval);
1411         
1412         return OPERATOR_FINISHED;
1413 }
1414         
1415 void MESH_OT_select_shortest_path(wmOperatorType *ot)
1416 {
1417         /* identifiers */
1418         ot->name= "Shortest Path Select";
1419         ot->idname= "MESH_OT_select_shortest_path";
1420         
1421         /* api callbacks */
1422         ot->invoke= mesh_shortest_path_select_invoke;
1423         ot->poll= ED_operator_editmesh;
1424         ot->description= "Select shortest path between two selections";
1425         
1426         /* flags */
1427         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1428         
1429         /* properties */
1430         RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
1431 }
1432
1433 /* ************************************************** */
1434 /* here actual select happens */
1435 /* gets called via generic mouse select operator */
1436 int mouse_mesh(bContext *C, const int mval[2], short extend)
1437 {
1438         ViewContext vc;
1439         BMVert *eve = NULL;
1440         BMEdge *eed = NULL;
1441         BMFace *efa = NULL;
1442         
1443         /* setup view context for argument to callbacks */
1444         em_setup_viewcontext(C, &vc);
1445         vc.mval[0]= mval[0];
1446         vc.mval[1]= mval[1];
1447         
1448         if(unified_findnearest(&vc, &eve, &eed, &efa)) {
1449                 
1450                 if(extend==0) EDBM_clear_flag_all(vc.em, BM_SELECT);
1451                 
1452                 if(efa) {
1453                         /* set the last selected face */
1454                         BM_set_actFace(vc.em->bm, efa);
1455                         
1456                         if(!BM_TestHFlag(efa, BM_SELECT)) {
1457                                 EDBM_store_selection(vc.em, efa);
1458                                 BM_Select(vc.em->bm, efa, TRUE);
1459                         }
1460                         else if(extend) {
1461                                 EDBM_remove_selection(vc.em, efa);
1462                                 BM_Select(vc.em->bm, efa, FALSE);
1463                         }
1464                 }
1465                 else if(eed) {
1466                         if(!BM_TestHFlag(eed, BM_SELECT)) {
1467                                 EDBM_store_selection(vc.em, eed);
1468                                 BM_Select(vc.em->bm, eed, TRUE);
1469                         }
1470                         else if(extend) {
1471                                 EDBM_remove_selection(vc.em, eed);
1472                                 BM_Select(vc.em->bm, eed, FALSE);
1473                         }
1474                 }
1475                 else if(eve) {
1476                         if(!BM_TestHFlag(eve, BM_SELECT)) {
1477                                 EDBM_store_selection(vc.em, eve);
1478                                 BM_Select(vc.em->bm, eve, TRUE);
1479                         }
1480                         else if(extend) {
1481                                 EDBM_remove_selection(vc.em, eve);
1482                                 BM_Select(vc.em->bm, eve, FALSE);
1483                         }
1484                 }
1485                 
1486                 EDBM_selectmode_flush(vc.em);
1487                   
1488 //              if (EM_texFaceCheck()) {
1489
1490                 if (efa && efa->mat_nr != vc.obedit->actcol-1) {
1491                         vc.obedit->actcol= efa->mat_nr+1;
1492                         vc.em->mat_nr= efa->mat_nr;
1493 //                      BIF_preview_changed(ID_MA);
1494                 }
1495
1496                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit);
1497                 return 1;
1498         }
1499
1500         return 0;
1501 }
1502
1503 static void EDBM_strip_selections(BMEditMesh *em)
1504 {
1505         BMEditSelection *ese, *nextese;
1506
1507         if(!(em->selectmode & SCE_SELECT_VERTEX)) {
1508                 ese = em->bm->selected.first;
1509                 while(ese) {
1510                         nextese = ese->next; 
1511                         if(ese->htype == BM_VERT) BLI_freelinkN(&(em->bm->selected),ese);
1512                         ese = nextese;
1513                 }
1514         }
1515         if(!(em->selectmode & SCE_SELECT_EDGE)) {
1516                 ese=em->bm->selected.first;
1517                 while(ese) {
1518                         nextese = ese->next;
1519                         if(ese->htype == BM_EDGE) BLI_freelinkN(&(em->bm->selected), ese);
1520                         ese = nextese;
1521                 }
1522         }
1523         if(!(em->selectmode & SCE_SELECT_FACE)) {
1524                 ese=em->bm->selected.first;
1525                 while(ese) {
1526                         nextese = ese->next;
1527                         if(ese->htype == BM_FACE) BLI_freelinkN(&(em->bm->selected), ese);
1528                         ese = nextese;
1529                 }
1530         }
1531 }
1532
1533 /* when switching select mode, makes sure selection is consistant for editing */
1534 /* also for paranoia checks to make sure edge or face mode works */
1535 void EDBM_selectmode_set(BMEditMesh *em)
1536 {
1537         BMVert *eve;
1538         BMEdge *eed;
1539         BMFace *efa;
1540         BMIter iter;
1541         
1542         em->bm->selectmode = em->selectmode;
1543
1544         EDBM_strip_selections(em); /*strip BMEditSelections from em->selected that are not relevant to new mode*/
1545         
1546         if(em->selectmode & SCE_SELECT_VERTEX) {
1547                 /*BMIter iter;
1548                 
1549                 eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
1550                 for ( ; eed; eed=BMIter_Step(&iter)) BM_Select(em->bm, eed, FALSE);
1551                 
1552                 efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
1553                 for ( ; efa; efa=BMIter_Step(&iter)) BM_Select(em->bm, efa, FALSE);*/
1554
1555                 EDBM_selectmode_flush(em);
1556         }
1557         else if(em->selectmode & SCE_SELECT_EDGE) {
1558                 /* deselect vertices, and select again based on edge select */
1559                 eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
1560                 for ( ; eve; eve=BMIter_Step(&iter)) BM_Select(em->bm, eve, FALSE);
1561                 
1562                 eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
1563                 for ( ; eed; eed=BMIter_Step(&iter)) {
1564                         if (BM_TestHFlag(eed, BM_SELECT)) {
1565                                 BM_Select(em->bm, eed, TRUE);
1566                         }
1567                 }
1568                 
1569                 /* selects faces based on edge status */
1570                 EDBM_selectmode_flush(em);
1571         }
1572         else if(em->selectmode & SCE_SELECT_FACE) {
1573                 /* deselect eges, and select again based on face select */
1574                 eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
1575                 for ( ; eed; eed=BMIter_Step(&iter)) BM_Select(em->bm, eed, FALSE);
1576                 
1577                 efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
1578                 for ( ; efa; efa=BMIter_Step(&iter)) {
1579                         if (BM_TestHFlag(efa, BM_SELECT)) {
1580                                 BM_Select(em->bm, efa, TRUE);
1581                         }
1582                 }
1583         }
1584 }
1585
1586 void EDBM_convertsel(BMEditMesh *em, short oldmode, short selectmode)
1587 {
1588         BMEdge *eed;
1589         BMFace *efa;
1590         BMIter iter;
1591
1592         /*have to find out what the selectionmode was previously*/
1593         if(oldmode == SCE_SELECT_VERTEX) {
1594                 if(selectmode == SCE_SELECT_EDGE) {
1595                         /*select all edges associated with every selected vertex*/
1596                         eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
1597                         for ( ; eed; eed=BMIter_Step(&iter)) {
1598                                 if ( (BM_TestHFlag(eed->v1, BM_SELECT) ||
1599                                       BM_TestHFlag(eed->v2, BM_SELECT)))
1600                                 {
1601                                         BM_Select(em->bm, eed, TRUE);
1602                                 }
1603                         }
1604                 }               
1605                 else if(selectmode == SCE_SELECT_FACE) {
1606                         BMIter liter;
1607                         BMLoop *l;
1608
1609                         /*select all faces associated with every selected vertex*/
1610                         efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
1611                         for ( ; efa; efa=BMIter_Step(&iter)) {
1612                                 l = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
1613                                 for (; l; l=BMIter_Step(&liter)) {
1614                                         if (BM_TestHFlag(l->v, BM_SELECT)) {
1615                                                 BM_Select(em->bm, efa, TRUE);
1616                                                 break;
1617                                         }
1618                                 }
1619                         }
1620                 }
1621         }
1622         
1623         if(oldmode == SCE_SELECT_EDGE) {
1624                 if(selectmode == SCE_SELECT_FACE) {
1625                         BMIter liter;
1626                         BMLoop *l;
1627
1628                         /*select all faces associated with every selected vertex*/
1629                         efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
1630                         for ( ; efa; efa=BMIter_Step(&iter)) {
1631                                 l = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
1632                                 for (; l; l=BMIter_Step(&liter)) {
1633                                         if (BM_TestHFlag(l->v, BM_SELECT)) {
1634                                                 BM_Select(em->bm, efa, TRUE);
1635                                                 break;
1636                                         }
1637                                 }
1638                         }
1639                 }
1640         }
1641 }
1642
1643
1644 void EDBM_deselect_by_material(struct BMEditMesh *em, const short index, const short select)
1645 {
1646         BMIter iter;
1647         BMFace *efa;
1648
1649         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1650                 if (BM_TestHFlag(efa, BM_HIDDEN))
1651                         continue;
1652                 if(efa->mat_nr == index) {
1653                         BM_Select(em->bm, efa, select);
1654                 }
1655         }
1656 }
1657
1658
1659 void EDBM_select_swap(BMEditMesh *em) /* exported for UV */
1660 {
1661         BMIter iter;
1662         BMVert *eve;
1663         BMEdge *eed;
1664         BMFace *efa;
1665         
1666         if(em->bm->selectmode & SCE_SELECT_VERTEX) {
1667                 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
1668                         if (BM_TestHFlag(eve, BM_HIDDEN))
1669                                 continue;
1670                         BM_Select(em->bm, eve, !BM_TestHFlag(eve, BM_SELECT));
1671                 }
1672         }
1673         else if(em->selectmode & SCE_SELECT_EDGE) {
1674                 BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
1675                         if (BM_TestHFlag(eed, BM_HIDDEN))
1676                                 continue;
1677                         BM_Select(em->bm, eed, !BM_TestHFlag(eed, BM_SELECT));
1678                 }
1679         }
1680         else {
1681                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1682                         if (BM_TestHFlag(efa, BM_HIDDEN))
1683                                 continue;
1684                         BM_Select(em->bm, efa, !BM_TestHFlag(efa, BM_SELECT));
1685                 }
1686
1687         }
1688 //      if (EM_texFaceCheck())
1689 }
1690
1691 static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
1692 {
1693         Object *obedit= CTX_data_edit_object(C);
1694         ViewContext vc;
1695         BMesh *bm;
1696         BMWalker walker;
1697         BMEditMesh *em;
1698         BMVert *eve;
1699         BMEdge *e, *eed;
1700         BMFace *efa;
1701         int sel= !RNA_boolean_get(op->ptr, "deselect");
1702         
1703         /* unified_finednearest needs ogl */
1704         view3d_operator_needs_opengl(C);
1705         
1706         /* setup view context for argument to callbacks */
1707         em_setup_viewcontext(C, &vc);
1708         em = vc.em;
1709
1710         if(em->bm->totedge==0)
1711                 return OPERATOR_CANCELLED;
1712         
1713         bm= em->bm;
1714
1715         vc.mval[0]= event->mval[0];
1716         vc.mval[1]= event->mval[1];
1717         
1718         /* return warning! */
1719
1720         /*if(limit) {
1721                 int retval= select_linked_limited_invoke(&vc, 0, sel);
1722                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1723                 return retval;
1724         }*/
1725         
1726         if( unified_findnearest(&vc, &eve, &eed, &efa)==0 ) {
1727                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1728         
1729                 return OPERATOR_CANCELLED;
1730         }
1731         
1732         if (em->selectmode == SCE_SELECT_FACE) {
1733                 BMIter iter;
1734
1735                 if (efa == NULL)
1736                         return OPERATOR_CANCELLED;
1737
1738                 BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
1739                         if (!BM_TestHFlag(e, BM_SEAM)) BMO_SetFlag(bm, e, BM_SELECT);
1740                         else                           BMO_ClearFlag(bm, e, BM_SELECT); /* is this needed ? */
1741                 }
1742
1743                 /* walk */
1744                 BMW_Init(&walker, bm, BMW_ISLAND,  0,BM_SELECT,0,0,  BMW_NIL_LAY);
1745                 e = BMW_Begin(&walker, efa);
1746                 for (; efa; efa=BMW_Step(&walker)) {
1747                         BM_Select(bm, efa, sel);
1748                 }
1749                 BMW_End(&walker);
1750         }
1751         else {
1752                 if (efa) {
1753                         eed = bm_firstfaceloop(efa)->e;
1754                 } else if (!eed) {
1755                         if (!eve || !eve->e)
1756                                 return OPERATOR_CANCELLED;
1757
1758                         eed = eve->e;
1759                 }
1760
1761                 BMW_Init(&walker, bm, BMW_SHELL, 0,0,0,0, BMW_NIL_LAY);
1762                 e = BMW_Begin(&walker, eed->v1);
1763                 for (; e; e=BMW_Step(&walker)) {
1764                                 BM_Select(bm, e->v1, sel);
1765                                 BM_Select(bm, e->v2, sel);
1766                 }
1767                 BMW_End(&walker);
1768                 EDBM_select_flush(em, SCE_SELECT_VERTEX);
1769         }
1770
1771         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1772         return OPERATOR_FINISHED;       
1773 }
1774
1775 void MESH_OT_select_linked_pick(wmOperatorType *ot)
1776 {
1777         /* identifiers */
1778         ot->name= "Select Linked";
1779         ot->idname= "MESH_OT_select_linked_pick";
1780         
1781         /* api callbacks */
1782         ot->invoke= select_linked_pick_invoke;
1783         ot->poll= ED_operator_editmesh;
1784         ot->description= "select/deselect all vertices linked to the edge under the mouse cursor";
1785         
1786         /* flags */
1787         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1788         
1789         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
1790         RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
1791 }
1792
1793
1794 static int select_linked_exec(bContext *C, wmOperator *UNUSED(op))
1795 {
1796         Object *obedit= CTX_data_edit_object(C);
1797         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
1798         BMesh *bm= em->bm;
1799         BMIter iter;
1800         BMVert *v;
1801         BMEdge *e;
1802         BMWalker walker;
1803
1804         if (em->selectmode == SCE_SELECT_FACE) {
1805                 BMFace *efa;
1806
1807                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1808                         if (BM_TestHFlag(efa, BM_SELECT) && !BM_TestHFlag(efa, BM_HIDDEN)) {
1809                                 BM_SetHFlag(efa, BM_TMP_TAG);
1810                         }
1811                         else {
1812                                 BM_ClearHFlag(efa, BM_TMP_TAG);
1813                         }
1814                 }
1815
1816                 BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
1817                         if (!BM_TestHFlag(e, BM_SEAM)) BMO_SetFlag(bm, e, BM_SELECT);
1818                         else                           BMO_ClearFlag(bm, e, BM_SELECT); /* is this needed ? */
1819                 }
1820
1821                 BMW_Init(&walker, bm, BMW_ISLAND,  0,BM_SELECT,0,0,  BMW_NIL_LAY);
1822                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1823                         if (BM_TestHFlag(efa, BM_TMP_TAG)) {
1824                                 e = BMW_Begin(&walker, efa);
1825                                 for (; efa; efa=BMW_Step(&walker)) {
1826                                         BM_Select(bm, efa, TRUE);
1827                                 }
1828                         }
1829                 }
1830                 BMW_End(&walker);
1831         }
1832         else  {
1833                 BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
1834                         if (BM_TestHFlag(v, BM_SELECT) && !BM_TestHFlag(v, BM_HIDDEN)) {
1835                                 BM_SetHFlag(v, BM_TMP_TAG);
1836                         }
1837                         else {
1838                                 BM_ClearHFlag(v, BM_TMP_TAG);
1839                         }
1840                 }
1841
1842                 BMW_Init(&walker, em->bm, BMW_SHELL, 0,0,0,0, BMW_NIL_LAY);
1843                 BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
1844                         if (BM_TestHFlag(v, BM_TMP_TAG)) {
1845                                 e = BMW_Begin(&walker, v);
1846                                 for (; e; e=BMW_Step(&walker)) {
1847                                         BM_Select(em->bm, e->v1, TRUE);
1848                                         BM_Select(em->bm, e->v2, TRUE);
1849                                 }
1850                         }
1851                 }
1852                 BMW_End(&walker);
1853         }
1854         EDBM_select_flush(em, SCE_SELECT_VERTEX);
1855
1856         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1857
1858         return OPERATOR_FINISHED;       
1859 }
1860
1861 void MESH_OT_select_linked(wmOperatorType *ot)
1862 {
1863         /* identifiers */
1864         ot->name= "Select Linked All";
1865         ot->idname= "MESH_OT_select_linked";
1866         
1867         /* api callbacks */
1868         ot->exec= select_linked_exec;
1869         ot->poll= ED_operator_editmesh;
1870         ot->description= "Select all vertices linked to the active mesh";
1871         
1872         /* flags */
1873         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1874         
1875         RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
1876 }
1877
1878 /* ******************** **************** */
1879
1880 static int select_more(bContext *C, wmOperator *op)
1881 {
1882         Object *obedit= CTX_data_edit_object(C);
1883         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1884         BMOperator bmop;
1885         int usefaces = em->selectmode > SCE_SELECT_EDGE;
1886
1887         EDBM_InitOpf(em, &bmop, op, "regionextend geom=%hvef constrict=%d usefaces=%d", 
1888                      BM_SELECT, 0, usefaces);
1889
1890         BMO_Exec_Op(em->bm, &bmop);
1891         BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL);
1892
1893         EDBM_selectmode_flush(em);
1894
1895         if (!EDBM_FinishOp(em, &bmop, op, 1))
1896                 return OPERATOR_CANCELLED;
1897
1898         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1899         return OPERATOR_FINISHED;
1900 }
1901
1902 void MESH_OT_select_more(wmOperatorType *ot)
1903 {
1904         /* identifiers */
1905         ot->name= "Select More";
1906         ot->idname= "MESH_OT_select_more";
1907         ot->description= "Select more vertices, edges or faces connected to initial selection";
1908
1909         /* api callbacks */
1910         ot->exec= select_more;
1911         ot->poll= ED_operator_editmesh;
1912         
1913         /* flags */
1914         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1915 }
1916
1917 static int select_less(bContext *C, wmOperator *op)
1918 {
1919         Object *obedit= CTX_data_edit_object(C);
1920         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1921         BMOperator bmop;
1922         int usefaces = em->selectmode > SCE_SELECT_EDGE;
1923
1924         EDBM_InitOpf(em, &bmop, op, "regionextend geom=%hvef constrict=%d usefaces=%d", 
1925                      BM_SELECT, 1, usefaces);
1926
1927         BMO_Exec_Op(em->bm, &bmop);
1928         BMO_UnHeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL);
1929
1930         EDBM_selectmode_flush(em);
1931
1932         if (!EDBM_FinishOp(em, &bmop, op, 1))
1933                 return OPERATOR_CANCELLED;
1934
1935         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1936         return OPERATOR_FINISHED;
1937 }
1938
1939 void MESH_OT_select_less(wmOperatorType *ot)
1940 {
1941         /* identifiers */
1942         ot->name= "Select Less";
1943         ot->idname= "MESH_OT_select_less";
1944         ot->description= "Deselect vertices, edges or faces at the boundary of each selection region";
1945
1946         /* api callbacks */
1947         ot->exec= select_less;
1948         ot->poll= ED_operator_editmesh;
1949         
1950         /* flags */
1951         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1952 }
1953
1954 /* Walk all reachable elements of the same type as h_act in breadth-first
1955    order, starting from h_act. Deselects elements if the depth when they
1956    are reached is not a multiple of "nth". */
1957 static void walker_deselect_nth(BMEditMesh *em, int nth, int offset, BMHeader *h_act)
1958 {
1959         BMHeader *h;
1960         BMesh *bm = em->bm;
1961         BMWalker walker;
1962         BMIter iter;
1963         int walktype = 0, itertype = 0, flushtype = 0;
1964         short mask_vert=0, mask_edge=0, mask_loop=0, mask_face=0;
1965
1966         /* No active element from which to start - nothing to do */
1967         if(h_act==NULL) {
1968                 return;
1969         }
1970
1971         /* Determine which type of iter, walker, and select flush to use
1972            based on type of the elements being deselected */
1973         switch (h_act->htype) {
1974         case BM_VERT:
1975                 itertype = BM_VERTS_OF_MESH;
1976                 walktype = BMW_CONNECTED_VERTEX;
1977                 flushtype = SCE_SELECT_VERTEX;
1978                 mask_vert = BM_SELECT;
1979                 break;
1980         case BM_EDGE:
1981                 itertype = BM_EDGES_OF_MESH;
1982                 walktype = BMW_SHELL;
1983                 flushtype = SCE_SELECT_EDGE;
1984                 mask_edge = BM_SELECT;
1985                 break;
1986         case BM_FACE:
1987                 itertype = BM_FACES_OF_MESH;
1988                 walktype = BMW_ISLAND;
1989                 flushtype = SCE_SELECT_FACE;
1990                 mask_face = BM_SELECT;
1991                 break;
1992         }
1993
1994         /* Walker restrictions uses BMO flags, not header flags,
1995            so transfer BM_SELECT from HFlags onto a BMO flag layer. */
1996         BMO_push(bm, NULL);
1997         BM_ITER(h, &iter, bm, itertype, NULL) {
1998                 if (BM_TestHFlag(h, BM_SELECT)) {
1999                         BMO_SetFlag(bm, h, BM_SELECT);
2000                 }
2001         }
2002
2003         /* Walk over selected elements starting at active */
2004         BMW_Init(&walker, bm, walktype,  mask_vert,mask_edge,mask_loop,mask_face,  BMW_NIL_LAY);
2005         BLI_assert(walker.order == BMW_BREADTH_FIRST);
2006         for (h = BMW_Begin(&walker, h_act); h != NULL; h = BMW_Step(&walker)) {
2007                 /* Deselect elements that aren't at "nth" depth from active */
2008                 if ((offset + BMW_CurrentDepth(&walker)) % nth) {
2009                         BM_Select(bm, h, FALSE);
2010                 }
2011         }
2012         BMW_End(&walker);
2013
2014         BMO_pop(bm);
2015
2016         /* Flush selection up */
2017         EDBM_select_flush(em, flushtype);
2018 }
2019
2020 static void deselect_nth_active(BMEditMesh *em, BMVert **v_p, BMEdge **e_p, BMFace **f_p)
2021 {
2022         BMVert *v;
2023         BMEdge *e;
2024         BMFace *f;
2025         BMIter iter;
2026         BMEditSelection *ese;
2027
2028         *v_p= NULL;
2029         *e_p= NULL;
2030         *f_p= NULL;
2031
2032         EDBM_selectmode_flush(em);
2033         ese= (BMEditSelection*)em->bm->selected.last;
2034
2035         if(ese) {
2036                 switch(ese->htype) {
2037                 case BM_VERT:
2038                         *v_p= (BMVert *)ese->data;
2039                         return;
2040                 case BM_EDGE:
2041                         *e_p= (BMEdge *)ese->data;
2042                         return;
2043                 case BM_FACE:
2044                         *f_p= (BMFace *)ese->data;
2045                         return;
2046                 }
2047         }
2048
2049         if(em->selectmode & SCE_SELECT_VERTEX) {
2050                 BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2051                         if (BM_TestHFlag(v, BM_SELECT)) {
2052                                 *v_p = v;
2053                                 return;
2054                         }
2055                 }
2056         }
2057         else if(em->selectmode & SCE_SELECT_EDGE) {
2058                 BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2059                         if (BM_TestHFlag(e, BM_SELECT)) {
2060                                 *e_p = e;
2061                                 return;
2062                         }
2063                 }
2064         }
2065         else if(em->selectmode & SCE_SELECT_FACE) {
2066                 f= BM_get_actFace(em->bm, 1);
2067                 if(f) {
2068                         *f_p= f;
2069                         return;
2070                 }
2071         }
2072 }
2073
2074 static int EM_deselect_nth(BMEditMesh *em, int nth, int offset)
2075 {
2076         BMVert *v;
2077         BMEdge *e;
2078         BMFace *f;
2079
2080         deselect_nth_active(em, &v, &e, &f);
2081
2082         if (v) {
2083                 walker_deselect_nth(em, nth, offset, &v->head);
2084                 return 1;
2085         }
2086         else if(e) {
2087                 walker_deselect_nth(em, nth, offset, &e->head);
2088                 return 1;
2089         }
2090         else if(f) {
2091                 walker_deselect_nth(em, nth, offset, &f->head);
2092                 return 1;
2093         }
2094
2095         return 0;
2096 }
2097
2098 static int mesh_select_nth_exec(bContext *C, wmOperator *op)
2099 {
2100         Object *obedit= CTX_data_edit_object(C);
2101         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2102         int nth= RNA_int_get(op->ptr, "nth");
2103         int offset= RNA_int_get(op->ptr, "offset");
2104
2105         offset = MIN2(nth, offset);
2106
2107         if(EM_deselect_nth(em, nth, offset) == 0) {
2108                 BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face");
2109                 return OPERATOR_CANCELLED;
2110         }
2111
2112         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
2113         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2114
2115         return OPERATOR_FINISHED;
2116 }
2117
2118
2119 void MESH_OT_select_nth(wmOperatorType *ot)
2120 {
2121         /* identifiers */
2122         ot->name= "Select Nth";
2123         ot->description= "";
2124         ot->idname= "MESH_OT_select_nth";
2125
2126         /* api callbacks */
2127         ot->exec= mesh_select_nth_exec;
2128         ot->poll= ED_operator_editmesh;
2129
2130         /* flags */
2131         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2132
2133         RNA_def_int(ot->srna, "nth", 2, 2, 100, "Nth Selection", "", 1, INT_MAX);
2134         RNA_def_int(ot->srna, "offset", 0, 0, 100, "Offset", "", 0, INT_MAX);
2135 }
2136
2137 void em_setup_viewcontext(bContext *C, ViewContext *vc)
2138 {
2139         view3d_set_viewcontext(C, vc);
2140         
2141         if(vc->obedit) {
2142                 Mesh *me= vc->obedit->data;
2143                 vc->em= me->edit_btmesh;
2144         }
2145 }
2146
2147 /* poll call for mesh operators requiring a view3d context */
2148 int EM_view3d_poll(bContext *C)
2149 {
2150         if(ED_operator_editmesh(C) && ED_operator_view3d_active(C))
2151                 return 1;
2152         return 0;
2153 }
2154
2155
2156 static int select_sharp_edges_exec(bContext *C, wmOperator *op)
2157 {
2158         /* Find edges that have exactly two neighboring faces,
2159         * check the angle between those faces, and if angle is
2160         * small enough, select the edge
2161         */
2162         Object *obedit= CTX_data_edit_object(C);
2163         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2164         BMIter iter;
2165         BMEdge *e;
2166         BMLoop *l1, *l2;
2167         float sharp = RNA_float_get(op->ptr, "sharpness"), angle;
2168
2169         sharp = DEG2RADF(sharp);
2170
2171         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2172                 if (BM_TestHFlag(e, BM_HIDDEN) || !e->l)
2173                         continue;
2174
2175                 l1 = e->l;
2176                 l2 = l1->radial_next;
2177
2178                 if (l1 == l2)
2179                         continue;
2180
2181                 /* edge has exactly two neighboring faces, check angle */
2182                 angle = saacos(l1->f->no[0]*l2->f->no[0]+l1->f->no[1]*l2->f->no[1]+l1->f->no[2]*l2->f->no[2]);
2183
2184                 if (fabsf(angle) < sharp) {
2185                         BM_Select(em->bm, e, TRUE);
2186                 }
2187
2188         }
2189
2190         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2191
2192         return OPERATOR_FINISHED;
2193 }
2194
2195 void MESH_OT_edges_select_sharp(wmOperatorType *ot)
2196 {
2197         /* identifiers */
2198         ot->name= "Select Sharp Edges";
2199         ot->description= "Marked selected edges as sharp";
2200         ot->idname= "MESH_OT_edges_select_sharp";
2201         
2202         /* api callbacks */
2203         ot->exec= select_sharp_edges_exec;
2204         ot->poll= ED_operator_editmesh;
2205         
2206         /* flags */
2207         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2208         
2209         /* props */
2210         RNA_def_float(ot->srna, "sharpness", 1.0f, 0.01f, FLT_MAX, "sharpness", "", 1.0f, 180.0f);
2211 }
2212
2213 static int select_linked_flat_faces_exec(bContext *C, wmOperator *op)
2214 {
2215         Object *obedit= CTX_data_edit_object(C);
2216         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2217         BMIter iter, liter, liter2;
2218         BMFace *f, **stack = NULL;
2219         BLI_array_declare(stack);
2220         BMLoop *l, *l2;
2221         float sharp = RNA_float_get(op->ptr, "sharpness");
2222         int i;
2223
2224         sharp = (sharp * M_PI) / 180.0;
2225
2226         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2227                 BM_ClearHFlag(f, BM_TMP_TAG);
2228         }
2229
2230         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2231                 if (BM_TestHFlag(f, BM_HIDDEN) || !BM_TestHFlag(f, BM_SELECT) || BM_TestHFlag(f, BM_TMP_TAG))
2232                         continue;
2233
2234                 BLI_array_empty(stack);
2235                 i = 1;
2236
2237                 BLI_array_growone(stack);
2238                 stack[i-1] = f;
2239
2240                 while (i) {
2241                         f = stack[i-1];
2242                         i--;
2243
2244                         BM_Select(em->bm, f, TRUE);
2245
2246                         BM_SetHFlag(f, BM_TMP_TAG);
2247
2248                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
2249                                 BM_ITER(l2, &liter2, em->bm, BM_LOOPS_OF_LOOP, l) {
2250                                         float angle;
2251
2252                                         if (BM_TestHFlag(l2->f, BM_TMP_TAG) || BM_TestHFlag(l2->f, BM_HIDDEN))
2253                                                 continue;
2254
2255                                         /* edge has exactly two neighboring faces, check angle */
2256                                         angle = saacos(f->no[0]*l2->f->no[0]+f->no[1]*l2->f->no[1]+f->no[2]*l2->f->no[2]);
2257
2258                                         /* invalidate: edge too sharp */
2259                                         if (fabs(angle) < sharp) {
2260                                                 BLI_array_growone(stack);
2261                                                 stack[i] = l2->f;
2262                                                 i++;
2263                                         }
2264                                 }
2265                         }
2266                 }
2267         }
2268
2269         BLI_array_free(stack);
2270
2271         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2272
2273         return OPERATOR_FINISHED;
2274 }
2275
2276 void MESH_OT_faces_select_linked_flat(wmOperatorType *ot)
2277 {
2278         /* identifiers */
2279         ot->name= "Select Linked Flat Faces";
2280         ot->description= "Select linked faces by angle";
2281         ot->idname= "MESH_OT_faces_select_linked_flat";
2282         
2283         /* api callbacks */
2284         ot->exec= select_linked_flat_faces_exec;
2285         ot->poll= ED_operator_editmesh;
2286         
2287         /* flags */
2288         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2289         
2290         /* props */
2291         RNA_def_float(ot->srna, "sharpness", 1.0f, 0.01f, FLT_MAX, "sharpness", "", 1.0f, 180.0f);
2292 }
2293
2294 static int select_non_manifold_exec(bContext *C, wmOperator *op)
2295 {
2296         Object *obedit= CTX_data_edit_object(C);
2297         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2298         BMVert *v;
2299         BMEdge *e;
2300         BMIter iter;
2301
2302         /* Selects isolated verts, and edges that do not have 2 neighboring
2303          * faces
2304          */
2305         
2306         if(em->selectmode==SCE_SELECT_FACE) {
2307                 BKE_report(op->reports, RPT_ERROR, "Doesn't work in face selection mode");
2308                 return OPERATOR_CANCELLED;
2309         }
2310         
2311         BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2312                 if (!BM_TestHFlag(em->bm, BM_HIDDEN) && BM_Nonmanifold_Vert(em->bm, v)) {
2313                         BM_Select(em->bm, v, TRUE);
2314                 }
2315         }
2316         
2317         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2318                 if (!BM_TestHFlag(em->bm, BM_HIDDEN) && BM_Edge_FaceCount(e) != 2) {
2319                         BM_Select(em->bm, e, TRUE);
2320                 }
2321         }
2322
2323         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2324
2325         return OPERATOR_FINISHED;       
2326 }
2327
2328 void MESH_OT_select_non_manifold(wmOperatorType *ot)
2329 {
2330         /* identifiers */
2331         ot->name= "Select Non Manifold";
2332         ot->description= "Select all non-manifold vertices or edges";
2333         ot->idname= "MESH_OT_select_non_manifold";
2334         
2335         /* api callbacks */
2336         ot->exec= select_non_manifold_exec;
2337         ot->poll= ED_operator_editmesh;
2338         
2339         /* flags */
2340         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2341 }
2342
2343 static int mesh_select_random_exec(bContext *C, wmOperator *op)
2344 {
2345         Object *obedit= CTX_data_edit_object(C);
2346         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2347         BMVert *eve;
2348         BMEdge *eed;
2349         BMFace *efa;
2350         BMIter iter;
2351         float randfac =  RNA_float_get(op->ptr, "percent")/100.0f;
2352
2353         BLI_srand( BLI_rand() ); /* random seed */
2354         
2355         if(!RNA_boolean_get(op->ptr, "extend"))
2356                 EDBM_clear_flag_all(em, BM_SELECT);
2357
2358         if(em->selectmode & SCE_SELECT_VERTEX) {
2359                 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2360                         if (!BM_TestHFlag(eve, BM_HIDDEN) && BLI_frand() < randfac) {
2361                                 BM_Select(em->bm, eve, TRUE);
2362                         }
2363                 }
2364                 EDBM_selectmode_flush(em);
2365         }
2366         else if(em->selectmode & SCE_SELECT_EDGE) {
2367                 BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2368                         if (!BM_TestHFlag(eed, BM_HIDDEN) && BLI_frand() < randfac) {
2369                                 BM_Select(em->bm, eed, TRUE);
2370                         }
2371                 }
2372                 EDBM_selectmode_flush(em);
2373         }
2374         else {
2375                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2376                         if (!BM_TestHFlag(efa, BM_HIDDEN) && BLI_frand() < randfac) {
2377                                 BM_Select(em->bm, efa, TRUE);
2378                         }
2379                 }
2380                 EDBM_selectmode_flush(em);
2381         }
2382         
2383         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2384         
2385         return OPERATOR_FINISHED;       
2386 }
2387
2388 void MESH_OT_select_random(wmOperatorType *ot)
2389 {
2390         /* identifiers */
2391         ot->name= "Select Random";
2392         ot->description= "Randomly select vertices";
2393         ot->idname= "MESH_OT_select_random";
2394
2395         /* api callbacks */
2396         ot->exec= mesh_select_random_exec;
2397         ot->poll= ED_operator_editmesh;
2398
2399         /* flags */
2400         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2401         
2402         /* props */
2403         RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of elements to select randomly", 0.f, 100.0f);
2404         RNA_def_boolean(ot->srna, "extend", 0, "Extend Selection", "Extend selection instead of deselecting everything first");
2405 }
2406
2407 static int select_next_loop(bContext *C, wmOperator *UNUSED(op))
2408 {
2409         Object *obedit= CTX_data_edit_object(C);
2410         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
2411         BMFace *f;
2412         BMVert *v;
2413         BMIter iter;
2414         
2415         BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2416                 BM_ClearHFlag(v, BM_TMP_TAG);
2417         }
2418         
2419         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2420                 BMLoop *l;
2421                 BMIter liter;
2422                 
2423                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
2424                         if (BM_TestHFlag(l->v, BM_SELECT) && !BM_TestHFlag(l->v, BM_HIDDEN)) {
2425                                 BM_SetHFlag(l->next->v, BM_TMP_TAG);
2426                                 BM_Select(em->bm, l->v, FALSE);
2427                         }
2428                 }
2429         }
2430
2431         BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2432                 if (BM_TestHFlag(v, BM_TMP_TAG)) {
2433                         BM_Select(em->bm, v, TRUE);
2434                 }
2435         }
2436
2437         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
2438         return OPERATOR_FINISHED;
2439 }
2440
2441 void MESH_OT_select_next_loop(wmOperatorType *ot)
2442 {
2443         /* identifiers */
2444         ot->name= "Select Next Loop";
2445         ot->idname= "MESH_OT_select_next_loop";
2446         ot->description= "";
2447
2448         /* api callbacks */
2449         ot->exec= select_next_loop;
2450         ot->poll= ED_operator_editmesh;
2451         
2452         /* flags */
2453         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2454 }
2455
2456
2457 static int region_to_loop(bContext *C, wmOperator *UNUSED(op))
2458 {
2459         Object *obedit = CTX_data_edit_object(C);
2460         BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
2461         BMFace *f;
2462         BMEdge *e;
2463         BMIter iter;
2464         ViewContext vc;
2465         
2466         em_setup_viewcontext(C, &vc);
2467         
2468         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2469                 BM_ClearHFlag(e, BM_TMP_TAG);
2470         }
2471
2472         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2473                 BMLoop *l1, *l2;
2474                 BMIter liter1, liter2;
2475                 
2476                 BM_ITER(l1, &liter1, em->bm, BM_LOOPS_OF_FACE, f) {
2477                         int tot=0, totsel=0;
2478                         
2479                         BM_ITER(l2, &liter2, em->bm, BM_LOOPS_OF_EDGE, l1->e) {
2480                                 tot++;
2481                                 totsel += BM_TestHFlag(l2->f, BM_SELECT) != 0;
2482                         }
2483                         
2484                         if ((tot != totsel && totsel > 0) || (totsel == 1 && tot == 1))
2485                                 BM_SetHFlag(l1->e, BM_TMP_TAG);
2486                 }
2487         }
2488
2489         EDBM_clear_flag_all(em, BM_SELECT);
2490         
2491         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2492                 if (BM_TestHFlag(e, BM_TMP_TAG) && !BM_TestHFlag(e, BM_HIDDEN))
2493                         BM_Select_Edge(em->bm, e, TRUE);
2494         }
2495
2496         /* If in face-only select mode, switch to edge select mode so that
2497            an edge-only selection is not inconsistent state */
2498         if (em->selectmode == SCE_SELECT_FACE) {
2499                 em->selectmode = SCE_SELECT_EDGE;
2500                 EDBM_selectmode_set(em);
2501                 EDBM_selectmode_to_scene(C);
2502         }
2503
2504         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2505
2506         return OPERATOR_FINISHED;
2507 }
2508
2509 void MESH_OT_region_to_loop(wmOperatorType *ot)
2510 {
2511         /* identifiers */
2512         ot->name= "Select Boundary Loop";
2513         ot->idname= "MESH_OT_region_to_loop";
2514
2515         /* api callbacks */
2516         ot->exec= region_to_loop;
2517         ot->poll= ED_operator_editmesh;
2518
2519         /* flags */
2520         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2521 }
2522
2523 static int loop_find_region(BMEditMesh *em, BMLoop *l, int flag, 
2524         SmallHash *fhash, BMFace ***region_out)
2525 {
2526         BLI_array_declare(region);
2527         BLI_array_declare(stack);
2528         BMFace **region = NULL, *f;
2529         BMFace **stack = NULL;
2530         
2531         BLI_array_append(stack, l->f);
2532         BLI_smallhash_insert(fhash, (uintptr_t)l->f, NULL);
2533         
2534         while (BLI_array_count(stack) > 0) {
2535                 BMIter liter1, liter2;
2536                 BMLoop *l1, *l2;
2537                 
2538                 f = BLI_array_pop(stack);
2539                 BLI_array_append(region, f);
2540                 
2541                 BM_ITER(l1, &liter1, em->bm, BM_LOOPS_OF_FACE, f) {
2542                         if (BM_TestHFlag(l1->e, flag))
2543                                 continue;
2544                         
2545                         BM_ITER(l2, &liter2, em->bm, BM_LOOPS_OF_EDGE, l1->e) {
2546                                 if (BLI_smallhash_haskey(fhash, (uintptr_t)l2->f))
2547                                         continue;
2548                                 
2549                                 BLI_array_append(stack, l2->f);
2550                                 BLI_smallhash_insert(fhash, (uintptr_t)l2->f, NULL);
2551                         }
2552                 }
2553         }
2554         
2555         BLI_array_free(stack);
2556         
2557         *region_out = region;
2558         return BLI_array_count(region);
2559 }
2560
2561 static int verg_radial(const void *va, const void *vb)
2562 {
2563         BMEdge *e1 = *((void**)va);
2564         BMEdge *e2 = *((void**)vb);
2565         int a, b;
2566         
2567         a = BM_Edge_FaceCount(e1);
2568         b = BM_Edge_FaceCount(e2);
2569         
2570         if (a > b) return -1;
2571         if (a == b) return 0;
2572         if (a < b) return 1;
2573         
2574         return -1;
2575 }
2576
2577 static int loop_find_regions(BMEditMesh *em, int selbigger)
2578 {
2579         SmallHash visithash;
2580         BMIter iter;
2581         BMEdge *e, **edges=NULL;
2582         BLI_array_declare(edges);
2583         BMFace *f;
2584         int count = 0, i;
2585         
2586         BLI_smallhash_init(&visithash);
2587         
2588         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2589                 BM_ClearHFlag(f, BM_TMP_TAG);
2590         }
2591
2592         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2593                 if (BM_TestHFlag(e, BM_SELECT)) {
2594                         BLI_array_append(edges, e);
2595                         BM_SetHFlag(e, BM_TMP_TAG);
2596                 } else {
2597                         BM_ClearHFlag(e, BM_TMP_TAG);
2598                 }
2599         }
2600         
2601         /*sort edges by radial cycle length*/
2602         qsort(edges,  BLI_array_count(edges), sizeof(void*), verg_radial);
2603         
2604         for (i=0; i<BLI_array_count(edges); i++) {
2605                 BMIter liter;
2606                 BMLoop *l;
2607                 BMFace **region=NULL, **r;
2608                 int c, tot=0;
2609                 
2610                 e = edges[i];
2611                 
2612                 if (!BM_TestHFlag(e, BM_TMP_TAG))
2613                         continue;
2614                 
2615                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_EDGE, e) {
2616                         if (BLI_smallhash_haskey(&visithash, (uintptr_t)l->f))
2617                                 continue;
2618                                                 
2619                         c = loop_find_region(em, l, BM_SELECT, &visithash, &r);
2620
2621                         if (!region || (selbigger ? c >= tot : c < tot)) {
2622                                 /* this region is the best seen so far */
2623                                 tot = c;
2624                                 if (region) {
2625                                         /* free the previous best */
2626                                         MEM_freeN(region);
2627                                 }
2628                                 /* track the current region as the new best */
2629                                 region = r;
2630                         }
2631                         else {
2632                                 /* this region is not as good as best so far, just free it */
2633                                 MEM_freeN(r);
2634                         }
2635                 }
2636                 
2637                 if (region) {
2638                         int j;
2639                         
2640                         for (j=0; j<tot; j++) {
2641                                 BM_SetHFlag(region[j], BM_TMP_TAG);
2642                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, region[j]) {
2643                                         BM_ClearHFlag(l->e, BM_TMP_TAG);
2644                                 }
2645                         }
2646                         
2647                         count += tot;
2648                         
2649                         MEM_freeN(region);
2650                 }
2651         }
2652         
2653         BLI_array_free(edges);
2654         BLI_smallhash_release(&visithash);
2655         
2656         return count;
2657 }
2658
2659 static int loop_to_region(bContext *C, wmOperator *op)
2660 {
2661         Object *obedit = CTX_data_edit_object(C);
2662         BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
2663         BMIter iter;
2664         BMFace *f;
2665         int selbigger = RNA_boolean_get(op->ptr, "select_bigger");
2666         int a, b;
2667
2668         /*find the set of regions with smallest number of total faces*/
2669         a = loop_find_regions(em, selbigger);
2670         b = loop_find_regions(em, !selbigger);
2671         
2672         if ((a <= b) ^ selbigger) {
2673                 loop_find_regions(em, selbigger);
2674         }
2675         
2676         EDBM_clear_flag_all(em, BM_SELECT);
2677         
2678         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2679                 if (BM_TestHFlag(f, BM_TMP_TAG) && !BM_TestHFlag(f, BM_HIDDEN)) {
2680                         BM_Select_Face(em->bm, f, TRUE);
2681                 }
2682         }
2683         
2684         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2685         return OPERATOR_FINISHED;
2686 }
2687
2688 void MESH_OT_loop_to_region(wmOperatorType *ot)
2689 {
2690         /* identifiers */
2691         ot->name= "Select Loop Inner-Region";
2692         ot->idname= "MESH_OT_loop_to_region";
2693
2694         /* api callbacks */
2695         ot->exec= loop_to_region;
2696         ot->poll= ED_operator_editmesh;
2697
2698         /* flags */
2699         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2700         
2701         RNA_def_boolean(ot->srna, "select_bigger", 0, "Select Bigger", "Select bigger regions instead of smaller ones");
2702 }