Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/transform/transform_op_mode_vert_slide.c
- This file was added.
| /* | |||||
| * 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. | |||||
| */ | |||||
| /** \file | |||||
| * \ingroup edtransform | |||||
| */ | |||||
| #include "MEM_guardedalloc.h" | |||||
| #include "BLI_math.h" | |||||
| #include "BLI_string.h" | |||||
| #include "BLT_translation.h" | |||||
| #include "BKE_context.h" | |||||
| #include "BKE_editmesh.h" | |||||
| #include "BKE_unit.h" | |||||
| #include "GPU_immediate.h" | |||||
| #include "GPU_matrix.h" | |||||
| #include "GPU_state.h" | |||||
| #include "RNA_define.h" | |||||
| #include "WM_api.h" | |||||
| #include "WM_types.h" | |||||
| #include "UI_interface.h" | |||||
| #include "UI_resources.h" | |||||
| #include "ED_screen.h" | |||||
| #include "transform.h" | |||||
| #include "transform_convert.h" | |||||
| #include "transform_op.h" | |||||
| const char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide"; | |||||
| /* -------------------------------------------------------------------- */ | |||||
| /* Transform (Vert Slide) */ | |||||
| /** \name Transform Vert Slide | |||||
| * \{ */ | |||||
| static void calcVertSlideCustomPoints(struct TransInfo *t) | |||||
| { | |||||
| VertSlideParams *slp = t->custom.mode.data; | |||||
| VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; | |||||
| TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index]; | |||||
| const float *co_orig_3d = sv->co_orig_3d; | |||||
| const float *co_curr_3d = sv->co_link_orig_3d[sv->co_link_curr]; | |||||
| float co_curr_2d[2], co_orig_2d[2]; | |||||
| int mval_ofs[2], mval_start[2], mval_end[2]; | |||||
| ED_view3d_project_float_v2_m4(t->ar, co_orig_3d, co_orig_2d, sld->proj_mat); | |||||
| ED_view3d_project_float_v2_m4(t->ar, co_curr_3d, co_curr_2d, sld->proj_mat); | |||||
| ARRAY_SET_ITEMS(mval_ofs, t->mouse.imval[0] - co_orig_2d[0], t->mouse.imval[1] - co_orig_2d[1]); | |||||
| ARRAY_SET_ITEMS(mval_start, co_orig_2d[0] + mval_ofs[0], co_orig_2d[1] + mval_ofs[1]); | |||||
| ARRAY_SET_ITEMS(mval_end, co_curr_2d[0] + mval_ofs[0], co_curr_2d[1] + mval_ofs[1]); | |||||
| if (slp->flipped && slp->use_even) { | |||||
| setCustomPoints(t, &t->mouse, mval_start, mval_end); | |||||
| } | |||||
| else { | |||||
| setCustomPoints(t, &t->mouse, mval_end, mval_start); | |||||
| } | |||||
| /* setCustomPoints isn't normally changing as the mouse moves, | |||||
| * in this case apply mouse input immediately so we don't refresh | |||||
| * with the value from the previous points */ | |||||
| applyMouseInput(t, &t->mouse, t->mval, t->values); | |||||
| } | |||||
| /** | |||||
| * Run once when initializing vert slide to find the reference edge | |||||
| */ | |||||
| static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2]) | |||||
| { | |||||
| /* Active object may have no selected vertices. */ | |||||
| VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; | |||||
| float mval_fl[2] = {UNPACK2(mval)}; | |||||
| TransDataVertSlideVert *sv; | |||||
| /* set the vertex to use as a reference for the mouse direction 'curr_sv_index' */ | |||||
| float dist_sq = 0.0f; | |||||
| float dist_min_sq = FLT_MAX; | |||||
| int i; | |||||
| for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) { | |||||
| float co_2d[2]; | |||||
| ED_view3d_project_float_v2_m4(t->ar, sv->co_orig_3d, co_2d, sld->proj_mat); | |||||
| dist_sq = len_squared_v2v2(mval_fl, co_2d); | |||||
| if (dist_sq < dist_min_sq) { | |||||
| dist_min_sq = dist_sq; | |||||
| sld->curr_sv_index = i; | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Run while moving the mouse to slide along the edge matching the mouse direction | |||||
| */ | |||||
| static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2]) | |||||
| { | |||||
| VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; | |||||
| float imval_fl[2] = {UNPACK2(t->mouse.imval)}; | |||||
| float mval_fl[2] = {UNPACK2(mval)}; | |||||
| float dir[3]; | |||||
| TransDataVertSlideVert *sv; | |||||
| int i; | |||||
| /* note: we could save a matrix-multiply for each vertex | |||||
| * by finding the closest edge in local-space. | |||||
| * However this skews the outcome with non-uniform-scale. */ | |||||
| /* first get the direction of the original mouse position */ | |||||
| sub_v2_v2v2(dir, imval_fl, mval_fl); | |||||
| ED_view3d_win_to_delta(t->ar, dir, dir, t->zfac); | |||||
| normalize_v3(dir); | |||||
| for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) { | |||||
| if (sv->co_link_tot > 1) { | |||||
| float dir_dot_best = -FLT_MAX; | |||||
| int co_link_curr_best = -1; | |||||
| int j; | |||||
| for (j = 0; j < sv->co_link_tot; j++) { | |||||
| float tdir[3]; | |||||
| float dir_dot; | |||||
| sub_v3_v3v3(tdir, sv->co_orig_3d, sv->co_link_orig_3d[j]); | |||||
| mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, tdir); | |||||
| project_plane_v3_v3v3(tdir, tdir, t->viewinv[2]); | |||||
| normalize_v3(tdir); | |||||
| dir_dot = dot_v3v3(dir, tdir); | |||||
| if (dir_dot > dir_dot_best) { | |||||
| dir_dot_best = dir_dot; | |||||
| co_link_curr_best = j; | |||||
| } | |||||
| } | |||||
| if (co_link_curr_best != -1) { | |||||
| sv->co_link_curr = co_link_curr_best; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| static bool createVertSlideVerts(TransInfo *t, TransDataContainer *tc) | |||||
| { | |||||
| BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); | |||||
| BMesh *bm = em->bm; | |||||
| BMIter iter; | |||||
| BMIter eiter; | |||||
| BMEdge *e; | |||||
| BMVert *v; | |||||
| TransDataVertSlideVert *sv_array; | |||||
| VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld"); | |||||
| int j; | |||||
| sld->curr_sv_index = 0; | |||||
| j = 0; | |||||
| BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { | |||||
| bool ok = false; | |||||
| if (BM_elem_flag_test(v, BM_ELEM_SELECT) && v->e) { | |||||
| BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { | |||||
| if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { | |||||
| ok = true; | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (ok) { | |||||
| BM_elem_flag_enable(v, BM_ELEM_TAG); | |||||
| j += 1; | |||||
| } | |||||
| else { | |||||
| BM_elem_flag_disable(v, BM_ELEM_TAG); | |||||
| } | |||||
| } | |||||
| if (!j) { | |||||
| MEM_freeN(sld); | |||||
| return false; | |||||
| } | |||||
| sv_array = MEM_callocN(sizeof(TransDataVertSlideVert) * j, "sv_array"); | |||||
| j = 0; | |||||
| BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { | |||||
| if (BM_elem_flag_test(v, BM_ELEM_TAG)) { | |||||
| int k; | |||||
| sv_array[j].v = v; | |||||
| copy_v3_v3(sv_array[j].co_orig_3d, v->co); | |||||
| k = 0; | |||||
| BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { | |||||
| if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { | |||||
| k++; | |||||
| } | |||||
| } | |||||
| sv_array[j].co_link_orig_3d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_3d) * k, | |||||
| __func__); | |||||
| sv_array[j].co_link_tot = k; | |||||
| k = 0; | |||||
| BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { | |||||
| if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { | |||||
| BMVert *v_other = BM_edge_other_vert(e, v); | |||||
| copy_v3_v3(sv_array[j].co_link_orig_3d[k], v_other->co); | |||||
| k++; | |||||
| } | |||||
| } | |||||
| j++; | |||||
| } | |||||
| } | |||||
| sld->sv = sv_array; | |||||
| sld->totsv = j; | |||||
| tc->custom.mode.data = sld; | |||||
| /* most likely will be set below */ | |||||
| unit_m4(sld->proj_mat); | |||||
| if (t->spacetype == SPACE_VIEW3D) { | |||||
| /* view vars */ | |||||
| RegionView3D *rv3d = NULL; | |||||
| ARegion *ar = t->ar; | |||||
| rv3d = ar ? ar->regiondata : NULL; | |||||
| if (rv3d) { | |||||
| ED_view3d_ob_project_mat_get(rv3d, tc->obedit, sld->proj_mat); | |||||
| } | |||||
| } | |||||
| /* XXX, calc vert slide across all objects */ | |||||
| if (tc == t->data_container) { | |||||
| calcVertSlideMouseActiveVert(t, t->mval); | |||||
| calcVertSlideMouseActiveEdges(t, t->mval); | |||||
| } | |||||
| return true; | |||||
| } | |||||
| void projectVertSlideData(TransInfo *t, bool is_final) | |||||
| { | |||||
| FOREACH_TRANS_DATA_CONTAINER (t, tc) { | |||||
| trans_mesh_customdata_correction_apply(tc, is_final); | |||||
| } | |||||
| } | |||||
| void freeVertSlideVerts(TransInfo *UNUSED(t), | |||||
| TransDataContainer *UNUSED(tc), | |||||
| TransCustomData *custom_data) | |||||
| { | |||||
| VertSlideData *sld = custom_data->data; | |||||
| if (!sld) { | |||||
| return; | |||||
| } | |||||
| if (sld->totsv > 0) { | |||||
| TransDataVertSlideVert *sv = sld->sv; | |||||
| int i = 0; | |||||
| for (i = 0; i < sld->totsv; i++, sv++) { | |||||
| MEM_freeN(sv->co_link_orig_3d); | |||||
| } | |||||
| } | |||||
| MEM_freeN(sld->sv); | |||||
| MEM_freeN(sld); | |||||
| custom_data->data = NULL; | |||||
| } | |||||
| static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event) | |||||
| { | |||||
| if (t->mode == TFM_VERT_SLIDE) { | |||||
| VertSlideParams *slp = t->custom.mode.data; | |||||
| if (slp) { | |||||
| switch (event->type) { | |||||
| case EKEY: | |||||
| if (event->val == KM_PRESS) { | |||||
| slp->use_even = !slp->use_even; | |||||
| if (slp->flipped) { | |||||
| calcVertSlideCustomPoints(t); | |||||
| } | |||||
| return TREDRAW_HARD; | |||||
| } | |||||
| break; | |||||
| case FKEY: | |||||
| if (event->val == KM_PRESS) { | |||||
| slp->flipped = !slp->flipped; | |||||
| calcVertSlideCustomPoints(t); | |||||
| return TREDRAW_HARD; | |||||
| } | |||||
| break; | |||||
| case CKEY: | |||||
| /* use like a modifier key */ | |||||
| if (event->val == KM_PRESS) { | |||||
| t->flag ^= T_ALT_TRANSFORM; | |||||
| calcVertSlideCustomPoints(t); | |||||
| return TREDRAW_HARD; | |||||
| } | |||||
| break; | |||||
| #if 0 | |||||
| case EVT_MODAL_MAP: | |||||
| switch (event->val) { | |||||
| case TFM_MODAL_EDGESLIDE_DOWN: | |||||
| sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv; | |||||
| break; | |||||
| case TFM_MODAL_EDGESLIDE_UP: | |||||
| sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv; | |||||
| break; | |||||
| } | |||||
| break; | |||||
| #endif | |||||
| case MOUSEMOVE: { | |||||
| /* don't recalculate the best edge */ | |||||
| const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); | |||||
| if (is_clamp) { | |||||
| calcVertSlideMouseActiveEdges(t, event->mval); | |||||
| } | |||||
| calcVertSlideCustomPoints(t); | |||||
| break; | |||||
| } | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| return TREDRAW_NOTHING; | |||||
| } | |||||
| void drawVertSlide(TransInfo *t) | |||||
| { | |||||
| if ((t->mode == TFM_VERT_SLIDE) && TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data) { | |||||
| const VertSlideParams *slp = t->custom.mode.data; | |||||
| VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; | |||||
| const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); | |||||
| /* Non-Prop mode */ | |||||
| { | |||||
| TransDataVertSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; | |||||
| TransDataVertSlideVert *sv; | |||||
| const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f; | |||||
| const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f; | |||||
| const int alpha_shade = -160; | |||||
| int i; | |||||
| GPU_depth_test(false); | |||||
| GPU_blend(true); | |||||
| GPU_blend_set_func_separate( | |||||
| GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); | |||||
| GPU_matrix_push(); | |||||
| GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); | |||||
| GPU_line_width(line_size); | |||||
| const uint shdr_pos = GPU_vertformat_attr_add( | |||||
| immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); | |||||
| immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); | |||||
| immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); | |||||
| immBegin(GPU_PRIM_LINES, sld->totsv * 2); | |||||
| if (is_clamp) { | |||||
| sv = sld->sv; | |||||
| for (i = 0; i < sld->totsv; i++, sv++) { | |||||
| immVertex3fv(shdr_pos, sv->co_orig_3d); | |||||
| immVertex3fv(shdr_pos, sv->co_link_orig_3d[sv->co_link_curr]); | |||||
| } | |||||
| } | |||||
| else { | |||||
| sv = sld->sv; | |||||
| for (i = 0; i < sld->totsv; i++, sv++) { | |||||
| float a[3], b[3]; | |||||
| sub_v3_v3v3(a, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d); | |||||
| mul_v3_fl(a, 100.0f); | |||||
| negate_v3_v3(b, a); | |||||
| add_v3_v3(a, sv->co_orig_3d); | |||||
| add_v3_v3(b, sv->co_orig_3d); | |||||
| immVertex3fv(shdr_pos, a); | |||||
| immVertex3fv(shdr_pos, b); | |||||
| } | |||||
| } | |||||
| immEnd(); | |||||
| GPU_point_size(ctrl_size); | |||||
| immBegin(GPU_PRIM_POINTS, 1); | |||||
| immVertex3fv(shdr_pos, | |||||
| (slp->flipped && slp->use_even) ? | |||||
| curr_sv->co_link_orig_3d[curr_sv->co_link_curr] : | |||||
| curr_sv->co_orig_3d); | |||||
| immEnd(); | |||||
| immUnbindProgram(); | |||||
| /* direction from active vertex! */ | |||||
| if ((t->mval[0] != t->mouse.imval[0]) || (t->mval[1] != t->mouse.imval[1])) { | |||||
| float zfac; | |||||
| float mval_ofs[2]; | |||||
| float co_orig_3d[3]; | |||||
| float co_dest_3d[3]; | |||||
| mval_ofs[0] = t->mval[0] - t->mouse.imval[0]; | |||||
| mval_ofs[1] = t->mval[1] - t->mouse.imval[1]; | |||||
| mul_v3_m4v3( | |||||
| co_orig_3d, TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, curr_sv->co_orig_3d); | |||||
| zfac = ED_view3d_calc_zfac(t->ar->regiondata, co_orig_3d, NULL); | |||||
| ED_view3d_win_to_delta(t->ar, mval_ofs, co_dest_3d, zfac); | |||||
| invert_m4_m4(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, | |||||
| TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); | |||||
| mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, co_dest_3d); | |||||
| add_v3_v3(co_dest_3d, curr_sv->co_orig_3d); | |||||
| GPU_line_width(1.0f); | |||||
| immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); | |||||
| float viewport_size[4]; | |||||
| GPU_viewport_size_get_f(viewport_size); | |||||
| immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); | |||||
| immUniform1i("colors_len", 0); /* "simple" mode */ | |||||
| immUniformColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |||||
| immUniform1f("dash_width", 6.0f); | |||||
| immUniform1f("dash_factor", 0.5f); | |||||
| immBegin(GPU_PRIM_LINES, 2); | |||||
| immVertex3fv(shdr_pos, curr_sv->co_orig_3d); | |||||
| immVertex3fv(shdr_pos, co_dest_3d); | |||||
| immEnd(); | |||||
| immUnbindProgram(); | |||||
| } | |||||
| GPU_matrix_pop(); | |||||
| GPU_depth_test(true); | |||||
| } | |||||
| } | |||||
| } | |||||
| void doVertSlide(TransInfo *t, float perc) | |||||
| { | |||||
| VertSlideParams *slp = t->custom.mode.data; | |||||
| slp->perc = perc; | |||||
| FOREACH_TRANS_DATA_CONTAINER (t, tc) { | |||||
| VertSlideData *sld = tc->custom.mode.data; | |||||
| TransDataVertSlideVert *svlist = sld->sv, *sv; | |||||
| int i; | |||||
| sv = svlist; | |||||
| if (slp->use_even == false) { | |||||
| for (i = 0; i < sld->totsv; i++, sv++) { | |||||
| interp_v3_v3v3(sv->v->co, sv->co_orig_3d, sv->co_link_orig_3d[sv->co_link_curr], perc); | |||||
| } | |||||
| } | |||||
| else { | |||||
| TransDataVertSlideVert *sv_curr = &sld->sv[sld->curr_sv_index]; | |||||
| const float edge_len_curr = len_v3v3(sv_curr->co_orig_3d, | |||||
| sv_curr->co_link_orig_3d[sv_curr->co_link_curr]); | |||||
| const float tperc = perc * edge_len_curr; | |||||
| for (i = 0; i < sld->totsv; i++, sv++) { | |||||
| float edge_len; | |||||
| float dir[3]; | |||||
| sub_v3_v3v3(dir, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d); | |||||
| edge_len = normalize_v3(dir); | |||||
| if (edge_len > FLT_EPSILON) { | |||||
| if (slp->flipped) { | |||||
| madd_v3_v3v3fl(sv->v->co, sv->co_link_orig_3d[sv->co_link_curr], dir, -tperc); | |||||
| } | |||||
| else { | |||||
| madd_v3_v3v3fl(sv->v->co, sv->co_orig_3d, dir, tperc); | |||||
| } | |||||
| } | |||||
| else { | |||||
| copy_v3_v3(sv->v->co, sv->co_orig_3d); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2])) | |||||
| { | |||||
| char str[UI_MAX_DRAW_STR]; | |||||
| size_t ofs = 0; | |||||
| float final; | |||||
| VertSlideParams *slp = t->custom.mode.data; | |||||
| const bool flipped = slp->flipped; | |||||
| const bool use_even = slp->use_even; | |||||
| const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); | |||||
| const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num)); | |||||
| final = t->values[0]; | |||||
| snapGridIncrement(t, &final); | |||||
| /* only do this so out of range values are not displayed */ | |||||
| if (is_constrained) { | |||||
| CLAMP(final, 0.0f, 1.0f); | |||||
| } | |||||
| applyNumInput(&t->num, &final); | |||||
| t->values_final[0] = final; | |||||
| /* header string */ | |||||
| ofs += BLI_strncpy_rlen(str + ofs, TIP_("Vert Slide: "), sizeof(str) - ofs); | |||||
| if (hasNumInput(&t->num)) { | |||||
| char c[NUM_STR_REP_LEN]; | |||||
| outputNumInput(&(t->num), c, &t->scene->unit); | |||||
| ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs); | |||||
| } | |||||
| else { | |||||
| ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final); | |||||
| } | |||||
| ofs += BLI_snprintf( | |||||
| str + ofs, sizeof(str) - ofs, TIP_("(E)ven: %s, "), WM_bool_as_string(use_even)); | |||||
| if (use_even) { | |||||
| ofs += BLI_snprintf( | |||||
| str + ofs, sizeof(str) - ofs, TIP_("(F)lipped: %s, "), WM_bool_as_string(flipped)); | |||||
| } | |||||
| ofs += BLI_snprintf( | |||||
| str + ofs, sizeof(str) - ofs, TIP_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp)); | |||||
| /* done with header string */ | |||||
| /* do stuff here */ | |||||
| doVertSlide(t, final); | |||||
| recalcData(t); | |||||
| ED_area_status_text(t->sa, str); | |||||
| } | |||||
| void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp) | |||||
| { | |||||
| t->mode = TFM_VERT_SLIDE; | |||||
| t->transform = applyVertSlide; | |||||
| t->handleEvent = handleEventVertSlide; | |||||
| { | |||||
| VertSlideParams *slp = MEM_callocN(sizeof(*slp), __func__); | |||||
| slp->use_even = use_even; | |||||
| slp->flipped = flipped; | |||||
| slp->perc = 0.0f; | |||||
| if (!use_clamp) { | |||||
| t->flag |= T_ALT_TRANSFORM; | |||||
| } | |||||
| t->custom.mode.data = slp; | |||||
| t->custom.mode.use_free = true; | |||||
| } | |||||
| bool ok = false; | |||||
| FOREACH_TRANS_DATA_CONTAINER (t, tc) { | |||||
| ok |= createVertSlideVerts(t, tc); | |||||
| VertSlideData *sld = tc->custom.mode.data; | |||||
| if (sld) { | |||||
| tc->custom.mode.free_cb = freeVertSlideVerts; | |||||
| } | |||||
| } | |||||
| if (ok == false) { | |||||
| t->state = TRANS_CANCEL; | |||||
| return; | |||||
| } | |||||
| trans_mesh_customdata_correction_init(t); | |||||
| /* set custom point first if you want value to be initialized by init */ | |||||
| calcVertSlideCustomPoints(t); | |||||
| initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO); | |||||
| t->idx_max = 0; | |||||
| t->num.idx_max = 0; | |||||
| t->snap[0] = 0.0f; | |||||
| t->snap[1] = 0.1f; | |||||
| t->snap[2] = t->snap[1] * 0.1f; | |||||
| copy_v3_fl(t->num.val_inc, t->snap[1]); | |||||
| t->num.unit_sys = t->scene->unit.system; | |||||
| t->num.unit_type[0] = B_UNIT_NONE; | |||||
| t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; | |||||
| } | |||||
| void initVertSlide(TransInfo *t) | |||||
| { | |||||
| initVertSlide_ex(t, false, false, true); | |||||
| } | |||||
| /** \} */ | |||||
| void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot) | |||||
| { | |||||
| /* identifiers */ | |||||
| ot->name = "Vertex Slide"; | |||||
| ot->description = "Slide a vertex along a mesh"; | |||||
| ot->idname = OP_VERT_SLIDE; | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; | |||||
| /* api callbacks */ | |||||
| ot->invoke = transform_invoke; | |||||
| ot->exec = transform_exec; | |||||
| ot->modal = transform_modal; | |||||
| ot->cancel = transform_cancel; | |||||
| ot->poll = ED_operator_editmesh_region_view3d; | |||||
| ot->poll_property = transform_poll_property; | |||||
| RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f); | |||||
| RNA_def_boolean(ot->srna, | |||||
| "use_even", | |||||
| false, | |||||
| "Even", | |||||
| "Make the edge loop match the shape of the adjacent edge loop"); | |||||
| WM_operatortype_props_advanced_begin(ot); | |||||
| RNA_def_boolean(ot->srna, | |||||
| "flipped", | |||||
| false, | |||||
| "Flipped", | |||||
| "When Even mode is active, flips between the two adjacent edge loops"); | |||||
| RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp", "Clamp within the edge extents"); | |||||
| Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV); | |||||
| } | |||||