ok, apparently didn't commit this either. apparently includes a merge with trunk...
[blender-staging.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_blenlib.h"
54 #include "BLI_math.h"
55 #include "BLI_rand.h"
56 #include "BLI_array.h"
57
58 #include "BKE_context.h"
59 #include "BKE_displist.h"
60 #include "BKE_depsgraph.h"
61 #include "BKE_DerivedMesh.h"
62 #include "BKE_customdata.h"
63 #include "BKE_global.h"
64 #include "BKE_mesh.h"
65 #include "BKE_material.h"
66 #include "BKE_texture.h"
67 #include "BKE_utildefines.h"
68 #include "BKE_report.h"
69 #include "BKE_tessmesh.h"
70
71 #include "IMB_imbuf_types.h"
72 #include "IMB_imbuf.h"
73
74 #include "RE_render_ext.h"  /* externtex */
75
76 #include "WM_api.h"
77 #include "WM_types.h"
78
79 #include "RNA_access.h"
80 #include "RNA_define.h"
81
82 #include "ED_mesh.h"
83 #include "ED_screen.h"
84 #include "ED_view3d.h"
85 #include "bmesh.h"
86
87 #include "BIF_gl.h"
88 #include "BIF_glutil.h"
89
90 #include "UI_resources.h"
91
92 #include "mesh_intern.h"
93
94 #include "BLO_sys_types.h" // for intptr_t support
95
96 /* XXX */
97 static void waitcursor() {}
98 static int pupmenu() {return 0;}
99
100 /* ****************************** MIRROR **************** */
101
102 void EDBM_select_mirrored(Object *obedit, BMEditMesh *em)
103 {
104 #if 0 //BMESH_TODO
105         if(em->selectmode & SCE_SELECT_VERTEX) {
106                 BMVert *eve, *v1;
107                 
108                 for(eve= em->verts.first; eve; eve= eve->next) {
109                         if(eve->f & SELECT) {
110                                 v1= BMEditMesh_get_x_mirror_vert(obedit, em, eve->co);
111                                 if(v1) {
112                                         eve->f &= ~SELECT;
113                                         v1->f |= SELECT;
114                                 }
115                         }
116                 }
117         }
118 #endif
119 }
120
121 void EDBM_automerge(Scene *scene, Object *obedit, int update)
122 {
123         BMEditMesh *em;
124         int len;
125         
126         if ((scene->toolsettings->automerge) &&
127             (obedit && obedit->type==OB_MESH) &&
128             (((Mesh*)obedit->data)->mr==NULL))
129         {
130                 em = ((Mesh*)obedit->data)->edit_btmesh;
131                 if (!em)
132                         return;
133
134                 BMO_CallOpf(em->bm, "automerge verts=%hv dist=%f", BM_SELECT, scene->toolsettings->doublimit);
135                 if (update) {
136                         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
137                 }
138         }
139 }
140
141 /* ****************************** SELECTION ROUTINES **************** */
142
143 unsigned int bm_solidoffs=0, bm_wireoffs=0, bm_vertoffs=0;      /* set in drawobject.c ... for colorindices */
144
145 /* facilities for border select and circle select */
146 static char *selbuf= NULL;
147
148 /* opengl doesn't support concave... */
149 static void draw_triangulated(short mcords[][2], short tot)
150 {
151         ListBase lb={NULL, NULL};
152         DispList *dl;
153         float *fp;
154         int a;
155         
156         /* make displist */
157         dl= MEM_callocN(sizeof(DispList), "poly disp");
158         dl->type= DL_POLY;
159         dl->parts= 1;
160         dl->nr= tot;
161         dl->verts= fp=  MEM_callocN(tot*3*sizeof(float), "poly verts");
162         BLI_addtail(&lb, dl);
163         
164         for(a=0; a<tot; a++, fp+=3) {
165                 fp[0]= (float)mcords[a][0];
166                 fp[1]= (float)mcords[a][1];
167         }
168         
169         /* do the fill */
170         filldisplist(&lb, &lb);
171
172         /* do the draw */
173         dl= lb.first;   /* filldisplist adds in head of list */
174         if(dl->type==DL_INDEX3) {
175                 int *index;
176                 
177                 a= dl->parts;
178                 fp= dl->verts;
179                 index= dl->index;
180                 glBegin(GL_TRIANGLES);
181                 while(a--) {
182                         glVertex3fv(fp+3*index[0]);
183                         glVertex3fv(fp+3*index[1]);
184                         glVertex3fv(fp+3*index[2]);
185                         index+= 3;
186                 }
187                 glEnd();
188         }
189         
190         freedisplist(&lb);
191 }
192
193
194 /* reads rect, and builds selection array for quick lookup */
195 /* returns if all is OK */
196 int EDBM_init_backbuf_border(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
197 {
198         struct ImBuf *buf;
199         unsigned int *dr;
200         int a;
201         
202         if(vc->obedit==NULL || vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
203         
204         buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
205         if(buf==NULL) return 0;
206         if(bm_vertoffs==0) return 0;
207
208         dr = buf->rect;
209         
210         /* build selection lookup */
211         selbuf= MEM_callocN(bm_vertoffs+1, "selbuf");
212         
213         a= (xmax-xmin+1)*(ymax-ymin+1);
214         while(a--) {
215                 if(*dr>0 && *dr<=bm_vertoffs) 
216                         selbuf[*dr]= 1;
217                 dr++;
218         }
219         IMB_freeImBuf(buf);
220         return 1;
221 }
222
223 int EDBM_check_backbuf(unsigned int index)
224 {
225         if(selbuf==NULL) return 1;
226         if(index>0 && index<=bm_vertoffs)
227                 return selbuf[index];
228         return 0;
229 }
230
231 void EDBM_free_backbuf(void)
232 {
233         if(selbuf) MEM_freeN(selbuf);
234         selbuf= NULL;
235 }
236
237 /* mcords is a polygon mask
238    - grab backbuffer,
239    - draw with black in backbuffer, 
240    - grab again and compare
241    returns 'OK' 
242 */
243 int EDBM_mask_init_backbuf_border(ViewContext *vc, short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
244 {
245         unsigned int *dr, *drm;
246         struct ImBuf *buf, *bufmask;
247         int a;
248         
249         /* method in use for face selecting too */
250         if(vc->obedit==NULL) {
251                 if(paint_facesel_test(vc->obact));
252                 else return 0;
253         }
254         else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
255
256         buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
257         if(buf==NULL) return 0;
258         if(bm_vertoffs==0) return 0;
259
260         dr = buf->rect;
261
262         /* draw the mask */
263         glDisable(GL_DEPTH_TEST);
264         
265         glColor3ub(0, 0, 0);
266         
267         /* yah, opengl doesn't do concave... tsk! */
268         ED_region_pixelspace(vc->ar);
269         draw_triangulated(mcords, tot); 
270         
271         glBegin(GL_LINE_LOOP);  /* for zero sized masks, lines */
272         for(a=0; a<tot; a++) glVertex2s(mcords[a][0], mcords[a][1]);
273         glEnd();
274         
275         glFinish();     /* to be sure readpixels sees mask */
276         
277         /* grab mask */
278         bufmask= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
279         drm = bufmask->rect;
280         if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */
281         
282         /* build selection lookup */
283         selbuf= MEM_callocN(bm_vertoffs+1, "selbuf");
284         
285         a= (xmax-xmin+1)*(ymax-ymin+1);
286         while(a--) {
287                 if(*dr>0 && *dr<=bm_vertoffs && *drm==0) selbuf[*dr]= 1;
288                 dr++; drm++;
289         }
290         IMB_freeImBuf(buf);
291         IMB_freeImBuf(bufmask);
292         return 1;
293         
294 }
295
296 /* circle shaped sample area */
297 int EDBM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads)
298 {
299         struct ImBuf *buf;
300         unsigned int *dr;
301         short xmin, ymin, xmax, ymax, xc, yc;
302         int radsq;
303         
304         /* method in use for face selecting too */
305         if(vc->obedit==NULL) {
306                 if(paint_facesel_test(vc->obact));
307                 else return 0;
308         }
309         else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
310         
311         xmin= xs-rads; xmax= xs+rads;
312         ymin= ys-rads; ymax= ys+rads;
313         buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
314         if(bm_vertoffs==0) return 0;
315         if(buf==NULL) return 0;
316
317         dr = buf->rect;
318         
319         /* build selection lookup */
320         selbuf= MEM_callocN(bm_vertoffs+1, "selbuf");
321         radsq= rads*rads;
322         for(yc= -rads; yc<=rads; yc++) {
323                 for(xc= -rads; xc<=rads; xc++, dr++) {
324                         if(xc*xc + yc*yc < radsq) {
325                                 if(*dr>0 && *dr<=bm_vertoffs) selbuf[*dr]= 1;
326                         }
327                 }
328         }
329
330         IMB_freeImBuf(buf);
331         return 1;
332         
333 }
334
335 static void findnearestvert__doClosest(void *userData, BMVert *eve, int x, int y, int index)
336 {
337         struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; BMVert *closest; } *data = userData;
338
339         if (data->pass==0) {
340                 if (index<=data->lastIndex)
341                         return;
342         } else {
343                 if (index>data->lastIndex)
344                         return;
345         }
346
347         if (data->dist>3) {
348                 int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y);
349                 if (BM_TestHFlag(eve, BM_SELECT) == data->select) {
350                         if (data->strict == 1)
351                                 return;
352                         else
353                                 temp += 5;
354                 }
355
356                 if (temp<data->dist) {
357                         data->dist = temp;
358                         data->closest = eve;
359                         data->closestIndex = index;
360                 }
361         }
362 }
363
364
365
366
367 static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index)
368 {
369         BMEditMesh *em= (BMEditMesh *)handle;
370         BMVert *eve = BMIter_AtIndex(em->bm, BM_VERTS_OF_MESH, NULL, index-1);
371
372         if(eve && BM_TestHFlag(eve, BM_SELECT)) return 0;
373         return 1; 
374 }
375 /**
376  * findnearestvert
377  * 
378  * dist (in/out): minimal distance to the nearest and at the end, actual distance
379  * sel: selection bias
380  *              if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
381  *              if 0, unselected vertice are given the bias
382  * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased 
383  */
384 BMVert *EDBM_findnearestvert(ViewContext *vc, int *dist, short sel, short strict)
385 {
386         if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)){
387                 int distance;
388                 unsigned int index;
389                 BMVert *eve;
390                 
391                 if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance, strict, vc->em, findnearestvert__backbufIndextest); 
392                 else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance, 0, NULL, NULL); 
393                 
394                 eve = BMIter_AtIndex(vc->em->bm, BM_VERTS_OF_MESH, NULL, index-1);
395                 
396                 if(eve && distance < *dist) {
397                         *dist = distance;
398                         return eve;
399                 } else {
400                         return NULL;
401                 }
402                         
403         }
404         else {
405                 struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; BMVert *closest; } data;
406                 static int lastSelectedIndex=0;
407                 static BMVert *lastSelected=NULL;
408                 
409                 if (lastSelected && BMIter_AtIndex(vc->em->bm, BM_VERTS_OF_MESH, NULL, lastSelectedIndex)!=lastSelected) {
410                         lastSelectedIndex = 0;
411                         lastSelected = NULL;
412                 }
413
414                 data.lastIndex = lastSelectedIndex;
415                 data.mval[0] = vc->mval[0];
416                 data.mval[1] = vc->mval[1];
417                 data.select = sel;
418                 data.dist = *dist;
419                 data.strict = strict;
420                 data.closest = NULL;
421                 data.closestIndex = 0;
422
423                 data.pass = 0;
424
425                 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
426
427                 mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
428
429                 if (data.dist>3) {
430                         data.pass = 1;
431                         mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
432                 }
433
434                 *dist = data.dist;
435                 lastSelected = data.closest;
436                 lastSelectedIndex = data.closestIndex;
437
438                 return data.closest;
439         }
440 }
441
442 /* returns labda for closest distance v1 to line-piece v2-v3 */
443 static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3) 
444 {
445         float rc[2], len;
446         
447         rc[0]= v3[0]-v2[0];
448         rc[1]= v3[1]-v2[1];
449         len= rc[0]*rc[0]+ rc[1]*rc[1];
450         if(len==0.0f)
451                 return 0.0f;
452         
453         return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
454 }
455
456 /* note; uses v3d, so needs active 3d window */
457 static void findnearestedge__doClosest(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index)
458 {
459         struct { ViewContext vc; float mval[2]; int dist; BMEdge *closest; } *data = userData;
460         float v1[2], v2[2];
461         int distance;
462                 
463         v1[0] = x0;
464         v1[1] = y0;
465         v2[0] = x1;
466         v2[1] = y1;
467                 
468         distance= dist_to_line_segment_v2(data->mval, v1, v2);
469                 
470         if(BM_TestHFlag(eed, BM_SELECT)) distance+=5;
471         if(distance < data->dist) {
472                 if(data->vc.rv3d->rflag & RV3D_CLIPPING) {
473                         float labda= labda_PdistVL2Dfl(data->mval, v1, v2);
474                         float vec[3];
475
476                         vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]);
477                         vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]);
478                         vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]);
479                         mul_m4_v3(data->vc.obedit->obmat, vec);
480
481                         if(view3d_test_clipping(data->vc.rv3d, vec, 1)==0) {
482                                 data->dist = distance;
483                                 data->closest = eed;
484                         }
485                 }
486                 else {
487                         data->dist = distance;
488                         data->closest = eed;
489                 }
490         }
491 }
492 BMEdge *EDBM_findnearestedge(ViewContext *vc, int *dist)
493 {
494
495         if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
496                 int distance;
497                 unsigned int index;
498                 BMEdge *eed;
499                 
500                 view3d_validate_backbuf(vc);
501                 
502                 index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_solidoffs, bm_wireoffs, &distance,0, NULL, NULL);
503                 eed = BMIter_AtIndex(vc->em->bm, BM_EDGES_OF_MESH, NULL, index-1);
504                 
505                 if (eed && distance<*dist) {
506                         *dist = distance;
507                         return eed;
508                 } else {
509                         return NULL;
510                 }
511         }
512         else {
513                 struct { ViewContext vc; float mval[2]; int dist; BMEdge *closest; } data;
514
515                 data.vc= *vc;
516                 data.mval[0] = vc->mval[0];
517                 data.mval[1] = vc->mval[1];
518                 data.dist = *dist;
519                 data.closest = NULL;
520                 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
521
522                 mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, 2);
523
524                 *dist = data.dist;
525                 return data.closest;
526         }
527 }
528
529 static void findnearestface__getDistance(void *userData, BMFace *efa, int x, int y, int index)
530 {
531         struct { short mval[2]; int dist; BMFace *toFace; } *data = userData;
532
533         if (efa==data->toFace) {
534                 int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
535
536                 if (temp<data->dist)
537                         data->dist = temp;
538         }
539 }
540 static void findnearestface__doClosest(void *userData, BMFace *efa, int x, int y, int index)
541 {
542         struct { short mval[2], pass; int dist, lastIndex, closestIndex; BMFace *closest; } *data = userData;
543
544         if (data->pass==0) {
545                 if (index<=data->lastIndex)
546                         return;
547         } else {
548                 if (index>data->lastIndex)
549                         return;
550         }
551
552         if (data->dist>3) {
553                 int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
554
555                 if (temp<data->dist) {
556                         data->dist = temp;
557                         data->closest = efa;
558                         data->closestIndex = index;
559                 }
560         }
561 }
562
563 BMFace *EDBM_findnearestface(ViewContext *vc, int *dist)
564 {
565
566         if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
567                 unsigned int index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]);
568                 BMFace *efa = BMIter_AtIndex(vc->em->bm, BM_FACES_OF_MESH, NULL, index-1);
569
570                 if (efa) {
571                         struct { short mval[2]; int dist; BMFace *toFace; } data;
572
573                         data.mval[0] = vc->mval[0];
574                         data.mval[1] = vc->mval[1];
575                         data.dist = 0x7FFF;             /* largest short */
576                         data.toFace = efa;
577
578                         mesh_foreachScreenFace(vc, findnearestface__getDistance, &data);
579
580                         if(vc->em->selectmode == SCE_SELECT_FACE || data.dist<*dist) {  /* only faces, no dist check */
581                                 *dist= data.dist;
582                                 return efa;
583                         }
584                 }
585                 
586                 return NULL;
587         }
588         else {
589                 struct { short mval[2], pass; int dist, lastIndex, closestIndex; BMFace *closest; } data;
590                 static int lastSelectedIndex=0;
591                 static BMFace *lastSelected=NULL;
592
593                 if (lastSelected && BMIter_AtIndex(vc->em->bm, BM_FACES_OF_MESH, NULL, lastSelectedIndex)!=lastSelected) {
594                         lastSelectedIndex = 0;
595                         lastSelected = NULL;
596                 }
597
598                 data.lastIndex = lastSelectedIndex;
599                 data.mval[0] = vc->mval[0];
600                 data.mval[1] = vc->mval[1];
601                 data.dist = *dist;
602                 data.closest = NULL;
603                 data.closestIndex = 0;
604                 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
605
606                 data.pass = 0;
607                 mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
608
609                 if (data.dist>3) {
610                         data.pass = 1;
611                         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
612                         mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
613                 }
614
615                 *dist = data.dist;
616                 lastSelected = data.closest;
617                 lastSelectedIndex = data.closestIndex;
618
619                 return data.closest;
620         }
621 }
622
623 /* best distance based on screen coords. 
624    use em->selectmode to define how to use 
625    selected vertices and edges get disadvantage
626    return 1 if found one
627 */
628 static int unified_findnearest(ViewContext *vc, BMVert **eve, BMEdge **eed, BMFace **efa) 
629 {
630         BMEditMesh *em= vc->em;
631         int dist= 75;
632         
633         *eve= NULL;
634         *eed= NULL;
635         *efa= NULL;
636         
637         /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
638         view3d_validate_backbuf(vc);
639         
640         if(em->selectmode & SCE_SELECT_VERTEX)
641                 *eve= EDBM_findnearestvert(vc, &dist, BM_SELECT, 0);
642         if(em->selectmode & SCE_SELECT_FACE)
643                 *efa= EDBM_findnearestface(vc, &dist);
644
645         dist-= 20;      /* since edges select lines, we give dots advantage of 20 pix */
646         if(em->selectmode & SCE_SELECT_EDGE)
647                 *eed= EDBM_findnearestedge(vc, &dist);
648
649         /* return only one of 3 pointers, for frontbuffer redraws */
650         if(*eed) {
651                 *efa= NULL; *eve= NULL;
652         }
653         else if(*efa) {
654                 *eve= NULL;
655         }
656         
657         return (*eve || *eed || *efa);
658 }
659
660 /* ****************  SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
661
662 static EnumPropertyItem prop_similar_types[] = {
663         {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""},
664         {SIMVERT_FACE, "FACE", 0, "Amount of Adjacent Faces", ""},
665         {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""},
666
667         {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""},
668         {SIMEDGE_DIR, "DIR", 0, "Direction", ""},
669         {SIMEDGE_FACE, "FACE", 0, "Amount of Faces Around an Edge", ""},
670         {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""},
671         {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""},
672         {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
673         {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
674
675         {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
676         {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
677         {SIMFACE_AREA, "AREA", 0, "Area", ""},
678         {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
679         {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
680         {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
681
682         {0, NULL, 0, NULL, NULL}
683 };
684
685 /* selects new faces/edges/verts based on the existing selection */
686
687 static int similar_face_select_exec(bContext *C, wmOperator *op)
688 {
689         Scene *scene = CTX_data_scene(C);
690         Object *ob = CTX_data_edit_object(C);
691         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
692         BMOperator bmop;
693
694         /* get the type from RNA */
695         int type = RNA_enum_get(op->ptr, "type");
696
697         float thresh = CTX_data_tool_settings(C)->select_thresh;
698
699         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
700         EDBM_InitOpf(em, &bmop, op, "similarfaces faces=%hf type=%d thresh=%f", BM_SELECT, type, thresh);
701
702         /* execute the operator */
703         BMO_Exec_Op(em->bm, &bmop);
704
705         /* clear the existing selection */
706         EDBM_clear_flag_all(em, BM_SELECT);
707
708         /* select the output */
709         BMO_HeaderFlag_Buffer(em->bm, &bmop, "faceout", BM_SELECT, BM_ALL);
710
711         /* finish the operator */
712         if( !EDBM_FinishOp(em, &bmop, op, 1) )
713                 return OPERATOR_CANCELLED;
714
715         /* dependencies graph and notification stuff */
716         DAG_id_flush_update(ob->data, OB_RECALC_DATA);
717         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
718
719         /* we succeeded */
720         return OPERATOR_FINISHED;
721 }       
722
723 /* ***************************************************** */
724
725 /* EDGE GROUP */
726
727 /* wrap the above function but do selection flushing edge to face */
728 static int similar_edge_select_exec(bContext *C, wmOperator *op)
729 {
730         Scene *scene = CTX_data_scene(C);
731         Object *ob = CTX_data_edit_object(C);
732         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
733         BMOperator bmop;
734
735         /* get the type from RNA */
736         int type = RNA_enum_get(op->ptr, "type");
737
738         float thresh = CTX_data_tool_settings(C)->select_thresh;
739
740         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
741         EDBM_InitOpf(em, &bmop, op, "similaredges edges=%he type=%d thresh=%f", BM_SELECT, type, thresh);
742
743         /* execute the operator */
744         BMO_Exec_Op(em->bm, &bmop);
745
746         /* clear the existing selection */
747         EDBM_clear_flag_all(em, BM_SELECT);
748
749         /* select the output */
750         BMO_HeaderFlag_Buffer(em->bm, &bmop, "edgeout", BM_SELECT, BM_ALL);
751         EDBM_selectmode_flush(em);
752
753         /* finish the operator */
754         if( !EDBM_FinishOp(em, &bmop, op, 1) )
755                 return OPERATOR_CANCELLED;
756
757         /* dependencies graph and notification stuff */
758         DAG_id_flush_update(ob->data, OB_RECALC_DATA);
759         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
760
761         /* we succeeded */
762         return OPERATOR_FINISHED;
763 }
764
765 /* ********************************* */
766
767 /*
768 VERT GROUP
769  mode 1: same normal
770  mode 2: same number of face users
771  mode 3: same vertex groups
772 */
773
774
775 static int similar_vert_select_exec(bContext *C, wmOperator *op)
776 {
777         Scene *scene = CTX_data_scene(C);
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_flush_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 *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= 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 #if 0
899 /* selects quads in loop direction of indicated edge */
900 /* only flush over edges with valence <= 2 */
901 void faceloop_select(EditMesh *em, EditEdge *startedge, int select)
902 {
903         EditEdge *eed;
904         EditFace *efa;
905         int looking= 1;
906         
907         /* in eed->f1 we put the valence (amount of faces in edge) */
908         /* in eed->f2 we put tagged flag as correct loop */
909         /* in efa->f1 we put tagged flag as correct to select */
910
911         for(eed= em->edges.first; eed; eed= eed->next) {
912                 eed->f1= 0;
913                 eed->f2= 0;
914         }
915         for(efa= em->faces.first; efa; efa= efa->next) {
916                 efa->f1= 0;
917                 if(efa->h==0) {
918                         efa->e1->f1++;
919                         efa->e2->f1++;
920                         efa->e3->f1++;
921                         if(efa->e4) efa->e4->f1++;
922                 }
923         }
924         
925         /* tag startedge OK*/
926         startedge->f2= 1;
927         
928         while(looking) {
929                 looking= 0;
930                 
931                 for(efa= em->faces.first; efa; efa= efa->next) {
932                         if(efa->h==0 && efa->e4 && efa->f1==0) {        /* not done quad */
933                                 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
934
935                                         /* if edge tagged, select opposing edge and mark face ok */
936                                         if(efa->e1->f2) {
937                                                 efa->e3->f2= 1;
938                                                 efa->f1= 1;
939                                                 looking= 1;
940                                         }
941                                         else if(efa->e2->f2) {
942                                                 efa->e4->f2= 1;
943                                                 efa->f1= 1;
944                                                 looking= 1;
945                                         }
946                                         if(efa->e3->f2) {
947                                                 efa->e1->f2= 1;
948                                                 efa->f1= 1;
949                                                 looking= 1;
950                                         }
951                                         if(efa->e4->f2) {
952                                                 efa->e2->f2= 1;
953                                                 efa->f1= 1;
954                                                 looking= 1;
955                                         }
956                                 }
957                         }
958                 }
959         }
960         
961         /* (de)select the faces */
962         if(select!=2) {
963                 for(efa= em->faces.first; efa; efa= efa->next) {
964                         if(efa->f1) EM_select_face(efa, select);
965                 }
966         }
967 }
968 #endif
969
970
971 /* selects or deselects edges that:
972 - if edges has 2 faces:
973         - has vertices with valence of 4
974         - not shares face with previous edge
975 - if edge has 1 face:
976         - has vertices with valence 4
977         - not shares face with previous edge
978         - but also only 1 face
979 - if edge no face:
980         - has vertices with valence 2
981 */
982
983 /* 
984    Almostly exactly the same code as faceloop select
985 */
986 static void edgering_select(BMEditMesh *em, BMEdge *startedge, int select)
987 {
988 #if 0 //BMESH_TODO
989         BMEdge *eed;
990         BMFace *efa;
991         int looking= 1;
992         
993         /* in eed->f1 we put the valence (amount of faces in edge) */
994         /* in eed->f2 we put tagged flag as correct loop */
995         /* in efa->f1 we put tagged flag as correct to select */
996
997         for(eed= em->edges.first; eed; eed= eed->next) {
998                 eed->f1= 0;
999                 eed->f2= 0;
1000         }
1001         for(efa= em->faces.first; efa; efa= efa->next) {
1002                 efa->f1= 0;
1003                 if(efa->h==0) {
1004                         efa->e1->f1++;
1005                         efa->e2->f1++;
1006                         efa->e3->f1++;
1007                         if(efa->e4) efa->e4->f1++;
1008                 }
1009         }
1010         
1011         /* tag startedge OK */
1012         startedge->f2= 1;
1013         
1014         while(looking) {
1015                 looking= 0;
1016                 
1017                 for(efa= em->faces.first; efa; efa= efa->next) {
1018                         if(efa->e4 && efa->f1==0 && !efa->h) {  /* not done quad */
1019                                 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
1020
1021                                         /* if edge tagged, select opposing edge and mark face ok */
1022                                         if(efa->e1->f2) {
1023                                                 efa->e3->f2= 1;
1024                                                 efa->f1= 1;
1025                                                 looking= 1;
1026                                         }
1027                                         else if(efa->e2->f2) {
1028                                                 efa->e4->f2= 1;
1029                                                 efa->f1= 1;
1030                                                 looking= 1;
1031                                         }
1032                                         if(efa->e3->f2) {
1033                                                 efa->e1->f2= 1;
1034                                                 efa->f1= 1;
1035                                                 looking= 1;
1036                                         }
1037                                         if(efa->e4->f2) {
1038                                                 efa->e2->f2= 1;
1039                                                 efa->f1= 1;
1040                                                 looking= 1;
1041                                         }
1042                                 }
1043                         }
1044                 }
1045         }
1046         
1047         /* (de)select the edges */
1048         for(eed= em->edges.first; eed; eed= eed->next) {
1049                 if(eed->f2) EM_select_edge(eed, select);
1050         }
1051 #endif
1052 }
1053
1054 static int loop_multiselect(bContext *C, wmOperator *op)
1055 {
1056 #if 0 //BMESH_TODO
1057         Object *obedit= CTX_data_edit_object(C);
1058         BMEditMesh *em= EM_GetBMEditMesh(((Mesh *)obedit->data));
1059         BMEdge *eed;
1060         BMEdge **edarray;
1061         int edindex, edfirstcount;
1062         int looptype= RNA_boolean_get(op->ptr, "ring");
1063         
1064         /* sets em->totedgesel */
1065         EM_nedges_selected(em);
1066         
1067         edarray = MEM_mallocN(sizeof(BMEdge*)*em->totedgesel,"edge array");
1068         edindex = 0;
1069         edfirstcount = em->totedgesel;
1070         
1071         for(eed=em->edges.first; eed; eed=eed->next){
1072                 if(eed->f&SELECT){
1073                         edarray[edindex] = eed;
1074                         edindex += 1;
1075                 }
1076         }
1077         
1078         if(looptype){
1079                 for(edindex = 0; edindex < edfirstcount; edindex +=1){
1080                         eed = edarray[edindex];
1081                         edgering_select(em, eed,SELECT);
1082                 }
1083                 EM_selectmode_flush(em);
1084         }
1085         else{
1086                 for(edindex = 0; edindex < edfirstcount; edindex +=1){
1087                         eed = edarray[edindex];
1088                         edgeloop_select(em, eed,SELECT);
1089                 }
1090                 EM_selectmode_flush(em);
1091         }
1092         MEM_freeN(edarray);
1093 //      if (EM_texFaceCheck())
1094         
1095         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1096
1097         EM_EndBMEditMesh(obedit->data, em);
1098 #endif
1099         return OPERATOR_FINISHED;       
1100 }
1101
1102 void MESH_OT_loop_multi_select(wmOperatorType *ot)
1103 {
1104         /* identifiers */
1105         ot->name= "Multi Select Loops";
1106         ot->idname= "MESH_OT_loop_multi_select";
1107         
1108         /* api callbacks */
1109         ot->exec= loop_multiselect;
1110         ot->poll= ED_operator_editmesh;
1111         ot->description= "Select a loop of connected edges by connection type.";
1112         
1113         /* flags */
1114         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1115         
1116         /* properties */
1117         RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
1118 }
1119
1120                 
1121 /* ***************** MAIN MOUSE SELECTION ************** */
1122
1123
1124 /* ***************** loop select (non modal) ************** */
1125
1126 static void mouse_mesh_loop(bContext *C, short mval[2], short extend, short ring)
1127 {
1128         ViewContext vc;
1129         BMEditMesh *em;
1130         BMEdge *eed;
1131         int select= 1;
1132         int dist= 50;
1133         
1134         em_setup_viewcontext(C, &vc);
1135         vc.mval[0]= mval[0];
1136         vc.mval[1]= mval[1];
1137         em= vc.em;
1138         
1139         /* no afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad */
1140         view3d_validate_backbuf(&vc);
1141
1142         eed= EDBM_findnearestedge(&vc, &dist);
1143         if(eed) {
1144                 if(extend==0) EDBM_clear_flag_all(em, BM_SELECT);
1145         
1146                 if(BM_TestHFlag(em, BM_SELECT)==0) select=1;
1147                 else if(extend) select=0;
1148
1149                 if(em->selectmode & SCE_SELECT_FACE) {
1150                         walker_select(em, BMW_FACELOOP, eed, select);
1151                 }
1152                 else if(em->selectmode & SCE_SELECT_EDGE) {
1153                         if(ring)
1154                                 walker_select(em, BMW_EDGERING, eed, select);
1155                         else
1156                                 walker_select(em, BMW_LOOP, eed, select);
1157                 }
1158                 else if(em->selectmode & SCE_SELECT_VERTEX) {
1159                         if(ring)
1160                                 walker_select(em, BMW_EDGERING, eed, select);
1161                         else 
1162                                 walker_select(em, BMW_LOOP, eed, select);
1163                 }
1164
1165                 EDBM_selectmode_flush(em);
1166 //                      if (EM_texFaceCheck())
1167                 
1168                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit);
1169         }
1170 }
1171
1172 static int mesh_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
1173 {
1174         
1175         view3d_operator_needs_opengl(C);
1176         
1177         mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"),
1178                                         RNA_boolean_get(op->ptr, "ring"));
1179         
1180         /* cannot do tweaks for as long this keymap is after transform map */
1181         return OPERATOR_FINISHED;
1182 }
1183
1184 void MESH_OT_loop_select(wmOperatorType *ot)
1185 {
1186         /* identifiers */
1187         ot->name= "Loop Select";
1188         ot->idname= "MESH_OT_loop_select";
1189         
1190         /* api callbacks */
1191         ot->invoke= mesh_select_loop_invoke;
1192         ot->poll= ED_operator_editmesh;
1193         ot->description= "Select a loop of connected edges.";
1194         
1195         /* flags */
1196         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1197         
1198         /* properties */
1199         RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
1200         RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "");
1201 }
1202
1203 /* ******************* mesh shortest path select, uses prev-selected edge ****************** */
1204
1205 /* since you want to create paths with multiple selects, it doesn't have extend option */
1206 static void mouse_mesh_shortest_path(bContext *C, short mval[2])
1207 {
1208 #if 0 //BMESH_TODO
1209         ViewContext vc;
1210         BMEditMesh *em;
1211         BMEdge *eed;
1212         int dist= 50;
1213         
1214         em_setup_viewcontext(C, &vc);
1215         vc.mval[0]= mval[0];
1216         vc.mval[1]= mval[1];
1217         em= vc.em;
1218         
1219         eed= findnearestedge(&vc, &dist);
1220         if(eed) {
1221                 Mesh *me= vc.obedit->data;
1222                 int path = 0;
1223                 
1224                 if (em->bm->selected.last) {
1225                         EditSelection *ese = em->bm->selected.last;
1226                         
1227                         if(ese && ese->type == BMEdge) {
1228                                 BMEdge *eed_act;
1229                                 eed_act = (BMEdge*)ese->data;
1230                                 if (eed_act != eed) {
1231                                         if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) {
1232                                                 EM_remove_selection(em, eed_act, BMEdge);
1233                                                 path = 1;
1234                                         }
1235                                 }
1236                         }
1237                 }
1238                 if (path==0) {
1239                         int act = (edgetag_context_check(vc.scene, eed)==0);
1240                         edgetag_context_set(vc.scene, eed, act); /* switch the edge option */
1241                 }
1242                 
1243                 EM_selectmode_flush(em);
1244
1245                 /* even if this is selected it may not be in the selection list */
1246                 if(edgetag_context_check(vc.scene, eed)==0)
1247                         EDBM_remove_selection(em, eed);
1248                 else
1249                         EDBM_store_selection(em, eed);
1250         
1251                 /* force drawmode for mesh */
1252                 switch (CTX_data_tool_settings(C)->edge_mode) {
1253                         
1254                         case EDGE_MODE_TAG_SEAM:
1255                                 me->drawflag |= ME_DRAWSEAMS;
1256                                 break;
1257                         case EDGE_MODE_TAG_SHARP:
1258                                 me->drawflag |= ME_DRAWSHARP;
1259                                 break;
1260                         case EDGE_MODE_TAG_CREASE:      
1261                                 me->drawflag |= ME_DRAWCREASES;
1262                                 break;
1263                         case EDGE_MODE_TAG_BEVEL:
1264                                 me->drawflag |= ME_DRAWBWEIGHTS;
1265                                 break;
1266                 }
1267                 
1268                 DAG_id_flush_update(ob->data, OB_RECALC_DATA);
1269                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
1270         }
1271 #endif
1272 }
1273
1274
1275 static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1276 {
1277         
1278         view3d_operator_needs_opengl(C);
1279
1280         mouse_mesh_shortest_path(C, event->mval);
1281         
1282         return OPERATOR_FINISHED;
1283 }
1284         
1285 void MESH_OT_select_shortest_path(wmOperatorType *ot)
1286 {
1287         /* identifiers */
1288         ot->name= "Shortest Path Select";
1289         ot->idname= "MESH_OT_select_shortest_path";
1290         
1291         /* api callbacks */
1292         ot->invoke= mesh_shortest_path_select_invoke;
1293         ot->poll= ED_operator_editmesh;
1294         ot->description= "Select shortest path between two selections.";
1295         
1296         /* flags */
1297         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1298         
1299         /* properties */
1300         RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
1301 }
1302
1303
1304 /* ************************************************** */
1305 /* here actual select happens */
1306 /* gets called via generic mouse select operator */
1307 void mouse_mesh(bContext *C, short mval[2], short extend)
1308 {
1309         ViewContext vc;
1310         BMVert *eve = NULL;
1311         BMEdge *eed = NULL;
1312         BMFace *efa = NULL;
1313         
1314         /* setup view context for argument to callbacks */
1315         em_setup_viewcontext(C, &vc);
1316         vc.mval[0]= mval[0];
1317         vc.mval[1]= mval[1];
1318         
1319         if(unified_findnearest(&vc, &eve, &eed, &efa)) {
1320                 
1321                 if(extend==0) EDBM_clear_flag_all(vc.em, BM_SELECT);
1322                 
1323                 if(efa) {
1324                         /* set the last selected face */
1325                         EDBM_set_actFace(vc.em, efa);
1326                         
1327                         if(!BM_TestHFlag(efa, BM_SELECT)) {
1328                                 EDBM_store_selection(vc.em, efa);
1329                                 BM_Select(vc.em->bm, efa, 1);
1330                         }
1331                         else if(extend) {
1332                                 EDBM_remove_selection(vc.em, efa);
1333                                 BM_Select(vc.em->bm, efa, 0);
1334                         }
1335                 }
1336                 else if(eed) {
1337                         if(!BM_TestHFlag(eed, BM_SELECT)) {
1338                                 EDBM_store_selection(vc.em, eed);
1339                                 BM_Select(vc.em->bm, eed, 1);
1340                         }
1341                         else if(extend) {
1342                                 EDBM_remove_selection(vc.em, eed);
1343                                 BM_Select(vc.em->bm, eed, 0);
1344                         }
1345                 }
1346                 else if(eve) {
1347                         if(!BM_TestHFlag(eve, BM_SELECT)) {
1348                                 EDBM_store_selection(vc.em, eve);
1349                                 BM_Select(vc.em->bm, eve, 1);
1350                         }
1351                         else if(extend){ 
1352                                 EDBM_remove_selection(vc.em, eve);
1353                                 BM_Select(vc.em->bm, eve, 0);
1354                         }
1355                 }
1356                 
1357                 EDBM_selectmode_flush(vc.em);
1358                   
1359 //              if (EM_texFaceCheck()) {
1360
1361                 if (efa && efa->mat_nr != vc.obedit->actcol-1) {
1362                         vc.obedit->actcol= efa->mat_nr+1;
1363                         vc.em->mat_nr= efa->mat_nr;
1364 //                      BIF_preview_changed(ID_MA);
1365                 }
1366         }
1367
1368         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit);
1369 }
1370
1371 static void EDBM_strip_selections(BMEditMesh *em)
1372 {
1373         BMEditSelection *ese, *nextese;
1374
1375         if(!(em->selectmode & SCE_SELECT_VERTEX)){
1376                 ese = em->bm->selected.first;
1377                 while(ese){
1378                         nextese = ese->next; 
1379                         if(ese->type == BM_VERT) BLI_freelinkN(&(em->bm->selected),ese);
1380                         ese = nextese;
1381                 }
1382         }
1383         if(!(em->selectmode & SCE_SELECT_EDGE)){
1384                 ese=em->bm->selected.first;
1385                 while(ese){
1386                         nextese = ese->next;
1387                         if(ese->type == BM_EDGE) BLI_freelinkN(&(em->bm->selected), ese);
1388                         ese = nextese;
1389                 }
1390         }
1391         if(!(em->selectmode & SCE_SELECT_FACE)){
1392                 ese=em->bm->selected.first;
1393                 while(ese){
1394                         nextese = ese->next;
1395                         if(ese->type == BM_FACE) BLI_freelinkN(&(em->bm->selected), ese);
1396                         ese = nextese;
1397                 }
1398         }
1399 }
1400
1401 /* when switching select mode, makes sure selection is consistant for editing */
1402 /* also for paranoia checks to make sure edge or face mode works */
1403 void EDBM_selectmode_set(BMEditMesh *em)
1404 {
1405         BMVert *eve;
1406         BMEdge *eed;
1407         BMFace *efa;
1408         BMIter iter;
1409         
1410         em->bm->selectmode = em->selectmode;
1411
1412         EDBM_strip_selections(em); /*strip BMEditSelections from em->selected that are not relevant to new mode*/
1413         
1414         if(em->selectmode & SCE_SELECT_VERTEX) {
1415                 /*BMIter iter;
1416                 
1417                 eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
1418                 for ( ; eed; eed=BMIter_Step(&iter)) BM_Select(em->bm, eed, 0);
1419                 
1420                 efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
1421                 for ( ; efa; efa=BMIter_Step(&iter)) BM_Select(em->bm, efa, 0);*/
1422
1423                 EDBM_selectmode_flush(em);
1424         }
1425         else if(em->selectmode & SCE_SELECT_EDGE) {
1426                 /* deselect vertices, and select again based on edge select */
1427                 eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
1428                 for ( ; eve; eve=BMIter_Step(&iter)) BM_Select(em->bm, eve, 0);
1429                 
1430                 eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
1431                 for ( ; eed; eed=BMIter_Step(&iter)) {
1432                         if (BM_TestHFlag(eed, BM_SELECT))
1433                                 BM_Select(em->bm, eed, 1);
1434                 }
1435                 
1436                 /* selects faces based on edge status */
1437                 EDBM_selectmode_flush(em);
1438         }
1439         else if(em->selectmode & SCE_SELECT_FACE) {
1440                 /* deselect eges, and select again based on face select */
1441                 eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
1442                 for ( ; eed; eed=BMIter_Step(&iter)) BM_Select(em->bm, eed, 0);
1443                 
1444                 efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
1445                 for ( ; efa; efa=BMIter_Step(&iter)) {
1446                         if (BM_TestHFlag(efa, BM_SELECT))
1447                                 BM_Select(em->bm, efa, 1);
1448                 }
1449         }
1450 }
1451
1452 void EDBM_convertsel(BMEditMesh *em, short oldmode, short selectmode)
1453 {
1454         BMVert *eve;
1455         BMEdge *eed;
1456         BMFace *efa;
1457         BMIter iter;
1458
1459         /*have to find out what the selectionmode was previously*/
1460         if(oldmode == SCE_SELECT_VERTEX) {
1461                 if(selectmode == SCE_SELECT_EDGE) {
1462                         /*select all edges associated with every selected vertex*/
1463                         eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
1464                         for ( ; eed; eed=BMIter_Step(&iter)) {
1465                                 if(BM_TestHFlag(eed->v1, BM_SELECT)) BM_Select(em->bm, eed, 1);
1466                                 else if(BM_TestHFlag(eed->v2, BM_SELECT)) BM_Select(em->bm, eed, 1);
1467                         }
1468                 }               
1469                 else if(selectmode == SCE_SELECT_FACE) {
1470                         BMIter liter;
1471                         BMLoop *l;
1472
1473                         /*select all faces associated with every selected vertex*/
1474                         efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
1475                         for ( ; efa; efa=BMIter_Step(&iter)) {
1476                                 l = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
1477                                 for (; l; l=BMIter_Step(&liter)) {
1478                                         if (BM_TestHFlag(l->v, BM_SELECT)) {
1479                                                 BM_Select(em->bm, efa, 1);
1480                                                 break;
1481                                         }
1482                                 }
1483                         }
1484                 }
1485         }
1486         
1487         if(oldmode == SCE_SELECT_EDGE){
1488                 if(selectmode == SCE_SELECT_FACE) {
1489                         BMIter liter;
1490                         BMLoop *l;
1491
1492                         /*select all faces associated with every selected vertex*/
1493                         efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
1494                         for ( ; efa; efa=BMIter_Step(&iter)) {
1495                                 l = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
1496                                 for (; l; l=BMIter_Step(&liter)) {
1497                                         if (BM_TestHFlag(l->v, BM_SELECT)) {
1498                                                 BM_Select(em->bm, efa, 1);
1499                                                 break;
1500                                         }
1501                                 }
1502                         }
1503                 }
1504         }
1505 }
1506
1507
1508 void EDBM_select_swap(BMEditMesh *em) /* exported for UV */
1509 {
1510         BMIter iter;
1511         BMVert *eve;
1512         BMEdge *eed;
1513         BMFace *efa;
1514         
1515         if(em->bm->selectmode & SCE_SELECT_VERTEX) {
1516                 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
1517                         if (BM_TestHFlag(eve, BM_HIDDEN))
1518                                 continue;
1519                         BM_Select(em->bm, eve, !BM_TestHFlag(eve, BM_SELECT));
1520                 }
1521         }
1522         else if(em->selectmode & SCE_SELECT_EDGE) {
1523                 BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
1524                         if (BM_TestHFlag(eed, BM_HIDDEN))
1525                                 continue;
1526                         BM_Select(em->bm, eed, !BM_TestHFlag(eed, BM_SELECT));
1527                 }
1528         }
1529         else {
1530                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1531                         if (BM_TestHFlag(efa, BM_HIDDEN))
1532                                 continue;
1533                         BM_Select(em->bm, efa, !BM_TestHFlag(efa, BM_SELECT));
1534                 }
1535
1536         }
1537 //      if (EM_texFaceCheck())
1538 }
1539
1540 static int select_inverse_mesh_exec(bContext *C, wmOperator *op)
1541 {
1542         Object *obedit= CTX_data_edit_object(C);
1543         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1544         
1545         EDBM_select_swap(em);
1546         
1547         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1548
1549         return OPERATOR_FINISHED;       
1550 }
1551
1552 void MESH_OT_select_inverse(wmOperatorType *ot)
1553 {
1554         /* identifiers */
1555         ot->name= "Select Inverse";
1556         ot->idname= "MESH_OT_select_inverse";
1557         ot->description= "Select inverse of (un)selected vertices, edges or faces.";
1558         
1559         /* api callbacks */
1560         ot->exec= select_inverse_mesh_exec;
1561         ot->poll= ED_operator_editmesh;
1562         
1563         /* flags */
1564         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1565 }
1566
1567
1568 static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
1569 {
1570         Object *obedit= CTX_data_edit_object(C);
1571         ViewContext vc;
1572         BMWalker walker;
1573         BMEditMesh *em;
1574         BMVert *eve;
1575         BMEdge *e, *eed;
1576         BMFace *efa;
1577         short done=1, toggle=0;
1578         int sel= !RNA_boolean_get(op->ptr, "deselect");
1579         int limit= RNA_boolean_get(op->ptr, "limit");
1580         
1581         /* unified_finednearest needs ogl */
1582         view3d_operator_needs_opengl(C);
1583         
1584         /* setup view context for argument to callbacks */
1585         em_setup_viewcontext(C, &vc);
1586         em = vc.em;
1587
1588         if(vc.em->bm->totedge==0)
1589                 return OPERATOR_CANCELLED;
1590         
1591         vc.mval[0]= event->mval[0];
1592         vc.mval[1]= event->mval[1];
1593         
1594         /* return warning! */
1595
1596         /*if(limit) {
1597                 int retval= select_linked_limited_invoke(&vc, 0, sel);
1598                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1599                 return retval;
1600         }*/
1601         
1602         if( unified_findnearest(&vc, &eve, &eed, &efa)==0 ) {
1603                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1604         
1605                 return OPERATOR_CANCELLED;
1606         }
1607         
1608         if (efa) {
1609                 eed = efa->loopbase->e;
1610         } else if (!eed) {
1611                 if (!eve || !eve->edge)
1612                         return OPERATOR_CANCELLED;
1613                 
1614                 eed = eve->edge;
1615         }
1616
1617         BMW_Init(&walker, em->bm, BMW_SHELL, 0, 0);
1618         e = BMW_Begin(&walker, eed->v1);
1619         for (; e; e=BMW_Step(&walker)) {
1620                         BM_Select(em->bm, e->v1, sel);
1621                         BM_Select(em->bm, e->v2, sel);
1622         }
1623         BMW_End(&walker);
1624         EDBM_select_flush(em, SCE_SELECT_VERTEX);
1625
1626         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1627         return OPERATOR_FINISHED;       
1628 }
1629
1630 void MESH_OT_select_linked_pick(wmOperatorType *ot)
1631 {
1632         /* identifiers */
1633         ot->name= "Select Linked";
1634         ot->idname= "MESH_OT_select_linked_pick";
1635         
1636         /* api callbacks */
1637         ot->invoke= select_linked_pick_invoke;
1638         ot->poll= ED_operator_editmesh;
1639         ot->description= "select/deselect all vertices linked to the edge under the mouse cursor.";
1640         
1641         /* flags */
1642         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1643         
1644         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
1645         RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
1646 }
1647
1648
1649 static int select_linked_exec(bContext *C, wmOperator *op)
1650 {
1651         Object *obedit= CTX_data_edit_object(C);
1652         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
1653         BLI_array_declare(verts);
1654         BMVert **verts = NULL;
1655         BMIter iter;
1656         BMVert *v;
1657         BMEdge *e;
1658         BMWalker walker;
1659         int i, tot;
1660
1661         tot = 0;
1662                 BM_ITER_SELECT(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL)
1663                 if (BM_TestHFlag(v, BM_SELECT)) {
1664                         BLI_array_growone(verts);
1665                         verts[tot++] = v;
1666                 }
1667         }
1668
1669         BMW_Init(&walker, em->bm, BMW_SHELL, 0, 0);
1670         for (i=0; i<tot; i++) {
1671                 e = BMW_Begin(&walker, verts[i]);
1672                 for (; e; e=BMW_Step(&walker)) {
1673                         BM_Select(em->bm, e->v1, 1);
1674                         BM_Select(em->bm, e->v2, 1);
1675                 }
1676         }
1677         BMW_End(&walker);
1678         EDBM_select_flush(em, SCE_SELECT_VERTEX);
1679
1680         BLI_array_free(verts);
1681         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1682
1683         return OPERATOR_FINISHED;       
1684 }
1685
1686 void MESH_OT_select_linked(wmOperatorType *ot)
1687 {
1688         /* identifiers */
1689         ot->name= "Select Linked All";
1690         ot->idname= "MESH_OT_select_linked";
1691         
1692         /* api callbacks */
1693         ot->exec= select_linked_exec;
1694         ot->poll= ED_operator_editmesh;
1695         ot->description= "Select all vertices linked to the active mesh.";
1696         
1697         /* flags */
1698         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1699         
1700         RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
1701 }
1702
1703 /* ******************** **************** */
1704
1705 static int select_more(bContext *C, wmOperator *op)
1706 {
1707         Object *obedit= CTX_data_edit_object(C);
1708         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1709         BMOperator bmop;
1710         int usefaces = em->selectmode > SCE_SELECT_EDGE;
1711
1712         EDBM_InitOpf(em, &bmop, op, "regionextend geom=%hvef constrict=%d usefaces=%d", 
1713                      BM_SELECT, 0, usefaces);
1714
1715         BMO_Exec_Op(em->bm, &bmop);
1716         BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL);
1717
1718         EDBM_selectmode_flush(em);
1719
1720         if (!EDBM_FinishOp(em, &bmop, op, 1))
1721                 return OPERATOR_CANCELLED;
1722
1723         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1724         return OPERATOR_FINISHED;
1725 }
1726
1727 void MESH_OT_select_more(wmOperatorType *ot)
1728 {
1729         /* identifiers */
1730         ot->name= "Select More";
1731         ot->idname= "MESH_OT_select_more";
1732         ot->description= "Select more vertices, edges or faces connected to initial selection.";
1733
1734         /* api callbacks */
1735         ot->exec= select_more;
1736         ot->poll= ED_operator_editmesh;
1737         
1738         /* flags */
1739         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1740 }
1741
1742 static int select_less(bContext *C, wmOperator *op)
1743 {
1744         Object *obedit= CTX_data_edit_object(C);
1745         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1746         BMOperator bmop;
1747         int usefaces = em->selectmode > SCE_SELECT_EDGE;
1748
1749         EDBM_InitOpf(em, &bmop, op, "regionextend geom=%hvef constrict=%d usefaces=%d", 
1750                      BM_SELECT, 1, usefaces);
1751
1752         BMO_Exec_Op(em->bm, &bmop);
1753         BMO_UnHeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL);
1754
1755         EDBM_selectmode_flush(em);
1756
1757         if (!EDBM_FinishOp(em, &bmop, op, 1))
1758                 return OPERATOR_CANCELLED;
1759
1760         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1761         return OPERATOR_FINISHED;
1762 }
1763
1764 void MESH_OT_select_less(wmOperatorType *ot)
1765 {
1766         /* identifiers */
1767         ot->name= "Select Less";
1768         ot->idname= "MESH_OT_select_less";
1769         ot->description= "Deselect vertices, edges or faces at the boundary of each selection region.";
1770
1771         /* api callbacks */
1772         ot->exec= select_less;
1773         ot->poll= ED_operator_editmesh;
1774         
1775         /* flags */
1776         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1777 }