Two in one:
[blender.git] / source / blender / src / editmesh_mods.c
index 7ea473f23fcaba285d61b9d8dc6ad157b7e8881f..5944c77e045fe2aab415ac3ac2b226b7dad560d9 100644 (file)
@@ -62,12 +62,17 @@ editmesh_mods.c, UI level access, no geometry changes
 #include "BKE_displist.h"
 #include "BKE_depsgraph.h"
 #include "BKE_DerivedMesh.h"
+#include "BKE_customdata.h"
 #include "BKE_global.h"
 #include "BKE_mesh.h"
 #include "BKE_material.h"
 #include "BKE_texture.h"
 #include "BKE_utildefines.h"
 
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#endif
+
 #include "BIF_editmesh.h"
 #include "BIF_resources.h"
 #include "BIF_gl.h"
@@ -81,6 +86,10 @@ editmesh_mods.c, UI level access, no geometry changes
 #include "BIF_space.h"
 #include "BIF_toolbox.h"
 
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
+
 #include "BDR_drawobject.h"
 #include "BDR_editobject.h"
 
@@ -91,8 +100,9 @@ editmesh_mods.c, UI level access, no geometry changes
 #include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
 
-#include "RE_render_ext.h"  // externtex
+#include "RE_render_ext.h"  /* externtex */
 
+#include "multires.h"
 #include "mydevice.h"
 #include "blendef.h"
 
@@ -121,7 +131,7 @@ void EM_select_mirrored(void)
 
 /* ****************************** SELECTION ROUTINES **************** */
 
-unsigned int em_solidoffs=0, em_wireoffs=0, em_vertoffs=0;     // set in drawobject.c ... for colorindices
+unsigned int em_solidoffs=0, em_wireoffs=0, em_vertoffs=0;     /* set in drawobject.c ... for colorindices */
 
 /* facilities for border select and circle select */
 static char *selbuf= NULL;
@@ -151,7 +161,7 @@ static void draw_triangulated(short mcords[][2], short tot)
        filldisplist(&lb, &lb);
 
        /* do the draw */
-       dl= lb.first;   // filldisplist adds in head of list
+       dl= lb.first;   /* filldisplist adds in head of list */
        if(dl->type==DL_INDEX3) {
                int *index;
                
@@ -253,19 +263,19 @@ int EM_mask_init_backbuf_border(short mcords[][2], short tot, short xmin, short
        /* yah, opengl doesn't do concave... tsk! */
        draw_triangulated(mcords, tot); 
        
-       glBegin(GL_LINE_LOOP);  // for zero sized masks, lines
+       glBegin(GL_LINE_LOOP);  /* for zero sized masks, lines */
        for(a=0; a<tot; a++) glVertex2s(mcords[a][0], mcords[a][1]);
        glEnd();
        
        persp(PERSP_VIEW);
-       glFinish();     // to be sure readpixels sees mask
+       glFinish();     /* to be sure readpixels sees mask */
        
        glDrawBuffer(GL_BACK);
        
        /* grab mask */
        bufmask= read_backbuf(xmin, ymin, xmax, ymax);
        drm = bufmask->rect;
-       if(bufmask==NULL) return 0; // only when mem alloc fails, go crash somewhere else!
+       if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */
        
        /* build selection lookup */
        selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
@@ -322,7 +332,7 @@ int EM_init_backbuf_circle(short xs, short ys, short rads)
 
 static void findnearestvert__doClosest(void *userData, EditVert *eve, int x, int y, int index)
 {
-       struct { short mval[2], pass, select; int dist, lastIndex, closestIndex; EditVert *closest; } *data = userData;
+       struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } *data = userData;
 
        if (data->pass==0) {
                if (index<=data->lastIndex)
@@ -334,7 +344,12 @@ static void findnearestvert__doClosest(void *userData, EditVert *eve, int x, int
 
        if (data->dist>3) {
                int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y);
-               if ((eve->f&1)==data->select) temp += 5;
+               if ((eve->f&1) == data->select) {
+                       if (data->strict == 1)
+                               return;
+                       else
+                               temp += 5;
+               }
 
                if (temp<data->dist) {
                        data->dist = temp;
@@ -343,26 +358,49 @@ static void findnearestvert__doClosest(void *userData, EditVert *eve, int x, int
                }
        }
 }
-static EditVert *findnearestvert(short *dist, short sel)
+
+
+
+
+static unsigned int findnearestvert__backbufIndextest(unsigned int index){
+               EditVert *eve = BLI_findlink(&G.editMesh->verts, index-1);
+               if(eve && (eve->f & SELECT)) return 0;
+               return 1; 
+}
+/**
+ * findnearestvert
+ * 
+ * dist (in/out): minimal distance to the nearest and at the end, actual distance
+ * sel: selection bias
+ *             if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
+ *             if 0, unselected vertice are given the bias
+ * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased 
+ */
+EditVert *findnearestvert(int *dist, short sel, short strict)
 {
        short mval[2];
 
        getmouseco_areawin(mval);
+       if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)){
+               int distance;
+               unsigned int index;
+               EditVert *eve;
                
-       if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)) {
-               short distance;
-               unsigned int index = sample_backbuf_rect(mval, 50, em_wireoffs, 0xFFFFFF, &distance);
-               EditVert *eve = BLI_findlink(&G.editMesh->verts, index-1);
-
-               if (eve && distance < *dist) {
+               if(strict) index = sample_backbuf_rect(mval, 50, em_wireoffs, 0xFFFFFF, &distance, strict, findnearestvert__backbufIndextest); 
+               else index = sample_backbuf_rect(mval, 50, em_wireoffs, 0xFFFFFF, &distance, 0, NULL); 
+               
+               eve = BLI_findlink(&G.editMesh->verts, index-1);
+               
+               if(eve && distance < *dist) {
                        *dist = distance;
                        return eve;
                } else {
                        return NULL;
                }
+                       
        }
        else {
-               struct { short mval[2], pass, select; int dist, lastIndex, closestIndex; EditVert *closest; } data;
+               struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } data;
                static int lastSelectedIndex=0;
                static EditVert *lastSelected=NULL;
 
@@ -376,6 +414,7 @@ static EditVert *findnearestvert(short *dist, short sel)
                data.mval[1] = mval[1];
                data.select = sel;
                data.dist = *dist;
+               data.strict = strict;
                data.closest = NULL;
                data.closestIndex = 0;
 
@@ -412,9 +451,9 @@ static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3)
 /* note; uses G.vd, so needs active 3d window */
 static void findnearestedge__doClosest(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
 {
-       struct { float mval[2]; short dist; EditEdge *closest; } *data = userData;
+       struct { float mval[2]; int dist; EditEdge *closest; } *data = userData;
        float v1[2], v2[2];
-       short distance;
+       int distance;
                
        v1[0] = x0;
        v1[1] = y0;
@@ -445,15 +484,15 @@ static void findnearestedge__doClosest(void *userData, EditEdge *eed, int x0, in
                }
        }
 }
-EditEdge *findnearestedge(short *dist)
+EditEdge *findnearestedge(int *dist)
 {
        short mval[2];
                
        getmouseco_areawin(mval);
 
        if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)) {
-               short distance;
-               unsigned int index = sample_backbuf_rect(mval, 50, em_solidoffs, em_wireoffs, &distance);
+               int distance;
+               unsigned int index = sample_backbuf_rect(mval, 50, em_solidoffs, em_wireoffs, &distance,0, NULL);
                EditEdge *eed = BLI_findlink(&G.editMesh->edges, index-1);
 
                if (eed && distance<*dist) {
@@ -464,7 +503,7 @@ EditEdge *findnearestedge(short *dist)
                }
        }
        else {
-               struct { float mval[2]; short dist; EditEdge *closest; } data;
+               struct { float mval[2]; int dist; EditEdge *closest; } data;
 
                data.mval[0] = mval[0];
                data.mval[1] = mval[1];
@@ -480,10 +519,10 @@ EditEdge *findnearestedge(short *dist)
 
 static void findnearestface__getDistance(void *userData, EditFace *efa, int x, int y, int index)
 {
-       struct { short mval[2], dist; EditFace *toFace; } *data = userData;
+       struct { short mval[2]; int dist; EditFace *toFace; } *data = userData;
 
        if (efa==data->toFace) {
-               short temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
+               int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
 
                if (temp<data->dist)
                        data->dist = temp;
@@ -491,7 +530,7 @@ static void findnearestface__getDistance(void *userData, EditFace *efa, int x, i
 }
 static void findnearestface__doClosest(void *userData, EditFace *efa, int x, int y, int index)
 {
-       struct { short mval[2], pass, dist; int lastIndex, closestIndex; EditFace *closest; } *data = userData;
+       struct { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } *data = userData;
 
        if (data->pass==0) {
                if (index<=data->lastIndex)
@@ -502,7 +541,7 @@ static void findnearestface__doClosest(void *userData, EditFace *efa, int x, int
        }
 
        if (data->dist>3) {
-               short temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
+               int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
 
                if (temp<data->dist) {
                        data->dist = temp;
@@ -511,7 +550,7 @@ static void findnearestface__doClosest(void *userData, EditFace *efa, int x, int
                }
        }
 }
-static EditFace *findnearestface(short *dist)
+static EditFace *findnearestface(int *dist)
 {
        short mval[2];
 
@@ -522,16 +561,16 @@ static EditFace *findnearestface(short *dist)
                EditFace *efa = BLI_findlink(&G.editMesh->faces, index-1);
 
                if (efa) {
-                       struct { short mval[2], dist; EditFace *toFace; } data;
+                       struct { short mval[2]; int dist; EditFace *toFace; } data;
 
                        data.mval[0] = mval[0];
                        data.mval[1] = mval[1];
-                       data.dist = 0x7FFF;             // largest short
+                       data.dist = 0x7FFF;             /* largest short */
                        data.toFace = efa;
 
                        mesh_foreachScreenFace(findnearestface__getDistance, &data);
 
-                       if(G.scene->selectmode == SCE_SELECT_FACE || data.dist<*dist) { // only faces, no dist check
+                       if(G.scene->selectmode == SCE_SELECT_FACE || data.dist<*dist) { /* only faces, no dist check */
                                *dist= data.dist;
                                return efa;
                        }
@@ -540,7 +579,7 @@ static EditFace *findnearestface(short *dist)
                return NULL;
        }
        else {
-               struct { short mval[2], pass, dist; int lastIndex, closestIndex; EditFace *closest; } data;
+               struct { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } data;
                static int lastSelectedIndex=0;
                static EditFace *lastSelected=NULL;
 
@@ -616,8 +655,7 @@ static void draw_dm_mapped_face_center(DerivedMesh *dm, EditFace *efa)
 
 static void unified_select_draw(EditVert *eve, EditEdge *eed, EditFace *efa)
 {
-       int dmNeedsFree;
-       DerivedMesh *dm = editmesh_get_derived_cage(&dmNeedsFree);
+       DerivedMesh *dm = editmesh_get_derived_cage(CD_MASK_BAREMESH);
 
        glDrawBuffer(GL_FRONT);
 
@@ -696,7 +734,7 @@ static void unified_select_draw(EditVert *eve, EditEdge *eed, EditFace *efa)
        glPointSize(1.0);
        glPopMatrix();
 
-       glFlush();
+       bglFlush();
        glDrawBuffer(GL_BACK);
 
        if(G.vd->flag & V3D_CLIPPING)
@@ -705,9 +743,7 @@ static void unified_select_draw(EditVert *eve, EditEdge *eed, EditFace *efa)
        /* signal that frontbuf differs from back */
        curarea->win_swap= WIN_FRONT_OK;
 
-       if (dmNeedsFree) {
-               dm->release(dm);
-       }
+       dm->release(dm);
 }
 
 
@@ -718,18 +754,18 @@ static void unified_select_draw(EditVert *eve, EditEdge *eed, EditFace *efa)
 */
 static int unified_findnearest(EditVert **eve, EditEdge **eed, EditFace **efa) 
 {
-       short dist= 75;
+       int dist= 75;
        
        *eve= NULL;
        *eed= NULL;
        *efa= NULL;
        
        if(G.scene->selectmode & SCE_SELECT_VERTEX)
-               *eve= findnearestvert(&dist, SELECT);
+               *eve= findnearestvert(&dist, SELECT, 0);
        if(G.scene->selectmode & SCE_SELECT_FACE)
                *efa= findnearestface(&dist);
 
-       dist-= 20;      // since edges select lines, we give dots advantage of 20 pix
+       dist-= 20;      /* since edges select lines, we give dots advantage of 20 pix */
        if(G.scene->selectmode & SCE_SELECT_EDGE)
                *eed= findnearestedge(&dist);
 
@@ -744,6 +780,10 @@ static int unified_findnearest(EditVert **eve, EditEdge **eed, EditFace **efa)
        return (*eve || *eed || *efa);
 }
 
+/* this as a way to compare the ares, perim  of 2 faces thay will scale to different sizes
+ *0.5 so smaller faces arnt ALWAYS selected with a thresh of 1.0 */
+#define SCALE_CMP(a,b) ((a+a*thresh >= b) && (a-(a*thresh*0.5) <= b))
+
 /* ****************  GROUP SELECTS ************** */
 /* selects new faces/edges/verts based on the
  existing selection
@@ -756,95 +796,133 @@ FACES GROUP
  mode 5: same normal
  mode 6: same co-planer
 */
-void facegroup_select(short mode)
+int facegroup_select(short mode)
 {
        EditMesh *em = G.editMesh;
        EditFace *efa, *base_efa=NULL;
-       unsigned int selcount=0;
-       float thresh=G.scene->toolsettings->doublimit; /* todo. better var for this */
+       unsigned int selcount=0; /*count how many new faces we select*/
+       
+       /*deselcount, count how many deselected faces are left, so we can bail out early
+       also means that if there are no deselected faces, we can avoid a lot of looping */
+       unsigned int deselcount=0; 
+       
+       short ok=0;
+       float thresh=G.scene->toolsettings->select_thresh;
        
        for(efa= em->faces.first; efa; efa= efa->next) {
-               if (efa->f & SELECT && !efa->h) {
-                       base_efa= efa;
-                       break;
+               if (!efa->h) {
+                       if (efa->f & SELECT) {
+                               efa->f1=1;
+                               ok=1;
+                       } else {
+                               efa->f1=0;
+                               deselcount++; /* a deselected face we may select later */
+                       }
                }
        }
        
-       if (!base_efa)
-               return;
+       if (!ok || !deselcount) /* no data selected OR no more data to select */
+               return 0;
        
-       if (mode==1) { /* same material */
-               for(efa= em->faces.first; efa; efa= efa->next) {
-                       if (!(efa->f & SELECT) && !efa->h && base_efa->mat_nr == efa->mat_nr) {
-                               EM_select_face(efa, 1);
-                               selcount++;
-                       }
-               }
-       } else if (mode==2) { /* same image */
+       /*if mode is 3 then record face areas, 4 record perimeter */
+       if (mode==3) {
                for(efa= em->faces.first; efa; efa= efa->next) {
-                       if (!(efa->f & SELECT) && !efa->h && base_efa->tf.tpage == efa->tf.tpage) {
-                               EM_select_face(efa, 1);
-                               selcount++;
-                       }
+                       efa->tmp.fp= EM_face_area(efa);
                }
-       } else if (mode==3) { /* same area */
-               float area, base_area;
-               base_area= EM_face_area(base_efa);
+       } else if (mode==4) {
                for(efa= em->faces.first; efa; efa= efa->next) {
-                       if (!(efa->f & SELECT) && !efa->h) {
-                               area= EM_face_area(efa);
-                               if (fabs(area-base_area)<=thresh) {
-                                       EM_select_face(efa, 1);
-                                       selcount++;
-                               }
-                       }
+                       efa->tmp.fp= EM_face_perimeter(efa);
                }
-       } else if (mode==4) { /* same perimeter */
-               float perimeter, base_perimeter;
-               base_perimeter= EM_face_perimeter(base_efa);
-               for(efa= em->faces.first; efa; efa= efa->next) {
-                       if (!(efa->f & SELECT) && !efa->h) {
-                               perimeter= EM_face_perimeter(efa);
-                               if (fabs(perimeter-base_perimeter)<=thresh) {
-                                       EM_select_face(efa, 1);
-                                       selcount++;
+       }
+       
+       for(base_efa= em->faces.first; base_efa; base_efa= base_efa->next) {
+               if (base_efa->f1) { /* This was one of the faces originaly selected */
+                       if (mode==1) { /* same material */
+                               for(efa= em->faces.first; efa; efa= efa->next) {
+                                       if (
+                                               !(efa->f & SELECT) &&
+                                               !efa->h &&
+                                               base_efa->mat_nr == efa->mat_nr
+                                       ) {
+                                               EM_select_face(efa, 1);
+                                               selcount++;
+                                               deselcount--;
+                                               if (!deselcount) /*have we selected all posible faces?, if so return*/
+                                                       return selcount;
+                                       }
                                }
-                       }
-               }
-       } else if (mode==5) { /* same normal */
-               float angle;
-               for(efa= em->faces.first; efa; efa= efa->next) {
-                       if (!(efa->f & SELECT) && !efa->h) {
-                               angle= VecAngle2(base_efa->n, efa->n);
-                               if (angle<=thresh) {
-                                       EM_select_face(efa, 1);
-                                       selcount++;
+                       } else if (mode==2) { /* same image */
+                               MTFace *tf, *base_tf;
+
+                               base_tf = (MTFace*)CustomData_em_get(&em->fdata, base_efa->data,
+                                                                    CD_MTFACE);
+
+                               if(!base_tf)
+                                       return selcount;
+
+                               for(efa= em->faces.first; efa; efa= efa->next) {
+                                       if (!(efa->f & SELECT) && !efa->h) {
+                                               tf = (MTFace*)CustomData_em_get(&em->fdata, efa->data,
+                                                                               CD_MTFACE);
+
+                                               if(base_tf->tpage == tf->tpage) {
+                                                       EM_select_face(efa, 1);
+                                                       selcount++;
+                                                       deselcount--;
+                                                       if (!deselcount) /*have we selected all posible faces?, if so return*/
+                                                               return selcount;
+                                               }
+                                       }
                                }
-                       }
-               }
-       } else if (mode==6) { /* same planer */
-               float angle, base_dot, dot;
-               base_dot= base_efa->cent[0]*base_efa->n[0] + base_efa->cent[1]*base_efa->n[1] + base_efa->cent[2]*base_efa->n[2];
-               for(efa= em->faces.first; efa; efa= efa->next) {
-                       if (!(efa->f & SELECT) && !efa->h) {
-                               angle= VecAngle2(base_efa->n, efa->n);
-                               if (angle<=thresh) {
-                                       dot= efa->cent[0]*base_efa->n[0] + efa->cent[1]*base_efa->n[1] + efa->cent[2]*base_efa->n[2];
-                                       if (fabs(base_dot-dot) <= thresh) {
+                       } else if (mode==3 || mode==4) { /* same area OR same perimeter, both use the same temp var */
+                               for(efa= em->faces.first; efa; efa= efa->next) {
+                                       if (
+                                               (!(efa->f & SELECT) && !efa->h) &&
+                                               SCALE_CMP(base_efa->tmp.fp, efa->tmp.fp)
+                                       ) {
                                                EM_select_face(efa, 1);
                                                selcount++;
+                                               deselcount--;
+                                               if (!deselcount) /*have we selected all posible faces?, if so return*/
+                                                       return selcount;
+                                       }
+                               }
+                       } else if (mode==5) { /* same normal */
+                               float angle;
+                               for(efa= em->faces.first; efa; efa= efa->next) {
+                                       if (!(efa->f & SELECT) && !efa->h) {
+                                               angle= VecAngle2(base_efa->n, efa->n);
+                                               if (angle/180.0<=thresh) {
+                                                       EM_select_face(efa, 1);
+                                                       selcount++;
+                                                       deselcount--;
+                                                       if (!deselcount) /*have we selected all posible faces?, if so return*/
+                                                               return selcount;
+                                               }
+                                       }
+                               }
+                       } else if (mode==6) { /* same planer */
+                               float angle, base_dot, dot;
+                               base_dot= Inpf(base_efa->cent, base_efa->n);
+                               for(efa= em->faces.first; efa; efa= efa->next) {
+                                       if (!(efa->f & SELECT) && !efa->h) {
+                                               angle= VecAngle2(base_efa->n, efa->n);
+                                               if (angle/180.0<=thresh) {
+                                                       dot=Inpf(efa->cent, base_efa->n);
+                                                       if (fabs(base_dot-dot) <= thresh) {
+                                                               EM_select_face(efa, 1);
+                                                               selcount++;
+                                                               deselcount--;
+                                                               if (!deselcount) /*have we selected all posible faces?, if so return*/
+                                                                       return selcount;
+                                                       }
+                                               }
                                        }
                                }
                        }
                }
-       }
-       
-       
-       if (selcount) {
-               G.totfacesel+=selcount;
-               allqueue(REDRAWVIEW3D, 0);
-               BIF_undo_push("Select Grouped Faces");
-       }
+       } /* end base_efa loop */
+       return selcount;
 }
 
 
@@ -853,60 +931,53 @@ EDGE GROUP
  mode 1: same length
  mode 2: same direction
  mode 3: same number of face users
+ mode 4: similar face angles.
+ mode 5: similar crease
 */
-void edgegroup_select(short mode)
+
+/* this function is only used by edgegroup_select's edge angle */
+
+
+
+int edgegroup_select(short mode)
 {
        EditMesh *em = G.editMesh;
        EditEdge *eed, *base_eed=NULL;
-       unsigned int selcount=0;
-       float thresh=G.scene->toolsettings->doublimit; /* todo. better var for this */
-       if (mode==3) { /* set all eed->tmp.l to 0 we use them later.*/
-               for(eed= em->edges.first; eed; eed= eed->next) {
-                       if (eed->f & SELECT && !eed->h) {
-                               base_eed= eed;
-                       }
+       unsigned int selcount=0; /* count how many new edges we select*/
+       
+       /*count how many visible selected edges there are,
+       so we can return when there are none left */
+       unsigned int deselcount=0;
+       
+       short ok=0;
+       float thresh=G.scene->toolsettings->select_thresh;
+       
+       for(eed= em->edges.first; eed; eed= eed->next) {
+               if (!eed->h) {
+                       if (eed->f & SELECT) {
+                               eed->f1=1;
+                               ok=1;
+                       } else {
+                               eed->f1=0;
+                               deselcount++;
+                       }
+                       /* set all eed->tmp.l to 0 we use it later.
+                       for counting face users*/
                        eed->tmp.l=0;
-               }
-       } else {
-               for(eed= em->edges.first; eed; eed= eed->next) {
-                       if (eed->f & SELECT && !eed->h) {
-                               base_eed= eed;
-                               break;
-                       }
+                       eed->f2=0; /* only for mode 4, edge animations */
                }
        }
        
-       if (!base_eed)
-               return;
+       if (!ok || !deselcount) /* no data selected OR no more data to select*/
+               return 0;
        
-       if (mode==1) { /* same length */
-               float base_length= VecLenf(base_eed->v1->co, base_eed->v2->co);
-               for(eed= em->edges.first; eed; eed= eed->next) {
-                       if (!(eed->f & SELECT) && !eed->h && ( fabs(base_length-VecLenf(eed->v1->co, eed->v2->co)) <= thresh ) ) {
-                               EM_select_edge(eed, 1);
-                               selcount++;
-                       }
-               }
-       } else if (mode==2) { /* same direction */
-               float base_dir[3], dir[3], angle;
-               VecSubf(base_dir, base_eed->v1->co, base_eed->v2->co);
+       if (mode==1) { /*store length*/
                for(eed= em->edges.first; eed; eed= eed->next) {
-                       if (!(eed->f & SELECT) && !eed->h) {
-                               VecSubf(dir, eed->v1->co, eed->v2->co);
-                               angle= VecAngle2(base_dir, dir);
-                               
-                               if (angle>90) /* use the smallest angle between the edges */
-                                       angle= fabs(angle-180.0f);
-                               
-                               if (angle<=thresh) {
-                                       EM_select_edge(eed, 1);
-                                       selcount++;
-                               }
-                       }
+                       if (!eed->h) /* dont calc data for hidden edges*/
+                               eed->tmp.fp= VecLenf(eed->v1->co, eed->v2->co);
                }
-       } else if (mode==3) { /* face users */
+       } else if (mode==3) { /*store face users*/
                EditFace *efa;
-               
                /* cound how many faces each edge uses use tmp->l */
                for(efa= em->faces.first; efa; efa= efa->next) {
                        efa->e1->tmp.l++;
@@ -914,21 +985,129 @@ void edgegroup_select(short mode)
                        efa->e3->tmp.l++;
                        if (efa->e4) efa->e4->tmp.l++;
                }
-               
-               for(eed= em->edges.first; eed; eed= eed->next) {
-                       if ((!(eed->f & SELECT) && !eed->h) && (base_eed->tmp.l==eed->tmp.l)) {
-                               EM_select_edge(eed, 1);
-                               selcount++;
+       } else if (mode==4) { /*store edge angles */
+               EditFace *efa;
+               int j;
+               /* cound how many faces each edge uses use tmp.l */
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       /* here we use the edges temp data to assign a face
+                       if a face has alredy been assigned (eed->f2==1)
+                       we calculate the angle between the current face and
+                       the edges previously found face.
+                       store the angle in eed->tmp.fp (loosing the face eed->tmp.f)
+                       but tagging eed->f2==2, so we know not to look at it again.
+                       This only works for edges that connect to 2 faces. but its good enough
+                       */
+                       
+                       /* se we can loop through face edges*/
+                       j=0;
+                       eed= efa->e1;
+                       while (j<4) {
+                               if (j==1) eed= efa->e2;
+                               else if (j==2) eed= efa->e3;
+                               else if (j==3) {
+                                       eed= efa->e4;
+                                       if (!eed)
+                                               break;
+                               } /* done looping */
+                               
+                               if (!eed->h) { /* dont calc data for hidden edges*/
+                                       if (eed->f2==2)
+                                               break;
+                                       else if (eed->f2==0) /* first access, assign the face */
+                                               eed->tmp.f= efa;
+                                       else if (eed->f2==1) /* second, we assign the angle*/
+                                               eed->tmp.fp= VecAngle2(eed->tmp.f->n, efa->n)/180;
+                                       eed->f2++; /* f2==0 no face assigned. f2==1 one face found. f2==2 angle calculated.*/
+                               }
+                               j++;
                        }
                }
        }
        
-       if (selcount) {
-               //EM_select_flush(); /* dont use because it can end up selecting more edges and is not usefull*/
-               G.totedgesel+=selcount;
-               allqueue(REDRAWVIEW3D, 0);
-               BIF_undo_push("Select Grouped Edges");
-       }
+       for(base_eed= em->edges.first; base_eed; base_eed= base_eed->next) {
+               if (base_eed->f1) {
+                       if (mode==1) { /* same length */
+                               for(eed= em->edges.first; eed; eed= eed->next) {
+                                       if (
+                                               !(eed->f & SELECT) &&
+                                               !eed->h &&
+                                               SCALE_CMP(base_eed->tmp.fp, eed->tmp.fp)
+                                       ) {
+                                               EM_select_edge(eed, 1);
+                                               selcount++;
+                                               deselcount--;
+                                               if (!deselcount) /*have we selected all posible faces?, if so return*/
+                                                       return selcount;
+                                       }
+                               }
+                       } else if (mode==2) { /* same direction */
+                               float base_dir[3], dir[3], angle;
+                               VecSubf(base_dir, base_eed->v1->co, base_eed->v2->co);
+                               for(eed= em->edges.first; eed; eed= eed->next) {
+                                       if (!(eed->f & SELECT) && !eed->h) {
+                                               VecSubf(dir, eed->v1->co, eed->v2->co);
+                                               angle= VecAngle2(base_dir, dir);
+                                               
+                                               if (angle>90) /* use the smallest angle between the edges */
+                                                       angle= fabs(angle-180.0f);
+                                               
+                                               if (angle/90.0<=thresh) {
+                                                       EM_select_edge(eed, 1);
+                                                       selcount++;
+                                                       deselcount--;
+                                                       if (!deselcount) /*have we selected all posible faces?, if so return*/
+                                                               return selcount;
+                                               }
+                                       }
+                               }
+                       } else if (mode==3) { /* face users */                          
+                               for(eed= em->edges.first; eed; eed= eed->next) {
+                                       if (
+                                               !(eed->f & SELECT) &&
+                                               !eed->h &&
+                                               base_eed->tmp.l==eed->tmp.l
+                                       ) {
+                                               EM_select_edge(eed, 1);
+                                               selcount++;
+                                               deselcount--;
+                                               if (!deselcount) /*have we selected all posible faces?, if so return*/
+                                                       return selcount;
+                                       }
+                               }
+                       } else if (mode==4 && base_eed->f2==2) { /* edge angles, f2==2 means the edge has an angle. */                          
+                               for(eed= em->edges.first; eed; eed= eed->next) {
+                                       if (
+                                               !(eed->f & SELECT) &&
+                                               !eed->h &&
+                                               eed->f2==2 &&
+                                               (fabs(base_eed->tmp.fp-eed->tmp.fp)<=thresh)
+                                       ) {
+                                               EM_select_edge(eed, 1);
+                                               selcount++;
+                                               deselcount--;
+                                               if (!deselcount) /*have we selected all posible faces?, if so return*/
+                                                       return selcount;
+                                       }
+                               }
+                       } else if (mode==5) { /* edge crease */
+                               for(eed= em->edges.first; eed; eed= eed->next) {
+                                       if (
+                                               !(eed->f & SELECT) &&
+                                               !eed->h &&
+                                               (fabs(base_eed->crease-eed->crease) <= thresh)
+                                       ) {
+                                               EM_select_edge(eed, 1);
+                                               selcount++;
+                                               deselcount--;
+                                               if (!deselcount) /*have we selected all posible faces?, if so return*/
+                                                       return selcount;
+                                       }
+                               }
+                       }
+               }
+       } 
+       return selcount;
 }
 
 
@@ -938,45 +1117,40 @@ VERT GROUP
  mode 2: same number of face users
  mode 3: same vertex groups
 */
-void vertgroup_select(short mode)
+int vertgroup_select(short mode)
 {
        EditMesh *em = G.editMesh;
        EditVert *eve, *base_eve=NULL;
        
-       unsigned int selcount=0;
-       float thresh=G.scene->toolsettings->doublimit; /* todo. better var for this */
+       unsigned int selcount=0; /* count how many new edges we select*/
        
-       if (mode==2) { /* set all eve->tmp.l to 0 we use them later.*/
-               for(eve= em->verts.first; eve; eve= eve->next) {
-                       if (eve->f & SELECT && !eve->h) {
-                               base_eve= eve;
+       /*count how many visible selected edges there are,
+       so we can return when there are none left */
+       unsigned int deselcount=0;
+       
+       short ok=0;
+       float thresh=G.scene->toolsettings->select_thresh;
+       
+       for(eve= em->verts.first; eve; eve= eve->next) {
+               if (!eve->h) {
+                       if (eve->f & SELECT) {
+                               eve->f1=1;
+                               ok=1;
+                       } else {
+                               eve->f1=0;
+                               deselcount++;
                        }
+                       /* set all eve->tmp.l to 0 we use them later.*/
                        eve->tmp.l=0;
                }
-       } else {
-               for(eve= em->verts.first; eve; eve= eve->next) {
-                       if (eve->f & SELECT && !eve->h) {
-                               base_eve= eve;
-                               break;
-                       }
-               }
+               
        }
        
-       if (!base_eve)
-               return;
+       if (!ok || !deselcount) /* no data selected OR no more data to select*/
+               return 0;
        
-       if (mode==1) { /* same normal */
-               float angle;
-               for(eve= em->verts.first; eve; eve= eve->next) {
-                       if (!(eve->f & SELECT) && !eve->h) {
-                               angle= VecAngle2(base_eve->no, eve->no);
-                               if (angle<=thresh) {
-                                       eve->f |= SELECT;
-                                       selcount++;
-                               }
-                       }
-               }
-       } else if (mode==2) { /* face users */
+       
+       if (mode==2) { /* store face users */
                EditFace *efa;
                
                /* count how many faces each edge uses use tmp->l */
@@ -986,62 +1160,141 @@ void vertgroup_select(short mode)
                        efa->v3->tmp.l++;
                        if (efa->v4) efa->v4->tmp.l++;
                }
-               
-               for(eve= em->verts.first; eve; eve= eve->next) {
-                       if ((!(eve->f & SELECT) && !eve->h) && (base_eve->tmp.l==eve->tmp.l)) {
-                               eve->f |= SELECT;
-                               selcount++;
-                       }
-               }
-       } else if (mode==3) { /* vertex groups */
-               short i,j; /*weight index*/
-               if (!base_eve->totweight)
-                       return;
-               
-               for(eve= em->verts.first; eve; eve= eve->next) {
-                       if (!(eve->f & SELECT) && !eve->h && eve->totweight) {
-                               /* do the extra check for selection in the following if, so were not
-                               checking verts that may be alredy selected */
-                               for (i=0; base_eve->totweight >i && !(eve->f & SELECT); i++) { 
-                                       for (j=0; eve->totweight >j; j++) {
-                                               if (base_eve->dw[i].def_nr==eve->dw[j].def_nr) {
+       }
+       
+       
+       for(base_eve= em->verts.first; base_eve; base_eve= base_eve->next) {
+               if (base_eve->f1) {
+                               
+                       if (mode==1) { /* same normal */
+                               float angle;
+                               for(eve= em->verts.first; eve; eve= eve->next) {
+                                       if (!(eve->f & SELECT) && !eve->h) {
+                                               angle= VecAngle2(base_eve->no, eve->no);
+                                               if (angle/180.0<=thresh) {
                                                        eve->f |= SELECT;
                                                        selcount++;
-                                                       break;
+                                                       deselcount--;
+                                                       if (!deselcount) /*have we selected all posible faces?, if so return*/
+                                                               return selcount;
+                                               }
+                                       }
+                               }
+                       } else if (mode==2) { /* face users */
+                               for(eve= em->verts.first; eve; eve= eve->next) {
+                                       if (
+                                               !(eve->f & SELECT) &&
+                                               !eve->h &&
+                                               base_eve->tmp.l==eve->tmp.l
+                                       ) {
+                                               eve->f |= SELECT;
+                                               selcount++;
+                                               deselcount--;
+                                               if (!deselcount) /*have we selected all posible faces?, if so return*/
+                                                       return selcount;
+                                       }
+                               }
+                       } else if (mode==3) { /* vertex groups */
+                               MDeformVert *dvert, *base_dvert;
+                               short i, j; /* weight index */
+
+                               base_dvert= CustomData_em_get(&em->vdata, base_eve->data,
+                                       CD_MDEFORMVERT);
+
+                               if (!base_dvert || base_dvert->totweight == 0)
+                                       return selcount;
+                               
+                               for(eve= em->verts.first; eve; eve= eve->next) {
+                                       dvert= CustomData_em_get(&em->vdata, eve->data,
+                                               CD_MDEFORMVERT);
+
+                                       if (dvert && !(eve->f & SELECT) && !eve->h && dvert->totweight) {
+                                               /* do the extra check for selection in the following if, so were not
+                                               checking verts that may be alredy selected */
+                                               for (i=0; base_dvert->totweight >i && !(eve->f & SELECT); i++) { 
+                                                       for (j=0; dvert->totweight >j; j++) {
+                                                               if (base_dvert->dw[i].def_nr==dvert->dw[j].def_nr) {
+                                                                       eve->f |= SELECT;
+                                                                       selcount++;
+                                                                       deselcount--;
+                                                                       if (!deselcount) /*have we selected all posible faces?, if so return*/
+                                                                               return selcount;
+                                                                       break;
+                                                               }
+                                                       }
                                                }
                                        }
                                }
                        }
                }
-               
-       }
-       if (selcount) {
-               EM_select_flush(); /* so that selected verts, go onto select faces */
-               G.totedgesel+=selcount;
-               allqueue(REDRAWVIEW3D, 0);
-               BIF_undo_push("Select Grouped Verts");
-       }
+       } /* end basevert loop */
+       return selcount;
 }
 
+/* EditMode menu triggered from space.c by pressing Shift+G
+handles face/edge vert context and
+facegroup_select/edgegroup_select/vertgroup_select do all the work
+*/
+
 void select_mesh_group_menu()
 {
        short ret;
+       int selcount, first_item=1;
+       char str[512] = "Select Grouped%t"; /* total max length is 404 at the moment */
+
+       if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+               first_item=0;
+               strcat(str, "|Verts...%x-1|    Similar Normal %x1|    Same Face Users %x2|    Shared Vertex Groups%x3");
+       }
+
+       if(G.scene->selectmode & SCE_SELECT_EDGE) {
+               if (!first_item)        strcat(str, "|%l");
+               else                            first_item=1;
+               
+               strcat(str, "|Edges...%x-1|    Similar Length %x10|    Similar Direction %x20|    Same Face Users%x30|    Similar Face Angle%x40|    Similar Crease%x50");
+       }
        
        if(G.scene->selectmode & SCE_SELECT_FACE) {
-               ret= pupmenu("Select Grouped Faces %t|Same Material %x1|Same Image %x2|Similar Area %x3|Similar Perimeter %x4|Similar Normal %x5|Similar Co-Planer %x6");
-               if (ret<1) return;
-               facegroup_select(ret);
+               if (!first_item)        strcat(str, "|%l");
+               strcat(str, "|Faces...%x-1|    Same Material %x100|    Same Image %x200|    Similar Area %x300|    Similar Perimeter %x400|    Similar Normal %x500|    Similar Co-Planer %x600");
+       
+       }
+       
+       ret= pupmenu(str);
+       if (ret<1) return;
+       
+       if (ret<10) {
+               selcount= vertgroup_select(ret);
+               if (selcount) { /* update if data was selected */
+                       EM_select_flush(); /* so that selected verts, go onto select faces */
+                       G.totvertsel += selcount;
+                       allqueue(REDRAWVIEW3D, 0);
+                       BIF_undo_push("Select Grouped Verts");
+               }
+               return;
+       }
+       
+       if (ret<100) {
+               selcount= edgegroup_select(ret/10);
                
-       } else if(G.scene->selectmode & SCE_SELECT_EDGE) {
-               ret= pupmenu("Select Grouped Edges%t|Similar Length %x1|Similar Direction %x2|Same Face Users%x3");
-               if (ret<1) return;
-               edgegroup_select(ret);
-       } else if(G.scene->selectmode & SCE_SELECT_VERTEX) {
-               ret= pupmenu("Select Grouped Verts%t|Similar Normal %x1|Same Face Users %x2|Shared Vertex Groups%x3");
-               if (ret<1) return;
-               vertgroup_select(ret);
+               if (selcount) { /* update if data was selected */
+                       /*EM_select_flush();*/ /* dont use because it can end up selecting more edges and is not usefull*/
+                       G.totedgesel+=selcount;
+                       allqueue(REDRAWVIEW3D, 0);
+                       BIF_undo_push("Select Grouped Edges");
+               }
+               return;
        }
        
+       if (ret<1000) {
+               selcount= facegroup_select(ret/100);
+               if (selcount) { /* update if data was selected */
+                       G.totfacesel+=selcount;
+                       allqueue(REDRAWVIEW3D, 0);
+                       BIF_undo_push("Select Grouped Faces");
+               }
+               return;
+       }
 }
 
 
@@ -1074,17 +1327,17 @@ void faceloop_select(EditEdge *startedge, int select)
                }
        }
        
-       // tag startedge OK
+       /* tag startedge OK*/
        startedge->f2= 1;
        
        while(looking) {
                looking= 0;
                
                for(efa= em->faces.first; efa; efa= efa->next) {
-                       if(efa->e4 && efa->f1==0) {     // not done quad
-                               if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { // valence ok
+                       if(efa->e4 && efa->f1==0) {     /* not done quad */
+                               if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
 
-                                       // if edge tagged, select opposing edge and mark face ok
+                                       /* if edge tagged, select opposing edge and mark face ok */
                                        if(efa->e1->f2) {
                                                efa->e3->f2= 1;
                                                efa->f1= 1;
@@ -1127,8 +1380,8 @@ static int edge_not_in_tagged_face(EditEdge *eed)
        
        for(efa= em->faces.first; efa; efa= efa->next) {
                if(efa->h==0) {
-                       if(efa->e1==eed || efa->e2==eed || efa->e3==eed || efa->e4==eed) {      // edge is in face
-                               if(efa->e1->f2 || efa->e2->f2 || efa->e3->f2 || (efa->e4 && efa->e4->f2)) {     // face is tagged
+                       if(efa->e1==eed || efa->e2==eed || efa->e3==eed || efa->e4==eed) {      /* edge is in face */
+                               if(efa->e1->f2 || efa->e2->f2 || efa->e3->f2 || (efa->e4 && efa->e4->f2)) {     /* face is tagged */
                                        return 0;
                                }
                        }
@@ -1165,7 +1418,7 @@ static void edgeloop_select(EditEdge *starteed, int select)
        for(eed= em->edges.first; eed; eed= eed->next) {
                eed->f1= 0;
                eed->f2= 0;
-               if((eed->h & 1)==0) {   // fgon edges add to valence too
+               if((eed->h & 1)==0) {   /* fgon edges add to valence too */
                        eed->v1->f1++; eed->v2->f1++;
                }
        }
@@ -1191,11 +1444,11 @@ static void edgeloop_select(EditEdge *starteed, int select)
                
                /* find correct valence edges which are not tagged yet, but connect to tagged one */
                for(eed= em->edges.first; eed; eed= eed->next) {
-                       if(eed->h==0 && eed->f2==0) { // edge not hidden, not tagged
-                               if( (eed->v1->f1<5 && eed->v1->f2) || (eed->v2->f1<5 && eed->v2->f2)) { // valence of vertex OK, and is tagged
+                       if(eed->h==0 && eed->f2==0) { /* edge not hidden, not tagged */
+                               if( (eed->v1->f1<5 && eed->v1->f2) || (eed->v2->f1<5 && eed->v2->f2)) { /* valence of vertex OK, and is tagged */
                                        /* new edge is not allowed to be in face with tagged edge */
                                        if(edge_not_in_tagged_face(eed)) {
-                                               if(eed->f1==starteed->f1) {     // same amount of faces
+                                               if(eed->f1==starteed->f1) {     /* same amount of faces */
                                                        looking= 1;
                                                        eed->f2= 1;
                                                        if(eed->v2->f1<5) eed->v2->f2= 1;
@@ -1239,17 +1492,17 @@ static void edgering_select(EditEdge *startedge, int select){
                }
        }
        
-       // tag startedge OK
+       /* tag startedge OK */
        startedge->f2= 1;
        
        while(looking) {
                looking= 0;
                
                for(efa= em->faces.first; efa; efa= efa->next) {
-                       if(efa->e4 && efa->f1==0) {     // not done quad
-                               if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { // valence ok
+                       if(efa->e4 && efa->f1==0 && !efa->h) {  /* not done quad */
+                               if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
 
-                                       // if edge tagged, select opposing edge and mark face ok
+                                       /* if edge tagged, select opposing edge and mark face ok */
                                        if(efa->e1->f2) {
                                                efa->e3->f2= 1;
                                                efa->f1= 1;
@@ -1281,7 +1534,7 @@ static void edgering_select(EditEdge *startedge, int select){
        }
 }
 
-static void loop_multiselect(int looptype)
+void loop_multiselect(int looptype)
 {
        EditEdge *eed;
        EditEdge **edarray;
@@ -1323,34 +1576,35 @@ static void loop_multiselect(int looptype)
                
 /* ***************** MAIN MOUSE SELECTION ************** */
 
-// just to have the functions nice together
+/* just to have the functions nice together */
 static void mouse_mesh_loop(void)
 {
        EditEdge *eed;
-       short dist= 50;
+       int select= 1;
+       int dist= 50;
        
        eed= findnearestedge(&dist);
        if(eed) {
                
                if((G.qual & LR_SHIFTKEY)==0) EM_clear_flag_all(SELECT);
                
-               if((eed->f & SELECT)==0) EM_select_edge(eed, 1);
-               else if(G.qual & LR_SHIFTKEY) EM_select_edge(eed, 0);
+               if((eed->f & SELECT)==0) select=1;
+               else if(G.qual & LR_SHIFTKEY) select=0;
 
                if(G.scene->selectmode & SCE_SELECT_FACE) {
-                       faceloop_select(eed, eed->f & SELECT);
+                       faceloop_select(eed, select);
                }
                else if(G.scene->selectmode & SCE_SELECT_EDGE) {
             if(G.qual == (LR_CTRLKEY | LR_ALTKEY) || G.qual == (LR_CTRLKEY | LR_ALTKEY |LR_SHIFTKEY))
-                       edgering_select(eed, eed->f & SELECT);
+                       edgering_select(eed, select);
             else if(G.qual & LR_ALTKEY)
-                       edgeloop_select(eed, eed->f & SELECT);
+                       edgeloop_select(eed, select);
                }
         else if(G.scene->selectmode & SCE_SELECT_VERTEX) {
             if(G.qual == (LR_CTRLKEY | LR_ALTKEY) || G.qual == (LR_CTRLKEY | LR_ALTKEY |LR_SHIFTKEY))
-                       edgering_select(eed, eed->f & SELECT);
+                       edgering_select(eed, select);
             else if(G.qual & LR_ALTKEY)
-                       edgeloop_select(eed, eed->f & SELECT);
+                       edgeloop_select(eed, select);
                }
 
                /* frontbuffer draw of last selected only */
@@ -1379,27 +1633,33 @@ void mouse_mesh(void)
                if(efa) {
                        
                        if( (efa->f & SELECT)==0 ) {
+                               EM_store_selection(efa, EDITFACE);
                                EM_select_face_fgon(efa, 1);
                        }
                        else if(G.qual & LR_SHIFTKEY) {
+                               EM_remove_selection(efa, EDITFACE);
                                EM_select_face_fgon(efa, 0);
                        }
                }
                else if(eed) {
                        if((eed->f & SELECT)==0) {
+                               EM_store_selection(eed, EDITEDGE);
                                EM_select_edge(eed, 1);
                        }
                        else if(G.qual & LR_SHIFTKEY) {
+                               EM_remove_selection(eed, EDITEDGE);
                                EM_select_edge(eed, 0);
                        }
                }
                else if(eve) {
                        if((eve->f & SELECT)==0) {
                                eve->f |= SELECT;
-                               if((G.qual & LR_SHIFTKEY)==0) G.editMesh->firstvert = eve;
-                               else G.editMesh->lastvert = eve;
+                               EM_store_selection(eve, EDITVERT);
+                       }
+                       else if(G.qual & LR_SHIFTKEY){ 
+                               EM_remove_selection(eve, EDITVERT);
+                               eve->f &= ~SELECT;
                        }
-                       else if(G.qual & LR_SHIFTKEY) eve->f &= ~SELECT;
                }
                
                /* frontbuffer draw of last selected only */
@@ -1573,7 +1833,7 @@ void hide_mesh(int swap)
                }
        
                for(efa= em->faces.first; efa; efa= efa->next) {
-                       if(efa->e1->h || efa->e2->h || efa->e3->h || (efa->e4 && efa->e4->h)) {
+                       if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
                                efa->h= 1;
                                efa->f &= ~SELECT;
                        }
@@ -1589,7 +1849,7 @@ void hide_mesh(int swap)
                }
 
                for(efa= em->faces.first; efa; efa= efa->next) {
-                       if(efa->e1->h || efa->e2->h || efa->e3->h || (efa->e4 && efa->e4->h)) {
+                       if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
                                efa->h= 1;
                                efa->f &= ~SELECT;
                        }
@@ -1671,7 +1931,7 @@ void reveal_mesh(void)
                }
        }
 
-       EM_fgon_flags();        // redo flags and indices for fgons
+       EM_fgon_flags();        /* redo flags and indices for fgons */
        EM_selectmode_flush();
        countall();
 
@@ -1685,26 +1945,25 @@ void select_faces_by_numverts(int numverts)
        EditMesh *em = G.editMesh;
        EditFace *efa;
 
-       /* Selects isolated verts, and edges that do not have 2 neighboring
+       /* Selects trias/qiads or isolated verts, and edges that do not have 2 neighboring
         * faces
         */
-       
-       if(G.scene->selectmode!=SCE_SELECT_FACE) {
+
+       /* for loose vertices/edges, we first select all, loop below will deselect */
+       if(numverts==5)
+               EM_set_flag_all(SELECT);
+       else if(G.scene->selectmode!=SCE_SELECT_FACE) {
                error("Only works in face selection mode");
                return;
        }
-
-       efa= em->faces.first;
-       while(efa) {
+       
+       for(efa= em->faces.first; efa; efa= efa->next) {
                if (efa->e4) {
                        EM_select_face(efa, (numverts==4) );
                }
-               else if (efa->e3) {
+               else {
                        EM_select_face(efa, (numverts==3) );
                }
-               else 
-                       EM_select_face(efa, (numverts!=3) && (numverts!=4) );
-               efa= efa->next;
        }
 
        countall();
@@ -2208,7 +2467,7 @@ void selectrandom_mesh(void) /* randomly selects a user-set % of vertices/edges/
        EditVert *eve;
        EditEdge *eed;
        EditFace *efa;
-       short randfac = 50;
+       static short randfac = 50;
 
        if(G.obedit==NULL || (G.obedit->lay & G.vd->lay)==0) return;
 
@@ -2326,6 +2585,8 @@ void editmesh_mark_seam(int clear)
 {
        EditMesh *em= G.editMesh;
        EditEdge *eed;
+       
+       if(multires_level1_test()) return;
 
        /* auto-enable seams drawing */
        if(clear==0) {
@@ -2359,10 +2620,54 @@ void editmesh_mark_seam(int clear)
        allqueue(REDRAWVIEW3D, 0);
 }
 
+void editmesh_mark_sharp(int set)
+{
+       EditMesh *em= G.editMesh;
+       EditEdge *eed;
+
+#if 0
+       /* auto-enable sharp edge drawing */
+       if(set) {
+               if(!(G.f & G_DRAWSEAMS)) {
+                       G.f |= G_DRAWSEAMS;
+                       allqueue(REDRAWBUTSEDIT, 0);
+               }
+       }
+#endif
+
+       if(set) {
+               eed= em->edges.first;
+               while(eed) {
+                       if(!eed->h && (eed->f & SELECT)) eed->sharp = 1;
+                       eed = eed->next;
+               }
+       } else {
+               eed= em->edges.first;
+               while(eed) {
+                       if(!eed->h && (eed->f & SELECT)) eed->sharp = 0;
+                       eed = eed->next;
+               }
+       }
+
+       allqueue(REDRAWVIEW3D, 0);
+}
+
+void BME_Menu()        {
+       short ret;
+       ret= pupmenu("BME modeller%t|Select Edges of Vert%x1");
+       
+       switch(ret)
+       {
+               case 1:
+               //BME_edges_of_vert();
+               break;
+       }
+}
+
 void Edge_Menu() {
        short ret;
 
-       ret= pupmenu("Edge Specials%t|Mark Seam %x1|Clear Seam %x2|Rotate Edge CW%x3|Rotate Edge CCW%x4|Loopcut%x6|Edge Slide%x5|Edge Loop Select%x7|Edge Ring Select%x8|Loop to Region%x9|Region to Loop%x10");
+       ret= pupmenu("Edge Specials%t|Mark Seam %x1|Clear Seam %x2|Rotate Edge CW%x3|Rotate Edge CCW%x4|Loopcut%x6|Edge Slide%x5|Edge Loop Select%x7|Edge Ring Select%x8|Loop to Region%x9|Region to Loop%x10|Mark Sharp%x11|Clear Sharp%x12");
 
        switch(ret)
        {
@@ -2398,6 +2703,16 @@ void Edge_Menu() {
        case 10:
                region_to_loop();
                break;
+       case 11:
+               editmesh_mark_sharp(1);
+               BIF_undo_push("Mark Sharp");
+               DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+               break;
+       case 12: 
+               editmesh_mark_sharp(0);
+               BIF_undo_push("Clear Sharp");
+               DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+               break;
        }
 }
 
@@ -2430,8 +2745,8 @@ void righthandfaces(int select)   /* makes faces righthand turning */
        
        eed= em->edges.first;
        while(eed) {
-               eed->f2= 0;             // edge direction
-               eed->f1= 0;             // counter
+               eed->f2= 0;             /* edge direction */
+               eed->f1= 0;             /* counter */
                eed= eed->next;
        }
 
@@ -2483,6 +2798,9 @@ void righthandfaces(int select)   /* makes faces righthand turning */
                        }
                        efa= efa->next;
                }
+
+               if (startvl==NULL)
+                       startvl= em->faces.first;
                
                /* set first face correct: calc normal */
                
@@ -2608,6 +2926,11 @@ void righthandfaces(int select)  /* makes faces righthand turning */
        recalc_editnormals();
        
        DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+#ifdef WITH_VERSE
+       if(G.editMesh->vnode)
+               sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
        
        waitcursor(0);
 }
@@ -2640,22 +2963,11 @@ static void editmesh_calc_selvert_center(float cent_r[3])
        }
 }
 
-static int tface_is_selected(TFace *tf)
+static int tface_is_selected(MTFace *tf)
 {
        return (!(tf->flag & TF_HIDE) && (tf->flag & TF_SELECT));
 }
 
-static int faceselect_nfaces_selected(Mesh *me)
-{
-       int i, count= 0;
-
-       for (i=0; i<me->totface; i++)
-               if (tface_is_selected(&me->tface[i]))
-                       count++;
-
-       return count;
-}
-
        /* XXX, code for both these functions should be abstract,
         * then unified, then written for other things (like objects,
         * which would use same as vertices method), then added
@@ -2663,38 +2975,39 @@ static int faceselect_nfaces_selected(Mesh *me)
         */
 void faceselect_align_view_to_selected(View3D *v3d, Mesh *me, int axis)
 {
-       if (!faceselect_nfaces_selected(me)) {
-               error("No faces selected.");
-       } else {
-               float norm[3];
-               int i;
-
-               norm[0]= norm[1]= norm[2]= 0.0;
-               for (i=0; i<me->totface; i++) {
-                       MFace *mf= ((MFace*) me->mface) + i;
-                       TFace *tf= ((TFace*) me->tface) + i;
-       
-                       if (tface_is_selected(tf)) {
-                               float *v1, *v2, *v3, fno[3];
-
-                               v1= me->mvert[mf->v1].co;
-                               v2= me->mvert[mf->v2].co;
-                               v3= me->mvert[mf->v3].co;
-                               if (mf->v4) {
-                                       float *v4= me->mvert[mf->v4].co;
-                                       CalcNormFloat4(v1, v2, v3, v4, fno);
-                               } else {
-                                       CalcNormFloat(v1, v2, v3, fno);
-                               }
+       float norm[3];
+       int i, totselected = 0;
 
-                               norm[0]+= fno[0];
-                               norm[1]+= fno[1];
-                               norm[2]+= fno[2];
+       norm[0]= norm[1]= norm[2]= 0.0;
+       for (i=0; i<me->totface; i++) {
+               MFace *mf= ((MFace*) me->mface) + i;
+               MTFace *tf= ((MTFace*) me->mtface) + i;
+
+               if (tface_is_selected(tf)) {
+                       float *v1, *v2, *v3, fno[3];
+
+                       v1= me->mvert[mf->v1].co;
+                       v2= me->mvert[mf->v2].co;
+                       v3= me->mvert[mf->v3].co;
+                       if (mf->v4) {
+                               float *v4= me->mvert[mf->v4].co;
+                               CalcNormFloat4(v1, v2, v3, v4, fno);
+                       } else {
+                               CalcNormFloat(v1, v2, v3, fno);
                        }
+
+                       norm[0]+= fno[0];
+                       norm[1]+= fno[1];
+                       norm[2]+= fno[2];
+
+                       totselected++;
                }
+       }
 
+       if (totselected == 0)
+               error("No faces selected.");
+       else
                view3d_align_axis_to_vector(v3d, axis, norm);
-       }
 }
 
 void editmesh_align_view_to_selected(View3D *v3d, int axis)
@@ -2897,6 +3210,11 @@ void vertexsmooth(void)
 
        allqueue(REDRAWVIEW3D, 0);
        DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+#ifdef WITH_VERSE
+       if(G.editMesh->vnode)
+               sync_all_verseverts_with_editverts(G.editMesh->vnode);
+#endif
        BIF_undo_push("Vertex Smooth");
 }
 
@@ -2944,6 +3262,10 @@ void vertexnoise(void)
        recalc_editnormals();
        allqueue(REDRAWVIEW3D, 0);
        DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+#ifdef WITH_VERSE
+       if(G.editMesh->vnode)
+               sync_all_verseverts_with_editverts(G.editMesh->vnode);
+#endif
        BIF_undo_push("Vertex Noise");
 }
 
@@ -3008,6 +3330,10 @@ void vertices_to_sphere(void)
        recalc_editnormals();
        allqueue(REDRAWVIEW3D, 0);
        DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+#ifdef WITH_VERSE
+       if(G.editMesh->vnode)
+               sync_all_verseverts_with_editverts(G.editMesh->vnode);
+#endif
        BIF_undo_push("To Sphere");
 }