Two in one:
[blender.git] / source / blender / src / editmesh_mods.c
index fb3d8942ee961dcda6b67afa620cf4b63a941f29..5944c77e045fe2aab415ac3ac2b226b7dad560d9 100644 (file)
@@ -40,10 +40,6 @@ editmesh_mods.c, UI level access, no geometry changes
 #include <string.h>
 #include <math.h>
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
 #include "MEM_guardedalloc.h"
 
 #include "MTC_matrixops.h"
@@ -51,6 +47,7 @@ editmesh_mods.c, UI level access, no geometry changes
 #include "DNA_mesh_types.h"
 #include "DNA_material_types.h"
 #include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
 #include "DNA_object_types.h"
 #include "DNA_texture_types.h"
 #include "DNA_scene_types.h"
@@ -65,24 +62,34 @@ 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"
 #include "BIF_glutil.h"
 #include "BIF_graphics.h"
 #include "BIF_interface.h"
+#include "BIF_meshtools.h"
 #include "BIF_mywindow.h"
 #include "BIF_resources.h"
 #include "BIF_screen.h"
 #include "BIF_space.h"
 #include "BIF_toolbox.h"
 
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
+
 #include "BDR_drawobject.h"
 #include "BDR_editobject.h"
 
@@ -90,162 +97,41 @@ editmesh_mods.c, UI level access, no geometry changes
 #include "BSE_edit.h"
 #include "BSE_view.h"
 
+#include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
 
+#include "RE_render_ext.h"  /* externtex */
+
+#include "multires.h"
 #include "mydevice.h"
 #include "blendef.h"
-#include "render.h"  // externtex
 
 #include "editmesh.h"
 
 
-/* ****************************** SELECTION ROUTINES **************** */
-
-unsigned int em_solidoffs=0, em_wireoffs=0, em_vertoffs=0;     // set in drawobject.c ... for colorindices
-
-static void check_backbuf(void)
-{
-       if(G.vd->flag & V3D_NEEDBACKBUFDRAW) {
-               backdrawview3d(0);
-       }
-}
-
-/* samples a single pixel (copied from vpaint) */
-static unsigned int sample_backbuf(int x, int y)
-{
-       unsigned int col;
-       
-       if(x>=curarea->winx || y>=curarea->winy) return 0;
-       x+= curarea->winrct.xmin;
-       y+= curarea->winrct.ymin;
-       
-       check_backbuf(); // actually not needed for apple
-
-#ifdef __APPLE__
-       glReadBuffer(GL_AUX0);
-#endif
-       glReadPixels(x,  y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,  &col);
-       glReadBuffer(GL_BACK);  
-       
-       if(G.order==B_ENDIAN) SWITCH_INT(col);
-       
-       return framebuffer_to_index(col);
-}
+/* ****************************** MIRROR **************** */
 
-/* reads full rect, converts indices */
-static unsigned int *read_backbuf(short xmin, short ymin, short xmax, short ymax)
+void EM_select_mirrored(void)
 {
-       unsigned int *dr, *buf;
-       int a;
-       short xminc, yminc, xmaxc, ymaxc;
-       
-       /* clip */
-       if(xmin<0) xminc= 0; else xminc= xmin;
-       if(xmax>=curarea->winx) xmaxc= curarea->winx-1; else xmaxc= xmax;
-       if(xminc > xmaxc) return NULL;
-
-       if(ymin<0) yminc= 0; else yminc= ymin;
-       if(ymax>=curarea->winy) ymaxc= curarea->winy-1; else ymaxc= ymax;
-       if(yminc > ymaxc) return NULL;
-       
-       buf= MEM_mallocN( (xmaxc-xminc+1)*(ymaxc-yminc+1)*sizeof(int), "sample rect");
-
-       check_backbuf(); // actually not needed for apple
-       
-#ifdef __APPLE__
-       glReadBuffer(GL_AUX0);
-#endif
-       glReadPixels(curarea->winrct.xmin+xminc, curarea->winrct.ymin+yminc, (xmaxc-xminc+1), (ymaxc-yminc+1), GL_RGBA, GL_UNSIGNED_BYTE, buf);
-       glReadBuffer(GL_BACK);  
-
-       if(G.order==B_ENDIAN) IMB_convert_rgba_to_abgr((xmaxc-xminc+1)*(ymaxc-yminc+1), buf);
-
-       a= (xmaxc-xminc+1)*(ymaxc-yminc+1);
-       dr= buf;
-       while(a--) {
-               if(*dr) *dr= framebuffer_to_index(*dr);
-               dr++;
-       }
-       
-       /* put clipped result back, if needed */
-       if(xminc==xmin && xmaxc==xmax && yminc==ymin && ymaxc==ymax) return buf;
-       else {
-               unsigned int *buf1= MEM_callocN( (xmax-xmin+1)*(ymax-ymin+1)*sizeof(int), "sample rect2");
-               unsigned int *rd;
-               short xs, ys;
-
-               rd= buf;
-               dr= buf1;
+       if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+               EditMesh *em = G.editMesh;
+               EditVert *eve, *v1;
                
-               for(ys= ymin; ys<=ymax; ys++) {
-                       for(xs= xmin; xs<=xmax; xs++, dr++) {
-                               if( xs>=xminc && xs<=xmaxc && ys>=yminc && ys<=ymaxc) {
-                                       *dr= *rd;
-                                       rd++;
+               for(eve= em->verts.first; eve; eve= eve->next) {
+                       if(eve->f & SELECT) {
+                               v1= editmesh_get_x_mirror_vert(G.obedit, eve->co);
+                               if(v1) {
+                                       eve->f &= ~SELECT;
+                                       v1->f |= SELECT;
                                }
                        }
                }
-               MEM_freeN(buf);
-               return buf1;
        }
-       
-       return buf;
 }
 
+/* ****************************** SELECTION ROUTINES **************** */
 
-/* smart function to sample a rect spiralling outside, nice for backbuf selection */
-static unsigned int sample_backbuf_rect(short mval[2], int size, unsigned int min, unsigned int max, short *dist)
-{
-       unsigned int *buf, *bufmin, *bufmax;
-       int minx, miny;
-       int a, b, rc, nr, amount, dirvec[4][2];
-       short distance=0;
-       unsigned int index = 0;
-       
-       amount= (size-1)/2;
-
-       minx = mval[0]-(amount+1);
-       miny = mval[1]-(amount+1);
-       buf = read_backbuf(minx, miny, minx+size-1, miny+size-1);
-       if (!buf)
-               return 0;
-
-       rc= 0;
-       
-       dirvec[0][0]= 1; dirvec[0][1]= 0;
-       dirvec[1][0]= 0; dirvec[1][1]= -size;
-       dirvec[2][0]= -1; dirvec[2][1]= 0;
-       dirvec[3][0]= 0; dirvec[3][1]= size;
-       
-       bufmin= buf;
-       bufmax= buf+ size*size;
-       buf+= amount*size+ amount;
-       
-       for(nr=1; nr<=size; nr++) {
-               
-               for(a=0; a<2; a++) {
-                       for(b=0; b<nr; b++, distance++) {
-                               if (*buf && *buf>=min && *buf<max) {
-                                       *dist= (short) sqrt( (float)distance ); // XXX, this distance is wrong - zr
-                                       index = *buf - min+1; // messy yah, but indices start at 1
-                                       goto exit;
-                               }
-                               
-                               buf+= (dirvec[rc][0]+dirvec[rc][1]);
-                               
-                               if(buf<bufmin || buf>=bufmax) {
-                                       goto exit;
-                               }
-                       }
-                       rc++;
-                       rc &= 3;
-               }
-       }
-
-exit:
-       MEM_freeN(bufmin);
-       return index;
-}
+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;
@@ -275,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;
                
@@ -300,14 +186,17 @@ static void draw_triangulated(short mcords[][2], short tot)
 /* returns if all is OK */
 int EM_init_backbuf_border(short xmin, short ymin, short xmax, short ymax)
 {
-       unsigned int *buf, *dr;
+       struct ImBuf *buf;
+       unsigned int *dr;
        int a;
        
        if(G.obedit==NULL || G.vd->drawtype<OB_SOLID || (G.vd->flag & V3D_ZBUF_SELECT)==0) return 0;
        if(em_vertoffs==0) return 0;
        
-       dr= buf= read_backbuf(xmin, ymin, xmax, ymax);
+       buf= read_backbuf(xmin, ymin, xmax, ymax);
        if(buf==NULL) return 0;
+
+       dr = buf->rect;
        
        /* build selection lookup */
        selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
@@ -318,7 +207,7 @@ int EM_init_backbuf_border(short xmin, short ymin, short xmax, short ymax)
                        selbuf[*dr]= 1;
                dr++;
        }
-       MEM_freeN(buf);
+       IMB_freeImBuf(buf);
        return 1;
 }
 
@@ -344,7 +233,8 @@ void EM_free_backbuf(void)
 */
 int EM_mask_init_backbuf_border(short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
 {
-       unsigned int *buf, *bufmask, *dr, *drm;
+       unsigned int *dr, *drm;
+       struct ImBuf *buf, *bufmask;
        int a;
        
        /* method in use for face selecting too */
@@ -356,9 +246,11 @@ int EM_mask_init_backbuf_border(short mcords[][2], short tot, short xmin, short
 
        if(em_vertoffs==0) return 0;
        
-       dr= buf= read_backbuf(xmin, ymin, xmax, ymax);
+       buf= read_backbuf(xmin, ymin, xmax, ymax);
        if(buf==NULL) return 0;
 
+       dr = buf->rect;
+
        /* draw the mask */
 #ifdef __APPLE__
        glDrawBuffer(GL_AUX0);
@@ -371,18 +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 */
-       drm= bufmask= read_backbuf(xmin, ymin, xmax, ymax);
-       if(bufmask==NULL) return 0; // only when mem alloc fails, go crash somewhere else!
+       bufmask= read_backbuf(xmin, ymin, xmax, ymax);
+       drm = bufmask->rect;
+       if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */
        
        /* build selection lookup */
        selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
@@ -392,8 +285,8 @@ int EM_mask_init_backbuf_border(short mcords[][2], short tot, short xmin, short
                if(*dr>0 && *dr<=em_vertoffs && *drm==0) selbuf[*dr]= 1;
                dr++; drm++;
        }
-       MEM_freeN(buf);
-       MEM_freeN(bufmask);
+       IMB_freeImBuf(buf);
+       IMB_freeImBuf(bufmask);
        return 1;
        
 }
@@ -401,7 +294,8 @@ int EM_mask_init_backbuf_border(short mcords[][2], short tot, short xmin, short
 /* circle shaped sample area */
 int EM_init_backbuf_circle(short xs, short ys, short rads)
 {
-       unsigned int *buf, *dr;
+       struct ImBuf *buf;
+       unsigned int *dr;
        short xmin, ymin, xmax, ymax, xc, yc;
        int radsq;
        
@@ -415,8 +309,10 @@ int EM_init_backbuf_circle(short xs, short ys, short rads)
        
        xmin= xs-rads; xmax= xs+rads;
        ymin= ys-rads; ymax= ys+rads;
-       dr= buf= read_backbuf(xmin, ymin, xmax, ymax);
+       buf= read_backbuf(xmin, ymin, xmax, ymax);
        if(buf==NULL) return 0;
+
+       dr = buf->rect;
        
        /* build selection lookup */
        selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
@@ -429,14 +325,14 @@ int EM_init_backbuf_circle(short xs, short ys, short rads)
                }
        }
 
-       MEM_freeN(buf);
+       IMB_freeImBuf(buf);
        return 1;
        
 }
 
 static void findnearestvert__doClosest(void *userData, EditVert *eve, int x, int y, int index)
 {
-       struct { short mval[2], pass, select, dist; int 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)
@@ -447,8 +343,13 @@ static void findnearestvert__doClosest(void *userData, EditVert *eve, int x, int
        }
 
        if (data->dist>3) {
-               short temp = abs(data->mval[0] - x) + abs(data->mval[1]- y);
-               if ((eve->f&1)==data->select) temp += 5;
+               int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y);
+               if ((eve->f&1) == data->select) {
+                       if (data->strict == 1)
+                               return;
+                       else
+                               temp += 5;
+               }
 
                if (temp<data->dist) {
                        data->dist = temp;
@@ -457,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, dist; int 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;
 
@@ -490,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;
 
@@ -509,11 +434,26 @@ static EditVert *findnearestvert(short *dist, short sel)
        }
 }
 
+/* returns labda for closest distance v1 to line-piece v2-v3 */
+static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3) 
+{
+       float rc[2], len;
+       
+       rc[0]= v3[0]-v2[0];
+       rc[1]= v3[1]-v2[1];
+       len= rc[0]*rc[0]+ rc[1]*rc[1];
+       if(len==0.0f)
+               return 0.0f;
+       
+       return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
+}
+
+/* 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;
@@ -524,19 +464,35 @@ static void findnearestedge__doClosest(void *userData, EditEdge *eed, int x0, in
                
        if(eed->f & SELECT) distance+=5;
        if(distance < data->dist) {
-               data->dist = distance;
-               data->closest = eed;
+               if(G.vd->flag & V3D_CLIPPING) {
+                       float labda= labda_PdistVL2Dfl(data->mval, v1, v2);
+                       float vec[3];
+
+                       vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]);
+                       vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]);
+                       vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]);
+                       Mat4MulVecfl(G.obedit->obmat, vec);
+
+                       if(view3d_test_clipping(G.vd, vec)==0) {
+                               data->dist = distance;
+                               data->closest = eed;
+                       }
+               }
+               else {
+                       data->dist = distance;
+                       data->closest = eed;
+               }
        }
 }
-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) {
@@ -547,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];
@@ -563,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;
@@ -574,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)
@@ -585,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;
@@ -594,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];
 
@@ -605,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;
                        }
@@ -623,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;
 
@@ -699,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);
 
@@ -779,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)
@@ -788,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);
 }
 
 
@@ -801,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);
 
@@ -827,11 +780,529 @@ 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
+
+FACES GROUP
+ mode 1: same material
+ mode 2: same image
+ mode 3: same area
+ mode 4: same perimeter
+ mode 5: same normal
+ mode 6: same co-planer
+*/
+int facegroup_select(short mode)
+{
+       EditMesh *em = G.editMesh;
+       EditFace *efa, *base_efa=NULL;
+       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->h) {
+                       if (efa->f & SELECT) {
+                               efa->f1=1;
+                               ok=1;
+                       } else {
+                               efa->f1=0;
+                               deselcount++; /* a deselected face we may select later */
+                       }
+               }
+       }
+       
+       if (!ok || !deselcount) /* no data selected OR no more data to select */
+               return 0;
+       
+       /*if mode is 3 then record face areas, 4 record perimeter */
+       if (mode==3) {
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       efa->tmp.fp= EM_face_area(efa);
+               }
+       } else if (mode==4) {
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       efa->tmp.fp= EM_face_perimeter(efa);
+               }
+       }
+       
+       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==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==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;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       } /* end base_efa loop */
+       return selcount;
+}
+
+
+/*
+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
+*/
+
+/* 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; /* 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;
+                       eed->f2=0; /* only for mode 4, edge animations */
+               }
+       }
+       
+       if (!ok || !deselcount) /* no data selected OR no more data to select*/
+               return 0;
+       
+       if (mode==1) { /*store length*/
+               for(eed= em->edges.first; eed; eed= eed->next) {
+                       if (!eed->h) /* dont calc data for hidden edges*/
+                               eed->tmp.fp= VecLenf(eed->v1->co, eed->v2->co);
+               }
+       } 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++;
+                       efa->e2->tmp.l++;
+                       efa->e3->tmp.l++;
+                       if (efa->e4) efa->e4->tmp.l++;
+               }
+       } 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++;
+                       }
+               }
+       }
+       
+       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;
+}
+
+
+/*
+VERT GROUP
+ mode 1: same normal
+ mode 2: same number of face users
+ mode 3: same vertex groups
+*/
+int vertgroup_select(short mode)
+{
+       EditMesh *em = G.editMesh;
+       EditVert *eve, *base_eve=NULL;
+       
+       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(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;
+               }
+               
+       }
+       
+       if (!ok || !deselcount) /* no data selected OR no more data to select*/
+               return 0;
+       
+       
+       if (mode==2) { /* store face users */
+               EditFace *efa;
+               
+               /* count how many faces each edge uses use tmp->l */
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       efa->v1->tmp.l++;
+                       efa->v2->tmp.l++;
+                       efa->v3->tmp.l++;
+                       if (efa->v4) efa->v4->tmp.l++;
+               }
+       }
+       
+       
+       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++;
+                                                       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;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       } /* 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) {
+               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);
+               
+               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;
+       }
+}
+
+
 /* ****************  LOOP SELECTS *************** */
 
 /* selects quads in loop direction of indicated edge */
 /* only flush over edges with valence <= 2 */
-static void faceloop_select(EditEdge *startedge, int select)
+void faceloop_select(EditEdge *startedge, int select)
 {
        EditMesh *em = G.editMesh;
        EditEdge *eed;
@@ -856,17 +1327,17 @@ static 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;
@@ -893,8 +1364,10 @@ static void faceloop_select(EditEdge *startedge, int select)
        }
        
        /* (de)select the faces */
-       for(efa= em->faces.first; efa; efa= efa->next) {
-               if(efa->f1) EM_select_face(efa, select);
+       if(select!=2) {
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       if(efa->f1) EM_select_face(efa, select);
+               }
        }
 }
 
@@ -907,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;
                                }
                        }
@@ -945,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++;
                }
        }
@@ -971,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;
@@ -1019,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;
@@ -1060,36 +1533,78 @@ static void edgering_select(EditEdge *startedge, int select){
                if(eed->f2) EM_select_edge(eed, select);
        }
 }
+
+void loop_multiselect(int looptype)
+{
+       EditEdge *eed;
+       EditEdge **edarray;
+       int edindex, edfirstcount;
+       
+       /*edarray = MEM_mallocN(sizeof(*edarray)*G.totedgesel,"edge array");*/
+       edarray = MEM_mallocN(sizeof(EditEdge*)*G.totedgesel,"edge array");
+       edindex = 0;
+       edfirstcount = G.totedgesel;
+       
+       for(eed=G.editMesh->edges.first; eed; eed=eed->next){
+               if(eed->f&SELECT){
+                       edarray[edindex] = eed;
+                       edindex += 1;
+               }
+       }
+       
+       if(looptype){
+               for(edindex = 0; edindex < edfirstcount; edindex +=1){
+                       eed = edarray[edindex];
+                       edgering_select(eed,SELECT);
+               }
+               countall();
+               EM_selectmode_flush();
+               BIF_undo_push("Edge Ring Multi-Select");
+       }
+       else{
+               for(edindex = 0; edindex < edfirstcount; edindex +=1){
+                       eed = edarray[edindex];
+                       edgeloop_select(eed,SELECT);
+               }
+               countall();
+               EM_selectmode_flush();
+               BIF_undo_push("Edge Loop Multi-Select");
+       }
+       MEM_freeN(edarray);
+       allqueue(REDRAWVIEW3D,0);
+}
+               
 /* ***************** 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 */
@@ -1118,23 +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;
-                       else if(G.qual & LR_SHIFTKEY) eve->f &= ~SELECT;
+                       if((eve->f & SELECT)==0) {
+                               eve->f |= SELECT;
+                               EM_store_selection(eve, EDITVERT);
+                       }
+                       else if(G.qual & LR_SHIFTKEY){ 
+                               EM_remove_selection(eve, EDITVERT);
+                               eve->f &= ~SELECT;
+                       }
                }
                
                /* frontbuffer draw of last selected only */
@@ -1308,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;
                        }
@@ -1324,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;
                        }
@@ -1368,7 +1893,8 @@ void hide_mesh(int swap)
                        if(eve->f1==1) eve->h= 1;
                }
        }
-               
+       
+       G.totedgesel= G.totfacesel= G.totvertsel= 0;
        allqueue(REDRAWVIEW3D, 0);
        DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);     
        BIF_undo_push("Hide");
@@ -1405,9 +1931,10 @@ 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();
+
        allqueue(REDRAWVIEW3D, 0);
        DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);     
        BIF_undo_push("Reveal");
@@ -1418,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();
@@ -1451,6 +1977,250 @@ void select_faces_by_numverts(int numverts)
                BIF_undo_push("Select non-Triangles/Quads");
 }
 
+void select_sharp_edges(void)
+{
+       /* Find edges that have exactly two neighboring faces,
+        * check the angle between those faces, and if angle is
+        * small enough, select the edge
+        */
+       EditMesh *em = G.editMesh;
+       EditEdge *eed;
+       EditFace *efa;
+       EditFace **efa1;
+       EditFace **efa2;
+       long edgecount = 0, i;
+       static short sharpness = 135;
+       float fsharpness;
+
+       if(G.scene->selectmode==SCE_SELECT_FACE) {
+               error("Doesn't work in face selection mode");
+               return;
+       }
+
+       if(button(&sharpness,0, 180,"Max Angle:")==0) return;
+       /* if faces are at angle 'sharpness', then the face normals
+        * are at angle 180.0 - 'sharpness' (convert to radians too)
+        */
+       fsharpness = ((180.0 - sharpness) * M_PI) / 180.0;
+
+       i=0;
+       /* count edges, use tmp.l  */
+       eed= em->edges.first;
+       while(eed) {
+               edgecount++;
+               eed->tmp.l = i;
+               eed= eed->next;
+               ++i;
+       }
+
+       /* for each edge, we want a pointer to two adjacent faces */
+       efa1 = MEM_callocN(edgecount*sizeof(EditFace *), 
+                                          "pairs of edit face pointers");
+       efa2 = MEM_callocN(edgecount*sizeof(EditFace *), 
+                                          "pairs of edit face pointers");
+
+#define face_table_edge(eed) { \
+               i = eed->tmp.l; \
+               if (i != -1) { \
+                       if (efa1[i]) { \
+                               if (efa2[i]) { \
+                                       /* invalidate, edge has more than two neighbors */ \
+                                       eed->tmp.l = -1; \
+                               } \
+                               else { \
+                                       efa2[i] = efa; \
+                               } \
+                       } \
+                       else { \
+                               efa1[i] = efa; \
+                       } \
+               } \
+       }
+
+       /* find the adjacent faces of each edge, we want only two */
+       efa= em->faces.first;
+       while(efa) {
+               face_table_edge(efa->e1);
+               face_table_edge(efa->e2);
+               face_table_edge(efa->e3);
+               if (efa->e4) {
+                       face_table_edge(efa->e4);
+               }
+               efa= efa->next;
+       }
+
+#undef face_table_edge
+
+       eed = em->edges.first;
+       while(eed) {
+               i = eed->tmp.l;
+               if (i != -1) { 
+                       /* edge has two or less neighboring faces */
+                       if ( (efa1[i]) && (efa2[i]) ) { 
+                               /* edge has exactly two neighboring faces, check angle */
+                               float angle;
+                               angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] +
+                                                          efa1[i]->n[1]*efa2[i]->n[1] +
+                                                          efa1[i]->n[2]*efa2[i]->n[2]);
+                               if (fabs(angle) >= fsharpness)
+                                       EM_select_edge(eed, 1);
+                       }
+               }
+
+               eed= eed->next;
+       }
+
+       MEM_freeN(efa1);
+       MEM_freeN(efa2);
+
+       countall();
+       addqueue(curarea->win,  REDRAW, 0);
+       BIF_undo_push("Select Sharp Edges");
+}
+
+void select_linked_flat_faces(void)
+{
+       /* Find faces that are linked to selected faces that are 
+        * relatively flat (angle between faces is higher than
+        * specified angle)
+        */
+       EditMesh *em = G.editMesh;
+       EditEdge *eed;
+       EditFace *efa;
+       EditFace **efa1;
+       EditFace **efa2;
+       long edgecount = 0, i, faceselcount=0, faceselcountold=0;
+       static short sharpness = 135;
+       float fsharpness;
+
+       if(G.scene->selectmode!=SCE_SELECT_FACE) {
+               error("Only works in face selection mode");
+               return;
+       }
+
+       if(button(&sharpness,0, 180,"Min Angle:")==0) return;
+       /* if faces are at angle 'sharpness', then the face normals
+        * are at angle 180.0 - 'sharpness' (convert to radians too)
+        */
+       fsharpness = ((180.0 - sharpness) * M_PI) / 180.0;
+
+       i=0;
+       /* count edges, use tmp.l */
+       eed= em->edges.first;
+       while(eed) {
+               edgecount++;
+               eed->tmp.l = i;
+               eed= eed->next;
+               ++i;
+       }
+
+       /* for each edge, we want a pointer to two adjacent faces */
+       efa1 = MEM_callocN(edgecount*sizeof(EditFace *), 
+                                          "pairs of edit face pointers");
+       efa2 = MEM_callocN(edgecount*sizeof(EditFace *), 
+                                          "pairs of edit face pointers");
+
+#define face_table_edge(eed) { \
+               i = eed->tmp.l; \
+               if (i != -1) { \
+                       if (efa1[i]) { \
+                               if (efa2[i]) { \
+                                       /* invalidate, edge has more than two neighbors */ \
+                                       eed->tmp.l = -1; \
+                               } \
+                               else { \
+                                       efa2[i] = efa; \
+                               } \
+                       } \
+                       else { \
+                               efa1[i] = efa; \
+                       } \
+               } \
+       }
+
+       /* find the adjacent faces of each edge, we want only two */
+       efa= em->faces.first;
+       while(efa) {
+               face_table_edge(efa->e1);
+               face_table_edge(efa->e2);
+               face_table_edge(efa->e3);
+               if (efa->e4) {
+                       face_table_edge(efa->e4);
+               }
+
+               /* while were at it, count the selected faces */
+               if (efa->f & SELECT) ++faceselcount;
+
+               efa= efa->next;
+       }
+
+#undef face_table_edge
+
+       eed= em->edges.first;
+       while(eed) {
+               i = eed->tmp.l;
+               if (i != -1) { 
+                       /* edge has two or less neighboring faces */
+                       if ( (efa1[i]) && (efa2[i]) ) { 
+                               /* edge has exactly two neighboring faces, check angle */
+                               float angle;
+                               angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] +
+                                                          efa1[i]->n[1]*efa2[i]->n[1] +
+                                                          efa1[i]->n[2]*efa2[i]->n[2]);
+                               /* invalidate: edge too sharp */
+                               if (fabs(angle) >= fsharpness)
+                                       eed->tmp.l = -1;
+                       }
+                       else {
+                               /* invalidate: less than two neighbors */
+                               eed->tmp.l = -1;
+                       }
+               }
+
+               eed= eed->next;
+       }
+
+#define select_flat_neighbor(eed) { \
+                               i = eed->tmp.l; \
+                               if (i!=-1) { \
+                                       if (! (efa1[i]->f & SELECT) ) { \
+                                               EM_select_face(efa1[i], 1); \
+                                               ++faceselcount; \
+                                       } \
+                                       if (! (efa2[i]->f & SELECT) ) { \
+                                               EM_select_face(efa2[i], 1); \
+                                               ++faceselcount; \
+                                       } \
+                               } \
+       }
+
+       while (faceselcount != faceselcountold) {
+               faceselcountold = faceselcount;
+
+               efa= em->faces.first;
+               while(efa) {
+                       if (efa->f & SELECT) {
+                               select_flat_neighbor(efa->e1);
+                               select_flat_neighbor(efa->e2);
+                               select_flat_neighbor(efa->e3);
+                               if (efa->e4) {
+                                       select_flat_neighbor(efa->e4);
+                               }
+                       }
+                       efa= efa->next;
+               }
+       }
+
+#undef select_flat_neighbor
+
+       MEM_freeN(efa1);
+       MEM_freeN(efa2);
+
+       countall();
+       addqueue(curarea->win,  REDRAW, 0);
+       BIF_undo_push("Select Linked Flat Faces");
+}
+
 void select_non_manifold(void)
 {
        EditMesh *em = G.editMesh;
@@ -1686,6 +2456,7 @@ void select_less(void)
        }
        
        countall();
+       BIF_undo_push("Select Less");
        allqueue(REDRAWVIEW3D, 0);
 }
 
@@ -1696,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;
 
@@ -1712,6 +2483,9 @@ void selectrandom_mesh(void) /* randomly selects a user-set % of vertices/edges/
                                        eve->f |= SELECT;
                        }
                }
+               EM_selectmode_flush();
+               countall();
+               BIF_undo_push("Select Random: Vertices");
        }
        else if(G.scene->selectmode & SCE_SELECT_EDGE) {
                for(eed= em->edges.first; eed; eed= eed->next) {
@@ -1720,6 +2494,9 @@ void selectrandom_mesh(void) /* randomly selects a user-set % of vertices/edges/
                                        EM_select_edge(eed, 1);
                        }
                }
+               EM_selectmode_flush();
+               countall();
+               BIF_undo_push("Select Random:Edges");
        }
        else {
                for(efa= em->faces.first; efa; efa= efa->next) {
@@ -1728,11 +2505,11 @@ void selectrandom_mesh(void) /* randomly selects a user-set % of vertices/edges/
                                        EM_select_face(efa, 1);
                        }
                }
+               
+               EM_selectmode_flush();
+               countall();
+               BIF_undo_push("Select Random:Faces");
        }
-       
-       EM_selectmode_flush();
-
-       countall();
        allqueue(REDRAWVIEW3D, 0);
 }
 
@@ -1773,12 +2550,31 @@ void EM_selectmode_menu(void)
        else pupmenu_set_active(3);
        
        val= pupmenu("Select Mode%t|Vertices|Edges|Faces");
-       if(val>0) {
-               if(val==1) G.scene->selectmode= SCE_SELECT_VERTEX;
-               else if(val==2) G.scene->selectmode= SCE_SELECT_EDGE;
-               else G.scene->selectmode= SCE_SELECT_FACE;
        
-               EM_selectmode_set(); // when mode changes
+       
+       if(val>0) {
+               if(val==1){ 
+                       G.scene->selectmode= SCE_SELECT_VERTEX;
+                       EM_selectmode_set();
+                       countall(); 
+                       BIF_undo_push("Selectmode Set: Vertex");
+                       }
+               else if(val==2){
+                       if((G.qual==LR_CTRLKEY)) EM_convertsel(G.scene->selectmode, SCE_SELECT_EDGE);
+                       G.scene->selectmode= SCE_SELECT_EDGE;
+                       EM_selectmode_set();
+                       countall();
+                       BIF_undo_push("Selectmode Set: Edge");
+               }
+               
+               else{
+                       if((G.qual==LR_CTRLKEY)) EM_convertsel(G.scene->selectmode, SCE_SELECT_FACE);
+                       G.scene->selectmode= SCE_SELECT_FACE;
+                       EM_selectmode_set();
+                       countall();
+                       BIF_undo_push("Selectmode Set: Vertex");
+               }
+               
                allqueue(REDRAWVIEW3D, 1);
        }
 }
@@ -1789,7 +2585,8 @@ void editmesh_mark_seam(int clear)
 {
        EditMesh *em= G.editMesh;
        EditEdge *eed;
-       Mesh *me= G.obedit->data;
+       
+       if(multires_level1_test()) return;
 
        /* auto-enable seams drawing */
        if(clear==0) {
@@ -1797,8 +2594,6 @@ void editmesh_mark_seam(int clear)
                        G.f |= G_DRAWSEAMS;
                        allqueue(REDRAWBUTSEDIT, 0);
                }
-               if(!me->medge)
-                       me->medge= MEM_callocN(sizeof(MEdge), "fake mesh edge");
        }
 
        if(clear) {
@@ -1825,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|EdgeLoop Delete%x7");
+       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)
        {
@@ -1846,15 +2685,33 @@ void Edge_Menu() {
                break;
        case 5:
                EdgeSlide(0,0.0);
-       BIF_undo_push("EdgeSlide");
+               BIF_undo_push("EdgeSlide");
                break;
        case 6:
-        CutEdgeloop(1);
+               CutEdgeloop(1);
                BIF_undo_push("Loopcut New");
                break;
        case 7:
-        EdgeLoopDelete();
-               BIF_undo_push("Edgeloop Remove");
+               loop_multiselect(0);
+               break;
+       case 8:
+               loop_multiselect(1);
+               break;
+       case 9:
+               loop_to_region();
+               break;
+       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;
        }
 }
@@ -1888,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;
        }
 
@@ -1941,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 */
                
@@ -2066,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);
 }
@@ -2098,26 +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++) {
-               MFace *mf= ((MFace*) me->mface) + i;
-               TFace *tf= ((TFace*) me->tface) + i;
-
-               if (mf->v3 && tface_is_selected(tf))
-                       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
@@ -2125,56 +2975,51 @@ 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 (mf->v3 && 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)
 {
        EditMesh *em = G.editMesh;
        int nselverts= EM_nvertices_selected();
-
-       if (nselverts<3) {
-               if (nselverts==0) {
-                       error("No faces or vertices selected.");
-               } else {
-                       error("At least one face or three vertices must be selected.");
-               }
+       float norm[3]={0.0, 0.0, 0.0}; /* used for storing the mesh normal */
+       
+       if (nselverts==0) {
+               error("No faces or vertices selected.");
        } else if (EM_nfaces_selected()) {
-               float norm[3];
                EditFace *efa;
-
-               norm[0]= norm[1]= norm[2]= 0.0;
                for (efa= em->faces.first; efa; efa= efa->next) {
                        if (faceselectedAND(efa, SELECT)) {
                                float fno[3];
@@ -2191,11 +3036,10 @@ void editmesh_align_view_to_selected(View3D *v3d, int axis)
 
                Mat4Mul3Vecfl(G.obedit->obmat, norm);
                view3d_align_axis_to_vector(v3d, axis, norm);
-       } else {
-               float cent[3], norm[3];
+       } else if (nselverts>2) {
+               float cent[3];
                EditVert *eve, *leve= NULL;
 
-               norm[0]= norm[1]= norm[2]= 0.0;
                editmesh_calc_selvert_center(cent);
                for (eve= em->verts.first; eve; eve= eve->next) {
                        if (eve->f & SELECT) {
@@ -2214,10 +3058,39 @@ void editmesh_align_view_to_selected(View3D *v3d, int axis)
                        }
                }
 
+               Mat4Mul3Vecfl(G.obedit->obmat, norm);
+               view3d_align_axis_to_vector(v3d, axis, norm);
+       } else if (nselverts==2) { /* Align view to edge (or 2 verts) */ 
+               EditVert *eve, *leve= NULL;
+
+               for (eve= em->verts.first; eve; eve= eve->next) {
+                       if (eve->f & SELECT) {
+                               if (leve) {
+                                       norm[0]= leve->co[0] - eve->co[0];
+                                       norm[1]= leve->co[1] - eve->co[1];
+                                       norm[2]= leve->co[2] - eve->co[2];
+                                       break; /* we know there are only 2 verts so no need to keep looking */
+                               }
+                               leve= eve;
+                       }
+               }
+               Mat4Mul3Vecfl(G.obedit->obmat, norm);
+               view3d_align_axis_to_vector(v3d, axis, norm);
+       } else if (nselverts==1) { /* Align view to vert normal */ 
+               EditVert *eve;
+
+               for (eve= em->verts.first; eve; eve= eve->next) {
+                       if (eve->f & SELECT) {
+                               norm[0]= eve->no[0];
+                               norm[1]= eve->no[1];
+                               norm[2]= eve->no[2];
+                               break; /* we know this is the only selected vert, so no need to keep looking */
+                       }
+               }
                Mat4Mul3Vecfl(G.obedit->obmat, norm);
                view3d_align_axis_to_vector(v3d, axis, norm);
        }
-}
+} 
 
 /* **************** VERTEX DEFORMS *************** */
 
@@ -2229,6 +3102,7 @@ void vertexsmooth(void)
        float *adror, *adr, fac;
        float fvec[3];
        int teller=0;
+       ModifierData *md= G.obedit->modifiers.first;
 
        if(G.obedit==0) return;
 
@@ -2244,12 +3118,44 @@ void vertexsmooth(void)
        eve= em->verts.first;
        while(eve) {
                if(eve->f & SELECT) {
-                       eve->vn= (EditVert *)adr;
+                       eve->tmp.fp = adr;
                        eve->f1= 0;
+                       eve->f2= 0;
                        adr+= 3;
                }
                eve= eve->next;
        }
+
+       /* if there is a mirror modifier with clipping, flag the verts that
+        * are within tolerance of the plane(s) of reflection 
+        */
+       for (; md; md=md->next) {
+               if (md->type==eModifierType_Mirror) {
+                       MirrorModifierData *mmd = (MirrorModifierData*) md;     
+               
+                       if(mmd->flag & MOD_MIR_CLIPPING) {
+                               for (eve= em->verts.first; eve; eve= eve->next) {
+                                       if(eve->f & SELECT) {
+
+                                               switch(mmd->axis){
+                                                       case 0:
+                                                               if (fabs(eve->co[0]) < mmd->tolerance)
+                                                                       eve->f2 |= 1;
+                                                               break;
+                                                       case 1:
+                                                               if (fabs(eve->co[1]) < mmd->tolerance)
+                                                                       eve->f2 |= 2;
+                                                               break;
+                                                       case 2:
+                                                               if (fabs(eve->co[2]) < mmd->tolerance)
+                                                                       eve->f2 |= 4;
+                                                               break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
        
        eed= em->edges.first;
        while(eed) {
@@ -2260,11 +3166,11 @@ void vertexsmooth(void)
                        
                        if((eed->v1->f & SELECT) && eed->v1->f1<255) {
                                eed->v1->f1++;
-                               VecAddf((float *)eed->v1->vn, (float *)eed->v1->vn, fvec);
+                               VecAddf(eed->v1->tmp.fp, eed->v1->tmp.fp, fvec);
                        }
                        if((eed->v2->f & SELECT) && eed->v2->f1<255) {
                                eed->v2->f1++;
-                               VecAddf((float *)eed->v2->vn, (float *)eed->v2->vn, fvec);
+                               VecAddf(eed->v2->tmp.fp, eed->v2->tmp.fp, fvec);
                        }
                }
                eed= eed->next;
@@ -2274,14 +3180,27 @@ void vertexsmooth(void)
        while(eve) {
                if(eve->f & SELECT) {
                        if(eve->f1) {
-                               adr= (float *)eve->vn;
+                               adr = eve->tmp.fp;
                                fac= 0.5/(float)eve->f1;
                                
                                eve->co[0]= 0.5*eve->co[0]+fac*adr[0];
                                eve->co[1]= 0.5*eve->co[1]+fac*adr[1];
                                eve->co[2]= 0.5*eve->co[2]+fac*adr[2];
+
+                               /* clip if needed by mirror modifier */
+                               if (eve->f2) {
+                                       if (eve->f2 & 1) {
+                                               eve->co[0]= 0.0f;
+                                       }
+                                       if (eve->f2 & 2) {
+                                               eve->co[1]= 0.0f;
+                                       }
+                                       if (eve->f2 & 4) {
+                                               eve->co[2]= 0.0f;
+                                       }
+                               }
                        }
-                       eve->vn= 0;
+                       eve->tmp.fp= 0;
                }
                eve= eve->next;
        }
@@ -2291,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");
 }
 
@@ -2338,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");
 }
 
@@ -2402,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");
 }