remove BM_ITER, BM_ITER_INDEX macros, use ELEM or MESH variants only (the maceros...
[blender-staging.git] / source / blender / editors / mesh / editmesh_slide.c
index 18c316d40fc141b1e3b6eee26e7dfd00823330d3..dd68cd30cf544628d2e91e170e823354db157613 100644 (file)
@@ -55,8 +55,7 @@
 
 #include "mesh_intern.h"
 
-#define VTX_SLIDE_SLIDE_SENS_F 15.0f
-#define VTX_SLIDE_SNAP_THRSH    0.3f
+#define VTX_SLIDE_SNAP_THRSH 15
 
 /* Cusom VertexSlide Operator data */
 typedef struct VertexSlideOp {
@@ -75,10 +74,13 @@ typedef struct VertexSlideOp {
 
        /* Are we in slide mode */
        int slide_mode;
-       int snap_n_weld;
+       int snap_n_merge;
        int snap_to_end_vtx;
        int snap_to_mid;
 
+       /* Snap threshold */
+       float snap_threshold;
+
        float distance;
        float interp[3];
 
@@ -97,21 +99,21 @@ typedef struct VertexSlideOp {
 } VertexSlideOp;
 
 static void vtx_slide_draw(const bContext *C, ARegion *ar, void *arg);
-static int edbm_vert_slide_exec(bContext *C, wmOperator *op);
+static int edbm_vertex_slide_exec(bContext *C, wmOperator *op);
 static void vtx_slide_exit(const bContext *C, wmOperator *op);
-static void vtx_slide_set_frame(VertexSlideOp *vso);
+static int vtx_slide_set_frame(VertexSlideOp *vso);
 
 static int vtx_slide_init(bContext *C, wmOperator *op)
 {
        Object *obedit = CTX_data_edit_object(C);
        BMEditMesh *em = BMEdit_FromObject(obedit);
-       BMEditSelection *ese = em->bm->selected.first;
+       BMEditSelection *ese;
 
        /* Custom data */
        VertexSlideOp *vso;
 
        const char *header_str = "Vertex Slide: Hover over an edge and left-click to select slide edge. "
-                                "Left-Shift: Midpoint Snap, Left-Alt: Snap, Left-Ctrl: Snap&Weld";
+                                "Left-Shift: Midpoint Snap, Left-Alt: Snap, Left-Ctrl: Snap&Merge";
 
        if (!obedit) {
                BKE_report(op->reports, RPT_ERROR, "Vertex Slide Error: Not object in context");
@@ -122,7 +124,7 @@ static int vtx_slide_init(bContext *C, wmOperator *op)
        ese = em->bm->selected.last;
 
        /* Is there a starting vertex  ? */
-       if (ese == NULL || ese->htype != BM_VERT) {
+       if (ese == NULL || (ese->htype != BM_VERT && ese->htype != BM_EDGE)) {
                BKE_report(op->reports, RPT_ERROR_INVALID_INPUT, "Vertex Slide Error: Select a (single) vertex");
                return FALSE;
        }
@@ -146,7 +148,7 @@ static int vtx_slide_init(bContext *C, wmOperator *op)
 
        vso->slide_mode = FALSE;
 
-       vso->snap_n_weld = FALSE;
+       vso->snap_n_merge = FALSE;
 
        vso->snap_to_end_vtx = FALSE;
 
@@ -154,8 +156,7 @@ static int vtx_slide_init(bContext *C, wmOperator *op)
 
        vso->distance = 0.0f;
 
-       /* Add handler for the vertex sliding */
-       WM_event_add_modal_handler(C, op);
+       vso->snap_threshold = 0.2f;
 
        /* Notify the viewport */
        view3d_operator_needs_opengl(C);
@@ -174,7 +175,14 @@ static int vtx_slide_init(bContext *C, wmOperator *op)
        vso->obj = obedit;
 
        /* Init frame */
-       vtx_slide_set_frame(vso);
+       if (!vtx_slide_set_frame(vso)) {
+               BKE_report(op->reports, RPT_ERROR_INVALID_INPUT, "Vertex Slide: Can't find starting vertex!");
+               vtx_slide_exit(C, op);
+               return FALSE;
+       }
+
+       /* Add handler for the vertex sliding */
+       WM_event_add_modal_handler(C, op);
 
        /* Tag for redraw */
        ED_region_tag_redraw(vso->active_region);
@@ -192,14 +200,24 @@ static void vtx_slide_confirm(bContext *C, wmOperator *op)
        BM_edge_select_set(bm, vso->sel_edge, TRUE);
 
        /* Invoke operator */
-       edbm_vert_slide_exec(C, op);
+       edbm_vertex_slide_exec(C, op);
 
-       if(vso->snap_n_weld) {
+       if (vso->snap_n_merge) {
+               float other_d;
                BMVert* other = BM_edge_other_vert(vso->sel_edge, vso->start_vtx);
-               BM_vert_select_set(bm, other, TRUE);
-       
-               EDBM_op_callf(em, op, "pointmerge verts=%hv mergeco=%v", BM_ELEM_SELECT, other->co);
-               EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+               other_d = len_v3v3(vso->interp, other->co);
+
+               /* Only snap if within threshold */
+               if (other_d < vso->snap_threshold) {
+                       BM_vert_select_set(bm, other, TRUE);
+                       BM_vert_select_set(bm, vso->start_vtx, TRUE);
+                       EDBM_op_callf(em, op, "pointmerge verts=%hv mergeco=%v", BM_ELEM_SELECT, other->co);
+                       EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+               }
+               else {
+                       /* Store in historty if not merging */
+                       EDBM_editselection_store(em, &vso->start_vtx->head);
+               }
        }
        else {
                /* Store edit selection of the active vertex, allows other
@@ -234,7 +252,7 @@ static void vtx_slide_exit(const bContext *C, wmOperator *op)
                MEM_freeN(vso->edge_frame);
        }
 
-       if(vso->vtx_frame) {
+       if (vso->vtx_frame) {
                MEM_freeN(vso->vtx_frame);
        }
 
@@ -246,6 +264,7 @@ static void vtx_slide_exit(const bContext *C, wmOperator *op)
 
        MEM_freeN(vso);
        vso = NULL;
+       op->customdata = NULL;
 
        /* Clear the header */
        ED_area_headerprint(CTX_wm_area(C), NULL);
@@ -259,7 +278,9 @@ static void vtx_slide_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
        if (vso && vso->sel_edge) {
                /* Get 3d view */
                View3D *view3d = CTX_wm_view3d(C);
-               const int outline_w = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 1;
+               const float outline_w = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.8f;
+               const float pt_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5;
+
                int i = 0;
 
                if (view3d && view3d->zbuf)
@@ -272,17 +293,7 @@ static void vtx_slide_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
 
                glEnable(GL_BLEND);
                glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-               /* Draw selected edge
-                * Add color offset and reduce alpha */
-               UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 50, -50);
-
-               glLineWidth(outline_w);
-
-               glBegin(GL_LINES);
-               bglVertex3fv(vso->sel_edge->v1->co);
-               bglVertex3fv(vso->sel_edge->v2->co);
-               glEnd();
+                       
 
                if (vso->slide_mode && vso->disk_edges > 0) {
                        /* Draw intermediate edge frame */
@@ -296,10 +307,21 @@ static void vtx_slide_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
                        }
                }
 
+                       /* Draw selected edge
+                * Add color offset and reduce alpha */
+               UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 40, -50);
+
+               glLineWidth(outline_w);
+
+               glBegin(GL_LINES);
+               bglVertex3fv(vso->sel_edge->v1->co);
+               bglVertex3fv(vso->sel_edge->v2->co);
+               glEnd();
+
                if (vso->slide_mode) {
                        /* Draw interpolated vertex */
-                       int pt_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 2;
-                       UI_ThemeColorShadeAlpha(TH_FACE_DOT, -90, -50);
+                       
+                       UI_ThemeColorShadeAlpha(TH_FACE_DOT, -80, -50);
 
                        glPointSize(pt_size);
 
@@ -352,9 +374,6 @@ static void vtx_slide_find_edge(VertexSlideOp *vso, wmEvent *event)
        /* Nearest edge */
        BMEdge *nst_edge = NULL;
 
-       /* Temp Vtx */
-       BMVert *start_vtx = vso->start_vtx;
-
        const float mval_float[] = { (float)event->mval[0], (float)event->mval[1]};
 
        /* Set mouse coords */
@@ -365,7 +384,8 @@ static void vtx_slide_find_edge(VertexSlideOp *vso, wmEvent *event)
 
        if (nst_edge) {
                /* Find a connected edge */
-               if (nst_edge->v1 == start_vtx || nst_edge->v2 == start_vtx) {
+               if (BM_vert_in_edge(nst_edge, vso->start_vtx)) {
+
                        /* Save mouse coords */
                        copy_v2_v2_int(vso->m_co, event->mval);
 
@@ -386,6 +406,7 @@ static void vtx_slide_update(VertexSlideOp *vso, wmEvent *event)
        if (edge) {
                float edge_other_proj[3];
                float start_vtx_proj[3];
+               float edge_len;
                BMVert *other;
 
                float interp[3];
@@ -409,6 +430,16 @@ static void vtx_slide_update(VertexSlideOp *vso, wmEvent *event)
 
                t_val = line_point_factor_v2(closest_2d, start_vtx_proj, edge_other_proj);
 
+               /* Set snap threshold to be proportional to edge length */
+               edge_len = len_v3v3(start_vtx_proj, edge_other_proj);
+               
+               if (edge_len <= 0.0f)
+                       edge_len = VTX_SLIDE_SNAP_THRSH;
+
+               edge_len =  (len_v3v3(edge->v1->co, edge->v2->co) * VTX_SLIDE_SNAP_THRSH) / edge_len;
+
+               vso->snap_threshold =  edge_len;
+
                /* Snap to mid */
                if (vso->snap_to_mid) {
                        t_val = 0.5f;
@@ -426,7 +457,7 @@ static void vtx_slide_update(VertexSlideOp *vso, wmEvent *event)
                        float v1_d = len_v3v3(vso->interp, edge->v1->co);
                        float v2_d = len_v3v3(vso->interp, edge->v2->co);
 
-                       if (v1_d > v2_d && v2_d < VTX_SLIDE_SNAP_THRSH) {
+                       if (v1_d > v2_d && v2_d < vso->snap_threshold) {
                                copy_v3_v3(vso->interp, edge->v2->co);
 
                                if (start_at_v1)
@@ -434,7 +465,7 @@ static void vtx_slide_update(VertexSlideOp *vso, wmEvent *event)
                                else
                                        vso->distance = 0.0f;
                        }
-                       if (v2_d > v1_d && v1_d < VTX_SLIDE_SNAP_THRSH) {
+                       if (v2_d > v1_d && v1_d < vso->snap_threshold) {
                                copy_v3_v3(vso->interp, edge->v1->co);
                                if (start_at_v1)
                                        vso->distance = 0.0f;
@@ -446,11 +477,12 @@ static void vtx_slide_update(VertexSlideOp *vso, wmEvent *event)
 }
 
 /* Sets the outline frame */
-static void vtx_slide_set_frame(VertexSlideOp *vso)
+static int vtx_slide_set_frame(VertexSlideOp *vso)
 {
        BMEdge *edge;
        float (*vtx_frame)[3] = NULL;
        BMEdge** edge_frame = NULL;
+       BMVert *curr_vert = NULL;
        BLI_array_declare(vtx_frame);
        BLI_array_declare(edge_frame);
        BMIter iter;
@@ -472,14 +504,16 @@ static void vtx_slide_set_frame(VertexSlideOp *vso)
        }
 
        /* Iterate over edges of vertex and copy them */
-       BM_ITER_INDEX(edge, &iter, bm, BM_EDGES_OF_VERT, sel_vtx, idx)
-       {
-               BLI_array_growone(vtx_frame);
+       BM_ITER_ELEM_INDEX (edge, &iter, sel_vtx, BM_EDGES_OF_VERT, idx) {
+               curr_vert = BM_edge_other_vert(edge, sel_vtx);
+               if (curr_vert) {
+                       BLI_array_growone(vtx_frame);
 
-               copy_v3_v3(vtx_frame[idx], BM_edge_other_vert(edge, sel_vtx)->co);
+                       copy_v3_v3(vtx_frame[idx], curr_vert->co);
 
-               BLI_array_append(edge_frame, edge);
-               vso->disk_edges++;
+                       BLI_array_append(edge_frame, edge);
+                       vso->disk_edges++;
+               }
        }
 
        vso->edge_frame = edge_frame;
@@ -487,11 +521,17 @@ static void vtx_slide_set_frame(VertexSlideOp *vso)
 
        /* Set the interp at starting vtx */
        copy_v3_v3(vso->interp, sel_vtx->co);
+
+       return vso->disk_edges > 0;
 }
 
-static int edbm_vert_slide_modal(bContext *C, wmOperator *op, wmEvent *event)
+static int edbm_vertex_slide_modal(bContext *C, wmOperator *op, wmEvent *event)
 {
        VertexSlideOp *vso = op->customdata;
+       char buff[128];
+
+       if (!vso)
+               return OPERATOR_CANCELLED;
 
        /* Notify the viewport */
        view3d_operator_needs_opengl(C);
@@ -514,11 +554,11 @@ static int edbm_vert_slide_modal(bContext *C, wmOperator *op, wmEvent *event)
                {
                        switch (event->val) {
                                case KM_PRESS:
-                                       vso->snap_n_weld = TRUE;
+                                       vso->snap_n_merge = TRUE;
                                        vso->snap_to_end_vtx = TRUE;
                                        break;
                                case KM_RELEASE:
-                                       vso->snap_n_weld = FALSE;
+                                       vso->snap_n_merge = FALSE;
                                        vso->snap_to_end_vtx = FALSE;
                                        break;
                        }
@@ -571,13 +611,14 @@ static int edbm_vert_slide_modal(bContext *C, wmOperator *op, wmEvent *event)
                }
                case MOUSEMOVE:
                {
+                       sprintf(buff, "Vertex Slide: %f", vso->distance);
                        if (!vso->slide_mode) {
                                vtx_slide_find_edge(vso, event);
                        }
                        else {
                                vtx_slide_update(vso, event);
                        }
-
+                       ED_area_headerprint(CTX_wm_area(C), buff);
                        ED_region_tag_redraw(vso->active_region);
                        break;
                }
@@ -586,7 +627,7 @@ static int edbm_vert_slide_modal(bContext *C, wmOperator *op, wmEvent *event)
        return OPERATOR_RUNNING_MODAL;
 }
 
-static int edbm_vert_slide_cancel(bContext *C, wmOperator *op)
+static int edbm_vertex_slide_cancel(bContext *C, wmOperator *op)
 {
        /* Exit the modal */
        vtx_slide_exit(C, op);
@@ -594,7 +635,7 @@ static int edbm_vert_slide_cancel(bContext *C, wmOperator *op)
        return OPERATOR_CANCELLED;
 }
 
-static int edbm_vert_slide_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+static int edbm_vertex_slide_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
 {
        /* Initialize the operator */
        if (vtx_slide_init(C, op))
@@ -604,26 +645,30 @@ static int edbm_vert_slide_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(e
 }
 
 /* Vertex Slide */
-static int edbm_vert_slide_exec(bContext *C, wmOperator *op)
+static int edbm_vertex_slide_exec(bContext *C, wmOperator *op)
 {
        Object *obedit = CTX_data_edit_object(C);
        BMEditMesh *em = BMEdit_FromObject(obedit);
        BMesh *bm = em->bm;
        BMVert *start_vert;
        BMOperator bmop;
-       BMEditSelection *ese = em->bm->selected.first;
+       BMEditSelection *ese = (BMEditSelection *)em->bm->selected.last;
 
        float distance_t = 0.0f;
 
        /* Invoked modally? */
-       if (op->type->modal == edbm_vert_slide_modal && op->customdata) {
-               VertexSlideOp *vso = op->customdata;
+       if (op->type->modal == edbm_vertex_slide_modal && op->customdata) {
+               VertexSlideOp *vso = (VertexSlideOp *)op->customdata;
 
                if (bm->totedgesel > 1) {
+                       /* Reset selections */
                        EDBM_flag_disable_all(em, BM_ELEM_SELECT);
                        BM_edge_select_set(bm, vso->sel_edge, TRUE);
+                       BM_vert_select_set(bm, vso->start_vtx, TRUE);
+
                        EDBM_editselection_store(em, &vso->sel_edge->head);
-                       ese = em->bm->selected.first;
+                       EDBM_editselection_store(em, &vso->start_vtx->head);                    
+                       ese = (BMEditSelection *)em->bm->selected.last;
                }
                distance_t = vso->distance;
                RNA_float_set(op->ptr, "distance_t", distance_t);
@@ -642,13 +687,16 @@ static int edbm_vert_slide_exec(bContext *C, wmOperator *op)
        start_vert = (BMVert *)ese->ele;
 
        /* Prepare operator */
-       if (!EDBM_op_init(em, &bmop, op, "vertslide vert=%e edge=%hfev distance_t=%f", start_vert, BM_ELEM_SELECT, distance_t))  {
+       if (!EDBM_op_init(em, &bmop, op, "vertex_slide vert=%e edge=%hev distance_t=%f", start_vert, BM_ELEM_SELECT, distance_t))  {
                return OPERATOR_CANCELLED;
        }
        /* Execute operator */
        BMO_op_exec(bm, &bmop);
 
-       /* Select the edge */
+       /* Deselect the input edges */
+       BMO_slot_buffer_hflag_disable(bm, &bmop, "edge", BM_ALL, BM_ELEM_SELECT, TRUE);
+
+       /* Select the output vert */
        BMO_slot_buffer_hflag_enable(bm, &bmop, "vertout", BM_ALL, BM_ELEM_SELECT, TRUE);
 
        /* Flush the select buffers */
@@ -674,12 +722,12 @@ void MESH_OT_vert_slide(wmOperatorType *ot)
        ot->description = "Vertex slide";
 
        /* api callback */
-       ot->invoke = edbm_vert_slide_invoke;
-       ot->modal = edbm_vert_slide_modal;
-       ot->cancel = edbm_vert_slide_cancel;
+       ot->invoke = edbm_vertex_slide_invoke;
+       ot->modal = edbm_vertex_slide_modal;
+       ot->cancel = edbm_vertex_slide_cancel;
        ot->poll = ED_operator_editmesh_region_view3d;
 
-       /* ot->exec = edbm_vert_slide_exec;
+       /* ot->exec = edbm_vertex_slide_exec;
         * ot->poll = ED_operator_editmesh; */
 
        /* flags */