Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py1
-rw-r--r--source/blender/bmesh/CMakeLists.txt1
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c18
-rw-r--r--source/blender/bmesh/intern/bmesh_operators_private.h1
-rw-r--r--source/blender/bmesh/operators/bmo_slide.c122
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt1
-rw-r--r--source/blender/editors/mesh/editmesh_slide.c695
-rw-r--r--source/blender/editors/mesh/mesh_intern.h1
-rw-r--r--source/blender/editors/mesh/mesh_ops.c3
9 files changed, 843 insertions, 0 deletions
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index c71ac6b4c10..c65572aff16 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -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()
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index 3dc10c5f97f..016d2802094 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -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
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 34a1a3e7511..8853771ed58 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -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 *));
diff --git a/source/blender/bmesh/intern/bmesh_operators_private.h b/source/blender/bmesh/intern/bmesh_operators_private.h
index 0e228148918..c4b4f01b5b5 100644
--- a/source/blender/bmesh/intern/bmesh_operators_private.h
+++ b/source/blender/bmesh/intern/bmesh_operators_private.h
@@ -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
index 00000000000..5a530e41d4f
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_slide.c
@@ -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
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index de9443d1eb4..3026eeb8f50 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -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
index 00000000000..764ec0d7cab
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_slide.c
@@ -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);
+}
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 2140bc4308b..706192f882b 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -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);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index f44d287e9f3..92fad097961 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -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);