diff options
-rw-r--r-- | source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c | 265 |
1 files changed, 165 insertions, 100 deletions
diff --git a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c index e8f29d9a9b2..c179f5c18ae 100644 --- a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c +++ b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c @@ -65,6 +65,7 @@ typedef struct GizmoGroupData_SpinInit { /* We could store more vars here! */ struct { wmOperatorType *ot_spin; + float orient_mat[3][3]; } data; } GizmoGroupData_SpinInit; @@ -95,6 +96,7 @@ static void gizmo_mesh_spin_init_setup(const bContext *UNUSED(C), wmGizmoGroup * WM_gizmo_set_color(gz, color); color[3] = alpha_hi; WM_gizmo_set_color_highlight(gz, color); + WM_gizmo_set_scale(gz, 3.0); } { @@ -106,10 +108,9 @@ static void gizmo_mesh_spin_init_setup(const bContext *UNUSED(C), wmGizmoGroup * WM_gizmo_set_color(gz, color); color[3] = alpha_hi; WM_gizmo_set_color_highlight(gz, color); + WM_gizmo_set_scale(gz, 3.2f); } - WM_gizmo_set_scale(ggd->gizmos.xyz_view[3], 1.2f); - ggd->data.ot_spin = WM_operatortype_find("MESH_OT_spin", true); } @@ -173,10 +174,9 @@ static void gizmo_mesh_spin_init_refresh(const bContext *C, wmGizmoGroup *gzgrou } } - float mat[3][3]; - ED_transform_calc_orientation_from_type(C, mat); + ED_transform_calc_orientation_from_type(C, ggd->data.orient_mat); for (int i = 0; i < 3; i++) { - gizmo_mesh_spin_init_refresh_axis_orientation(gzgroup, i, mat[i]); + gizmo_mesh_spin_init_refresh_axis_orientation(gzgroup, i, ggd->data.orient_mat[i]); } { @@ -241,11 +241,6 @@ void MESH_GGT_spin(struct wmGizmoGroupType *gzgt) * \{ */ /** - * Don't show these for now, because they overlay the tools #MESH_GGT_spin_redo gizmos. - * this means we cant rotate the currently running gizmo. - */ -// #define USE_EXTRA_CONTROLS -/** * Orient the dial so the 'arc' starts where the mouse cursor is, * this is simply to keep the gizmo displaying where the cursor starts. * It's not needed for practical functionality. @@ -253,15 +248,21 @@ void MESH_GGT_spin(struct wmGizmoGroupType *gzgt) #define USE_ANGLE_Z_ORIENT typedef struct GizmoGroupData_SpinRedo { - /* Arrow to change plane depth. */ - struct wmGizmo *translate_z; - /* Translate XYZ */ + /* Translate XYZ. */ struct wmGizmo *translate_c; - /* For grabbing the gizmo and moving freely. */ - struct wmGizmo *rotate_c; /* Spin angle */ struct wmGizmo *angle_z; + /* Translate XY constrained. */ + struct wmGizmo *translate_xy[2]; + /* For grabbing the gizmo and moving freely. */ + struct wmGizmo *rotate_xy[2]; + + struct { + float plane_co[3]; + float plane_no[3]; + } prev; + /* We could store more vars here! */ struct { bContext *context; @@ -272,10 +273,17 @@ typedef struct GizmoGroupData_SpinRedo { PropertyRNA *prop_angle; float rotate_axis[3]; - float rotate_up[3]; #ifdef USE_ANGLE_Z_ORIENT float orient_axis[3]; #endif + /* The orientation, since the operator doesn't store this, we store our own. + * this is kept in sync with the operator, + * rotating the orientation when it doesn't match. + * + * Initialize to a sensible value where possible. + */ + float orient_mat[3][3]; + } data; } GizmoGroupData_SpinRedo; @@ -295,18 +303,39 @@ static void gizmo_spin_exec(GizmoGroupData_SpinRedo *ggd) static void gizmo_mesh_spin_redo_update_from_op(GizmoGroupData_SpinRedo *ggd) { wmOperator *op = ggd->data.op; - float plane_co[3], plane_no[3]; - RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co); RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no); + if (UNLIKELY(normalize_v3(plane_no) == 0.0f)) { + return; + } + const bool is_plane_co_eq = equals_v3v3(plane_co, ggd->prev.plane_co); + const bool is_plane_no_eq = equals_v3v3(plane_no, ggd->prev.plane_no); + if (is_plane_co_eq && is_plane_no_eq) { + return; + } + copy_v3_v3(ggd->prev.plane_co, plane_co); + copy_v3_v3(ggd->prev.plane_no, plane_no); + + if (is_plane_no_eq == false) { + float mat[3][3]; + rotation_between_vecs_to_mat3(mat, ggd->data.orient_mat[2], plane_no); + mul_m3_m3m3(ggd->data.orient_mat, mat, ggd->data.orient_mat); + /* Not needed, just set for numeric stability. */ + copy_v3_v3(ggd->data.orient_mat[2], plane_no); + } - WM_gizmo_set_matrix_location(ggd->translate_z, plane_co); - WM_gizmo_set_matrix_location(ggd->rotate_c, plane_co); + for (int i = 0; i < 2; i++) { + WM_gizmo_set_matrix_location(ggd->rotate_xy[i], plane_co); + WM_gizmo_set_matrix_location(ggd->translate_xy[i], plane_co); + } WM_gizmo_set_matrix_location(ggd->angle_z, plane_co); /* translate_c location comes from the property. */ - WM_gizmo_set_matrix_rotation_from_z_axis(ggd->translate_z, plane_no); + for (int i = 0; i < 2; i++) { + WM_gizmo_set_matrix_rotation_from_z_axis(ggd->translate_xy[i], ggd->data.orient_mat[i]); + WM_gizmo_set_matrix_rotation_from_z_axis(ggd->rotate_xy[i], ggd->data.orient_mat[i]); + } #ifdef USE_ANGLE_Z_ORIENT { float plane_tan[3]; @@ -321,30 +350,6 @@ static void gizmo_mesh_spin_redo_update_from_op(GizmoGroupData_SpinRedo *ggd) #else WM_gizmo_set_matrix_rotation_from_z_axis(ggd->angle_z, plane_no); #endif - - WM_gizmo_set_scale(ggd->translate_c, 0.2); - - WM_gizmo_set_scale(ggd->angle_z, 2.0f); - WM_gizmo_set_line_width(ggd->angle_z, 1.0f); - - RegionView3D *rv3d = ED_view3d_context_rv3d(ggd->data.context); - if (rv3d) { - normalize_v3_v3(ggd->data.rotate_axis, rv3d->viewinv[2]); - normalize_v3_v3(ggd->data.rotate_up, rv3d->viewinv[1]); - - /* ensure its orthogonal */ - project_plane_normalized_v3_v3v3(ggd->data.rotate_up, ggd->data.rotate_up, ggd->data.rotate_axis); - normalize_v3(ggd->data.rotate_up); - - WM_gizmo_set_matrix_rotation_from_z_axis(ggd->translate_c, plane_no); - WM_gizmo_set_matrix_rotation_from_yz_axis(ggd->rotate_c, plane_no, ggd->data.rotate_axis); - - /* show the axis instead of mouse cursor */ - RNA_enum_set(ggd->rotate_c->ptr, "draw_options", - ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_MIRROR | - ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_START_Y); - - } } /* depth callbacks */ @@ -359,9 +364,9 @@ static void gizmo_spin_prop_depth_get( BLI_assert(gz_prop->type->array_length == 1); UNUSED_VARS_NDEBUG(gz_prop); - float plane_co[3], plane_no[3]; + const float *plane_no = gz->matrix_basis[2]; + float plane_co[3]; RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co); - RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no); value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, gz->matrix_basis[3]); } @@ -379,8 +384,7 @@ static void gizmo_spin_prop_depth_set( float plane_co[3], plane[4]; RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co); - RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane); - normalize_v3(plane); + normalize_v3_v3(plane, gz->matrix_basis[2]); plane[3] = -value[0] - dot_v3v3(plane, gz->matrix_basis[3]); @@ -438,11 +442,15 @@ static void gizmo_spin_prop_axis_angle_get( RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no); normalize_v3(plane_no); + const float *rotate_axis = gz->matrix_basis[2]; + float rotate_up[3]; + ortho_v3_v3(rotate_up, rotate_axis); + float plane_no_proj[3]; - project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, ggd->data.rotate_axis); + project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, rotate_axis); if (!is_zero_v3(plane_no_proj)) { - const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, ggd->data.rotate_up, ggd->data.rotate_axis); + const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, rotate_up, rotate_axis); value[0] = angle; } else { @@ -465,15 +473,19 @@ static void gizmo_spin_prop_axis_angle_set( RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no); normalize_v3(plane_no); + const float *rotate_axis = gz->matrix_basis[2]; + float rotate_up[3]; + ortho_v3_v3(rotate_up, rotate_axis); + float plane_no_proj[3]; - project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, ggd->data.rotate_axis); + project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, rotate_axis); if (!is_zero_v3(plane_no_proj)) { - const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, ggd->data.rotate_up, ggd->data.rotate_axis); + const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, rotate_up, rotate_axis); const float angle_delta = angle - angle_compat_rad(value[0], angle); if (angle_delta != 0.0f) { float mat[3][3]; - axis_angle_normalized_to_mat3(mat, ggd->data.rotate_axis, angle_delta); + axis_angle_normalized_to_mat3(mat, rotate_axis, angle_delta); mul_m3_v3(mat, plane_no); /* re-normalize - seems acceptable */ @@ -569,29 +581,57 @@ static void gizmo_mesh_spin_redo_setup(const bContext *C, wmGizmoGroup *gzgroup) const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true); const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true); - ggd->translate_z = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL); - ggd->translate_c = WM_gizmo_new_ptr(gzt_move, gzgroup, NULL); - ggd->rotate_c = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); - ggd->angle_z = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); - - UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->translate_z->color); - UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->translate_c->color); - UI_GetThemeColor3fv(TH_GIZMO_SECONDARY, ggd->rotate_c->color); - copy_v3_v3(ggd->angle_z->color, ggd->angle_z->color_hi); - ggd->angle_z->color[3] = 0.5f; - - RNA_enum_set(ggd->translate_z->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_NORMAL); - RNA_enum_set(ggd->translate_c->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_RING_2D); + /* Translate Center (translate_c) */ + { + wmGizmo *gz = WM_gizmo_new_ptr(gzt_move, gzgroup, NULL); + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); + gz->color[3] = 0.6f; + RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_RING_2D); + WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true); + WM_gizmo_set_scale(gz, 0.15); + WM_gizmo_set_line_width(gz, 2.0f); + ggd->translate_c = gz; + } - RNA_boolean_set(ggd->angle_z->ptr, "wrap_angle", false); - RNA_enum_set(ggd->angle_z->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE); - RNA_float_set(ggd->angle_z->ptr, "arc_inner_factor", 0.9f); + /* Spin Angle (angle_z) */ + { + wmGizmo *gz = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); + copy_v3_v3(gz->color, gz->color_hi); + gz->color[3] = 0.5f; + RNA_boolean_set(gz->ptr, "wrap_angle", false); + RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE); + RNA_float_set(gz->ptr, "arc_inner_factor", 0.9f); + WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true); + WM_gizmo_set_scale(gz, 2.0f); + WM_gizmo_set_line_width(gz, 1.0f); + ggd->angle_z = gz; + } - WM_gizmo_set_flag(ggd->translate_c, WM_GIZMO_DRAW_VALUE, true); - WM_gizmo_set_flag(ggd->rotate_c, WM_GIZMO_DRAW_VALUE, true); - WM_gizmo_set_flag(ggd->angle_z, WM_GIZMO_DRAW_VALUE, true); + /* Translate X/Y Tangents (translate_xy) */ + for (int i = 0; i < 2; i++) { + wmGizmo *gz = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL); + UI_GetThemeColor3fv(TH_AXIS_X + i, gz->color); + RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_NORMAL); + RNA_enum_set(gz->ptr, "draw_options", 0); + WM_gizmo_set_scale(gz, 1.2f); + ggd->translate_xy[i] = gz; + } - WM_gizmo_set_scale(ggd->rotate_c, 0.8f); + /* Rotate X/Y Tangents (rotate_xy) */ + for (int i = 0; i < 2; i++) { + wmGizmo *gz = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); + UI_GetThemeColor3fv(TH_AXIS_X + i, gz->color); + gz->color[3] = 0.6f; + WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true); + WM_gizmo_set_scale(gz, 1.0f); + WM_gizmo_set_line_width(gz, 3.0f); + /* show the axis instead of mouse cursor */ + RNA_enum_set(gz->ptr, "draw_options", + ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_MIRROR | + ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_START_Y | + ED_GIZMO_DIAL_DRAW_FLAG_CLIP); + ggd->rotate_xy[i] = gz; + } { ggd->data.context = (bContext *)C; @@ -602,20 +642,28 @@ static void gizmo_mesh_spin_redo_setup(const bContext *C, wmGizmoGroup *gzgroup) ggd->data.prop_angle = RNA_struct_type_find_property(ot->srna, "angle"); } + /* The spin operator only knows about an axis, + * while the manipulator has X/Y orientation for the gizmos. + * Initialize the orientation from the spin gizmo if possible. + */ + { + ARegion *ar = CTX_wm_region(C); + wmGizmoMap *gzmap = ar->gizmo_map; + wmGizmoGroup *gzgroup_init = WM_gizmomap_group_find(gzmap, "MESH_GGT_spin"); + if (gzgroup_init) { + GizmoGroupData_SpinInit *ggd_init = gzgroup_init->customdata; + copy_m3_m3(ggd->data.orient_mat, ggd_init->data.orient_mat); + } + else { + unit_m3(ggd->data.orient_mat); + } + } + gizmo_mesh_spin_redo_update_from_op(ggd); /* Setup property callbacks */ { WM_gizmo_target_property_def_func( - ggd->translate_z, "offset", - &(const struct wmGizmoPropertyFnParams) { - .value_get_fn = gizmo_spin_prop_depth_get, - .value_set_fn = gizmo_spin_prop_depth_set, - .range_get_fn = NULL, - .user_data = NULL, - }); - - WM_gizmo_target_property_def_func( ggd->translate_c, "offset", &(const struct wmGizmoPropertyFnParams) { .value_get_fn = gizmo_spin_prop_translate_get, @@ -624,14 +672,24 @@ static void gizmo_mesh_spin_redo_setup(const bContext *C, wmGizmoGroup *gzgroup) .user_data = NULL, }); - WM_gizmo_target_property_def_func( - ggd->rotate_c, "offset", - &(const struct wmGizmoPropertyFnParams) { - .value_get_fn = gizmo_spin_prop_axis_angle_get, - .value_set_fn = gizmo_spin_prop_axis_angle_set, - .range_get_fn = NULL, - .user_data = NULL, - }); + for (int i = 0; i < 2; i++) { + WM_gizmo_target_property_def_func( + ggd->rotate_xy[i], "offset", + &(const struct wmGizmoPropertyFnParams) { + .value_get_fn = gizmo_spin_prop_axis_angle_get, + .value_set_fn = gizmo_spin_prop_axis_angle_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + WM_gizmo_target_property_def_func( + ggd->translate_xy[i], "offset", + &(const struct wmGizmoPropertyFnParams) { + .value_get_fn = gizmo_spin_prop_depth_get, + .value_set_fn = gizmo_spin_prop_depth_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + } WM_gizmo_target_property_def_func( ggd->angle_z, "offset", @@ -641,16 +699,8 @@ static void gizmo_mesh_spin_redo_setup(const bContext *C, wmGizmoGroup *gzgroup) .range_get_fn = NULL, .user_data = NULL, }); - } -#ifndef USE_EXTRA_CONTROLS - /* Disable for now. */ - WM_gizmo_set_flag(ggd->translate_z, WM_GIZMO_HIDDEN, true); - WM_gizmo_set_flag(ggd->translate_c, WM_GIZMO_HIDDEN, true); - WM_gizmo_set_flag(ggd->rotate_c, WM_GIZMO_HIDDEN, true); -#endif - /* Become modal as soon as it's started. */ gizmo_mesh_spin_redo_modal_from_setup(C, gzgroup); } @@ -662,7 +712,22 @@ static void gizmo_mesh_spin_redo_draw_prepare( if (ggd->data.op->next) { ggd->data.op = WM_operator_last_redo((bContext *)ggd->data.context); } - gizmo_mesh_spin_redo_update_from_op(ggd); + + /* Not essentual, just avoids feedback loop where matrices could shift because of float precision. + * Updates in this case are also redundant. */ + bool is_modal = false; + for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) { + if (gz->state & WM_GIZMO_STATE_MODAL) { + is_modal = true; + break; + } + } + if (!is_modal) { + gizmo_mesh_spin_redo_update_from_op(ggd); + } + + RegionView3D *rv3d = ED_view3d_context_rv3d(ggd->data.context); + WM_gizmo_set_matrix_rotation_from_z_axis(ggd->translate_c, rv3d->viewinv[2]); } void MESH_GGT_spin_redo(struct wmGizmoGroupType *gzgt) |