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