svn merge ^/trunk/blender/ -r41453:41458
authorCampbell Barton <ideasman42@gmail.com>
Wed, 2 Nov 2011 06:19:04 +0000 (06:19 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 2 Nov 2011 06:19:04 +0000 (06:19 +0000)
1  2 
source/blender/editors/sculpt_paint/paint_vertex.c
source/blender/editors/transform/transform.c
source/blender/makesdna/DNA_mesh_types.h

index 0e0b1ae2bf24c6a597d638b2a804878c5149d5c7,57f926b06126010a85e2a5e7cc53a72e69b28b73..7599cf1117aca32a82486d75f58e34d9d9cf906f
@@@ -43,7 -43,6 +43,7 @@@
  
  #include "BLI_blenlib.h"
  #include "BLI_math.h"
 +#include "BLI_memarena.h"
  #include "BLI_utildefines.h"
  #include "BLI_ghash.h"
  
@@@ -198,7 -197,7 +198,7 @@@ unsigned int vpaint_get_current_col(VPa
        return rgba_to_mcol(brush->rgb[0], brush->rgb[1], brush->rgb[2], 1.0f);
  }
  
 -static void do_shared_vertexcol(Mesh *me)
 +static void do_shared_vertex_tesscol(Mesh *me)
  {
        /* if no mcol: do not do */
        /* if tface: only the involved faces, otherwise all */
        MEM_freeN(scolmain);
  }
  
 +void do_shared_vertexcol(Mesh *me)
 +{
 +      MLoop *ml = me->mloop;
 +      MLoopCol *lcol = me->mloopcol;
 +      MTexPoly *mtp = me->mtpoly;
 +      MPoly *mp = me->mpoly;
 +      float (*scol)[5];
 +      int i, has_shared = 0;
 +
 +      /* if no mloopcol: do not do */
 +      /* if mtexpoly: only the involved faces, otherwise all */
 +
 +      if(me->mloopcol==0 || me->totvert==0 || me->totpoly==0) return;
 +
 +      scol = MEM_callocN(sizeof(float)*me->totvert*5, "scol");
 +
 +      for (i=0; i<me->totloop; i++, ml++, lcol++) {
 +              if (i >= mp->loopstart + mp->totloop) {
 +                      mp++;
 +                      if (mtp) mtp++;
 +              }
 +
 +              if (!(mtp && (mtp->mode & TF_SHAREDCOL)) && (me->editflag & ME_EDIT_PAINT_MASK)!=0)
 +                      continue;
 +
 +              scol[ml->v][0] += lcol->r;
 +              scol[ml->v][1] += lcol->g;
 +              scol[ml->v][2] += lcol->b;
 +              scol[ml->v][3] += lcol->a;
 +              scol[ml->v][4] += 1.0;
 +              has_shared = 1;
 +      }
 +      
 +      if (has_shared) {
 +              for (i=0; i<me->totvert; i++) {
 +                      if (!scol[i][4]) continue;
 +
 +                      scol[i][0] /= scol[i][4];
 +                      scol[i][1] /= scol[i][4];
 +                      scol[i][2] /= scol[i][4];
 +                      scol[i][3] /= scol[i][4];
 +              }
 +      
 +              ml = me->mloop;
 +              lcol = me->mloopcol;
 +              for (i=0; i<me->totloop; i++, ml++, lcol++) {
 +                      if (!scol[ml->v][4]) continue;
 +
 +                      lcol->r = scol[ml->v][0];
 +                      lcol->g = scol[ml->v][1];
 +                      lcol->b = scol[ml->v][2];
 +                      lcol->a = scol[ml->v][3];
 +              }
 +      }
 +
 +      MEM_freeN(scol);
 +
 +      if (has_shared) {
 +              do_shared_vertex_tesscol(me);
 +      }
 +}
 +
  static void make_vertexcol(Object *ob)        /* single ob */
  {
        Mesh *me;
        if(!ob || ob->id.lib) return;
        me= get_mesh(ob);
        if(me==NULL) return;
 -      if(me->edit_mesh) return;
 +      if(me->edit_btmesh) return;
  
        /* copies from shadedisplist to mcol */
 -      if(!me->mcol) {
 -              CustomData_add_layer(&me->fdata, CD_MCOL, CD_CALLOC, NULL, me->totface);
 -              mesh_update_customdata_pointers(me);
 -      }
 +      if(!me->mcol)
 +              CustomData_add_layer(&me->fdata, CD_MCOL, CD_DEFAULT, NULL, me->totface);
 +      if (!me->mloopcol)
 +              CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop);
 +      
 +      mesh_update_customdata_pointers(me);
  
        //if(shade)
        //      shadeMeshMCol(scene, ob, me);
@@@ -388,7 -323,7 +388,7 @@@ static int wpaint_mirror_vgroup_ensure(
        return -1;
  }
  
 -static void copy_vpaint_prev(VPaint *vp, unsigned int *mcol, int tot)
 +static void copy_vpaint_prev(VPaint *vp, unsigned int *lcol, int tot)
  {
        if(vp->vpaint_prev) {
                MEM_freeN(vp->vpaint_prev);
        }
        vp->tot= tot;   
        
 -      if(mcol==NULL || tot==0) return;
 +      if(lcol==NULL || tot==0) return;
        
 -      vp->vpaint_prev= MEM_mallocN(4*sizeof(int)*tot, "vpaint_prev");
 -      memcpy(vp->vpaint_prev, mcol, 4*sizeof(int)*tot);
 +      vp->vpaint_prev= MEM_mallocN(sizeof(int)*tot, "vpaint_prev");
 +      memcpy(vp->vpaint_prev, lcol, sizeof(int)*tot);
        
  }
  
@@@ -422,11 -357,9 +422,11 @@@ static void copy_wpaint_prev (VPaint *w
  void vpaint_fill(Object *ob, unsigned int paintcol)
  {
        Mesh *me;
 -      MFace *mf;
 +      MFace *mf;
 +      MPoly *mp;
 +      MLoopCol *lcol;
        unsigned int *mcol;
 -      int i, selected;
 +      int i, j, selected;
  
        me= get_mesh(ob);
        if(me==NULL || me->totface==0) return;
                        mcol[3] = paintcol;
                }
        }
 +
 +      mp = me->mpoly;
 +      lcol = me->mloopcol;
 +      for (i=0; i<me->totpoly; i++, mp++) {
 +              if (!(!selected || mp->flag & ME_FACE_SEL))
 +                      continue;
 +
 +              lcol = me->mloopcol + mp->loopstart;
 +              for (j=0; j<mp->totloop; j++, lcol++) {
 +                      *(int*)lcol = paintcol;
 +              }
 +      }
        
        DAG_id_tag_update(&me->id, 0);
  }
  /* fills in the selected faces with the current weight and vertex group */
  void wpaint_fill(VPaint *wp, Object *ob, float paintweight)
  {
-       Mesh *me;
-       MFace *mface;
+       Mesh *me= ob->data;
 -      MFace *mf;
++      MPoly *mf;
        MDeformWeight *dw, *uw;
-       int *indexar;
-       unsigned int index;
        int vgroup, vgroup_mirror= -1;
-       int selected;
-       
-       int use_vert_sel;
-       me= ob->data;
-       if(me==NULL || me->totface==0 || me->dvert==NULL || !me->mface) return;
-       
-       selected= (me->editflag & ME_EDIT_PAINT_MASK);
-       
-       use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
+       unsigned int index;
  
-       indexar= get_indexarray(me);
+       /* mutually exclusive, could be made into a */
+       const short paint_selmode= ME_EDIT_PAINT_SEL_MODE(me);
  
-       if(selected) {
-               for(index=0, mface=me->mface; index<me->totface; index++, mface++) {
-                       if((mface->flag & ME_FACE_SEL)==0)
-                               indexar[index]= 0;
-                       else
-                               indexar[index]= index+1;
-               }
-       }
-       else {
-               for(index=0; index<me->totface; index++)
-                       indexar[index]= index+1;
-       }
 -      if(me->totface==0 || me->dvert==NULL || !me->mface) return;
++      if(me->totpoly==0 || me->dvert==NULL || !me->mpoly) return;
        
        vgroup= ob->actdef-1;
  
        
        copy_wpaint_prev(wp, me->dvert, me->totvert);
        
-       for(index=0; index<me->totface; index++) {
-               if(indexar[index] && indexar[index]<=me->totface) {
-                       MFace *mf= &me->mface[indexar[index]-1];
-                       unsigned int fidx= mf->v4 ? 3:2;
 -      for(index=0, mf= me->mface; index < me->totface; index++, mf++) {
 -              unsigned int fidx= mf->v4 ? 3:2;
++      for(index=0, mf= me->mpoly; index < me->totpoly; index++, mf++) {
++              unsigned int fidx= mf->totloop - 1;
+               if ((paint_selmode == SCE_SELECT_FACE) && !(mf->flag & ME_FACE_SEL)) {
+                       continue;
+               }
  
-                       do {
-                               unsigned int vidx= *(&mf->v1 + fidx);
+               do {
 -                      unsigned int vidx= *(&mf->v1 + fidx);
++                      unsigned int vidx= me->mloop[mf->loopstart + fidx].v;
  
-                               if(!me->dvert[vidx].flag) {
-                                       if(use_vert_sel && !(me->mvert[vidx].flag & SELECT)) {
-                                               continue;
-                                       }
+                       if(!me->dvert[vidx].flag) {
+                               if((paint_selmode == SCE_SELECT_VERTEX) && !(me->mvert[vidx].flag & SELECT)) {
+                                       continue;
+                               }
  
-                                       dw= defvert_verify_index(&me->dvert[vidx], vgroup);
-                                       if(dw) {
-                                               uw= defvert_verify_index(wp->wpaint_prev+vidx, vgroup);
-                                               uw->weight= dw->weight; /* set the undo weight */
-                                               dw->weight= paintweight;
-                                               if(me->editflag & ME_EDIT_MIRROR_X) {   /* x mirror painting */
-                                                       int j= mesh_get_x_mirror_vert(ob, vidx);
-                                                       if(j>=0) {
-                                                               /* copy, not paint again */
-                                                               if(vgroup_mirror != -1) {
-                                                                       dw= defvert_verify_index(me->dvert+j, vgroup_mirror);
-                                                                       uw= defvert_verify_index(wp->wpaint_prev+j, vgroup_mirror);
-                                                               } else {
-                                                                       dw= defvert_verify_index(me->dvert+j, vgroup);
-                                                                       uw= defvert_verify_index(wp->wpaint_prev+j, vgroup);
-                                                               }
-                                                               uw->weight= dw->weight; /* set the undo weight */
-                                                               dw->weight= paintweight;
+                               dw= defvert_verify_index(&me->dvert[vidx], vgroup);
+                               if(dw) {
+                                       uw= defvert_verify_index(wp->wpaint_prev+vidx, vgroup);
+                                       uw->weight= dw->weight; /* set the undo weight */
+                                       dw->weight= paintweight;
+                                       if(me->editflag & ME_EDIT_MIRROR_X) {   /* x mirror painting */
+                                               int j= mesh_get_x_mirror_vert(ob, vidx);
+                                               if(j>=0) {
+                                                       /* copy, not paint again */
+                                                       if(vgroup_mirror != -1) {
+                                                               dw= defvert_verify_index(me->dvert+j, vgroup_mirror);
+                                                               uw= defvert_verify_index(wp->wpaint_prev+j, vgroup_mirror);
+                                                       } else {
+                                                               dw= defvert_verify_index(me->dvert+j, vgroup);
+                                                               uw= defvert_verify_index(wp->wpaint_prev+j, vgroup);
                                                        }
+                                                       uw->weight= dw->weight; /* set the undo weight */
+                                                       dw->weight= paintweight;
                                                }
                                        }
-                                       me->dvert[vidx].flag= 1;
                                }
+                               me->dvert[vidx].flag= 1;
+                       }
  
-                       } while (fidx--);
-               }
+               } while (fidx--);
        }
  
        {
                        dv->flag= 0;
                }
        }
-       
-       MEM_freeN(indexar);
        copy_wpaint_prev(wp, NULL, 0);
  
        DAG_id_tag_update(&me->id, 0);
@@@ -982,14 -881,14 +960,14 @@@ static int weight_sample_invoke(bContex
  
                index= view3d_sample_backbuf(&vc, event->mval[0], event->mval[1]);
  
 -              if(index && index<=me->totface) {
 +              if(index && index<=me->totpoly) {
                        DerivedMesh *dm= mesh_get_derived_final(vc.scene, vc.obact, CD_MASK_BAREMESH);
  
                        if(dm->getVertCo==NULL) {
                                BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations");
                        }
                        else {
 -                              MFace *mf= ((MFace *)me->mface) + index-1;
 +                              MPoly *mf= ((MPoly *)me->mpoly) + index-1;
                                const int vgroup= vc.obact->actdef - 1;
                                ToolSettings *ts= vc.scene->toolsettings;
                                float mval_f[2];
                                mval_f[0]= (float)event->mval[0];
                                mval_f[1]= (float)event->mval[1];
  
-                               fidx= mf->totloop;
 -                              fidx= mf->v4 ? 3:2;
++                              fidx= mf->totloop - 1;
                                do {
                                        float co[3], sco[3], len;
 -                                      const int v_idx= (*(&mf->v1 + fidx));
 +                                      const int v_idx= me->mloop[mf->loopstart + fidx].v;
                                        dm->getVertCo(dm, v_idx, co);
                                        project_float_noclip(vc.ar, co, sco);
                                        len= len_squared_v2v2(mval_f, sco);
@@@ -1069,13 -968,13 +1047,13 @@@ static EnumPropertyItem *weight_paint_s
                                if(index && index<=me->totface) {
                                        const int totgroup= BLI_countlist(&vc.obact->defbase);
                                        if(totgroup) {
 -                                              MFace *mf= ((MFace *)me->mface) + index-1;
 -                                              unsigned int fidx= mf->v4 ? 3:2;
 +                                              MPoly *mf= ((MPoly *)me->mpoly) + index-1;
-                                               unsigned int fidx= mf->totloop;
++                                              unsigned int fidx= mf->totloop - 1;
                                                int *groups= MEM_callocN(totgroup*sizeof(int), "groups");
                                                int found= FALSE;
  
                                                do {
 -                                                      MDeformVert *dvert= me->dvert + (*(&mf->v1 + fidx));
 +                                                      MDeformVert *dvert= me->dvert + me->mloop[mf->loopstart + fidx].v;
                                                        int i= dvert->totweight;
                                                        MDeformWeight *dw;
                                                        for(dw= dvert->dw; i > 0; dw++, i--) {
@@@ -1959,13 -1858,6 +1937,13 @@@ static int wpaint_stroke_test_start(bCo
        me= get_mesh(ob);
        if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH;
        
 +      /*we can't assume mfaces have a correct origindex layer that indices to mpolys.
 +        so instead we have to regenerate the tesselation faces altogether.*/
 +      me->totface = mesh_recalcTesselation(&me->fdata, &me->ldata, &me->pdata, 
 +              me->mvert, me->totface, me->totloop, me->totpoly, 1, 0);
 +      mesh_update_customdata_pointers(me);
 +      makeDerivedMesh(scene, ob, NULL, CD_MASK_BAREMESH, 0);
 +
        /* if nothing was added yet, we make dverts and a vertex deform group */
        if (!me->dvert) {
                ED_vgroup_data_create(&me->id);
@@@ -2108,22 -2000,22 +2086,22 @@@ static void wpaint_stroke_update_step(b
                        
        if(wp->flag & VP_COLINDEX) {
                for(index=0; index<totindex; index++) {
 -                      if(indexar[index] && indexar[index]<=me->totface) {
 -                              MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
 +                      if(indexar[index] && indexar[index]<=me->totpoly) {
 +                              MPoly *mpoly= ((MPoly *)me->mpoly) + (indexar[index]-1);
                                                
 -                              if(mface->mat_nr!=ob->actcol-1) {
 +                              if(mpoly->mat_nr!=ob->actcol-1) {
                                        indexar[index]= 0;
                                }
                        }
                }
        }
                        
 -      if((me->editflag & ME_EDIT_PAINT_MASK) && me->mface) {
 +      if((me->editflag & ME_EDIT_PAINT_MASK) && me->mpoly) {
                for(index=0; index<totindex; index++) {
 -                      if(indexar[index] && indexar[index]<=me->totface) {
 -                              MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
 +                      if(indexar[index] && indexar[index]<=me->totpoly) {
 +                              MPoly *mpoly= ((MPoly *)me->mpoly) + (indexar[index]-1);
                                                
 -                              if((mface->flag & ME_FACE_SEL)==0) {
 +                              if((mpoly->flag & ME_FACE_SEL)==0) {
                                        indexar[index]= 0;
                                }
                        }                                       
                paintweight= ts->vgroup_weight;
                        
        for(index=0; index<totindex; index++) {
 -              if(indexar[index] && indexar[index]<=me->totface) {
 -                      MFace *mface= me->mface + (indexar[index]-1);
 +              if(indexar[index] && indexar[index]<=me->totpoly) {
 +                      MPoly *mpoly= me->mpoly + (indexar[index]-1);
 +                      MLoop *ml = me->mloop + mpoly->loopstart;
 +                      int i;
  
                        if(use_vert_sel) {
 -                              me->dvert[mface->v1].flag = (me->mvert[mface->v1].flag & SELECT);
 -                              me->dvert[mface->v2].flag = (me->mvert[mface->v2].flag & SELECT);
 -                              me->dvert[mface->v3].flag = (me->mvert[mface->v3].flag & SELECT);
 -                              if(mface->v4) me->dvert[mface->v4].flag = (me->mvert[mface->v4].flag & SELECT);
 +                              for (i=0; i<mpoly->totloop; i++, ml++) {
 +                                      me->dvert[ml->v].flag = (me->mvert[ml->v].flag & SELECT);
 +                              }
                        }
                        else {
 -                              me->dvert[mface->v1].flag= 1;
 -                              me->dvert[mface->v2].flag= 1;
 -                              me->dvert[mface->v3].flag= 1;
 -                              if(mface->v4) me->dvert[mface->v4].flag= 1;
 +                              for (i=0; i<mpoly->totloop; i++, ml++) {
 +                                      me->dvert[ml->v].flag = 1;
 +                              }
                        }
                                        
                        if(brush->vertexpaint_tool==VP_BLUR) {
                                MDeformWeight *dw, *(*dw_func)(MDeformVert *, const int);
 -                              unsigned int fidx= mface->v4 ? 3:2;
                                                
                                if(wp->flag & VP_ONLYVGROUP)
                                        dw_func= (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index;
                                else
                                        dw_func= defvert_verify_index;
 -
 -                              do {
 -                                      unsigned int vidx= *(&mface->v1 + fidx);
 -
 -                                      dw= dw_func(me->dvert+vidx, ob->actdef-1);
 -                                      if(dw) {
 -                                              paintweight+= dw->weight;
 +                                              
 +                              ml = me->mloop + mpoly->loopstart;
 +                              for (i=0; i<mpoly->totloop; i++, ml++) {
 +                                      dw = dw_func(me->dvert+ml->v, ob->actdef-1);
 +                                      if (dw) {
 +                                              paintweight += dw->weight;
                                                totw++;
                                        }
 -
 -                              } while (fidx--);
 -
 +                              }
                        }
                }
        }
                paintweight/= (float)totw;
                        
        for(index=0; index<totindex; index++) {
 -                              
 -              if(indexar[index] && indexar[index]<=me->totface) {
 -                      MFace *mf= me->mface + (indexar[index]-1);
 -                      unsigned int fidx= mf->v4 ? 3:2;
 -                      do {
 -                              unsigned int vidx= *(&mf->v1 + fidx);
 -
 -                              if(me->dvert[vidx].flag) {
 +              if(indexar[index] && indexar[index]<=me->totpoly) {
 +                      MPoly *mpoly= me->mpoly + (indexar[index]-1);
 +                      MLoop *ml=me->mloop+mpoly->loopstart;
 +                      int i;
 +
 +                      for (i=0; i<mpoly->totloop; i++, ml++) {
 +                              unsigned int vidx= ml->v;
 +                              if (me->dvert[vidx].flag) {
                                        alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*vidx, mval, pressure);
                                        if(alpha) {
                                                do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight);
                                        }
                                        me->dvert[vidx].flag= 0;
                                }
 -                      } while (fidx--);
 +                      }
                }
        }
  
@@@ -2333,7 -2229,7 +2311,7 @@@ static int set_vpaint(bContext *C, wmOp
                return OPERATOR_PASS_THROUGH;
        }
        
 -      if(me && me->mcol==NULL) make_vertexcol(ob);
 +      if(me && me->mloopcol==NULL) make_vertexcol(ob);
        
        /* toggle: end vpaint */
        if(ob->mode & OB_MODE_VERTEX_PAINT) {
@@@ -2401,60 -2297,14 +2379,60 @@@ For future
  
  */
  
 +typedef struct polyfacemap_e {
 +      struct polyfacemap_e *next, *prev;
 +      int facenr;
 +} polyfacemap_e;
 +
  typedef struct VPaintData {
        ViewContext vc;
        unsigned int paintcol;
        int *indexar;
        float *vertexcosnos;
        float vpimat[3][3];
 +      
 +      /*mpoly -> mface mapping*/
 +      MemArena *arena;
 +      ListBase *polyfacemap;
  } VPaintData;
  
 +static void vpaint_build_poly_facemap(struct VPaintData *vd, Mesh *me,
 +                                    Object *ob, Scene *scene)
 +{
 +      MFace *mf;
 +      polyfacemap_e *e;
 +      int *origIndex;
 +      int i;
 +
 +      vd->arena = BLI_memarena_new(1<<13, "vpaint tmp");
 +      BLI_memarena_use_calloc(vd->arena);
 +
 +      vd->polyfacemap = BLI_memarena_alloc(vd->arena, sizeof(ListBase)*me->totpoly);
 +
 +      /*we can't assume mfaces have a correct origindex layer that indices to mpolys.
 +        so instead we have to regenerate the tesselation faces altogether.*/
 +      me->totface = mesh_recalcTesselation(&me->fdata, &me->ldata, &me->pdata, 
 +              me->mvert, me->totface, me->totloop, me->totpoly, 1, 0);
 +      mesh_update_customdata_pointers(me);
 +      makeDerivedMesh(scene, ob, NULL, CD_MASK_BAREMESH, 0);
 +
 +      origIndex = CustomData_get_layer(&me->fdata, CD_ORIGINDEX);
 +      mf = me->mface;
 +
 +      if (!origIndex)
 +              return;
 +
 +      for (i=0; i<me->totface; i++, mf++, origIndex++) {
 +              if (*origIndex == ORIGINDEX_NONE)
 +                      continue;
 +
 +              e = BLI_memarena_alloc(vd->arena, sizeof(polyfacemap_e));
 +              e->facenr = i;
 +              
 +              BLI_addtail(&vd->polyfacemap[*origIndex], e);
 +      }
 +}
 +
  static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *UNUSED(event))
  {
        ToolSettings *ts= CTX_data_tool_settings(C);
        VPaint *vp= ts->vpaint;
        struct VPaintData *vpd;
        Object *ob= CTX_data_active_object(C);
 +      Scene *scene = CTX_data_scene(C);
        Mesh *me;
        float mat[4][4], imat[4][4];
  
        /* context checks could be a poll() */
        me= get_mesh(ob);
 -      if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH;
 +      if(me==NULL || me->totpoly==0)
 +              return OPERATOR_PASS_THROUGH;
        
 -      if(me->mcol==NULL) make_vertexcol(ob);
 -      if(me->mcol==NULL) return OPERATOR_CANCELLED;
 +      if(me->mloopcol==NULL)
 +              make_vertexcol(ob);
 +      if(me->mloopcol==NULL)
 +              return OPERATOR_CANCELLED;
        
        /* make mode data storage */
        vpd= MEM_callocN(sizeof(struct VPaintData), "VPaintData");
        vpd->vertexcosnos= mesh_get_mapped_verts_nors(vpd->vc.scene, ob);
        vpd->indexar= get_indexarray(me);
        vpd->paintcol= vpaint_get_current_col(vp);
 +      vpaint_build_poly_facemap(vpd, me, ob, scene);
        
        /* for filtering */
 -      copy_vpaint_prev(vp, (unsigned int *)me->mcol, me->totface);
 +      copy_vpaint_prev(vp, (unsigned int *)me->mloopcol, me->totloop);
        
        /* some old cruft to sort out later */
        mul_m4_m4m4(mat, ob->obmat, vpd->vc.rv3d->viewmat);
        return 1;
  }
  
 -static void vpaint_paint_face(VPaint *vp, VPaintData *vpd, Object *ob, const unsigned int index, const float mval[2], float pressure, int UNUSED(flip))
 +#if 0
 +static void vpaint_paint_face(VPaint *vp, VPaintData *vpd, Object *ob, int index, const float mval[2], float pressure, int UNUSED(flip))
  {
        ViewContext *vc = &vpd->vc;
        Brush *brush = paint_brush(&vp->paint);
                        vpaint_blend(vp, mcol+i, mcolorig+i, vpd->paintcol, (int)(alpha*255.0f));
        }
  }
 +#endif
  
  static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
  {
        Brush *brush = paint_brush(&vp->paint);
        ViewContext *vc= &vpd->vc;
        Object *ob= vc->obact;
 +      polyfacemap_e *e;
        Mesh *me= ob->data;
        float mat[4][4];
        int *indexar= vpd->indexar;
                        
        /* which faces are involved */
        if(vp->flag & VP_AREA) {
 -              totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush_size(brush));
 +              totindex= sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size(brush));
        }
        else {
                indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]);
                        
        swap_m4m4(vc->rv3d->persmat, mat);
                        
 -      for(index=0; index<totindex; index++) {                         
 -              if(indexar[index] && indexar[index]<=me->totface)
 -                      vpaint_paint_face(vp, vpd, ob, indexar[index]-1, mval, pressure, flip);
 +      if(vp->flag & VP_COLINDEX) {
 +              for(index=0; index<totindex; index++) {
 +                      if(indexar[index] && indexar[index]<=me->totpoly) {
 +                              MPoly *mpoly= ((MPoly *)me->mpoly) + (indexar[index]-1);
 +                                              
 +                              if(mpoly->mat_nr!=ob->actcol-1) {
 +                                      indexar[index]= 0;
 +                              }
 +                      }                                       
 +              }
        }
 +
 +      if((me->editflag & ME_EDIT_PAINT_MASK) && me->mpoly) {
 +              for(index=0; index<totindex; index++) {
 +                      if(indexar[index] && indexar[index]<=me->totpoly) {
 +                              MPoly *mpoly= ((MPoly *)me->mpoly) + (indexar[index]-1);
                                                
 +                              if((mpoly->flag & ME_FACE_SEL)==0)
 +                                      indexar[index]= 0;
 +                      }                                       
 +              }
 +      }
 +      
        swap_m4m4(vc->rv3d->persmat, mat);
  
        /* was disabled because it is slow, but necessary for blur */
        if(brush->vertexpaint_tool == VP_BLUR)
                do_shared_vertexcol(me);
                        
 -      ED_region_tag_redraw(vc->ar);
 +      for(index=0; index<totindex; index++) {
 +                              
 +              if(indexar[index] && indexar[index]<=me->totpoly) {
 +                      MPoly *mpoly= ((MPoly *)me->mpoly) + (indexar[index]-1);
 +                      MFace *mf;
 +                      MCol *mc;
 +                      MLoop *ml;
 +                      MLoopCol *mlc;
 +                      unsigned int *lcol = ((unsigned int*)me->mloopcol) + mpoly->loopstart;
 +                      unsigned int *lcolorig = ((unsigned int*)vp->vpaint_prev) + mpoly->loopstart;
 +                      float alpha;
 +                      int i, j;
 +                                      
 +                      if(brush->vertexpaint_tool==VP_BLUR) {
 +                              unsigned int blend[5] = {0};
 +                              char *col;
 +
 +                              for (j=0; j<mpoly->totloop; j += 2) {
 +                                      col = (char*)(lcol + j);
 +                                      blend[0] += col[0];
 +                                      blend[1] += col[1];
 +                                      blend[2] += col[2];
 +                                      blend[3] += col[3];
 +                              }
 +
 +                              blend[0] /= mpoly->totloop;
 +                              blend[1] /= mpoly->totloop;
 +                              blend[2] /= mpoly->totloop;
 +                              blend[3] /= mpoly->totloop;
 +                              col = (char*)(blend + 4);
 +                              col[0] = blend[0];
 +                              col[1] = blend[1];
 +                              col[2] = blend[2];
 +                              col[3] = blend[3];
 +
 +                              vpd->paintcol = *((unsigned int*)col);
 +                      }
 +
 +                      ml = me->mloop + mpoly->loopstart;
 +                      for (i=0; i<mpoly->totloop; i++, ml++) {
 +                              alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, 
 +                                         vpd->vertexcosnos+6*ml->v, mval, pressure);
 +                              if(alpha > 0.0f) vpaint_blend(vp, lcol+i, lcolorig+i, vpd->paintcol, (int)(alpha*255.0f));
 +                      }
 +      
 +                      #ifdef CPYCOL
 +                      #undef CPYCOL
 +                      #endif
 +                      #define CPYCOL(c, l) (c)->a = (l)->a, (c)->r = (l)->r, (c)->g = (l)->g, (c)->b = (l)->b
 +
 +                      /*update vertex colors for tesselations incrementally,
 +                        rather then regenerating the tesselation altogether.*/
 +                      for (e=vpd->polyfacemap[(indexar[index]-1)].first; e; e=e->next) {
 +                              mf = me->mface + e->facenr;
 +                              mc = me->mcol + e->facenr*4;
 +                              
 +                              ml = me->mloop + mpoly->loopstart;
 +                              mlc = me->mloopcol + mpoly->loopstart;
 +                              for (j=0; j<mpoly->totloop; j++, ml++, mlc++) {
 +                                      if (ml->v == mf->v1)
 +                                              CPYCOL(mc, mlc);
 +                                      else if (ml->v == mf->v2)
 +                                              CPYCOL(mc+1, mlc);
 +                                      else if (ml->v == mf->v3)
 +                                              CPYCOL(mc+2, mlc);
 +                                      else if (mf->v4 && ml->v == mf->v4)
 +                                              CPYCOL(mc+3, mlc);
 +
 +                              }
 +                      }
 +                      #undef CPYCOL
 +              }
 +      }
 +              
 +      swap_m4m4(vc->rv3d->persmat, mat);
                        
 +      /* was disabled because it is slow, but necessary for blur */
 +      if(brush->vertexpaint_tool == VP_BLUR) {
 +              do_shared_vertexcol(me);
 +      }
 +
 +      ED_region_tag_redraw(vc->ar);           
        DAG_id_tag_update(ob->data, 0);
  }
  
@@@ -2698,8 -2442,7 +2676,8 @@@ static void vpaint_stroke_done(bContex
        
        /* frees prev buffer */
        copy_vpaint_prev(ts->vpaint, NULL, 0);
 -      
 +      BLI_memarena_free(vpd->arena);
 +
        MEM_freeN(vpd);
  }
  
index 72a07f1b3c9bc6491a4316c2baf4ba392d1018a0,759fefba438053b19d1d6af150c72137ad080dc4..42f28c9fb7cb2e2d49494976e62df524846d1ea9
@@@ -82,8 -82,6 +82,8 @@@
  #include "BLI_editVert.h"
  #include "BLI_ghash.h"
  #include "BLI_linklist.h"
 +#include "BLI_smallhash.h"
 +#include "BLI_array.h"
  
  #include "UI_resources.h"
  
@@@ -93,8 -91,6 +93,8 @@@
  
  #include "transform.h"
  
 +#include <stdio.h>
 +
  void drawTransformApply(const struct bContext *C, struct ARegion *ar, void *arg);
  int doEdgeSlide(TransInfo *t, float perc);
  
@@@ -122,10 -118,22 +122,22 @@@ void setTransformViewMatrices(TransInf
        calculateCenter2D(t);
  }
  
+ static void convertViewVec2D(View2D *v2d, float *vec, int dx, int dy)
+ {
+       float divx, divy;
+       
+       divx= v2d->mask.xmax - v2d->mask.xmin;
+       divy= v2d->mask.ymax - v2d->mask.ymin;
+       vec[0]= (v2d->cur.xmax - v2d->cur.xmin) * dx / divx;
+       vec[1]= (v2d->cur.ymax - v2d->cur.ymin) * dy / divy;
+       vec[2]= 0.0f;
+ }
  void convertViewVec(TransInfo *t, float *vec, int dx, int dy)
  {
-       if (t->spacetype==SPACE_VIEW3D) {
-               if (t->ar->regiontype == RGN_TYPE_WINDOW) {
+       if(t->spacetype==SPACE_VIEW3D) {
+               if(t->ar->regiontype == RGN_TYPE_WINDOW) {
                        float mval_f[2];
                        mval_f[0]= dx;
                        mval_f[1]= dy;
                }
        }
        else if(t->spacetype==SPACE_IMAGE) {
-               View2D *v2d = t->view;
-               float divx, divy, aspx, aspy;
+               float aspx, aspy;
  
-               ED_space_image_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
-               divx= v2d->mask.xmax-v2d->mask.xmin;
-               divy= v2d->mask.ymax-v2d->mask.ymin;
+               convertViewVec2D(t->view, vec, dx, dy);
  
-               vec[0]= aspx*(v2d->cur.xmax-v2d->cur.xmin)*(dx)/divx;
-               vec[1]= aspy*(v2d->cur.ymax-v2d->cur.ymin)*(dy)/divy;
-               vec[2]= 0.0f;
+               ED_space_image_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
+               vec[0]*= aspx;
+               vec[1]*= aspy;
        }
        else if(ELEM(t->spacetype, SPACE_IPO, SPACE_NLA)) {
-               View2D *v2d = t->view;
-               float divx, divy;
-               divx= v2d->mask.xmax-v2d->mask.xmin;
-               divy= v2d->mask.ymax-v2d->mask.ymin;
-               vec[0]= (v2d->cur.xmax-v2d->cur.xmin)*(dx) / (divx);
-               vec[1]= (v2d->cur.ymax-v2d->cur.ymin)*(dy) / (divy);
-               vec[2]= 0.0f;
+               convertViewVec2D(t->view, vec, dx, dy);
        }
-       else if(t->spacetype==SPACE_NODE) {
-               View2D *v2d = &t->ar->v2d;
-               float divx, divy;
-               divx= v2d->mask.xmax-v2d->mask.xmin;
-               divy= v2d->mask.ymax-v2d->mask.ymin;
-               vec[0]= (v2d->cur.xmax-v2d->cur.xmin)*(dx)/divx;
-               vec[1]= (v2d->cur.ymax-v2d->cur.ymin)*(dy)/divy;
-               vec[2]= 0.0f;
-       }
-       else if(t->spacetype==SPACE_SEQ) {
-               View2D *v2d = &t->ar->v2d;
-               float divx, divy;
-               divx= v2d->mask.xmax-v2d->mask.xmin;
-               divy= v2d->mask.ymax-v2d->mask.ymin;
-               vec[0]= (v2d->cur.xmax-v2d->cur.xmin)*(dx)/divx;
-               vec[1]= (v2d->cur.ymax-v2d->cur.ymin)*(dy)/divy;
-               vec[2]= 0.0f;
+       else if(ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) {
+               convertViewVec2D(&t->ar->v2d, vec, dx, dy);
        }
  }
  
@@@ -3458,8 -3435,7 +3439,8 @@@ static void applyTranslation(TransInfo 
                
                protectedTransBits(td->protectflag, tvec);
                
 -              add_v3_v3v3(td->loc, td->iloc, tvec);
 +              if (td->loc)
 +                      add_v3_v3v3(td->loc, td->iloc, tvec);
                
                constraintTransLim(t, td);
        }
@@@ -4252,467 -4228,506 +4233,467 @@@ int BoneEnvelope(TransInfo *t, const in
  }
  
  /* ********************  Edge Slide   *************** */
 +static BMEdge *get_other_edge(BMesh *bm, BMVert *v, BMEdge *e)
 +{
 +      BMIter iter;
 +      BMEdge *e2;
 +
 +      BM_ITER(e2, &iter, bm, BM_EDGES_OF_VERT, v) {
 +              if (BM_TestHFlag(e2, BM_SELECT) && e2 != e)
 +                      return e2;
 +      }
 +
 +      return NULL;
 +}
 +
 +static BMLoop *get_next_loop(BMesh *UNUSED(bm), BMVert *v, BMLoop *l, 
 +                             BMEdge *olde, BMEdge *nexte, float vec[3])
 +{
 +      BMLoop *firstl;
 +      float a[3] = {0.0f, 0.0f, 0.0f}, n[3] = {0.0f, 0.0f, 0.0f};
 +      int i=0;
 +
 +      firstl = l;
 +      do {
 +              l = BM_OtherFaceLoop(l->e, l->f, v);
 +              if (l->radial_next == l)
 +                      return NULL;
 +              
 +              if (l->e == nexte) {
 +                      if (i) {
 +                              mul_v3_fl(a, 1.0f / (float)i);
 +                      } else {
 +                              float f1[3], f2[3], f3[3];
 +
 +                              sub_v3_v3v3(f1, BM_OtherEdgeVert(olde, v)->co, v->co);
 +                              sub_v3_v3v3(f2, BM_OtherEdgeVert(nexte, v)->co, v->co);
 +
 +                              cross_v3_v3v3(f3, f1, l->f->no);
 +                              cross_v3_v3v3(a, f2, l->f->no);
 +                              mul_v3_fl(a, -1.0f);
 +
 +                              add_v3_v3(a, f3);
 +                              mul_v3_fl(a, 0.5f);
 +                      }
 +                      
 +                      copy_v3_v3(vec, a);
 +                      return l;
 +              } else {
 +                      sub_v3_v3v3(n, BM_OtherEdgeVert(l->e, v)->co, v->co);
 +                      add_v3_v3v3(a, a, n);
 +                      i += 1;
 +              }
 +
 +              if (BM_OtherFaceLoop(l->e, l->f, v)->e == nexte) {
 +                      if (i)
 +                              mul_v3_fl(a, 1.0f / (float)i);
 +                      
 +                      copy_v3_v3(vec, a);
 +                      return BM_OtherFaceLoop(l->e, l->f, v);
 +              }
 +              
 +              l = l->radial_next;
 +      } while (l != firstl); 
 +
 +      if (i)
 +              mul_v3_fl(a, 1.0f / (float)i);
 +      
 +      copy_v3_v3(vec, a);
 +      
 +      return NULL;
 +}
  
  static int createSlideVerts(TransInfo *t)
  {
        Mesh *me = t->obedit->data;
 -      EditMesh *em = me->edit_mesh;
 -      EditFace *efa;
 -      EditEdge *eed,*first=NULL,*last=NULL, *temp = NULL;
 -      EditVert *ev, *nearest = NULL;
 -      LinkNode *edgelist = NULL, *vertlist=NULL, *look;
 -      GHash *vertgh;
 +      BMEditMesh *em = me->edit_btmesh;
 +      BMesh *bm = em->bm;
 +      BMIter iter, iter2;
 +      BMEdge *e, *e1, *ee, *le;
 +      BMVert *v, *v2, *first;
 +      BMLoop *l, *l1, *l2;
        TransDataSlideVert *tempsv;
 -      int i, j, numsel, numadded=0, timesthrough = 0, vertsel=0;
 -      /* UV correction vars */
 -      GHash **uvarray= NULL;
 +      BMBVHTree *btree = BMBVH_NewBVH(em, 0, NULL, NULL);
 +      SmallHash table;
        SlideData *sld = MEM_callocN(sizeof(*sld), "sld");
 -      const int  uvlay_tot=  (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) ? CustomData_number_of_layers(&em->fdata, CD_MTFACE) : 0;
 -      int uvlay_idx;
 -      TransDataSlideUv *slideuvs=NULL, *suv=NULL, *suv_last=NULL;
 -      RegionView3D *v3d = t->ar ? t->ar->regiondata : NULL; /* background mode support */
 +      View3D *v3d = t->sa ? t->sa->spacedata.first : NULL;
 +      RegionView3D *rv3d = t->ar ? t->ar->regiondata : NULL; /* background mode support */
 +      ARegion *ar = t->ar;
        float projectMat[4][4];
 -      float start[3] = {0.0f, 0.0f, 0.0f}, end[3] = {0.0f, 0.0f, 0.0f};
 -      float vec[3];
 -      float totvec=0.0;
 +      float start[3] = {0.0f, 0.0f, 0.0f}, dir[3], end[3] = {0.0f, 0.0f, 0.0f};
 +      float vec[3], vec2[3], lastvec[3], size, dis=0.0, z;
 +      int numsel, i, j;
  
        if (!v3d) {
                /*ok, let's try to survive this*/
                unit_m4(projectMat);
        } else {
 -              ED_view3d_ob_project_mat_get(v3d, t->obedit, projectMat);
 +              ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
        }
        
 -      numsel =0;
 -
 -      // Get number of selected edges and clear some flags
 -      for(eed=em->edges.first;eed;eed=eed->next) {
 -              eed->f1 = 0;
 -              eed->f2 = 0;
 -              if(eed->f & SELECT) numsel++;
 -      }
 -
 -      for(ev=em->verts.first;ev;ev=ev->next) {
 -              ev->f1 = 0;
 -      }
 +      BLI_smallhash_init(&sld->vhash);
 +      BLI_smallhash_init(&sld->origfaces);
 +      BLI_smallhash_init(&table);
 +      
 +      /*ensure valid selection*/
 +      BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
 +              if (BM_TestHFlag(v, BM_SELECT)) {
 +                      numsel = 0;
 +                      BM_ITER(e, &iter2, em->bm, BM_EDGES_OF_VERT, v) {
 +                              if (BM_TestHFlag(e, BM_SELECT)) {
 +                                      /*BMESH_TODO: this is probably very evil,
 +                                        set v->e to a selected edge*/
 +                                      v->e = e;
  
 -      //Make sure each edge only has 2 faces
 -      // make sure loop doesn't cross face
 -      for(efa=em->faces.first;efa;efa=efa->next) {
 -              int ct = 0;
 -              if(efa->e1->f & SELECT) {
 -                      ct++;
 -                      efa->e1->f1++;
 -                      if(efa->e1->f1 > 2) {
 -                              //BKE_report(op->reports, RPT_ERROR, "3+ face edge");
 -                              MEM_freeN(sld);
 -                              return 0;
 -                      }
 -              }
 -              if(efa->e2->f & SELECT) {
 -                      ct++;
 -                      efa->e2->f1++;
 -                      if(efa->e2->f1 > 2) {
 -                              //BKE_report(op->reports, RPT_ERROR, "3+ face edge");
 -                              MEM_freeN(sld);
 -                              return 0;
 -                      }
 -              }
 -              if(efa->e3->f & SELECT) {
 -                      ct++;
 -                      efa->e3->f1++;
 -                      if(efa->e3->f1 > 2) {
 -                              //BKE_report(op->reports, RPT_ERROR, "3+ face edge");
 -                              MEM_freeN(sld);
 -                              return 0;
 +                                      numsel++;
 +                              }
                        }
 -              }
 -              if(efa->e4 && efa->e4->f & SELECT) {
 -                      ct++;
 -                      efa->e4->f1++;
 -                      if(efa->e4->f1 > 2) {
 -                              //BKE_report(op->reports, RPT_ERROR, "3+ face edge");
 -                              MEM_freeN(sld);
 -                              return 0;
 +
 +                      if (numsel == 0 || numsel > 2) {
 +                              return 0; //invalid edge selection
                        }
                }
 -              // Make sure loop is not 2 edges of same face
 -              if(ct > 1) {
 -                 //BKE_report(op->reports, RPT_ERROR, "Loop crosses itself");
 -                      MEM_freeN(sld);
 -                      return 0;
 +      }
 +
 +      BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
 +              if (BM_TestHFlag(e, BM_SELECT)) {
 +                      if (BM_Edge_FaceCount(e) != 2)
 +                              return 0; //can only handle exactly 2 faces around each edge
                }
        }
  
 -      // Get # of selected verts
 -      for(ev=em->verts.first;ev;ev=ev->next) {
 -              if(ev->f & SELECT) vertsel++;
 +      j = 0;
 +      BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
 +              if (BM_TestHFlag(v, BM_SELECT)) {
 +                      BM_SetHFlag(v, BM_TMP_TAG);
 +                      BLI_smallhash_insert(&table, (uintptr_t)v, SET_INT_IN_POINTER(j));
 +                      j += 1;
 +              }
 +              else {
 +                      BM_ClearHFlag(v, BM_TMP_TAG);
 +              }
        }
  
 -      // Test for multiple segments
 -      if(vertsel > numsel+1) {
 -              //BKE_report(op->reports, RPT_ERROR, "Please choose a single edge loop");
 -              MEM_freeN(sld);
 +      if (!j)
                return 0;
 -      }
  
 -      // Get the edgeloop in order - mark f1 with SELECT once added
 -      for(eed=em->edges.first;eed;eed=eed->next) {
 -              if((eed->f & SELECT) && !(eed->f1 & SELECT)) {
 -                      // If this is the first edge added, just put it in
 -                      if(!edgelist) {
 -                              BLI_linklist_prepend(&edgelist,eed);
 -                              numadded++;
 -                              first = eed;
 -                              last  = eed;
 -                              eed->f1 = SELECT;
 -                      } else {
 -                              if(editedge_getSharedVert(eed, last)) {
 -                                      BLI_linklist_append(&edgelist,eed);
 -                                      eed->f1 = SELECT;
 -                                      numadded++;
 -                                      last = eed;
 -                              }  else if(editedge_getSharedVert(eed, first)) {
 -                                      BLI_linklist_prepend(&edgelist,eed);
 -                                      eed->f1 = SELECT;
 -                                      numadded++;
 -                                      first = eed;
 -                              }
 -                      }
 -              }
 -              if(eed->next == NULL && numadded != numsel) {
 -                      eed=em->edges.first;
 -                      timesthrough++;
 -              }
 +      tempsv = MEM_callocN(sizeof(TransDataSlideVert)*j, "tempsv");
 +
 +      j = 0;
 +      while (1) {
 +              v = NULL;
 +              BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
 +                      if (BM_TestHFlag(v, BM_TMP_TAG))
 +                              break;
  
 -              // It looks like there was an unexpected case - Hopefully should not happen
 -              if(timesthrough >= numsel*2) {
 -                      BLI_linklist_free(edgelist,NULL);
 -                      //BKE_report(op->reports, RPT_ERROR, "Could not order loop");
 -                      MEM_freeN(sld);
 -                      return 0;
                }
 -      }
  
 -      // Put the verts in order in a linklist
 -      look = edgelist;
 -      while(look) {
 -              eed = look->link;
 -              if(!vertlist) {
 -                      if(look->next) {
 -                              temp = look->next->link;
 +              if (!v)
 +                      break;
  
 -                              //This is the first entry takes care of extra vert
 -                              if(eed->v1 != temp->v1 && eed->v1 != temp->v2) {
 -                                      BLI_linklist_append(&vertlist,eed->v1);
 -                                      eed->v1->f1 = 1;
 -                              } else {
 -                                      BLI_linklist_append(&vertlist,eed->v2);
 -                                      eed->v2->f1 = 1;
 -                              }
 -                      } else {
 -                              //This is the case that we only have 1 edge
 -                              BLI_linklist_append(&vertlist,eed->v1);
 -                              eed->v1->f1 = 1;
 -                      }
 -              }
 -              // for all the entries
 -              if(eed->v1->f1 != 1) {
 -                      BLI_linklist_append(&vertlist,eed->v1);
 -                      eed->v1->f1 = 1;
 -              } else  if(eed->v2->f1 != 1) {
 -                      BLI_linklist_append(&vertlist,eed->v2);
 -                      eed->v2->f1 = 1;
 -              }
 -              look = look->next;
 -      }
 -
 -      // populate the SlideVerts
 -
 -      vertgh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "createSlideVerts gh");
 -      look = vertlist;
 -      while(look) {
 -              i=0;
 -              j=0;
 -              ev = look->link;
 -              tempsv = (struct TransDataSlideVert*)MEM_mallocN(sizeof(struct TransDataSlideVert),"SlideVert");
 -              tempsv->up = NULL;
 -              tempsv->down = NULL;
 -              tempsv->origvert.co[0] = ev->co[0];
 -              tempsv->origvert.co[1] = ev->co[1];
 -              tempsv->origvert.co[2] = ev->co[2];
 -              tempsv->origvert.no[0] = ev->no[0];
 -              tempsv->origvert.no[1] = ev->no[1];
 -              tempsv->origvert.no[2] = ev->no[2];
 -              // i is total edges that vert is on
 -              // j is total selected edges that vert is on
 -
 -              for(eed=em->edges.first;eed;eed=eed->next) {
 -                      if(eed->v1 == ev || eed->v2 == ev) {
 -                              i++;
 -                              if(eed->f & SELECT) {
 -                                       j++;
 -                              }
 -                      }
 -              }
 -              // If the vert is in the middle of an edge loop, it touches 2 selected edges and 2 unselected edges
 -              if(i == 4 && j == 2) {
 -                      for(eed=em->edges.first;eed;eed=eed->next) {
 -                              if(editedge_containsVert(eed, ev)) {
 -                                      if(!(eed->f & SELECT)) {
 -                                              if(!tempsv->up) {
 -                                                      tempsv->up = eed;
 -                                              } else if (!(tempsv->down)) {
 -                                                      tempsv->down = eed;
 -                                              }
 -                                      }
 -                              }
 -                      }
 -              }
 -              // If it is on the end of the loop, it touches 1 selected and as least 2 more unselected
 -              if(i >= 3 && j == 1) {
 -                      for(eed=em->edges.first;eed;eed=eed->next) {
 -                              if(editedge_containsVert(eed, ev) && eed->f & SELECT) {
 -                                      for(efa = em->faces.first;efa;efa=efa->next) {
 -                                              if(editface_containsEdge(efa, eed)) {
 -                                                      if(editedge_containsVert(efa->e1, ev) && efa->e1 != eed) {
 -                                                              if(!tempsv->up) {
 -                                                                      tempsv->up = efa->e1;
 -                                                              } else if (!(tempsv->down)) {
 -                                                                      tempsv->down = efa->e1;
 -                                                              }
 -                                                      }
 -                                                      if(editedge_containsVert(efa->e2, ev) && efa->e2 != eed) {
 -                                                              if(!tempsv->up) {
 -                                                                      tempsv->up = efa->e2;
 -                                                              } else if (!(tempsv->down)) {
 -                                                                      tempsv->down = efa->e2;
 -                                                              }
 -                                                      }
 -                                                      if(editedge_containsVert(efa->e3, ev) && efa->e3 != eed) {
 -                                                              if(!tempsv->up) {
 -                                                                      tempsv->up = efa->e3;
 -                                                              } else if (!(tempsv->down)) {
 -                                                                      tempsv->down = efa->e3;
 -                                                              }
 -                                                      }
 -                                                      if(efa->e4) {
 -                                                              if(editedge_containsVert(efa->e4, ev) && efa->e4 != eed) {
 -                                                                      if(!tempsv->up) {
 -                                                                              tempsv->up = efa->e4;
 -                                                                      } else if (!(tempsv->down)) {
 -                                                                              tempsv->down = efa->e4;
 -                                                                      }
 -                                                              }
 -                                                      }
 +              if (!v->e)
 +                      continue;
 +              
 +              first = v;
  
 -                                              }
 -                                      }
 -                              }
 +              /*walk along the edge loop*/
 +              e = v->e;
 +
 +              /*first, rewind*/
 +              numsel = 0;
 +              do {
 +                      e = get_other_edge(bm, v, e);
 +                      if (!e) {
 +                              e = v->e;
 +                              break;
                        }
 -              }
 -              if(i > 4 && j == 2) {
 -                      BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN);
 -                      BLI_linklist_free(vertlist,NULL);
 -                      BLI_linklist_free(edgelist,NULL);
 -                      return 0;
 -              }
 -              BLI_ghash_insert(vertgh,ev,tempsv);
  
 -              look = look->next;
 -      }
 +                      numsel += 1;
 +
 +                      if (!BM_TestHFlag(BM_OtherEdgeVert(e, v), BM_TMP_TAG))
 +                              break;
  
 -      // make sure the UPs and DOWNs are 'faceloops'
 -      // Also find the nearest slidevert to the cursor
 +                      v = BM_OtherEdgeVert(e, v);
 +              } while (e != first->e);
  
 -      look = vertlist;
 -      nearest = NULL;
 -      while(look) {
 -              tempsv  = BLI_ghash_lookup(vertgh,(EditVert*)look->link);
 +              BM_ClearHFlag(v, BM_TMP_TAG);
  
 -              if(!tempsv->up || !tempsv->down) {
 -                      //BKE_report(op->reports, RPT_ERROR, "Missing rails");
 -                      BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN);
 -                      BLI_linklist_free(vertlist,NULL);
 -                      BLI_linklist_free(edgelist,NULL);
 -                      return 0;
 -              }
 +              l1 = l2 = l = NULL;
 +              l1 = e->l;
 +              l2 = e->l->radial_next;
  
 -              if(me->drawflag & ME_DRAWEXTRA_EDGELEN) {
 -                      if(!(tempsv->up->f & SELECT)) {
 -                              tempsv->up->f |= SELECT;
 -                              tempsv->up->f2 |= 16;
 -                      } else {
 -                              tempsv->up->f2 |= ~16;
 -                      }
 -                      if(!(tempsv->down->f & SELECT)) {
 -                              tempsv->down->f |= SELECT;
 -                              tempsv->down->f2 |= 16;
 -                      } else {
 -                              tempsv->down->f2 |= ~16;
 -                      }
 -              }
 +              l = BM_OtherFaceLoop(l1->e, l1->f, v);
 +              sub_v3_v3v3(vec, BM_OtherEdgeVert(l->e, v)->co, v->co);
  
 -              if(look->next != NULL) {
 -                      TransDataSlideVert *sv;
 -                      
 -                      ev = (EditVert*)look->next->link;
 -                      sv = BLI_ghash_lookup(vertgh, ev);
 +              if (l2 != l1) {
 +                      l = BM_OtherFaceLoop(l2->e, l2->f, v);
 +                      sub_v3_v3v3(vec2, BM_OtherEdgeVert(l->e, v)->co, v->co);
 +              } else {
 +                      l2 = NULL;
 +              }
  
 -                      if(sv) {
 -                              float co[3], co2[3], tvec[3];
 +              /*iterate over the loop*/
 +              first = v;
 +              do {
 +                      TransDataSlideVert *sv = tempsv + j;
  
 -                              ev = (EditVert*)look->link;
 +                      sv->v = v;
 +                      sv->origvert = *v;
 +                      VECCOPY(sv->upvec, vec);
 +                      if (l2)
 +                              VECCOPY(sv->downvec, vec2);
  
 -                              if(!sharesFace(em, tempsv->up,sv->up)) {
 -                                      EditEdge *swap;
 -                                      swap = sv->up;
 -                                      sv->up = sv->down;
 -                                      sv->down = swap;
 -                              }
 -                              
 -                              if (v3d) {
 -                                      ED_view3d_project_float(t->ar, tempsv->up->v1->co, co, projectMat);
 -                                      ED_view3d_project_float(t->ar, tempsv->up->v2->co, co2, projectMat);
 -                              }
 +                      l = BM_OtherFaceLoop(l1->e, l1->f, v);
 +                      sv->up = BM_OtherEdgeVert(l->e, v);
  
 -                              if (ev == tempsv->up->v1) {
 -                                      sub_v3_v3v3(tvec, co, co2);
 -                              } else {
 -                                      sub_v3_v3v3(tvec, co2, co);
 -                              }
 +                      if (l2) {
 +                              l = BM_OtherFaceLoop(l2->e, l2->f, v);
 +                              sv->down = BM_OtherEdgeVert(l->e, v);
 +                      }
  
 -                              add_v3_v3(start, tvec);
 +                      v2=v, v = BM_OtherEdgeVert(e, v);
  
 -                              if (v3d) {
 -                                      ED_view3d_project_float(t->ar, tempsv->down->v1->co, co, projectMat);
 -                                      ED_view3d_project_float(t->ar, tempsv->down->v2->co, co2, projectMat);
 -                              }
 +                      e1 = e;
 +                      e = get_other_edge(bm, v, e);
 +                      if (!e) {
 +                              //v2=v, v = BM_OtherEdgeVert(l1->e, v);
  
 -                              if (ev == tempsv->down->v1) {
 -                                      sub_v3_v3v3(tvec, co2, co);
 -                              } else {
 -                                      sub_v3_v3v3(tvec, co, co2);
 +                              sv = tempsv + j + 1;
 +                              sv->v = v;
 +                              sv->origvert = *v;
 +                              
 +                              l = BM_OtherFaceLoop(l1->e, l1->f, v);
 +                              sv->up = BM_OtherEdgeVert(l->e, v);
 +                              sub_v3_v3v3(sv->upvec, BM_OtherEdgeVert(l->e, v)->co, v->co);
 +
 +                              if (l2) {
 +                                      l = BM_OtherFaceLoop(l2->e, l2->f, v);
 +                                      sv->down = BM_OtherEdgeVert(l->e, v);
 +                                      sub_v3_v3v3(sv->downvec, BM_OtherEdgeVert(l->e, v)->co, v->co);
                                }
  
 -                              add_v3_v3(end, tvec);
 -
 -                              totvec += 1.0f;
 -                              nearest = (EditVert*)look->link;
 +                              BM_ClearHFlag(v, BM_TMP_TAG);
 +                              BM_ClearHFlag(v2, BM_TMP_TAG);
 +                              
 +                              j += 2;
 +                              break;
                        }
 -              }
  
 +                      l1 = get_next_loop(bm, v, l1, e1, e, vec);
 +                      l2 = l2 ? get_next_loop(bm, v, l2, e1, e, vec2) : NULL;
  
 +                      j += 1;
  
 -              look = look->next;
 +                      BM_ClearHFlag(v, BM_TMP_TAG);
 +                      BM_ClearHFlag(v2, BM_TMP_TAG);
 +              } while (e != first->e && l1);
        }
  
 -      add_v3_v3(start, end);
 -      mul_v3_fl(start, 0.5f*(1.0f/totvec));
 -      copy_v3_v3(vec, start);
 -      start[0] = t->mval[0];
 -      start[1] = t->mval[1];
 -      add_v3_v3v3(end, start, vec);
 +      //EDBM_clear_flag_all(em, BM_SELECT);
  
 +      sld->sv = tempsv;
 +      sld->totsv = j;
 +      
 +      /*find mouse vector*/
 +      dis = z = -1.0f;
 +      size = 50.0;
 +      zero_v3(lastvec); zero_v3(dir);
 +      ee = le = NULL;
 +      BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
 +              if (BM_TestHFlag(e, BM_SELECT)) {
 +                      BMIter iter2;
 +                      BMEdge *e2;
 +                      float vec1[3], dis2, mval[2] = {t->mval[0], t->mval[1]}, d;
 +                                              
 +                      /*search cross edges for visible edge to the mouse cursor,
 +              then use the shared vertex to calculate screen vector*/
 +                      dis2 = -1.0f;
 +                      for (i=0; i<2; i++) {
 +                              v = i?e->v1:e->v2;
 +                              BM_ITER(e2, &iter2, em->bm, BM_EDGES_OF_VERT, v) {
 +                                      if (BM_TestHFlag(e2, BM_SELECT))
 +                                              continue;
 +                                      
 +                                      if (!BMBVH_EdgeVisible(btree, e2, ar, v3d, t->obedit))
 +                                              continue;
 +                                      
 +                                      j = GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v));
 +
 +                                      if (tempsv[j].down) {
 +                                              ED_view3d_project_float_v3(ar, tempsv[j].down->co, vec1, projectMat);
 +                                      } else {
 +                                              add_v3_v3v3(vec1, v->co, tempsv[j].downvec);
 +                                              ED_view3d_project_float_v3(ar, vec1, vec1, projectMat);
 +                                      }
 +                                      
 +                                      if (tempsv[j].up) {
 +                                              ED_view3d_project_float_v3(ar, tempsv[j].up->co, vec2, projectMat);
 +                                      } else {
 +                                              add_v3_v3v3(vec1, v->co, tempsv[j].upvec);
 +                                              ED_view3d_project_float_v3(ar, vec2, vec2, projectMat);
 +                                      }
  
 -      /* Ensure minimum screen distance, when looking top down on edge loops */
 -#define EDGE_SLIDE_MIN 30
 -      if (len_squared_v2v2(start, end) < (EDGE_SLIDE_MIN * EDGE_SLIDE_MIN)) {
 -              if(ABS(start[0]-end[0]) + ABS(start[1]-end[1]) < 4.0f) {
 -                      /* even more exceptional case, points are ontop of each other */
 -                      end[0]= start[0];
 -                      end[1]= start[1] + EDGE_SLIDE_MIN;
 -              }
 -              else {
 -                      sub_v2_v2(end, start);
 -                      normalize_v2(end);
 -                      mul_v2_fl(end, EDGE_SLIDE_MIN);
 -                      add_v2_v2(end, start);
 +                                      d = dist_to_line_segment_v2(mval, vec1, vec2);
 +                                      if (dis2 == -1.0f || d < dis2) {
 +                                              dis2 = d;
 +                                              ee = e2;
 +                                              size = len_v3v3(vec1, vec2);
 +                                              sub_v3_v3v3(dir, vec1, vec2);
 +                                      }
 +                              }
 +                      }
                }
        }
 -#undef EDGE_SLIDE_MIN
 +      
 +      em->bm->ob = t->obedit;
 +      bmesh_begin_edit(em->bm, BMOP_UNTAN_MULTIRES);
  
 +      /*create copies of faces for customdata projection*/
 +      tempsv = sld->sv;
 +      for (i=0; i<sld->totsv; i++, tempsv++) {
 +              BMIter fiter, liter;
 +              BMFace *f;
 +              BMLoop *l;
 +              
 +              BM_ITER(f, &fiter, em->bm, BM_FACES_OF_VERT, tempsv->v) {
 +                      
 +                      if (!BLI_smallhash_haskey(&sld->origfaces, (uintptr_t)f)) {
 +                              BMFace *copyf = BM_Copy_Face(em->bm, f, 1, 1);
 +                              
 +                              BM_Select(em->bm, copyf, 0);
 +                              BM_SetHFlag(copyf, BM_HIDDEN);
 +                              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, copyf) {
 +                                      BM_Select(em->bm, l->v, 0);
 +                                      BM_SetHFlag(l->v, BM_HIDDEN);
 +                                      BM_Select(em->bm, l->e, 0);
 +                                      BM_SetHFlag(l->e, BM_HIDDEN);
 +                              }
  
 -      sld->start[0] = (int) start[0];
 -      sld->start[1] = (int) start[1];
 -      sld->end[0] = (int) end[0];
 -      sld->end[1] = (int) end[1];
 +                              BLI_smallhash_insert(&sld->origfaces, (uintptr_t)f, copyf);
 +                      }
 +              }
 +
 +              BLI_smallhash_insert(&sld->vhash, (uintptr_t)tempsv->v, tempsv);
 +      }
 +      
 +      sld->em = em;
        
 -      if (uvlay_tot) {
 -              int maxnum = 0;
 +      /*zero out start*/
 +      zero_v3(start);
 +      
 +      /*dir holds a vector along edge loop*/
 +      copy_v3_v3(end, dir);
 +      mul_v3_fl(end, 0.5);
 +      
 +      sld->start[0] = t->mval[0] + start[0];
 +      sld->start[1] = t->mval[1] + start[1];
  
 -              uvarray = MEM_callocN( uvlay_tot * sizeof(GHash *), "SlideUVs Array");
 -              sld->totuv = uvlay_tot;
 -              suv_last = slideuvs = MEM_callocN( uvlay_tot * (numadded+1) * sizeof(TransDataSlideUv), "SlideUVs"); /* uvLayers * verts */
 -              suv = NULL;
 +      sld->end[0] = t->mval[0] + end[0];
 +      sld->end[1] = t->mval[1] + end[1];
 +      
 +      sld->perc = 0.0f;
 +      
 +      t->customData = sld;
 +      
 +      BLI_smallhash_release(&table);
 +      BMBVH_FreeBVH(btree);
 +      
 +      return 1;
 +}
  
 -              for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
 +void projectSVData(TransInfo *t, int final)
 +{
 +      SlideData *sld = t->customData;
 +      TransDataSlideVert *tempsv;
 +      BMEditMesh *em = sld->em;
 +      SmallHash visit;
 +      int i;
 +      
 +      if (!em)
 +              return;
 +      
 +      /* BMESH_TODO, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)
 +       * currently all vertex data is interpolated which is nice mostly
 +       * except for shape keys where you dont want to modify UVs for eg.
 +       * current BMesh code doesnt make it easy to pick which data we interpolate
 +       * - campbell */
  
 -                      uvarray[uvlay_idx] = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "createSlideVerts2 gh");
 +      BLI_smallhash_init(&visit);
 +      
 +              for (i=0, tempsv=sld->sv; i<sld->totsv; i++, tempsv++) {
 +              BMIter fiter;
 +              BMFace *f;
 +              
 +              BM_ITER(f, &fiter, em->bm, BM_FACES_OF_VERT, tempsv->v) {
 +                      BMIter liter2;
 +                      BMFace *copyf, *copyf2;
 +                      BMLoop *l2;
 +                      int sel, hide, do_vdata;
 +                      
 +                      if (BLI_smallhash_haskey(&visit, (uintptr_t)f))
 +                              continue;
 +                      
 +                      BLI_smallhash_insert(&visit, (uintptr_t)f, NULL);
 +                      
 +                      /*the face attributes of the copied face will get
 +                        copied over, so its necessary to save the selection
 +                        and hidden state*/
 +                      sel = BM_TestHFlag(f, BM_SELECT);
 +                      hide = BM_TestHFlag(f, BM_HIDDEN);
 +                      
 +                      copyf2 = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)f);
 +                      
 +                      /*project onto copied projection face*/
 +                      BM_ITER(l2, &liter2, em->bm, BM_LOOPS_OF_FACE, f) {
 +                              copyf = copyf2;
 +                              do_vdata = l2->v==tempsv->v;
 +                              
 +                              if (BM_TestHFlag(l2->e, BM_SELECT) || BM_TestHFlag(l2->prev->e, BM_SELECT)) {
 +                                      BMLoop *l3 = l2;
 +                                      
 +                                      do_vdata = 1;
 +                                      
 +                                      if (!BM_TestHFlag(l2->e, BM_SELECT))
 +                                              l3 = l3->prev;
 +                                      
 +                                      if (sld->perc < 0.0 && BM_Vert_In_Face(l3->radial_next->f, tempsv->down)) {
 +                                              copyf = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)l3->radial_next->f);
 +                                      } else if (sld->perc > 0.0 && BM_Vert_In_Face(l3->radial_next->f, tempsv->up)) {
 +                                              copyf = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)l3->radial_next->f);
 +                                      }
 +                                      if (!copyf)
 +                                              continue;  /* shouldn't happen, but protection */
 +                              }
 +                              
 +                              BM_loop_interp_from_face(em->bm, l2, copyf, do_vdata, 0);
  
 -                      for(ev=em->verts.first;ev;ev=ev->next) {
 -                              ev->tmp.l = 0;
 -                      }
 -                      look = vertlist;
 -                      while(look) {
 -                              float *uv_new;
 -                              tempsv  = BLI_ghash_lookup(vertgh,(EditVert*)look->link);
 -
 -                              ev = look->link;
 -                              suv = NULL;
 -                              for(efa = em->faces.first;efa;efa=efa->next) {
 -                                      if (ev->tmp.l != -1) { /* test for self, in this case its invalid */
 -                                              int k=-1; /* face corner */
 -
 -                                              /* Is this vert in the faces corner? */
 -                                              if              (efa->v1==ev)                           k=0;
 -                                              else if (efa->v2==ev)                           k=1;
 -                                              else if (efa->v3==ev)                           k=2;
 -                                              else if (efa->v4 && efa->v4==ev)        k=3;
 -
 -                                              if (k != -1) {
 -                                                      MTFace *tf = CustomData_em_get_n(&em->fdata, efa->data, CD_MTFACE, uvlay_idx);
 -                                                      EditVert *ev_up, *ev_down;
 -
 -                                                      uv_new = tf->uv[k];
 -
 -                                                      if (ev->tmp.l) {
 -                                                              if (fabsf(suv->origuv[0]-uv_new[0]) > 0.0001f || fabs(suv->origuv[1]-uv_new[1]) > 0.0001f) {
 -                                                                      ev->tmp.l = -1; /* Tag as invalid */
 -                                                                      BLI_linklist_free(suv->fuv_list,NULL);
 -                                                                      suv->fuv_list = NULL;
 -                                                                      BLI_ghash_remove(uvarray[uvlay_idx],ev, NULL, NULL);
 -                                                                      suv = NULL;
 -                                                                      break;
 -                                                              }
 -                                                      } else {
 -                                                              ev->tmp.l = 1;
 -                                                              suv = suv_last;
 -
 -                                                              suv->fuv_list = NULL;
 -                                                              suv->uv_up = suv->uv_down = NULL;
 -                                                              suv->origuv[0] = uv_new[0];
 -                                                              suv->origuv[1] = uv_new[1];
 -
 -                                                              BLI_linklist_prepend(&suv->fuv_list, uv_new);
 -                                                              BLI_ghash_insert(uvarray[uvlay_idx],ev,suv);
 -
 -                                                              suv_last++; /* advance to next slide UV */
 -                                                              maxnum++;
 -                                                      }
 -
 -                                                      /* Now get the uvs along the up or down edge if we can */
 -                                                      if (suv) {
 -                                                              if (!suv->uv_up) {
 -                                                                      ev_up = editedge_getOtherVert(tempsv->up,ev);
 -                                                                      if              (efa->v1==ev_up)                                suv->uv_up = tf->uv[0];
 -                                                                      else if (efa->v2==ev_up)                                suv->uv_up = tf->uv[1];
 -                                                                      else if (efa->v3==ev_up)                                suv->uv_up = tf->uv[2];
 -                                                                      else if (efa->v4 && efa->v4==ev_up)             suv->uv_up = tf->uv[3];
 -                                                              }
 -                                                              if (!suv->uv_down) { /* if the first face was apart of the up edge, it cant be apart of the down edge */
 -                                                                      ev_down = editedge_getOtherVert(tempsv->down,ev);
 -                                                                      if              (efa->v1==ev_down)                              suv->uv_down = tf->uv[0];
 -                                                                      else if (efa->v2==ev_down)                              suv->uv_down = tf->uv[1];
 -                                                                      else if (efa->v3==ev_down)                              suv->uv_down = tf->uv[2];
 -                                                                      else if (efa->v4 && efa->v4==ev_down)   suv->uv_down = tf->uv[3];
 -                                                              }
 -
 -                                                              /* Copy the pointers to the face UV's */
 -                                                              BLI_linklist_prepend(&suv->fuv_list, uv_new);
 -                                                      }
 -                                              }
 +                              if (final) {
 +                                      BM_loop_interp_multires(em->bm, l2, copyf);     
 +                                      if (copyf2 != copyf) {
 +                                              BM_loop_interp_multires(em->bm, l2, copyf2);
                                        }
                                }
 -                              look = look->next;
                        }
 -              } /* end uv layer loop */
 -      } /* end uvlay_tot */
 -
 -      sld->uvhash = uvarray;
 -      sld->slideuv = slideuvs;
 -      sld->vhash = vertgh;
 -      sld->nearest = nearest;
 -      sld->vertlist = vertlist;
 -      sld->edgelist = edgelist;
 -      sld->suv_last = suv_last;
 -      sld->uvlay_tot = uvlay_tot;
 -
 -      // we should have enough info now to slide
 -
 -      t->customData = sld;
 -
 -      return 1;
 +                      
 +                      /*make sure face-attributes are correct (e.g. MTexPoly)*/
 +                      BM_Copy_Attributes(em->bm, em->bm, copyf2, f);
 +                      
 +                      /*restore selection and hidden flags*/
 +                      BM_Select(em->bm, f, sel);
 +                      BM_Hide(em->bm, f, hide);
 +              }
 +      }
 +      
 +      BLI_smallhash_release(&visit);
  }
  
  void freeSlideVerts(TransInfo *t)
  {
 -      TransDataSlideUv *suv;
        SlideData *sld = t->customData;
 -      Mesh *me = t->obedit->data;
 -      int uvlay_idx;
 -
 +      SmallHashIter hiter;
 +      BMFace *copyf;
 +      
 +#if 0 /*BMESH_TODO*/
        if(me->drawflag & ME_DRAWEXTRA_EDGELEN) {
                TransDataSlideVert *tempsv;
                LinkNode *look = sld->vertlist;
                        look = look->next;
                }
        }
 -
 -      //BLI_ghash_free(edgesgh, freeGHash, NULL);
 -      BLI_ghash_free(sld->vhash, NULL, (GHashValFreeFP)MEM_freeN);
 -      BLI_linklist_free(sld->vertlist, NULL);
 -      BLI_linklist_free(sld->edgelist, NULL);
 -
 -      if (sld->uvlay_tot) {
 -              for (uvlay_idx=0; uvlay_idx<sld->uvlay_tot; uvlay_idx++) {
 -                      BLI_ghash_free(sld->uvhash[uvlay_idx], NULL, NULL);
 -              }
 -
 -              suv = sld->suv_last-1;
 -              while (suv >= sld->slideuv) {
 -                      if (suv->fuv_list) {
 -                              BLI_linklist_free(suv->fuv_list,NULL);
 -                      }
 -                      suv--;
 -              }
 -
 -              MEM_freeN(sld->slideuv);
 -              MEM_freeN(sld->uvhash);
 +#endif
 +      
 +      if (!sld)
 +              return;
 +      
 +      /*handle multires reprojection, done
 +      on transform completion since it's
 +      really slow -joeedh*/
 +      if (t->state != TRANS_CANCEL) {
 +              projectSVData(t, 1);
 +      } else {
 +              sld->perc = 0.0;
 +              projectSVData(t, 0);
        }
 +      
 +      copyf = BLI_smallhash_iternew(&sld->origfaces, &hiter, NULL);
 +      for (; copyf; copyf=BLI_smallhash_iternext(&hiter, NULL)) {
 +              BM_Kill_Face_Verts(sld->em->bm, copyf);
 +      }
 +      
 +      sld->em->bm->ob = t->obedit;
 +      bmesh_end_edit(sld->em->bm, BMOP_UNTAN_MULTIRES);
  
 +      BLI_smallhash_release(&sld->vhash);
 +      BLI_smallhash_release(&sld->origfaces);
 +      
 +      MEM_freeN(sld->sv);
        MEM_freeN(sld);
 +      
        t->customData = NULL;
 +      
 +      recalcData(t);
  }
  
  void initEdgeSlide(TransInfo *t)
  int doEdgeSlide(TransInfo *t, float perc)
  {
        SlideData *sld = t->customData;
 -      EditVert *ev, *nearest = sld->nearest;
 -      EditVert *centerVert, *upVert, *downVert;
 -      LinkNode *vertlist=sld->vertlist, *look;
 -      GHash *vertgh = sld->vhash;
 -      TransDataSlideVert *tempsv;
 -      float len;
 -      int prop=1, flip=0;
 -      /* UV correction vars */
 -      GHash **uvarray= sld->uvhash;
 -      const int  uvlay_tot= sld->uvlay_tot;
 -      int uvlay_idx;
 -      TransDataSlideUv *suv;
 -      float uv_tmp[2];
 -      LinkNode *fuv_link;
 -
 -      tempsv = BLI_ghash_lookup(vertgh,nearest);
 -
 -      centerVert = editedge_getSharedVert(tempsv->up, tempsv->down);
 -      upVert = editedge_getOtherVert(tempsv->up, centerVert);
 -      downVert = editedge_getOtherVert(tempsv->down, centerVert);
 -
 -      len = MIN2(perc, len_v3v3(upVert->co,downVert->co));
 -      len = MAX2(len, 0);
 -
 -      //Adjust Edgeloop
 -      if(prop) {
 -              look = vertlist;
 -              while(look) {
 -                      EditVert *tempev;
 -                      ev = look->link;
 -                      tempsv = BLI_ghash_lookup(vertgh,ev);
 -
 -                      tempev = editedge_getOtherVert((perc>=0)?tempsv->up:tempsv->down, ev);
 -                      interp_v3_v3v3(ev->co, tempsv->origvert.co, tempev->co, fabs(perc));
 -
 -                      if (uvlay_tot) {
 -                              for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
 -                                      suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev );
 -                                      if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) {
 -                                              interp_v2_v2v2(uv_tmp, suv->origuv,  (perc>=0)?suv->uv_up:suv->uv_down, fabs(perc));
 -                                              fuv_link = suv->fuv_list;
 -                                              while (fuv_link) {
 -                                                      VECCOPY2D(((float *)fuv_link->link), uv_tmp);
 -                                                      fuv_link = fuv_link->next;
 -                                              }
 -                                      }
 -                              }
 -                      }
 +      TransDataSlideVert *svlist = sld->sv, *sv;
 +      float vec[3];
 +      int i;
  
 -                      look = look->next;
 -              }
 -      }
 -      else {
 -              //Non prop code
 -              look = vertlist;
 -              while(look) {
 -                      float newlen, edgelen;
 -                      ev = look->link;
 -                      tempsv = BLI_ghash_lookup(vertgh,ev);
 -                      edgelen = len_v3v3(editedge_getOtherVert(tempsv->up,ev)->co,editedge_getOtherVert(tempsv->down,ev)->co);
 -                      newlen = (edgelen != 0.0f)? (len / edgelen): 0.0f;
 -                      if(newlen > 1.0f) {newlen = 1.0;}
 -                      if(newlen < 0.0f) {newlen = 0.0;}
 -                      if(flip == 0) {
 -                              interp_v3_v3v3(ev->co, editedge_getOtherVert(tempsv->down,ev)->co, editedge_getOtherVert(tempsv->up,ev)->co, fabs(newlen));
 -                              if (uvlay_tot) {
 -                                      /* dont do anything if no UVs */
 -                                      for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
 -                                              suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev );
 -                                              if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) {
 -                                                      interp_v2_v2v2(uv_tmp, suv->uv_down, suv->uv_up, fabs(newlen));
 -                                                      fuv_link = suv->fuv_list;
 -                                                      while (fuv_link) {
 -                                                              VECCOPY2D(((float *)fuv_link->link), uv_tmp);
 -                                                              fuv_link = fuv_link->next;
 -                                                      }
 -                                              }
 -                                      }
 -                              }
 -                      } else{
 -                              interp_v3_v3v3(ev->co, editedge_getOtherVert(tempsv->up,ev)->co, editedge_getOtherVert(tempsv->down,ev)->co, fabs(newlen));
 -
 -                              if (uvlay_tot) {
 -                                      /* dont do anything if no UVs */
 -                                      for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
 -                                              suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev );
 -                                              if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) {
 -                                                      interp_v2_v2v2(uv_tmp, suv->uv_up, suv->uv_down, fabs(newlen));
 -                                                      fuv_link = suv->fuv_list;
 -                                                      while (fuv_link) {
 -                                                              VECCOPY2D(((float *)fuv_link->link), uv_tmp);
 -                                                              fuv_link = fuv_link->next;
 -                                                      }
 -                                              }
 -                                      }
 -                              }
 -                      }
 -                      look = look->next;
 -              }
 +      sld->perc = perc;
  
 +      sv = svlist;
 +      for (i=0; i<sld->totsv; i++, sv++) {
 +              if (perc > 0.0f) {
 +                      copy_v3_v3(vec, sv->upvec);
 +                      mul_v3_fl(vec, perc);
 +                      add_v3_v3v3(sv->v->co, sv->origvert.co, vec);
 +              } else {
 +                      copy_v3_v3(vec, sv->downvec);
 +                      mul_v3_fl(vec, -perc);
 +                      add_v3_v3v3(sv->v->co, sv->origvert.co, vec);
 +              }
        }
 -
 +      
 +      projectSVData(t, 0);
 +      
        return 1;
  }
  
index c38e8d02954385af5a1412730aa010bccaf349cb,bb67b46a7e514c801ace1e4fc13fa92dfa3c55ed..125c18fa7c4d2146697966e15cc29cf7fa17b9ea
@@@ -46,11 -46,6 +46,11 @@@ struct MCol
  struct MSticky;
  struct Mesh;
  struct OcInfo;
 +struct MPoly;
 +struct MTexPoly;
 +struct MLoop;
 +struct MLoopUV;
 +struct MLoopCol;
  struct Multires;
  struct PartialVisibility;
  struct EditMesh;
@@@ -65,35 -60,23 +65,35 @@@ typedef struct Mesh 
        struct Ipo *ipo;                // XXX depreceated... old animation system
        struct Key *key;
        struct Material **mat;
 +      
 +      /*new face structures*/
 +      struct MPoly *mpoly;
 +      struct MTexPoly *mtpoly;
 +      struct MLoop *mloop;
 +      struct MLoopUV *mloopuv;
 +      struct MLoopCol *mloopcol;
  
 -      struct MFace *mface;    /* array of mesh object mode faces */
 -      struct MTFace *mtface;  /* store face UV's and texture here */
 +      /*mface stores the tesselation (triangulation) of the mesh,
 +        real faces are now stored in nface.*/
 +      struct MFace *mface;    /* array of mesh object mode faces for tesselation */
 +      struct MTFace *mtface;  /* store tesselation face UV's and texture here */
        struct TFace *tface;    /* depecrated, use mtface */
        struct MVert *mvert;    /* array of verts */
        struct MEdge *medge;    /* array of edges */
        struct MDeformVert *dvert;      /* deformgroup vertices */
 -      struct MCol *mcol;              /* array of colors, this must be the number of faces * 4 */
 +      
 +      /* array of colors for the tesselated faces, must be number of tesselated
 +         faces * 4 in length */
 +      struct MCol *mcol;              
        struct MSticky *msticky;
        struct Mesh *texcomesh;
        struct MSelect *mselect;
        
 -      struct EditMesh *edit_mesh;     /* not saved in file! */
 +      struct BMEditMesh *edit_btmesh; /* not saved in file! */
  
 -      struct CustomData vdata, edata, fdata;
 +      struct CustomData vdata, edata, fdata, pdata, ldata;
  
 -      int totvert, totedge, totface, totselect;
 +      int totvert, totedge, totface, totpoly, totloop, totselect;
        
        /* the last selected vertex/edge/face are used for the active face however
         * this means the active face must always be selected, this is to keep track
@@@ -142,6 -125,14 +142,14 @@@ typedef struct TFace 
  #define ME_EDIT_MIRROR_TOPO (1 << 4)
  #define ME_EDIT_VERT_SEL (1 << 5)
  
+ /* we cant have both flags enabled at once,
+  * flags defined in DNA_scene_types.h */
+ #define ME_EDIT_PAINT_SEL_MODE(_me)  (                                        \
+       (_me->editflag & ME_EDIT_PAINT_MASK) ? SCE_SELECT_FACE :                  \
+               (_me->editflag & ME_EDIT_VERT_SEL) ? SCE_SELECT_VERTEX :              \
+                       0                                                                 \
+       )
  /* me->flag */
  /* #define ME_ISDONE          1 */
  #define ME_DEPRECATED 2