Added Vertex Slide: Slides a vertex along a selected and connected edge (Shift+Ctrl+V)
authorFrancisco De La Cruz <dlcs.frank@gmail.com>
Sat, 7 Apr 2012 03:15:20 +0000 (03:15 +0000)
committerFrancisco De La Cruz <dlcs.frank@gmail.com>
Sat, 7 Apr 2012 03:15:20 +0000 (03:15 +0000)
-
BMop: "vertslide vert=%e edge=%hfev distance_t=%f"

release/scripts/startup/bl_ui/space_view3d.py
source/blender/bmesh/CMakeLists.txt
source/blender/bmesh/intern/bmesh_opdefines.c
source/blender/bmesh/intern/bmesh_operators_private.h
source/blender/bmesh/operators/bmo_slide.c [new file with mode: 0644]
source/blender/editors/mesh/CMakeLists.txt
source/blender/editors/mesh/editmesh_slide.c [new file with mode: 0644]
source/blender/editors/mesh/mesh_intern.h
source/blender/editors/mesh/mesh_ops.c

index c71ac6b4c101baa773b42a64d62dac14c4f9dfba..c65572aff167896fbc3fe24bf90e79af0a84cc06 100644 (file)
@@ -1684,6 +1684,7 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
         layout.operator("mesh.split")
         layout.operator("mesh.separate")
         layout.operator("mesh.vert_connect")
+        layout.operator("mesh.vert_slide")
 
         layout.separator()
 
index 3dc10c5f97fc2997f93227b84835166a0484207a..016d2802094cd3b533e4cf9f9c6060f5d67c6317 100644 (file)
@@ -36,6 +36,7 @@ set(INC
 set(SRC
        operators/bmo_bevel.c
        operators/bmo_connect.c
+       operators/bmo_slide.c
        operators/bmo_create.c
        operators/bmo_dissolve.c
        operators/bmo_dupe.c
index 34a1a3e7511ace6cc41b7451c2360b456eb0d666..8853771ed5884983bbe7e181390907e6f92cce45 100644 (file)
@@ -1103,6 +1103,23 @@ static BMOpDefine bmo_inset_def = {
        0
 };
 
+/*
+ * Vertex Slide
+ *
+ * Translates vertes along an edge
+ */
+static BMOpDefine bmo_vert_slide_def = {
+"vertslide",
+       {{BMO_OP_SLOT_ELEMENT_BUF, "vert"},
+        {BMO_OP_SLOT_ELEMENT_BUF, "edge"},
+        {BMO_OP_SLOT_ELEMENT_BUF, "vertout"},
+        {BMO_OP_SLOT_FLT, "distance_t"},
+        {0} /* null-terminating sentinel */},
+       bmo_vert_slide_exec,
+       BMO_OP_FLAG_UNTAN_MULTIRES
+};
+
+
 BMOpDefine *opdefines[] = {
        &bmo_split_def,
        &bmo_spin_def,
@@ -1170,6 +1187,7 @@ BMOpDefine *opdefines[] = {
        &bmo_bridge_loops_def,
        &bmo_solidify_def,
        &bmo_inset_def,
+       &bmo_vert_slide_def,
 };
 
 int bmesh_total_ops = (sizeof(opdefines) / sizeof(void *));
index 0e2281489183984b40da51a5145c57dc88439183..c4b4f01b5b52e58f1e5022969c27bf6c86c01c68 100644 (file)
@@ -43,6 +43,7 @@ void bmo_dissolve_faces_exec(BMesh *bmesh, BMOperator *op);
 void bmo_dissolve_verts_exec(BMesh *bmesh, BMOperator *op);
 void bmo_dissolve_limit_exec(BMesh *bmesh, BMOperator *op);
 void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op);
+void bmo_vert_slide_exec(BMesh *bm, BMOperator *op);
 void bmo_connectverts_exec(BMesh *bm, BMOperator *op);
 void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op);
 void bmo_mesh_to_bmesh_exec(BMesh *bm, BMOperator *op);
diff --git a/source/blender/bmesh/operators/bmo_slide.c b/source/blender/bmesh/operators/bmo_slide.c
new file mode 100644 (file)
index 0000000..5a530e4
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Francisco De La Cruz
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/operators/bmo_slide.c
+*  \ingroup bmesh
+*/
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_global.h"
+
+#include "BLI_math.h"
+#include "BLI_array.h"
+#include "BLI_utildefines.h"
+
+#include "bmesh.h"
+
+#include "intern/bmesh_operators_private.h" /* own include */
+
+#define EDGE_MARK 1
+#define VERT_MARK 2
+
+/*
+ * Slides a vertex along a connected edge
+ *
+ */
+void bmo_vert_slide_exec(BMesh *bm, BMOperator *op)
+{
+       BMOIter oiter;
+       BMIter iter;
+       BMHeader *h;
+       BMVert *vertex;
+       BMEdge *edge;
+       int is_start_v1 = 0;
+
+       /* Selection counts */
+       int selected_verts = 0;
+       int selected_edges = 0;
+
+       /* Get slide amount */
+       const float distance_t = BMO_slot_float_get(op, "distance_t");
+
+       /* Get start vertex */
+       vertex = BMO_iter_new(&oiter, bm, op, "vert", BM_VERT);
+
+
+       if (!vertex) {
+               if (G.debug & G_DEBUG)
+                       fprintf(stderr, "vertslide: No vertex selected...");
+               return;
+       }
+
+       /* Count selected edges */
+       BMO_ITER(h, &oiter, bm, op, "edge", BM_VERT | BM_EDGE) {
+               switch (h->htype) {
+                       case BM_VERT:
+                               selected_verts++;
+                               break;
+                       case BM_EDGE:
+                               selected_edges++;
+                               /* Mark all selected edges (cast BMHeader->BMEdge) */
+                               BMO_elem_flag_enable(bm, (BMElemF *)h, EDGE_MARK);
+                               break;
+               }
+       }
+
+       /* Only allow sliding between two verts */
+
+       if (selected_verts != 2 || selected_edges == 0) {
+               if (G.debug & G_DEBUG)
+                       fprintf(stderr, "vertslide: select a single edge\n");
+               return;
+       }
+
+       /* Make sure we get the correct edge. */
+       BM_ITER(edge, &iter, bm, BM_EDGES_OF_VERT, vertex) {
+               if (BMO_elem_flag_test(bm, edge, EDGE_MARK)) {
+                       is_start_v1 = (edge->v1 == vertex);
+                       break;
+               }
+       }
+
+       /* Found edge */
+       if (edge) {
+               BMVert *other = BM_edge_other_vert(edge, vertex);
+
+               /* mark */
+               BMO_elem_flag_enable(bm, vertex, VERT_MARK);
+
+               /* Interpolate */
+               interp_v3_v3v3(vertex->co, vertex->co, other->co, distance_t);
+       }
+
+       /* Deselect the edges */
+       BMO_slot_buffer_hflag_disable(bm, op, "edge", BM_ALL, BM_ELEM_SELECT, TRUE);
+
+       /* Return the new edge. The same previously marked with VERT_MARK */
+       BMO_slot_buffer_from_enabled_flag(bm, op, "vertout", BM_VERT, VERT_MARK);
+       return;
+}
+
+#undef EDGE_MARK
+#undef VERT_MARK
index de9443d1eb42072f98dda85c5252961bfb4edda5..3026eeb8f50cdd6a0dbd7eac48c07236663b7105 100644 (file)
@@ -46,6 +46,7 @@ set(SRC
        editmesh_select.c
        editmesh_tools.c
        editmesh_utils.c
+       editmesh_slide.c
        mesh_data.c
        mesh_ops.c
        meshtools.c
diff --git a/source/blender/editors/mesh/editmesh_slide.c b/source/blender/editors/mesh/editmesh_slide.c
new file mode 100644 (file)
index 0000000..764ec0d
--- /dev/null
@@ -0,0 +1,695 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Francisco De La Cruz
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/* Takes heavily from editmesh_loopcut.c */
+
+#include <float.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_array.h"
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_blender.h"
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_mesh.h"
+#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_mesh.h"
+#include "ED_space_api.h"
+
+#include "UI_resources.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "mesh_intern.h"
+
+#define VTX_SLIDE_SLIDE_SENS_F 15.0f
+#define VTX_SLIDE_SNAP_THRSH    0.3f
+
+/* Cusom VertexSlide Operator data */
+typedef struct VertexSlideOp {
+       /* Starting Vertex */
+       BMVert *start_vtx;
+       BMEdge *sel_edge;
+
+       ViewContext *view_context;
+       ARegion *active_region;
+
+       /* Draw callback handle */
+       void *draw_handle;
+
+       /* Active Object */
+       Object *obj;
+
+       /* Are we in slide mode */
+       int slide_mode;
+       int snap_n_weld;
+       int snap_to_end_vtx;
+       int snap_to_mid;
+
+       float distance;
+       float interp[3];
+
+       /* Edge Frame Count */
+       int disk_edges;
+
+       /* Edges */
+       BMEdge** edge_frame;
+
+       /* Slide Frame Endpoints */
+       float (*vtx_frame)[3];
+
+       /* Mouse Click 2d pos */
+       int m_co[2];
+
+} VertexSlideOp;
+
+static void vtx_slide_draw(const bContext *C, ARegion *ar, void *arg);
+static int edbm_vert_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_init(bContext *C, wmOperator *op)
+{
+       Object *obedit = CTX_data_edit_object(C);
+       BMEditMesh *em = BMEdit_FromObject(obedit);
+       BMEditSelection *ese = em->bm->selected.first;
+
+       /* 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";
+
+       if (!obedit) {
+               BKE_report(op->reports, RPT_ERROR, "Vertex Slide Error: Not object in context");
+               return FALSE;
+       }
+
+       EDBM_selectmode_flush(em);
+       ese = em->bm->selected.first;
+
+       /* Is there a starting vertex  ? */
+       if (ese == NULL || ese->htype != BM_VERT) {
+               BKE_report(op->reports, RPT_ERROR_INVALID_INPUT, "Vertex Slide Error: Select a (single) vertex");
+               return FALSE;
+       }
+
+       vso = MEM_callocN(sizeof(VertexSlideOp), "Vertex Slide Operator");
+       vso->view_context = MEM_callocN(sizeof(ViewContext), "Vertex Slide View Context");
+
+       op->customdata = vso;
+
+       /* Set the start vertex */
+       vso->start_vtx = (BMVert *)ese->ele;
+
+       vso->sel_edge = NULL;
+
+       /* Edges */
+       vso->edge_frame = NULL;
+
+       vso->vtx_frame = NULL;
+
+       vso->disk_edges = 0;
+
+       vso->slide_mode = FALSE;
+
+       vso->snap_n_weld = FALSE;
+
+       vso->snap_to_end_vtx = FALSE;
+
+       vso->snap_to_mid = FALSE;
+
+       vso->distance = 0.0f;
+
+       /* Add handler for the vertex sliding */
+       WM_event_add_modal_handler(C, op);
+
+       /* Notify the viewport */
+       view3d_operator_needs_opengl(C);
+
+       /* Set the drawing region */
+       vso->active_region = CTX_wm_region(C);
+
+       /* Set the draw callback */
+       vso->draw_handle = ED_region_draw_cb_activate(vso->active_region->type, vtx_slide_draw, vso, REGION_DRAW_POST_VIEW);
+
+       ED_area_headerprint(CTX_wm_area(C), header_str);
+       
+       em_setup_viewcontext(C, vso->view_context);
+
+       /* Set the object */
+       vso->obj = obedit;
+
+       /* Init frame */
+       vtx_slide_set_frame(vso);
+
+       /* Tag for redraw */
+       ED_region_tag_redraw(vso->active_region);
+
+       return TRUE;
+}
+
+static void vtx_slide_confirm(bContext *C, wmOperator *op)
+{
+       VertexSlideOp *vso = op->customdata;
+       BMEditMesh *em = BMEdit_FromObject(vso->obj);
+       BMesh* bm = em->bm;
+
+       /* Select new edge */
+       BM_edge_select_set(bm, vso->sel_edge, TRUE);
+
+       /* Invoke operator */
+       edbm_vert_slide_exec(C, op);
+
+       if(vso->snap_n_weld) {
+               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);
+       } else {
+               /* Store edit selection of the active vertex, allows other
+                *  ops to run without reselecting */
+               EDBM_editselection_store(em, &vso->start_vtx->head);
+       }
+
+       EDBM_selectmode_flush(em);
+       
+       /* NC_GEOM | ND_DATA & Retess */
+       EDBM_update_generic(C, em, TRUE);
+       
+       ED_region_tag_redraw(vso->active_region);
+}
+
+static void vtx_slide_exit(const bContext *C, wmOperator *op) {
+       /* Fetch custom data */
+       VertexSlideOp *vso = op->customdata;
+       BMEditMesh *em = BMEdit_FromObject(vso->obj);
+
+       /* Clean-up the custom data */
+       ED_region_draw_cb_exit(vso->active_region->type, vso->draw_handle);
+
+       /* Free Custom Data
+        *
+        */
+       MEM_freeN(vso->view_context);
+
+       vso->view_context = NULL;
+
+       if (vso->edge_frame) {
+               MEM_freeN(vso->edge_frame);
+       }
+
+       if(vso->vtx_frame) {
+               MEM_freeN(vso->vtx_frame);
+       }
+
+       vso->edge_frame = NULL;
+
+       vso->vtx_frame = NULL;
+
+       vso->slide_mode = FALSE;
+
+       MEM_freeN(vso);
+       vso = NULL;
+
+       /* Clear the header */
+       ED_area_headerprint(CTX_wm_area(C), NULL);
+
+}
+
+static void vtx_slide_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
+{
+       VertexSlideOp *vso = arg;
+
+       /* Have an edge to draw */
+       if (vso && vso->sel_edge) {
+               /* Get 3d view */
+               View3D *view3d = CTX_wm_view3d(C);
+               int outline_w = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 1;
+               int i = 0;
+               if (view3d && view3d->zbuf)
+                       glDisable(GL_DEPTH_TEST);
+
+               glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT | GL_POINT_BIT);
+
+               glPushMatrix();
+               glMultMatrixf(vso->obj->obmat);
+
+               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 */
+                       UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 50, -50);
+
+                       for (i = 0; i < vso->disk_edges; i++) {
+                               glBegin(GL_LINES);
+                               glVertex3fv(vso->vtx_frame[i]);
+                               glVertex3fv(vso->interp);
+                               glEnd();
+                       }
+               }
+
+               if (vso->slide_mode) {
+                       /* Draw interpolated vertex */
+                       int pt_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 2;
+                       UI_ThemeColorShadeAlpha(TH_FACE_DOT, -90, -50);
+
+                       glPointSize(pt_size);
+
+                       bglBegin(GL_POINTS);
+                       bglVertex3fv(vso->interp);
+                       bglEnd();
+               }
+
+               glDisable(GL_BLEND);
+               glPopMatrix();
+               glPopAttrib();
+
+               if (view3d && view3d->zbuf)
+                       glEnable(GL_DEPTH_TEST);
+       }
+}
+
+static BMEdge* vtx_slide_nrst_in_frame(VertexSlideOp *vso, const float mval[2])
+{
+       BMEdge* cl_edge = NULL;
+       if (vso->disk_edges > 0) {
+               int i = 0;
+               BMEdge* edge = NULL;
+               
+               float v1_proj[3], v2_proj[3];
+               float dist = 0;
+               float min_dist = FLT_MAX;
+               for (i = 0; i < vso->disk_edges; i++) {
+                       edge = vso->edge_frame[i];
+                       project_float_noclip(vso->active_region, edge->v1->co, v1_proj);
+                       project_float_noclip(vso->active_region, edge->v2->co, v2_proj);
+                       dist = dist_to_line_segment_v2(mval, v1_proj, v2_proj);
+                       if (dist < min_dist) {
+                               min_dist = dist;
+                               cl_edge = edge;
+                       }
+               }
+       }
+       return cl_edge;
+}
+
+static void vtx_slide_find_edge(VertexSlideOp *vso, wmEvent *event)
+{
+       /* Nearest edge */
+       BMEdge *nst_edge = NULL;
+
+       /* Temp Vtx */
+       BMVert *start_vtx = vso->start_vtx;
+
+       float mval_float[] = { (float)event->mval[0], (float)event->mval[1]};
+
+       /* Set mouse coords */
+       vso->view_context->mval[0] = event->mval[0];
+       vso->view_context->mval[1] = event->mval[1];
+
+       /* Find nearest edge */
+       nst_edge = vtx_slide_nrst_in_frame(vso, mval_float);
+
+       if (nst_edge) {
+               /* Find a connected edge */
+               if (nst_edge->v1 == start_vtx || nst_edge->v2 == start_vtx) {
+                       /* Save mouse coords */
+                       vso->m_co[0] = event->mval[0];
+                       vso->m_co[1] = event->mval[1];
+
+                       /* Set edge */
+                       vso->sel_edge = nst_edge;
+               }
+       }
+}
+
+/* Updates the status of the operator - Invoked on mouse movement */
+static void vtx_slide_update(VertexSlideOp *vso, wmEvent *event)
+{
+       BMEdge *edge;
+       float edge_other_proj[3];
+       float start_vtx_proj[3];
+       BMVert *other;
+       /* Find nearest edge */
+       edge = vso->sel_edge;
+
+       if (edge) {
+               float interp[3];
+
+               /* Calculate interpolation value for preview */
+               float t_val;
+
+               float mval_float[] = { (float)event->mval[0], (float)event->mval[1]};
+               float closest_2d[2];
+
+               other = BM_edge_other_vert(edge, vso->start_vtx);
+
+               /* Project points onto screen and do interpolation in 2D */
+               project_float_noclip(vso->active_region, vso->start_vtx->co, start_vtx_proj);
+
+               project_float_noclip(vso->active_region, other->co, edge_other_proj);
+
+               closest_to_line_v2(closest_2d, mval_float, start_vtx_proj, edge_other_proj);
+
+               t_val = line_point_factor_v2(closest_2d, start_vtx_proj, edge_other_proj);
+
+               /* Snap to mid */
+               if (vso->snap_to_mid) {
+                       t_val = 0.5f;
+               }
+
+               /* Interpolate preview vertex 3D */
+               interp_v3_v3v3(interp, vso->start_vtx->co, other->co, t_val);
+               copy_v3_v3(vso->interp, interp);
+
+               vso->distance = t_val;
+
+               /* If snapping */
+               if (vso->snap_to_end_vtx) {
+                       int start_at_v1 = edge->v1 == vso->start_vtx;
+                       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) {
+                               copy_v3_v3(vso->interp, edge->v2->co);
+
+                               if (start_at_v1)
+                                       vso->distance = 1.0f;
+                               else
+                                       vso->distance = 0.0f;
+                       }
+                       if (v2_d > v1_d && v1_d < VTX_SLIDE_SNAP_THRSH) {
+                               copy_v3_v3(vso->interp, edge->v1->co);
+                               if (start_at_v1)
+                                       vso->distance = 0.0f;
+                               else
+                                       vso->distance = 1.0f;
+                       }
+               }
+       }
+}
+
+/* Sets the outline frame */
+static void vtx_slide_set_frame(VertexSlideOp *vso)
+{
+       BMEdge *edge;
+       float (*vtx_frame)[3] = NULL;
+       BMEdge** edge_frame = NULL;
+       BLI_array_declare(vtx_frame);
+       BLI_array_declare(edge_frame);
+       BMIter iter;
+       BMEditMesh *em = BMEdit_FromObject(vso->obj);
+       BMesh *bm = em->bm;
+       BMVert *sel_vtx = vso->start_vtx;
+       int idx = 0;
+
+       vso->disk_edges = 0;
+
+       if (vso->edge_frame) {
+               MEM_freeN(vso->edge_frame);
+               vso->edge_frame = NULL;
+       }
+
+       if (vso->vtx_frame) {
+               MEM_freeN(vso->vtx_frame);
+               vso->vtx_frame = NULL;
+       }
+
+       /* 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);
+
+               if (sel_vtx == edge->v1)
+                       copy_v3_v3(vtx_frame[idx], edge->v2->co);
+               else
+                       copy_v3_v3(vtx_frame[idx], edge->v1->co);
+
+               BLI_array_append(edge_frame, edge);
+               vso->disk_edges++;
+       }
+
+       vso->edge_frame = edge_frame;
+       vso->vtx_frame = vtx_frame;
+
+       /* Set the interp at starting vtx */
+       copy_v3_v3(vso->interp, sel_vtx->co);
+}
+
+static int edbm_vert_slide_modal(bContext *C, wmOperator *op, wmEvent *event)
+{
+       VertexSlideOp *vso = op->customdata;
+
+       /* Notify the viewport */
+       view3d_operator_needs_opengl(C);
+
+       switch (event->type) {
+               case LEFTSHIFTKEY:
+               {
+                       switch (event->val) {
+                               case KM_PRESS:
+                                       vso->snap_to_mid = TRUE;
+                                       break;
+                               case KM_RELEASE:
+                                       vso->snap_to_mid = FALSE;
+                                       break;
+                       }
+
+                       break;
+               }
+               case LEFTCTRLKEY:
+               {
+                       switch (event->val) {
+                               case KM_PRESS:
+                                       vso->snap_n_weld = TRUE;
+                                       vso->snap_to_end_vtx = TRUE;
+                                       break;
+                               case KM_RELEASE:
+                                       vso->snap_n_weld = FALSE;
+                                       vso->snap_to_end_vtx = FALSE;
+                                       break;
+                       }
+
+                       break;
+               }
+               case LEFTALTKEY:
+               {
+                       switch (event->val) {
+                               case KM_PRESS:
+                                       vso->snap_to_end_vtx = TRUE;
+                                       break;
+                               case KM_RELEASE:
+                                       vso->snap_to_end_vtx = FALSE;
+                                       break;
+                       }
+
+                       break;
+               }
+               case RIGHTMOUSE:
+               {
+                       /* Enforce redraw */
+                       ED_region_tag_redraw(vso->active_region);
+
+                       /* Clean-up */
+                       vtx_slide_exit(C, op);
+
+                       return OPERATOR_CANCELLED;
+               }
+               case LEFTMOUSE:
+               {
+                       if (event->val == KM_PRESS) {
+                               /* Update mouse coords */
+                               copy_v2_v2_int(vso->m_co, event->mval);
+
+                               if (vso->slide_mode) {
+                                       vtx_slide_confirm(C, op);
+                                       /* Clean-up */
+                                       vtx_slide_exit(C, op);
+                                       return OPERATOR_FINISHED;
+                               }
+                               else if (vso->sel_edge) {
+                                       vso->slide_mode = TRUE;
+                               }
+                       }
+
+                       ED_region_tag_redraw(vso->active_region);
+                       break;
+
+               }
+               case MOUSEMOVE:
+               {
+                       if (!vso->slide_mode) {
+                               vtx_slide_find_edge(vso, event);
+                       }
+                       else {
+                               vtx_slide_update(vso, event);
+                       }
+
+                       ED_region_tag_redraw(vso->active_region);
+                       break;
+               }
+       }
+
+       return OPERATOR_RUNNING_MODAL;
+}
+
+static int edbm_vert_slide_cancel(bContext *C, wmOperator *op)
+{
+       /* Exit the modal */
+       vtx_slide_exit(C, op);
+
+       return OPERATOR_CANCELLED;
+}
+
+static int edbm_vert_slide_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+{
+       /* Initialize the operator */
+       if (vtx_slide_init(C, op))
+               return OPERATOR_RUNNING_MODAL;
+       else
+               return OPERATOR_CANCELLED;
+}
+
+/* Vertex Slide */
+static int edbm_vert_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;
+
+       float distance_t = 0.0f;
+
+       /* Invoked modally? */
+       if (op->type->modal == edbm_vert_slide_modal && op->customdata) {
+               VertexSlideOp *vso = op->customdata;
+               if (bm->totedgesel > 1) {
+                       EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+                       BM_edge_select_set(bm, vso->sel_edge, TRUE);
+                       EDBM_editselection_store(em, &vso->sel_edge->head);
+                       ese = em->bm->selected.first;
+               }
+               distance_t = vso->distance;
+               RNA_float_set(op->ptr, "distance_t", distance_t);
+       }
+       else {
+               /* Get Properties */
+               distance_t = RNA_float_get(op->ptr, "distance_t");
+       }
+
+       /* Is there a starting vertex  ? */
+       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 OPERATOR_CANCELLED;
+       }
+
+       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))  {
+               return OPERATOR_CANCELLED;
+       }
+       /* Execute operator */
+       BMO_op_exec(bm, &bmop);
+
+       /* Select the edge */
+       BMO_slot_buffer_hflag_enable(bm, &bmop, "vertout", BM_ALL, BM_ELEM_SELECT, TRUE);
+
+       /* Flush the select buffers */
+       EDBM_selectmode_flush(em);
+
+       if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
+               return OPERATOR_CANCELLED;
+       }
+
+       /* Update Geometry */
+       EDBM_update_generic(C, em, TRUE);
+
+       return OPERATOR_FINISHED;
+}
+
+void MESH_OT_vert_slide(wmOperatorType *ot)
+{
+       PropertyRNA *prop;
+
+       /* identifiers */
+       ot->name = "Vertex Slide";
+       ot->idname = "MESH_OT_vert_slide";
+       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->poll = ED_operator_editmesh_region_view3d;
+
+       /* ot->exec = edbm_vert_slide_exec;
+        * ot->poll = ED_operator_editmesh; */
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       /* Properties for vertex slide */
+       prop = RNA_def_float(ot->srna, "distance_t", 0.0f, -FLT_MAX, FLT_MAX, "Distance", "Distance", -5.0f, 5.0f);
+       RNA_def_property_ui_range(prop, -5.0f, 5.0f, 0.1, 4);
+       RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
index 2140bc4308b4a7007965701b4a9daaa5bdcbe0d7..706192f882bf86448ab15875f894686451a95de4 100644 (file)
@@ -214,6 +214,7 @@ void MESH_OT_bevel(struct wmOperatorType *ot);
 
 void MESH_OT_bridge_edge_loops(struct wmOperatorType *ot);
 void MESH_OT_inset(struct wmOperatorType *ot);
+void MESH_OT_vert_slide(struct wmOperatorType *ot);
 
 /* ******************* mesh_navmesh.c */
 void MESH_OT_navmesh_make(struct wmOperatorType *ot);
index f44d287e9f3caf3d12409716af681aec0ebcd340..92fad097961c560c5083b54b2fef54d3b25cb616 100644 (file)
@@ -155,6 +155,7 @@ void ED_operatortypes_mesh(void)
        WM_operatortype_append(MESH_OT_solidify);
        WM_operatortype_append(MESH_OT_select_nth);
        WM_operatortype_append(MESH_OT_vert_connect);
+       WM_operatortype_append(MESH_OT_vert_slide);
        WM_operatortype_append(MESH_OT_knifetool);
 
        WM_operatortype_append(MESH_OT_bevel);
@@ -335,6 +336,8 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
        WM_keymap_add_item(keymap, "MESH_OT_split", YKEY, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "MESH_OT_vert_connect", JKEY, KM_PRESS, 0, 0);
 
+       /* Vertex Slide */
+       WM_keymap_add_item(keymap, "MESH_OT_vert_slide", VKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
        /* use KM_CLICK because same key is used for tweaks */
        kmi = WM_keymap_add_item(keymap, "MESH_OT_dupli_extrude_cursor", ACTIONMOUSE, KM_CLICK, KM_CTRL, 0);
        RNA_boolean_set(kmi->ptr, "rotate_source", TRUE);