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