diff --git a/scripts/startup/bl_ui/space_userpref.py b/scripts/startup/bl_ui/space_userpref.py index 25c5fad971f..82540c34026 100644 --- a/scripts/startup/bl_ui/space_userpref.py +++ b/scripts/startup/bl_ui/space_userpref.py @@ -1700,6 +1700,7 @@ class USERPREF_PT_input_mouse(InputPanel, CenterAlignMixIn, Panel): subrow.active = inputs.use_mouse_emulate_3_button flow.prop(inputs, "use_mouse_continuous") + flow.prop(inputs, "use_accumulative_trackball") flow.prop(inputs, "use_drag_immediately") flow.prop(inputs, "mouse_double_click_time", text="Double Click Speed") flow.prop(inputs, "drag_threshold_mouse") diff --git a/source/blender/blenloader/intern/versioning_userdef.cc b/source/blender/blenloader/intern/versioning_userdef.cc index 3da1008a7dc..d17cb404d4d 100644 --- a/source/blender/blenloader/intern/versioning_userdef.cc +++ b/source/blender/blenloader/intern/versioning_userdef.cc @@ -723,7 +723,7 @@ void blo_do_versions_userdef(UserDef *userdef) userdef->pixelsize = 1.0f; } /* Clear old userdef flag for "Camera Parent Lock". */ - userdef->uiflag &= ~USER_UIFLAG_UNUSED_3; + userdef->uiflag &= ~USER_ACCUMULATE_TRACKBALL; } if (!USER_VERSION_ATLEAST(292, 9)) { diff --git a/source/blender/editors/transform/transform_data.hh b/source/blender/editors/transform/transform_data.hh index 75dab5e271e..21b51e2686e 100644 --- a/source/blender/editors/transform/transform_data.hh +++ b/source/blender/editors/transform/transform_data.hh @@ -136,6 +136,9 @@ struct TransData { TransDataCurveHandleFlags *hdata; /** If set, copy of Object or #bPoseChannel protection. */ short protectflag; + /** Local rotation accumulator for Trackball (is initialized) */ + short rotmtx_init; + float rotmtx[3][3]; }; #define TRANSDATA_THREAD_LIMIT 1024 diff --git a/source/blender/editors/transform/transform_mode_trackball.cc b/source/blender/editors/transform/transform_mode_trackball.cc index e212f9d4558..f7d363bf2bc 100644 --- a/source/blender/editors/transform/transform_mode_trackball.cc +++ b/source/blender/editors/transform/transform_mode_trackball.cc @@ -54,7 +54,18 @@ static void transdata_elem_trackball(const TransInfo *t, float mat_buf[3][3]; const float(*mat)[3] = mat_final; if (t->flag & T_PROP_EDIT) { + if (UNLIKELY(!td->rotmtx_init)) { + unit_m3(td->rotmtx); + td->rotmtx_init = true; + } axis_angle_normalized_to_mat3(mat_buf, axis, td->factor * angle); + + /* Apply "continuous" trackball rotation. */ + if (U.uiflag & USER_ACCUMULATE_TRACKBALL) { + mul_m3_m3_post(mat_buf, td->rotmtx); + copy_m3_m3(td->rotmtx, mat_buf); + } + mat = mat_buf; } ElementRotation(t, tc, td, mat, t->around); @@ -97,8 +108,16 @@ static void applyTrackballValue(TransInfo *t, const float axis[3], const float a float mat_final[3][3]; int i; + /* Hack: Use otherwise-unused matrix storage for this */ + float (*mat_temp)[3] = t->orient[0].matrix; + axis_angle_normalized_to_mat3(mat_final, axis, angle); + if (U.uiflag & USER_ACCUMULATE_TRACKBALL) { + mul_m3_m3_post(mat_final, mat_temp); + copy_m3_m3(mat_temp, mat_final); + } + FOREACH_TRANS_DATA_CONTAINER (t, tc) { if (tc->data_len < TRANSDATA_THREAD_LIMIT) { TransData *td = tc->data; @@ -130,8 +149,17 @@ static void applyTrackball(TransInfo *t) size_t ofs = 0; float phi[2]; + /* Store previous mouse coordinates as (z,w) in the xyzw vector */ + float* phi_prev = t->values + 2; + copy_v2_v2(phi, t->values); + /* Get mouse delta only since phi_prev */ + if (U.uiflag & USER_ACCUMULATE_TRACKBALL) { + sub_v2_v2(phi, phi_prev); + copy_v2_v2(phi_prev, t->values); + } + transform_snap_increment(t, phi); applyNumInput(&t->num, phi); @@ -194,6 +222,9 @@ static void initTrackball(TransInfo *t, wmOperator * /*op*/) initMouseInputMode(t, &t->mouse, INPUT_TRACKBALL); + /* Initialize re-used matrix storage to I */ + unit_m3(t->orient[0].matrix); + t->idx_max = 1; t->num.idx_max = 1; t->snap[0] = DEG2RAD(5.0); diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index f770e42f258..33c19b9c252 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -1192,7 +1192,7 @@ typedef enum eUserpref_UI_Flag { USER_HIDE_DOT = (1 << 16), USER_SHOW_GIZMO_NAVIGATE = (1 << 17), USER_SHOW_VIEWPORTNAME = (1 << 18), - USER_UIFLAG_UNUSED_3 = (1 << 19), /* Cleared. */ + USER_ACCUMULATE_TRACKBALL = (1 << 19), USER_ZOOM_TO_MOUSEPOS = (1 << 20), USER_SHOW_FPS = (1 << 21), USER_REGISTER_ALL_USERS = (1 << 22), diff --git a/source/blender/makesrna/intern/rna_userdef.cc b/source/blender/makesrna/intern/rna_userdef.cc index 11f27d3b9d9..a89d68d50f9 100644 --- a/source/blender/makesrna/intern/rna_userdef.cc +++ b/source/blender/makesrna/intern/rna_userdef.cc @@ -6263,6 +6263,15 @@ static void rna_def_userdef_input(BlenderRNA *brna) "Let the mouse wrap around the view boundaries so mouse movements are not limited by the " "screen size (used by transform, dragging of UI controls, etc.)"); + prop = RNA_def_property(srna, "use_accumulative_trackball", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_ACCUMULATE_TRACKBALL); + RNA_def_property_ui_text( + prop, + "Continuous Trackball", + "Continuously accumulate trackball rotation as the mouse is moved, rather than applying it all at once. " + "Allows for more intuitive trackball rotations when moving the mouse a larger distance." + ); + prop = RNA_def_property(srna, "use_drag_immediately", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, nullptr, "flag", USER_RELEASECONFIRM); RNA_def_property_ui_text(prop,