From b00a8122e3e5fa88e3870ca20eedbd251d245237 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 13 Oct 2013 01:09:23 +0000 Subject: [PATCH] improve warp transform so it can be used as a general bending tool too. --- source/blender/editors/transform/transform.c | 225 ++++++++++-------- source/blender/editors/transform/transform.h | 1 + .../editors/transform/transform_generics.c | 5 + .../editors/transform/transform_input.c | 16 ++ 4 files changed, 150 insertions(+), 97 deletions(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index ba7bdebd5bf..ea039c15be4 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -105,6 +105,8 @@ 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); +static void len_v3_ensure(float v[3], const float length); +static void postInputRotation(TransInfo *t, float values[3]); static bool transdata_check_local_center(TransInfo *t) { @@ -2576,29 +2578,33 @@ static void constraintSizeLim(TransInfo *t, TransData *td) /* ************************** WARP *************************** */ -static void postInputWarp(TransInfo *t, float values[3]) -{ - mul_v3_fl(values, (float)(M_PI * 2)); +struct WarpCustomData { + float warp_sta[3]; + float warp_end[3]; - if (t->customData) { /* non-null value indicates reversed input */ - negate_v3(values); - } -} + float warp_nor[3]; + float warp_tan[3]; + + /* for applying the mouse distance */ + float warp_init_dist; +}; void initWarp(TransInfo *t) { - float max[3], min[3]; - int i; + const float mval_fl[2] = {UNPACK2(t->mval)}; + const float *curs; + float tvec[3]; + struct WarpCustomData *data; t->mode = TFM_WARP; t->transform = Warp; t->handleEvent = handleEventWarp; - setInputPostFct(&t->mouse, postInputWarp); - initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO); + setInputPostFct(&t->mouse, postInputRotation); + initMouseInputMode(t, &t->mouse, INPUT_ANGLE_SPRING); - t->idx_max = 0; - t->num.idx_max = 0; + t->idx_max = 1; + t->num.idx_max = 1; t->snap[0] = 0.0f; t->snap[1] = DEG2RAD(5.0); t->snap[2] = DEG2RAD(1.0); @@ -2606,28 +2612,33 @@ void initWarp(TransInfo *t) t->num.increment = 1.0f; t->flag |= T_NO_CONSTRAINT; - - /* we need min/max in view space */ - for (i = 0; i < t->total; i++) { - float center[3]; - copy_v3_v3(center, t->data[i].center); - mul_m3_v3(t->data[i].mtx, center); - mul_m4_v3(t->viewmat, center); - sub_v3_v3(center, t->viewmat[3]); - if (i) { - minmax_v3v3_v3(min, max, center); - } - else { - copy_v3_v3(max, center); - copy_v3_v3(min, center); - } + + //copy_v3_v3(t->center, give_cursor(t->scene, t->view)); + calculateCenterCursor(t); + + t->val = 0.0f; + + data = MEM_callocN(sizeof(*data), __func__); + + curs = give_cursor(t->scene, t->view); + copy_v3_v3(data->warp_sta, curs); + ED_view3d_win_to_3d(t->ar, curs, mval_fl, data->warp_end); + + copy_v3_v3(data->warp_nor, t->viewinv[2]); + if (t->flag & T_EDIT) { + sub_v3_v3(data->warp_sta, t->obedit->obmat[3]); + sub_v3_v3(data->warp_end, t->obedit->obmat[3]); } + normalize_v3(data->warp_nor); - mid_v3_v3v3(t->center, min, max); + /* tangent */ + sub_v3_v3v3(tvec, data->warp_end, data->warp_sta); + cross_v3_v3v3(data->warp_tan, tvec, data->warp_nor); + normalize_v3(data->warp_tan); - if (max[0] == min[0]) - max[0] += 0.1f; /* not optimal, but flipping is better than invalid garbage (i.e. division by zero!) */ - t->val = (max[0] - min[0]) / 2.0f; /* t->val is X dimension projected boundbox */ + data->warp_init_dist = len_v3v3(data->warp_end, data->warp_sta); + + t->customData = data; } int handleEventWarp(TransInfo *t, const wmEvent *event) @@ -2635,11 +2646,7 @@ int handleEventWarp(TransInfo *t, const wmEvent *event) int status = 0; if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) { - // Use customData pointer to signal warp direction - if (t->customData == NULL) - t->customData = (void *)1; - else - t->customData = NULL; + (void)t; status = 1; } @@ -2650,91 +2657,115 @@ int handleEventWarp(TransInfo *t, const wmEvent *event) int Warp(TransInfo *t, const int UNUSED(mval[2])) { TransData *td = t->data; - float vec[3], circumfac, dist, phi0, co, si, cursor[3], gcursor[3]; - const float *curs; + float vec[3]; + float pivot[3]; + float warp_end_radius[3]; int i; char str[MAX_INFO_LEN]; - - curs = give_cursor(t->scene, t->view); - /* - * gcursor is the one used for helpline. - * It has to be in the same space as the drawing loop - * (that means it needs to be in the object's space when in edit mode and - * in global space in object mode) - * - * cursor is used for calculations. - * It needs to be in view space, but we need to take object's offset - * into account if in Edit mode. - */ - copy_v3_v3(cursor, curs); - copy_v3_v3(gcursor, cursor); - if (t->flag & T_EDIT) { - sub_v3_v3(cursor, t->obedit->obmat[3]); - sub_v3_v3(gcursor, t->obedit->obmat[3]); - mul_m3_v3(t->data->smtx, gcursor); - } - mul_m4_v3(t->viewmat, cursor); - sub_v3_v3(cursor, t->viewmat[3]); - + const struct WarpCustomData *data = t->customData; + const bool is_clamp = (t->flag & T_ALT_TRANSFORM) == 0; + + union { + struct { float angle, scale; }; + float vector[2]; + } values; + /* amount of radians for warp */ - circumfac = t->values[0]; - - snapGrid(t, &circumfac); - applyNumInput(&t->num, &circumfac); + copy_v2_v2(values.vector, t->values); + +#if 0 + snapGrid(t, angle_rad); +#else + /* hrmf, snapping radius is using 'angle' steps, need to convert to something else + * this isnt essential but nicer to give reasonable snapping values for radius */ + if (t->tsnap.mode == SCE_SNAP_MODE_INCREMENT) { + const float radius_snap = 0.1f; + const float snap_hack = (t->snap[1] * data->warp_init_dist) / radius_snap; + values.scale *= snap_hack; + snapGrid(t, values.vector); + values.scale /= snap_hack; + } +#endif /* header print for NumInput */ if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; + char c[NUM_STR_REP_LEN * 2]; + applyNumInput(&t->num, values.vector); + outputNumInput(&(t->num), c); - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Warp: %s"), c); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Warp Angle: %s Radius: %s Alt, Clamp %s"), + &c[0], &c[NUM_STR_REP_LEN], + WM_bool_as_string(is_clamp)); - circumfac = DEG2RADF(circumfac); + values.angle = DEG2RADF(values.angle); + values.scale = values.scale / data->warp_init_dist; } else { /* default header print */ - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Warp: %.3f"), RAD2DEGF(circumfac)); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Warp Angle: %.3f Radius: %.4f, Alt, Clamp %s"), + RAD2DEGF(values.angle), values.scale * data->warp_init_dist, + WM_bool_as_string(is_clamp)); } - t->values[0] = circumfac; + copy_v2_v2(t->values, values.vector); - circumfac /= 2; /* only need 180 on each side to make 360 */ + values.angle *= -1.0f; + values.scale *= data->warp_init_dist; + /* calc 'data->warp_end' from 'data->warp_end_init' */ + copy_v3_v3(warp_end_radius, data->warp_end); + dist_ensure_v3_v3fl(warp_end_radius, data->warp_sta, values.scale); + /* done */ + + /* calculate pivot */ + copy_v3_v3(pivot, data->warp_sta); + if (values.angle > 0.0f) { + madd_v3_v3fl(pivot, data->warp_tan, -values.scale * shell_angle_to_dist((float)M_PI_2 - values.angle)); + } + else { + madd_v3_v3fl(pivot, data->warp_tan, +values.scale * shell_angle_to_dist((float)M_PI_2 + values.angle)); + } + for (i = 0; i < t->total; i++, td++) { - float loc[3]; + float mat[3][3]; + float delta[3]; + float fac, fac_scaled; + if (td->flag & TD_NOACTION) break; if (td->flag & TD_SKIP) continue; - - /* translate point to center, rotate in such a way that outline==distance */ + + if (UNLIKELY(values.angle == 0.0f)) { + copy_v3_v3(td->loc, td->iloc); + continue; + } + copy_v3_v3(vec, td->iloc); mul_m3_v3(td->mtx, vec); - mul_m4_v3(t->viewmat, vec); - sub_v3_v3(vec, t->viewmat[3]); - - dist = vec[0] - cursor[0]; - - /* t->val is X dimension projected boundbox */ - phi0 = (circumfac * dist / t->val); - - vec[1] = (vec[1] - cursor[1]); - - co = cosf(phi0); - si = sinf(phi0); - loc[0] = -si * vec[1] + cursor[0]; - loc[1] = co * vec[1] + cursor[1]; - loc[2] = vec[2]; - - mul_m4_v3(t->viewinv, loc); - sub_v3_v3(loc, t->viewinv[3]); - mul_m3_v3(td->smtx, loc); - - sub_v3_v3(loc, td->iloc); - mul_v3_fl(loc, td->factor); - add_v3_v3v3(td->loc, td->iloc, loc); + + fac = line_point_factor_v3(vec, data->warp_sta, warp_end_radius); + if (is_clamp) { + CLAMP(fac, 0.0f, 1.0f); + } + + fac_scaled = fac * td->factor; + axis_angle_normalized_to_mat3(mat, data->warp_nor, values.angle * fac_scaled); + interp_v3_v3v3(delta, data->warp_sta, warp_end_radius, fac_scaled); + sub_v3_v3(delta, data->warp_sta); + + /* delta is subtracted, rotation adds back this offset */ + sub_v3_v3(vec, delta); + + sub_v3_v3(vec, pivot); + mul_m3_v3(mat, vec); + add_v3_v3(vec, pivot); + + mul_m3_v3(td->smtx, vec); + copy_v3_v3(td->loc, vec); } recalcData(t); diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 9355773c47b..b32ba5ad527 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -678,6 +678,7 @@ typedef enum { INPUT_SPRING, INPUT_SPRING_FLIP, INPUT_ANGLE, + INPUT_ANGLE_SPRING, INPUT_TRACKBALL, INPUT_HORIZONTAL_RATIO, INPUT_HORIZONTAL_ABSOLUTE, diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index b6f031614ca..94f481d8dfc 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1145,6 +1145,11 @@ int initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *even if (v3d->flag & V3D_ALIGN) t->flag |= T_V3D_ALIGN; t->around = v3d->around; + /* warp always uses the cursor */ + if (t->mode == TFM_WARP) { + t->around = V3D_CURSOR; + } + if (op && ((prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) && RNA_property_is_set(op->ptr, prop))) { diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c index db214e1f6db..ee993129303 100644 --- a/source/blender/editors/transform/transform_input.c +++ b/source/blender/editors/transform/transform_input.c @@ -279,6 +279,16 @@ static void InputAngle(TransInfo *UNUSED(t), MouseInput *mi, const int mval[2], output[0] = *angle; } +static void InputAngleSpring(TransInfo *t, MouseInput *mi, const int mval[2], float output[3]) +{ + float toutput[3]; + + InputAngle(t, mi, mval, output); + InputSpring(t, mi, mval, toutput); + + output[1] = toutput[0]; +} + void initMouseInput(TransInfo *UNUSED(t), MouseInput *mi, const float center[2], const int mval[2]) { mi->factor = 0; @@ -328,6 +338,12 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode) mi->apply = InputAngle; t->helpline = HLP_ANGLE; break; + case INPUT_ANGLE_SPRING: + calcSpringFactor(mi); + mi->data = MEM_callocN(sizeof(double), "angle accumulator"); + mi->apply = InputAngleSpring; + t->helpline = HLP_ANGLE; + break; case INPUT_TRACKBALL: /* factor has to become setting or so */ mi->factor = 0.01f;