code cleanup: rename transform Slide operations to EdgeSlide.
[blender.git] / source / blender / editors / transform / transform.c
index 4d9913d61b041b53abef915eb5946e24da3f05c2..7cc6006970c8302e2a5ce5a6d3abd90fb72703e2 100644 (file)
 #include "DNA_movieclip_types.h"
 #include "DNA_scene_types.h"  /* PET modes */
 
-#include "RNA_access.h"
-
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
-
-#include "BLF_api.h"
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_rect.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_smallhash.h"
 
 #include "BKE_nla.h"
 #include "BKE_bmesh.h"
@@ -69,6 +71,9 @@
 #include "BKE_unit.h"
 #include "BKE_mask.h"
 
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
 #include "ED_image.h"
 #include "ED_keyframing.h"
 #include "ED_screen.h"
 #include "ED_clip.h"
 #include "ED_mask.h"
 
-#include "UI_view2d.h"
 #include "WM_types.h"
 #include "WM_api.h"
 
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-#include "BLI_linklist.h"
-#include "BLI_smallhash.h"
-#include "BLI_array.h"
-
+#include "UI_view2d.h"
 #include "UI_interface_icons.h"
 #include "UI_resources.h"
 
+#include "RNA_access.h"
+
+#include "BLF_api.h"
+
 #include "transform.h"
 
 static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg);
@@ -352,6 +353,7 @@ void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
                case SPACE_VIEW3D:
                {
                        if (t->ar->regiontype == RGN_TYPE_WINDOW) {
+                               /* allow points behind the view [#33643] */
                                if (ED_view3d_project_float_global(t->ar, vec, adr, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
                                        /* XXX, 2.64 and prior did this, weak! */
                                        adr[0] = t->ar->winx / 2.0f;
@@ -461,7 +463,10 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
                        WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
                else
                        WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
-               
+
+               if (t->mode == TFM_EDGE_SLIDE && (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT))
+                       WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
+
                /* for realtime animation record - send notifiers recognised by animation editors */
                // XXX: is this notifier a lame duck?
                if ((t->animtimer) && IS_AUTOKEY_ON(t->scene))
@@ -526,6 +531,10 @@ static void viewRedrawPost(bContext *C, TransInfo *t)
                /* if autokeying is enabled, send notifiers that keyframes were added */
                if (IS_AUTOKEY_ON(t->scene))
                        WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+               /* redraw UV editor */
+               if (t->mode == TFM_EDGE_SLIDE && (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT))
+                       WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
                
                /* XXX temp, first hack to get auto-render in compositor work (ton) */
                WM_event_add_notifier(C, NC_SCENE | ND_TRANSFORM_DONE, CTX_data_scene(C));
@@ -681,6 +690,9 @@ static void view_editmove(unsigned short UNUSED(event))
 #define TFM_MODAL_EDGESLIDE_UP 24
 #define TFM_MODAL_EDGESLIDE_DOWN 25
 
+/* for analog input, like trackpad */
+#define TFM_MODAL_PROPSIZE             26
+
 /* called in transform_ops.c, on each regeneration of keymaps */
 wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
 {
@@ -710,6 +722,7 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
                {TFM_MODAL_AUTOIK_LEN_DEC, "AUTOIK_CHAIN_LEN_DOWN", 0, "Decrease Max AutoIK Chain Length", ""},
                {TFM_MODAL_EDGESLIDE_UP, "EDGESLIDE_EDGE_NEXT", 0, "Select next Edge Slide Edge", ""},
                {TFM_MODAL_EDGESLIDE_DOWN, "EDGESLIDE_PREV_NEXT", 0, "Select previous Edge Slide Edge", ""},
+               {TFM_MODAL_PROPSIZE, "PROPORTIONAL_SIZE", 0, "Adjust Proportional Influence", ""},
                {0, NULL, 0, NULL, NULL}
        };
        
@@ -745,6 +758,7 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
        WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
        WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP);
        WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
+       WM_modalkeymap_add_item(keymap, MOUSEPAN, 0, 0, 0, TFM_MODAL_PROPSIZE);
 
        WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_UP);
        WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_DOWN);
@@ -1019,6 +1033,19 @@ int transformEvent(TransInfo *t, wmEvent *event)
                                removeSnapPoint(t);
                                t->redraw |= TREDRAW_HARD;
                                break;
+                               
+                       case TFM_MODAL_PROPSIZE:
+                               /* MOUSEPAN usage... */
+                               if (t->flag & T_PROP_EDIT) {
+                                       float fac = 1.0f + 0.005f *(event->y - event->prevy);
+                                       t->prop_size *= fac;
+                                       if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
+                                               t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
+                                       calculatePropRatio(t);
+                               }
+                               t->redraw |= TREDRAW_HARD;
+                               break;
+                               
                        case TFM_MODAL_PROPSIZE_UP:
                                if (t->flag & T_PROP_EDIT) {
                                        t->prop_size *= 1.1f;
@@ -1220,6 +1247,14 @@ int transformEvent(TransInfo *t, wmEvent *event)
                                }
                                else view_editmove(event->type);
                                t->redraw = 1;
+                               break;
+                       case LEFTALTKEY:
+                       case RIGHTALTKEY:
+                               if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) {
+                                       t->flag |= T_ALT_TRANSFORM;
+                                       t->redraw |= TREDRAW_HARD;
+                               }
+
                                break;
                        default:
                                handled = 0;
@@ -1254,6 +1289,14 @@ int transformEvent(TransInfo *t, wmEvent *event)
 ////                   if (t->options & CTX_TWEAK)
 //                             t->state = TRANS_CONFIRM;
 //                     break;
+                       case LEFTALTKEY:
+                       case RIGHTALTKEY:
+                               if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) {
+                                       t->flag &= ~T_ALT_TRANSFORM;
+                                       t->redraw |= TREDRAW_HARD;
+                               }
+
+                               break;
                        default:
                                handled = 0;
                                break;
@@ -1275,7 +1318,6 @@ int transformEvent(TransInfo *t, wmEvent *event)
                t->redraw |= t->handleEvent(t, event);
 
        if (handled || t->redraw) {
-               printf("handled %d redraw %d\n", handled, t->redraw);
                return 0;
        }
        else {
@@ -1480,7 +1522,6 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
                                glTranslatef(mval[0], mval[1], 0);
 
                                glLineWidth(3.0);
-                               glBegin(GL_LINES);
                                drawArrow(UP, 5, 10, 5);
                                drawArrow(DOWN, 5, 10, 5);
                                glLineWidth(1.0);
@@ -1566,14 +1607,17 @@ static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), voi
 /* just draw a little warning message in the top-right corner of the viewport to warn that autokeying is enabled */
 static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
 {
+       rcti rect;
        const char printable[] = "Auto Keying On";
        float      printable_size[2];
        int xco, yco;
 
+       ED_region_visible_rect(ar, &rect);
+       
        BLF_width_and_height_default(printable, &printable_size[0], &printable_size[1]);
        
-       xco = ar->winx - (int)printable_size[0] - 10;
-       yco = ar->winy - (int)printable_size[1] - 10;
+       xco = rect.xmax - (int)printable_size[0] - 10;
+       yco = rect.ymax - (int)printable_size[1] - 10;
        
        /* warning text (to clarify meaning of overlays)
         * - original color was red to match the icon, but that clashes badly with a less nasty border
@@ -2235,8 +2279,8 @@ static void protectedQuaternionBits(short protectflag, float *quat, float *oldqu
 static void constraintTransLim(TransInfo *t, TransData *td)
 {
        if (td->con) {
-               bConstraintTypeInfo *ctiLoc = get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT);
-               bConstraintTypeInfo *ctiDist = get_constraint_typeinfo(CONSTRAINT_TYPE_DISTLIMIT);
+               bConstraintTypeInfo *ctiLoc = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT);
+               bConstraintTypeInfo *ctiDist = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_DISTLIMIT);
                
                bConstraintOb cob = {NULL};
                bConstraint *con;
@@ -2286,7 +2330,7 @@ static void constraintTransLim(TransInfo *t, TransData *td)
                                }
                                
                                /* get constraint targets if needed */
-                               get_constraint_targets_for_solving(con, &cob, &targets, ctime);
+                               BKE_get_constraint_targets_for_solving(con, &cob, &targets, ctime);
                                
                                /* do constraint */
                                cti->evaluate_constraint(con, &cob, &targets);
@@ -2338,7 +2382,7 @@ static void constraintob_from_transdata(bConstraintOb *cob, TransData *td)
 static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
 {
        if (td->con) {
-               bConstraintTypeInfo *cti = get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT);
+               bConstraintTypeInfo *cti = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT);
                bConstraintOb cob;
                bConstraint *con;
                int do_limit = FALSE;
@@ -2405,9 +2449,11 @@ static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
 static void constraintSizeLim(TransInfo *t, TransData *td)
 {
        if (td->con && td->ext) {
-               bConstraintTypeInfo *cti = get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT);
+               bConstraintTypeInfo *cti = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT);
                bConstraintOb cob = {NULL};
                bConstraint *con;
+               float size_sign[3], size_abs[3];
+               int i;
                
                /* Make a temporary bConstraintOb for using these limit constraints
                 *  - they only care that cob->matrix is correctly set ;-)
@@ -2421,8 +2467,14 @@ static void constraintSizeLim(TransInfo *t, TransData *td)
                        /* Reset val if SINGLESIZE but using a constraint */
                        if (td->flag & TD_SINGLESIZE)
                                return;
+
+                       /* separate out sign to apply back later */
+                       for (i = 0; i < 3; i++) {
+                               size_sign[i] = signf(td->ext->size[i]);
+                               size_abs[i] = fabsf(td->ext->size[i]);
+                       }
                        
-                       size_to_mat4(cob.matrix, td->ext->size);
+                       size_to_mat4(cob.matrix, size_abs);
                }
                
                /* Evaluate valid constraints */
@@ -2470,7 +2522,9 @@ static void constraintSizeLim(TransInfo *t, TransData *td)
                        if (td->flag & TD_SINGLESIZE)
                                return;
 
+                       /* extrace scale from matrix and apply back sign */
                        mat4_to_size(td->ext->size, cob.matrix);
+                       mul_v3_v3(td->ext->size, size_sign);
                }
        }
 }
@@ -2550,7 +2604,8 @@ int handleEventWarp(TransInfo *t, wmEvent *event)
 int Warp(TransInfo *t, const int UNUSED(mval[2]))
 {
        TransData *td = t->data;
-       float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3];
+       float vec[3], circumfac, dist, phi0, co, si, cursor[3], gcursor[3];
+       const float *curs;
        int i;
        char str[50];
        
@@ -2687,6 +2742,18 @@ int handleEventShear(TransInfo *t, wmEvent *event)
 
                status = 1;
        }
+       else if (event->type == XKEY && event->val == KM_PRESS) {
+               initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
+               t->customData = NULL;
+               
+               status = 1;
+       }
+       else if (event->type == YKEY && event->val == KM_PRESS) {
+               initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
+               t->customData = (void *)1;
+               
+               status = 1;
+       }
        
        return status;
 }
@@ -2720,7 +2787,7 @@ int Shear(TransInfo *t, const int UNUSED(mval[2]))
        }
        else {
                /* default header print */
-               sprintf(str, "Shear: %.3f %s", value, t->proptext);
+               sprintf(str, "Shear: %.3f %s (Press X or Y to set shear axis)", value, t->proptext);
        }
        
        t->values[0] = value;
@@ -2841,11 +2908,21 @@ static void headerResize(TransInfo *t, float vec[3], char *str)
        (void)spos;
 }
 
-#define SIGN(a)     (a<-FLT_EPSILON ? 1 : a>FLT_EPSILON ? 2 : 3)
-#define VECSIGNFLIP(a, b) ((SIGN(a[0]) & SIGN(b[0])) == 0 || (SIGN(a[1]) & SIGN(b[1])) == 0 || (SIGN(a[2]) & SIGN(b[2])) == 0)
+/* FLT_EPSILON is too small [#29633], 0.0000001f starts to flip */
+#define TX_FLIP_EPS 0.00001f
+BLI_INLINE int tx_sign(const float a)
+{
+       return (a < -TX_FLIP_EPS ? 1 : a > TX_FLIP_EPS ? 2 : 3);
+}
+BLI_INLINE int tx_vec_sign_flip(const float a[3], const float b[3])
+{
+       return ((tx_sign(a[0]) & tx_sign(b[0])) == 0 ||
+               (tx_sign(a[1]) & tx_sign(b[1])) == 0 ||
+               (tx_sign(a[2]) & tx_sign(b[2])) == 0);
+}
 
 /* smat is reference matrix, only scaled */
-static void TransMat3ToSize(float mat[][3], float smat[][3], float *size)
+static void TransMat3ToSize(float mat[3][3], float smat[3][3], float size[3])
 {
        float vec[3];
        
@@ -2857,9 +2934,9 @@ static void TransMat3ToSize(float mat[][3], float smat[][3], float *size)
        size[2] = normalize_v3(vec);
        
        /* first tried with dotproduct... but the sign flip is crucial */
-       if (VECSIGNFLIP(mat[0], smat[0]) ) size[0] = -size[0];
-       if (VECSIGNFLIP(mat[1], smat[1]) ) size[1] = -size[1];
-       if (VECSIGNFLIP(mat[2], smat[2]) ) size[2] = -size[2];
+       if (tx_vec_sign_flip(mat[0], smat[0]) ) size[0] = -size[0];
+       if (tx_vec_sign_flip(mat[1], smat[1]) ) size[1] = -size[1];
+       if (tx_vec_sign_flip(mat[2], smat[2]) ) size[2] = -size[2];
 }
 
 
@@ -3936,10 +4013,8 @@ void initShrinkFatten(TransInfo *t)
 }
 
 
-
 int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
 {
-       float vec[3];
        float distance;
        int i;
        char str[64];
@@ -3967,17 +4042,20 @@ int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
        t->values[0] = -distance;
 
        for (i = 0; i < t->total; i++, td++) {
+               float tdistance;  /* temp dist */
                if (td->flag & TD_NOACTION)
                        break;
 
                if (td->flag & TD_SKIP)
                        continue;
 
-               copy_v3_v3(vec, td->axismtx[2]);
-               mul_v3_fl(vec, distance);
-               mul_v3_fl(vec, td->factor);
+               /* get the final offset */
+               tdistance = distance * td->factor;
+               if (td->ext && (t->flag & T_ALT_TRANSFORM)) {
+                       tdistance *= td->ext->isize[0];  /* shell factor */
+               }
 
-               add_v3_v3v3(td->loc, td->iloc, vec);
+               madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance);
        }
 
        recalcData(t);
@@ -4794,8 +4872,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
                                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);
+                               mid_v3_v3v3(a, a, f3);
                        }
                        
                        copy_v3_v3(vec, a);
@@ -4826,9 +4903,9 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
        return NULL;
 }
 
-static void calcNonProportionalEdgeSlide(TransInfo *t, SlideData *sld, const float mval[2])
+static void calcNonProportionalEdgeSlide(TransInfo *t, EdgeSlideData *sld, const float mval[2])
 {
-       TransDataSlideVert *sv = sld->sv;
+       TransDataEdgeSlideVert *sv = sld->sv;
 
        if (sld->totsv > 0) {
                int i = 0;
@@ -4837,16 +4914,12 @@ static void calcNonProportionalEdgeSlide(TransInfo *t, SlideData *sld, const flo
                float dist = 0;
                float min_dist = FLT_MAX;
 
-               float up_p[3];
-               float dw_p[3];
-
                for (i = 0; i < sld->totsv; i++, sv++) {
                        /* Set length */
-                       add_v3_v3v3(up_p, sv->origvert.co, sv->upvec);
-                       add_v3_v3v3(dw_p, sv->origvert.co, sv->downvec);
-                       sv->edge_len = len_v3v3(dw_p, up_p);
+                       sv->edge_len = len_v3v3(sv->upvec, sv->downvec);
 
                        mul_v3_m4v3(v_proj, t->obedit->obmat, sv->v->co);
+                       /* allow points behind the view [#33643] */
                        if (ED_view3d_project_float_global(t->ar, v_proj, v_proj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
                                dist = len_squared_v2v2(mval, v_proj);
                                if (dist < min_dist) {
@@ -4861,17 +4934,17 @@ static void calcNonProportionalEdgeSlide(TransInfo *t, SlideData *sld, const flo
        }
 }
 
-static int createSlideVerts(TransInfo *t)
+static int createEdgeSlideVerts(TransInfo *t)
 {
        BMEditMesh *em = BMEdit_FromObject(t->obedit);
        BMesh *bm = em->bm;
        BMIter iter;
        BMEdge *e, *e1;
        BMVert *v, *v2, *first;
-       TransDataSlideVert *sv_array;
-       BMBVHTree *btree = BMBVH_NewBVH(em, BMBVH_RESPECT_HIDDEN, NULL, NULL);
+       TransDataEdgeSlideVert *sv_array;
+       BMBVHTree *btree;
        SmallHash table;
-       SlideData *sld = MEM_callocN(sizeof(*sld), "sld");
+       EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
        View3D *v3d = NULL;
        RegionView3D *rv3d = NULL;
        ARegion *ar = t->ar;
@@ -4881,6 +4954,7 @@ static int createSlideVerts(TransInfo *t)
        float vec[3], vec2[3] /*, lastvec[3], size, dis=0.0, z */ /* UNUSED */;
        float dir[3], maxdist, (*loop_dir)[3], *loop_maxdist;
        int numsel, i, j, loop_nr, l_nr;
+       int use_btree_disp;
 
        if (t->spacetype == SPACE_VIEW3D) {
                /* background mode support */
@@ -4888,6 +4962,15 @@ static int createSlideVerts(TransInfo *t)
                rv3d = t->ar ? t->ar->regiondata : NULL;
        }
 
+       use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
+
+       if (use_btree_disp) {
+               btree = BMBVH_NewBVH(em, BMBVH_RESPECT_HIDDEN, NULL, NULL);
+       }
+       else {
+               btree = NULL;
+       }
+
        sld->is_proportional = TRUE;
        sld->curr_sv_index = 0;
        sld->flipped_vtx = FALSE;
@@ -4921,7 +5004,8 @@ static int createSlideVerts(TransInfo *t)
 
                        if (numsel == 0 || numsel > 2) {
                                MEM_freeN(sld);
-                               BMBVH_FreeBVH(btree);
+                               if (btree)
+                                       BMBVH_FreeBVH(btree);
                                return 0; /* invalid edge selection */
                        }
                }
@@ -4931,7 +5015,8 @@ static int createSlideVerts(TransInfo *t)
                if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
                        if (!BM_edge_is_manifold(e)) {
                                MEM_freeN(sld);
-                               BMBVH_FreeBVH(btree);
+                               if (btree)
+                                       BMBVH_FreeBVH(btree);
                                return 0; /* can only handle exactly 2 faces around each edge */
                        }
                }
@@ -4951,11 +5036,12 @@ static int createSlideVerts(TransInfo *t)
 
        if (!j) {
                MEM_freeN(sld);
-               BMBVH_FreeBVH(btree);
+               if (btree)
+                       BMBVH_FreeBVH(btree);
                return 0;
        }
 
-       sv_array = MEM_callocN(sizeof(TransDataSlideVert) * j, "sv_array");
+       sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * j, "sv_array");
        loop_nr = 0;
 
        j = 0;
@@ -5017,7 +5103,7 @@ static int createSlideVerts(TransInfo *t)
                /*iterate over the loop*/
                first = v;
                do {
-                       TransDataSlideVert *sv = sv_array + j;
+                       TransDataEdgeSlideVert *sv = sv_array + j;
 
                        sv->v = v;
                        sv->origvert = *v;
@@ -5106,9 +5192,7 @@ static int createSlideVerts(TransInfo *t)
                                                continue;
 
                                        /* This test is only relevant if object is not wire-drawn! See [#32068]. */
-                                       if (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE &&
-                                           !BMBVH_EdgeVisible(btree, e2, ar, v3d, t->obedit))
-                                       {
+                                       if (use_btree_disp && !BMBVH_EdgeVisible(btree, e2, ar, v3d, t->obedit)) {
                                                continue;
                                        }
 
@@ -5182,7 +5266,7 @@ static int createSlideVerts(TransInfo *t)
                if (dot_v3v3(loop_dir[l_nr], dir) < 0.0f) {
                        swap_v3_v3(sv_array->upvec, sv_array->downvec);
                        SWAP(BMVert, sv_array->vup, sv_array->vdown);
-                       SWAP(BMVert*, sv_array->up, sv_array->down);
+                       SWAP(BMVert *, sv_array->up, sv_array->down);
                }
        }
 
@@ -5210,17 +5294,22 @@ static int createSlideVerts(TransInfo *t)
        t->customData = sld;
        
        BLI_smallhash_release(&table);
-       BMBVH_FreeBVH(btree);
+       if (btree) {
+               BMBVH_FreeBVH(btree);
+       }
        MEM_freeN(loop_dir);
        MEM_freeN(loop_maxdist);
-       
+
+       /* arrays are dirty from copying faces: EDBM_index_arrays_free */
+       EDBM_update_generic(em, FALSE, TRUE);
+
        return 1;
 }
 
-void projectSVData(TransInfo *t, int final)
+void projectEdgeSlideData(TransInfo *t, bool is_final)
 {
-       SlideData *sld = t->customData;
-       TransDataSlideVert *sv;
+       EdgeSlideData *sld = t->customData;
+       TransDataEdgeSlideVert *sv;
        BMEditMesh *em = sld->em;
        SmallHash visit;
        int i;
@@ -5339,7 +5428,7 @@ void projectSVData(TransInfo *t, int final)
                                        }
 
                                }
-                               
+
                                if (!affected)
                                        continue;
 
@@ -5347,7 +5436,7 @@ void projectSVData(TransInfo *t, int final)
                                 * and we do not want to mess up other shape keys */
                                BM_loop_interp_from_face(em->bm, l, f_copy_flip, FALSE, FALSE);
 
-                               if (final) {
+                               if (is_final) {
                                        BM_loop_interp_multires(em->bm, l, f_copy_flip);
                                        if (f_copy != f_copy_flip) {
                                                BM_loop_interp_multires(em->bm, l, f_copy);
@@ -5371,7 +5460,7 @@ void projectSVData(TransInfo *t, int final)
        BLI_smallhash_release(&visit);
 }
 
-void freeSlideTempFaces(SlideData *sld)
+void freeEdgeSlideTempFaces(EdgeSlideData *sld)
 {
        if (sld->origfaces_init) {
                SmallHashIter hiter;
@@ -5385,17 +5474,20 @@ void freeSlideTempFaces(SlideData *sld)
                BLI_smallhash_release(&sld->origfaces);
 
                sld->origfaces_init = FALSE;
+
+               /* arrays are dirty from removing faces: EDBM_index_arrays_free */
+               EDBM_update_generic(sld->em, FALSE, TRUE);
        }
 }
 
 
-void freeSlideVerts(TransInfo *t)
+void freeEdgeSlideVerts(TransInfo *t)
 {
-       SlideData *sld = t->customData;
+       EdgeSlideData *sld = t->customData;
        
 #if 0 /*BMESH_TODO*/
        if (me->drawflag & ME_DRAWEXTRA_EDGELEN) {
-               TransDataSlideVert *sv;
+               TransDataEdgeSlideVert *sv;
                LinkNode *look = sld->vertlist;
                GHash *vertgh = sld->vhash;
                while (look) {
@@ -5412,7 +5504,7 @@ void freeSlideVerts(TransInfo *t)
        if (!sld)
                return;
        
-       freeSlideTempFaces(sld);
+       freeEdgeSlideTempFaces(sld);
 
        bmesh_edit_end(sld->em->bm, BMO_OP_FLAG_UNTAN_MULTIRES);
 
@@ -5428,13 +5520,13 @@ void freeSlideVerts(TransInfo *t)
 
 void initEdgeSlide(TransInfo *t)
 {
-       SlideData *sld;
+       EdgeSlideData *sld;
 
        t->mode = TFM_EDGE_SLIDE;
        t->transform = EdgeSlide;
        t->handleEvent = handleEventEdgeSlide;
 
-       if (!createSlideVerts(t)) {
+       if (!createEdgeSlideVerts(t)) {
                t->state = TRANS_CANCEL;
                return;
        }
@@ -5444,7 +5536,7 @@ void initEdgeSlide(TransInfo *t)
        if (!sld)
                return;
 
-       t->customFree = freeSlideVerts;
+       t->customFree = freeEdgeSlideVerts;
 
        /* set custom point first if you want value to be initialized by init */
        setCustomPoints(t, &t->mouse, sld->end, sld->start);
@@ -5464,7 +5556,7 @@ void initEdgeSlide(TransInfo *t)
 int handleEventEdgeSlide(struct TransInfo *t, struct wmEvent *event)
 {
        if (t->mode == TFM_EDGE_SLIDE) {
-               SlideData *sld = t->customData;
+               EdgeSlideData *sld = t->customData;
 
                if (sld) {
                        switch (event->type) {
@@ -5510,15 +5602,15 @@ int handleEventEdgeSlide(struct TransInfo *t, struct wmEvent *event)
 void drawNonPropEdge(const struct bContext *C, TransInfo *t)
 {
        if (t->mode == TFM_EDGE_SLIDE) {
-               SlideData *sld = (SlideData *)t->customData;
+               EdgeSlideData *sld = (EdgeSlideData *)t->customData;
                /* Non-Prop mode */
                if (sld && sld->is_proportional == FALSE) {
                        View3D *v3d = CTX_wm_view3d(C);
                        float marker[3];
                        float v1[3], v2[3];
                        float interp_v;
-                       TransDataSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
-                       const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5;
+                       TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
+                       const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
                        const float guide_size = ctrl_size - 0.5f;
                        const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
                        const int alpha_shade = -30;
@@ -5583,9 +5675,8 @@ void drawNonPropEdge(const struct bContext *C, TransInfo *t)
 
 static int doEdgeSlide(TransInfo *t, float perc)
 {
-       SlideData *sld = t->customData;
-       TransDataSlideVert *svlist = sld->sv, *sv;
-       float vec[3];
+       EdgeSlideData *sld = t->customData;
+       TransDataEdgeSlideVert *svlist = sld->sv, *sv;
        int i;
 
        sld->perc = perc;
@@ -5593,6 +5684,7 @@ static int doEdgeSlide(TransInfo *t, float perc)
 
        if (sld->is_proportional == TRUE) {
                for (i = 0; i < sld->totsv; i++, sv++) {
+                       float vec[3];
                        if (perc > 0.0f) {
                                copy_v3_v3(vec, sv->upvec);
                                mul_v3_fl(vec, perc);
@@ -5610,25 +5702,34 @@ static int doEdgeSlide(TransInfo *t, float perc)
                 * Implementation note, non proportional mode ignores the starting positions and uses only the
                 * up/down verts, this could be changed/improved so the distance is still met but the verts are moved along
                 * their original path (which may not be straight), however how it works now is OK and matches 2.4x - Campbell
+                *
+                * \note len_v3v3(curr_sv->upvec, curr_sv->downvec)
+                * is the same as the distance between the original vert locations, same goes for the lines below.
                 */
-               TransDataSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
-               const float curr_length_perc = len_v3v3(curr_sv->up->co, curr_sv->down->co) *
-                                              (((sld->flipped_vtx ? perc : -perc) + 1.0f) / 2.0f);
+               TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
+               const float curr_length_perc = curr_sv->edge_len * (((sld->flipped_vtx ? perc : -perc) + 1.0f) / 2.0f);
+
+               float down_co[3];
+               float up_co[3];
 
                for (i = 0; i < sld->totsv; i++, sv++) {
-                       const float sv_length = len_v3v3(sv->up->co, sv->down->co);
-                       const float fac = min_ff(sv_length, curr_length_perc) / sv_length;
+                       if (sv->edge_len > FLT_EPSILON) {
+                               const float fac = min_ff(sv->edge_len, curr_length_perc) / sv->edge_len;
 
-                       if (sld->flipped_vtx) {
-                               interp_v3_v3v3(sv->v->co, sv->down->co, sv->up->co, fac);
-                       }
-                       else {
-                               interp_v3_v3v3(sv->v->co, sv->up->co, sv->down->co, fac);
+                               add_v3_v3v3(up_co, sv->origvert.co, sv->upvec);
+                               add_v3_v3v3(down_co, sv->origvert.co, sv->downvec);
+
+                               if (sld->flipped_vtx) {
+                                       interp_v3_v3v3(sv->v->co, down_co, up_co, fac);
+                               }
+                               else {
+                                       interp_v3_v3v3(sv->v->co, up_co, down_co, fac);
+                               }
                        }
                }
        }
        
-       projectSVData(t, 0);
+       projectEdgeSlideData(t, 0);
        
        return 1;
 }
@@ -5637,7 +5738,7 @@ int EdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
 {
        char str[128];
        float final;
-       SlideData *sld =  t->customData;
+       EdgeSlideData *sld =  t->customData;
        int flipped = sld->flipped_vtx;
        int is_proportional = sld->is_proportional;