svn merge ^/trunk/blender -r43092:43092
[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_inverse_mesh_exec(bContext *C, wmOperator *UNUSED(op))
1692 {
1693         Object *obedit= CTX_data_edit_object(C);
1694         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1695         
1696         EDBM_select_swap(em);
1697         
1698         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1699
1700         return OPERATOR_FINISHED;       
1701 }
1702
1703 void MESH_OT_select_inverse(wmOperatorType *ot)
1704 {
1705         /* identifiers */
1706         ot->name= "Select Inverse";
1707         ot->idname= "MESH_OT_select_inverse";
1708         ot->description= "Select inverse of (un)selected vertices, edges or faces";
1709         
1710         /* api callbacks */
1711         ot->exec= select_inverse_mesh_exec;
1712         ot->poll= ED_operator_editmesh;
1713         
1714         /* flags */
1715         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1716 }
1717
1718
1719 static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
1720 {
1721         Object *obedit= CTX_data_edit_object(C);
1722         ViewContext vc;
1723         BMesh *bm;
1724         BMWalker walker;
1725         BMEditMesh *em;
1726         BMVert *eve;
1727         BMEdge *e, *eed;
1728         BMFace *efa;
1729         int sel= !RNA_boolean_get(op->ptr, "deselect");
1730         
1731         /* unified_finednearest needs ogl */
1732         view3d_operator_needs_opengl(C);
1733         
1734         /* setup view context for argument to callbacks */
1735         em_setup_viewcontext(C, &vc);
1736         em = vc.em;
1737
1738         if(em->bm->totedge==0)
1739                 return OPERATOR_CANCELLED;
1740         
1741         bm= em->bm;
1742
1743         vc.mval[0]= event->mval[0];
1744         vc.mval[1]= event->mval[1];
1745         
1746         /* return warning! */
1747
1748         /*if(limit) {
1749                 int retval= select_linked_limited_invoke(&vc, 0, sel);
1750                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1751                 return retval;
1752         }*/
1753         
1754         if( unified_findnearest(&vc, &eve, &eed, &efa)==0 ) {
1755                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1756         
1757                 return OPERATOR_CANCELLED;
1758         }
1759         
1760         if (em->selectmode == SCE_SELECT_FACE) {
1761                 BMIter iter;
1762
1763                 if (efa == NULL)
1764                         return OPERATOR_CANCELLED;
1765
1766                 BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
1767                         if (!BM_TestHFlag(e, BM_SEAM)) BMO_SetFlag(bm, e, BM_SELECT);
1768                         else                           BMO_ClearFlag(bm, e, BM_SELECT); /* is this needed ? */
1769                 }
1770
1771                 /* walk */
1772                 BMW_Init(&walker, bm, BMW_ISLAND,  0,BM_SELECT,0,0,  BMW_NIL_LAY);
1773                 e = BMW_Begin(&walker, efa);
1774                 for (; efa; efa=BMW_Step(&walker)) {
1775                         BM_Select(bm, efa, sel);
1776                 }
1777                 BMW_End(&walker);
1778         }
1779         else {
1780                 if (efa) {
1781                         eed = bm_firstfaceloop(efa)->e;
1782                 } else if (!eed) {
1783                         if (!eve || !eve->e)
1784                                 return OPERATOR_CANCELLED;
1785
1786                         eed = eve->e;
1787                 }
1788
1789                 BMW_Init(&walker, bm, BMW_SHELL, 0,0,0,0, BMW_NIL_LAY);
1790                 e = BMW_Begin(&walker, eed->v1);
1791                 for (; e; e=BMW_Step(&walker)) {
1792                                 BM_Select(bm, e->v1, sel);
1793                                 BM_Select(bm, e->v2, sel);
1794                 }
1795                 BMW_End(&walker);
1796                 EDBM_select_flush(em, SCE_SELECT_VERTEX);
1797         }
1798
1799         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1800         return OPERATOR_FINISHED;       
1801 }
1802
1803 void MESH_OT_select_linked_pick(wmOperatorType *ot)
1804 {
1805         /* identifiers */
1806         ot->name= "Select Linked";
1807         ot->idname= "MESH_OT_select_linked_pick";
1808         
1809         /* api callbacks */
1810         ot->invoke= select_linked_pick_invoke;
1811         ot->poll= ED_operator_editmesh;
1812         ot->description= "select/deselect all vertices linked to the edge under the mouse cursor";
1813         
1814         /* flags */
1815         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1816         
1817         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
1818         RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
1819 }
1820
1821
1822 static int select_linked_exec(bContext *C, wmOperator *UNUSED(op))
1823 {
1824         Object *obedit= CTX_data_edit_object(C);
1825         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
1826         BMesh *bm= em->bm;
1827         BMIter iter;
1828         BMVert *v;
1829         BMEdge *e;
1830         BMWalker walker;
1831
1832         if (em->selectmode == SCE_SELECT_FACE) {
1833                 BMFace *efa;
1834
1835                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1836                         if (BM_TestHFlag(efa, BM_SELECT) && !BM_TestHFlag(efa, BM_HIDDEN)) {
1837                                 BM_SetHFlag(efa, BM_TMP_TAG);
1838                         }
1839                         else {
1840                                 BM_ClearHFlag(efa, BM_TMP_TAG);
1841                         }
1842                 }
1843
1844                 BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
1845                         if (!BM_TestHFlag(e, BM_SEAM)) BMO_SetFlag(bm, e, BM_SELECT);
1846                         else                           BMO_ClearFlag(bm, e, BM_SELECT); /* is this needed ? */
1847                 }
1848
1849                 BMW_Init(&walker, bm, BMW_ISLAND,  0,BM_SELECT,0,0,  BMW_NIL_LAY);
1850                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1851                         if (BM_TestHFlag(efa, BM_TMP_TAG)) {
1852                                 e = BMW_Begin(&walker, efa);
1853                                 for (; efa; efa=BMW_Step(&walker)) {
1854                                         BM_Select(bm, efa, TRUE);
1855                                 }
1856                         }
1857                 }
1858                 BMW_End(&walker);
1859         }
1860         else  {
1861                 BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
1862                         if (BM_TestHFlag(v, BM_SELECT) && !BM_TestHFlag(v, BM_HIDDEN)) {
1863                                 BM_SetHFlag(v, BM_TMP_TAG);
1864                         }
1865                         else {
1866                                 BM_ClearHFlag(v, BM_TMP_TAG);
1867                         }
1868                 }
1869
1870                 BMW_Init(&walker, em->bm, BMW_SHELL, 0,0,0,0, BMW_NIL_LAY);
1871                 BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
1872                         if (BM_TestHFlag(v, BM_TMP_TAG)) {
1873                                 e = BMW_Begin(&walker, v);
1874                                 for (; e; e=BMW_Step(&walker)) {
1875                                         BM_Select(em->bm, e->v1, TRUE);
1876                                         BM_Select(em->bm, e->v2, TRUE);
1877                                 }
1878                         }
1879                 }
1880                 BMW_End(&walker);
1881         }
1882         EDBM_select_flush(em, SCE_SELECT_VERTEX);
1883
1884         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1885
1886         return OPERATOR_FINISHED;       
1887 }
1888
1889 void MESH_OT_select_linked(wmOperatorType *ot)
1890 {
1891         /* identifiers */
1892         ot->name= "Select Linked All";
1893         ot->idname= "MESH_OT_select_linked";
1894         
1895         /* api callbacks */
1896         ot->exec= select_linked_exec;
1897         ot->poll= ED_operator_editmesh;
1898         ot->description= "Select all vertices linked to the active mesh";
1899         
1900         /* flags */
1901         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1902         
1903         RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
1904 }
1905
1906 /* ******************** **************** */
1907
1908 static int select_more(bContext *C, wmOperator *op)
1909 {
1910         Object *obedit= CTX_data_edit_object(C);
1911         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1912         BMOperator bmop;
1913         int usefaces = em->selectmode > SCE_SELECT_EDGE;
1914
1915         EDBM_InitOpf(em, &bmop, op, "regionextend geom=%hvef constrict=%d usefaces=%d", 
1916                      BM_SELECT, 0, usefaces);
1917
1918         BMO_Exec_Op(em->bm, &bmop);
1919         BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL);
1920
1921         EDBM_selectmode_flush(em);
1922
1923         if (!EDBM_FinishOp(em, &bmop, op, 1))
1924                 return OPERATOR_CANCELLED;
1925
1926         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1927         return OPERATOR_FINISHED;
1928 }
1929
1930 void MESH_OT_select_more(wmOperatorType *ot)
1931 {
1932         /* identifiers */
1933         ot->name= "Select More";
1934         ot->idname= "MESH_OT_select_more";
1935         ot->description= "Select more vertices, edges or faces connected to initial selection";
1936
1937         /* api callbacks */
1938         ot->exec= select_more;
1939         ot->poll= ED_operator_editmesh;
1940         
1941         /* flags */
1942         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1943 }
1944
1945 static int select_less(bContext *C, wmOperator *op)
1946 {
1947         Object *obedit= CTX_data_edit_object(C);
1948         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1949         BMOperator bmop;
1950         int usefaces = em->selectmode > SCE_SELECT_EDGE;
1951
1952         EDBM_InitOpf(em, &bmop, op, "regionextend geom=%hvef constrict=%d usefaces=%d", 
1953                      BM_SELECT, 1, usefaces);
1954
1955         BMO_Exec_Op(em->bm, &bmop);
1956         BMO_UnHeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL);
1957
1958         EDBM_selectmode_flush(em);
1959
1960         if (!EDBM_FinishOp(em, &bmop, op, 1))
1961                 return OPERATOR_CANCELLED;
1962
1963         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1964         return OPERATOR_FINISHED;
1965 }
1966
1967 void MESH_OT_select_less(wmOperatorType *ot)
1968 {
1969         /* identifiers */
1970         ot->name= "Select Less";
1971         ot->idname= "MESH_OT_select_less";
1972         ot->description= "Deselect vertices, edges or faces at the boundary of each selection region";
1973
1974         /* api callbacks */
1975         ot->exec= select_less;
1976         ot->poll= ED_operator_editmesh;
1977         
1978         /* flags */
1979         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1980 }
1981
1982 /* Walk all reachable elements of the same type as h_act in breadth-first
1983    order, starting from h_act. Deselects elements if the depth when they
1984    are reached is not a multiple of "nth". */
1985 static void walker_deselect_nth(BMEditMesh *em, int nth, int offset, BMHeader *h_act)
1986 {
1987         BMHeader *h;
1988         BMesh *bm = em->bm;
1989         BMWalker walker;
1990         BMIter iter;
1991         int walktype = 0, itertype = 0, flushtype = 0;
1992         short mask_vert=0, mask_edge=0, mask_loop=0, mask_face=0;
1993
1994         /* No active element from which to start - nothing to do */
1995         if(h_act==NULL) {
1996                 return;
1997         }
1998
1999         /* Determine which type of iter, walker, and select flush to use
2000            based on type of the elements being deselected */
2001         switch (h_act->htype) {
2002         case BM_VERT:
2003                 itertype = BM_VERTS_OF_MESH;
2004                 walktype = BMW_CONNECTED_VERTEX;
2005                 flushtype = SCE_SELECT_VERTEX;
2006                 mask_vert = BM_SELECT;
2007                 break;
2008         case BM_EDGE:
2009                 itertype = BM_EDGES_OF_MESH;
2010                 walktype = BMW_SHELL;
2011                 flushtype = SCE_SELECT_EDGE;
2012                 mask_edge = BM_SELECT;
2013                 break;
2014         case BM_FACE:
2015                 itertype = BM_FACES_OF_MESH;
2016                 walktype = BMW_ISLAND;
2017                 flushtype = SCE_SELECT_FACE;
2018                 mask_face = BM_SELECT;
2019                 break;
2020         }
2021
2022         /* Walker restrictions uses BMO flags, not header flags,
2023            so transfer BM_SELECT from HFlags onto a BMO flag layer. */
2024         BMO_push(bm, NULL);
2025         BM_ITER(h, &iter, bm, itertype, NULL) {
2026                 if (BM_TestHFlag(h, BM_SELECT)) {
2027                         BMO_SetFlag(bm, h, BM_SELECT);
2028                 }
2029         }
2030
2031         /* Walk over selected elements starting at active */
2032         BMW_Init(&walker, bm, walktype,  mask_vert,mask_edge,mask_loop,mask_face,  BMW_NIL_LAY);
2033         BLI_assert(walker.order == BMW_BREADTH_FIRST);
2034         for (h = BMW_Begin(&walker, h_act); h != NULL; h = BMW_Step(&walker)) {
2035                 /* Deselect elements that aren't at "nth" depth from active */
2036                 if ((offset + BMW_CurrentDepth(&walker)) % nth) {
2037                         BM_Select(bm, h, FALSE);
2038                 }
2039         }
2040         BMW_End(&walker);
2041
2042         BMO_pop(bm);
2043
2044         /* Flush selection up */
2045         EDBM_select_flush(em, flushtype);
2046 }
2047
2048 static void deselect_nth_active(BMEditMesh *em, BMVert **v_p, BMEdge **e_p, BMFace **f_p)
2049 {
2050         BMVert *v;
2051         BMEdge *e;
2052         BMFace *f;
2053         BMIter iter;
2054         BMEditSelection *ese;
2055
2056         *v_p= NULL;
2057         *e_p= NULL;
2058         *f_p= NULL;
2059
2060         EDBM_selectmode_flush(em);
2061         ese= (BMEditSelection*)em->bm->selected.last;
2062
2063         if(ese) {
2064                 switch(ese->htype) {
2065                 case BM_VERT:
2066                         *v_p= (BMVert *)ese->data;
2067                         return;
2068                 case BM_EDGE:
2069                         *e_p= (BMEdge *)ese->data;
2070                         return;
2071                 case BM_FACE:
2072                         *f_p= (BMFace *)ese->data;
2073                         return;
2074                 }
2075         }
2076
2077         if(em->selectmode & SCE_SELECT_VERTEX) {
2078                 BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2079                         if (BM_TestHFlag(v, BM_SELECT)) {
2080                                 *v_p = v;
2081                                 return;
2082                         }
2083                 }
2084         }
2085         else if(em->selectmode & SCE_SELECT_EDGE) {
2086                 BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2087                         if (BM_TestHFlag(e, BM_SELECT)) {
2088                                 *e_p = e;
2089                                 return;
2090                         }
2091                 }
2092         }
2093         else if(em->selectmode & SCE_SELECT_FACE) {
2094                 f= BM_get_actFace(em->bm, 1);
2095                 if(f) {
2096                         *f_p= f;
2097                         return;
2098                 }
2099         }
2100 }
2101
2102 static int EM_deselect_nth(BMEditMesh *em, int nth, int offset)
2103 {
2104         BMVert *v;
2105         BMEdge *e;
2106         BMFace *f;
2107
2108         deselect_nth_active(em, &v, &e, &f);
2109
2110         if (v) {
2111                 walker_deselect_nth(em, nth, offset, &v->head);
2112                 return 1;
2113         }
2114         else if(e) {
2115                 walker_deselect_nth(em, nth, offset, &e->head);
2116                 return 1;
2117         }
2118         else if(f) {
2119                 walker_deselect_nth(em, nth, offset, &f->head);
2120                 return 1;
2121         }
2122
2123         return 0;
2124 }
2125
2126 static int mesh_select_nth_exec(bContext *C, wmOperator *op)
2127 {
2128         Object *obedit= CTX_data_edit_object(C);
2129         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2130         int nth= RNA_int_get(op->ptr, "nth");
2131         int offset= RNA_int_get(op->ptr, "offset");
2132
2133         offset = MIN2(nth, offset);
2134
2135         if(EM_deselect_nth(em, nth, offset) == 0) {
2136                 BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face");
2137                 return OPERATOR_CANCELLED;
2138         }
2139
2140         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
2141         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2142
2143         return OPERATOR_FINISHED;
2144 }
2145
2146
2147 void MESH_OT_select_nth(wmOperatorType *ot)
2148 {
2149         /* identifiers */
2150         ot->name= "Select Nth";
2151         ot->description= "";
2152         ot->idname= "MESH_OT_select_nth";
2153
2154         /* api callbacks */
2155         ot->exec= mesh_select_nth_exec;
2156         ot->poll= ED_operator_editmesh;
2157
2158         /* flags */
2159         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2160
2161         RNA_def_int(ot->srna, "nth", 2, 2, 100, "Nth Selection", "", 1, INT_MAX);
2162         RNA_def_int(ot->srna, "offset", 0, 0, 100, "Offset", "", 0, INT_MAX);
2163 }
2164
2165 void em_setup_viewcontext(bContext *C, ViewContext *vc)
2166 {
2167         view3d_set_viewcontext(C, vc);
2168         
2169         if(vc->obedit) {
2170                 Mesh *me= vc->obedit->data;
2171                 vc->em= me->edit_btmesh;
2172         }
2173 }
2174
2175 /* poll call for mesh operators requiring a view3d context */
2176 int EM_view3d_poll(bContext *C)
2177 {
2178         if(ED_operator_editmesh(C) && ED_operator_view3d_active(C))
2179                 return 1;
2180         return 0;
2181 }
2182
2183
2184 static int select_sharp_edges_exec(bContext *C, wmOperator *op)
2185 {
2186         /* Find edges that have exactly two neighboring faces,
2187         * check the angle between those faces, and if angle is
2188         * small enough, select the edge
2189         */
2190         Object *obedit= CTX_data_edit_object(C);
2191         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2192         BMIter iter;
2193         BMEdge *e;
2194         BMLoop *l1, *l2;
2195         float sharp = RNA_float_get(op->ptr, "sharpness"), angle;
2196
2197         sharp = DEG2RADF(sharp);
2198
2199         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2200                 if (BM_TestHFlag(e, BM_HIDDEN) || !e->l)
2201                         continue;
2202
2203                 l1 = e->l;
2204                 l2 = l1->radial_next;
2205
2206                 if (l1 == l2)
2207                         continue;
2208
2209                 /* edge has exactly two neighboring faces, check angle */
2210                 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]);
2211
2212                 if (fabsf(angle) < sharp) {
2213                         BM_Select(em->bm, e, TRUE);
2214                 }
2215
2216         }
2217
2218         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2219
2220         return OPERATOR_FINISHED;
2221 }
2222
2223 void MESH_OT_edges_select_sharp(wmOperatorType *ot)
2224 {
2225         /* identifiers */
2226         ot->name= "Select Sharp Edges";
2227         ot->description= "Marked selected edges as sharp";
2228         ot->idname= "MESH_OT_edges_select_sharp";
2229         
2230         /* api callbacks */
2231         ot->exec= select_sharp_edges_exec;
2232         ot->poll= ED_operator_editmesh;
2233         
2234         /* flags */
2235         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2236         
2237         /* props */
2238         RNA_def_float(ot->srna, "sharpness", 1.0f, 0.01f, FLT_MAX, "sharpness", "", 1.0f, 180.0f);
2239 }
2240
2241 static int select_linked_flat_faces_exec(bContext *C, wmOperator *op)
2242 {
2243         Object *obedit= CTX_data_edit_object(C);
2244         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2245         BMIter iter, liter, liter2;
2246         BMFace *f, **stack = NULL;
2247         BLI_array_declare(stack);
2248         BMLoop *l, *l2;
2249         float sharp = RNA_float_get(op->ptr, "sharpness");
2250         int i;
2251
2252         sharp = (sharp * M_PI) / 180.0;
2253
2254         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2255                 BM_ClearHFlag(f, BM_TMP_TAG);
2256         }
2257
2258         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2259                 if (BM_TestHFlag(f, BM_HIDDEN) || !BM_TestHFlag(f, BM_SELECT) || BM_TestHFlag(f, BM_TMP_TAG))
2260                         continue;
2261
2262                 BLI_array_empty(stack);
2263                 i = 1;
2264
2265                 BLI_array_growone(stack);
2266                 stack[i-1] = f;
2267
2268                 while (i) {
2269                         f = stack[i-1];
2270                         i--;
2271
2272                         BM_Select(em->bm, f, TRUE);
2273
2274                         BM_SetHFlag(f, BM_TMP_TAG);
2275
2276                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
2277                                 BM_ITER(l2, &liter2, em->bm, BM_LOOPS_OF_LOOP, l) {
2278                                         float angle;
2279
2280                                         if (BM_TestHFlag(l2->f, BM_TMP_TAG) || BM_TestHFlag(l2->f, BM_HIDDEN))
2281                                                 continue;
2282
2283                                         /* edge has exactly two neighboring faces, check angle */
2284                                         angle = saacos(f->no[0]*l2->f->no[0]+f->no[1]*l2->f->no[1]+f->no[2]*l2->f->no[2]);
2285
2286                                         /* invalidate: edge too sharp */
2287                                         if (fabs(angle) < sharp) {
2288                                                 BLI_array_growone(stack);
2289                                                 stack[i] = l2->f;
2290                                                 i++;
2291                                         }
2292                                 }
2293                         }
2294                 }
2295         }
2296
2297         BLI_array_free(stack);
2298
2299         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2300
2301         return OPERATOR_FINISHED;
2302 }
2303
2304 void MESH_OT_faces_select_linked_flat(wmOperatorType *ot)
2305 {
2306         /* identifiers */
2307         ot->name= "Select Linked Flat Faces";
2308         ot->description= "Select linked faces by angle";
2309         ot->idname= "MESH_OT_faces_select_linked_flat";
2310         
2311         /* api callbacks */
2312         ot->exec= select_linked_flat_faces_exec;
2313         ot->poll= ED_operator_editmesh;
2314         
2315         /* flags */
2316         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2317         
2318         /* props */
2319         RNA_def_float(ot->srna, "sharpness", 1.0f, 0.01f, FLT_MAX, "sharpness", "", 1.0f, 180.0f);
2320 }
2321
2322 static int select_non_manifold_exec(bContext *C, wmOperator *op)
2323 {
2324         Object *obedit= CTX_data_edit_object(C);
2325         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2326         BMVert *v;
2327         BMEdge *e;
2328         BMIter iter;
2329
2330         /* Selects isolated verts, and edges that do not have 2 neighboring
2331          * faces
2332          */
2333         
2334         if(em->selectmode==SCE_SELECT_FACE) {
2335                 BKE_report(op->reports, RPT_ERROR, "Doesn't work in face selection mode");
2336                 return OPERATOR_CANCELLED;
2337         }
2338         
2339         BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2340                 if (!BM_TestHFlag(em->bm, BM_HIDDEN) && BM_Nonmanifold_Vert(em->bm, v)) {
2341                         BM_Select(em->bm, v, TRUE);
2342                 }
2343         }
2344         
2345         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2346                 if (!BM_TestHFlag(em->bm, BM_HIDDEN) && BM_Edge_FaceCount(e) != 2) {
2347                         BM_Select(em->bm, e, TRUE);
2348                 }
2349         }
2350
2351         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2352
2353         return OPERATOR_FINISHED;       
2354 }
2355
2356 void MESH_OT_select_non_manifold(wmOperatorType *ot)
2357 {
2358         /* identifiers */
2359         ot->name= "Select Non Manifold";
2360         ot->description= "Select all non-manifold vertices or edges";
2361         ot->idname= "MESH_OT_select_non_manifold";
2362         
2363         /* api callbacks */
2364         ot->exec= select_non_manifold_exec;
2365         ot->poll= ED_operator_editmesh;
2366         
2367         /* flags */
2368         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2369 }
2370
2371 static int mesh_select_random_exec(bContext *C, wmOperator *op)
2372 {
2373         Object *obedit= CTX_data_edit_object(C);
2374         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2375         BMVert *eve;
2376         BMEdge *eed;
2377         BMFace *efa;
2378         BMIter iter;
2379         float randfac =  RNA_float_get(op->ptr, "percent")/100.0f;
2380
2381         BLI_srand( BLI_rand() ); /* random seed */
2382         
2383         if(!RNA_boolean_get(op->ptr, "extend"))
2384                 EDBM_clear_flag_all(em, BM_SELECT);
2385
2386         if(em->selectmode & SCE_SELECT_VERTEX) {
2387                 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2388                         if (!BM_TestHFlag(eve, BM_HIDDEN) && BLI_frand() < randfac) {
2389                                 BM_Select(em->bm, eve, TRUE);
2390                         }
2391                 }
2392                 EDBM_selectmode_flush(em);
2393         }
2394         else if(em->selectmode & SCE_SELECT_EDGE) {
2395                 BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2396                         if (!BM_TestHFlag(eed, BM_HIDDEN) && BLI_frand() < randfac) {
2397                                 BM_Select(em->bm, eed, TRUE);
2398                         }
2399                 }
2400                 EDBM_selectmode_flush(em);
2401         }
2402         else {
2403                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2404                         if (!BM_TestHFlag(efa, BM_HIDDEN) && BLI_frand() < randfac) {
2405                                 BM_Select(em->bm, efa, TRUE);
2406                         }
2407                 }
2408                 EDBM_selectmode_flush(em);
2409         }
2410         
2411         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2412         
2413         return OPERATOR_FINISHED;       
2414 }
2415
2416 void MESH_OT_select_random(wmOperatorType *ot)
2417 {
2418         /* identifiers */
2419         ot->name= "Select Random";
2420         ot->description= "Randomly select vertices";
2421         ot->idname= "MESH_OT_select_random";
2422
2423         /* api callbacks */
2424         ot->exec= mesh_select_random_exec;
2425         ot->poll= ED_operator_editmesh;
2426
2427         /* flags */
2428         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2429         
2430         /* props */
2431         RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of elements to select randomly", 0.f, 100.0f);
2432         RNA_def_boolean(ot->srna, "extend", 0, "Extend Selection", "Extend selection instead of deselecting everything first");
2433 }
2434
2435 static int select_next_loop(bContext *C, wmOperator *UNUSED(op))
2436 {
2437         Object *obedit= CTX_data_edit_object(C);
2438         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
2439         BMFace *f;
2440         BMVert *v;
2441         BMIter iter;
2442         
2443         BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2444                 BM_ClearHFlag(v, BM_TMP_TAG);
2445         }
2446         
2447         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2448                 BMLoop *l;
2449                 BMIter liter;
2450                 
2451                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
2452                         if (BM_TestHFlag(l->v, BM_SELECT) && !BM_TestHFlag(l->v, BM_HIDDEN)) {
2453                                 BM_SetHFlag(l->next->v, BM_TMP_TAG);
2454                                 BM_Select(em->bm, l->v, FALSE);
2455                         }
2456                 }
2457         }
2458
2459         BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2460                 if (BM_TestHFlag(v, BM_TMP_TAG)) {
2461                         BM_Select(em->bm, v, TRUE);
2462                 }
2463         }
2464
2465         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
2466         return OPERATOR_FINISHED;
2467 }
2468
2469 void MESH_OT_select_next_loop(wmOperatorType *ot)
2470 {
2471         /* identifiers */
2472         ot->name= "Select Next Loop";
2473         ot->idname= "MESH_OT_select_next_loop";
2474         ot->description= "";
2475
2476         /* api callbacks */
2477         ot->exec= select_next_loop;
2478         ot->poll= ED_operator_editmesh;
2479         
2480         /* flags */
2481         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2482 }
2483
2484
2485 static int region_to_loop(bContext *C, wmOperator *UNUSED(op))
2486 {
2487         Object *obedit = CTX_data_edit_object(C);
2488         BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
2489         BMFace *f;
2490         BMEdge *e;
2491         BMIter iter;
2492         ViewContext vc;
2493         
2494         em_setup_viewcontext(C, &vc);
2495         
2496         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2497                 BM_ClearHFlag(e, BM_TMP_TAG);
2498         }
2499
2500         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2501                 BMLoop *l1, *l2;
2502                 BMIter liter1, liter2;
2503                 
2504                 BM_ITER(l1, &liter1, em->bm, BM_LOOPS_OF_FACE, f) {
2505                         int tot=0, totsel=0;
2506                         
2507                         BM_ITER(l2, &liter2, em->bm, BM_LOOPS_OF_EDGE, l1->e) {
2508                                 tot++;
2509                                 totsel += BM_TestHFlag(l2->f, BM_SELECT) != 0;
2510                         }
2511                         
2512                         if ((tot != totsel && totsel > 0) || (totsel == 1 && tot == 1))
2513                                 BM_SetHFlag(l1->e, BM_TMP_TAG);
2514                 }
2515         }
2516
2517         EDBM_clear_flag_all(em, BM_SELECT);
2518         
2519         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2520                 if (BM_TestHFlag(e, BM_TMP_TAG) && !BM_TestHFlag(e, BM_HIDDEN))
2521                         BM_Select_Edge(em->bm, e, TRUE);
2522         }
2523
2524         /* If in face-only select mode, switch to edge select mode so that
2525            an edge-only selection is not inconsistent state */
2526         if (em->selectmode == SCE_SELECT_FACE) {
2527                 em->selectmode = SCE_SELECT_EDGE;
2528                 EDBM_selectmode_set(em);
2529                 EDBM_selectmode_to_scene(C);
2530         }
2531
2532         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2533
2534         return OPERATOR_FINISHED;
2535 }
2536
2537 void MESH_OT_region_to_loop(wmOperatorType *ot)
2538 {
2539         /* identifiers */
2540         ot->name= "Select Boundary Loop";
2541         ot->idname= "MESH_OT_region_to_loop";
2542
2543         /* api callbacks */
2544         ot->exec= region_to_loop;
2545         ot->poll= ED_operator_editmesh;
2546
2547         /* flags */
2548         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2549 }
2550
2551 static int loop_find_region(BMEditMesh *em, BMLoop *l, int flag, 
2552         SmallHash *fhash, BMFace ***region_out)
2553 {
2554         BLI_array_declare(region);
2555         BLI_array_declare(stack);
2556         BMFace **region = NULL, *f;
2557         BMFace **stack = NULL;
2558         
2559         BLI_array_append(stack, l->f);
2560         BLI_smallhash_insert(fhash, (uintptr_t)l->f, NULL);
2561         
2562         while (BLI_array_count(stack) > 0) {
2563                 BMIter liter1, liter2;
2564                 BMLoop *l1, *l2;
2565                 
2566                 f = BLI_array_pop(stack);
2567                 BLI_array_append(region, f);
2568                 
2569                 BM_ITER(l1, &liter1, em->bm, BM_LOOPS_OF_FACE, f) {
2570                         if (BM_TestHFlag(l1->e, flag))
2571                                 continue;
2572                         
2573                         BM_ITER(l2, &liter2, em->bm, BM_LOOPS_OF_EDGE, l1->e) {
2574                                 if (BLI_smallhash_haskey(fhash, (uintptr_t)l2->f))
2575                                         continue;
2576                                 
2577                                 BLI_array_append(stack, l2->f);
2578                                 BLI_smallhash_insert(fhash, (uintptr_t)l2->f, NULL);
2579                         }
2580                 }
2581         }
2582         
2583         BLI_array_free(stack);
2584         
2585         *region_out = region;
2586         return BLI_array_count(region);
2587 }
2588
2589 static int verg_radial(const void *va, const void *vb)
2590 {
2591         BMEdge *e1 = *((void**)va);
2592         BMEdge *e2 = *((void**)vb);
2593         int a, b;
2594         
2595         a = BM_Edge_FaceCount(e1);
2596         b = BM_Edge_FaceCount(e2);
2597         
2598         if (a > b) return -1;
2599         if (a == b) return 0;
2600         if (a < b) return 1;
2601         
2602         return -1;
2603 }
2604
2605 static int loop_find_regions(BMEditMesh *em, int selbigger)
2606 {
2607         SmallHash visithash;
2608         BMIter iter;
2609         BMEdge *e, **edges=NULL;
2610         BLI_array_declare(edges);
2611         BMFace *f;
2612         int count = 0, i;
2613         
2614         BLI_smallhash_init(&visithash);
2615         
2616         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2617                 BM_ClearHFlag(f, BM_TMP_TAG);
2618         }
2619
2620         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2621                 if (BM_TestHFlag(e, BM_SELECT)) {
2622                         BLI_array_append(edges, e);
2623                         BM_SetHFlag(e, BM_TMP_TAG);
2624                 } else {
2625                         BM_ClearHFlag(e, BM_TMP_TAG);
2626                 }
2627         }
2628         
2629         /*sort edges by radial cycle length*/
2630         qsort(edges,  BLI_array_count(edges), sizeof(void*), verg_radial);
2631         
2632         for (i=0; i<BLI_array_count(edges); i++) {
2633                 BMIter liter;
2634                 BMLoop *l;
2635                 BMFace **region=NULL, **r;
2636                 int c, tot=0;
2637                 
2638                 e = edges[i];
2639                 
2640                 if (!BM_TestHFlag(e, BM_TMP_TAG))
2641                         continue;
2642                 
2643                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_EDGE, e) {
2644                         if (BLI_smallhash_haskey(&visithash, (uintptr_t)l->f))
2645                                 continue;
2646                                                 
2647                         c = loop_find_region(em, l, BM_SELECT, &visithash, &r);
2648
2649                         if (!region || (selbigger ? c >= tot : c < tot)) {
2650                                 /* this region is the best seen so far */
2651                                 tot = c;
2652                                 if (region) {
2653                                         /* free the previous best */
2654                                         MEM_freeN(region);
2655                                 }
2656                                 /* track the current region as the new best */
2657                                 region = r;
2658                         }
2659                         else {
2660                                 /* this region is not as good as best so far, just free it */
2661                                 MEM_freeN(r);
2662                         }
2663                 }
2664                 
2665                 if (region) {
2666                         int j;
2667                         
2668                         for (j=0; j<tot; j++) {
2669                                 BM_SetHFlag(region[j], BM_TMP_TAG);
2670                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, region[j]) {
2671                                         BM_ClearHFlag(l->e, BM_TMP_TAG);
2672                                 }
2673                         }
2674                         
2675                         count += tot;
2676                         
2677                         MEM_freeN(region);
2678                 }
2679         }
2680         
2681         BLI_array_free(edges);
2682         BLI_smallhash_release(&visithash);
2683         
2684         return count;
2685 }
2686
2687 static int loop_to_region(bContext *C, wmOperator *op)
2688 {
2689         Object *obedit = CTX_data_edit_object(C);
2690         BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
2691         BMIter iter;
2692         BMFace *f;
2693         int selbigger = RNA_boolean_get(op->ptr, "select_bigger");
2694         int a, b;
2695
2696         /*find the set of regions with smallest number of total faces*/
2697         a = loop_find_regions(em, selbigger);
2698         b = loop_find_regions(em, !selbigger);
2699         
2700         if ((a <= b) ^ selbigger) {
2701                 loop_find_regions(em, selbigger);
2702         }
2703         
2704         EDBM_clear_flag_all(em, BM_SELECT);
2705         
2706         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2707                 if (BM_TestHFlag(f, BM_TMP_TAG) && !BM_TestHFlag(f, BM_HIDDEN)) {
2708                         BM_Select_Face(em->bm, f, TRUE);
2709                 }
2710         }
2711         
2712         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2713         return OPERATOR_FINISHED;
2714 }
2715
2716 void MESH_OT_loop_to_region(wmOperatorType *ot)
2717 {
2718         /* identifiers */
2719         ot->name= "Select Loop Inner-Region";
2720         ot->idname= "MESH_OT_loop_to_region";
2721
2722         /* api callbacks */
2723         ot->exec= loop_to_region;
2724         ot->poll= ED_operator_editmesh;
2725
2726         /* flags */
2727         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2728         
2729         RNA_def_boolean(ot->srna, "select_bigger", 0, "Select Bigger", "Select bigger regions instead of smaller ones");
2730 }