Gizmo: let cage gizmo follow the cursor exactly when scaling #104405

Closed
Weizhen Huang wants to merge 1 commits from weizhen:exact_cursor into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
2 changed files with 69 additions and 57 deletions

View File

@ -959,55 +959,60 @@ static int gizmo_cage2d_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
return OPERATOR_RUNNING_MODAL; 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) { 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: { case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X: {
ARRAY_SET_ITEMS(r_pt, 0.5, 0.0); ARRAY_SET_ITEMS(r_pt, 0.5, 0.0);
x = false;
break; break;
} }
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X: { case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X: {
ARRAY_SET_ITEMS(r_pt, -0.5, 0.0); ARRAY_SET_ITEMS(r_pt, -0.5, 0.0);
x = false;
break; break;
} }
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y: { case ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y: {
ARRAY_SET_ITEMS(r_pt, 0.0, 0.5); ARRAY_SET_ITEMS(r_pt, 0.0, 0.5);
y = false;
break; break;
} }
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y: { case ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y: {
ARRAY_SET_ITEMS(r_pt, 0.0, -0.5); ARRAY_SET_ITEMS(r_pt, 0.0, -0.5);
y = false;
break; break;
} }
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y: { case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y: {
ARRAY_SET_ITEMS(r_pt, 0.5, 0.5); ARRAY_SET_ITEMS(r_pt, 0.5, 0.5);
x = y = false;
break; break;
} }
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y: { case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y: {
ARRAY_SET_ITEMS(r_pt, 0.5, -0.5); ARRAY_SET_ITEMS(r_pt, 0.5, -0.5);
x = y = false;
break; break;
} }
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y: { case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y: {
ARRAY_SET_ITEMS(r_pt, -0.5, 0.5); ARRAY_SET_ITEMS(r_pt, -0.5, 0.5);
x = y = false;
break; break;
} }
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y: { case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y: {
ARRAY_SET_ITEMS(r_pt, -0.5, -0.5); ARRAY_SET_ITEMS(r_pt, -0.5, -0.5);
x = y = false;
break; break;
} }
default: default:
BLI_assert(0); BLI_assert(0);
} }
r_constrain_axis[0] = x;
r_constrain_axis[1] = y;
} }
static int gizmo_cage2d_modal(bContext *C, static int gizmo_cage2d_modal(bContext *C,
@ -1105,46 +1110,55 @@ static int gizmo_cage2d_modal(bContext *C,
else { else {
/* scale */ /* scale */
copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset); copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
float pivot[2]; const int draw_style = RNA_enum_get(gz->ptr, "draw_style");
bool constrain_axis[2] = {false};
float pivot[2];
if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE) { 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 { else {
zero_v2(pivot); zero_v2(pivot);
} }
/* Cursor deltas scaled to (-0.5..0.5). */ bool constrain_axis[2] = {false};
float delta_orig[2], delta_curr[2]; gizmo_constrain_from_scale_part(gz->highlight_part, constrain_axis);
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];
}
float scale[2] = {1.0f, 1.0f}; float scale[2] = {1.0f, 1.0f};
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
if (constrain_axis[i] == false) { if (constrain_axis[i] == false) {
if (delta_orig[i] < 0.0f) { /* Original cursor position relative to pivot, remapped to [-1, 1] */
delta_orig[i] *= -1.0f; const float delta_orig = (data->orig_mouse[i] - data->orig_matrix_offset[3][i]) /
delta_curr[i] *= -1.0f; (dims[i] * len_v3(data->orig_matrix_offset[i])) -
} pivot[i];
const int sign = signum_i(scale[i]); const float delta_curr = (point_local[i] - data->orig_matrix_offset[3][i]) /
(dims[i] * len_v3(data->orig_matrix_offset[i])) -
scale[i] = 1.0f + ((delta_curr[i] - delta_orig[i]) / len_v3(data->orig_matrix_offset[i])); pivot[i];
if ((transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_SCALE_SIGNED) == 0) { 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; 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 (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_SCALE_UNIFORM) {
if (constrain_axis[0] == false && constrain_axis[1] == false) { 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) { else if (constrain_axis[0] == false) {
scale[1] = scale[0]; scale[1] = scale[0];

View File

@ -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 && 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) { 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}; const float sign[3] = {0.5f, 0.0f, -0.5f};
for (int i = 0; i < 3; i++) { 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); r_constrain_axis[i] = (range[i] == 1);
} }
} }
@ -512,41 +515,36 @@ static int gizmo_cage3d_modal(bContext *C,
else { else {
/* scale */ /* scale */
copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset); copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
float pivot[3]; float pivot[3];
bool constrain_axis[3] = {false}; bool constrain_axis[3] = {false};
bool has_translation = transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE;
if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE) { gizmo_rect_pivot_from_scale_part(gz->highlight_part, pivot, constrain_axis, has_translation);
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];
}
float scale[3] = {1.0f, 1.0f, 1.0f}; float scale[3] = {1.0f, 1.0f, 1.0f};
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
if (constrain_axis[i] == false) { if (constrain_axis[i] == false) {
if (delta_orig[i] < 0.0f) { /* Original cursor position relative to pivot, remapped to [-1, 1] */
delta_orig[i] *= -1.0f; const float delta_orig = (data->orig_mouse[i] - data->orig_matrix_offset[3][i]) /
delta_curr[i] *= -1.0f; (dims[i] * len_v3(data->orig_matrix_offset[i])) -
} pivot[i];
const int sign = signum_i(scale[i]); const float delta_curr = (point_local[i] - data->orig_matrix_offset[3][i]) /
(dims[i] * len_v3(data->orig_matrix_offset[i])) -
scale[i] = 1.0f + ((delta_curr[i] - delta_orig[i]) / len_v3(data->orig_matrix_offset[i])); pivot[i];
if ((transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_SCALE_SIGNED) == 0) { 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; 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]);
}
} }
} }