improve warp transform so it can be used as a general bending tool too.
authorCampbell Barton <ideasman42@gmail.com>
Sun, 13 Oct 2013 01:09:23 +0000 (01:09 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Sun, 13 Oct 2013 01:09:23 +0000 (01:09 +0000)
source/blender/editors/transform/transform.c
source/blender/editors/transform/transform.h
source/blender/editors/transform/transform_generics.c
source/blender/editors/transform/transform_input.c

index ba7bdebd5bf911f7de467a1cea7d23193f63be4a..ea039c15be4b1229fc551e9b196b3aa9fa7a3891 100644 (file)
@@ -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);
index 9355773c47b06ef4b2af68c48364e10bbab2a201..b32ba5ad527ce5ae838c19c69a44d2929896b97e 100644 (file)
@@ -678,6 +678,7 @@ typedef enum {
        INPUT_SPRING,
        INPUT_SPRING_FLIP,
        INPUT_ANGLE,
+       INPUT_ANGLE_SPRING,
        INPUT_TRACKBALL,
        INPUT_HORIZONTAL_RATIO,
        INPUT_HORIZONTAL_ABSOLUTE,
index b6f031614ca822e22e562fbb1dd4e92c776826be..94f481d8dfc09be15c5595ab37d75c2e47e88d2c 100644 (file)
@@ -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)))
                {
index db214e1f6db4289f428c8cd1a7ea381f786d1da8..ee993129303b7c8921d0eac24be1f71dd57f9204 100644 (file)
@@ -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;