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