diff options
author | Campbell Barton <ideasman42@gmail.com> | 2013-01-13 18:08:53 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2013-01-13 18:08:53 +0400 |
commit | af5d994b155650ef390635030bb5e9b528637695 (patch) | |
tree | 33157b82bbe9f0b78783babbacdee5d639d659e6 /source/blender/editors/transform | |
parent | 5eb2070fc7920706ffc9b06220f5d698fc91f015 (diff) |
add new vertex slide transform operator, different from the existing vertex slide tool based on user feedback.
- no 2-step select edge, then slide. Instead you can slide and select the edge at the same time.
- ability to slide multiple verts at one.
supports proportional option for vertex slide and flipping, both matching edge slide functionality.
Diffstat (limited to 'source/blender/editors/transform')
-rw-r--r-- | source/blender/editors/transform/transform.c | 466 | ||||
-rw-r--r-- | source/blender/editors/transform/transform.h | 33 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_ops.c | 23 |
3 files changed, 518 insertions, 4 deletions
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 7cc6006970c..63663b408ca 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -99,6 +99,10 @@ static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg); static int doEdgeSlide(TransInfo *t, float perc); +static int doVertSlide(TransInfo *t, float perc); + +static void drawEdgeSlide(const struct bContext *C, TransInfo *t); +static void drawVertSlide(const struct bContext *C, TransInfo *t); /* ************************** SPACE DEPENDANT CODE **************************** */ @@ -1601,7 +1605,10 @@ static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), voi drawConstraint(t); drawPropCircle(C, t); drawSnapping(C, t); - drawNonPropEdge(C, t); + + /* edge slide, vert slide */ + drawEdgeSlide(C, t); + drawVertSlide(C, t); } /* just draw a little warning message in the top-right corner of the viewport to warn that autokeying is enabled */ @@ -1950,6 +1957,9 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int case TFM_EDGE_SLIDE: initEdgeSlide(t); break; + case TFM_VERT_SLIDE: + initVertSlide(t); + break; case TFM_BONE_ROLL: initBoneRoll(t); break; @@ -5599,7 +5609,7 @@ int handleEventEdgeSlide(struct TransInfo *t, struct wmEvent *event) return 0; } -void drawNonPropEdge(const struct bContext *C, TransInfo *t) +void drawEdgeSlide(const struct bContext *C, TransInfo *t) { if (t->mode == TFM_EDGE_SLIDE) { EdgeSlideData *sld = (EdgeSlideData *)t->customData; @@ -5783,6 +5793,458 @@ int EdgeSlide(TransInfo *t, const int UNUSED(mval[2])) return 1; } + +/* ******************** Vert Slide *************** */ +static void calcVertSlideCustomPoints(struct TransInfo *t) +{ + VertSlideData *sld = t->customData; + TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index]; + int start[2] = {UNPACK2(sv->co_orig_2d)}; + int end[2] = {UNPACK2(sv->co_link_orig_2d[sv->co_link_curr])}; + if (sld->flipped_vtx) { + setCustomPoints(t, &t->mouse, start, end); + } + else { + setCustomPoints(t, &t->mouse, end, start); + } +} +static void calcVertSlideMouseMove(struct TransInfo *t, const int mval[2], const bool is_init) +{ + VertSlideData *sld = t->customData; + float mval_fl[2] = {UNPACK2(mval)}; + + float dir[2]; + TransDataVertSlideVert *sv; + int i; + + sv = sld->sv; + + if (is_init) { + /* set the vertex to use as a reference for the mouse direction 'curr_sv_index' */ + float dist = 0.0f; + float min_dist = FLT_MAX; + + for (i = 0; i < sld->totsv; i++, sv++) { + /* allow points behind the view [#33643] */ + dist = len_squared_v2v2(mval_fl, sv->co_orig_2d); + if (dist < min_dist) { + min_dist = dist; + sld->curr_sv_index = i; + } + } + } + + /* first get the direction of the original vertex */ + sub_v2_v2v2(dir, sld->sv[sld->curr_sv_index].co_orig_2d, mval_fl); + normalize_v2(dir); + + sv = sld->sv; + + for (i = 0; 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[2]; + float dir_dot; + sub_v2_v2v2(tdir, sv->co_orig_2d, sv->co_link_orig_2d[j]); + normalize_v2(tdir); + dir_dot = dot_v2v2(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 int createVertSlideVerts(TransInfo *t) +{ + BMEditMesh *em = BMEdit_FromObject(t->obedit); + BMesh *bm = em->bm; + BMIter iter; + BMIter eiter; + BMEdge *e; + BMVert *v; + TransDataVertSlideVert *sv_array; + VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld"); +// View3D *v3d = NULL; + RegionView3D *rv3d = NULL; + ARegion *ar = t->ar; + float projectMat[4][4]; + int j; + + if (t->spacetype == SPACE_VIEW3D) { + /* background mode support */ +// v3d = t->sa ? t->sa->spacedata.first : NULL; + rv3d = t->ar ? t->ar->regiondata : NULL; + } + + sld->is_proportional = TRUE; + sld->curr_sv_index = 0; + sld->flipped_vtx = FALSE; + + if (!rv3d) { + /* ok, let's try to survive this */ + unit_m4(projectMat); + } + else { + ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat); + } + + 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 0; + } + + 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_SELECT)) { + 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_orig_2d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_2d) * 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); + ED_view3d_project_float_v2_m4(ar, + sv_array[j].co_link_orig_3d[k], + sv_array[j].co_link_orig_2d[k], + projectMat); + k++; + } + } + + ED_view3d_project_float_v2_m4(ar, + sv_array[j].co_orig_3d, + sv_array[j].co_orig_2d, + projectMat); + + j++; + } + } + + sld->sv = sv_array; + sld->totsv = j; + + sld->em = em; + + sld->perc = 0.0f; + + t->customData = sld; + + if (rv3d) + calcVertSlideMouseMove(t, t->mval, true); + + return 1; +} + +void freeVertSlideVerts(TransInfo *t) +{ + VertSlideData *sld = t->customData; + + 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_2d); + MEM_freeN(sv->co_link_orig_3d); + } + } + + MEM_freeN(sld->sv); + MEM_freeN(sld); + + t->customData = NULL; + + recalcData(t); +} + +void initVertSlide(TransInfo *t) +{ + VertSlideData *sld; + + t->mode = TFM_VERT_SLIDE; + t->transform = VertSlide; + t->handleEvent = handleEventVertSlide; + + if (!createVertSlideVerts(t)) { + t->state = TRANS_CANCEL; + return; + } + + sld = t->customData; + + if (!sld) + return; + + t->customFree = freeVertSlideVerts; + + /* 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; + + t->num.increment = t->snap[1]; + + t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; +} + +int handleEventVertSlide(struct TransInfo *t, struct wmEvent *event) +{ + if (t->mode == TFM_VERT_SLIDE) { + VertSlideData *sld = t->customData; + + if (sld) { + switch (event->type) { + case EKEY: + if (event->val == KM_PRESS) { + sld->is_proportional = !sld->is_proportional; + return 1; + } + break; + case FKEY: + { + if (event->val == KM_PRESS) { + if (sld->is_proportional == FALSE) { + sld->flipped_vtx = !sld->flipped_vtx; + calcVertSlideCustomPoints(t); + } + return 1; + } + 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; + } + } + } +#endif + case MOUSEMOVE: + { + calcVertSlideMouseMove(t, event->mval, false); + calcVertSlideCustomPoints(t); + } + default: + break; + } + } + } + return 0; +} + +static void drawVertSlide(const struct bContext *C, TransInfo *t) +{ + if (t->mode == TFM_VERT_SLIDE) { + VertSlideData *sld = (VertSlideData *)t->customData; + /* Non-Prop mode */ + if (sld) { + View3D *v3d = CTX_wm_view3d(C); + 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 = -30; + int i; + + if (v3d && v3d->zbuf) + glDisable(GL_DEPTH_TEST); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT | GL_POINT_BIT); + glPushMatrix(); + + glMultMatrixf(t->obedit->obmat); + + glLineWidth(line_size); + UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); + glBegin(GL_LINES); + sv = sld->sv; + for (i = 0; i < sld->totsv; i++, sv++) { + glVertex3fv(sv->co_orig_3d); + glVertex3fv(sv->co_link_orig_3d[sv->co_link_curr]); + } + bglEnd(); + + glPointSize(ctrl_size); + + bglBegin(GL_POINTS); + bglVertex3fv((sld->flipped_vtx && sld->is_proportional == FALSE) ? + curr_sv->co_link_orig_3d[curr_sv->co_link_curr] : + curr_sv->co_orig_3d); + bglEnd(); + + glPopMatrix(); + glPopAttrib(); + + glDisable(GL_BLEND); + + if (v3d && v3d->zbuf) + glEnable(GL_DEPTH_TEST); + } + } +} + +static int doVertSlide(TransInfo *t, float perc) +{ + VertSlideData *sld = t->customData; + TransDataVertSlideVert *svlist = sld->sv, *sv; + int i; + + sld->perc = perc; + sv = svlist; + + if (sld->is_proportional == TRUE) { + const float tperc = perc + 1.0f; + for (i = 0; i < sld->totsv; i++, sv++) { + interp_v3_v3v3(sv->v->co, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d, tperc); + } + } + 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 (sld->flipped_vtx) { + 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); + } + printf("%.6f\n", tperc); + } + else { + copy_v3_v3(sv->v->co, sv->co_orig_3d); + } + } + } + + return 1; +} + +int VertSlide(TransInfo *t, const int UNUSED(mval[2])) +{ + char str[128]; + float final; + VertSlideData *sld = t->customData; + int flipped = sld->flipped_vtx; + int is_proportional = sld->is_proportional; + + final = t->values[0]; + + snapGrid(t, &final); + + /* only do this so out of range values are not displayed */ + CLAMP(final, -1.0f, 1.0f); + + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + + applyNumInput(&t->num, &final); + + outputNumInput(&(t->num), c); + + BLI_snprintf(str, sizeof(str), "Vert Slide: %s (E)ven: %s, (F)lipped: %s", + &c[0], !is_proportional ? "ON" : "OFF", flipped ? "ON" : "OFF"); + } + else { + BLI_snprintf(str, sizeof(str), "Vert Slide: %.2f (E)ven: %s, (F)lipped: %s", + final, !is_proportional ? "ON" : "OFF", flipped ? "ON" : "OFF"); + } + + CLAMP(final, -1.0f, 1.0f); + + t->values[0] = final; + + /*do stuff here*/ + if (t->customData) + doVertSlide(t, final); + else { + strcpy(str, "Invalid Vert Selection"); + t->state = TRANS_CANCEL; + } + + recalcData(t); + + ED_area_headerprint(t->sa, str); + + return 1; +} + + /* ******************** EditBone roll *************** */ void initBoneRoll(TransInfo *t) diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 59ed1abe2c4..5eb9bc19cd3 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -224,6 +224,31 @@ typedef struct EdgeSlideData { int curr_sv_index; } EdgeSlideData; + +typedef struct TransDataVertSlideVert { + BMVert *v; + float co_orig_3d[3]; + float co_orig_2d[2]; + float (*co_link_orig_3d)[3]; + float (*co_link_orig_2d)[2]; + int co_link_tot; + int co_link_curr; +} TransDataVertSlideVert; + +typedef struct VertSlideData { + TransDataVertSlideVert *sv; + int totsv; + + struct BMEditMesh *em; + + float perc; + + int is_proportional; + int flipped_vtx; + + int curr_sv_index; +} VertSlideData; + typedef struct TransData { float dist; /* Distance needed to affect element (for Proportionnal Editing) */ float rdist; /* Distance to the nearest element (for Proportionnal Editing) */ @@ -530,6 +555,10 @@ void initEdgeSlide(TransInfo *t); int handleEventEdgeSlide(TransInfo *t, struct wmEvent *event); int EdgeSlide(TransInfo *t, const int mval[2]); +void initVertSlide(TransInfo *t); +int handleEventVertSlide(TransInfo *t, struct wmEvent *event); +int VertSlide(TransInfo *t, const int mval[2]); + void initTimeTranslate(TransInfo *t); int TimeTranslate(TransInfo *t, const int mval[2]); @@ -672,8 +701,6 @@ void resetTransRestrictions(TransInfo *t); void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis, short options); -void drawNonPropEdge(const struct bContext *C, TransInfo *t); - /* DRAWLINE options flags */ #define DRAWLIGHT 1 @@ -719,4 +746,6 @@ void freeEdgeSlideTempFaces(EdgeSlideData *sld); void freeEdgeSlideVerts(TransInfo *t); void projectEdgeSlideData(TransInfo *t, bool is_final); +void freeVertSlideVerts(TransInfo *t); + #endif diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 916cf540589..f7c538b2dc7 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -73,6 +73,7 @@ static char OP_TILT[] = "TRANSFORM_OT_tilt"; static char OP_TRACKBALL[] = "TRANSFORM_OT_trackball"; static char OP_MIRROR[] = "TRANSFORM_OT_mirror"; static char OP_EDGE_SLIDE[] = "TRANSFORM_OT_edge_slide"; +static char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide"; static char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease"; static char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight"; static char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide"; @@ -90,6 +91,7 @@ static void TRANSFORM_OT_tilt(struct wmOperatorType *ot); static void TRANSFORM_OT_trackball(struct wmOperatorType *ot); static void TRANSFORM_OT_mirror(struct wmOperatorType *ot); static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot); +static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot); static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot); static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot); static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot); @@ -109,6 +111,7 @@ static TransformModeItem transform_modes[] = {OP_TRACKBALL, TFM_TRACKBALL, TRANSFORM_OT_trackball}, {OP_MIRROR, TFM_MIRROR, TRANSFORM_OT_mirror}, {OP_EDGE_SLIDE, TFM_EDGE_SLIDE, TRANSFORM_OT_edge_slide}, + {OP_VERT_SLIDE, TFM_VERT_SLIDE, TRANSFORM_OT_vert_slide}, {OP_EDGE_CREASE, TFM_CREASE, TRANSFORM_OT_edge_crease}, {OP_EDGE_BWEIGHT, TFM_BWEIGHT, TRANSFORM_OT_edge_bevelweight}, {OP_SEQ_SLIDE, TFM_SEQ_SLIDE, TRANSFORM_OT_seq_slide}, @@ -793,6 +796,26 @@ static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot) Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV); } +static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vert 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; + + RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f); + + Transform_Properties(ot, P_MIRROR | P_SNAP); +} + static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot) { /* identifiers */ |