improve warp transform so it can be used as a general bending tool too.

This commit is contained in:
Campbell Barton
2013-10-13 01:09:23 +00:00
parent eabf7ab335
commit b00a8122e3
4 changed files with 150 additions and 97 deletions

View 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);

View 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,

View 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)))
{

View 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;