760bb5b65e0bd1839c36fe4942107fb82eb4cc97
[blender-staging.git] / source / blender / editors / mesh / bmesh_select.c
1 /**
2  * $Id: 
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2004 Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 /*
31
32 BMEditMesh_mods.c, UI level access, no geometry changes 
33
34 */
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include <math.h>
39
40 #include "MEM_guardedalloc.h"
41
42 #include "MTC_matrixops.h"
43
44 #include "DNA_mesh_types.h"
45 #include "DNA_material_types.h"
46 #include "DNA_meshdata_types.h"
47 #include "DNA_modifier_types.h"
48 #include "DNA_object_types.h"
49 #include "DNA_texture_types.h"
50 #include "DNA_scene_types.h"
51 #include "DNA_screen_types.h"
52 #include "DNA_space_types.h"
53 #include "DNA_view3d_types.h"
54
55 #include "BLI_blenlib.h"
56 #include "BLI_arithb.h"
57 #include "BLI_rand.h"
58
59 #include "BKE_context.h"
60 #include "BKE_displist.h"
61 #include "BKE_depsgraph.h"
62 #include "BKE_DerivedMesh.h"
63 #include "BKE_customdata.h"
64 #include "BKE_global.h"
65 #include "BKE_mesh.h"
66 #include "BKE_material.h"
67 #include "BKE_texture.h"
68 #include "BKE_utildefines.h"
69 #include "BKE_report.h"
70 #include "BKE_tessmesh.h"
71
72 #include "IMB_imbuf_types.h"
73 #include "IMB_imbuf.h"
74
75 #include "RE_render_ext.h"  /* externtex */
76
77 #include "WM_api.h"
78 #include "WM_types.h"
79
80 #include "RNA_access.h"
81 #include "RNA_define.h"
82
83 #include "ED_mesh.h"
84 #include "ED_screen.h"
85 #include "ED_view3d.h"
86 #include "bmesh.h"
87
88 #include "BIF_gl.h"
89 #include "BIF_glutil.h"
90
91 #include "mesh_intern.h"
92
93 #include "BLO_sys_types.h" // for intptr_t support
94
95 /* XXX */
96 static void waitcursor() {}
97 static int pupmenu() {return 0;}
98
99 /* ****************************** MIRROR **************** */
100
101 void EDBM_select_mirrored(Object *obedit, BMEditMesh *em)
102 {
103 #if 0 //BMESH_TODO
104         if(em->selectmode & SCE_SELECT_VERTEX) {
105                 BMVert *eve, *v1;
106                 
107                 for(eve= em->verts.first; eve; eve= eve->next) {
108                         if(eve->f & SELECT) {
109                                 v1= BMEditMesh_get_x_mirror_vert(obedit, em, eve->co);
110                                 if(v1) {
111                                         eve->f &= ~SELECT;
112                                         v1->f |= SELECT;
113                                 }
114                         }
115                 }
116         }
117 #endif
118 }
119
120 void EDBM_automerge(int update) 
121 {
122 // XXX  int len;
123         
124 //      if ((scene->automerge) &&
125 //              (obedit && obedit->type==OB_MESH) &&
126 //              (((Mesh*)obedit->data)->mr==NULL)
127 //        ) {
128 //              len = removedoublesflag(1, 1, scene->toolsettings->doublimit);
129 //              if (len) {
130 //                      em->totvert -= len; /* saves doing a countall */
131 //                      if (update) {
132 //                              DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
133 //                      }
134 //              }
135 //      }
136 }
137
138 /* ****************************** SELECTION ROUTINES **************** */
139
140 unsigned int bm_solidoffs=0, bm_wireoffs=0, bm_vertoffs=0;      /* set in drawobject.c ... for colorindices */
141
142 /* facilities for border select and circle select */
143 static char *selbuf= NULL;
144
145 /* opengl doesn't support concave... */
146 static void draw_triangulated(short mcords[][2], short tot)
147 {
148         ListBase lb={NULL, NULL};
149         DispList *dl;
150         float *fp;
151         int a;
152         
153         /* make displist */
154         dl= MEM_callocN(sizeof(DispList), "poly disp");
155         dl->type= DL_POLY;
156         dl->parts= 1;
157         dl->nr= tot;
158         dl->verts= fp=  MEM_callocN(tot*3*sizeof(float), "poly verts");
159         BLI_addtail(&lb, dl);
160         
161         for(a=0; a<tot; a++, fp+=3) {
162                 fp[0]= (float)mcords[a][0];
163                 fp[1]= (float)mcords[a][1];
164         }
165         
166         /* do the fill */
167         filldisplist(&lb, &lb);
168
169         /* do the draw */
170         dl= lb.first;   /* filldisplist adds in head of list */
171         if(dl->type==DL_INDEX3) {
172                 int *index;
173                 
174                 a= dl->parts;
175                 fp= dl->verts;
176                 index= dl->index;
177                 glBegin(GL_TRIANGLES);
178                 while(a--) {
179                         glVertex3fv(fp+3*index[0]);
180                         glVertex3fv(fp+3*index[1]);
181                         glVertex3fv(fp+3*index[2]);
182                         index+= 3;
183                 }
184                 glEnd();
185         }
186         
187         freedisplist(&lb);
188 }
189
190
191 /* reads rect, and builds selection array for quick lookup */
192 /* returns if all is OK */
193 int EDBM_init_backbuf_border(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
194 {
195         struct ImBuf *buf;
196         unsigned int *dr;
197         int a;
198         
199         if(vc->obedit==NULL || vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
200         
201         buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
202         if(buf==NULL) return 0;
203         if(bm_vertoffs==0) return 0;
204
205         dr = buf->rect;
206         
207         /* build selection lookup */
208         selbuf= MEM_callocN(bm_vertoffs+1, "selbuf");
209         
210         a= (xmax-xmin+1)*(ymax-ymin+1);
211         while(a--) {
212                 if(*dr>0 && *dr<=bm_vertoffs) 
213                         selbuf[*dr]= 1;
214                 dr++;
215         }
216         IMB_freeImBuf(buf);
217         return 1;
218 }
219
220 int EDBM_check_backbuf(unsigned int index)
221 {
222         if(selbuf==NULL) return 1;
223         if(index>0 && index<=bm_vertoffs)
224                 return selbuf[index];
225         return 0;
226 }
227
228 void EDBM_free_backbuf(void)
229 {
230         if(selbuf) MEM_freeN(selbuf);
231         selbuf= NULL;
232 }
233
234 /* mcords is a polygon mask
235    - grab backbuffer,
236    - draw with black in backbuffer, 
237    - grab again and compare
238    returns 'OK' 
239 */
240 int EDBM_mask_init_backbuf_border(ViewContext *vc, short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
241 {
242         unsigned int *dr, *drm;
243         struct ImBuf *buf, *bufmask;
244         int a;
245         
246         /* method in use for face selecting too */
247         if(vc->obedit==NULL) {
248                 if(FACESEL_PAINT_TEST);
249                 else return 0;
250         }
251         else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
252
253         buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
254         if(buf==NULL) return 0;
255         if(bm_vertoffs==0) return 0;
256
257         dr = buf->rect;
258
259         /* draw the mask */
260         glDisable(GL_DEPTH_TEST);
261         
262         glColor3ub(0, 0, 0);
263         
264         /* yah, opengl doesn't do concave... tsk! */
265         ED_region_pixelspace(vc->ar);
266         draw_triangulated(mcords, tot); 
267         
268         glBegin(GL_LINE_LOOP);  /* for zero sized masks, lines */
269         for(a=0; a<tot; a++) glVertex2s(mcords[a][0], mcords[a][1]);
270         glEnd();
271         
272         glFinish();     /* to be sure readpixels sees mask */
273         
274         /* grab mask */
275         bufmask= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
276         drm = bufmask->rect;
277         if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */
278         
279         /* build selection lookup */
280         selbuf= MEM_callocN(bm_vertoffs+1, "selbuf");
281         
282         a= (xmax-xmin+1)*(ymax-ymin+1);
283         while(a--) {
284                 if(*dr>0 && *dr<=bm_vertoffs && *drm==0) selbuf[*dr]= 1;
285                 dr++; drm++;
286         }
287         IMB_freeImBuf(buf);
288         IMB_freeImBuf(bufmask);
289         return 1;
290         
291 }
292
293 /* circle shaped sample area */
294 int EDBM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads)
295 {
296         struct ImBuf *buf;
297         unsigned int *dr;
298         short xmin, ymin, xmax, ymax, xc, yc;
299         int radsq;
300         
301         /* method in use for face selecting too */
302         if(vc->obedit==NULL) {
303                 if(FACESEL_PAINT_TEST);
304                 else return 0;
305         }
306         else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
307         
308         xmin= xs-rads; xmax= xs+rads;
309         ymin= ys-rads; ymax= ys+rads;
310         buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
311         if(bm_vertoffs==0) return 0;
312         if(buf==NULL) return 0;
313
314         dr = buf->rect;
315         
316         /* build selection lookup */
317         selbuf= MEM_callocN(bm_vertoffs+1, "selbuf");
318         radsq= rads*rads;
319         for(yc= -rads; yc<=rads; yc++) {
320                 for(xc= -rads; xc<=rads; xc++, dr++) {
321                         if(xc*xc + yc*yc < radsq) {
322                                 if(*dr>0 && *dr<=bm_vertoffs) selbuf[*dr]= 1;
323                         }
324                 }
325         }
326
327         IMB_freeImBuf(buf);
328         return 1;
329         
330 }
331
332 static void findnearestvert__doClosest(void *userData, BMVert *eve, int x, int y, int index)
333 {
334         struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; BMVert *closest; } *data = userData;
335
336         if (data->pass==0) {
337                 if (index<=data->lastIndex)
338                         return;
339         } else {
340                 if (index>data->lastIndex)
341                         return;
342         }
343
344         if (data->dist>3) {
345                 int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y);
346                 if (BM_TestHFlag(eve, BM_SELECT) == data->select) {
347                         if (data->strict == 1)
348                                 return;
349                         else
350                                 temp += 5;
351                 }
352
353                 if (temp<data->dist) {
354                         data->dist = temp;
355                         data->closest = eve;
356                         data->closestIndex = index;
357                 }
358         }
359 }
360
361
362
363
364 static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index)
365 {
366         BMEditMesh *em= (BMEditMesh *)handle;
367         BMIter iter;
368         BMVert *eve = BMIter_AtIndex(em->bm, BM_VERTS_OF_MESH, NULL, index-1);
369
370         if(eve && BM_TestHFlag(eve, BM_SELECT)) return 0;
371         return 1; 
372 }
373 /**
374  * findnearestvert
375  * 
376  * dist (in/out): minimal distance to the nearest and at the end, actual distance
377  * sel: selection bias
378  *              if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
379  *              if 0, unselected vertice are given the bias
380  * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased 
381  */
382 BMVert *EDBM_findnearestvert(ViewContext *vc, int *dist, short sel, short strict)
383 {
384         if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)){
385                 int distance;
386                 unsigned int index;
387                 BMVert *eve;
388                 
389                 if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance, strict, vc->em, findnearestvert__backbufIndextest); 
390                 else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance, 0, NULL, NULL); 
391                 
392                 eve = BMIter_AtIndex(vc->em->bm, BM_VERTS_OF_MESH, NULL, index-1);
393                 
394                 if(eve && distance < *dist) {
395                         *dist = distance;
396                         return eve;
397                 } else {
398                         return NULL;
399                 }
400                         
401         }
402         else {
403                 struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; BMVert *closest; } data;
404                 static int lastSelectedIndex=0;
405                 static BMVert *lastSelected=NULL;
406                 
407                 if (lastSelected && BMIter_AtIndex(vc->em->bm, BM_VERTS_OF_MESH, NULL, lastSelectedIndex)!=lastSelected) {
408                         lastSelectedIndex = 0;
409                         lastSelected = NULL;
410                 }
411
412                 data.lastIndex = lastSelectedIndex;
413                 data.mval[0] = vc->mval[0];
414                 data.mval[1] = vc->mval[1];
415                 data.select = sel;
416                 data.dist = *dist;
417                 data.strict = strict;
418                 data.closest = NULL;
419                 data.closestIndex = 0;
420
421                 data.pass = 0;
422                 mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
423
424                 if (data.dist>3) {
425                         data.pass = 1;
426                         mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
427                 }
428
429                 *dist = data.dist;
430                 lastSelected = data.closest;
431                 lastSelectedIndex = data.closestIndex;
432
433                 return data.closest;
434         }
435 }
436
437 /* returns labda for closest distance v1 to line-piece v2-v3 */
438 static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3) 
439 {
440         float rc[2], len;
441         
442         rc[0]= v3[0]-v2[0];
443         rc[1]= v3[1]-v2[1];
444         len= rc[0]*rc[0]+ rc[1]*rc[1];
445         if(len==0.0f)
446                 return 0.0f;
447         
448         return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
449 }
450
451 /* note; uses v3d, so needs active 3d window */
452 static void findnearestedge__doClosest(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index)
453 {
454         struct { ViewContext vc; float mval[2]; int dist; BMEdge *closest; } *data = userData;
455         float v1[2], v2[2];
456         int distance;
457                 
458         v1[0] = x0;
459         v1[1] = y0;
460         v2[0] = x1;
461         v2[1] = y1;
462                 
463         distance= PdistVL2Dfl(data->mval, v1, v2);
464                 
465         if(BM_TestHFlag(eed, BM_SELECT)) distance+=5;
466         if(distance < data->dist) {
467                 if(data->vc.rv3d->rflag & RV3D_CLIPPING) {
468                         float labda= labda_PdistVL2Dfl(data->mval, v1, v2);
469                         float vec[3];
470
471                         vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]);
472                         vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]);
473                         vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]);
474                         Mat4MulVecfl(data->vc.obedit->obmat, vec);
475
476                         if(view3d_test_clipping(data->vc.rv3d, vec)==0) {
477                                 data->dist = distance;
478                                 data->closest = eed;
479                         }
480                 }
481                 else {
482                         data->dist = distance;
483                         data->closest = eed;
484                 }
485         }
486 }
487 BMEdge *EDBM_findnearestedge(ViewContext *vc, int *dist)
488 {
489
490         if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
491                 int distance;
492                 unsigned int index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_solidoffs, bm_wireoffs, &distance,0, NULL, NULL);
493                 BMEdge *eed = BMIter_AtIndex(vc->em->bm, BM_EDGES_OF_MESH, NULL, index-1);
494
495                 if (eed && distance<*dist) {
496                         *dist = distance;
497                         return eed;
498                 } else {
499                         return NULL;
500                 }
501         }
502         else {
503                 struct { ViewContext vc; float mval[2]; int dist; BMEdge *closest; } data;
504
505                 data.vc= *vc;
506                 data.mval[0] = vc->mval[0];
507                 data.mval[1] = vc->mval[1];
508                 data.dist = *dist;
509                 data.closest = NULL;
510
511                 mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, 2);
512
513                 *dist = data.dist;
514                 return data.closest;
515         }
516 }
517
518 static void findnearestface__getDistance(void *userData, BMFace *efa, int x, int y, int index)
519 {
520         struct { short mval[2]; int dist; BMFace *toFace; } *data = userData;
521
522         if (efa==data->toFace) {
523                 int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
524
525                 if (temp<data->dist)
526                         data->dist = temp;
527         }
528 }
529 static void findnearestface__doClosest(void *userData, BMFace *efa, int x, int y, int index)
530 {
531         struct { short mval[2], pass; int dist, lastIndex, closestIndex; BMFace *closest; } *data = userData;
532
533         if (data->pass==0) {
534                 if (index<=data->lastIndex)
535                         return;
536         } else {
537                 if (index>data->lastIndex)
538                         return;
539         }
540
541         if (data->dist>3) {
542                 int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
543
544                 if (temp<data->dist) {
545                         data->dist = temp;
546                         data->closest = efa;
547                         data->closestIndex = index;
548                 }
549         }
550 }
551 static BMFace *EDBM_findnearestface(ViewContext *vc, int *dist)
552 {
553
554         if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
555                 unsigned int index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]);
556                 BMFace *efa = BMIter_AtIndex(vc->em->bm, BM_FACES_OF_MESH, NULL, index-1);
557
558                 if (efa) {
559                         struct { short mval[2]; int dist; BMFace *toFace; } data;
560
561                         data.mval[0] = vc->mval[0];
562                         data.mval[1] = vc->mval[1];
563                         data.dist = 0x7FFF;             /* largest short */
564                         data.toFace = efa;
565
566                         mesh_foreachScreenFace(vc, findnearestface__getDistance, &data);
567
568                         if(vc->em->selectmode == SCE_SELECT_FACE || data.dist<*dist) {  /* only faces, no dist check */
569                                 *dist= data.dist;
570                                 return efa;
571                         }
572                 }
573                 
574                 return NULL;
575         }
576         else {
577                 struct { short mval[2], pass; int dist, lastIndex, closestIndex; BMFace *closest; } data;
578                 static int lastSelectedIndex=0;
579                 static BMFace *lastSelected=NULL;
580
581                 if (lastSelected && BMIter_AtIndex(vc->em->bm, BM_FACES_OF_MESH, NULL, lastSelectedIndex)!=lastSelected) {
582                         lastSelectedIndex = 0;
583                         lastSelected = NULL;
584                 }
585
586                 data.lastIndex = lastSelectedIndex;
587                 data.mval[0] = vc->mval[0];
588                 data.mval[1] = vc->mval[1];
589                 data.dist = *dist;
590                 data.closest = NULL;
591                 data.closestIndex = 0;
592
593                 data.pass = 0;
594                 mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
595
596                 if (data.dist>3) {
597                         data.pass = 1;
598                         mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
599                 }
600
601                 *dist = data.dist;
602                 lastSelected = data.closest;
603                 lastSelectedIndex = data.closestIndex;
604
605                 return data.closest;
606         }
607 }
608
609 /* best distance based on screen coords. 
610    use em->selectmode to define how to use 
611    selected vertices and edges get disadvantage
612    return 1 if found one
613 */
614 static int unified_findnearest(ViewContext *vc, BMVert **eve, BMEdge **eed, BMFace **efa) 
615 {
616         BMEditMesh *em= vc->em;
617         int dist= 75;
618         
619         *eve= NULL;
620         *eed= NULL;
621         *efa= NULL;
622         
623         /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
624         view3d_validate_backbuf(vc);
625         
626         if(em->selectmode & SCE_SELECT_VERTEX)
627                 *eve= EDBM_findnearestvert(vc, &dist, BM_SELECT, 0);
628         if(em->selectmode & SCE_SELECT_FACE)
629                 *efa= EDBM_findnearestface(vc, &dist);
630
631         dist-= 20;      /* since edges select lines, we give dots advantage of 20 pix */
632         if(em->selectmode & SCE_SELECT_EDGE)
633                 *eed= EDBM_findnearestedge(vc, &dist);
634
635         /* return only one of 3 pointers, for frontbuffer redraws */
636         if(*eed) {
637                 *efa= NULL; *eve= NULL;
638         }
639         else if(*efa) {
640                 *eve= NULL;
641         }
642         
643         return (*eve || *eed || *efa);
644 }
645
646
647 /* ****************  SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
648
649 /* selects new faces/edges/verts based on the
650  existing selection
651
652 FACES GROUP
653  mode 1: same material
654  mode 2: same image
655  mode 3: same area
656  mode 4: same perimeter
657  mode 5: same normal
658  mode 6: same co-planer
659 */
660
661 static EnumPropertyItem prop_simface_types[] = {
662         {1, "MATERIAL", 0, "Material", ""},
663         {2, "IMAGE", 0, "Image", ""},
664         {3, "AREA", 0, "Area", ""},
665         {4, "PERIMETER", 0, "Perimeter", ""},
666         {5, "NORMAL", 0, "Normal", ""},
667         {6, "COPLANAR", 0, "Co-planar", ""},
668         {0, NULL, 0, NULL, NULL}
669 };
670
671
672 /* this as a way to compare the ares, perim  of 2 faces thay will scale to different sizes
673 *0.5 so smaller faces arnt ALWAYS selected with a thresh of 1.0 */
674 #define SCALE_CMP(a,b) ((a+a*thresh >= b) && (a-(a*thresh*0.5) <= b))
675
676 static int similar_face_select__internal(Scene *scene, BMEditMesh *em, int mode)
677 {
678 #if 0 //BMESH_TODO
679         BMFace *efa, *base_efa=NULL;
680         unsigned int selcount=0; /*count how many new faces we select*/
681         
682         /*deselcount, count how many deselected faces are left, so we can bail out early
683         also means that if there are no deselected faces, we can avoid a lot of looping */
684         unsigned int deselcount=0; 
685         float thresh= scene->toolsettings->select_thresh;
686         short ok=0;
687         
688         for(efa= em->faces.first; efa; efa= efa->next) {
689                 if (!efa->h) {
690                         if (efa->f & SELECT) {
691                                 efa->f1=1;
692                                 ok=1;
693                         } else {
694                                 efa->f1=0;
695                                 deselcount++; /* a deselected face we may select later */
696                         }
697                 }
698         }
699         
700         if (!ok || !deselcount) /* no data selected OR no more data to select */
701                 return 0;
702         
703         /*if mode is 3 then record face areas, 4 record perimeter */
704         if (mode==3) {
705                 for(efa= em->faces.first; efa; efa= efa->next) {
706                         efa->tmp.fp= EM_face_area(efa);
707                 }
708         } else if (mode==4) {
709                 for(efa= em->faces.first; efa; efa= efa->next) {
710                         efa->tmp.fp= EM_face_perimeter(efa);
711                 }
712         }
713         
714         for(base_efa= em->faces.first; base_efa; base_efa= base_efa->next) {
715                 if (base_efa->f1) { /* This was one of the faces originaly selected */
716                         if (mode==1) { /* same material */
717                                 for(efa= em->faces.first; efa; efa= efa->next) {
718                                         if (
719                                                 !(efa->f & SELECT) &&
720                                                 !efa->h &&
721                                                 base_efa->mat_nr == efa->mat_nr
722                                         ) {
723                                                 EM_select_face(efa, 1);
724                                                 selcount++;
725                                                 deselcount--;
726                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
727                                                         return selcount;
728                                         }
729                                 }
730                         } else if (mode==2) { /* same image */
731                                 MTFace *tf, *base_tf;
732
733                                 base_tf = (MTFace*)CustomData_em_get(&em->fdata, base_efa->data,
734                                                                      CD_MTFACE);
735
736                                 if(!base_tf)
737                                         return selcount;
738
739                                 for(efa= em->faces.first; efa; efa= efa->next) {
740                                         if (!(efa->f & SELECT) && !efa->h) {
741                                                 tf = (MTFace*)CustomData_em_get(&em->fdata, efa->data,
742                                                                                 CD_MTFACE);
743
744                                                 if(base_tf->tpage == tf->tpage) {
745                                                         EM_select_face(efa, 1);
746                                                         selcount++;
747                                                         deselcount--;
748                                                         if (!deselcount) /*have we selected all posible faces?, if so return*/
749                                                                 return selcount;
750                                                 }
751                                         }
752                                 }
753                         } else if (mode==3 || mode==4) { /* same area OR same perimeter, both use the same temp var */
754                                 for(efa= em->faces.first; efa; efa= efa->next) {
755                                         if (
756                                                 (!(efa->f & SELECT) && !efa->h) &&
757                                                 SCALE_CMP(base_efa->tmp.fp, efa->tmp.fp)
758                                         ) {
759                                                 EM_select_face(efa, 1);
760                                                 selcount++;
761                                                 deselcount--;
762                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
763                                                         return selcount;
764                                         }
765                                 }
766                         } else if (mode==5) { /* same normal */
767                                 float angle;
768                                 for(efa= em->faces.first; efa; efa= efa->next) {
769                                         if (!(efa->f & SELECT) && !efa->h) {
770                                                 angle= VecAngle2(base_efa->n, efa->n);
771                                                 if (angle/180.0<=thresh) {
772                                                         EM_select_face(efa, 1);
773                                                         selcount++;
774                                                         deselcount--;
775                                                         if (!deselcount) /*have we selected all posible faces?, if so return*/
776                                                                 return selcount;
777                                                 }
778                                         }
779                                 }
780                         } else if (mode==6) { /* same planer */
781                                 float angle, base_dot, dot;
782                                 base_dot= Inpf(base_efa->cent, base_efa->n);
783                                 for(efa= em->faces.first; efa; efa= efa->next) {
784                                         if (!(efa->f & SELECT) && !efa->h) {
785                                                 angle= VecAngle2(base_efa->n, efa->n);
786                                                 if (angle/180.0<=thresh) {
787                                                         dot=Inpf(efa->cent, base_efa->n);
788                                                         if (fabs(base_dot-dot) <= thresh) {
789                                                                 EM_select_face(efa, 1);
790                                                                 selcount++;
791                                                                 deselcount--;
792                                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
793                                                                         return selcount;
794                                                         }
795                                                 }
796                                         }
797                                 }
798                         }
799                 }
800         } /* end base_efa loop */
801         return selcount;
802 #endif
803 }
804
805 /* ***************************************************** */
806
807 /* ****************  LOOP SELECTS *************** */
808 static void walker_select(BMEditMesh *em, int walkercode, void *start, int select)
809 {
810         BMesh *bm = em->bm;
811         BMHeader *h;
812         BMWalker walker;
813
814         BMW_Init(&walker, bm, walkercode, 0);
815         h = BMW_Begin(&walker, start);
816         for (; h; h=BMW_Step(&walker)) {
817                 BM_Select(bm, h, select);
818         }
819         BMW_End(&walker);
820 }
821
822 #if 0
823 /* selects quads in loop direction of indicated edge */
824 /* only flush over edges with valence <= 2 */
825 void faceloop_select(EditMesh *em, EditEdge *startedge, int select)
826 {
827         EditEdge *eed;
828         EditFace *efa;
829         int looking= 1;
830         
831         /* in eed->f1 we put the valence (amount of faces in edge) */
832         /* in eed->f2 we put tagged flag as correct loop */
833         /* in efa->f1 we put tagged flag as correct to select */
834
835         for(eed= em->edges.first; eed; eed= eed->next) {
836                 eed->f1= 0;
837                 eed->f2= 0;
838         }
839         for(efa= em->faces.first; efa; efa= efa->next) {
840                 efa->f1= 0;
841                 if(efa->h==0) {
842                         efa->e1->f1++;
843                         efa->e2->f1++;
844                         efa->e3->f1++;
845                         if(efa->e4) efa->e4->f1++;
846                 }
847         }
848         
849         /* tag startedge OK*/
850         startedge->f2= 1;
851         
852         while(looking) {
853                 looking= 0;
854                 
855                 for(efa= em->faces.first; efa; efa= efa->next) {
856                         if(efa->h==0 && efa->e4 && efa->f1==0) {        /* not done quad */
857                                 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
858
859                                         /* if edge tagged, select opposing edge and mark face ok */
860                                         if(efa->e1->f2) {
861                                                 efa->e3->f2= 1;
862                                                 efa->f1= 1;
863                                                 looking= 1;
864                                         }
865                                         else if(efa->e2->f2) {
866                                                 efa->e4->f2= 1;
867                                                 efa->f1= 1;
868                                                 looking= 1;
869                                         }
870                                         if(efa->e3->f2) {
871                                                 efa->e1->f2= 1;
872                                                 efa->f1= 1;
873                                                 looking= 1;
874                                         }
875                                         if(efa->e4->f2) {
876                                                 efa->e2->f2= 1;
877                                                 efa->f1= 1;
878                                                 looking= 1;
879                                         }
880                                 }
881                         }
882                 }
883         }
884         
885         /* (de)select the faces */
886         if(select!=2) {
887                 for(efa= em->faces.first; efa; efa= efa->next) {
888                         if(efa->f1) EM_select_face(efa, select);
889                 }
890         }
891 }
892 #endif
893
894
895 /* selects or deselects edges that:
896 - if edges has 2 faces:
897         - has vertices with valence of 4
898         - not shares face with previous edge
899 - if edge has 1 face:
900         - has vertices with valence 4
901         - not shares face with previous edge
902         - but also only 1 face
903 - if edge no face:
904         - has vertices with valence 2
905 */
906
907 /* 
908    Almostly exactly the same code as faceloop select
909 */
910 static void edgering_select(BMEditMesh *em, BMEdge *startedge, int select)
911 {
912 #if 0 //BMESH_TODO
913         BMEdge *eed;
914         BMFace *efa;
915         int looking= 1;
916         
917         /* in eed->f1 we put the valence (amount of faces in edge) */
918         /* in eed->f2 we put tagged flag as correct loop */
919         /* in efa->f1 we put tagged flag as correct to select */
920
921         for(eed= em->edges.first; eed; eed= eed->next) {
922                 eed->f1= 0;
923                 eed->f2= 0;
924         }
925         for(efa= em->faces.first; efa; efa= efa->next) {
926                 efa->f1= 0;
927                 if(efa->h==0) {
928                         efa->e1->f1++;
929                         efa->e2->f1++;
930                         efa->e3->f1++;
931                         if(efa->e4) efa->e4->f1++;
932                 }
933         }
934         
935         /* tag startedge OK */
936         startedge->f2= 1;
937         
938         while(looking) {
939                 looking= 0;
940                 
941                 for(efa= em->faces.first; efa; efa= efa->next) {
942                         if(efa->e4 && efa->f1==0 && !efa->h) {  /* not done quad */
943                                 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
944
945                                         /* if edge tagged, select opposing edge and mark face ok */
946                                         if(efa->e1->f2) {
947                                                 efa->e3->f2= 1;
948                                                 efa->f1= 1;
949                                                 looking= 1;
950                                         }
951                                         else if(efa->e2->f2) {
952                                                 efa->e4->f2= 1;
953                                                 efa->f1= 1;
954                                                 looking= 1;
955                                         }
956                                         if(efa->e3->f2) {
957                                                 efa->e1->f2= 1;
958                                                 efa->f1= 1;
959                                                 looking= 1;
960                                         }
961                                         if(efa->e4->f2) {
962                                                 efa->e2->f2= 1;
963                                                 efa->f1= 1;
964                                                 looking= 1;
965                                         }
966                                 }
967                         }
968                 }
969         }
970         
971         /* (de)select the edges */
972         for(eed= em->edges.first; eed; eed= eed->next) {
973                 if(eed->f2) EM_select_edge(eed, select);
974         }
975 #endif
976 }
977
978 static int loop_multiselect(bContext *C, wmOperator *op)
979 {
980 #if 0 //BMESH_TODO
981         Object *obedit= CTX_data_edit_object(C);
982         BMEditMesh *em= EM_GetBMEditMesh(((Mesh *)obedit->data));
983         BMEdge *eed;
984         BMEdge **edarray;
985         int edindex, edfirstcount;
986         int looptype= RNA_boolean_get(op->ptr, "ring");
987         
988         /* sets em->totedgesel */
989         EM_nedges_selected(em);
990         
991         edarray = MEM_mallocN(sizeof(BMEdge*)*em->totedgesel,"edge array");
992         edindex = 0;
993         edfirstcount = em->totedgesel;
994         
995         for(eed=em->edges.first; eed; eed=eed->next){
996                 if(eed->f&SELECT){
997                         edarray[edindex] = eed;
998                         edindex += 1;
999                 }
1000         }
1001         
1002         if(looptype){
1003                 for(edindex = 0; edindex < edfirstcount; edindex +=1){
1004                         eed = edarray[edindex];
1005                         edgering_select(em, eed,SELECT);
1006                 }
1007                 EM_selectmode_flush(em);
1008         }
1009         else{
1010                 for(edindex = 0; edindex < edfirstcount; edindex +=1){
1011                         eed = edarray[edindex];
1012                         edgeloop_select(em, eed,SELECT);
1013                 }
1014                 EM_selectmode_flush(em);
1015         }
1016         MEM_freeN(edarray);
1017 //      if (EM_texFaceCheck())
1018         
1019         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1020
1021         EM_EndBMEditMesh(obedit->data, em);
1022 #endif
1023         return OPERATOR_FINISHED;       
1024 }
1025
1026 void MESH_OT_loop_multi_select(wmOperatorType *ot)
1027 {
1028         /* identifiers */
1029         ot->name= "Multi Select Loops";
1030         ot->idname= "MESH_OT_loop_multi_select";
1031         
1032         /* api callbacks */
1033         ot->exec= loop_multiselect;
1034         ot->poll= ED_operator_editmesh;
1035         
1036         /* flags */
1037         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1038         
1039         /* properties */
1040         RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
1041 }
1042
1043                 
1044 /* ***************** MAIN MOUSE SELECTION ************** */
1045
1046
1047 /* ***************** loop select (non modal) ************** */
1048
1049 static void mouse_mesh_loop(bContext *C, short mval[2], short extend, short ring)
1050 {
1051         ViewContext vc;
1052         BMEditMesh *em;
1053         BMEdge *eed;
1054         int select= 1;
1055         int dist= 50;
1056         
1057         em_setup_viewcontext(C, &vc);
1058         vc.mval[0]= mval[0];
1059         vc.mval[1]= mval[1];
1060         em= vc.em;
1061         
1062         eed= EDBM_findnearestedge(&vc, &dist);
1063         if(eed) {
1064                 if(extend==0) EDBM_clear_flag_all(em, BM_SELECT);
1065         
1066                 if(BM_TestHFlag(em, BM_SELECT)==0) select=1;
1067                 else if(extend) select=0;
1068
1069                 if(em->selectmode & SCE_SELECT_FACE) {
1070                         walker_select(em, BMW_FACELOOP, eed, select);
1071                 }
1072                 else if(em->selectmode & SCE_SELECT_EDGE) {
1073                         if(ring)
1074                                 edgering_select(em, eed, select);
1075                         else
1076                                 walker_select(em, BMW_LOOP, eed, select);
1077                 }
1078                 else if(em->selectmode & SCE_SELECT_VERTEX) {
1079                         if(ring)
1080                                 edgering_select(em, eed, select);
1081                         else 
1082                                 walker_select(em, BMW_LOOP, eed, select);
1083                 }
1084
1085                 EDBM_selectmode_flush(em);
1086 //                      if (EM_texFaceCheck())
1087                 
1088                 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
1089         }
1090 }
1091
1092 static int mesh_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
1093 {
1094         
1095         view3d_operator_needs_opengl(C);
1096         
1097         mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"),
1098                                         RNA_boolean_get(op->ptr, "ring"));
1099         
1100         /* cannot do tweaks for as long this keymap is after transform map */
1101         return OPERATOR_FINISHED;
1102 }
1103
1104 void MESH_OT_loop_select(wmOperatorType *ot)
1105 {
1106         /* identifiers */
1107         ot->name= "Loop Select";
1108         ot->idname= "MESH_OT_loop_select";
1109         
1110         /* api callbacks */
1111         ot->invoke= mesh_select_loop_invoke;
1112         ot->poll= ED_operator_editmesh;
1113         
1114         /* flags */
1115         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1116         
1117         /* properties */
1118         RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
1119         RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "");
1120 }
1121
1122 /* ******************* mesh shortest path select, uses prev-selected edge ****************** */
1123
1124 /* since you want to create paths with multiple selects, it doesn't have extend option */
1125 static void mouse_mesh_shortest_path(bContext *C, short mval[2])
1126 {
1127 #if 0 //BMESH_TODO
1128         ViewContext vc;
1129         BMEditMesh *em;
1130         BMEdge *eed;
1131         int dist= 50;
1132         
1133         em_setup_viewcontext(C, &vc);
1134         vc.mval[0]= mval[0];
1135         vc.mval[1]= mval[1];
1136         em= vc.em;
1137         
1138         eed= findnearestedge(&vc, &dist);
1139         if(eed) {
1140                 Mesh *me= vc.obedit->data;
1141                 int path = 0;
1142                 
1143                 if (em->bm->selected.last) {
1144                         EditSelection *ese = em->bm->selected.last;
1145                         
1146                         if(ese && ese->type == BMEdge) {
1147                                 BMEdge *eed_act;
1148                                 eed_act = (BMEdge*)ese->data;
1149                                 if (eed_act != eed) {
1150                                         if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) {
1151                                                 EM_remove_selection(em, eed_act, BMEdge);
1152                                                 path = 1;
1153                                         }
1154                                 }
1155                         }
1156                 }
1157                 if (path==0) {
1158                         int act = (edgetag_context_check(vc.scene, eed)==0);
1159                         edgetag_context_set(vc.scene, eed, act); /* switch the edge option */
1160                 }
1161                 
1162                 EM_selectmode_flush(em);
1163
1164                 /* even if this is selected it may not be in the selection list */
1165                 if(edgetag_context_check(vc.scene, eed)==0)
1166                         EDBM_remove_selection(em, eed);
1167                 else
1168                         EDBM_store_selection(em, eed);
1169         
1170                 /* force drawmode for mesh */
1171                 switch (vc.scene->toolsettings->edge_mode) {
1172                         
1173                         case EDGE_MODE_TAG_SEAM:
1174                                 me->drawflag |= ME_DRAWSEAMS;
1175                                 break;
1176                         case EDGE_MODE_TAG_SHARP:
1177                                 me->drawflag |= ME_DRAWSHARP;
1178                                 break;
1179                         case EDGE_MODE_TAG_CREASE:      
1180                                 me->drawflag |= ME_DRAWCREASES;
1181                                 break;
1182                         case EDGE_MODE_TAG_BEVEL:
1183                                 me->drawflag |= ME_DRAWBWEIGHTS;
1184                                 break;
1185                 }
1186                 
1187                 DAG_object_flush_update(vc.scene, vc.obedit, OB_RECALC_DATA);
1188         
1189                 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
1190         }
1191 #endif
1192 }
1193
1194
1195 static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1196 {
1197         
1198         view3d_operator_needs_opengl(C);
1199
1200         mouse_mesh_shortest_path(C, event->mval);
1201         
1202         return OPERATOR_FINISHED;
1203 }
1204         
1205 void MESH_OT_select_shortest_path(wmOperatorType *ot)
1206 {
1207         /* identifiers */
1208         ot->name= "Shortest Path Select";
1209         ot->idname= "MESH_OT_select_shortest_path";
1210         
1211         /* api callbacks */
1212         ot->invoke= mesh_shortest_path_select_invoke;
1213         ot->poll= ED_operator_editmesh;
1214         
1215         /* flags */
1216         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1217         
1218         /* properties */
1219         RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
1220 }
1221
1222
1223 /* ************************************************** */
1224 /* here actual select happens */
1225 /* gets called via generic mouse select operator */
1226 void mouse_mesh(bContext *C, short mval[2], short extend)
1227 {
1228         ViewContext vc;
1229         BMVert *eve = NULL;
1230         BMEdge *eed = NULL;
1231         BMFace *efa = NULL;
1232         
1233         /* setup view context for argument to callbacks */
1234         em_setup_viewcontext(C, &vc);
1235         vc.mval[0]= mval[0];
1236         vc.mval[1]= mval[1];
1237         
1238         if(unified_findnearest(&vc, &eve, &eed, &efa)) {
1239                 
1240                 if(extend==0) EDBM_clear_flag_all(vc.em, BM_SELECT);
1241                 
1242                 if(efa) {
1243                         /* set the last selected face */
1244                         EDBM_set_actFace(vc.em, efa);
1245                         
1246                         if(!BM_TestHFlag(efa, BM_SELECT)) {
1247                                 EDBM_store_selection(vc.em, efa);
1248                                 BM_Select(vc.em->bm, efa, 1);
1249                         }
1250                         else if(extend) {
1251                                 EDBM_remove_selection(vc.em, efa);
1252                                 BM_Select(vc.em->bm, efa, 1);
1253                         }
1254                 }
1255                 else if(eed) {
1256                         if(!BM_TestHFlag(eed, BM_SELECT)) {
1257                                 EDBM_store_selection(vc.em, eed);
1258                                 BM_Select(vc.em->bm, eed, 1);
1259                         }
1260                         else if(extend) {
1261                                 EDBM_remove_selection(vc.em, eed);
1262                                 BM_Select(vc.em->bm, eed, 0);
1263                         }
1264                 }
1265                 else if(eve) {
1266                         if(!BM_TestHFlag(eve, BM_SELECT)) {
1267                                 EDBM_store_selection(vc.em, eve);
1268                                 BM_Select(vc.em->bm, eve, 1);
1269                         }
1270                         else if(extend){ 
1271                                 EDBM_remove_selection(vc.em, eve);
1272                                 BM_Select(vc.em->bm, eve, 0);
1273                         }
1274                 }
1275                 
1276                 EDBM_selectmode_flush(vc.em);
1277                   
1278 //              if (EM_texFaceCheck()) {
1279
1280                 if (efa && efa->mat_nr != vc.obedit->actcol-1) {
1281                         vc.obedit->actcol= efa->mat_nr+1;
1282                         vc.em->mat_nr= efa->mat_nr;
1283 //                      BIF_preview_changed(ID_MA);
1284                 }
1285         }
1286
1287         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
1288 }
1289
1290 static void EDBM_strip_selections(BMEditMesh *em)
1291 {
1292         BMEditSelection *ese, *nextese;
1293
1294         if(!(em->selectmode & SCE_SELECT_VERTEX)){
1295                 ese = em->bm->selected.first;
1296                 while(ese){
1297                         nextese = ese->next; 
1298                         if(ese->type == BM_VERT) BLI_freelinkN(&(em->bm->selected),ese);
1299                         ese = nextese;
1300                 }
1301         }
1302         if(!(em->selectmode & SCE_SELECT_EDGE)){
1303                 ese=em->bm->selected.first;
1304                 while(ese){
1305                         nextese = ese->next;
1306                         if(ese->type == BM_EDGE) BLI_freelinkN(&(em->bm->selected), ese);
1307                         ese = nextese;
1308                 }
1309         }
1310         if(!(em->selectmode & SCE_SELECT_FACE)){
1311                 ese=em->bm->selected.first;
1312                 while(ese){
1313                         nextese = ese->next;
1314                         if(ese->type == BM_FACE) BLI_freelinkN(&(em->bm->selected), ese);
1315                         ese = nextese;
1316                 }
1317         }
1318 }
1319
1320 /* when switching select mode, makes sure selection is consistant for editing */
1321 /* also for paranoia checks to make sure edge or face mode works */
1322 void EDBM_selectmode_set(BMEditMesh *em)
1323 {
1324         BMVert *eve;
1325         BMEdge *eed;
1326         BMFace *efa;
1327         BMIter iter;
1328         
1329         em->bm->selectmode = em->selectmode;
1330
1331         EDBM_strip_selections(em); /*strip BMEditSelections from em->selected that are not relevant to new mode*/
1332         
1333         if(em->selectmode & SCE_SELECT_VERTEX) {
1334                 BMIter iter;
1335                 
1336                 /*eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
1337                 for ( ; eed; eed=BMIter_Step(&iter)) BM_Select(em->bm, eed, 0);
1338                 
1339                 efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
1340                 for ( ; efa; efa=BMIter_Step(&iter)) BM_Select(em->bm, efa, 0);*/
1341
1342                 EDBM_selectmode_flush(em);
1343         }
1344         else if(em->selectmode & SCE_SELECT_EDGE) {
1345                 /* deselect vertices, and select again based on edge select */
1346                 eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
1347                 for ( ; eve; eve=BMIter_Step(&iter)) BM_Select(em->bm, eve, 0);
1348                 
1349                 eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
1350                 for ( ; eed; eed=BMIter_Step(&iter)) {
1351                         if (BM_TestHFlag(eed, BM_SELECT))
1352                                 BM_Select(em->bm, eed, 1);
1353                 }
1354                 
1355                 /* selects faces based on edge status */
1356                 EDBM_selectmode_flush(em);
1357         }
1358         else if(em->selectmode & SCE_SELECT_FACE) {
1359                 /* deselect eges, and select again based on face select */
1360                 eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
1361                 for ( ; eed; eed=BMIter_Step(&iter)) BM_Select(em->bm, eed, 0);
1362                 
1363                 efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
1364                 for ( ; efa; efa=BMIter_Step(&iter)) {
1365                         if (BM_TestHFlag(efa, BM_SELECT))
1366                                 BM_Select(em->bm, efa, 1);
1367                 }
1368         }
1369 }
1370
1371 void EDBM_convertsel(BMEditMesh *em, short oldmode, short selectmode)
1372 {
1373         BMVert *eve;
1374         BMEdge *eed;
1375         BMFace *efa;
1376         BMIter iter;
1377
1378         /*have to find out what the selectionmode was previously*/
1379         if(oldmode == SCE_SELECT_VERTEX) {
1380                 if(selectmode == SCE_SELECT_EDGE) {
1381                         /*select all edges associated with every selected vertex*/
1382                         eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
1383                         for ( ; eed; eed=BMIter_Step(&iter)) {
1384                                 if(BM_TestHFlag(eed->v1, BM_SELECT)) BM_Select(em->bm, eed, 1);
1385                                 else if(BM_TestHFlag(eed->v2, BM_SELECT)) BM_Select(em->bm, eed, 1);
1386                         }
1387                 }               
1388                 else if(selectmode == SCE_SELECT_FACE) {
1389                         BMIter liter;
1390                         BMLoop *l;
1391
1392                         /*select all faces associated with every selected vertex*/
1393                         efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
1394                         for ( ; efa; efa=BMIter_Step(&iter)) {
1395                                 l = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
1396                                 for (; l; l=BMIter_Step(&liter)) {
1397                                         if (BM_TestHFlag(l->v, BM_SELECT)) {
1398                                                 BM_Select(em->bm, efa, 1);
1399                                                 break;
1400                                         }
1401                                 }
1402                         }
1403                 }
1404         }
1405         
1406         if(oldmode == SCE_SELECT_EDGE){
1407                 if(selectmode == SCE_SELECT_FACE) {
1408                         BMIter liter;
1409                         BMLoop *l;
1410
1411                         /*select all faces associated with every selected vertex*/
1412                         efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
1413                         for ( ; efa; efa=BMIter_Step(&iter)) {
1414                                 l = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
1415                                 for (; l; l=BMIter_Step(&liter)) {
1416                                         if (BM_TestHFlag(l->v, BM_SELECT)) {
1417                                                 BM_Select(em->bm, efa, 1);
1418                                                 break;
1419                                         }
1420                                 }
1421                         }
1422                 }
1423         }
1424 }