Gizmo: make cage gizmo follow the cursor exactly when scaling
Ref #104280 The scaling of area light / spot light blend was wrong because it is calculated for pivot at the edges. The new implementation in theory works for all `abs(pivot) <= 0.5f`, although we only have -0.5, 0, and 0.5. - Axis constraint for box cage was only applied when there is translate flag, now the same logic is applied regardless of the translate flag, this means when dragging the edge, the scaling in the other axis stays the same; when dragging the corners, it applies free-form scaling. - Due to the existence of margin, `data->orig_mouse` does not lie exactly on the boundary. Using that value to compute the scaling causes the error to accumulate over distance. The new implementation uses the original dimension of the object instead, and only uses `data->orig_mouse` to determine the side of the original cursor relative to the pivot. - For circular gizmo with unsigned scaling, the gizmo only follow the cursor exactly when the cursor stays in the original quadrant, otherwise it's hard to handle the logic when we should clamp the scaling.
This commit is contained in:
@@ -959,55 +959,60 @@ static int gizmo_cage2d_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static void gizmo_rect_pivot_from_scale_part(int part, float r_pt[2], bool r_constrain_axis[2])
|
||||
static void gizmo_constrain_from_scale_part(int part, bool r_constrain_axis[2])
|
||||
{
|
||||
r_constrain_axis[0] = (part > ED_GIZMO_CAGE2D_PART_SCALE_MAX_X &&
|
||||
part < ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y) ?
|
||||
true :
|
||||
false;
|
||||
r_constrain_axis[1] = (part > ED_GIZMO_CAGE2D_PART_SCALE &&
|
||||
part < ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y) ?
|
||||
true :
|
||||
false;
|
||||
}
|
||||
|
||||
static void gizmo_pivot_from_scale_part(int part, float r_pt[2])
|
||||
{
|
||||
bool x = true, y = true;
|
||||
switch (part) {
|
||||
case ED_GIZMO_CAGE2D_PART_SCALE: {
|
||||
ARRAY_SET_ITEMS(r_pt, 0.0, 0.0);
|
||||
break;
|
||||
}
|
||||
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X: {
|
||||
ARRAY_SET_ITEMS(r_pt, 0.5, 0.0);
|
||||
x = false;
|
||||
break;
|
||||
}
|
||||
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X: {
|
||||
ARRAY_SET_ITEMS(r_pt, -0.5, 0.0);
|
||||
x = false;
|
||||
break;
|
||||
}
|
||||
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y: {
|
||||
ARRAY_SET_ITEMS(r_pt, 0.0, 0.5);
|
||||
y = false;
|
||||
break;
|
||||
}
|
||||
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y: {
|
||||
ARRAY_SET_ITEMS(r_pt, 0.0, -0.5);
|
||||
y = false;
|
||||
break;
|
||||
}
|
||||
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y: {
|
||||
ARRAY_SET_ITEMS(r_pt, 0.5, 0.5);
|
||||
x = y = false;
|
||||
break;
|
||||
}
|
||||
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y: {
|
||||
ARRAY_SET_ITEMS(r_pt, 0.5, -0.5);
|
||||
x = y = false;
|
||||
break;
|
||||
}
|
||||
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y: {
|
||||
ARRAY_SET_ITEMS(r_pt, -0.5, 0.5);
|
||||
x = y = false;
|
||||
break;
|
||||
}
|
||||
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y: {
|
||||
ARRAY_SET_ITEMS(r_pt, -0.5, -0.5);
|
||||
x = y = false;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert(0);
|
||||
}
|
||||
r_constrain_axis[0] = x;
|
||||
r_constrain_axis[1] = y;
|
||||
}
|
||||
|
||||
static int gizmo_cage2d_modal(bContext *C,
|
||||
@@ -1105,46 +1110,55 @@ static int gizmo_cage2d_modal(bContext *C,
|
||||
else {
|
||||
/* scale */
|
||||
copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
|
||||
float pivot[2];
|
||||
bool constrain_axis[2] = {false};
|
||||
const int draw_style = RNA_enum_get(gz->ptr, "draw_style");
|
||||
|
||||
float pivot[2];
|
||||
if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE) {
|
||||
gizmo_rect_pivot_from_scale_part(gz->highlight_part, pivot, constrain_axis);
|
||||
gizmo_pivot_from_scale_part(gz->highlight_part, pivot);
|
||||
}
|
||||
else {
|
||||
zero_v2(pivot);
|
||||
}
|
||||
|
||||
/* Cursor deltas scaled to (-0.5..0.5). */
|
||||
float delta_orig[2], delta_curr[2];
|
||||
for (int i = 0; i < 2; i++) {
|
||||
delta_orig[i] = ((data->orig_mouse[i] - data->orig_matrix_offset[3][i]) / dims[i]) -
|
||||
pivot[i];
|
||||
delta_curr[i] = ((point_local[i] - data->orig_matrix_offset[3][i]) / dims[i]) - pivot[i];
|
||||
}
|
||||
bool constrain_axis[2] = {false};
|
||||
gizmo_constrain_from_scale_part(gz->highlight_part, constrain_axis);
|
||||
|
||||
float scale[2] = {1.0f, 1.0f};
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (constrain_axis[i] == false) {
|
||||
if (delta_orig[i] < 0.0f) {
|
||||
delta_orig[i] *= -1.0f;
|
||||
delta_curr[i] *= -1.0f;
|
||||
}
|
||||
const int sign = signum_i(scale[i]);
|
||||
|
||||
scale[i] = 1.0f + ((delta_curr[i] - delta_orig[i]) / len_v3(data->orig_matrix_offset[i]));
|
||||
/* Original cursor position relative to pivot, remapped to [-1, 1] */
|
||||
const float delta_orig = (data->orig_mouse[i] - data->orig_matrix_offset[3][i]) /
|
||||
(dims[i] * len_v3(data->orig_matrix_offset[i])) -
|
||||
pivot[i];
|
||||
const float delta_curr = (point_local[i] - data->orig_matrix_offset[3][i]) /
|
||||
(dims[i] * len_v3(data->orig_matrix_offset[i])) -
|
||||
pivot[i];
|
||||
|
||||
if ((transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_SCALE_SIGNED) == 0) {
|
||||
if (sign != signum_i(scale[i])) {
|
||||
if (signum_i(delta_orig) != signum_i(delta_curr)) {
|
||||
scale[i] = 0.0f;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (delta_orig < 0) {
|
||||
scale[i] = -delta_curr / (pivot[i] + 0.5f);
|
||||
}
|
||||
else {
|
||||
scale[i] = delta_curr / (0.5f - pivot[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_SCALE_UNIFORM) {
|
||||
if (constrain_axis[0] == false && constrain_axis[1] == false) {
|
||||
scale[1] = scale[0] = (scale[1] + scale[0]) / 2.0f;
|
||||
if (draw_style == ED_GIZMO_CAGE2D_STYLE_CIRCLE) {
|
||||
/* So that the cursor lies on the circle. */
|
||||
scale[1] = scale[0] = len_v2(scale);
|
||||
}
|
||||
else {
|
||||
scale[1] = scale[0] = (scale[1] + scale[0]) / 2.0f;
|
||||
}
|
||||
}
|
||||
else if (constrain_axis[0] == false) {
|
||||
scale[1] = scale[0];
|
||||
|
||||
@@ -88,7 +88,10 @@ static void gizmo_calc_rect_view_margin(const wmGizmo *gz, const float dims[3],
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
static void gizmo_rect_pivot_from_scale_part(int part, float r_pt[3], bool r_constrain_axis[3])
|
||||
static void gizmo_rect_pivot_from_scale_part(int part,
|
||||
float r_pt[3],
|
||||
bool r_constrain_axis[3],
|
||||
bool has_translation)
|
||||
{
|
||||
if (part >= ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z &&
|
||||
part <= ED_GIZMO_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z) {
|
||||
@@ -102,7 +105,7 @@ static void gizmo_rect_pivot_from_scale_part(int part, float r_pt[3], bool r_con
|
||||
|
||||
const float sign[3] = {0.5f, 0.0f, -0.5f};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
r_pt[i] = sign[range[i]];
|
||||
r_pt[i] = has_translation ? sign[range[i]] : 0.0f;
|
||||
r_constrain_axis[i] = (range[i] == 1);
|
||||
}
|
||||
}
|
||||
@@ -512,41 +515,36 @@ static int gizmo_cage3d_modal(bContext *C,
|
||||
else {
|
||||
/* scale */
|
||||
copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
|
||||
|
||||
float pivot[3];
|
||||
bool constrain_axis[3] = {false};
|
||||
|
||||
if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE) {
|
||||
gizmo_rect_pivot_from_scale_part(gz->highlight_part, pivot, constrain_axis);
|
||||
}
|
||||
else {
|
||||
zero_v3(pivot);
|
||||
}
|
||||
|
||||
/* Cursor deltas scaled to (-0.5..0.5). */
|
||||
float delta_orig[3], delta_curr[3];
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
delta_orig[i] = ((data->orig_mouse[i] - data->orig_matrix_offset[3][i]) / dims[i]) -
|
||||
pivot[i];
|
||||
delta_curr[i] = ((point_local[i] - data->orig_matrix_offset[3][i]) / dims[i]) - pivot[i];
|
||||
}
|
||||
bool has_translation = transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE;
|
||||
gizmo_rect_pivot_from_scale_part(gz->highlight_part, pivot, constrain_axis, has_translation);
|
||||
|
||||
float scale[3] = {1.0f, 1.0f, 1.0f};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (constrain_axis[i] == false) {
|
||||
if (delta_orig[i] < 0.0f) {
|
||||
delta_orig[i] *= -1.0f;
|
||||
delta_curr[i] *= -1.0f;
|
||||
}
|
||||
const int sign = signum_i(scale[i]);
|
||||
|
||||
scale[i] = 1.0f + ((delta_curr[i] - delta_orig[i]) / len_v3(data->orig_matrix_offset[i]));
|
||||
/* Original cursor position relative to pivot, remapped to [-1, 1] */
|
||||
const float delta_orig = (data->orig_mouse[i] - data->orig_matrix_offset[3][i]) /
|
||||
(dims[i] * len_v3(data->orig_matrix_offset[i])) -
|
||||
pivot[i];
|
||||
const float delta_curr = (point_local[i] - data->orig_matrix_offset[3][i]) /
|
||||
(dims[i] * len_v3(data->orig_matrix_offset[i])) -
|
||||
pivot[i];
|
||||
|
||||
if ((transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_SCALE_SIGNED) == 0) {
|
||||
if (sign != signum_i(scale[i])) {
|
||||
if (signum_i(delta_orig) != signum_i(delta_curr)) {
|
||||
scale[i] = 0.0f;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (delta_orig < 0) {
|
||||
scale[i] = -delta_curr / (pivot[i] + 0.5f);
|
||||
}
|
||||
else {
|
||||
scale[i] = delta_curr / (0.5f - pivot[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user