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